首先看JSBundleLoader,
public static JSBundleLoader createFileLoader(final String fileName) {
return new JSBundleLoader() {
@Override
public void loadScript(CatalystInstanceImpl instance) {
instance.loadScriptFromFile(fileName,fileName);
}
@Override
public String getSourceUrl() {
return fileName;
}
};
}
JSBundlerLoader本身是用来加载JS Bundle的,本质上它还是调用CatalyInstanceImpl总的native方法走到C++层
/* package */ native void loadScriptFromAssets(AssetManager assetManager,String assetURL);
/* package */ native void loadScriptFromFile(String fileName,String sourceURL);
/* package */ native void loadScriptFromOptimizedBundle(String path,String sourceURL,int flags);
在XReactInstanceManagerImpl执行createReactContext的时候,会调用到CatalyInstanceImpl的runJSBundle
而runJSBundler本质还是调用mJSBundleLoader.loadScript(CatalystInstanceImpl.this);去加载JS
就这样传递到C++层,结合JavaScriptCore对JS进行解释执行了
对于开发模式我们看到在XReactInstanceManagerImpl中会执行到onJSBundleLoadedFromServer,
先从服务端获取JSBundle
注意:实际加载请求等应该发生于C++端
以上参考自:http://www.jianshu.com/p/17d6f6c57a5c
现在我想知道ReactNativeHOST是如何被利用的,如何通过这家伙拿到Bundle的路径,我们又如何自定义Bundle的路径
要回答这个问题,首先先补课:
<application
android:allowBackup="true"
android:name=".MainApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
我们自定义了一个MainApplication,
Application application = getApplication();
if(application instanceof MainApplication){
Toast.makeText(application,"是MainApplication的实例",Toast.LENGTH_LONG).show();
}else {
Toast.makeText(application,"不是MainApplication的实例",Toast.LENGTH_LONG).show();
}
结果显示是MainAppction的实例,所有我们首先明确这一点
我们现在先看看使用RN的第一张写法
public class MainActivity extends ReactActivity {
@Override
protected String getMainComponentName() {
..
}
@Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
// @Override
// protected List<ReactPackage> getPackages() {
// return Arrays.<ReactPackage>asList(
// new MainReactPackage()
// );
}
}
在里面我们会获取到一个ReactNativeHost
protected ReactNativeHost getReactNativeHost() {
return ((ReactApplication) getPlainActivity().getApplication()).getReactNativeHost();
}
所有采用这种方式我们要把MainApplication实现ReactApplication,否则会被强制转换异常的,看图
我们注意到我们是从当前Activity的Application是获取的
所有我们在MainApplication实现ReactApplication接口,那么通过当前Activity就能拿到MainApplication,从而
调用到接口中的getReactNativeHost了
public class MainApplication extends Application implements ReactApplication {
private Application context;
@Override
public ReactNativeHost getReactNativeHost() {
context = this;
ReactNativeHost host = null;
if (host==null){
host = new ReactNativeHost(context) {
@Override
protected boolean getUseDeveloperSupport() {
return false;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new IntentReactPackage()
);
}
};
}
return host;
}
}
经过一系列的调用会执行到
protected ReactInstanceManager createReactInstanceManager() {
ReactInstanceManager.Builder builder = ReactInstanceManager.builder()
.setApplication(mApplication)
.setJSMainModuleName(getJSMainModuleName())
.setUseDeveloperSupport(getUseDeveloperSupport())
.setRedBoxHandler(getRedBoxHandler())
.setUIImplementationProvider(getUIImplementationProvider())
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE);
for (ReactPackage reactPackage : getPackages()) {
builder.addPackage(reactPackage);
}
String jsBundleFile = getJSBundleFile();
if (jsBundleFile != null) {
builder.setJSBundleFile(jsBundleFile);
} else {
builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
}
return builder.build();
}
注意红色的两句,就是我们利用ReactNativeHost里指定的路径的代码,
第二种写法
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mReactRootView = new ReactRootView(this); mReactInstanceManager = ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModuleName("index.android") .addPackage(new MainReactPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) .build(); mReactRootView.startReactApplication(mReactInstanceManager,"HelloWorld",null); setContentView(mReactRootView); }
这个是我们自己new ReactInstanceManager的,我们传递的BudlerAssetName会被组成Bundle的路径
public Builder setBundleAssetName(String bundleAssetName) { mJSBundleAssetUrl = (bundleAssetName == null ? null : "assets://" + bundleAssetName); mJSBundleLoader = null; return this; }
这中写法我猜测可能没有利用到ReactNativeHOST吧
本文另外参考了:http://www.cnblogs.com/zhang740/p/5978323.html
http://blog.csdn.net/ssksuke/article/details/52403754?locationNum=6