我們都知道在Debug模式下,會去載入JS Server服務的bundle。在Release模式下會去載入本地的bundle,原生中是如果確定bundle的載入路徑的?什麼時候會在Debug模式下載入本地的bundle?在下文中會分別對iOS和Android原生程式碼的中如何確定bundle載入路徑進行分析。
iOS的bundle載入路徑確認以及遇到的飄紅(RCTRedBox)
第一步:packageHost的確定
在Debug模式下會去guessPackagerHost
,沒錯,就是去猜packageHost,猜的步驟如下:
- 查詢是否有ip.txt檔案在bundle中,有的話就把ip.txt的內容讀出來,沒有的話就是用localhost。
- 然後是用host和port拼成
http://localhost:8081/status
傳送請求,如果返回的是packager-status:running
.代表packagerHost是可用的,會返回這個host,否則返回null。
在Rlease模式下如果沒有設定host在偏好設定中,則會返回null。
第二步:bundle路徑(jsCodeLocation)的確定
如果第一步的host不為null,則會拼成:http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false
的url。如果第一步的host為空,則會去載入mainBundle(可以簡略理解成本地的)中的main.jsbundle。
注意:如果本地沒有main.jsbundle則會返回null,這個會導致後面飄紅。
第三步:bridge去載入jsCodeLocation
前話:bundleURL不存在或載入過程中失敗的飄紅都是從這裡出來的。
可以在這裡打斷點:
RCTBatchedBridge.m->(void)stopLoadingWithError:複製程式碼
1、第一個遇到的錯誤:
//RCTBatchBridge.m -> (void)loadSource:_onSourceLoad:onProgress
bundleURL must be non-nil when not implementing loadSourceForBridge複製程式碼
如果飄了這個錯誤,證明bundleURL為空,這是就是第二步注意事項提到的,這時可以確定的是它連不上JS Server才導致它試圖去找本地的main.jsbundle,但是很遺憾,本地也沒找到,那麼可以按以下步驟檢查:
- 是否開了JS Server
- 是否科學上網了。
- 是否在同一個區域網內。
- 是否需要指定host(通過ip.txt),而不能使用localhost。
- 或者你指定了ip(通過ip.txt),但是卻重啟路由之類的,導致ip改了。
2、JS端的堆疊資訊列印
會把檔名,方法名,行號列印出來,最後會把錯誤描述在最上面。
遇到這種錯誤是因為JS Server檢查出了js方的錯誤,並返回了錯誤資訊。此時對著錯誤調就好了,比較簡單,調好後再reload。
3、網路錯誤,如果確定網路正常,並且第1個錯誤的檢查點都檢查了,可以多刷幾次。因為可能是超時,或偶爾出現的500。
Could not connect to development server
Ensure the following
- Node server is running and available on the same network - run `npm start` from react-native root
- Node server URL is correctly set in AppDelegate
URL: *****複製程式碼
4、Remote Debug JS 連線不上的錯誤
這種錯誤會報到RCTWebSocketExecutor上去,很有可能是在Debug模式下開了Remote Debug JS,卻沒開JS Server,然後加了到了本地的bundle。這時候需要開啟JS Server,然後重啟應用,關閉Remote Debug JS即可。
Connection to http://localhost:8081/debugger-proxy?role=client timed out.Are you running...複製程式碼
總結
由上可以知道在Debug模式下,iOS會先會嘗試連線它自己guess的host(使用ip.txt指定了,不然預設為localhost),如果沒有獲取到則會去嘗試載入本地的main.jsbundle,當本地也沒有bundle時就會報錯了(本地的main.jsbundle何時存在可以參考這篇文章:探索react-native run-ios(android))。在Release模式下是不會去猜host的,直接去載入本地的jsbundle。
Android的bundle載入路徑確認以及遇到的飄紅
Android的bundle路徑嘗試方式與iOS完全相反,它的大致思路是無論是Release還是Debug模式下都嘗試去載入本地的index.android.bundle,當在Debug模式下載入不到時會直接飄紅,然後我們需要搖出開發者選項設定ip和埠,Reload後才能去載入JS Server的bundle。
因為Android的自動打包bundle與iOS不一樣(可以參考這篇文章:探索react-native run-ios(android)),所以如果想在Debug模式下做原生開發,又不想開JS Server時,可以打個bundle放到assets下,這樣它就不會去載入JS Server中的去了。
在專案中的應用
1、在混合開發時,可以給iOS和Android原生都打bundle包,這樣原生就算在Debug模式下不開JS Server也不會有問題。不過這時js開發必須把Android中的index.android.bundle刪了才能載入JS Server中的內容。
2、ios可以在專案中加入一個ip.txt檔案(指定JS Server)然後再重編來重定向JS Server。
簡書同步更新地址:www.jianshu.com/u/b92ab7b3a…