Подтвердить что ты не робот

Как получить доступ к действию с помощью Android-модуля React Native?

Я пытаюсь подключиться к функциям Android, чтобы сохранить экран в React Native. Я решил, что могу сделать это с помощью простого модуля, однако я не знаю, как получить доступ к текущей активности Android из указанного модуля.

Мне нужна ссылка Activity, поэтому я могу называть .getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); на ней

Я попытался получить активность с помощью каста таким образом ((Activity)getReactApplicationContext().getBaseContext()), но это вызывает ошибку "не может быть перенесена в Android.app.Activity"

4b9b3361

Ответ 1

CustomReactPackage.java:

public class CustomReactPackage implements ReactPackage {

    private Activity mActivity = null;

    public CustomReactPackage(Activity activity) {
        mActivity = activity;
    }

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        // Add native modules here
        return modules;
    }

    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        List<ViewManager> modules = new ArrayList<>();
        // Add native UI components here
        modules.add(new LSPlayerManager(mActivity));
        return modules;
    }
}

LSPlayerManager - это мой собственный компонент пользовательского интерфейса. Я определяю конструктор так, чтобы я мог передавать в действие:

public LSPlayerManager(Activity activity) {
    mActivity = activity;
}

И наконец, в MainActivity.java, где определен ReactInstanceManager, мы можем передать активность в наш пользовательский пакет React:

mReactInstanceManager = ReactInstanceManager.builder()
        .setApplication(getApplication())
        .setBundleAssetName("index.android.bundle")
        .setJSMainModuleName("src/index.android")
        .addPackage(new MainReactPackage())
        .addPackage(new CustomReactPackage(this)) // <--- LIKE THIS!
        .setUseDeveloperSupport(BuildConfig.DEBUG)
        .setInitialLifecycleState(LifecycleState.RESUMED)
        .build();

ОБНОВЛЕНИЕ ДЛЯ РЕАКТИВНОЙ ДЕЯТЕЛЬНОСТИ 0.29.0

Это уже не то, как вы получаете доступ к активности в собственном модуле. См. https://github.com/facebook/react-native/releases/tag/v0.29.0 для инструкций по миграции

Ответ 2

Я думаю, getCurrentActivity() метод ReactContextBaseJavaModule может использоваться как следующий код, который был скопирован из React-Native исходного кода;

import android.app.Activity;
import com.facebook.react.bridge.ReactContextBaseJavaModule;

public class AwesomeModule extends ReactContextBaseJavaModule {

  public AwesomeModule(ReactApplicationContext reactContext) {
    super(reactContext);
  }

  @Override
  public String getName() {
    return "AwesomeAndroid";
  }

  private static final String ERROR_NO_ACTIVITY = "E_NO_ACTIVITY";
  private static final String ERROR_NO_ACTIVITY_MESSAGE = "Tried to do the something while not attached to an Activity";

  @ReactMethod
  public void doSomething(successCallback, errorCallback) {

    final Activity activity = getCurrentActivity();

    if (activity == null) {
      errorCallback(ERROR_NO_ACTIVITY, ERROR_NO_ACTIVITY_MESSAGE);
      return;
    }

  }

}

Ответ 3

Editted:

Проблема заключается в том, что getReactApplicationContext() возвращает контекст приложения, а не Activity. Вы не можете привить контекст приложения к Activity.

Это простой способ

Как правило, в реакции-native есть только одно действие (основная активность). Мы можем записать статическую функцию в MainActivity, чтобы вернуть активность

private static Activity mCurrentActivity = null;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mCurrentActivity = this;
    ...
}
...
public static Activity getActivity(){
    Activity activity = new Activity();
    activity = mCurrentActivity;
    return activity;
}

затем вызовите MainActivity.getActivity() из мостовых модулей

Ответ 4

Для 0.28 и раньше вы можете получить активность от ReactInstanceManagerImpl private @Nullable Activity mCurrentActivity;, 0.29+ ReactContextBaseJavaModule с использованием того же поля.

Ответ 5

Как передать активность в пакет из ReactApplication:: getPackages()?

Я не понимаю. Я не могу найти четких примеров

package com.bluetoothioexample;

import android.app.Application;
import android.util.Log;

import com.facebook.react.bridge.ReactContextBaseJavaModule;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;

import java.util.Arrays;
import java.util.List;

import com.subsite.bluetoothio.BluetoothIOPackage;
import com.oblador.vectoricons.VectorIconsPackage;

public class MainApplication extends Application implements ReactApplication {

  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
    protected boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG;
    }

    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
          new MainReactPackage(),
          new BluetoothIOPackage(this), //<- How pass the activity
                                        // from ReactApplication ?
          new VectorIconsPackage()
      );
    }
  };

  @Override
  public ReactNativeHost getReactNativeHost() {
      return mReactNativeHost;
  }
}

Ответ: вы не передаете Activity из MainApplication в пакет.

Вы вызываете getCurrentActivity() из вашего ReactContextBaseJavaModule

Ответ 6

Мне нужно было изменить устаревший модуль (react-android-360-video) и нашел это полезным...

В android/app/src/main/java/com/webcdpmobiledemo/MainApplication.java я использовал новый формат для добавления пакета:

...
import com.vrvideocomponent.VrVideoViewPackage;

public class MainApplication extends Application implements ReactApplication {

    ...

    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
      ...

      @Override
      protected List<ReactPackage> getPackages() {
        return Arrays.<ReactPackage>asList(
            new MainReactPackage(),
            new VrVideoViewPackage()
        );
      }

      ...
    };

    ...
}

И android/app/src/main/java/com/webcdpmobiledemo/MainActivity.java по существу пуст:

package com.yourproject;

import com.facebook.react.ReactActivity;

public class MainActivity extends ReactActivity {

    /**
     * Returns the name of the main component registered from JavaScript.
     * This is used to schedule rendering of the component.
     */
    @Override
    protected String getMainComponentName() {
        return "YourProject";
    }
}

Затем я изменил файл VrVideoViewPackage, который должен передать reactContext в VrVideoViewManager, который он вызывает:

...

public class VrVideoViewPackage implements ReactPackage {
    ...

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Arrays.<ViewManager>asList(
                new VrVideoViewManager(reactContext)
        );
    }

}

И, наконец, в VrVideoViewManager к активности можно обратиться так:

...

import android.app.Activity;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.bridge.ReactContext;

...

public class VrVideoViewManager extends SimpleViewManager<VrVideoView> {
    ...

    public VrVideoViewManager(ReactContext reactContext) {
        // Do not store mActivity, always getCurrentActivity when needed
        Activity mActivity = mContext.getCurrentActivity();
    }

    @Override
    protected VrVideoView createViewInstance(ThemedReactContext reactContext) {

        // You can also activity from ThemedReactContext
        Activity mActivity = reactContext.getCurrentActivity();

        VrVideoView vrView = new VrVideoView(mActivity);
        vrView.setEventListener(new ActivityEventListener(vrView));
        vrView.pauseVideo();
        return new VrVideoView(mActivity);
    }

    ...
}

Ответ 7

Это не очень ясно из https://github.com/facebook/react-native/blob/master/docs/NativeModulesAndroid.md, но вы можете прочитать исходный код ToastModule в ответном родном дистрибутиве, чтобы увидеть, как они сделайте это github.com/facebook/react-native/blob/daba14264c9f0d29c0327440df25d81c2f58316c/ReactAndroid/src/main/java/com/facebook/react/modules/toast/ToastModule.java#L31-L33

Идея состоит в том, что основное действие будет передано как responseContext в инициализаторе для модуля, вызванного вызовом ReactInstanceManager.builder() в github.com/facebook/react-native/blob/3b4845f93c296ed93c348733809845d587227823/local-cli/generator -android/templates/package/MainActivity.java # L28 через экземпляр MainReactPackage github.com/facebook/react-native/blob/daba14264c9f0d29c0327440df25d81c2f58316c/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java # L49