[ReactNative]Android原生源码解读(用Markdown写PPT)

尝试了用Markdown写PPT,阅读效果更佳,欢迎品尝:http://www.vmfor.com/md/2019-01-10ed7ba094-ae05-42c7-a998-8b3d5d31f46c.md

[slide style="background-image:url('/img/4.jpg')"]

Android-RN 应用程序

混合开发

热更新

麦文昌 2019-01

[slide style="background-color:#31456A"]

前言

  • 原生APP在性能方面具有优势,而ReactNative更加灵活 {:&.fadeIn}
  • 我们将逐渐把APP往原生方面过渡,包括第三方库以及重要的逻辑和界面。
  • Native层提供React原生模块以供React层使用,包括API,UI和后台任务。

[slide style="background-color:#31456A"]

目录


  • ReactNative启动流程 {:&.fadeIn}
  • ReactNative混合开发
  • Native模块
  • 热更新
  • 启动优化
  • bundle文件安全
  • 总结

[slide style="background-color:#31456A"]

ReactNative启动流程


{:&.zoomIn}

    AppRegistry.registerComponent('cassecapp', () => cassecapp);

[slide style="background-color:#31456A"]

ReactNative启动流程

public class MainApplication extends Application implements ReactApplication {

  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {

    @Override
    protected String getJSBundleFile() {//“index.android.bundle”文件的存储路径
        return CodePush.getJSBundleFile();
    }

    @Override
    public boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG;
    }

    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
        new MainReactPackage(),
        new CodePush(BuildConfig.CODEPUSH_KEY, getApplicationContext(), BuildConfig.DEBUG, "https://codepush.cassmall.com/"),
        ...
      );
    }
  };

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

  @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    GrowingIO.startWithConfiguration(this, new Configuration()
        .useID()
        .trackAllFragments()
        .setChannel("测试")
    );
    CrashReport.initCrashReport(getApplicationContext(), "b8b801654b", true);
  }
}

[slide style="background-color:#31456A"]

ReactNative启动流程


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 "cassecapp";
    }

  ...
}

[slide style="background-color:#31456A"]

ReactNative启动流程

package com.facebook.react;
public abstract class ReactActivity extends Activity
    implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {

  private final ReactActivityDelegate mDelegate;

  protected ReactActivity() {
    mDelegate = createReactActivityDelegate();
  }

  ...

  /**
   * Called at construction time, override if you have a custom delegate implementation.
   */
  protected ReactActivityDelegate createReactActivityDelegate() {
    return new ReactActivityDelegate(this, getMainComponentName());
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mDelegate.onCreate(savedInstanceState);
  }

  @Override
  protected void onPause() {
    super.onPause();
    mDelegate.onPause();
  }

  @Override
  protected void onResume() {
    super.onResume();
    mDelegate.onResume();
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    mDelegate.onDestroy();
  }

  @Override
  public void onActivityResult(int requestCode, int resultCode, Intent data) {
    mDelegate.onActivityResult(requestCode, resultCode, data);
  }

  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
    return mDelegate.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
  }
  ...
}

[slide style="background-color:#31456A"]

ReactNative启动流程

package com.facebook.react
/**
 * Delegate class for {@link ReactActivity} and {@link ReactFragmentActivity}. You can subclass this
 * to provide custom implementations for e.g. {@link #getReactNativeHost()}, if your Application
 * class doesn't implement {@link ReactApplication}.
 */
public class ReactActivityDelegate {

  ...

  private final @Nullable Activity mActivity;
  private final @Nullable FragmentActivity mFragmentActivity;
  private final @Nullable String mMainComponentName;

  private @Nullable ReactRootView mReactRootView;

  public ReactActivityDelegate(Activity activity, @Nullable String mainComponentName) {
    mActivity = activity;
    mMainComponentName = mainComponentName;
    mFragmentActivity = null;
  }

  protected ReactRootView createRootView() {
    return new ReactRootView(getContext());
  }

  protected ReactNativeHost getReactNativeHost() {
    return ((ReactApplication) getPlainActivity().getApplication()).getReactNativeHost();
  }

  public ReactInstanceManager getReactInstanceManager() {
    return getReactNativeHost().getReactInstanceManager();
  }

  protected void onCreate(Bundle savedInstanceState) {
    if (mMainComponentName != null) {
      loadApp(mMainComponentName);
    }
    mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
  }

  protected void loadApp(String appKey) {
    if (mReactRootView != null) {
      throw new IllegalStateException("Cannot loadApp while app is already running.");
    }
    mReactRootView = createRootView();//ReactRootView: 加载React视图的容器
    mReactRootView.startReactApplication(
      //ReactInstanceManager: 负责加载JS,并且管理原生与JS通信
      getReactNativeHost().getReactInstanceManager(),
      appKey,//“cassecapp”
      getLaunchOptions());//加载界面时的一些设置
    getPlainActivity().setContentView(mReactRootView);
  }

  ...
}

[slide style="background-color:#31456A"]

ReactNative启动流程

package com.facebook.react;
/**
 * Simple class that holds an instance of {@link ReactInstanceManager}. This can be used in your
 * {@link Application class} (see {@link ReactApplication}), or as a static field.
 */
public abstract class ReactNativeHost {

  private final Application mApplication;
  private @Nullable ReactInstanceManager mReactInstanceManager;

  protected ReactNativeHost(Application application) {
    mApplication = application;
  }

  /**
   * Get the current {@link ReactInstanceManager} instance, or create one.
   */
  public ReactInstanceManager getReactInstanceManager() {
    if (mReactInstanceManager == null) {
      ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_START);
      mReactInstanceManager = createReactInstanceManager();
      ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_END);
    }
    return mReactInstanceManager;
  }

  protected ReactInstanceManager createReactInstanceManager() {
    ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START);
    ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
      .setApplication(mApplication)//必要
      .setJSMainModulePath(getJSMainModuleName())//必要,对应index.js
      .setUseDeveloperSupport(getUseDeveloperSupport()//必要
      .setRedBoxHandler(getRedBoxHandler())
      .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
      .setUIImplementationProvider(getUIImplementationProvider())
      .setJSIModulesPackage(getJSIModulePackage())
      .setInitialLifecycleState(LifecycleState.BEFORE_CREATE);//必要,声明加载时机

    for (ReactPackage reactPackage : getPackages()) {
      builder.addPackage(reactPackage);//提供给RN交互的原生模块
    }

    String jsBundleFile = getJSBundleFile();
    if (jsBundleFile != null) {
      // 外部存储目录下的index.android.bundle文件
      builder.setJSBundleFile(jsBundleFile);
    } else {
      // assets/index.android.bundle
      builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
    }
    ReactInstanceManager reactInstanceManager = builder.build();
    ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END);
    return reactInstanceManager;
  }

}

[slide style="background-color:#31456A"]

ReactNative启动流程


{:&.zoomIn}

ReactRootView {:.highlight}

ReactInstanceManager {:.highlight}

[slide style="background-color:#31456A"]

ReactNative混合开发


如何在一个在原生界面上显示React组件?

.

.

[slide style="background-color:#31456A"]

ReactNative混合开发


{:&.zoomIn}

import React from 'react';
import {AppRegistry, StyleSheet, Text, View} from 'react-native';

export default class HelloWorld extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.hello}>Hello, World</Text>
      </View>
    );
  }
}
// .../index.js
AppRegistry.registerComponent('HelloWorld', () => HelloWorld);
AppRegistry.registerComponent('RNOnLayout', () => RNOnLayout);
AppRegistry.registerComponent('ExternalBundle', () => ExternalBundle);

[slide style="background-color:#31456A"]

ReactNative混合开发

public class HelloWorldActivity extends Activity {

    private ReactInstanceManager mReactInstanceManager;
    private ReactRootView mReactRootView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mReactRootView = new ReactRootView(this);
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setBundleAssetName("index.android.bundle")//assets 文件目录下的bundle文件
                .setJSMainModulePath("index")//对应index.js
                .addPackage(new MainReactPackage())
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
        //  "HelloWorld" 对应index.js中的:
        // AppRegistry.registerComponent('HelloWorld', () => HelloWorld);
        mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null);

        setContentView(mReactRootView);
    }
}

[slide style="width:400"]

ReactNative混合开发

.

.

[slide style="background-color:#31456A"]

ReactNative混合开发

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:background="#f2f2f2"
        android:gravity="center"
        android:text="这里是原生部分"
        android:textColor="#000000" />

    <com.facebook.react.ReactRootView
        android:id="@+id/react_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

[slide style="background-color:#31456A"]

ReactNative混合开发

public class NativeReactActivity extends BaseReactActivity {

    private ReactInstanceManager mReactInstanceManager;
    private ReactRootView mReactRootView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_react_test);
        //找到布局中的ReactRootView
        mReactRootView = findViewById(R.id.react_view);
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setBundleAssetName("index.android.bundle") //assets 文件目录下的bundle文件
                .setJSMainModulePath("index")  //对应index.js
                .addPackage(new MainReactPackage())
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
        mReactRootView.startReactApplication(mReactInstanceManager, "RNOnLayout", null);
    }
}

[slide style="background-color:#31456A"]

ReactNative混合开发

.

.

[slide style="background-color:#31456A"]

ReactNative混合开发

public class ExternalReactActivity extends BaseReactActivity {

    private ReactInstanceManager mReactInstanceManager;
    private ReactRootView mReactRootView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_react_test);
        //找到布局中的ReactRootView
        mReactRootView = findViewById(R.id.react_view);
        //获取bundle文件路径:在外部存储空间"test"文件夹下
        String path = Environment.getExternalStorageDirectory() + "/test/index.android.bundle";
        //初始化ReactInstanceManager
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                // .setBundleAssetName("index.android.bundle")
                .setJSMainModulePath("index") //对应index.js
                .addPackage(new MainReactPackage())//原生模块
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setJSBundleFile(path) //设置文件路径
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();

        //"ExternalBundle" 对应js中 :AppRegistry.registerComponent('ExternalBundle', () => ExternalBundle);
        mReactRootView.startReactApplication(mReactInstanceManager, "ExternalBundle", null);
    }
}

[slide style="background-color:#31456A"]

ReactNative混合开发

.

.

[slide style="background-color:#31456A"]

Native原生模块

.

.

[slide style="background-color:#31456A"]

Native原生模块(UI)

/**
* 1.创建一个ViewManager类
* 例子: 实现一个图片显示器
*/
public class RCTImageManager extends SimpleViewManager<RCImageView> {

    private static final String RC_IMAGE_VIEW = "RCImageView";

     /**
     * 2. 实现getName方法,返回该组件的名字
     */
    @Override
    public String getName() {
        return RC_IMAGE_VIEW;
    }

    /**
     * 3. 实现createViewInstance方法,创建视图,并初始化为默认的状态
     */
    @Override
    protected RCImageView createViewInstance(ThemedReactContext reactContext) {
        return new RCImageView(reactContext, Fresco.newDraweeControllerBuilder(), null, null);
    }

  /*
  * 4. 通过@ReactProp(或@ReactPropGroup)注解来导出属性的设置方法。
  */

    //url属性 src = {'https://www.baidu.com/img/bd_logo1.png'}
    @ReactProp(name = "src")
    public void setSrc(ReactImageView view, @Nullable String sources) {
        WritableMap map = Arguments.createMap();
        map.putString("uri", sources);
        WritableArray array = Arguments.createArray();
        array.pushMap(map);
        //转换成ReadableArray传给View
        view.setSource(array);
    }

    @ReactProp(name = "borderRadius", defaultFloat = 0f)
    public void setBorderRadius(ReactImageView view, float borderRadius) {
        view.setBorderRadius(borderRadius);
    }

    @ReactProp(name = ViewProps.RESIZE_MODE)
    public void setResizeMode(ReactImageView view, @Nullable String resizeMode) {
        view.setScaleType(ImageResizeMode.toScaleType(resizeMode));
    }

    /**
     * 注册回调事件
     */
    @javax.annotation.Nullable
    @Override
    public Map<String, Object> getExportedCustomBubblingEventTypeConstants() {
        return MapBuilder.<String, Object>builder()
                //把topChange注册到系统中
                .put("topChange",
                        MapBuilder.of(
                                "phasedRegistrationNames",
                                MapBuilder.of("bubbled", "onChange")))//onChange是暴露给 R 层的接口
                .build();
    }

}

[slide style="background-color:#31456A"]

Native原生模块(UI)

参数对照表

|Java | JavaScript|
:-------|:-------|:------
布尔型|Boolean | Bool
整形|Integer | Number
双精度浮点型|Double | Number
浮点型|Float | Number
字符串|String | String
回调|Callback | function
映射|ReadableMap | Object
数组|ReadableArray | Array

[slide style="background-color:#31456A"]

Native原生模块(UI)

@Override
public class NativePackage implements ReactPackage {
    /**
     * 5.在ReactPackage中注册ViewManager
     */
    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Arrays.<ViewManager>asList(
                new RCTImageManager() //原生图片显示UI
        );
    }
}

[slide style="background-color:#31456A"]

Native原生模块(UI)

//6.实现对应的JavaScript模块
class NativeUIExample extends Component {

  static navigationOptions = {
    title: 'NativeUIExample',
  };

  _onButtonPress(){
      alert("onButtonPress");
  }

  render() {
    return (
      <View style={styles.container}>
        <RCImageView
          src = {'http://www.casstime.com/images/Product2.jpg'}
          borderRadius= {25}
          style={{width: 300, height: 225}}
          onChangeMessage = {this._onButtonPress}
        />
      </View>
    );
  }
  ...
}

[slide style="background-color:#31456A"]

Native原生模块(UI)

.

.

[slide style="background-color:#31456A"]

Native原生模块(API)

原生模块给React层提的供API:

  • 原生的第三方库API {:&.fadeIn}
  • 可复用的原生代码
  • 高性能的、多线程的原生代码、譬如图片处理、数据库、或者各种高级扩展等等

[slide style="background-color:#31456A"]

Native原生模块(API)

/*
* 1. 创建一个新的Java类继承ReactContextBaseJavaModule,并命名为ToastModule.java
* 例子: 实现一个吐司模块
*/
public class ToastModule extends ReactContextBaseJavaModule {

  private static final String TOAST_MODULE = "ToastExample";

    private static final String DURATION_SHORT_KEY = "SHORT";
    private static final String DURATION_LONG_KEY = "LONG";

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

    //2. 实现getName方法,返回该模块的名字
    @Override
    public String getName() {
        return TOAST_MODULE;
    }

    //3. 实现getConstants方法,返回需要导出给JavaScript使用的常量
    @Nullable
    @Override
    public Map<String, Object> getConstants() {
        Map<String, Object> constants = new HashMap<>();
        constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
        constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
        return constants;
    }

    //4. 使用注解@ReactMethod导出一个方法给JavaScript使用
    @ReactMethod(isBlockingSynchronousMethod = false)
    public void show(String message, int duration) {
        Toast.makeText(getReactApplicationContext(), message, duration).show();
    }
}

[slide style="background-color:#31456A"]

Native原生模块(API)

public class NativePackage implements ReactPackage {

    /**
     * 5.在ReactPackage中注册ToastModule模块
     */
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        return Arrays.<NativeModule>asList(
                new ToastModule(reactContext),//吐司模块
    }
}

[slide style="background-color:#31456A"]

Native原生模块(API)


{:&.fadeIn}

// ToastExample.js
// 通常我们都会把原生模块封装成一个 JavaScript 模块
import { NativeModules } from "react-native";

module.exports = NativeModules.ToastExample;
// 在JavaScript代码中可以这样调用:
import ToastExample from "./ToastExample";

ToastExample.show("Awesome", ToastExample.SHORT);

[slide style="background-color:#31456A"]

Native原生模块(API)

其他特性

  • 回调函数:com.facebook.react.bridge.Callback
  • Promises: 原生模块还可以使用Promise来简化代码
  • 事件发射器:RCTDeviceEventEmitter
  • 生命周期监听:ActivityEventListener&LifecycleEventListener

[slide style="background-color:#31456A"]

Native原生模块(Task)

/*
* 1.创建一个类继承HeadlessJsTaskService
* 例子: 模拟网络状态监听
*/
public class OnNetworkChangeTaskService extends HeadlessJsTaskService {

    /**
     * 2.配置任务
     */
    @Nullable
    @Override
    protected HeadlessJsTaskConfig getTaskConfig(Intent intent) {
        if (intent==null)return null;
        Bundle extras = intent.getExtras();
        if (extras == null) return  null;
        HeadlessJsTaskConfig taskConfig = new HeadlessJsTaskConfig(
                "NetworkChangeTask", //任务名称
                Arguments.fromBundle(extras), // 任务参数
                5000, //任务超时时间
                true // 是否允许在前台运行,默认false
        );
        return taskConfig;
    }
}

[slide style="background-color:#31456A"]

Native原生模块(Task)

/*
* 3.在APP切换到后台的时候开启后台任务监听网络状态,
* 并且在网络发生改变时执行JavaScript任务;
*/

Intent serviceIntent = new Intent(context, OnNetworkChangeTaskService.class);
serviceIntent.putExtra("hasInternet", hasInternet);
context.startService(serviceIntent);

[slide style="background-color:#31456A"]

Native原生模块(Task)

// 5. 创建执行任务的NetworkChangeTask.js文件
module.exports = async (taskData) => {
    if (taskData["hasInternet"]) {
        console.log('网络可用')
    }else{
        console.log('网络不可用')
    }
};
/*
*5.在index.js中引用创建执行任务的NetworkChangeTask.js文件;
*  并注册`NetworkChangeTask`任务
*/
import NetworkChangeTask from './NetworkChangeTask';

AppRegistry.registerHeadlessTask("NetworkChangeTask", () => require("NetworkChangeTask"));

[slide style="background-color:#31456A"]

Native原生模块(Task)

module.exports = async (taskData) => {
    if (taskData["hasInternet"]) {
        console.log('网络可用')
    }else{
        console.log('网络不可用')
    }
};

[slide style="background-color:#31456A"]

热更新

ReactNative热更新原理:

  1. 版本更新时,从服务器重新拉取bundle文件和图片资源到本地; {:&.fadeIn}
  2. 在setJSBundleFile()方法中返回新的bundle文件路径;
  3. ReactInstanceManager加载新的bundle文件。

[slide style="background-color:#31456A"]

热更新 第三方库

react-native-pushy

ReactNative中文网推出的代码热更新服务:

  1. 每个应用每个月不超过10000次下载; {:&.fadeIn}
  2. 基于bsdiff算法创建的超小更新包,通常版本迭代后在1-10KB之间,避免数百KB的流量消耗;
  3. 支持崩溃回滚,安全可靠;
  4. 开放API,提供更高扩展性;
  5. 跨越多个版本进行更新时,只需要下载一个更新包,不需要逐版本依次更新。

[slide style="background-color:#31456A"]

热更新 第三方库

react-native-code-push

微软推出的代码热更新服务:

  1. 支持版本回滚; {:&.fadeIn}
  2. 支持图片增量更新;
  3. 官方服务器在国外,国内访问受限,建议自建服务;
  4. 没有开放后台源码。

[slide style="background-color:#31456A"]

热更新

搭建自己的热更新服务

  1. 打包bundle文件和图片文件,并上传服务器; {:&.fadeIn}
  2. 使用bsdiff对比两个版本的bundle文件得到补丁文件;
  3. 检查更新,下载补丁文件和图片;
  4. 使用bspatch对文件打补丁;
  5. 增量更新bundle文件和图片文件(Bsdiff工具);
  6. ReactInstanceManager空闲时重新加载bundle文件(或重启app时生效)。

[slide style="background-color:#31456A"]

启动优化

jsBundle文件预加载

  1. ReactRootView.startReactApplication() {:&.fadeIn}
  2. ReactInstanceManager.recreateReactContextInBackground()
  3. ReactInstanceManager.runCreateReactContextOnNewThread()
public void startReactApplication(
      ReactInstanceManager reactInstanceManager,
      String moduleName,
      @Nullable Bundle initialProperties) {
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "startReactApplication");
    try {
      ...
      if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
      //后台创建ReactContext(加载jsBundle)
        mReactInstanceManager.createReactContextInBackground();
      }
      attachToReactInstanceManager();
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    }
  }

[slide style="background-color:#31456A"]

启动优化

jsBundle文件预加载

private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
    ...
  //开启子线程
    mCreateReactContextThread =
        new Thread((Runnable)()-> {
                ...
                try {
                  Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
                  final ReactApplicationContext reactApplicationContext =
                      createReactContext(
                          //加载jsBundle
                          initParams.getJsExecutorFactory().create(),
                          initParams.getJsBundleLoader());
                  ...

                  Runnable setupReactContextRunnable = new Runnable() {()->{
                      ...
                      //在主线程设置ReactRootView
                      setupReactContext(reactApplicationContext);
                      ...
                  }};
                  reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable);
                  UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable);
                } catch (Exception e) {
                  mDevSupportManager.handleException(e);
                }
              }
            });
    ReactMarker.logMarker(REACT_CONTEXT_THREAD_START);
    mCreateReactContextThread.start();
}

[slide style="background-color:#31456A"]

启动优化

  • 全局单例的ReactInstanceManager {:&.fadeIn}
  • ReactInstanceManager的创建时机

[slide style="background-color:#31456A"]

启动优化

  • 预加载ReactRootView {:&.fadeIn}
  • 缓存并复用ReactRootView

[slide style="background-color:#31456A"]

bundle文件安全

裸奔的jsBundle

  1. 网络接口安全。 {:&.fadeIn}

  2. jsBundle防篡改。为防止篡改js入侵app业务,需对jsBundle做签名校验,
    一是下载文件后校验其完整性,二是每次加载jsBundle时校验。

  3. jsBundle业务安全。因为jsBundle是明文,所以业务中需要进行加解密等
    敏感措施就不能在js层实现,应该在native层实现加解密暴露给js接口调用。

[slide style="background-color:#31456A"]

总结

  • ReactNative启动流程 {:&.fadeIn}
  • ReactNative混合开发
  • Native模块
  • 热更新
  • 启动优化
  • bundle文件安全

[slide style="background-color:#31456A"]


End

「Talk is cheap. Show me the code」

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342