学习基础:
- js的基础知识,
- rect.js基础
- JSX语法基础
- FlexBox布局
安装
- 安装node.js
下载地址: https://nodejs.org/en/ - 运行
npm install -g react-native-cli
安装react-native-cli。 - 运行
react-native init [your project name]
,这样就会自动生成一个基本的ReactNative项目。 - cd到项目中执行
react-native start
,会部署本地的package服务。 - 重新启动一个命令行, cd到项目中, 执行
react-native run-android
注意:android项目可能会没有缺少local.properties文件,项目运行时会报错,可以从本地别的项目里拷贝一份放进去。
兼容性
- JS文件中平台区分
var { Platform} = React;
if(Platform.OS === 'ios'){
//ios相关操作
}else{
//android相关操作
}
Platform不止可以区分平台,还可以区分Android版本号等。
- 文件后缀区分不同平台
你有my-icon.ios.png和my-icon.android.png,Packager就会根据平台而选择不同的文件, 同理js文件也会根据后缀的不同.ios.js和.android.js,自动找到匹配相应的文件。 - 图片适配不同屏幕
可以使用@2x,@3x这样的文件名后缀,来为不同的屏幕精度提供图片。
├── button.js
└── img
├── check@2x.png
└── check@3x.png
<Image source={require('./img/check.png')} />
Android打包
- 确保Android项目中有assets目录
- 执行:
react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/
成功后会在assets目录中生成index.android.bundle和index.android.bundle.meta两个文件表示已经打包成功了。
放在js目录下的图片会自动打包到android项目的drawable目录下。比如我在
*\MyReactDemo\js\login\img
目录下为了适配不同屏幕有三张图片
login-background.png
login-background@2x.png
login-background@3x.png
打包后会自动修改名称并添加到相应的drawable目录下
打包的时候只会把js里用到的图片导入到drawable,其他相应的图片并没有导进去, 这里应该是做了检查,防止导入不用图片资源。
增量热更新
由于官方没有提供热更新方案, 可以使用微软推出的Codepush,但是服务器在国外,可能会有些问题,没有增量更新。
想实现增量热更新:
参考http://www.jianshu.com/p/2cb3eb9604ca
注意文章有些地方需要注意:
-
更换index.android.bundle目录应该是重写Application中的ReactNativeHost的getJsBundleFile()方法。
-
bundle位置变化后图片地址访问不到。
当下载后的bundle文件放入SDCard,会出现图片不能加载的问,这是因为bundel文件存在不同位置,路径解析方式会有不同。
找到Image.ios.js或者Image.android.js文件,查看render方法。
发现通过resolveAssetSource来做地址解析,打开resolveAssetSource.js
发现通过resolver.defaultAsset返回资源地址, 在AssetSourceResolver.js中找到defaultAsset()函数。
这里会根据bundle文件加载方式不同,图片路径会通过不同的方式加载。如果路径而不是从assets里面加载的话,会从文件bundle文件所在路径下加载图片。
通过注释我们知道只要把图片资源和bundle文件放到同一个目录下面就可以访问到, 但是我实际操作后发现有些特殊情况需要注意。
比如开发的项目中:
访问图片的js文件路径:/js/login/LoginPage.js
图片的访问方式:<Image style={styles.container} source={require("./img/icon_search.png")}>
图片放到同级目录img下:/js/login/img/icon_search.png
正确的文件路径应该是在sdcard中在bundle包同级目录下的/drawable-mdpi/js_login_img_icon_search.png
这是因为在getAssetPathInDrawableFolder方法中会通过屏幕deviceScale的属性找到对应的drawable目录,然后再做一个拼接。最后拼接出来的图片地址:
这种方式如果用户清理缓存数据后js文件又回到了原始状态,这个可以可以通过每次启动检查更新来避免。
常见问题
Q:RN所支持的最低iOS和Android版本?
A:Android >= 4.1 (API 16) iOS >= 7.0
Q:可以使用现有的js库吗?
A:由于RN理论上更接近nodejs的运行环境,所以对nodejs的库兼容更好一些。浏览器端的js库,涉及到DOM、BOM、CSS等功能的模块无法使用,因为RN的环境中没有这些东西。
Q: 可以使用现有的objc/swift/java库吗
A: 可以但是要做更改。
Q:可以热更新吗?苹果允许吗?
A:官方没有提供热更新方案, 苹果目前的政策明确允许基于javascriptCore的热更新,可以使用微软推出的Codepush来更新文件。
报错
** 1.invariant violation:expected a component class,got[object object]**
创建自定义组件首字母要大写,否则会报错.**
** 2. Module 0 is not a registered callable module.**
将gradle升级成最新版本(cd Android) 进入android目录执行:sudo ./gradlew clean) 或者通过android studio工具升级.
** 3. android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?**
该错误属于安卓Native的错误,如果引用的Activity不存在或者已经销毁,再次引用就会报该错误,如果是React Native调用原生控件的话,创建控件需要引用:getCurrentActivity()
** 4.android.app.Application cannot be cast to com.facebook.React.ReactApplication.**
需要将创建的MainApplication在AndroidManifest.xml配置好.
** 5. Element type is invalid: expected a string (for built-in components) or a class/function but got: object**
发生原生一般是你引用了无效的组件,如果组件确实正确,看下引用的组件是否正常导出:(export defalut)
** 6. react native undefined is not an object (evaluating this....**
发生该错误的一般是忘记bind(this),只要回调函数中需要用到this的,一般都需要bind.
** 7. react native - expected a component class, got [object Object]**
该错误可能是你引用了小写的组件,组件首字母一定要大写,比如<login/>应该写成<Login/>**
** 8. Invariant Violation:Application XXXX has not been registered.**
请确保index.*.js中的
AppRegistry.registerComponent('项目名',() => ...);
MainActivity.java中的
@Overrideprotected String getMainComponentName() { return "项目名";}
都保持一致。
** 9. 遇到403 Forbidden错误.**
首先运行netstat -ano
检查默认端口8081被占用的情况,如果被占用可以关掉占用的程序或者修改端口。
修改端口方法:
-
找到
\node_modules\react-native\local-cli\server\server.js
修改default端口号
在MainActivity中添加
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
mSp.edit().putString("debug_http_host","localhost:7777").commit();
}
端口修改后用chrome调试会有问题, 这是因为调试走的端口并没有被修改,抱歉没有找到修改的地方,哪位大神找到了麻烦告诉我一声,我的解决方法是在调试的时候手动修改debugerWorker.js加载bundle地址的端口号。
学习资料
Flex布局学习:
http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
资源集合:
https://github.com/reactnativecn/react-native-guide#%E7%BB%84%E4%BB%B6