介绍

本文介绍如何配置 Gradle 打包 Android。

系列

环境

  • Unity 2019.4.32f1
  • Android Studio 2021.1.1 Patch 2
  • Gradle 6.8

Unity 导出 Gradle 工程

导出

使用 Unity 2019 导出工程后直接使用 Android Studio 调用 Gradle 打包。

官方文档介绍了导出的 Gradle 工程结构,unity 相关内容作为 library 使用,可以嵌入到其他 Android 程序中。

他人的实践过程

符号文件

Unity 2019.4 文档中没有 Android 符号文件介绍,Unity 2020.3 中有:

由于 Unity 在打包符号文件时使用了 Store 压缩方法,即不进行压缩,导致生成的 zip 文件达到了 1.4G,只需要简单的解压后使用 Deflate 压缩就可以减小到 388.5M,使用 BandiZip 最大压缩为 zip 也只到 387.0M。

Gradle 直接打包

构建

直接 Build | Make Project 就可以生成需要的 apk

类型切换

如果需要修改 debug 为 release,点击 Build | Select Build Variant,在下拉框中选择。

优化

Gradle 集成 SDK 打包

降级 Gradle 版本

gradle/wrapper/gradle-wrapper.properties 中 distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip 改为 distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip

Gradle 版本由 6.8 升级到 7.2 报以下错误,回滚回 6.8。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
FAILURE: Build completed with 3 failures.

1: Task failed with an exception.
-----------
* What went wrong:
A problem was found with the configuration of task ':unityLibrary:checkDebugManifest' (type 'CheckManifest').
  - In plugin 'com.android.build.gradle.api.AndroidBasePlugin' type 'com.android.build.gradle.internal.tasks.CheckManifest' property 'manifest' has @Input annotation used on property of type 'File'.
    
    Reason: A property of type 'File' annotated with @Input cannot determine how to interpret the file.
    
    Possible solutions:
      1. Annotate with @InputFile for regular files.
      2. Annotate with @InputDirectory for directories.
      3. If you want to track the path, return File.absolutePath as a String and keep @Input.
    
    Please refer to https://docs.gradle.org/7.2/userguide/validation_problems.html#incorrect_use_of_input_annotation for more details about this problem.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
==============================================================================

升级 Gradle 插件版本

build.gradle 中的 Gradle Android 插件版本由 3.4.0 升级到 4.2.0。

升级完 Gradle 插件后,执行 Gradle Sync 会报错

1
2
3
4
5
Could not determine the dependencies of task ':launcher:compileDebugJavaWithJavac'.
> Installed Build Tools revision 32.0.0 is corrupted. Remove and install again using the SDK Manager.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

The main problem is the two files missing in SDK build tool 31 that are:

  1. dx.bat
  2. dx.jar

The solution is that these files are named d8 in the file location so changing their name to dx will solve the error.

AndroidX

1
2
This project uses AndroidX dependencies, but the 'android.useAndroidX' property is not enabled. Set this property to true in the gradle.properties file and retry.
The following AndroidX dependencies are detected: androidx.core:core:1.6.0, androidx.room:room-runtime:2.2.5, androidx.slidingpanelayout:slidingpanelayout:1.0.0, androidx.fragment:fragment:1.1.0, androidx.versionedparcelable:versionedparcelable:1.1.1, androidx.appcompat:appcompat:1.2.0, androidx.customview:customview:1.0.0, androidx.swiperefreshlayout:swiperefreshlayout:1.0.0, androidx.interpolator:interpolator:1.0.0, androidx.sqlite:sqlite:2.1.0, androidx.annotation:annotation-experimental:1.1.0, androidx.loader:loader:1.0.0, androidx.drawerlayout:drawerlayout:1.0.0, androidx.activity:activity:1.0.0, androidx.sqlite:sqlite-framework:2.1.0, androidx.collection:collection:1.1.0, androidx.viewpager:viewpager:1.0.0, androidx.work:work-runtime:2.7.0, androidx.constraintlayout:constraintlayout-core:1.0.3, androidx.localbroadcastmanager:localbroadcastmanager:1.0.0, androidx.constraintlayout:constraintlayout:2.1.3, androidx.arch.core:core-common:2.1.0, androidx.annotation:annotation:1.2.0, androidx.savedstate:savedstate:1.0.0, androidx.lifecycle:lifecycle-service:2.1.0, androidx.appcompat:appcompat-resources:1.2.0, androidx.startup:startup-runtime:1.0.0, androidx.room:room-common:2.2.5, androidx.lifecycle:lifecycle-common:2.1.0, androidx.lifecycle:lifecycle-livedata:2.1.0, androidx.legacy:legacy-support-core-ui:1.0.0, androidx.tracing:tracing:1.0.0, androidx.lifecycle:lifecycle-viewmodel:2.1.0, androidx.browser:browser:1.0.0, androidx.lifecycle:lifecycle-livedata-core:2.1.0, androidx.arch.core:core-runtime:2.1.0, androidx.legacy:legacy-support-core-utils:1.0.0, androidx.documentfile:documentfile:1.0.0, androidx.cursoradapter:cursoradapter:1.0.0, androidx.vectordrawable:vectordrawable-animated:1.1.0, androidx.lifecycle:lifecycle-runtime:2.1.0, androidx.coordinatorlayout:coordinatorlayout:1.0.0, androidx.asynclayoutinflater:asynclayoutinflater:1.0.0, androidx.vectordrawable:vectordrawable:1.1.0, androidx.print:print:1.0.0

gradle.properties 增加

1
android.useAndroidX=true

minCompileSdk

1
2
3
4
5
The minCompileSdk (31) specified in a
dependency's AAR metadata (META-INF/com/android/build/gradle/aar-metadata.properties)
is greater than this module's compileSdkVersion (android-30).
Dependency: androidx.work:work-runtime:2.7.0.
AAR metadata file: C:\Users\xxxxx\.gradle\caches\transforms-3\a3a2026ed6ac68a7f6d8c6498c4dbdfb\transformed\work-runtime-2.7.0\META-INF\com\android\build\gradle\aar-metadata.properties.

compileSdkVersion 30 改为 compileSdkVersion 31

dex 数量过多

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
> Task :launcher:mergeDexDebug FAILED
AGPBI: {"kind":"error","text":"Cannot fit requested classes in a single dex file (# methods: 77400 > 65536)","sources":[{}],"tool":"D8"}
com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives: 
The number of method references in a .dex file cannot exceed 64K.
Learn how to resolve this issue at https://developer.android.com/tools/building/multidex.html
	at com.android.builder.dexing.D8DexArchiveMerger.getExceptionToRethrow(D8DexArchiveMerger.java:128)
	at com.android.builder.dexing.D8DexArchiveMerger.mergeDexArchives(D8DexArchiveMerger.java:115)
	at com.android.build.gradle.internal.transforms.DexMergerTransformCallable.call(DexMergerTransformCallable.java:111)
	at com.android.build.gradle.internal.tasks.DexMergingWorkAction.merge(DexMergingTask.kt:805)
	at com.android.build.gradle.internal.tasks.DexMergingWorkAction.run(DexMergingTask.kt:760)

launcher/build.gradle 中 android/defaultConfig 中增加 multiDexEnabled true

multidex 文件冲突

1
2
3
4
5
6
7
8
Execution failed for task ':launcher:mergeDebugJavaResource'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.MergeJavaResWorkAction
   > 2 files found with path 'androidsupportmultidexversion.txt' from inputs:
      - C:\Users\xxxxx\.gradle\caches\transforms-3\ec3771b3d655e41488dab1c89209626f\transformed\multidex-2.0.0\jars\classes.jar
      - C:\Users\xxxxx\.gradle\caches\transforms-3\0dcf899549e9f9298debd81fc9b2ac72\transformed\multidex-1.0.3\jars\classes.jar
     Adding a packagingOptions block may help, please refer to
     https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html
     for more information

因为项目新引入的类库里面有androidx.multidex:multidex:2.0.0包和项目中 com.android.support:multidex:1.0.3冲突。 使用命令:gradlew :app:dependencies 查看哪些包冲突 其实这个是因为androidx与android support库不能兼容导致的问题。 最后的解决方案就是 https://www.jianshu.com/p/f7a7a8765294 ,将项目构建成androidx库兼容。

将项目改成 androidx 兼容

迁移 jcenter

1
2
3
4
5
Please remove usages of `jcenter()` Maven repository from your build scripts and migrate your build to other Maven repositories.
This repository is deprecated and it will be shut down in the future.
See http://developer.android.com/r/tools/jcenter-end-of-service for more information.
Currently detected usages in: root project 'Demo', project ':launcher', project ':unityLibrary'
Remove JCenter from repositories

jcenter 已经弃用,迁移到 mavenCentral。

Gradle 命令行

1
gradlew.bat --project-dir "C:\Demo\" assemble

通过 Gradle 命令行文档,可以了解在一行命令中执行多个任务只需要用空格将多个任务分隔开。构建多项目工程需要在任务前指定所属的项目:gradle :my-subproject:taskName

注意,这里给出的是 Gradle 6.8 的文档,如果需要其他版本文档,可以前往 Gradle | Releases

找不到 JDK

gradlew.bat assemble

1
2
3
4
5
6
7
> Task :unityLibrary:compileDebugJavaWithJavac FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':unityLibrary:compileDebugJavaWithJavac'.
> Could not find tools.jar. Please check that C:\Program Files\Java\jre1.8.0_321 contains a valid JDK installation.

gradle.properties 中指定 org.gradle.java.home=C\:\\Program Files\\Unity\\Hub\\Editor\\2019.4.32f1\\Editor\\Data\\PlaybackEngines\\AndroidPlayer\\OpenJDK

打包报错

gradlew.bat assemble

1
2
3
4
5
6
7
> Task :unityLibrary:bundleDebugAar FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':unityLibrary:bundleDebugAar'.
> Direct local .aar file dependencies are not supported when building an AAR. The resulting AAR would be broken because the classes and Android resources from any local .aar file dependencies would not be packaged in the resulting AAR. Previous versions of the Android Gradle Plugin produce broken AARs in this case too (despite not throwing this error). The following direct local .aar file dependencies of the :unityLibrary project caused this error: C:\Demo\unityLibrary\libs\xxxxx.aar, C:\Demo\unityLibrary\libs\unity-ads.aar

需要显式地指定打包模块:gradlew.bat :launcher:assembleDebug

路径问题

1
2
3
4
5
6
C:\Demo\gradlew.bat --project-dir "C:\Demo\" :launcher:assembleRelease

FAILURE: Build failed with an exception.

* What went wrong:
java.io.IOException: 文件名、目录名或卷标语法不正确。

Gradle 工程目录路径不能以 /\ 结尾。

SDK 版本

1
2
3
4
Could not determine the dependencies of task ':launcher:compileReleaseJavaWithJavac'.
> Failed to install the following SDK components:
      platforms;android-31 Android SDK Platform 31
  The SDK directory is not writable (C:\Program Files\Unity\Hub\Editor\2019.4.32f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK)

需要复制一份 android-31C:\Program Files\Unity\Hub\Editor\2019.4.32f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-31

targetSdkVersion 32

1
Manifest merger failed : Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.

dx

1
2
3
4
5
* What went wrong:
Could not determine the dependencies of task ':launcher:processReleaseResources'.
> Installed Build Tools revision 32.0.0 is corrupted. Remove and install again using the SDK Manager.

Build-tool 32.0.0 is missing DX at C:\Program Files\Unity\Hub\Editor\2019.4.32f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\32.0.0\dx.bat

The main problem is the two files missing in SDK build tool 31 that are:

  1. dx.bat
  2. dx.jar

The solution is that these files are named d8 in the file location so changing their name to dx will solve the error.

AAB 打包

使用 Gradle 构建 app bundle

如果您更喜欢从命令行生成 app bundle,请在应用的基础模块上运行 bundleVariant Gradle 任务。例如,以下命令会为基础模块的调试版本构建 App Bundle:

1
./gradlew :base:bundleDebug

签名

按照官方文档配置 launcher/build.gradle。将 jks 签名文件直接放在 launcher 目录中,这样可以使用相对路径引用。

Google Play 提交应用

创建应用

创建内部测试版本,上传应用时报错:

您上传的是在调试模式下签名的 APK 或 Android App Bundle。请在发布模式下为 APK 或 Android App Bundle 签名。详细了解签名。

手动签名发布到 Google Play:

导出私钥

需要选择 从 Java 密钥库导出并上传密钥,然后 下载 Play Encrypt Private Key (PEPK) 工具 执行以下命令行,生成压缩包后上传。

搜索后发现 .keystore 和 .jks 是相同的文件,因此可以直接调用命令。

1
2
3
java -jar "C:\Demo\pepk.jar" --keystore="C:\Demo\xxxxxxx.jks" --alias=codemr --output=output.zip --include-cert --encryptionkey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Enter password for store 'xxxxxxx.jks':
Enter password for key 'xxx':

Android App Bundle

重要提示:自 2021 年 8 月起,新应用需要使用 Android App Bundle 才能在 Google Play 中发布。现在,Play Feature DeliveryPlay Asset Delivery 支持大小超过 150 MB 的新应用。

结合使用 app bundle 和 Android Studio 进行部署

如果您已经在使用 Android Studio 开发应用,可以将应用构建为 Android App Bundle,并直接从 IDE 将其部署到连接的设备。由于 IDE 和 Google Play 使用相同的工具提取 APK 并将其安装在设备上,因此这种本地测试策略可帮助您验证以下几点:

  • 您是否可以将应用构建为 app bundle。
  • IDE 是否能够从 app bundle 中提取目标设备配置的 APK。
  • 您分离成功能模块的功能与应用的基本模块是否兼容。
  • 您的应用是否可以在目标设备上按预期方式运行。

必须按照要求导出 AAB 格式包,在本地运行测试,确定可以使用。

本地测试正常后,再上传到 Google Play 进行测试。

上传应用

上传应用提示

您的应用目前的目标 API 级别为 29,但其目标 API 级别必须最低为 30,这样才能确保应用基于最新 API 而构建,让安全性和性能达到最佳状态。请将应用的目标 API 级别至少更改为 30。了解详情

launcher\build.gradle 与 unityLibrary\build.gradle 必须将 targetSdkVersion 29 改为 targetSdkVersion 30,compileSdkVersion 29 也要改为 compileSdkVersion 30,更改后执行 Gradle Sync。

测试

需要先向测试人员发送邀请链接,在接受邀请后再点击邀请页面中的 Google Play 页面链接下载应用。

前往 Google Play Console,选择应用,前往 测试 | 内部测试 | 测试用户数量 | 测试人员参与测试的方式 | 复制链接

测试链接样例:Android 应用测试 - Google Play

隐私权限

您的 APK 或 Android App Bundle 会使用需提供隐私权政策的权限(例如:android.permission.READ_PHONE_STATE)。了解详情

在提交 Google Play 时,需要提供隐私权政策。