React Native釋出APP之簽名打包APK
用React Native開發好APP之後,如何將APP釋出以供使用者使用呢?一款APP的釋出流程無外乎:簽名打包—>釋出到各store這兩大步驟。本文將向大家分享如何簽名打包一款React Native APP。
眾所周知,Android要求所有的APP都需要進行數字簽名後,才能夠被安裝到相應的裝置上。簽名打包一個Android APP已經是每一位Android開發者的家常便飯了。
那麼如何簽名打包一款用React Native開發的APP呢?
既然Android Studio中可以進行APP的簽名打包,那我們可不可以用它進行打包呢,實踐表明用Android Studio打包React Native APP不是一種推薦的方案。
為什麼不用Android Studio打包React Native APP?
在發這篇博文前我曾試著用Android Studio打包React Native APP,編譯,打包,安裝各項指數正常,當我欣喜在手機上開啟APP看一下效果時,APP在啟動時閃退了。多試幾次依然如此,這時讓我想起每次通過terminal安裝APP到模擬器上時,launchPackager.command
終端都會輸出http://localhost:8081/index.android.bundle?platform=android&dev=true&hot=false&minify=false
PS.
1. 在開發環境下,每次啟動APP,都會連線JS Server將專案中編寫的js檔案程式碼載入到APP(這也是React Native的動態更新的精髓)。
2. 簽名打包後的APK已經從開發環境變成了生產環境,自然不會在每次啟動的時候連線JS Server載入相應的js檔案。所以導致APP因缺少相應的js而無法啟動。
既然Android Stuio打包行不通,那麼我們採用React Native官方推薦的方式
對比用Android Studio簽名打包生成的APK與用官方推薦方式簽名打包生成的APK,發現了它們在大小上和內容上都有所差別,如圖:
大小上的差別:
對比兩種打包方式發現,它們所生成的apk在大小上相差幾百k。為什麼會相差那麼大呢,帶著這個疑問我們就將兩個apk解壓之後看看他們內部具體有什麼不同。
apk內部差別:
上圖是解壓之後apk的內部細節,發現通過官方推薦的方式打包的apk多了兩個檔案“index.android.bundle”與“index.android.bundle.meta”,開啟“index.android.bundle”發現其和從http://localhost:8081/index.android.bundle?platform=android&dev=true&hot=false&minify=false
獲取的檔案內容是一樣的,都是我們寫的 React Native 的 JS 程式碼。
結論
1. 在開發環境下,為方便除錯,APP會在啟動時從JS Server伺服器將index.android.bundle檔案載入到APP。
2. 簽名打包後的APP變成了生產環境,此時APP會預設從本地載入 index.android.bundle檔案,由於通過Android Studio打包的APK沒有將index.android.bundle打包進apk,所以會因缺少index.android.bundle而無法啟動。
通過官方推薦的方式簽名打包APK
第一步:生成Android簽名證書
如果你已經有簽名證書可以繞過此步驟。
簽名APK需要一個證書用於為APP簽名,生成簽名證書可以Android Studio以視覺化的方式生成,也可以使用終端採用命令列的方式生成,需要的可以自行Google這裡不再敖述。
第二步:設定gradle變數
- 將你的簽名證書copy到 android/app目錄下。
- 編輯
~/.gradle/gradle.properties
或../android/gradle.properties
(一個是全域性gradle.properties
,一個是專案中的gradle.properties
,大家可以根據需要進行修改) ,加入如下程式碼:
MYAPP_RELEASE_STORE_FILE=your keystore filename
MYAPP_RELEASE_KEY_ALIAS=your keystore alias
MYAPP_RELEASE_STORE_PASSWORD=*****
MYAPP_RELEASE_KEY_PASSWORD=*****
提示:用正確的證書密碼、alias以及key密碼替換掉 *。
第三步:在gradle配置檔案中添加簽名配置
編輯 android/app/build.gradle檔案新增如下程式碼:
...
android {
...
defaultConfig { ... }
signingConfigs {
release {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
buildTypes {
release {
...
signingConfig signingConfigs.release
}
}
}
...
第四步:簽名打包APK
terminal進入專案下的android目錄,執行如下程式碼:
./gradlew assembleRelease
簽名打包成功後你會在 “android/app/build/outputs/apk/”目錄下看到簽名成功後的app-release.apk檔案。
提示:如果你需要對apk進行混淆打包 編輯android/app/build.gradle:
/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
def enableProguardInReleaseBuilds = true
如何在gradle中不使用明文密碼?
上文中直接將證書密碼以明文的形式寫在了gradle.properties檔案中,雖然可以將此檔案排除在版本控制之外,但也無法保證密碼的安全,下面將向大家分享一種方法避免在gradle中直接使用明文密碼。
通過“鑰匙串訪問(Keychain Access)”工具保護密碼安全
下面闡述的方法只在OS X上可行。
我們可以通過將釋出證書密碼委託在“鑰匙串訪問(Keychain Access)”工具中,然後通過gradle訪問“鑰匙串訪問”工具來獲取證書密碼。
具體步驟:
cmd+space
開啟“鑰匙串訪問(Keychain Access)”工具。- 在登入選項中新鑰匙串,如圖:
提示: 你可以在terminal中執行如下命令檢查新建的鑰匙串是否成功。
security find-generic-password -s android_keystore -w
3. 在build.gradle中訪問你的祕鑰串,將下列程式碼編輯到android/app/build.gradle中:
def getPassword(String currentUser, String keyChain) {
def stdout = new ByteArrayOutputStream()
def stderr = new ByteArrayOutputStream()
exec {
commandLine 'security', '-q', 'find-generic-password', '-a', currentUser, '-s', keyChain, '-w'
standardOutput = stdout
errorOutput = stderr
ignoreExitValue true
}
//noinspection GroovyAssignabilityCheck
stdout.toString().trim()
}
// Add this line
def pass = getPassword("YOUR_USER_NAME","android_keystore")
...
android {
...
defaultConfig { ... }
signingConfigs {
release {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword pass // Change this
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword pass // Change this
}
}
buildTypes {
release {
...
signingConfig signingConfigs.release
}
}
}
...
注意事項
鑰匙串訪問(Keychain Access)工具只是幫我們託管了,證書密碼,證書明和alias還是需要我們在gradle.properties
中設定一下的。