學(xué)習(xí)基礎(chǔ):
- js的基礎(chǔ)知識(shí),
- rect.js基礎(chǔ)
- JSX語(yǔ)法基礎(chǔ)
- FlexBox布局
安裝
- 安裝node.js
下載地址: https://nodejs.org/en/ - 運(yùn)行
npm install -g react-native-cli安裝react-native-cli。 - 運(yùn)行
react-native init [your project name],這樣就會(huì)自動(dòng)生成一個(gè)基本的ReactNative項(xiàng)目。 - cd到項(xiàng)目中執(zhí)行
react-native start,會(huì)部署本地的package服務(wù)。 - 重新啟動(dòng)一個(gè)命令行, cd到項(xiàng)目中, 執(zhí)行
react-native run-android
注意:android項(xiàng)目可能會(huì)沒有缺少local.properties文件,項(xiàng)目運(yùn)行時(shí)會(huì)報(bào)錯(cuò),可以從本地別的項(xiàng)目里拷貝一份放進(jìn)去。
兼容性
- JS文件中平臺(tái)區(qū)分
var { Platform} = React;
if(Platform.OS === 'ios'){
//ios相關(guān)操作
}else{
//android相關(guān)操作
}
Platform不止可以區(qū)分平臺(tái),還可以區(qū)分Android版本號(hào)等。
- 文件后綴區(qū)分不同平臺(tái)
你有my-icon.ios.png和my-icon.android.png,Packager就會(huì)根據(jù)平臺(tái)而選擇不同的文件, 同理js文件也會(huì)根據(jù)后綴的不同.ios.js和.android.js,自動(dòng)找到匹配相應(yīng)的文件。 - 圖片適配不同屏幕
可以使用@2x,@3x這樣的文件名后綴,來(lái)為不同的屏幕精度提供圖片。
├── button.js
└── img
├── check@2x.png
└── check@3x.png
<Image source={require('./img/check.png')} />
Android打包
- 確保Android項(xiàng)目中有assets目錄
- 執(zhí)行:
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/
成功后會(huì)在assets目錄中生成index.android.bundle和index.android.bundle.meta兩個(gè)文件表示已經(jīng)打包成功了。
放在js目錄下的圖片會(huì)自動(dòng)打包到android項(xiàng)目的drawable目錄下。比如我在
*\MyReactDemo\js\login\img
目錄下為了適配不同屏幕有三張圖片
login-background.png
login-background@2x.png
login-background@3x.png
打包后會(huì)自動(dòng)修改名稱并添加到相應(yīng)的drawable目錄下

打包的時(shí)候只會(huì)把js里用到的圖片導(dǎo)入到drawable,其他相應(yīng)的圖片并沒有導(dǎo)進(jìn)去, 這里應(yīng)該是做了檢查,防止導(dǎo)入不用圖片資源。
增量熱更新
由于官方?jīng)]有提供熱更新方案, 可以使用微軟推出的Codepush,但是服務(wù)器在國(guó)外,可能會(huì)有些問(wèn)題,沒有增量更新。
想實(shí)現(xiàn)增量熱更新:
參考http://www.itdecent.cn/p/2cb3eb9604ca
注意文章有些地方需要注意:
-
更換index.android.bundle目錄應(yīng)該是重寫Application中的ReactNativeHost的getJsBundleFile()方法。
Paste_Image.png -
bundle位置變化后圖片地址訪問(wèn)不到。
當(dāng)下載后的bundle文件放入SDCard,會(huì)出現(xiàn)圖片不能加載的問(wèn),這是因?yàn)閎undel文件存在不同位置,路徑解析方式會(huì)有不同。
找到Image.ios.js或者Image.android.js文件,查看render方法。
發(fā)現(xiàn)通過(guò)resolveAssetSource來(lái)做地址解析,打開resolveAssetSource.js
發(fā)現(xiàn)通過(guò)resolver.defaultAsset返回資源地址, 在AssetSourceResolver.js中找到defaultAsset()函數(shù)。
這里會(huì)根據(jù)bundle文件加載方式不同,圖片路徑會(huì)通過(guò)不同的方式加載。如果路徑而不是從assets里面加載的話,會(huì)從文件bundle文件所在路徑下加載圖片。
通過(guò)注釋我們知道只要把圖片資源和bundle文件放到同一個(gè)目錄下面就可以訪問(wèn)到, 但是我實(shí)際操作后發(fā)現(xiàn)有些特殊情況需要注意。
比如開發(fā)的項(xiàng)目中:
訪問(wèn)圖片的js文件路徑:/js/login/LoginPage.js
圖片的訪問(wèn)方式:<Image style={styles.container} source={require("./img/icon_search.png")}>
圖片放到同級(jí)目錄img下:/js/login/img/icon_search.png
正確的文件路徑應(yīng)該是在sdcard中在bundle包同級(jí)目錄下的/drawable-mdpi/js_login_img_icon_search.png
這是因?yàn)樵趃etAssetPathInDrawableFolder方法中會(huì)通過(guò)屏幕deviceScale的屬性找到對(duì)應(yīng)的drawable目錄,然后再做一個(gè)拼接。最后拼接出來(lái)的圖片地址:
這種方式如果用戶清理緩存數(shù)據(jù)后js文件又回到了原始狀態(tài),這個(gè)可以可以通過(guò)每次啟動(dòng)檢查更新來(lái)避免。
常見問(wèn)題
Q:RN所支持的最低iOS和Android版本?
A:Android >= 4.1 (API 16) iOS >= 7.0
Q:可以使用現(xiàn)有的js庫(kù)嗎?
A:由于RN理論上更接近nodejs的運(yùn)行環(huán)境,所以對(duì)nodejs的庫(kù)兼容更好一些。瀏覽器端的js庫(kù),涉及到DOM、BOM、CSS等功能的模塊無(wú)法使用,因?yàn)镽N的環(huán)境中沒有這些東西。
Q: 可以使用現(xiàn)有的objc/swift/java庫(kù)嗎
A: 可以但是要做更改。
Q:可以熱更新嗎?蘋果允許嗎?
A:官方?jīng)]有提供熱更新方案, 蘋果目前的政策明確允許基于javascriptCore的熱更新,可以使用微軟推出的Codepush來(lái)更新文件。
報(bào)錯(cuò)
** 1.invariant violation:expected a component class,got[object object]**
創(chuàng)建自定義組件首字母要大寫,否則會(huì)報(bào)錯(cuò).**
** 2. Module 0 is not a registered callable module.**
將gradle升級(jí)成最新版本(cd Android) 進(jìn)入android目錄執(zhí)行:sudo ./gradlew clean) 或者通過(guò)android studio工具升級(jí).
** 3. android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?**
該錯(cuò)誤屬于安卓Native的錯(cuò)誤,如果引用的Activity不存在或者已經(jīng)銷毀,再次引用就會(huì)報(bào)該錯(cuò)誤,如果是React Native調(diào)用原生控件的話,創(chuàng)建控件需要引用:getCurrentActivity()
** 4.android.app.Application cannot be cast to com.facebook.React.ReactApplication.**
需要將創(chuàng)建的MainApplication在AndroidManifest.xml配置好.
** 5. Element type is invalid: expected a string (for built-in components) or a class/function but got: object**
發(fā)生原生一般是你引用了無(wú)效的組件,如果組件確實(shí)正確,看下引用的組件是否正常導(dǎo)出:(export defalut)
** 6. react native undefined is not an object (evaluating this....**
發(fā)生該錯(cuò)誤的一般是忘記bind(this),只要回調(diào)函數(shù)中需要用到this的,一般都需要bind.
** 7. react native - expected a component class, got [object Object]**
該錯(cuò)誤可能是你引用了小寫的組件,組件首字母一定要大寫,比如<login/>應(yīng)該寫成<Login/>**
** 8. Invariant Violation:Application XXXX has not been registered.**
請(qǐng)確保index.*.js中的
AppRegistry.registerComponent('項(xiàng)目名',() => ...);
MainActivity.java中的
@Overrideprotected String getMainComponentName() { return "項(xiàng)目名";}
都保持一致。
** 9. 遇到403 Forbidden錯(cuò)誤.**
首先運(yùn)行netstat -ano 檢查默認(rèn)端口8081被占用的情況,如果被占用可以關(guān)掉占用的程序或者修改端口。
修改端口方法:
-
找到
\node_modules\react-native\local-cli\server\server.js修改default端口號(hào)
Paste_Image.png 在MainActivity中添加
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
mSp.edit().putString("debug_http_host","localhost:7777").commit();
}
端口修改后用chrome調(diào)試會(huì)有問(wèn)題, 這是因?yàn)檎{(diào)試走的端口并沒有被修改,抱歉沒有找到修改的地方,哪位大神找到了麻煩告訴我一聲,我的解決方法是在調(diào)試的時(shí)候手動(dòng)修改debugerWorker.js加載bundle地址的端口號(hào)。

學(xué)習(xí)資料
Flex布局學(xué)習(xí):
http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
資源集合:
https://github.com/reactnativecn/react-native-guide#%E7%BB%84%E4%BB%B6







