背景&问题&目的
- 背景:老项目一直是用Unity5.6.3f1默认Internal打包方式,结合Jenkins构建的。新项目使用2018.4.2f1构建
- 问题:项目接入小米最新版本SDK时,接入的Jar包不少,遇到了方法数超过 64K的问题,使用Unity的Innternal打包方式没法成功打包;若是选择用Export Gradle Project方式,自动化流程改动较大;只能选择使用Unity Gradle方式打包。
- 记录Unity5.6.3f1使用Unity Gradle打包的流程和解决遇到的问题。
步骤
- 新建Unity空工程(测试时建议使用小工程测试),导入项目中使用到的Plugins/Android目录内容,同时导入小米SDK资源,Build Settings中Build System选择Gradle。
- 从Unity5.6.3f1安装目录“Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\GradleTemplates”,获取到mainTemplate.gradle 和 libTemplate.gradle两个文件,复制到上面新建的工程里
- 修改mainTemplate.gradle,在 buildscript/repositories 和 allprojects/repositories 对象内添加
repositories { maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'} maven{ url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'} //注意保留原来的内容 ... }
- 修改mainTemplate.gradle和libTemplate.gradle,修改 buildscript/dependencies 对象中的 classpath 'com.android.tools.build:gradle:2.1.0' 的gradle版本号为2.3.3
dependencies { classpath 'com.android.tools.build:gradle:2.3.3' }
- 修改mainTemplate.gradle, 在 dependencies 对象中添加
dependencies { //注意保留原来的内容 ... compile 'com.android.support:multidex:1.0.3' }
在 android/defaultConfig 对象中添加html
android { defaultConfig { //注意保留原来的内容 ... multiDexEnabled true } }
- 更新Unity 5.6.3f1中的Gradle版本
* Unity 5.6.3f1中集成的Gradle版本是 2.1.0 * Unity 2018.4.2f1集成的Gradle版本是 4.6.0 分别本地安装的找到Unity 5.6.3f1和Unity 2018.x的安装目录“Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle”中的lib文件,先备份5.6.3f1的lib文件,再将2018.x的lib复制过来。
- Jenkins工程配置:在Unity player settings中配置安卓签名
//例如 PlayerSettings.Android.keystoreName = KeystorePath; PlayerSettings.Android.keyaliasName = "alias"; PlayerSettings.Android.keyaliasPass = "123456"; PlayerSettings.Android.keystorePass = "123456";
- Jenkins工程配置:在Unity player settings中配置BundleId
//例如 PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, BundleName);
- Jenkins工程配置:在Unity build settings中选择Gradle
//例如 EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Gradle;
- 整合小米SDK提供的Jar包
使用ANT整合打包小米提供的Jar (命名格式:support-xxx-27.1.1.jar) 和工程内现有的android-support-v4.jar进行对比 删除从小米导出的Jar里的对比相同的类 (尽可能保证工程内现有使用android-support-v4.jar的功能稳定,只增长一个小米的不稳定因素) 尝试打包
问题&解决
- 测试时若是遇到打包失败时,下一次尝试打包时,记得删除Unity 工程目录下的Temp目录
- 没有开代理的状况下,遇到没法获取gradle的问题
摘自下文参考连接中的相似日志 * What went wrong: A problem occurred configuring root project 'gradleOut'. > Could not resolve all files for configuration ':classpath'. > Could not resolve com.android.tools.build:gradle:2.1.0. Required by: project : > Could not resolve com.android.tools.build:gradle:2.1.0. > Could not get resource 'https://jcenter.bintray.com/com/android/tools/build/gradle/2.1.0/gradle-2.1.0.pom'. > Could not HEAD 'https://jcenter.bintray.com/com/android/tools/build/gradle/2.1.0/gradle-2.1.0.pom'. > Connect to XXX [/XXX] failed: Connection refused: connect
* 解决方法: 配置阿里云国内镜像
- 在默认使用Unity5.6.3f的gradle版本执行打包时
* What went wrong: A problem occurred evaluating root project 'gradleOut'. > Failed to apply plugin [id 'com.android.application'] > Gradle version 2.10 is required. Current version is 4.0.1. If using the gradle wrapper, try editing the distributionUrl in E:\Unity3D\TTAiLaoyu\Temp\gradleOut\gradle\wrapper\gradle-wrapper.properties to gradle-2.10-all.zip
* 解决方法: 拷贝2018版本的Unity的gradle到5.6.3f1下,并修改.gradle文件的gradle版本号2.3.3 若是使用AndroidStudio,方法同样,也是更新最新的gradle解决这个问题的版本 如:使用最新的AndroidStudio3.0
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.0.1' } }
注:若是使用的是AndroidStudio2.3或更低版本,请使用
classpath 'com.android.tools.build:gradle:2.3.3'
- 遇到jar包类重复:
duplicate entry: com/bumptech/glide/gifdecoder/GifDecoder$BitmapProvider.class 相似日志
解决方法:尝试删除新导入jar包中的同包名+类名的类文件
- 针对多 dex 文件配置您的应用:
当 minSdkVersion 低于20及如下时,注意配置三点 android { defaultConfig { ... minSdkVersion 15 targetSdkVersion 28 // 1 multiDexEnabled true } ... } dependencies { // 2 compile 'com.android.support:multidex:1.0.3' } // 3 不替换Application <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp"> <application android:name="android.support.multidex.MultiDexApplication" > ... </application> </manifest> 替换Application public class MyApplication extends MultiDexApplication { ... } 替换Application 但没法修改基类 public class MyApplication extends SomeOtherApplication { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } }
- 完成上述MultiDex配置,可以正常Build,可是在Android5.0如下设备上安装闪退,提示 Class Not Found,详细请参考
为多 dex 文件应用编译每一个 DEX 文件时,编译工具会执行复杂的决策制定来肯定主要 DEX 文件中须要的类,以便您的应用可以成功启动。若是主要 DEX 文件中未提供启动期间须要的任何类,则您的应用会崩溃并出现 java.lang.NoClassDefFoundError 错误。 对于直接从您的应用代码访问的代码,不该发生这种状况,由于编译工具能够识别这些代码路径。可是,当代码路径的可见性较低时(例如,当您使用的库具备复杂的依赖项时),可能会发生这种状况。例如,若是代码使用自检机制或从原生代码调用 Java 方法,那么可能不会将这些类识别为主要 DEX 文件中的必需类。 所以,若是您收到 java.lang.NoClassDefFoundError,则必须使用版本类型中的 multiDexKeepFile 或 multiDexKeepProguard 属性声明这些其余类,以手动将这些类指定为主要 DEX 文件中的必需类。若是某个类在 multiDexKeepFile 或 multiDexKeepProguard 文件中匹配到,则会将该类添加到主要 DEX 文件。
- <font color=blue>补充和修复2019/10/25</font> 1.不添加MultiDex.install(base);接口
- 打包后在Android 4.4上Crash:
提示 java.lang.NoClassDefFoundError : org.xiaomi.gamecenter.milink.msg 使用 multiDexKeepProguard 方法:在Unity5.6.3f1工程的 Plugins/Android目录下添加了一个**“proguard-user.txt”**文件,并在mainTemplate.gradle文件 中 指定 multiDexKeepProguard file('proguard-user.txt')
- 从新打包测试,继续Crash:
- 打包后在Android 4.4上Crash:
10-23 21:46:03.922: E/IdentifierManager(5549): reflect exception!com.android.id.impl.IdProviderImpl 10-23 21:46:03.972: E/IdentifierManager(5549): reflect exception! 10-23 21:46:03.972: E/IdentifierManager(5549): java.lang.ClassNotFoundException: com.android.id.impl.IdProviderImpl 10-23 21:46:03.972: E/IdentifierManager(5549): at java.lang.Class.classForName(Native Method) 10-23 21:46:03.972: E/IdentifierManager(5549): at java.lang.Class.forName(Class.java:251) 10-23 21:46:03.972: E/IdentifierManager(5549): at java.lang.Class.forName(Class.java:216) 10-23 21:46:03.972: E/IdentifierManager(5549): at com.xiaomi.gamecenter.gamesdk.datasdk.b.f.<clinit>(Unknown Source) 10-23 21:46:03.972: E/IdentifierManager(5549): at com.xiaomi.gamecenter.gamesdk.datasdk.b.b.a(Unknown Source) 10-23 21:46:03.972: E/IdentifierManager(5549): at com.xiaomi.gamecenter.gamesdk.datasdk.bean.HBean.init(Unknown Source) 10-23 21:46:03.972: E/IdentifierManager(5549): at com.xiaomi.gamecenter.gamesdk.datasdk.datasdk.DataSDK.initHeader(Unknown Source) 10-23 21:46:03.972: E/IdentifierManager(5549): at com.xiaomi.gamecenter.sdk.report.ReportData.a(Unknown Source) 10-23 21:46:03.972: E/IdentifierManager(5549): at com.xiaomi.gamecenter.sdk.MiCommplatform.<init>(Unknown Source) 10-23 21:46:03.972: E/IdentifierManager(5549): at com.xiaomi.gamecenter.sdk.MiCommplatform.Init(Unknown Source) 10-23 21:46:03.972: E/IdentifierManager(5549): at com.xiaomi.gamecenter.sdk.MiCommplatform.Init(Unknown Source) ``` * 尝试使用 multiDexKeepFile 或 multiDexKeepProguard 添加 android.id.impl.IdProviderImpl,如:-keep class com.android.id.impl.IdProviderImpl 同时因为Unity 5.6.3f1只支持Gradle打包自定义一个名称为“proguard-user.txt”的文件,没法成功打包java
2.添加MultiDex.install(base);接口 * 因为在游戏自定义MyApplication中加入了 ``` java import androidx.multidex.MultiDex; @Override
protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(base); } * 使用生成的Jar,打包后在Android 4.4上Crash:
shell java.lang.NoClassDefFoundError: Failed resolution of: Landroix/multidex/MultiDex ``` * 使用Unity5.6.3f1 使用Gradle2.3.3配置,打包时,暂时找不到解决方法android
3.尝试在Unity5.6.3f1中使用Gradle 3.x打包 * 打包报错: ``` shell
stderr[ FAILURE: Build failed with an exception. What went wrong: A problem occurred configuring root project 'gradleOut'.git
Could not resolve all artifacts for configuration ':classpath'. Could not find com.android.tools.build:gradle:3.2.0. Searched in the following locations: http://maven.aliyun.com/nexus/content/groups/public/com/android/tools/build/gradle/3.2.0/gradle-3.2.0.pom http://maven.aliyun.com/nexus/content/groups/public/com/android/tools/build/gradle/3.2.0/gradle-3.2.0.jar http://maven.aliyun.com/nexus/content/repositories/jcenter/com/android/tools/build/gradle/3.2.0/gradle-3.2.0.pom http://maven.aliyun.com/nexus/content/repositories/jcenter/com/android/tools/build/gradle/3.2.0/gradle-3.2.0.jar https://jcenter.bintray.com/com/android/tools/build/gradle/3.2.0/gradle-3.2.0.pom https://jcenter.bintray.com/com/android/tools/build/gradle/3.2.0/gradle-3.2.0.jar Required by: project :
* 解决方法:
json repositories { google() } ```github
4.继续在Unity5.6.3f1上使用Gradle 3.x打包 * 打包报错: ``` shell
FileNotFoundException: Temp\gradleOut\build\outputs\apk\gradleOut-release.apk does not exist System.IO.File.Move (System.String sourceFileName, System.String destFileName) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.IO/File.cs:318) UnityEditor.Android.PostProcessor.Tasks.BuildGradleProject.Execute (UnityEditor.Android.PostProcessor.PostProcessorContext context) UnityEditor.Android.PostProcessor.PostProcessRunner.RunAllTasks (UnityEditor.Android.PostProcessor.PostProcessorContext context) UnityEditor.Android.PostProcessAndroidPlayer.PostProcess (BuildTarget target, System.String stagingAreaData, System.String stagingArea, System.String playerPackage, System.String installPath, System.String companyName, System.String productName, BuildOptions options, UnityEditor.RuntimeClassRegistry usedClassRegistry) UnityEditor.Android.AndroidBuildPostprocessor.PostProcess (BuildPostProcessArgs args) UnityEditor.PostprocessBuildPlayer.Postprocess (BuildTargetGroup targetGroup, BuildTarget target, System.String installPath, System.String companyName, System.String productName, Int32 width, Int32 height, System.String downloadWebplayerUrl, System.String manualDownloadWebplayerUrl, BuildOptions options, UnityEditor.RuntimeClassRegistry usedClassRegistry, UnityEditor.BuildReporting.BuildReport report) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/PostprocessBuildPlayer.cs:186) UnityEditor.HostView:OnGUI()
* 定位问题:
text 在Unity 5.6.3f1工程目录下有Temp这个打包缓存目录,原先用Gradle 2.x打包时,生成的apk在Temp\gradleOut\build\outputs\apk\release\gradleOut-release.apk下 使用Gradle 3.x后 Temp\gradleOut\build\outputs\apk\gradleOut-release.apk 5.尝试放入android.support.multidex.jar到Android Jar包工程(使用Android Studio2.x),打Jar,将生成的MyJar和android.support.multidex.jar放到Unity工程打包,保留上述mainTemplate.gradle配置 * Jar工程引用:
java import android.support.multidex.*; * 打包报错:
shell * What went wrong: Execution failed for task ':transformClassesWithJarMergingForRelease'.shell
com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: android/support/multidex/BuildConfig.class ```json
6.第(5)步中删除放入的android.support.multidex.jar * 打包报错: ``` shell
What went wrong: Execution failed for task ':transformResourcesWithMergeJavaResForRelease'.c#
com.android.build.api.transform.TransformException: com.android.builder.packaging.DuplicateFileException: Duplicate files copied in APK androidsupportmultidexversion.txt File1: E:\Projects\Test_Unity5.6.3_Xiaomi_MultiDex_GradleBuild\Temp\gradleOut\libs\AndroidPlugin_Xiaomi.jar File2: C:\Users\��ľ����.android\build-cache\9f10bcca4b107d54e1cfef721951c6936e095fb8\output\jars\classes.jar ```api
7.第(6)步中,修改mainTemplate.gradle配置 * 成功打包,配置以下 ``` shell
dependencies { //注释!!! //compile 'com.android.support:multidex:1.0.3' } ```缓存
总结&后续
- Unity打包时,开启“multiDexEnabled true”后,会在User/用户名/.android目录下生成一个android support multidex 的jar
例如:.android\build-cache\9f10bcca4b107d54e1cfef721951c6936e095fb8\output\jars\classes.jar 同时这个classes.jar第一次打包时就会生成,因此不须要在Unity/Plugins/Android/下再放一个android.support.multidex.jar了。
- Android Studio 2.x打Jar时,调用MultiDex接口,若是在gradle中配置了(AndroidStuidio 2.x)compile 'com.android.support:multidex:1.0.3' 或者 (AndroidStudio 3.x)implementation 'com.android.support:multidex:1.0.3',仍是没法引用到MultiDex类,则手动下载并引用一个稳定版本的support multidex jar。
- Unity 5.6.3f1 和 Android Studio 2.0 支持的Gradle版本为 2.x版本,由于build的apk的Temp目录结构和Unity2018有点不一样
- Unity 5.6.3f1 用到的Jar用Android Studio 2.x导出,Unity2018的用Android Studio 3.x导出
- Unity打包的报错信息,仔细查找定位问题核心,根据不一样问题,找对应的解决方法;对于Gradle的语法和一些经常使用问题须要记录和整理。
- 多 dex 文件支持库具备一些已知的局限性,将其归入您的应用编译配置时,您应注意这些局限性并进行针对性的测试:
启动期间在设备的数据分区上安装 DEX 文件的过程至关复杂,若是辅助 DEX 文件较大,可能会致使应用无响应 (ANR) 错误。在这种状况下,您应经过 ProGuard 应用代码压缩,以尽可能减少 DEX 文件的大小,并移除未使用的那部分代码。 当运行的版本低于 Android 5.0(API 级别 21)时,使用多 dex 文件不足以避开 linearalloc 限制(问题 78035)。此上限在 Android 4.0(API 级别 14)中有所提升,但这并未彻底解决该问题。在低于 Android 4.0 的版本中,您可能会在达到 DEX 索引限制以前达到 linearalloc 限制。所以,若是您的目标 API 级别低于 14,请在这些版本的平台上进行全面测试,由于您的应用可能会在启动时或加载特定类组时出现问题。
参考&感谢
- CSDN-【Unity / Gradle】 Unity 5.6.x Gradle build APK 报错 Connection refused 解决方法
- 知乎 -你们都是怎样处理Gradle中的这个文件下载慢的问题的?回答:【使用阿里云的国内镜像仓库地址,就能够快速的下载须要的文件 修改项目根目录下的文件 build.gradle :】
- Unity Gradle 打包Gradle不匹配
- 如何解决AndroidStudio中 Failed to apply plugin [id 'com.android.application']的问题?
- 为方法数超过 64K 的应用启用多 dex 文件 -【在开发编译中优化多 dex 文件】
- Jar包下载-Android Multi Dex Library » 1.0.3
- Jar包下载-github-dandar3/android-support-multidex
- Jar包下载-GoogleGit-版本较老