在你的APP有一定的規模後
就是要建置給內部人員 or 客戶測試使用
本篇會使用Expo專案
搭著React Native官方Android打包說明
帶你完成建置Android APP
※本篇使用環境為Windows PC & Visual Studio Code IDE
稍微講解一下Android建置原理
(iOS建置概念相同,本篇一併介紹)
以及為何Expo有推出EAS CI/CD建置工具而不使用
雙平台差不多,這邊就一併講解
手做一張建置流程圖提供參考
<View> <Text>
實際上是在底層原生代碼中使用的Expo專案對Android打包手冊參考:
https://docs.expo.dev/build-reference/apk/
使用免費版EAS Build雲端建置時
曾經排隊建置時間(Quene time)等了3h 9m 0s
建置時間(Build time)也長達10m 41s
排隊時間還會隨著建置時間逐漸累加😡
在金錢成本吃緊的情況下
打消了Expo EAS雲端建置上架的念頭
在新增Android專案前
得先調整好APP的名稱、LOGO、版本、權限
Expo對於app.json的所有設定講解
https://docs.expo.dev/versions/latest/config/app/
這邊只列出Expo在新增專案時所使用的
"name": "我是Expo系統",
"slug": "TestExpoApp",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./img/logo.jpg",
"splash": {
"image": "./img/logo2.jpg",
"resizeMode": "contain",
"backgroundColor": "#000000"
}
name
應用程式名稱,在使用者安裝APP後會看到此名稱slug
識別專案名稱,通常用於APP建置在Expo服務器中使用https://expo.io/@你的用戶名/你的slug
version
版本號,讓Play商店知道你現在的APP版本orientation
APP方向,可以設定APP要直向還是橫向,預設雙向可用icon
APP的圖示,一定要記得修改圖示userInterfaceStyle
介面外觀,可調整深色、淺色模式(預設為淺色)splash
啟動畫面圖示另外針對android部分,進行細節設定
"android": {
"package": "com.xxx.TestxxxAPP",
"permissions":["ACCESS_COARSE_LOCATION","ACCESS_FINE_LOCATION","ACCESS_BACKGROUND_LOCATION"],
"versionCode": 1
},
package
Android應用程式 ID,參考下方命名方式應用程式 ID 的命名規則比較嚴格:
必須包含至少兩個區隔 (一或多個點)。
每個區隔的開頭都必須是英文字母。
所有字元都必須為英數字元或底線 [a-zA-Z0-9_]。
permissions
Android權限versionCode
Play商店內部識別版本號,此版本號使用者不可見React Native Android專案使用Gradle建置工具
在下載Android Studio時,Gradle也會一併被下載
Windows使用者:需先安裝Java、JDK (Java Development Kit)後才能使用建置工具
MAC使用者:可參考Mac 上用 Homebrew 安裝 Java 的方式
在安裝Java完成後
需手動設定JAVA_HOME
環境變數
才能在VS Code終端機直接使用Java相關功能
Windows 10使用者:
JAVA_HOME
系統變數,變數值為JDK安裝路徑C:\Program Files\Java\jdk-17
(JDK版本有更新記得調整此部分)MAC使用者:
在終端機輸入下方指令就能設定環境變數了export JAVA_HOME="$(/usr/libexec/java_home)"
Expo專案預先是不會幫你建好Android專案
必須先使用該指令:npx expo prebuild
(在MACOS則會新增ios資料夾)
※若你已有Android資料夾,則不一定要使用該指令
通常有SDK升級、新權限才會使用該指令
因為本段指令會將專案重建
其他環境指令參數參考:
https://docs.expo.dev/workflow/prebuild/
指令下達成功後,資料夾內容如圖
keystore主要是讓APP識別開發者資訊
以及加密簽署APP、憑證存取、用戶密碼儲存...等
另外keystore是可以簽署多支APP的
設定一次之後,一定要記得保留此簽署檔
Web使用者可以當作是,產出TLS安全協議憑證(https)的概念
Android開發者專區針對keystore介紹:
https://developer.android.com/training/articles/keystore
※使用指令前,需使用系統管理員權限之終端機
使用keytool(Java內建公用程式)keytool -genkeypair -v -storetype PKCS12 -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
-genkeypair
告訴keytool需創建一對密鑰-v
verbose,詳細列出操作進展-storetype PKCS12
指定密鑰存儲的類型(PKCS12)-keystore my-release-key.keystore
keystore檔的檔名,可自行調整-alias my-key-alias
金鑰別名,用於識別 keystore 中的密鑰對-keyalg RSA
加密演算法(RSA)-keysize 2048
演算法密鑰的位數,長度越長,安全性越高,但相對計算更久-validity 10000
證書有效期限(10000天),可依需求自行調整執行後會需要填入一些公司行號/個人資訊
設定完後keystore路徑會在C:\Program Files\Java\jdkx.x.x_x\bin
最後將產出後的keystore檔
放到android\app
資料夾中
找到android/gradle.properties
gradle配置設定檔
在檔案下方加入以下設定,讓gradle知道要使用哪一份簽署檔
# 以下是發布Keysotre設定
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
MYAPP_RELEASE_STORE_PASSWORD=qaz555
MYAPP_RELEASE_KEY_PASSWORD=qaz555
設定值會以當時使用keytool產出的內容為主
找到android/app/build.gradle
應用程式建置設定
找到下方有一項signingConfigs
設定
加上release
讀取上方properties
的內容值
參數名稱可以自行改掉MYAPP_RELEASE...
只要參數名稱有對應到,就能讀取剛剛設定好的keystore檔了
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
release {
if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
}
另外,React Native官方還要求調整buildTypes
設定
將signingConfigs
調整為release
在打包之前確定使用release
版本的keystore檔
buildTypes {
release {
...
signingConfig signingConfigs.release
}
}
參考:https://reactnative.dev/docs/signed-apk-android
在外層也有一支build.gradle,常常讓開發者混淆
外層build.gradle只能做全域型設定
(Gradle版本、所有子專案的依賴關係、全局的Gradle插件)
APK(Android Package)是Android平台的套件檔案格式
Android使用者只要對著APK點一下
就能將APP安裝進去
適用於內部上架
不透過Play商店,讓使用者下載APP
若你自身已有網站
可以將APK檔放到網站主機上,並設定好路徑讓使用者下載APK
產出APK指令:
cd android
./gradlew assembleRelease
成功後APK路徑如下APP資料夾\android\app\build\outputs\apk\release
打包過程中會看到Expo模組一個個被gradle轉譯
AAB(Android APP Bundle)是Android 2018年推出的新版格式
可以縮小APP的容量
Android官方文件對於AAB格式詳細說明:
https://developer.android.com/guide/app-bundle/faq?hl=zh-tw#what_is_the_android_app_bundle_aab
目前上架Play商店時,需使用此格式
產出AAB指令:
cd android
./gradlew bundleRelease
成功後AAB路徑如下APP資料夾\android\app\build\outputs\bundle\release
下圖代表建置成功,你的第一支APP就此誕生👏
※建置時間會取決於電腦處理速度及運算能力
若過程中發生Error,需初步檢查以下內容
npx expo-doctor
請醫生診斷整個專案的套件是否衝突npx expo run:android
是否正常在實體手機/模擬器執行node_modules
資料夾刪除npm install
將套件安裝回來若還是發生其他不可預期的Error
可以將錯誤訊息貼到Google or ChatGPT查看是否有同樣解法
結語:
Android專案其實還有非常多的設定
都是Expo建置時,就已經設定完成
想了解其他設定值可以參考React Native官方文件
react-native-gradle-plugin
如果你的專案不需上架至Play商店
那麼本篇已經完成你的第一支Android APP了🤟
若你需要上架至Play商店
那麼AAB檔打包後請留在電腦裡,下一篇會使用
下一篇要來講解
讓你的Android APP上架至Play商店,讓大家來安裝。
版主辛苦了
以下是我跟著步驟所遇到的問題以及如何解決
第一個是在使用keytool
若是事先沒有先設好JAVA_HOME環境變數且沒有使用系統管理員啟動命令提示字元(CMD),會無法建置keystore。(有可能是因為我跳著看文章導致前面有提過所以沒設置到)
第二個是在設定build.gradle時
根據版主的程式碼:
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
release {
if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
會出現錯誤訊息如下:
Could not find method release() for arguments [build_9yszuqzdc3k78iio30o9ei0u6$_run_closure2$_closure7@7aa4ca12] on extension 'android' of type com.android.build.gradle.internal.dsl.BaseAppModuleExtension.
修改程式碼為:
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
release {
if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
}
就可以正常建置了。
感謝你的測試🙏
JAVA_HOME
環境變數的部分真的是少講到signingConfigs
部分是貼Code的時候debug
那塊多打一個大括弧😢皆已調整文章內容了。
補充一下(?
當在 app/build.gradle 下放入 signingConfigs 的 release 設定後,還要調整下面的 buildTypes,設定當 release 時 signingConfig 要讀 signingConfigs.release
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
signingConfig signingConfigs.release
}
}
感謝🙏
文章調整了