重啟React Native老專案的奇幻之旅:填坑實錄與解決方案分享

dreampursuer發表於2024-04-16

這兩天為了重啟五年前基於 React Native(版本 0.59.9)開發的老專案,經過各種填坑查詢等操作,最終把它成功地執行起來了。

在這篇文章中,我將詳述那些遭遇的挑戰以及對應的解決方案,以期為同樣面臨此類困境的開發者提供寶貴的經驗參考。

這個專案涉及到的環境基本版本資訊如下:

react: 16.8.3

react-native: 0.59.9

下載Gradle包

本來想著很簡單,因為這個專案在之前是能正常執行的,我的機器環境就沒有改變過,程式碼也沒有修改過,所以直接執行如下命令:

react-native run-android

然而現實卻是Gradle包下載緩慢且頻繁中斷,後來就透過上外網的方式把它解決了。

不過這種上網的方式下載也是挺慢的,想以後如果不是透過其它上網方式該如何解決呢?

這裡提供一個連結,估計按照下面的方式應該是能更快地下載Gradle包的。

國內最方便的AndroidStudio Gradle包下載方法

NPM證書過期與映象源遷移

想著Gradle下載好了,我又沒有修改過什麼程式碼,總可以把專案給執行起來了吧。

然而是我小看整個過程中碰到的難題了。

再次執行 react-native run-android 命令,直接報瞭如下的錯誤:

[npm] ERR: request to https://registry.npm.taobao.org failed, reason: certificate has expired

碰到問題就直接在網上搜尋相關問題,瞭解下來應該是 npm.taobao.org 和 registry.npm.taobao.org 域名於 2022 年 05 月 31 日零時起停止服務,而 npm.taobao.org 這個網站的證書也於 2024年01月22日過期了,這也就是為啥會出現request to https://registry.npm.taobao.org failed, reason: certificate has expired錯誤的原因。

既然知道了原因,那就把映象源給換掉,新的映象源要切換成 https://registry.npmmirror.com

網上一搜就知道如何切換了,由於我這邊有時用npm有時用yarn,所以就一起把npm和yarn的映象源都設定掉了。

使用的命令如下:

#設定npm的映象源
npm config set registry https://registry.npmmirror.com
#設定yarn的映象源
yarn config set registry https://registry.npmmirror.com

為了檢視映象源是否被設定過來了,就用如下的命令進行驗證:

#檢視npm當前的映象源
npm config get registry
#檢視yarn當前的映象源
yarn config get registry

經過驗證,當前的映象源確實被修改成了https://registry.npmmirror.com

想著這下問題總歸被解決了吧,繼續執行 react-native run-android命令,但出乎我的意料,依然報 request to https://registry.npm.taobao.org failed, reason: certificate has expired 錯誤,而且看起來映象源也沒有被切換過來。

難道是npm中代理設定的問題?

那就檢視一下目前的代理:

#檢視代理
npm config list
yarn config list

發現確實設定過代理,那就先把代理給刪除掉:

# npm刪除代理
npm config delete proxy
npm config delete https-proxy

# yarn刪除代理
yarn config delete proxy
yarn config delete https-proxy

如果以後還要設定代理的話,就把設定代理的命令記錄在這裡,免得以後可以用到:

# npm設定代理
npm config set proxy http://127.0.0.1:8080
npm config set https-proxy http://127.0.0.1:8080

# yarn設定代理
yarn config set proxy http://127.0.0.1:8080
yarn config set https-proxy http://127.0.0.1:8080

刪除了代理後,繼續執行 react-native run-android命令進行驗證,依然報上面的certificate has expired錯誤。看起來有點到了山群水盡的地步,

最後,索性一不做二不休,直接跳過SSL證書驗證,執行下面的命令。

# 跳過npm SSL證書驗證
npm set strict-ssl false
# 跳過yarn SSL證書驗證
yarn config set "strict-ssl" false -g

再次執行react-native run-android命令,這次certificate has expired錯誤消失了。

至少把問題往前推進了一步。

不過也別高興得太早,又碰到了新的問題。且繼續看下面的填坑記錄。

Invalid regular expression引發的困擾

這次報告的錯誤訊息為:

error Invalid regular expression: 
/(.*\\__fixtures__\\.*|node_modules[\\\]react[\\\]dist[\\\].*|website\\node_modules\\.
*|heapCapture\\bundle\.js|.*\\__tests__\\.*)$/:
 Unterminated character class. Run CLI with --verbose flag for more details.

好傢伙,直接報告這一堆亂七八糟的錯誤訊息給我,把我給整懵了。

還好遇事不懂網路搜尋,最後可以透過下面的方式進行解決:

修改檔案\node_modules\metro-config\src\defaults\blacklist.js,把其中的某段內容替換為:

var sharedBlacklist = [
  /node_modules[\/\\]react[\/\\]dist[\/\\].*/,
  /website\/node_modules\/.*/,
  /heapCapture\/bundle\.js/,
  /.*\/__tests__\/.*/
];

根據這個修改的內容推測應該是某個工具對於windows下的打包路徑正規表示式沒有寫好導致的。

再次執行react-native run-android命令,又出現新的么蛾子了...

程式包com.facebook.react.bridge不存在

這次出現的錯誤訊息為:

> Task :react-native-camera:compileGeneralDebugJavaWithJavac
E:\project\exphone\exphoneapp2\node_modules\react-native-camera\android\src\main\java\com\google\android\cameraview\Camera1.java:31: 錯誤: 程式包com.facebook.react.bridge不存在
import com.facebook.react.bridge.ReadableMap;
                                ^
E:\project\exphone\exphoneapp2\node_modules\react-native-camera\android\src\main\java\com\google\android\cameraview\CameraViewImpl.java:23: 錯誤: 程式包com.facebook.react.bridge不存在
import com.facebook.react.bridge.ReadableMap;

依然是上網搜尋,找到了一個解決方案:

如果react-native版本低於0.63,在 android\build.gradle 新增如下內容:

def REACT_NATIVE_VERSION = new File(['node', '--print',"JSON.parse(require('fs').readFileSync(require.resolve('react-native/package.json'), 'utf-8')).version"].execute(null, rootDir).text.trim())

allprojects {
    configurations.all {
        resolutionStrategy {
            // Remove this override in 0.65+, as a proper fix is included in react-native itself.
            force "com.facebook.react:react-native:" + REACT_NATIVE_VERSION
        }
    }

我的react-native版本是0.59.9,低於0.63,那就直接用上面的方法。

再次執行react-native run-android進行驗證,這次總算打包成功了!!!

不過也不要高興得太早,預知後事如何,請繼續...

DeviceException: No connected devices

執行後出現如下的異常:

PS E:\project\exphone\exphoneapp2> react-native run-android
(node:18976) Warning: Accessing non-existent property 'padLevels' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
info Starting JS server...
info Building and installing the app on the device (cd android && gradlew.bat app:installDebug)...
> Task :app:installDebug FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:installDebug'.
> com.android.builder.testing.api.DeviceException: No connected devices!

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

這個異常的核心是com.android.builder.testing.api.DeviceException: No connected devices!

也就是沒有連線到模擬器。

我用的模擬器是BlueStacks藍疊,這個模擬器要比Google的模擬器快。

需要設定的地方是勾選其中允許ADB連線:

明明我的模擬器啟動起來了,為何不能連線上呢?

輸入命令檢視當前模擬器裝置:

# adb devices列出模擬器裝置
PS E:\project\exphone\exphoneapp2> adb devices
List of devices attached

發現確實沒有顯示出連線上的模擬器。

那我們就手動連線一個:

# 使用adb connect進行連線
PS E:\project\exphone\exphoneapp2> adb connect 127.0.0.1:5555
connected to 127.0.0.1:5555
PS E:\project\exphone\exphoneapp2> adb devices               
List of devices attached
127.0.0.1:5555  device    

連線上android模擬器之後,就繼續用react-native run-android命令進行驗證。

打包成功,android模擬器也連線上了,不過期望的介面沒有呈現,只顯示了一個紅色的醒目的錯誤介面。革命尚未成功,同志還需努力... 😭😭😭

執行時TypeError: cb.apply is not a function

在模擬器載入應用後,卻不幸收到了類似如下的異常:

/node_modules/npm/node_modules/graceful-fs/polyfills.js:287
      if (cb) cb.apply(this, arguments)

TypeError: cb.apply is not a function
    at /node_modules/npm/node_modules/graceful-fs/polyfills.js:287:18
    at FSReqCallback.oncomplete (node:fs:199:5)

經過一通網上搜尋,找到其中一個相對簡單的解決方案,就是在package.json中新增:

  "resolutions": {
    "**/graceful-fs": "^4.2.4"
  }

執行react-native run-android終於在模擬器中看到了應用程式成功啟動起來的介面:

總結

至此有種經過九九八十一難總算到了西天取到真經的感覺。

為了便於後續查閱與實踐,這裡整理了一些前面用到的命令,以備後事之需。

映象源管理

#設定npm的映象源
npm config set registry https://registry.npmmirror.com
#設定yarn的映象源
yarn config set registry https://registry.npmmirror.com


#檢視npm當前的映象源
npm config get registry
#檢視yarn當前的映象源
yarn config get registry

快取管理

# 檢視已快取包的列表
yarn cache list

# 查詢cache快取檔案目錄路徑
yarn cache dir

# 清理快取包
npm cache clean --force
yarn cache clean

代理管理

#檢視代理
npm config list
yarn config list

# npm刪除代理
npm config delete proxy
npm config delete https-proxy

# yarn刪除代理
yarn config delete proxy
yarn config delete https-proxy


# npm設定代理
npm config set proxy http://127.0.0.1:8080
npm config set https-proxy http://127.0.0.1:8080

# yarn設定代理
yarn config set proxy http://127.0.0.1:8080
yarn config set https-proxy http://127.0.0.1:8080

證書驗證

# 跳過npm SSL證書驗證
npm set strict-ssl false
# 跳過yarn SSL證書驗證
yarn config set "strict-ssl" false -g

模擬器管理

# adb devices列出模擬器裝置
adb devices
# 使用adb connect進行連線
adb connect 127.0.0.1:5555

相關文章