从7月底到9月底两个月的时间开发了一个React-Native的APP。不得不说,用RN的开发效率还是很快的。就来总结一下历程。
整个项目的逻辑大概就是:
- 新建项目,导入项目的图片资源,APP的图标,启动图,ios的启动图在Xcode中直接设置Launch Image和icon,对于安卓的启动图要写代码实现才行。对于项目的图片资源,可以两套系统共用一套图片那就可以放在一个文件夹下,引入的时候用相对路径导入;也可以放在Xcode或者是Android Studio中进行uri:+图片名称导入。
- 用上一篇的第三方组件和一些基本组件大概完成了一些页面,完成了登录,手势解锁页,还有主页面的框架和主页面中一些子页面的大体显示。接下来遇到的问题大概有两个:
第一:如何跳转,把这个页面都串起来,就像一些珠子如何才能串成一串:导航的使用:Navigator已经废弃,就要使用react-naviagtion来导航。
第二:如何进行数据处理:
- 是如何从服务器获取数据.
- 是如何把从服务器获取的数据进行持久化存储。
如何在页面间进行参数的传递
对于数据的处理也是难点。
首先对于网络请求要用fetch,
遇到的相关问题:获取设备ID:用第三方库,补充:JS中如何把字符串中的?替换为&:
var str_replaced = str.replace(/\?/g,"&");//加g就是替换所有的?号
- React-Natvie用RSA加密用户的密码:
react-native-rsa
node-rsa
虽然有这些第三方库,但是我并没有用,这个简直搞到我头大,终于搞定了!
主要是参照这两个网址:
http://www.cnblogs.com/Grart/p/5080228.html
node-rsa的基础库http://www-cs-students.stanford.edu/~tjw/jsbn/
因为密码需要先用公钥RSA加密,然后在用base64加密,加密以后的字符串传给服务器,服务器那边再先base64解密,然后再用私钥解密。
在使用的时候最大的问题就是你要传一个N和E的参数来setPublic,这个问题困扰了我一天之久,终于后端的同学帮我搞定了,Java里面有方法可以根据已有的公钥来逆向出N和E的值,然后再使用下面的那个网页,网页,没错,就是下载下来那个网页,然后就有基本的JS文件了,其实RN就是JS,只怪自己前端不佳,然后把JS文件转化成RN可以用的JS组件库导入直接调用就可以加密成功了!终于加密成功了。感动哭。
- 设置假数据显示一般来说都是容易的,与后台交互就需要用网络请求了。一般是GET和POST请求。POST的请求头:
一般常见的网络请求:
1 | var login=function(data,doSuccess,doError){ |
而我们这个post请求头呢?是下面这样的。
1 | 'Content-Type':'application/x-www-form-urlencoded' |
一般在post的body中是用:
{userName:this.state.userName,passWord:_pwd}这样的JSON传过去,再body: JSON.stringify(data)。。。
而我们这个呢?data是拼接起来的,我也是醉了,这我是用Charles发请求后才发现的,也是折腾了半天才明白的。也用postman还有终端httpie发现都可以请求成功,唯独用这个请求不到,后来就拼接了一下,成功了。
- JSON.stringify(result);和JSON.parse(result)有什么区别啊?
用于把JavaScript对象序列化为JSON字符串和把JSON字符串解析为原生JavaScript。
JSON.stringify将JavaScript对象转换为JSON文本,并将该JSON文本存储在字符串中。
JSON.parse将一串JSON文本转换成Javascript对象。
当你在fetch请求后 .then((response)=> response.json())的时候就不用解析直接用.取。。。
当你在fetch请求后, .then((response) => response.text())的时候就需要JSON.parse(result);
初学者最容易犯错误的地方就是this指针了!!我是在导航跳转的时候意识到这个问题的。每个组件都是有props和states的。
子组件如何调用父组件:this.props。
父组件如何调用子组件:首先用属性ref给子组件取个名字吧,this.refs.名字.getDOMNode().从服务返回的JSON数据的解析,有些需要遍历一下。
1 | let brandata = result.dangqiAnalysisBrandList; |
安卓打包
- 生成一个签名密钥
keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
最后它会生成一个叫做my-release-key.keystore的密钥库文件
找到路径/android/app/src/main,并在该目录下新建assets文件夹
在工程目录下将index.android.bundle下载并保存到assets资源文件夹中
curl -k "http://localhost:8081/index.android.bundle" > android/app/src/main/assets/index.android.bundle
这句命令是重点,如果assets目录中不存在该文件,则打包的apk在执行时显示空白。
Protocol ‘http not supported or disabled in libcurl
Windows下安装使用curl命令:http://jingyan.baidu.com/article/a681b0dec4c67a3b1943467c.html
- 添加gradle的android keystore配置
打包的apk在未签名的情况下,在手机中(非root)是不允许安装的
在build.gradle文件中
//签名signingConfigs{
release {
storeFile file("/my-release-key.keystore")
storePassword "密码"
keyAlias "keyAlias的名字"
keyPassword "密码"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release //添加这句话引用签名配置
}
}
- 启用Proguard代码混淆来缩小APK文件的大小
Proguard是一个Java字节码混淆压缩工具,它可以移除掉React Native Java(和它的依赖库中)中没有被使用到的部分,最终有效的减少APK的大小。
重要:启用Proguard之后,你必须再次全面地测试你的应用。Proguard有时候需要为你引入的每个原生库做一些额外的配置。参见app/proguard-rules.pro文件。
def enableProguardInReleaseBuilds = true
- 在/android/目录中执行gradle assembleRelease命令,打包后的文件在 android/app/build/outputs/apk目录中,例如app-release.apk。如果打包碰到问题可以先执行 gradle clean 清理一下。
一定要注意:在打包的时候要运行起来安卓。
安装gradle工具(版本与android\gradle\wrapper下的一致),并配置环境变量,配置GRADLE_HOME到你的gradle根目录当中,然后把%GRADLE_HOME%/bin(linux或mac的是$GRADLE_HOME/bin)加到PATH的环境变量。
mac要配置gradle的环境变量的路径
配置完成之后,运行gradle -v,检查一下是否安装无误
- 将apk发布到各大应用市场(BUILD SUCCESSFUL)
iOS打包
- 在项目的目录下建立bundle文件夹。然后执行如下命令
react-native bundle --entry-file index.ios.js --platform ios --bundle-output ./bundle/main.jsbundle --dev false --assets-dest ./bundle/
几分钟过后,在 bundle 文件夹里会多出个 assets 文件夹和 main.jsbundle 文件。不然会提示npm install…
把刚刚得到的 main.jsbundle 和 assets 文件夹添加到项目中, 在 Xcode 中 assets 资源文件夹比较特殊,必须用 Create folder references 的方式添加进去,添加完后是蓝色文件夹图标.
修改 AppDelegate.m 文件
在XCODE里打开 APPDELEGATE.M 文件,找到代码 JSCODELOCATION = [[RCTBUNDLEURLPROVIDER SHAREDSETTINGS],在其下方添加以下代码
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
注意:代码里的 @”main” 和 @”jsbundle”,与之前生成的文件 main.jsbundle 对应。
- 在XCODE里点击运行,使用模拟器测试APP能否正常运行。
- 和在Xcode里面打包原生应用一样的。
打包遇到的问题
native-echarts的组件问题 —–真机上面React-echart显示不了吗?白色的。
主要是因为路径不对。
Android
将node_modules/native-echarts/src/components/Echarts/tpl.html拷贝到assets下需要修改node_modules/native-echarts/src/components/Echarts/index.js
IOS
将tpl.html 放置 Xcode项目 下面 然后如下引用,修改源码下面的index.js
为下面的:
1 | import React, { Component } from 'react'; |
真机测试时候发现的问题
react-navigation的问题:
ios上面:
手势左边滑动就能返回到上一个页面,这样在你不需要返回的时候也返回了。
解决方法:
gesturesEnabled:是否支持滑动返回收拾,iOS默认支持,安卓默认关闭。设置为false试了一下。
参照文章:https://hans007.github.io/react-native/2017/06/19/react-navigationAndroid上面:物理返回键的处理。
BackAndroid已经废弃了,使用BackHandler,大概思路就是添加监听,
之前使用Navigator的时候,可以通过下面的方法实现监听安卓的返回键,但使用了react-navigation后,会很迷茫,不知该怎么监听了。
解决办法:集成Redux咯!集成完Redux,在跳转之后,就能获得路由的length,可以通过length来判断当前页面是第几层。
Navigator的方法
1 | componentWillMount() { |
react-navigation的方式
1 | componentWillMount() { |
其他小问题
需要把服务器取过来的数字(也有可能是数字字符串),将小数点前的数字每隔三位添加一个逗号(前面数是一个四位数的值)。比如取到的值是123456,要将其转换成123,456。搜索了一下,这叫数字分位符号。
总结
代码量:近1万行,调通近40个接口。还有很多方面要优化,比如没有用Redux。还有一些其他方面的逻辑也有待优化。