ReactNative混合开发,Facebook官网文档比较精简,坑比较多,根据此文档,作为初学者并不能顺利的将ReactNative引入Android项目,且不能了解ReactNative是以一种怎样的形式存在Native项目中。

此为开篇,解说官方引入方案,附带了我的踩坑经验,引导小诀窍,让你傻瓜式一键集成ReactNative。后续文章会介绍云集项目中React的实践,优化方案。这是一篇入门篇,没有门槛,何来高楼。

希望这一个系列的React文章能够帮助大家快速了解ReactNative的混合开发与掌握云集App中React的使用,快速定位相关问题,人人成为ReactNative小能手。

本文需要有初步的React Native基础,至少有能够运行一个React Native demo的环境与项目。

适用人群:Android工程师 Or 对ReactNative感兴趣的开发者

加载原理

(1)、Facebook有能够将页面的JS,通过自研的Metro工具转化一个bundle的压缩文件;
(2)、同时开发了一套能够解析Bundle文件中JS转化为Native行为的黑盒子工具API;
(3)、集成至于Native的根本原理,就是将Facebook的黑盒API引入到Android项目,同时能够加载Bundle文件;
(4)、集成ReactNative到原生项目分两大步:第一步引入依赖,第二步初始化ReactNative,加载页面;

1、正确引入ReactNative相关依赖

1.1、准备,组建一个React Native项目

  • 首先按照开发环境搭建教程来安装 React Native 在 Android 平台上所需的一切依赖软件,创建一个React项目,
//初始化创建项目-AwesomeProject
npm init AwesomeProject
//下载React相关依赖,React Native (JS, Android binaries)等
npm install
//安装项目
react-native run-android

项目中package.json文件,可修改指定的React Native版本号

  • 利用Android Studio模式打开AwesomeProject项目,编译Gradle

小技巧:成功编译后,对引入第三方lib,打包成aar,非常便捷

1.2、集成React Native

  • Android项目Lib or App下创建node_modules\react-native\android目录,并从AwesomeProject项目中node_modules\react-native\android目录下所有的文件拷贝至该目录

1.3、集成配置 maven

  • 你的 app 中 build.gradle 文件中添加 React Native 依赖:
dependencies {implementation 'com.android.support:appcompat-v7:27.1.1'...//如要指定特定的 React Native 版本,可以用具体的版本号替换 +,当然前提是你从 npm 里下载的是这个版本。implementation "com.facebook.react:react-native:+" // From node_modules
}
  • 在项目的 build.gradle 文件中为 React Native 添加一个 maven 依赖的入口,必须写在 “allprojects” 代码块中:

    allprojects {repositories {maven {// All of React Native (JS, Android binaries) is installed from npm//上述项目中引入react-native的相对目录位置url "$rootDir/xxx/node_modules/react-native/android"}...}...
    }
    

$rootDir表示项目根目录

1.4、集成React Native的基础Lib

  • 你的 app 中 build.gradle 文件中添加-图片依赖
dependencies {...//匹配图片框架与对应的版本号implementation 'com.facebook.fresco:animated-gif:2.0.0'implementation "com.facebook.fresco:webpsupport:2.0.0"
}

匹配版本号,从引入的ReactNative文件中,找出react-native-0.61.3.pom,查询对应的fresco的版本号

//打开此文件node_modules\...\react-native\react-native-0.61.3.pom查看各个依赖版本号
...
<dependency><groupId>com.facebook.fresco</groupId><artifactId>imagepipeline-okhttp3</artifactId><version>2.0.0</version><scope>compile</scope>
</dependency>
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>3.12.1</version><scope>compile</scope>
</dependency>
...
  • 引入第三方lib【推荐AAR方式 or 源码方式 】
//app 中 `build.gradle` 文件中添加 React Native 依赖
dependencies {...implementation(name: 'react-native-video-5.0.2', ext: 'aar')implementation(name: 'react-native-vector-icons-6.6.0', ext: 'aar')..........
}

小技巧:

1、通过Android Studio打开项目,在对应lib中,通过Gradle-assemble指令生成aar

2、第三方依赖某些适合并不完成与你的项目匹配,源码更容易修改调整

2、初始化ReactNative,加载开发页面Bundle

2.1、初始化React

applicatiion中,so初始化,ReactNativeHost初始化

public class MainApplication extends Application implements ReactApplication {private final ReactNativeHost mReactNativeHost =new ReactNativeHost(this) {/*** 开发模式开发【红屏模式开关】** @return*/@Overridepublic boolean getUseDeveloperSupport() {return BuildConfig.DEBUG;}/*** 自定义React package链接处** @return*/@Overrideprotected List<ReactPackage> getPackages() {@SuppressWarnings("UnnecessaryLocalVariable")List<ReactPackage> packages = new PackageList(this).getPackages();// Packages that cannot be autolinked yet can be added manually here, for example:// packages.add(new MyReactNativePackage());return packages;}/***  开发模式,地址路径* @return*/@Overrideprotected String getJSMainModuleName() {return "index";}};@Overridepublic ReactNativeHost getReactNativeHost() {return mReactNativeHost;}@Overridepublic void onCreate() {super.onCreate();/*** React相关so初始化*/SoLoader.init(this, /* native exopackage */ false);}}

需要在ReactNativeHost下重写getJSBundleFile(),指定bundle路径,否则将加载默认文件【assets://index.android.bundle】

2.2、加载React开发的页面,

public class MainActivity extends ReactActivity {@Overrideprotected String getMainComponentName() {// Js入口AppRegistry.registerComponent中的appKey参数return "rnBuyer";}
}

到此为止普通的官方版的ReactNative已经集成完成,是不是很简单;【业务适用版集成方式,请关注后续React文章】

2.3、页面加载流程分解

①、React页面继承ReactActivity,逐步往上查看源码,可以看到ReactActivityDelegate.java中

........
//要么加载bundle入口
protected void loadApp(String appKey) {mReactDelegate.loadApp(appKey);getPlainActivity().setContentView(mReactDelegate.getReactRootView());}
.....

②、再次深入,facebook内部加载过程,ReactRootView.java呈现

ReactRootView.java
...../*** Schedule rendering of the react component rendered by the JS application from the given JS* module (@{param moduleName}) using provided {@param reactInstanceManager} to attach to the JS* context of that manager. Extra parameter {@param launchOptions} can be used to pass initial* properties for the react component.*/public void startReactApplication(ReactInstanceManager reactInstanceManager,String moduleName,@Nullable Bundle initialProperties,@Nullable String initialUITemplate) {//...无关代码//子线程加载bundlemReactInstanceManager.createReactContextInBackground();//...无关代码}
.....

③、在深入,ReactInstanceManager类中选择对应的bundle来源,区分开发模式情况,与release情况

-----------------ReactInstanceManager.java
//主线程选择bundle
@ThreadConfined(UI)
private void recreateReactContextInBackgroundInner() {Log.d(ReactConstants.TAG, "ReactInstanceManager.recreateReactContextInBackgroundInner()");PrinterHolder.getPrinter().logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: recreateReactContextInBackground");UiThreadUtil.assertOnUiThread();//开发者模式,取bundle方式, application中给mUseDeveloperSupport初始化赋值模式if (mUseDeveloperSupport && mJSMainModulePath != null) {final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();if (!Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {if (mBundleLoader == null) {mDevSupportManager.handleReloadJS();} else {//mDevSupportManager.isPackagerRunning()后面React加载会优先检查metro服务器是否打通mDevSupportManager.isPackagerRunning(new PackagerStatusCallback() {@Overridepublic void onPackagerStatusFetched(final boolean packagerIsRunning) {UiThreadUtil.runOnUiThread(new Runnable() {@Overridepublic void run() {//metro通,会优先加载服务器的bundle,否则加载本地if (packagerIsRunning) {//服务器bundlemDevSupportManager.handleReloadJS();} else if (mDevSupportManager.hasUpToDateJSBundleInCache()&& !devSettings.isRemoteJSDebugEnabled()) {// If there is a up-to-date bundle downloaded from server,// with remote JS debugging disabled, always use that.onJSBundleLoadedFromServer(null);} else {// If dev server is down, disable the remote JS debugging.devSettings.setRemoteJSDebugEnabled(false);//本地bundlerecreateReactContextInBackgroundFromBundleLoader();}}});}});}return;}}//release模式下,加载bundle路径recreateReactContextInBackgroundFromBundleLoader();}-----------------release模式下继续加载bundle,ReactInstanceManager.java
//......无关代码
@ThreadConfined(UI)
private void runCreateReactContextOnNewThread(final ReactInstanceManager.ReactContextInitParams initParams) {//.....无关代码//加载bundlefinal ReactApplicationContext reactApplicationContext =createReactContext(initParams.getJsExecutorFactory().create(),initParams.getJsBundleLoader());//.....无关代码}
//.....无关代码
private ReactApplicationContext createReactContext(JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {//.....无关代码//加载初始化赋值的本地bundlecatalystInstance.runJSBundle();//.....无关代码}//.....无关代码-----------------DevServerHelper.java meto服务间相关交互检查实践类....
//通过http://localhost:8081/status 检测metro是否通顺
public void isPackagerRunning(final PackagerStatusCallback callback)....

④、回顾整个流程,整个流程图如图:

2.4、升级到ReactNative 0.61.3版本采坑

  • 仅支持so的armeabi_v7架构

  • 当Android 4.4系统中报xx.so找不到,但是在Android高版本中加载正常

    解决思路:xx.so与腾讯的xx.so冲突,报xx.so找不到,解析Apk,对比so的Md5后,发现xx.so非facebook提供的so,分析React的so加载流程,走串行链式加载方式

总结:

此次分享内容就是关于快速集成React到Native-Android的方式与踩坑,和解析了bundle在Android APP中是通过怎么流程进行加载的,方便大家快速上手集成,关于在云集项目中ReactNative是怎么封装使用的,见后续分享。

参考文献

2.4、升级到ReactNative 0.61.3版本采坑

  • 仅支持so的armeabi_v7架构

  • 当Android 4.4系统中报xx.so找不到,但是在Android高版本中加载正常

    解决思路:xx.so与腾讯的xx.so冲突,报xx.so找不到,解析Apk,对比so的Md5后,发现xx.so非facebook提供的so,分析React的so加载流程,走串行链式加载方式

总结:

此次分享内容就是关于快速集成React到Native-Android的方式与踩坑,和解析了bundle在Android APP中是通过怎么流程进行加载的,方便大家快速上手集成,关于在云集项目中ReactNative是怎么封装使用的,见后续分享。

参考文献

1、React Native中文官网

集成 React Native 到现有Android项目相关推荐

  1. 混合开发架构|Android工程集成React Native、Flutter、ReactJs

    混合开发架构|Android工程集成React Native.Flutter.ReactJs 架构设计说明 创建安卓原生工程 创建Flutter 集成嵌入原生工程 创建React Native 解决R ...

  2. android 回退函数,详解React Native监听Android回退按键与程序化退出应用

    详解React Native监听Android回退按键与程序化退出应用 发布时间:2020-09-29 09:25:52 来源:脚本之家 阅读:137 作者:lqh 详解React Native监听A ...

  3. 回退监听android,详解React Native监听Android回退按键与程序化退出应用

    详解React Native监听Android回退按键与程序化退出应用 前言 我们知道Android回退按键,会控制页面返回, 并且退出应用并非真正意义退出,仍在后台运行,所以在某些场景下需要监控an ...

  4. 在原有Android项目中快速集成React Native

    前言 对于现有的大多数项目来说都不是从头构建的,而要在原有项目的基础上引入React Native则肯定和用react-native init xxx创建工程不同.因此下面就来说下具体操作.不过在真正 ...

  5. React Native 与 嵌入Android原生与Activity页面互相跳转

    前言 RN作为混合开发,肯定需要与原生直接的页面跳转,这里也属于和原生端通信的知识模块.我们知道Android的页面跳转是通过Intent.Rn是通过路由,而两者直接页面互相跳转就需要原生借助JS暴露 ...

  6. react native实现兼容Android与ios的视频播放器

    呦吼-,我来啦,这是我的第一篇文章,当然是福利啦,项目代码可以直接运行使用的呀,这种便宜尽情挥霍去吧-.好了装嫩结束,来点实际的,这个项目其实是我主讲的一门视频课程(看文章就可以学到所有知识,若需要可 ...

  7. 兼容iOS Android,React Native兼容iOS Android的TabBar

    最近着手开发的一个兼容iOS.Android的TabBar.还在不断开发中! 欢迎fork,欢迎star. :p 自己捣鼓了个E文的readme,没啥难度凑合可看. react-native-tabs ...

  8. 【JetPack】为现有 Android 项目配置视图绑定 ( ViewBinding ) 模块 ( 视图绑定不影响传统布局操作 | 视图绑定类关联 Activity | 视图绑定类本质 )

    文章目录 I . 为现有项目配置 视图绑定 ( ViewBinding ) 应用 II . 视图绑定 ( ViewBinding ) 定制 III . 视图绑定 ( ViewBinding ) 对于正 ...

  9. android 仿ios tabs,React Native兼容iOS Android的TabBar

    tabbar 最近着手开发的一个兼容iOS.Android的TabBar.还在不断开发中. 欢迎fork,欢迎star. :p 自己捣鼓了个E文的readme,没啥难度凑合可看. react-nati ...

  10. Android之React Native平台与Android本地模块之间的调用

    Native 模块(Android)          有时候APP需要做出React Native平台没有的功能,你也许会想用一些存在的java代码去解决问题,而不是用javascript脚本去去解 ...

最新文章

  1. 文件中数组的最大值及其对应的最小下标
  2. 鼠标悬停事件_Red语言-GUI-事件和参与者
  3. Spring Boot spring mvc 拦截器
  4. python38怎么用_Python基础练习实例38(数组操作)
  5. 机器学习的最佳学习路线,就在这里!
  6. sqlserver 存储过程 C#调用 实现从数据库Get数据
  7. php发卡8.0源码_素材资源解析平台PHP源码 V8.0运营版+会员功能+代理功能+卡密充值...
  8. RobHess的SIFT源码分析:imgfeatures.h和imgfeatures.c文件
  9. mysql同一台服务器上不同数据库中个别表内容同步
  10. [Alamofire] 错误总结
  11. 通过 JavaScript 获取/设置元素样式的方法
  12. [小问题笔记(八)] 常用SQL(读字段名,改字段名,打印影响行数,添加默认值,查找存储过程等)...
  13. bili弹幕姬_B站弹幕姬插件——弹幕日志
  14. ROBOGUIDE软件:FANUC机器人弧焊焊接起始点接触寻位虚拟仿真
  15. python pack是什么意思_Python中pack和unpack用法介绍
  16. Google Dapper,大规模分布式系统的跟踪系统
  17. 猎头解密互联网公司offer行情,网易游戏研发高达40W--IT薪资待遇
  18. c++11 std::decay源码剖析
  19. ip经济ip猫:「飞海豚」大圣基因/医修鸽的ValueUP | Chain++
  20. android 推送图标大小,设计方法论:一种统一图标大小的方法

热门文章

  1. java调用万网域名接口
  2. Pandas08--文本数据
  3. amr文件怎么转换成mp3
  4. 数据分析~中国五大城市PM2.5数据分析02
  5. Codevs P1066 引水入城 2010年NOIP全国联赛提高组
  6. [C#]Excel画斜线以及Excel宏的利用
  7. C++实践之华氏温度转摄氏温度
  8. linux根windows,linux系统刨根之路(二):实现windows和linux双系统-Go语言中文社区...
  9. 线性稳压芯片的优势及注意事项
  10. 上海交通大学教授金耀辉:AI在智慧法院中的应用