unity-android和gradle升级

unity-android和gradle升级, 使用的 unity 版本是 2018.4.36f1 (LTS)


前篇

适配 android 11,12 的需要


sdk 升级到 最新版本后 unity 打包问题

报错无法识别的属性名模块: unrecognized Attribute name MODULE

  • 完整报错

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    CommandInvokationFailure: Gradle build failed. 
    D:\unity2018.4.36f1\Editor\Data\PlaybackEngines\AndroidPlayer/Tools\OpenJDK\Windows\bin\java.exe -classpath "D:\unity2018.4.36f1\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle\lib\gradle-launcher-5.1.1.jar" org.gradle.launcher.GradleMain "-Dorg.gradle.jvmargs=-Xmx4096m" "assembleRelease"

    stderr[
    编译器 (1.8.0-adoptopenjdk) 中出现异常错误。如果在 Bug Database (http://bugs.java.com) 中没有找到该错误, 请通过 Java Bug 报告页 (http://bugreport.java.com) 建立该 Java 编译器 Bug。请在报告中附上您的程序和以下诊断信息。谢谢。
    java.lang.AssertionError: annotationType(): unrecognized Attribute name MODULE (class com.sun.tools.javac.util.UnsharedNameTable$NameImpl)
    at com.sun.tools.javac.util.Assert.error(Assert.java:133)
    at com.sun.tools.javac.code.TypeAnnotations.annotationType(TypeAnnotations.java:231)
    at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.separateAnnotationsKinds(TypeAnnotations.java:294)
    at com.sun.tools.javac.code.TypeAnnotations$TypeAnnotationPositions.visitVarDef(TypeAnnotations.java:1164)
    at com.sun.tools.javac.tree.JCTree$JCVariableDecl.accept(JCTree.java:852)
    at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
  • 原因

    使用的自定义 gradle (mainTemplate.gradle) 中使用的 tool (4.0.0) 版本高于 unity 自带的 gradle 版本 (5.1.1)

    1
    2
    3
    4
    5
    buildscript {
    dependencies {
    classpath 'com.android.tools.build:gradle:4.0.0' # 对应的 gradle 版本是 6.1.1
    **BUILD_SCRIPT_DEPS**}
    }

    gradle tool 版本对应关系 - https://developer.android.com/studio/releases/gradle-plugin?hl=zh-cn#updating-gradle

  • 解决办法: [gradle 升级](#gradle 升级)


android 升级

升级到 32

  1. 下载 android-studio-2020.3.1.26-windows.zip

    新版 as 编辑器默认不显示 gradle 任务, 需要手动打开

    settings -> experimental, 取消勾选 do not build gradle task list during…

  2. 更新 sdk,tools

  3. 修改 build-tools

    1. %ANDROID_SDK%\build-tools\32.0.0 目录下的 d8.bat 改成 dx.bat
    2. %ANDROID_SDK%\build-tools\32.0.0\lib 目录下的 d8.jar 改成 dx.jar

模块升级

  1. 将每个模块的 gradle 构建版本都改成新版本

    1
    2
    3
    4
    5
    6
    7
    android {
    compileSdkVersion 32
    buildToolsVersion '32.0.0'
    defaultConfig {
    targetSdkVersion 32
    }
    }
  2. 如果有引入 androidx.test 单元测试 , 也将版本升级一下

    单元测试最新版本: https://developer.android.com/jetpack/androidx/releases/test?hl=zh-cn

    1
    2
    3
    4
    5
    androidTestImplementation 'androidx.test:core:1.4.0'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test:runner:1.4.0'
    androidTestImplementation 'androidx.test:rules:1.4.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    • 不然可能出现 构建 app 正常, 执行单元测试用例却失败的情况, 报错: processdebugandroidtestmanifest manifest merger failed

    • 也可以在 gui 中升级


踩坑

gradle tool 升级报错已损坏

报错: Installed Build Tools revision 32.0.0 is corrupted. Remove and install again using the SDK Manager. 错误

gradle 配置的是 32.0.0

1
2
3
4
5
6
7
8
android {
compileSdkVersion 32
buildToolsVersion '32.0.0'
defaultConfig {
minSdkVersion 19
targetSdkVersion 32
}
}

改成 31.0.0 也报类似的错误

原因是:

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

  1. dx.bat
  2. dx.jar

解决办法:

  1. %ANDROID_SDK%\build-tools\32.0.0 目录下的 d8.bat 改成 dx.bat
  2. %ANDROID_SDK%\build-tools\32.0.0\lib 目录下的 d8.jar 改成 dx.jar

参考: https://stackoverflow.com/questions/68387270/android-studio-error-installed-build-tools-revision-31-0-0-is-corrupted


gradle 升级

  1. 下载 tool 对应的 gradle 版本, 比如: tool 4.0.1 对应的 gradle 是 6.1.1

  2. 将 unity 安装目录下的 UNITY_ROOT\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle 的 lib 删了, 然后从 gradle-6.1.1-all.zip 文件中解压 lib 丢到该目录下


踩坑

unity 默认版本 低于 tools 版本
  • 自定义配置 tools 版本是 4.0.1, 需要对应的 gradle 版本是 6.1.1, 而 unity 默认版本是 5.1.1

    1
    classpath 'com.android.tools.build:gradle:4.0.1'
  • 报错

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    CommandInvokationFailure: Gradle build failed. 
    D:\unity2018.4.36f1\Editor\Data\PlaybackEngines\AndroidPlayer/Tools\OpenJDK\Windows\bin\java.exe -classpath "D:\unity2018.4.36f1\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle\lib\gradle-launcher-5.1.1.jar" org.gradle.launcher.GradleMain "-Dorg.gradle.jvmargs=-Xmx4096m" "assembleRelease"

    stderr[

    FAILURE: Build failed with an exception.

    * What went wrong:
    A problem occurred evaluating root project 'gradleOut'.
    > Failed to apply plugin [id 'com.android.internal.version-check']
    > Minimum supported Gradle version is 6.1.1. Current version is 5.1.1. If using the gradle wrapper, try editing the distributionUrl in E:\its\tdmj_itc\Temp\gradleOut\gradle\wrapper\gradle-wrapper.properties to gradle-6.1.1-all.zip
  • 解决办法

    将 unity 默认的 gradle 升级到 6.1.1


aaptOptions.noCompress 数组超出限制

aaptOptions.noCompress 数组的容量限制是 255

  • 对应的 tools 版本是 4.0.1, 对应的 gradle 版本是 6.1.1

    1
    classpath 'com.android.tools.build:gradle:4.0.1'
  • 报错

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    CommandInvokationFailure: Gradle build failed. 
    D:/unity_kit/Java/jdk1.8.0_144\bin\java.exe -classpath "D:\unity2018.4.36f1\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle\lib\gradle-launcher-6.1.1.jar" org.gradle.launcher.GradleMain "-Dorg.gradle.jvmargs=-Xmx4096m" "assembleRelease"

    stderr[

    FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ':processReleaseResources'.
    > A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
    > AAPT2 aapt2-4.0.1-6197926-windows Daemon #0: Unexpected error during link, attempting to stop daemon.
    This should not happen under normal circumstances, please file an issue if it does.
  • 原因

    streamingAssets 下项目下文件数量过多引起的, 导致 unity 默认配置中的 **STREAMING_ASSETS** 这个占位符在 gradle 构建时会全部展开为所有文件

    1
    2
    3
    aaptOptions {
    noCompress = ['.unity3d', '.ress', '.resource', '.obb'**STREAMING_ASSETS**]
    }**SIGN**
    • 构建失败后, 可以查看 UNITY_PROJ\Temp\gradleOut\build.gradle

  • 解决办法

    直接去掉 **STREAMING_ASSETS**, 变为

    1
    2
    3
    aaptOptions {
    noCompress = ['.unity3d', '.ress', '.resource', '.obb']
    }**SIGN**
  • 参考


aaptOptions.noCompress 配置技巧

aapt官方文档以及网上查到的一些资料都说aaptOptions.noCompress配置的是不压缩资源文件的后缀名,但是使用后缀名来配置有一定的局限性,比如有些文件后缀名相同,但是如果只想将其中几个文件(而不是全部)配成不压缩,再比如有的文件没有后缀名怎么办?

经过实践发现aaptOptions.noCompress机制并不是检查文件后缀名,而是判断文件路径是否以某个字符串结尾,另外一个需要注意的地方是,在做string.EndWith判断之前会将文件路径全部转换为小写,所以aaptOptions.noCompress中的配置项也必须全为小写


android 12 需要明确指定 android:exported
  • 对应的 tools 版本是 4.2.0, 版本 6.7.1

    1
    classpath 'com.android.tools.build:gradle:4.2.0'
  • 报错

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    CommandInvokationFailure: Gradle build failed. 
    D:/unity_kit/Java/jdk1.8.0_144\bin\java.exe -classpath "D:\unity2018.4.36f1\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle\lib\gradle-launcher-6.7.1.jar" org.gradle.launcher.GradleMain "-Dorg.gradle.jvmargs=-Xmx4096m" "assembleRelease"

    stderr[
    E:\its\tdmj_itc\Temp\gradleOut\src\main\AndroidManifest.xml Error:
    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.

    FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ':processReleaseMainManifest'.
    > Manifest merger failed with multiple errors, see logs
  • 解决办法: 所有包含 intent-filterservice/receiver/activity 都加上 android:exported="true"android:exported="false"


unity android 配置修改

  1. 修改自定义 gradle

    1. tools 版本, 使用的自定义 gradle (mainTemplate.gradle) 中使用的 tool (4.0.0)

      1
      2
      3
      4
      5
      buildscript {
      dependencies {
      classpath 'com.android.tools.build:gradle:4.0.0' # 对应的 gradle 版本是 6.1.1
      **BUILD_SCRIPT_DEPS**}
      }
    2. 增加后置任务.

      升级 unity 内置 gradle (4.0.1版本) 生成的 aab 文件名为 gradleOut-release.aab, 而 unity 回去找的文件是 gradleOut.aab, 所以会

      报错: FileNotFoundException: Temp\gradleOut\build\outputs\bundle\release\gradleOut.aab does not exist

      添加个重命名的任务即可

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      defaultConfig {
      // rename aab for unity
      tasks.whenTaskAdded { task ->
      if (task.name.startsWith("bundle")) {
      def renameTaskName = "rename${task.name.capitalize()}Aab"
      def flavor = task.name.substring("bundle".length()).uncapitalize()
      tasks.create(renameTaskName, Copy) {
      def path = "${buildDir}/outputs/bundle/${flavor}/"
      from(path)
      include "gradleOut-release.aab"
      destinationDir file("${buildDir}/outputs/bundle/${flavor}/")
      rename "gradleOut-release.aab", "gradleOut.aab"
      }
      task.finalizedBy(renameTaskName)
      }
      }
      }
  2. 修改自定义 AndroidManifest

    所有包含 intent-filterservice/receiver/activity 都加上 android:exported="true"android:exported="false"

    1
    2
    3
    4
    5
    6
    7
    <activity
    android:name="${ps_pkg_path}.MainActivity"
    android:label="@string/app_name" android:exported="true">
    <intent-filter>
    ...
    </intent-filter>
    </activity>

Android 12 启动异常

异常行为可能是 闪退 或者 卡住

unity 社区大多都是报闪退的错误, 参考: https://forum.unity.com/threads/android-12-crash-on-startup.1230936/

原因可能是因为升级了 gradle 导致的 (不升级没办法, 要使用 Android 12 相关 api)

  1. 解决办法

    1. 简单粗暴升级 unity, 可以升级到 unity 2020.3.31, 这个版本实测过没问题, 过不有在线项目的慎重

    2. 经测试, 会卡住流程的是在 csharp 的协程里面的 yield return 语句, 如:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      public class GameMgr : MonoBehaviour {
      void Awake() {
      Debug.LogFormat("--- ccc 1");
      StartCoroutine(Init());
      }

      IEnumerator Init() {
      Debug.LogFormat("--- ccc 2");
      yield return StartLuaMain();
      }

      IEnumerator StartLuaMain() {
      Debug.LogFormat("--- ccc 2-1");
      yield return 1; // 这里卡住, 不往下走了
      Debug.LogFormat("--- ccc 3");
      }
      }

      解决办法是需要 Android 的 电话权限, 而且还不能动态申请, 一定要跳转到 app 信息里面手动把 电话权限 打开. 可以在 app 启动 onCreate 的下一帧提示一下去打开 (onCreate 里面不能做一些 ui 操作, 即使在 ui 线程中)

      ```java
      @Override
      protected void onCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);
       ...
       // 跳一帧, 检测 Android 12 电话权限
       new Handler(Looper.getMainLooper()).post(() -> Tools.adr12CallPermCheck());
      

      }