前言
Facebook 在 2015.9.15 发布了 React Native for Android,把 JavaScript 开发技术扩展到了移动 Android 平台。基于 React 的 React Native 让前端开发者使用 JavaScript 和 React 编写应用,利用相同的核心代码就可以创建 基于 Web,iOS 和 Android 平台的原生应用。在 React Native for Android 出来之后,本人花了些时间从环境搭建到做出几个 demo,从体验来看都挺流畅,具体将此间遇到和问题和具体的新的体会,向大家分享一下。
原理简介
1 React Native for Android 和 for IOS 的基本原理是一致的,通过 android 的 JavaScriptCore 来异步解析 js 代码 (jsbundle 文件),然后根据引入的支持和配置,渲染成原生 native 组件。
2 复用 React 系统,也减少了一定学习和开发成本,更重要的是利用了 React 里面的分层和 diff 机制。js 层传给 Native 层的是一个 diff 后的 json,然后由 Native 将这个数据映射成真正的布局视图。
环境搭建
环境搭建的话,在网上也找到过很多教程,但是还是推荐还是去看官方文档 https://facebook.github.io/react-native/docs/android-setup.html#content,在搭建的过程中可能会遇到一些问题。
1 在 React Native for Android 刚出来的时候,官方称是不支持在 windows 系统上安装的,只有在 mac 上才可以使用,但是最新版的 React Native for Android 已经支持在 windows 上使用,更新 React Native 的方法:下载最新版的 react-native-cli 即 npm install -g react-native-cli,并且保证 node 是最新版的即>4.0。
2 在执行 react-native init AwesomeProject 命令时,由于这个命令会去下载一些 node module 所以要根据自己的实际情况设置 npm 的代理和镜像,本人就曾经因为这个问题搞了很久才成功,可以安装 nrm(npm install -g nrm) 来便捷设置 npm 的代理和镜像,其次是执行这个命令必须现在机器上装有 git,并且设置好 git 的环境变量,另外这个命令需要等待一些时间,不要提前取消。
3 在调用 react-native run-android 的命令时,有时会报出找不到 android-sdk 环境变量的错误(自己确实已经正确设置环境变量)提示例如
的错误时,可以单独在项目根目录下,也就是 AwesomeProject/新建一个 local.propertites 文件,添加 sdk.dir=你的 android 的 sdk 目录,然后在运行 react-native run-android。
4 在调用 react-native run-android 命令时,其实这个命令就是执行的两部分操作一是是构建你的 android 项目并生成 apk,另外一个是打开 react-native 的 package 管理工具同时编译你的 js 文件,其实可以在项目根目录的 package.json 下找到
其实是执行了另外一条命令 node node_modules\react-native\packager\packager.js 来打开 package 的管理工具,有些可能没打开一个新的命令行窗口,自己手动执行这条 node 命令也是可以的。在这条命令执行完之后,node 就会开启一个服务,同时把 js 文件编译成 jsbundle 文件,我们可以通过 http://localhost:8081/index.android.bundle?platform=android 来访问到这个文件,可以简单将这个文件理解成一个 html,android 就是通过解析这个 html 来达到渲染的目的,将该文件部署到 CDN 可供 android app 从网络获取,即可实现不用发版本让 app 的 UI 随时更新,并且可获得接近 native 的体验,这也是 react-native 最吸引开发者的亮点之一。
5 用 react native 命令生成的 android 项目是基于 gradle 构建和部署的 (不清楚 gradle 的可以 google),这个以前一些搞用 eclipse 来 android 开发的可能不太一样,gradle 是用在 google 主推的一款 android 开发 IDE,android statio 里面默认的项目构建方式,所以我们的项目里会看到一些 build.gradle 的文件,这些都是配置文件。
6 我们在根据教程搭环境时会碰到需要安装 android 模拟器的步骤,这个步骤会提示你安装一个 HAXM 的东西可以看到这个安装不是必须的,其实这个是一个 android 模拟器的加速程序,按了这个你的模拟器可能会跑的更快,但是在安装这个程序时,会遇到的错误是由于 CPU 的虚拟化未开启,需要重新开机在 bios 上设置一下,具体怎么设置,可以自行 google。
7 react-native android 在本地调试开发时,你只需要修改 js 文件,然后刷新你的项目,所以在创建 android 模拟器时要记得选择带有 android 键盘的模拟器,这样才能在模拟器上刷新你的更改。
与现有的 android 项目集成
1 想要在现有的 android 项目里添加 react native 支持,你必须要先创建一个基于 gradle 的 android 项目,推荐使用 android studio 来创建项目,要记得创建的项目要高于 Android 4.1 (API 16)的 android 项目。
2 用 android studio 创建一个项目 并且能跑起来,这段教程可以直接去网上少,一般配置无误的情况下,很容易跑出一个 android helloword 来,你只需要保持之前的 node package 服务开启,程序依然会去寻找 http://localhost:8081/index.android.bundle?platform=android 这个文件的。只是你的 android 模拟器是通过 android studio 来管理了。
3 在按照 http://facebook.github.io/react-native/docs/embedded-app-android.html#content 配置你的结合项目时,还要注意在 AndroidManifest.xml 文件里面添加<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" /> 这样才能开启调试模式。
4 对于 android 项目来说,react native 的支持也是就在 Activity 里面创建了一个 ReactRootView,对这不是 webview,然后将 Activity 的其他事件生命周期等等都交给 react manager 来管理,所以对于 react native 的 android 页面,就可以简单理解成一个 activety 里面套一个 reactrootview 这个 view 去加载并 jsbundle 文件,渲染出原生 native 的 ui 组件。
远程加载 jsbundle 文件
1 目前在 react android 的官方文档里面,还没有找到如何远程加载 jsbundle 文件的地方,只能是事先把 jsbundle 文件放在 assets 目录下面,一起打包成 apk,也就是 release apk 文件,可以参考 https://facebook.github.io/react-native/docs/signed-apk-android.html。
样式和布局
1 react native 的代码和 react 基本一样,组件的生命周期,jsx 语法都支持,只是在使用 jsx 时要经常调用官方提供的组件。
2 react native 里面的样式大部分是可以利用 css 语法来写的,只有文档里面有的属性才能用,不是所有的 css 都可以在 react native 里面用的,采用 obj 的形式将 css 属性横杠后面的第一个字母大写即可。
3 react 的宽高度不支持百分比,设置宽高度时不需要带单位,在 react native 里面默认使用 pt 为单位,注意在给 image 设置大小时要根据 PixelRatio 设置合适的值。
4 使用 dimensions.get("window") 可以获取到当前 viewport 的大小,这个值可能会根据屏幕横竖来动态改变。
5 react native 里面没有 float 的用法,是根据 flex 来布局,alignItems 和 justifyContent 分别决定子元素的布局,而 flexDirection 决定子元素的排列方式垂直还是水平,flex:number 决定子元素所占的比例,alignSelf 决定元素本事的布局,子 view 会默认根据父 view 来 absolute,这里有个技巧,如果想让子 view 实现 100% 的效果可以设置 left:0 ,right :0, 同理 height 可以用 top:0,bottom:0。
6 使用 text 的 numberOfLines 可以实现文本截取省略号,即 css 的 text-overflow 属性。
7 默认情况下如果元素超过了父元素,是不可以滚动的,必须在外部套一个<ScrollView> 才可以。
8 react native 里面没有 z-index 的概念,是根据 jsx 语法里面定义组件的顺序来实现的,后写的组件会覆盖在先写的组件上。
总结
1 react native android 和 ios 相比,由于出现的还比较晚一些功能还没有非常完善,所以一些文档里面没有写的东西还需要自己摸索, 例如 android 上使用 borderTopLeftRadius 没起作用。
2 react native android 在性能上要比 web 来的好很多,毕竟渲染出来的是原生的组件,尤其是在一些低端 android 机型上,但是跟真正的 native 相比还是要逊色一些,但是 react native 的优势在于一套代码可以跨平台复用,而且可以通过更新远端 JS,直接更新 app,并且对于前端工程师来说用 js 的语法写 native 的组件也并没有很难。
3 本人用 react native android 做出的 demo,大家可以体验一下。http://7jpp2v.com1.z0.glb.clouddn.com/app-release.apk
不断跟新中
参考资料:http://www.nihaoshijie.com.cn/index.php/archives/550
夏风 2016 年 8 月 15 日
这上边也有几篇文章不错 http://www.rnblog.cn
sky 2016 年 7 月 16 日
多个 ReactNativeActivity 怎么支持?目前新版入口实在 Application 里面初始化的
龙龙 2016 年 6 月 16 日
我想问问 与原生合并之后的代码混淆问题怎么解决呀 现在遇到一个问题是代码混淆后 RN 所在的 activity 进入后闪退
丰瞻 2016 年 4 月 29 日
代码写的有问题,那个 Demo。listview 耗内存特别大,几百 mb。重新打开应用时重复执行 mReactRootView.startReactApplication
吕鸣 2016 年 5 月 3 日
mReactRootView.startReactApplication 这段代码是官方 demo 里面的,没有改动这里的代码,内存消耗大是 listview 的原因,跟 startReactApplication 并没关系吧
丰瞻 2016 年 5 月 4 日
startReactApplication 会重新启动一个线程,每次退出应用后(直接按照官方的 back 退出),再次进入会重新进入 onCreate,startReactApplication 中应该会再次进行加载。所以在使用 back 退出的时候应该执行 System.exit(0). 直接杀死所有线程,当然这样也不是最好的,或许你能试下 back 退出后的效果,给出一个更好的解决办法。(感觉源码这样不断重启线程比较不负责任)
吕鸣 2016 年 5 月 4 日
我理解 android 应用程序是在程序退出的时候,1 如果是真退出即没有后台操作,整个程序的内存会被回收吧 2 如果只是后台操作,那么 oncreate 也只会执行一次吧应该不存在手动去杀掉进程回收内存这种情况吧
丰瞻 2016 年 5 月 4 日
我用了两个方法:1.DDMS 查看使用的线程,不断退出重新进入应用,线程无限增加,我测到 100 多个就没继续了。2.adb shell dumpsys meminfo com.example.tennylv.myfff 使用这个命令查看你的应用所占内存,依旧是不断重新进入应用,内存占用逐渐增大,对不不常关机的用户来说,这是很恐怖的。我是用你的 Demo 测试的,你也可以试试。
吕鸣 2016 年 5 月 4 日
我在机器上试了一下, 1 当在主页面按 back 时,程序退出,和按 home 不一样。2 这时会有进程被后台缓存起来,这类进程属于后台缓存的进程,不会占用 cpu 资源,缓存是为了在下次打开时块一些,并且在内存不够时系统会优先杀掉这类进程。3 自己新建一个纯净的 android demo 时,在主页面点击 back 时也会变成后台缓存的进程。4 使用杀进程的方式退出 demo 时,是不会有进程缓存的,整个程序的内存会被回收。
丰瞻 2016 年 5 月 5 日
我的应用有个退出选项,我还是选择了完全退出~
守望 2016 年 3 月 24 日
我只是看了看 webQQ 的网页代码……就一路翻到了这里-.-
吕鸣 2016 年 3 月 24 日
[嘻嘻]
react开发者 2016 年 3 月 23 日
安卓怎么解决适配问题
如果我是一只蚂蚁 2016 年 1 月 13 日
表示心在坑在修改完 刷新上了,物理键盘可以刷新?
tangsir 2016 年 2 月 1 日
可以的 修改 onKeyup
灵感创作 2016 年 1 月 10 日
昨晚女儿带男朋友第一次来家里吃饭,我一高兴把他灌醉了,没想到这小子酒量差酒品也差,喝醉了竟然偷偷跟我说带我去找小姐,我现在想起来还很生气,女儿怎么会看上这么一个说话不算话的男人。
linx 2015 年 11 月 28 日
用什么 IDE 啊? 怎么导入 Android studio?
指手握白愁、 2015 年 11 月 26 日
这个没有代码补全吗?
微笑的鱼 2015 年 11 月 19 日
远程加载 jsbundle 文件,需要开启 DEBUG 模式,host 和 port 是写在 PreferenceManager.getDefaultSharedPreferences,key 为 debug_http_host,查看 DevServerHelper.java 的 getDebugServerHost 方法
微笑的鱼 2015 年 11 月 19 日
开启 DEBUG 模式后,需要运行 react-native start 开启本地服务器
小白-react-native 2015 年 11 月 12 日
可否给分源码?1537018097@qq.com 谢谢
ypzhou 2015 年 11 月 10 日
三星 S6 表示运行不起来你的 demo
TAT.iptton 2015 年 11 月 10 日
应该不需要 10M ,一个几乎完善的知乎日报也才 8M
Cmdmac 2015 年 11 月 10 日
官方 demo 打包有 7m, 不过包含了 x86 的 so
TAT.iptton 2015 年 11 月 10 日
是的,就是 x86 的 so 太大,去掉可以少 3M
TAT.iptton 2015 年 11 月 10 日
最小估计就是 4M 左右了
Cmdmac 2015 年 11 月 4 日
一个 apk 有 10m,现在来看还不能应用到实际项目中
盛装舞步 2015 年 10 月 30 日
小米 note2 上表示运行不起来你的 demo
吕鸣 2015 年 11 月 4 日
是 android 4.1 以上么 现在 reactnative 支持 android 4.1+
Paul 2015 年 10 月 28 日
可否发一份源码研究一下?pentcui@live.com
多谢
吕鸣 2015 年 10 月 28 日
具体是哪个源码?[嘻嘻]
AlloyTeam 2015 年 10 月 27 日
赞一个
iamxz 2015 年 10 月 27 日
到现在安卓模拟器还没有启动开~ 都快哭死了。
吕鸣 2015 年 10 月 28 日
卡在哪一步了?
exoticknight 2015 年 10 月 25 日
好!