[unity]-Unity5.6.3f1使用Gradle打Android包-填坑

背景&問題&目的

  • 背景:老項目一直是用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:
     

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,請在這些版本的平臺上進行全面測試,由於您的應用可能會在啓動時或加載特定類組時出現問題。

參考&感謝

相關文章
相關標籤/搜索