Android 工程实践
本文讲述 React Native 工程化,Android 工程需要做的准备工作。
本文包括以下内容
- 生成签名密钥
- 混淆配置
生成签名密钥
使用 Android Studio 打开我们的 Android 项目,并生成密钥和密钥库
在菜单栏中,点击 Build > Build > Generate Signed Bundle/APK
在 Generate Signed Bundle or APK 对话框中,选择 APK,然后点击 Next
在 Key store path 字段下面,点击 Create new
在 New Key Store 窗口上,为您的密钥库和密钥提供以下信息,如图
Key store path 选择 android/keystores/release
生成的密钥请务必备份,且妥善保管,一般情况下,为了安全,不宜放在项目文件夹内,不宜加入到版本控制系统,这是另外一个问题,本文不作展开。
填写完表单后,请点击 OK。
- 在 Generate Signed Bundle or APK 对话框中,点击 Cancel
- 配置签名文件
android {
signingConfigs {
config {
keyAlias 'MyApp'
keyPassword '123456'
storeFile file('../keystores/release')
storePassword '123456'
}
}
buildTypes {
release {
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
signingConfig signingConfigs.config
}
debug {
signingConfig signingConfigs.config
}
}
}
组装 APK
- 设置应用 Application ID
修改 android/app/build.gradle 文件
设置 applicationId:
android {
defaultConfig {
applicationId System.getenv("APPLICATION_ID") ?: "com.xxxxxx.mayapp"
}
}
- 分离不同 CPU 架构的 APK
修改 android/app/build.gradle 文件
android {
splits {
abi {
reset()
enable true
universalApk true // If true, also generate a universal APK
include "arm64-v8a", "armeabi-v7a", "x86_64"
}
}
}
- 移除生成 Version Code 的脚本,因为后续我们会通过 CI 变量来处理 version code。
修改 android/app/build.gradle 文件
- import com.android.build.OutputFile
android{
defaultConfig {
- versionCode 1
+ versionCode ((System.getenv("VERSION_CODE") ?: '1').toInteger())
- versionName "1.0"
+ versionName (System.getenv("VERSION_NAME") ?: '1.0.0')
}
- // applicationVariants are e.g. debug, release
- applicationVariants.all { variant ->
- variant.outputs.each { output ->
- // For each separate APK per architecture, set a unique version code as described here:
- // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
- def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
- def abi = output.getFilter(OutputFile.ABI)
- if (abi != null) { // null for the universal-debug, universal-release variants
- output.versionCodeOverride =
- versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
- }
- }
- }
}
最终看起来的效果像这样
apply plugin: "com.android.application"
project.ext.react = [
entryFile: "index.js"
]
apply from: "../../node_modules/react-native/react.gradle"
android {
compileSdkVersion rootProject.ext.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
applicationId System.getenv("APPLICATION_ID") ?: "com.xxxxxx.mayapp"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode ((System.getenv("VERSION_CODE") ?: '1').toInteger())
versionName (System.getenv("VERSION_NAME") ?: '1.0.0')
}
splits {
abi {
reset()
enable true
universalApk true // If true, also generate a universal APK
include "arm64-v8a", "armeabi-v7a", "x86_64"
}
}
signingConfigs {
config {
keyAlias 'MyApp'
keyPassword '123456'
storeFile file('../keystores/release')
storePassword '123456'
}
}
buildTypes {
release {
// 打生产包时,混淆 java 代码
minifyEnabled true
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
signingConfig signingConfigs.config
}
debug {
signingConfig signingConfigs.config
}
}
flavorDimensions "default"
productFlavors {
qa {
}
production {
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" // From node_modules
}
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}
- 添加混淆配置
打开 android/app/proguard-rules.pro 文件,添加如下混淆配置
-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
# Do not strip any method/class that is annotated with @DoNotStrip
-keep @com.facebook.proguard.annotations.DoNotStrip class *
-keepclassmembers class * {
@com.facebook.proguard.annotations.DoNotStrip *;
}
-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
void set*(***);
*** get*();
}
-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
-keep class * extends com.facebook.react.bridge.NativeModule { *; }
-keepclassmembers,includedescriptorclasses class * { native <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.UIProp <fields>; }
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }
-dontwarn com.facebook.react.**
-keep class android.text {* ;}
-dontwarn android.text.*
-keep class com.facebook.react.bridge.CatalystInstanceImpl { *; }
-keep class com.facebook.react.bridge.JavaScriptExecutor { *; }
-keep class com.facebook.react.bridge.queue.NativeRunnable { *; }
-keep class com.facebook.react.bridge.ReadableType { *; }
# okhttp
-keepattributes Signature
-keepattributes *Annotation*
-keep class com.squareup.okhttp.** { *; }
-keep interface com.squareup.okhttp.** { *; }
-dontwarn com.squareup.okhttp.**
# okio
-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn okio.**
# stetho
-dontwarn com.facebook.stetho.**
# sentry
-keepattributes LineNumberTable,SourceFile
-dontwarn org.slf4j.**
-dontwarn javax.**
-keep class io.sentry.event.Event { *; }
- 尝试构建
cd 到 android 文件夹,执行如下命令,尝试构建 production 环境的包
cd android
./gradlew assembleProductionRelease
构建成功后,可以在 anroid/app/build/outputs/apk/production/release 下,看到两个 APK 包,一个可以安装在真机上,一个可以安装在模拟器上。
使用 adb install
命令安装即可