当前分析的ReactNative版本为0.61.5:
一、NativeModule基本使用
我们知道,要想访问原生提供的功能,需要通过继承NativeModule,并提供相关的方法,只有这样JS层才能直接访问。
举个例子,StatusBarModule类:
/** {@link NativeModule} that allows changing the appearance of the status bar. */
@ReactModule(name = StatusBarModule.NAME)
public class StatusBarModule extends ReactContextBaseJavaModule {
@Override
public String getName() {
return NAME;
}
@ReactMethod
public void setColor(final int color, final boolean animated) {
final Activity activity = getCurrentActivity();
if (activity == null) {
FLog.w(
ReactConstants.TAG,
"StatusBarModule: Ignored status bar change, current activity is null.");
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
UiThreadUtil.runOnUiThread(
new GuardedRunnable(getReactApplicationContext()) {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void runGuarded() {
activity
.getWindow()
.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
if (animated) {
int curColor = activity.getWindow().getStatusBarColor();
ValueAnimator colorAnimation =
ValueAnimator.ofObject(new ArgbEvaluator(), curColor, color);
colorAnimation.addUpdateListener(
new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
activity
.getWindow()
.setStatusBarColor((Integer) animator.getAnimatedValue());
}
});
colorAnimation.setDuration(300).setStartDelay(0);
colorAnimation.start();
} else {
activity.getWindow().setStatusBarColor(color);
}
}
});
}
}
....
}
我们看到,StatusBarModule继承ReactContextBaseJavaModule,而该类父类最终会实现NativeModule接口。
我们再来看getName方法,该方法提供NativeModule的名称,供JS层直接访问。
最后,再来看setColor方法,该方法有个注解ReactMethod,该注解说明该方法直接暴露给JS层,供JS层直接调用。
二、NativeModule如何被注册
既然我们定义了这样的一个Module类,那么这些类是如何被注册进ReactNative框架中的呢?
ReactNative提供了ReactPackage接口,我们看下这个接口的说明:
/**
* Main interface for providing additional capabilities to the catalyst framework by couple of
* different means:
*
* <ol>
* <li>Registering new native modules
* <li>Registering new JS modules that may be accessed from native modules or from other parts of
* the native code (requiring JS modules from the package doesn't mean it will automatically
* be included as a part of the JS bundle, so there should be a corresponding piece of code on
* JS side that will require implementation of that JS module so that it gets bundled)
* <li>Registering custom native views (view managers) and custom event types
* <li>Registering natively packaged assets/resources (e.g. images) exposed to JS
* </ol>
*
* <p>TODO(6788500, 6788507): Implement support for adding custom views, events and resources
*/
public interface ReactPackage {
/**
* @param reactContext react application context that can be used to create modules
* @return list of native modules to register with the newly created catalyst instance
*/
@NonNull
List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext);
/** @return a list of view managers that should be registered with {@link UIManagerModule} */
@NonNull
List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext);
}
要实现这个接口,需要实现createNativeModules和createViewManagers这两个方法,createViewManagers方法我们先忽略,后续会讲。createNativeModules方法需要关注。当实现这个接口,需要实现createNativeModules方法,返回我们自定义的NativeModule类。
这样我们就实现了一个ReactPackage。那我们自定义的ReactPackage如何注册进框架里?
接着分析,在我们使用ReactNative时候,需要继承ReactNativeHost抽象类,该类里有个方法getPackages,返回自定义的ReactPackage就可以。
三、ReactInstanceManager创建流程
在讲解ReactInstanceManager创建之前,最好先了解ReactContext创建流程,可以参考如下这篇文章:
ReactNative源码分析之ReactContext创建流程.
创建ReactContext流程中,会先创建ReactInstanceManager类,我们看下代码:
/* package */ ReactInstanceManager(
Context applicationContext,
@Nullable Activity currentActivity,
@Nullable DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler,
JavaScriptExecutorFactory javaScriptExecutorFactory,
@Nullable JSBundleLoader bundleLoader,
@Nullable String jsMainModulePath,
List<ReactPackage> packages,
boolean useDeveloperSupport,
@Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
LifecycleState initialLifecycleState,
@Nullable UIImplementationProvider mUIImplementationProvider,
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler,
@Nullable RedBoxHandler redBoxHandler,
boolean lazyViewManagersEnabled,
@Nullable DevBundleDownloadListener devBundleDownloadListener,
int minNumShakes,
int minTimeLeftInFrameForNonBatchedOperationMs,
@Nullable JSIModulePackage jsiModulePackage,
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.ctor()");
initializeSoLoaderIfNecessary(applicationContext);
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(applicationContext);
mApplicationContext = applicationContext;
mCurrentActivity = currentActivity;
mDefaultBackButtonImpl = defaultHardwareBackBtnHandler;
mJavaScriptExecutorFactory = javaScriptExecutorFactory;
mBundleLoader = bundleLoader;
mJSMainModulePath = jsMainModulePath;
mPackages = new ArrayList<>();
mUseDeveloperSupport = useDeveloperSupport;
Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstanceManager.initDevSupportManager");
mDevSupportManager =
DevSupportManagerFactory.create