1. 程式人生 > >React Native釋出APP之簽名打包APK

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

這樣一行資訊,然後APP在啟動頁載入一會才進入應用。通過瀏覽器訪問上面的連結,發現連結返回的是一個js檔案,開啟該檔案發現檔案中的程式碼其實是我們寫的 React Native 的 JS 程式碼。
PS.
1. 在開發環境下,每次啟動APP,都會連線JS Server將專案中編寫的js檔案程式碼載入到APP(這也是React Native的動態更新的精髓)。
2. 簽名打包後的APK已經從開發環境變成了生產環境,自然不會在每次啟動的時候連線JS Server載入相應的js檔案。所以導致APP因缺少相應的js而無法啟動。

既然Android Stuio打包行不通,那麼我們採用React Native官方推薦的方式

進行簽名打包(下文會重點講解“通過官方推薦的方式簽名打包”),打包過程很順利,將打包好的APK安裝到手機上後,發現能正常執行。
對比用Android Studio簽名打包生成的APK與用官方推薦方式簽名打包生成的APK,發現了它們在大小上和內容上都有所差別,如圖:
大小上的差別:
兩種打包方式apk大小差異.png

對比兩種打包方式發現,它們所生成的apk在大小上相差幾百k。為什麼會相差那麼大呢,帶著這個疑問我們就將兩個apk解壓之後看看他們內部具體有什麼不同。
apk內部差別:
兩種方式簽名打包的APK內部差別.png

上圖是解壓之後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變數

  1. 將你的簽名證書copy到 android/app目錄下。
  2. 編輯~/.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

簽名打包成功.png

簽名打包成功後你會在 “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訪問“鑰匙串訪問”工具來獲取證書密碼。

具體步驟:

  1. cmd+space開啟“鑰匙串訪問(Keychain Access)”工具。
  2. 在登入選項中新鑰匙串,如圖:
    通過“鑰匙串訪問(Keychain Access)”工具保護密碼安全  .png

提示: 你可以在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中設定一下的。

About

推薦閱讀