1. 程式人生 > >記一次在Windows上搭建React Native Android環境踩過的坑

記一次在Windows上搭建React Native Android環境踩過的坑

要說最近技術圈什麼比較活躍,我想除了動態載入框架和熱修復技術之外,非Facebook的React Native莫屬了吧,其實RN對IOS的支援比較早,但是Android似乎難產了,直到9月份才剛開源。距離RN開源也有一段時間了,一直沒有去學習,今天興趣來潮,索性學一把吧。

本文假設你的Windows上安裝了Android SDK,並配置好了環境變數。

安裝Node.js

從官網https://nodejs.org/en/下載Node.js的windows版,也不知道為什麼版本迭代這麼快,之前安裝的時候版本還是v0.12的,如今已經到了v5.1版,直接下載最新版就可以了。安裝的時候記得勾選新增到環境變數中去,這樣就不用手動新增環境變量了。

安裝react-native-cli

開啟命令列,輸入npm install -g react-native-cli

初始化專案

命令列輸入react-native init AwesomeProject,這一步如果卡死,建議翻個牆試試,本人在沒翻牆前直接卡死在這一步,後來用了vpn翻了下牆就初始化好了。

這裡寫圖片描述

啟動React Native Server

命令列進入AwesomeProject目錄,執行react-native start開啟server

這裡寫圖片描述

匯入Android專案

使用Android Studio匯入AwesomeProject/android專案,點選run執行(手機和電腦處於同一區域網內)。點選選單,彈出除錯相關的介面。

這裡有一個深坑!
這裡有一個深坑!
這裡有一個深坑!

重要的事情說三次!

由於該除錯介面使用的是懸浮窗彈出,而我使用的是小米實體機進行除錯的,預設情況下會關閉所有應用的懸浮窗許可權,這時候你怎麼按選單鍵或者玩死裡搖手機,該介面都不會出來。解決方法就是在應用許可權裡開啟懸浮窗許可權。

之後按選單鍵就可以彈出該介面了,修改server地址為你電腦上的ip地址加埠。

這樣,執行程式是沒問題了。

但是我們需要將其打包進apk,所以就需要用到打包命令。

打包Bundle

進入AwesomeProject目錄,命令列執行

react-native bundle –platform android –dev false –entry-file index.android.js –bundle-output C:\Users\Administrator\Desktop\AwesomeProject\android\app\build\intermediates\assets\release\index.android.bundle –assets-dest C:\Users\Administrator\Desktop\AwesomeProject\android\app\build\intermediates\res\merged\release

如果這裡你報錯了,類似下面的錯誤

C:\Users\Administrator\Desktop\AwesomeProject>react-native bundle --platform and
roid --dev false --entry-file index.android.js --bundle-output C:\Users\Administ
rator\Desktop\AwesomeProject\android\app\build\intermediates\assets\release\inde
x.android.bundle --assets-dest C:\Users\Administrator\Desktop\AwesomeProject\and
roid\app\build\intermediates\res\merged\release
C:\Users\Administrator\Desktop\AwesomeProject\node_modules\promise\lib\done.js:1
0
      throw err;
      ^

Error: Took too long to start server. Server logs:
Wed, 18 Nov 2015 05:38:45 GMT ReactNativePackager:SocketServer server got ipc me
ssage { type: 'createSocketServer',
  data:
   { sockPath: 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\react-packager-2bca40
9637da75daf8b8a17b9bdf33aa',
     options:
      { projectRoots: [Object],
        assetRoots: [],
        blacklistRE: [Object],
        transformModulePath: 'C:\\Users\\Administrator\\Desktop\\AwesomeProject\
\node_modules\\react-native\\packager\\transformer.js' } } }
[13:38:45] <START> Building Dependency Graph
[13:38:45] <START> Crawling File System
[13:38:45] <START> Loading bundles layout
[13:38:45] <END>   Loading bundles layout (1ms)
Wed, 18 Nov 2015 05:38:45 GMT ReactNativePackager:SocketServer error creating se
rver EACCES
Wed, 18 Nov 2015 05:38:45 GMT ReactNativePackager:SocketServer uncaught error Er
ror: listen EACCES C:\Users\ADMINI~1\AppData\Local\Temp\react-packager-2bca40963
7da75daf8b8a17b9bdf33aa
    at Object.exports._errnoException (util.js:856:11)
    at exports._exceptionWithHostPort (util.js:879:20)
    at Server._listen2 (net.js:1221:19)
    at listen (net.js:1270:10)
    at Server.listen (net.js:1360:5)
    at new SocketServer (C:/Users/Administrator/Desktop/AwesomeProject/node_modu
les/react-native/packager/react-packager/src/SocketInterface/SocketServer.js:24:
18)
    at process.<anonymous> (C:/Users/Administrator/Desktop/AwesomeProject/node_m
odules/react-native/packager/react-packager/src/SocketInterface/SocketServer.js:
177:7)
    at emitTwo (events.js:87:13)
    at process.emit (events.js:172:7)
    at handleMessage (internal/child_process.js:686:10)
Wed, 18 Nov 2015 05:41:12 GMT ReactNativePackager:SocketServer server got ipc me
ssage { type: 'createSocketServer',
  data:
   { sockPath: 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\react-packager-2bca40
9637da75daf8b8a17b9bdf33aa',
     options:
      { projectRoots: [Object],
        assetRoots: [],
        blacklistRE: [Object],
        transformModulePath: 'C:\\Users\\Administrator\\Desktop\\AwesomeProject\
\node_modules\\react-native\\packager\\transformer.js' } } }
[13:41:12] <START> Building Dependency Graph
[13:41:12] <START> Crawling File System
[13:41:12] <START> Loading bundles layout
[13:41:12] <END>   Loading bundles layout (1ms)
Wed, 18 Nov 2015 05:41:12 GMT ReactNativePackager:SocketServer error creating se
rver EACCES
Wed, 18 Nov 2015 05:41:12 GMT ReactNativePackager:SocketServer uncaught error Er
ror: listen EACCES C:\Users\ADMINI~1\AppData\Local\Temp\react-packager-2bca40963
7da75daf8b8a17b9bdf33aa
    at Object.exports._errnoException (util.js:856:11)
    at exports._exceptionWithHostPort (util.js:879:20)
    at Server._listen2 (net.js:1221:19)
    at listen (net.js:1270:10)
    at Server.listen (net.js:1360:5)
    at new SocketServer (C:/Users/Administrator/Desktop/AwesomeProject/node_modu
les/react-native/packager/react-packager/src/SocketInterface/SocketServer.js:24:
18)
    at process.<anonymous> (C:/Users/Administrator/Desktop/AwesomeProject/node_m
odules/react-native/packager/react-packager/src/SocketInterface/SocketServer.js:
177:7)
    at emitTwo (events.js:87:13)
    at process.emit (events.js:172:7)
    at handleMessage (internal/child_process.js:686:10)
Wed, 18 Nov 2015 05:43:57 GMT ReactNativePackager:SocketServer server got ipc me
ssage { type: 'createSocketServer',
  data:
   { sockPath: 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\react-packager-2bca40
9637da75daf8b8a17b9bdf33aa',
     options:
      { projectRoots: [Object],
        assetRoots: [],
        blacklistRE: [Object],
        transformModulePath: 'C:\\Users\\Administrator\\Desktop\\AwesomeProject\
\node_modules\\react-native\\packager\\transformer.js' } } }
[13:43:57] <START> Building Dependency Graph
[13:43:57] <START> Crawling File System
[13:43:57] <START> Loading bundles layout
[13:43:57] <END>   Loading bundles layout (1ms)
Wed, 18 Nov 2015 05:43:57 GMT ReactNativePackager:SocketServer error creating se
rver EACCES
Wed, 18 Nov 2015 05:43:57 GMT ReactNativePackager:SocketServer uncaught error Er
ror: listen EACCES C:\Users\ADMINI~1\AppData\Local\Temp\react-packager-2bca40963
7da75daf8b8a17b9bdf33aa
    at Object.exports._errnoException (util.js:856:11)
    at exports._exceptionWithHostPort (util.js:879:20)
    at Server._listen2 (net.js:1221:19)
    at listen (net.js:1270:10)
    at Server.listen (net.js:1360:5)
    at new SocketServer (C:/Users/Administrator/Desktop/AwesomeProject/node_modu
les/react-native/packager/react-packager/src/SocketInterface/SocketServer.js:24:
18)
    at process.<anonymous> (C:/Users/Administrator/Desktop/AwesomeProject/node_m
odules/react-native/packager/react-packager/src/SocketInterface/SocketServer.js:
177:7)
    at emitTwo (events.js:87:13)
    at process.emit (events.js:172:7)
    at handleMessage (internal/child_process.js:686:10)
Wed, 18 Nov 2015 05:55:30 GMT ReactNativePackager:SocketServer server got ipc me
ssage { type: 'createSocketServer',
  data:
   { sockPath: 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\react-packager-2bca40
9637da75daf8b8a17b9bdf33aa',
     options:
      { projectRoots: [Object],
        assetRoots: [],
        blacklistRE: [Object],
        transformModulePath: 'C:\\Users\\Administrator\\Desktop\\AwesomeProject\
\node_modules\\react-native\\packager\\transformer.js' } } }
[13:55:30] <START> Building Dependency Graph
[13:55:31] <START> Crawling File System
[13:55:31] <START> Loading bundles layout
[13:55:31] <END>   Loading bundles layout (0ms)
Wed, 18 Nov 2015 05:55:31 GMT ReactNativePackager:SocketServer error creating se
rver EACCES
Wed, 18 Nov 2015 05:55:31 GMT ReactNativePackager:SocketServer uncaught error Er
ror: listen EACCES C:\Users\ADMINI~1\AppData\Local\Temp\react-packager-2bca40963
7da75daf8b8a17b9bdf33aa
    at Object.exports._errnoException (util.js:856:11)
    at exports._exceptionWithHostPort (util.js:879:20)
    at Server._listen2 (net.js:1221:19)
    at listen (net.js:1270:10)
    at Server.listen (net.js:1360:5)
    at new SocketServer (C:/Users/Administrator/Desktop/AwesomeProject/node_modu
les/react-native/packager/react-packager/src/SocketInterface/SocketServer.js:24:
18)
    at process.<anonymous> (C:/Users/Administrator/Desktop/AwesomeProject/node_m
odules/react-native/packager/react-packager/src/SocketInterface/SocketServer.js:
177:7)
    at emitTwo (events.js:87:13)
    at process.emit (events.js:172:7)
    at handleMessage (internal/child_process.js:686:10)
Wed, 18 Nov 2015 05:57:02 GMT ReactNativePackager:SocketServer server got ipc me
ssage { type: 'createSocketServer',
  data:
   { sockPath: 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\react-packager-2bca40
9637da75daf8b8a17b9bdf33aa',
     options:
      { projectRoots: [Object],
        assetRoots: [],
        blacklistRE: [Object],
        transformModulePath: 'C:\\Users\\Administrator\\Desktop\\AwesomeProject\
\node_modules\\react-native\\packager\\transformer.js' } } }
[13:57:02] <START> Building Dependency Graph
[13:57:02] <START> Crawling File System
[13:57:02] <START> Loading bundles layout
[13:57:02] <END>   Loading bundles layout (0ms)
Wed, 18 Nov 2015 05:57:02 GMT ReactNativePackager:SocketServer error creating se
rver EACCES
Wed, 18 Nov 2015 05:57:02 GMT ReactNativePackager:SocketServer uncaught error Er
ror: listen EACCES C:\Users\ADMINI~1\AppData\Local\Temp\react-packager-2bca40963
7da75daf8b8a17b9bdf33aa
    at Object.exports._errnoException (util.js:856:11)
    at exports._exceptionWithHostPort (util.js:879:20)
    at Server._listen2 (net.js:1221:19)
    at listen (net.js:1270:10)
    at Server.listen (net.js:1360:5)
    at new SocketServer (C:/Users/Administrator/Desktop/AwesomeProject/node_modu
les/react-native/packager/react-packager/src/SocketInterface/SocketServer.js:24:
18)
    at process.<anonymous> (C:/Users/Administrator/Desktop/AwesomeProject/node_m
odules/react-native/packager/react-packager/src/SocketInterface/SocketServer.js:
177:7)
    at emitTwo (events.js:87:13)
    at process.emit (events.js:172:7)
    at handleMessage (internal/child_process.js:686:10)

    at [object Object]._onTimeout (C:/Users/Administrator/Desktop/AwesomeProject
/node_modules/react-native/packager/react-packager/src/SocketInterface/index.js:
82:7)
    at Timer.listOnTimeout (timers.js:92:15)

解決方法就是修改AwesomeProject/node_modules/react-native/packager/react-packager/src/SocketInterface/index.js檔案中40行附件的

  const sockPath = path.join(
    tmpdir,
    'react-packager-' + hash.digest('hex')
  );

為下面的內容


  let sockPath = path.join(
    tmpdir,
    'react-packager-' + hash.digest('hex')
  );
  if (process.platform==='win32'){
    sockPath = sockPath.replace(/^\//, '')
    sockPath = sockPath.replace(/\//g, '-')
    sockPath = '\\\\.\\pipe\\' + sockPath
  }

之後將生成的index.android.bundle拷到assets目錄即可。

這裡也有一個深坑。

Android Studio中,android目錄下的build.gradle會使用react.gradle,該檔案中就是打包bundle的task

def config = project.hasProperty("react") ? project.react : [];

def bundleAssetName = config.bundleAssetName ?: "index.android.bundle"
def entryFile = config.entryFile ?: "index.android.js"

// because elvis operator
def elvisFile(thing) {
    return thing ? file(thing) : null;
}

def reactRoot = elvisFile(config.root) ?: file("../../")
def jsBundleDirDebug = elvisFile(config.jsBundleDirDebug) ?:
        file("$buildDir/intermediates/assets/debug")
def jsBundleDirRelease = elvisFile(config.jsBundleDirRelease) ?:
        file("$buildDir/intermediates/assets/release")
def resourcesDirDebug = elvisFile(config.resourcesDirDebug) ?:
        file("$buildDir/intermediates/res/merged/debug")
def resourcesDirRelease = elvisFile(config.resourcesDirRelease) ?:
        file("$buildDir/intermediates/res/merged/release")
def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"]

def jsBundleFileDebug = file("$jsBundleDirDebug/$bundleAssetName")
def jsBundleFileRelease = file("$jsBundleDirRelease/$bundleAssetName")

task bundleDebugJsAndAssets(type: Exec) {
    // create dirs if they are not there (e.g. the "clean" task just ran)
    doFirst {
        jsBundleDirDebug.mkdirs()
        resourcesDirDebug.mkdirs()
    }

    // set up inputs and outputs so gradle can cache the result
    inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
    outputs.dir jsBundleDirDebug
    outputs.dir resourcesDirDebug

    // set up the call to the react-native cli
    workingDir reactRoot
    commandLine "react-native", "bundle", "--platform", "android", "--dev", "true", "--entry-file",
            entryFile, "--bundle-output", jsBundleFileDebug, "--assets-dest", resourcesDirDebug

    enabled config.bundleInDebug ?: false
}

task bundleReleaseJsAndAssets(type: Exec) {
    // create dirs if they are not there (e.g. the "clean" task just ran)
    doFirst {
        jsBundleDirRelease.mkdirs()
        resourcesDirRelease.mkdirs()
    }

    // set up inputs and outputs so gradle can cache the result
    inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
    outputs.dir jsBundleDirRelease
    outputs.dir resourcesDirRelease

    // set up the call to the react-native cli
    workingDir reactRoot
    commandLine "react-native", "bundle", "--platform", "android", "--dev", "false", "--entry-file",
            entryFile, "--bundle-output", jsBundleFileRelease, "--assets-dest", resourcesDirRelease

    enabled config.bundleInRelease ?: true
}

gradle.projectsEvaluated {
    // hook bundleDebugJsAndAssets into the android build process
    bundleDebugJsAndAssets.dependsOn mergeDebugResources
    bundleDebugJsAndAssets.dependsOn mergeDebugAssets
    processDebugResources.dependsOn bundleDebugJsAndAssets

    // hook bundleReleaseJsAndAssets into the android build process
    bundleReleaseJsAndAssets.dependsOn mergeReleaseResources
    bundleReleaseJsAndAssets.dependsOn mergeReleaseAssets
    processReleaseResources.dependsOn bundleReleaseJsAndAssets
}

如果我們執行bundleReleaseJsAndAssets,或者bundleDebugJsAndAssets這兩個task,不知道什麼原因,總是報錯,但是將對應的命令

react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output C:\Users\Administrator\Desktop\AwesomeProject\android\app\build\intermediates\assets\release\index.android.bundle --assets-dest C:\Users\Administrator\Desktop\AwesomeProject\android\app\build\intermediates\res\merged\release

複製到命令列執行,卻是可以生成bundle檔案的,然而上面的兩個task最終執行的就是這條命令,但是無論怎麼樣它就是報錯,最後無奈只能命令列生成,也無傷什麼大雅。

如果知道這個問題原因是什麼的,也請告知!