文章

Unity 打包 Apk 研究

Unity 打包 Apk 研究

Part 1:Unity 构建 Android的项目结构

Unity 构建 Android 主要由两个module 组成

  • launcher
  • unityLibrary

游戏代码(C# 脚本)和大部分插件都位于 unityLibrary 模块中,而 mainTemplate.gradle 正是用来配置这个模块的。launcherTemplate.gradle 只配置那个启动游戏的“空壳”应用。

Unity 的工作流程

1,生成临时 Android Gradle 项目
2,填充模板
3,变量替换 VARIABLE_NAME,替换为 Player Settings 中配置的值
4,调用 Gradle 执行编译,生成 APK 或 AAB

占位符变量 (在 .gradle 文件中)对应的 Unity Player Setting示例值
**APPLICATION_ID**Package Name (包名)com.mycompany.mygame
**BUNDLE_VERSION_CODE**Bundle Version Code(内部版本号)1210
**VERSION_NAME**Version (外部版本名)1.02.1.3
**MIN_SDK_VERSION**Minimum API Level (最低 API 级别)22
**TARGET_SDK_VERSION**Target API Level (目标 API 级别)33
**UNITY_PLAYER_NAME**Product Name (产品名称)My Awesome Game
**UNITY_COMPANY_NAME**Company Name (公司名称)My Company
**SPLITS_ENABLED**Split APKs by architecture(ARMv7, ARM64)true 或 false
**IL2CPP_DEVELOPMENT_BUILD**Development Build (开发构建)true 或 false

Part 2: 如何生成和使用自定义 Gradle 模板?

  1. 打开 Player SettingsEdit > Project Settings > Player
  2. 切换到 Android 标签页 🤖。
  3. 展开 Publishing Settings:
  4. 在这里,你会看到几个用于自定义构建的选项。勾选它们:
    1. Custom Main Manifest -> 生成 AndroidManifest.xml
    2. Custom Main Gradle Template -> 生成 mainTemplate.gradle
    3. Custom Launcher Gradle Template -> 生成 launcherTemplate.gradle
    4. Custom Base Gradle Template -> 生成 baseProjectTemplate.gradle
    5. Custom Gradle Settings Template - > 生成 settingsTemplate.gradle
    6. 其他的根据项目需要生成
  • 核心就是将导出 Android Project中的资源打包,copy 到 Unity Assets/Plugins/Android中

Part 3: 标准的自定义 build.gradle 配置是什么样的?

1. mainTemplate.gradle - 核心模块配置

这个文件对应的是 unityLibrary 模块的 build.gradle。绝大多数自定义需求,比如添加依赖库,都在这里完成。 一个标准的带有注释的 mainTemplate.gradle 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// mainTemplate.gradle (for unityLibrary module)

// 声明这是一个 Android 库模块
apply plugin: 'com.android.library'

// (可选) 如果你使用 Kotlin,需要添加这个插件
// apply plugin: 'kotlin-android'

dependencies {
    // Unity 默认的依赖
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // ============== 自定义区域开始 ==============
    // 在这里添加你的原生 Android 库依赖
    // 例如,添加 Google Play Core 库
    // implementation 'com.google.android.play:core:1.10.3'

    // 例如,添加一个第三方广告 SDK
    // implementation 'com.some.ad.sdk:sdk-core:3.2.1'
    // ============== 自定义区域结束 ==============

    **DEPS** // <-- 这个占位符很重要,Unity 会用它来注入其他内部依赖,必须保留!
}

android {
    // 编译用的 SDK 版本
    compileSdkVersion **SDK_VERSION**
    // 构建工具版本
    buildToolsVersion '**BUILD_TOOLS_VERSION**'

    // 默认配置块,这里的变量会被 Unity 替换
    defaultConfig {
        // 使用 Unity 的包名占位符
        // 注意:库模块通常不设置 applicationId,但如果设置了,它应该与主模块一致
        // applicationId '**APPLICATION_ID**'

        // 使用 Unity 的最低/目标 SDK 版本占位符
        minSdkVersion **MIN_SDK_VERSION**
        targetSdkVersion **TARGET_SDK_VERSION**
        
        // 使用 Unity 的版本号占位符
        versionCode **BUNDLE_VERSION_CODE**
        versionName '**VERSION_NAME**'

        consumerProguardFiles 'proguard-unity.txt', 'proguard-user.txt'
    }

    // 设置 Java 源码的兼容性
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    // Unity 自动生成的签名配置,让它保持原样
    signingConfigs {
        release {
            storeFile file(project.property('unity.keystore.path'))
            storePassword project.property('unity.keystore.password')
            keyAlias project.property('unity.keyalias.name')
            keyPassword project.property('unity.keyalias.password')
        }
    }

    // 构建类型配置
    buildTypes {
        debug {
            minifyEnabled false
            debuggable true
        }
        release {
            // 使用 Unity 的签名配置
            signingConfig signingConfigs.release
            minifyEnabled true // 开启混淆和压缩
            // ProGuard 规则文件
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-unity.txt', 'proguard-user.txt'
        }
    }
    
    // aapt 选项,保持默认
    aaptOptions {
        noCompress = ['.unity3d', '.ress', '.resource', '.obb'**NO_COMPRESS_EXTENSIONS**]
        ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*~:!*.bak:!*.orig:!*.*.meta:"
    }
}

Q&A

1.Unity 导出 Android 继承GameActivity的启动类?

  • 第一次导出Unity 的 AndroidProject 项目默认的启动类和现在导出的 Unity 默认启动类有差异了? Unity 版本2023.2.20f1c1 系统 Mac
  • 当前导出的项目
    • Unity 默认使用的启动类是 com.unity3d.player.UnityPlayerGameActivity
    • UnityPlayerGameActivity 继承的是GameActivity,在类库’androidx.games:games-activity:3.0.0’中
  • 首次导出的
    • com.unity3d.player.UnityPlayerActivity
    • UnityPlayerActivity 默认继承的是 Activity,module项目 unitylibrary没有引入其他类库

参考官方文档了解更多细节。

  • Unity → File → Build Settings → Player Settings → Player → Other Settings
  • 找到 Application Entry Point
    • Activity 采用 Activity 方式,也就是com.unity3d.player.UnityPlayerActivity,默认继承 Activity
    • GameActivity,默认导出三方库androidx.games:games-activity:3.0.0,默认继承 GameActivity

2.Unity 打包 apk 时,合并 AndroidManifest.xml时报错?

  • 无法自动解析并合并 AAR 与远程依赖库中的 AndroidManifest.xml,至少目前是没有解析合并入 LauncherAndroidManifest.xml 中?
  • 是 LauncherManifest.xml 中 Application 标签中定义的 tools:node=”replace” 导致放弃了其他非主 module 中的 AndroidManifest.xml 合并
  • 解决方案是不能使用 tools:node=”replace”属性,将默认添加的那个 MAIN 入口类设置属性 tools:node=”remove” 即可
    1
    2
    3
    
      <activity
          android:name="com.unity3d.player.UnityPlayerActivity"
          tools:node="remove" />
    
本文由作者按照 CC BY 4.0 进行授权