RN嵌入app所踩的坑
本篇文章不会包括RN中的相关概念,生命周期等内容,
只包括在接入过程中所遇到的一些问题,
接入RN的平台为Android,开发环境为mac.
官方文档
首当其冲抛出官方文档,接入是基于官方文档的.
下面会列出接入的步骤以及所遇到的问题.
官方文档
问题及注意点汇总
先描述接入过程中遇到的问题及注意事项,后面会在接入过程中给出相关解决办法.
- android项目依赖的RN版本不对.
- react 引入版本不对.
- 真机调试
- 运行时libgnustl_shared.so使用的版本不对
接入步骤
创建android项目
正常使用Android Studio创建Android项目.
目前创建的项目就是常规的项目,跟RN还没有任何关系.
添加RN相关依赖
使用npm命令创建项目并添加依赖
按照顺序在项目根目录执行下面的命令
//初始化package.json
$ npm init
//安装react react-native并保存.此处可能会导致一些问题,参见后面的问题
$ npm install --save react react-native
//获取.flow的配置文件
$ curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
上面三步是项目接入RN的基础,因为需要通过npm来下载RN相关的环境依赖.
需要注意如下几点
- 初始化项目,需要注意根目录的位置,也就是执行
npm init时所在的目录
,
此处是我遇到的第一个坑,导致问题1的产生.无论时我们创建的项目本身,还是用到的RN的第三方库,
都需要引用RN框架,RN框架的引入是通过本地maven库的方式引入的,而对RN项目引入的路径是在build.gradle中写死的(引入的第三方库).
所以如果RN的初始化的目录不对,会导致找不到RN框架,或者RN框架的版本不对.(因为不指定本地库的话,默认时从jcenter中拉取的,但是RN的最新版本是没有提交到jcenter的,所以会出错,或者拉取的版本不对).
下图为目录结构图,reactnativeintergration为root目录.android目录下,是我们创建的android项目的代码.我们的项目及第三方的RN库对RN本身的依赖都是通过$rootDir/../node_modules/react-native/android
来查找的.所以如果相对路径不对,则会出现该问题Failed to resolve: com.facebook.react:react-native
.
按照这样的目录结构,我们执行
npm init
的位置应该是在reactnativeintegration
目录下.
2.由于执行npm install
时未指定RN以及react的版本,所以获取的版本并不一定是我们需要的.
此处遇到了另外的坑,也就是问题2.
未指定版本时,使用默认安装的,则react安装的版本为15.x.
而使用15.x是会报该错误的Unable to resolve module react/lib/ReactDebugCurrentFrame
解决的办法就是指定依赖的react版本为16.xx.
npm install -save react@~16.0.0-alpha.6
参考文章
3.flow的作用.
第三个命令时复制flow的配置文件,没什么问题.
flow是Facebook用来给js添加静态类型的库,
详细可以参考flow官网
添加运行命令
在package.json中的的scripts标签下添加如下命令.
添加之后可以直接运行npm start
启动bundle server.
"start": "node node_modules/react-native/local-cli/cli.js start"
创建index.android.js文件
此处是添加一个RN的页面.具体代码不贴,参照代码index.android.js.
为Android项目中添加RN依赖
RN在native层是需要项目进行依赖的.所以需要在build.gradle中添加项目依赖.
示例项目中是依赖RN0.43.4版本的.需要注意的是,对于本地maven库的添加,如果不指定maven库的地址则会通过jcenter仓库去获取,但是RN最新版本的库是没有传到jcenter中的.所以需要在build.gradle中添加maven中心库,添加的maven库需要指向node_modules中,就是因为这个原因,所以需要在第一步通过npm init初始化项目时,将目录位置指定正确,否则就会遇到问题1
//添加RN库的依赖,指定版本
//app/build.gradle
dependencies {
...
compile "com.facebook.react:react-native:0.43.4" // From node_modules.
}
//添加maven本地库
//root/build.gradle
allprojects {
repositories {
...
maven {
// All of React Native (JS, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
}
...
}
添加权限
访问网络的权限时必须的.
<uses-permission android:name="android.permission.INTERNET" />
overlay的权限根据不同的target api进行不同的处理.
我的示例中的target-api设置的为22.所以没有适配新的权限系统.
也就是说,如果你是22以上的项目,则需要动态获取下在其他界面之上绘制内容的权限.
添加权限
添加Native代码
RN是需要一个运行渲染环境的,我的代码中将这些操作放在一个Activity中,
当然也可以放在Fragment中.此处需要注意的是,Activity的theme需要设置为@style/Theme.AppCompat.Light.NoActionBar
,因为有些第三方的组件依赖该theme.
具体代码参考示例RNContainerActivity类.
运行app
1.正常安装app
2.执行adb reverse tcp:8081 tcp:8081
这么做是为了做端口转发,端口转发后,当手机访问http://localhost:8081时,
会被转发到执行该命令的电脑上的8081端口.
从而访问到bundle.js文件.此处对应问题3.
推荐一篇文章关于reverse命令的
3.运行时提示出现so找不到的问题.
java.lang.UnsatisfiedLinkError: dlopen failed: "/data/data/reactnative.com.yftx.reactnativeintegration/lib-main/libgnustl_shared.so" is 32-bit instead of 64-bit
我的测试手机时pixel xl,由于cpu架构不同,会导致找不到so库,
因为在初始化创建项目时,没有指定需要包含哪些cpu架构的so文件.
通过参照通过react-native init创建的项目中的build.gradle添加上相关so依赖即可.
总结及代码
接入过程总体来说不是很复杂,暂时先写这么多.
只需要注意一下上面提到的几个问题就行了.
欢迎关注我的这个项目,技术含量没有,但是后面会有比较详细的接入的注释.
项目代码
未完成的部分
1.RN项目同Native项目之间通讯.
2.Native类容器ReactInstanceManager的使用.
3.bundle的打包及部署.
4.热更新的方式.
5.RN的裁剪.
上面几块会分别写还是更新改文档还不确定,欢迎大家关注.