[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 對象中添加

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 文件。

  • 補充和修復2019/10/25
    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. (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. (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”的文件,無法成功打包

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配置,打包時,暫時找不到解決方法

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'.

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()
}
```

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'.

com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: android/support/multidex/BuildConfig.class
```

6.第(5)步中刪除放入的android.support.multidex.jar
* 打包報錯:
``` shell

What went wrong:
Execution failed for task ':transformResourcesWithMergeJavaResForRelease'.

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
```

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

參考&感謝


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM