如何从 React Native Android 模块访问 Activity?
Posted
技术标签:
【中文标题】如何从 React Native Android 模块访问 Activity?【英文标题】:How to access Activity from a React Native Android module? 【发布时间】:2015-12-18 16:35:21 【问题描述】:我正在尝试将保持屏幕显示的 android 功能过渡到 React Native。我想我可以用一个简单的模块来做到这一点,但是我不知道如何从所述模块访问当前的 Android Activity。
我需要 Activity 引用,这样我就可以在上面调用.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
我试图通过像 ((Activity)getReactApplicationContext().getBaseContext())
这样的转换来获取活动,但这会引发“无法转换为 Android.app.Activity”错误
【问题讨论】:
关于android和native组件之间通信的例子。 Repo Link 【参考方案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
是我的原生 UI 组件。我定义了一个构造函数,以便我可以传入活动:
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();
REACT NATIVE 0.29.0 更新
这不再是您在本机模块中访问活动的方式。有关迁移说明,请参阅 https://github.com/facebook/react-native/releases/tag/v0.29.0
【讨论】:
这绝对是最好的答案,也正是我在自己的项目中所做的。就我而言,我在 React Native 中使用嵌入式 ZXing QR 码扫描仪,并且需要启动扫描和读取结果(onActivityResult)。这是我的代码的要点,以防它帮助任何有类似问题的人 - gist.github.com/mdp/a501edd93632f13fd9f8 如何将当前活动传递给添加包的新方法。 return Arrays.MainApplication.java
中声明包
@SudoPlz 你是对的。现在您可以扩展ReactContextBaseJavaModule
并调用getCurrentActivity()
。但是,这仅适用于原生模块,不适用于原生 UI 组件。我仍然没有找到在SimpleViewManager
类中获取活动的方法...
如何将活动从 ReactApplication::getPackages() 传递给包?我不明白。我找不到任何明确的例子。【参考方案2】:
我猜ReactContextBaseJavaModule的getCurrentActivity()
方法可能会像下面的代码一样使用,它是从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;
【讨论】:
我在回答中写的链接指定了react-native
的主仓库,它似乎还活着。我也试图找到任何关于它的删除但我不能。你能分享更多关于它的信息吗?
当然 ReactContextBaseJavaModule.getCurrentActivity 在最新的 RN (0.56) 中工作,并返回 RN 应用程序上唯一的一个活动:MainActivity,除非您使用的是 react-native-navigation。【参考方案3】:
已编辑:
问题在于 getReactApplicationContext() 返回的是应用程序的上下文,而不是活动。您不能将 Application 上下文类型转换为 Activity。
这是一个简单的解决方法
由于react-native中通常只有一个activity(Main Activity),我们可以在MainActivity中写一个静态函数来返回这个activity
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()
【讨论】:
这行得通,但我假设你在 GitHub 上看到了评论:github.com/facebook/react-native/issues/…。我正在使用这种方法,并且效果很好。如果您编辑您的答案以描述该方法,我会接受它。 我还没有考虑创建自己的 ReactPackage 实现。既然你已经想通了,如果你能把你的知识传授给社区,对社区会有很大的帮助 刚刚发布了我自己的答案。看看并试一试。 我是 android 新手,你能告诉我如何在 react native 包中调用getCurrentActivity()
吗?我正在寻找集成github.com/msmakhlouf/react-native-android-sms 插件,但由于活动this
,它似乎不起作用。【参考方案4】:
使用 UI 线程上下文获取活动/窗口/装饰视图
在您的类文件中导入包括...
import android.view.WindowManager;
import android.view.Window;
import android.view.View;
在你的类构造函数中...
private static ReactApplicationContext reactContext;
MyModule(ReactApplicationContext context)
super(context);
reactContext = context;
然后在for类方法中...
@ReactMethod
public void doSomethingRequiringWindow()
// get access to current UI thread first
reactContext.getCurrentActivity().runOnUiThread(new Runnable()
@Override
public void run()
Window window = reactContext
.getCurrentActivity().getWindow();
View decorView = reactContext
.getCurrentActivity().getWindow().getDecorView();
// you have access to main ui thread so you can effect
// immediate behavior on window and decorView
);
【讨论】:
【参考方案5】:自定义UI组件,可以在构造函数中获取上下文,后面可以通过context.getCurrentActivity()
获取activity
【讨论】:
兄弟我有点困惑。我正在尝试使用“GoogleSignIn.getAccountForExtension”,但无法将上下文链接到它。请查看***.com/questions/65948333/… @grooot 兄弟链接失效了 请检查这个兄弟。 ***.com/questions/65950331/…【参考方案6】:对于 0.28 及之前的版本,您可以使用相同的字段从 ReactInstanceManagerImpl
的 private @Nullable Activity mCurrentActivity;
、0.29+ 的 ReactContextBaseJavaModule
获取活动。
【讨论】:
【参考方案7】:如何将活动从 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 传递到包。
您从 ReactContextBaseJavaModule 中调用 getCurrentActivity()
【讨论】:
没关系。 ReactContextBaseJavaModule 类有一个 getCurrentActivity() 方法。【参考方案8】:如果您想在 ReactContextBaseJavaModule
子类中获取前台活动的当前实例,请使用:
// class MyReactModule extends ReactContextBaseJavaModule
Activity activity = getCurrentActivity();
它来自ReactContextBaseJavaModule#getCurrentActivity
,它使用reactContext.getCurrentActivity()
注意:
ReactApplicationContext#getCurrentActivity
是包私有。所以你不能使用reactContext.getCurrentActivity()
。
ReactContextBaseJavaModule
受到保护。因此,推导出它可以实现:
protected @Nullable final Activity getCurrentActivity()
return mReactApplicationContext.getCurrentActivity();
ReactApplicationContext
是包私有的(默认访问)。所以你无法得到它:
/* package */ @Nullable Activity getCurrentActivity()
return mCurrentActivity;
布诺斯
既然是
@Nullable
,请务必检查它的可用性:if (reactContext.hasCurrentActivity()) // There is. So get it Activity theActivity = getCurrentActivity();
【讨论】:
有趣,你如何添加现有的原生代码/ui? ***.com/questions/69562692/… 嗯。我会发布答案【参考方案9】:https://github.com/facebook/react-native/blob/master/docs/NativeModulesAndroid.md 不是很清楚,但是你可以阅读 React Native 发行版中 ToastModule 的源代码,看看他们是如何做到的 github.com/facebook/react-native/blob/daba14264c9f0d29c0327440df25d81c2f58316c/ReactAndroid/src /main/java/com/facebook/react/modules/toast/ToastModule.java#L31-L33
这个想法是,主要活动将作为 reactContext 传递给从 github.com/facebook/react-native/blob/3b4845f93c296ed93c348733809845d587227823/local-cli/generator 中调用的 ReactInstanceManager.builder() 调用的模块的初始化程序-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
【讨论】:
没有说明如何获取Activity。【参考方案10】:我需要修改一个过时的模块 (react-android-360-video),发现这很有帮助...
在android/app/src/main/java/com/webcdpmobiledemo/MainApplication.java
中,我使用new格式来添加包:
...
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);
...
【讨论】:
Upto Package 没问题,之后呢?我必须从模块“公共类 DeviceModule 扩展 ReactContextBaseJavaModule”中获取 DeviceToken 一个字符串值作为来自 .js 的“PackageReference.ReactOverridemethod.StringValue”???? @Ramaraju 我不确定我是否理解你的问题,你能改写一下吗?我提供的解决方案是在 ReactPackage 类和 SimpleViewManager 类中提取活动。如果您想从 ReactContextBaseJavaModule 类中提取,您可以查看 efkan 的答案以上是关于如何从 React Native Android 模块访问 Activity?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 React Native Android 模块访问 Activity?
如何从 iOS 中删除 react-native-firebase,同时将其保留在 Android 中?
如何让 React Native 仅在 Android 操作系统上从包中获取/导入功能