本篇文章主要包括两方面,如何从0开始把RN(react-native)项目整合进入现有Android项目,以及我们做的第一个RN的上线项目遇到的一些坑。
初次做RN项目,我们选择做了一个逻辑相对简单的转转app内部的帮助中心项目。整个项目有4个页面用的RN,其他页面走的是native提供的统跳协议,跳转到对应的native页面或者是H5页面。
整合RN到android项目中
react-native cli提供的init指令,可以帮助我们创建一个RN的工程,但是很多场景下RN都是移植进入原生android或者iOS中。例如应该如何实现,在Android页面,点击一个按钮进入RN页面呢?
下面是具体的实现过程。
1、新建一个Android项目
注意Minimum SDK选择API23以上,一路next后finish。
2、添加JS
打开studio的Terminal窗口,输入如下命令:
npm init
按照提示输入就行了。
npm install react@16.0.0-alpha.6 - -save
注意,一定优先安装react哦
大约一两分钟的样子(如果卡到这里了,看看安装时是不是忘了配置镜像),完成之后你的根目录下会多了一个node_modules的文件夹,里面存放了下载好的React 和React Native。这里有童鞋可能会质疑为什么不把react和react-native的依赖直接写入package.json中,然后直接npm install,如果这么做的化,npm run start启动的时候会报如下的错误:
接下来把如下命令粘贴到package.json 文件下 scripts 标签中
“start”: “node node_modules/react-native/local-cli/cli.js start”
下一步,在根目录下创建index.android.js文件并把如下代码粘贴到其中:
代码很简单,居中显示一个HelloWorld。
3、项目配置(Android)
用android studio打开工程,修改android根目录下Gradle Scripts的build.gradle(Module:app)文件添加如下内容,注意下面appcompat-v7版本为25.2.0,而且我把dependencies中test相关的依赖移除掉了,避免不必要的bug。
在build.gradle(Project:***)中添加依赖
继续下一步,在AndroidManifest.xml中添加网络访问权限
4、创建Activity
以下几步不要安装官网的去做,官网的步骤太麻烦,而且很久没有更新了。
1.新建一个Activity,让其继承ReactActivity,并重写getMainComponentName(),返回我们在index.android.js中注册的HelloWorld这个组件。
别忘了把这个activity加入app/manifests/AndroidManifest.xml文件中
2.自定义一个Application,继承ReactApplication ,编写以下代码:
记得在AndroidManifest.xml中引用
android:name=”.App”
3.在目录res/layout中增加activity_main.xml文件,内容如下:
在MainActivity中通过按钮启动我们的ReactNativeActivity
4.app/src/main下新建assets文件夹
运行如下命令
react-native start
然后直接在android studio工程中,点击上方工具栏的“run”按钮,应该就可以了。
没关系,用资源管理器打开你工程的根目录,在此目录下重新运行一个命令行并在其中输入如下命令
react-native bundle - -platform android - -dev false - -entry-file index.android.js - -bundle-output app/src/main/assets/index.android.bundle - -assets-dest app/src/main/res/
完成之后assets目录下会生成以下两个文件
确认一下react native service处于运行状态,然后正常运行你的APP,点击start,如果出现
恭喜你!你已经成功入坑,但是,实际项目中并不是这么简单!
项目实战踩坑
1.技术栈
es6 + redux + react-redux + redux-thunk + react-navigation
2.项目心得
这个项目踩坑最多的地方还是在react-navigation的使用上:
1、同一页面参数不同,多次回退始终进入同一个页面:
解决办法是通过componentWillReceiveProps,shouldComponentUpdate以及componentDidUpdate,当nextProps中的params.cateId和当前的params.cateId不同的时候,触发页面的render。
2、实现手势swipe向右滑动后退功能:
因为上述代码中的 GESTURE_RESPONSE_DISTANCE_HORIZONTAL 过小,导致始终return false,把这个值从20改到60就可以了。
3、实现页面跳转动画效果
StackNavigator(RouteConfigs, StackNavigatorConfig);
在第二个参数StackNavigatorConfig的配置中,可以传入mode: ‘card’,这个参数会在native端获取默认的滑动效果,iOS端默认的是左右切换的效果,但是android端默认的是上下切换效果。为了实现统一的过场效果。
FlatList问题:
1.ListHeaderComponent,ListFooterComponent
2.通过利用getItemLayout,把高度提前设定好,可以较少一次RN计算高度的render。
图片问题:
1.RN中的图片有两种来源:native内部图片,cdn的图片。native内部图片,直接可以通过require图片名字取到,一定不要加.png等后缀。例如:
当然我们可以通过在打包的时候把通过相对路径引入的内部图片,
例如:
通过配置–asset-dest打包进入native原生目录res中,这时候要注意,打出来的RN的bundle,只有放入android的assets文件夹下才能根据相对路径取到这些存放在res目录中的图片。
cdn的图片,只有指定图片的宽高才能够显示出来。
与native交互的处理
NativeModules:native暴露出来的模块,可以通过NativeModules对象取到。
有些场景需要native直接传递某些参数到RN端,iOS可以通过调用initWithBundleURL,在initialProperties参数传参,android通过getLaunchOptions把参数写入返回的bundle中。在RN工程的根文件(例如app.js),通过this.props.key(key是属性名字)直接取到。