Unity基于Gradle的Android打包
- Unity
- 2024-05-14
- 1044热度
- 0评论
Unity打包apk一般有两种方式,一种是直接在Unity导出apk
,还有一种是先导出gradle
工程,再通过外部工具对gradle
工程进行构建(如Android Studio).
一、什么是Gradle
Gradle是一个项目自动化构建
的开源工具,基于JVM,它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置.DSL语法和Java相接近.
二、Unity导出Gradle工程
-
使用UnityHub安装依赖项: 下载"Android Build Support",并且勾选AndroidSDK和NDK工具,以及OpenJDK.
Unity将AndroidSDK&NDK和OpenJDK分别安装在/[EditorVersion]/Editor/Data/PlaybackEngines/AndroidPlayer/SDK
OpenJDK中NDK
-
每个Unity版本支持的每个依赖项的版本信息都是不同的,每个Unity都需要特定版本的Android NDK和Android JDK,但Android SDK没有确切的版本要求
-
适用于Android的外部工具: External Tools:
-
打包时勾选
Export Project
点击Export后就会得到Gradle文件夹.
三、Unity的Grade的层次结构
3.1 Launcher
启动器部分,其中包含应用程序的名称及其图标.默认是可启动Unity的简单Android应用程序.
- src:启动器模块的代码和资源
- build.gradle:
- 描述如何构建启动器模块,并包含要在构建中包含的依赖项列表
- 依赖于
unityLibrary
模块,当构建启动器模块时,unityLibrary必须包含在最终结果中 - 对呀自定义Gradle的
Custom Launcher Gradle Template
文件
3.2 UnityLibrary
Unity模块,包含Unity运行时和播放器数据,可以集成到其他任何Gradle项目中.
-
libs:
- 用于存放unityLibrary模块的Android Archive(.arr)和java Archive(.jar)插件
- 导出的Unity项目,包含了unity-classes.jar文件(Unity引擎使用的java代码)
-
src:包含unityLibrary模块的源代码和资源.Unity将源代码和资源放在次目录中(AndroidManifest.xml和java代码等).
-
build.gradle:
- 描述了如何构建unityLibrary模块,并包含了构建中要包含的依赖项列表
- unityLibrary模块依赖于Unity项目中的所有插件
- 对呀自定义Gradle的
Custom Main Gradle Template
文件
3.3 build.gradle
- 整体项目的构建逻辑,负责引入所需的全部子项目Gradle并触发每个构建命令
- 文件位于项目的根目录下,用于定义适用于项目中的所有模块的依赖项.
- 会影响所有模块的配置.
- 可包含用于清理build目录的代码
- 用于指定
Android Gradle Plugin
版本 - 对呀自定义Gradle的
Custom Base Gradle Template
文件
3.4 gradle.properties
- 配置了Gradle和JVM的属性
- 配置守护进程并管理构建过程中启动JVM的方式
- Unity默认添加了数据流文件资源目录中的资源类型unityStreamingAssets=.unity3d,告诉Gradle不应该压缩它们。多个文件用","进行分割。
- 对呀自定义Gradle的
Custom Gradle Properties Template
文件
3.5 local.properties
- 用于配置本地环境属性,如Android SDK或者Android NDK
3.6 setting.gradle
- 用于多项目构建或者具有子项目的项目的定义文件
- Unity中通常包含launcher和unityLibrary
- 如果使用Play Asset Delivery,由于所有的资源包都是单独的模块,所以将会列出每个资源模块.
四、自定义Gradle模块
4.1 自定义Gradle模板变量
变量 | 描述 |
---|---|
dependencies | 项目依赖项(即,项目使用的库)的列表。 |
compileSdkVersion | 构建针对的 API 版本(例如 25) |
buildToolsVersion | 使用的 SDK 构建工具(例如 25.0.1) |
minSdkVersion | 最小兼容的Android平台版本 |
targetSdkVersion | 目标 API 版本(例如,25) |
versionCode | 版本码,递增的整数 |
versionName | 版本名 |
consumerProguardFiles | Proguard的配置文件 |
applicationId | Android 应用程序 ID(例如,com.mycompany.myapp) |
4.2 Custom Main Gradle Template
此文件包含有关如何将Unity的 Android 应用程序构建为库的配置信息,对应Gradle结构的"unityLibrary/build.gradle"文件.
//表述这个工程的工程类型,一般包含3种:
//App类型工程:apply plugin: 'com.android.application'
//库类型工程:apply plugin: 'com.android.library'
//Test工程类型:apply plugin: 'com.android.test'
apply plugin: 'com.android.library'
//指构建工程所依赖的所有依赖项
dependencies {
//一般来说有3种依赖类型
//对于本地模块的依赖:implementation project(':mylibrary') [mylibrary此名称必须与在您的 settings.gradle 文件中使用 include: 定义的库名称相符)]
//本地文件依赖项:implementation fileTree(dir: 'libs', include: ['*.jar'])[对项目的libs目录中 JAR 文件的依赖关系,Gradle会读取build.gradle文件的相对路径]
//也可以按如下方式指定各个文件:implementation files('libs/foo.jar', 'libs/bar.jar')
//远程文件依赖项:implementation 'com.example.android:app-magic:12.3'[实际是implementation group: 'com.example.android', name: 'app-magic', version: '12.3'的简写]
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
//针对Android选项的配置块
android {
//编译依赖的SDK版本
compileSdkVersion 29
//构建工具版本
buildToolsVersion '30.0.2'
//编译选项
compileOptions {
//这里配置的是Java 语言的的源码版本
sourceCompatibility JavaVersion.VERSION_1_8
//这里配置的是Java生成的字节码版本
targetCompatibility JavaVersion.VERSION_1_8
}
//默认的配置
defaultConfig {
//最小兼容的Android平台版本,如果低于此版本将会阻止用户安装。
minSdkVersion 19
//指定我们基于哪个版本开发。
targetSdkVersion 29
ndk {
//ABI 是 Application Binary Interface 的缩写。帮助适配不同的CPU架构。
//把除了v7a以外的兼容包都过滤掉
abiFilters 'armeabi-v7a'
}
//版本码,是一个递增的整数
versionCode 1
//版本名
versionName '1.0.2'
//Proguard的配置文件,这里面有两个文件一个是unity自身的配置还有一个是我们自己配置的Proguard配置文件
consumerProguardFiles 'proguard-unity.txt', 'proguard-user.txt'
}
//Lint选项配置
lintOptions {
//当发生错误不终止构建
//更多lint配置:https://developer.android.google.cn/reference/tools/gradle-api/4.1/com/android/build/api/dsl/LintOptions?hl=cn
abortOnError false
}
//aapt全称为Android Asset Packaging Tool,为Android资源打包工具。
//https://developer.android.google.cn/reference/tools/gradle-api/4.1/com/android/build/api/dsl/AaptOptions?hl=en
aaptOptions {
//这里表示这些文件类型不会被压缩存储在APK中。
//unityStreamingAssets.tokenize 这里获取的是gradle.properties文件中unityStreamingAssets的配置。
noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ')
//需要忽略的资源类型
ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~"
}
//Packaging选项
//https://developer.android.google.cn/reference/tools/gradle-api/7.4/com/android/build/api/dsl/PackagingOptions?hl=en
packagingOptions {
//设置armeabi-v7a相关文件不会被剥离优化压缩
doNotStrip '*/armeabi-v7a/*.so'
}
}
4.3 Custom Launcher Gradle Template
此文件包含有关如何构建 Android 应用主模块的配置,对应Gradle结构的"unityLibrary/launcher.gradle"文件。
//此模块为App应用
apply plugin: 'com.android.application'
dependencies {
//依赖于unityLibrary本地模块
implementation project(':unityLibrary')
}
android {
compileSdkVersion 29
buildToolsVersion '30.0.2'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
minSdkVersion 19
targetSdkVersion 29
//设置applicationId,appi要与包名一致,这里Unity会帮我们通过playersetting设置
applicationId 'com.DefaultCompany.com.unity.template.mobile2D'
ndk {
abiFilters 'armeabi-v7a'
}
versionCode 1
versionName '1.0.2'
}
aaptOptions {
noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ')
ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~"
}
lintOptions {
abortOnError false
}
//这里用于配置我们不同的构建类型
buildTypes {
debug {
//是否启用混淆,启用之后增加反编译成本
minifyEnabled false
//设置混淆文件规则
//getDefaultProguardFile('proguard-android.txt')从Android SDK tools/proguard/文件夹获取默认的 ProGuard规则文件,为我们提供的默认混淆规则文件。
//proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro' 可以设置自定义混淆规则文件。
//proguard-rules.pro用于添加自定义位于模块根目录。
proguardFiles getDefaultProguardFile('proguard-android.txt')
//签名配置
signingConfig signingConfigs.debug
//是否激活NDK调试
jniDebuggable true
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt')
signingConfig signingConfigs.debug
}
}
packagingOptions {
doNotStrip '*/armeabi-v7a/*.so'
}
//改进的应用程序打包方式,能大幅度减少应用体积。
//默认情况下,构建器会自动根据CPU架构对屏幕分辨率、语言等维度将app 分拆,如果希望自由控制分拆维度,可以在此控制。
//android 5.0以下不支持bundle
bundle {
//对语言进行拆分
language {
enableSplit = false
}
//对屏幕密度进行拆分
density {
enableSplit = false
}
//对不同CPU架构进行拆分
abi {
enableSplit = true
}
}
}
4.4 Custom Base Gradle Template
//在这里指定所有模块的依赖项和远程仓
//当只有单个模块需要的依赖项应该放在对应的模块级的build.gradle文件中。
allprojects {
//gradle脚本执行所需的依赖项和远程仓
buildscript {
//使用JCenter和Google作为远程仓,本质就是个Maven仓库
repositories {
google()
jcenter()
}
//配置依赖关系
dependencies {
classpath 'com.android.tools.build:gradle:3.6.0'
}
}
//当前项目所需的依赖项和远程仓
//使用JCenter和Google作为远程仓
repositories {
google()
jcenter()
//设置源类型目录位置
//这里设置我们的unityLibrary模块的libs文件夹
flatDir {
dirs "${project(':unityLibrary').projectDir}/libs"
}
}
}
//定义了一个任务,用于删除项目中build文件夹下的内容
task clean(type: Delete) {
delete rootProject.buildDir
}
4.5 Custom Gradle Properties Template
此文件包含 Gradle 构建环境的配置设置,对应Gradle结构的"gradle.properties"文件。
//分配给守护进程,JVM内存的大小,分配较高的值对提高构建性能特别有用。
org.gradle.jvmargs=-Xmx4096M
//多个构建任务进行并行执行
org.gradle.parallel=true
//Android Gradle插件3.4.0或更高版本时可用,R8和Proguard 相比,R8 可以更快地缩减代码,同时改善输出大小。
android.enableR8=false
//不对.unity3d在构建应用时进行压缩
unityStreamingAssets=.unity3d
五、 Gradle构建APK
利用python脚本在Gradle工程中构建apk
- 构建apk脚本:
import os
# gradle路径 user\.gradle\wrapper\dists\gradle版本号
Gradle =r"C:\Users\lwy\.gradle\wrapper\dists\gradle-6.1.1-bin\4i3ntwqiazourd86epxcz427c\gradle-6.1.1\bin"
def StartBuild(gradlePath):
os.chdir(gradlePath)
# jdk路径
os.putenv("JAVA_HOME", r"C:\Users\lwy\.jdks\corretto-1.8.0_412")
# android sdk路径
os.putenv("ANDROID_HOME", r"D:\Android\SDK")
# gradle路径
os.putenv("GRADLE_BIN", r"C:\Users\lwy\.gradle\wrapper\dists\gradle-6.1.1-bin\4i3ntwqiazourd86epxcz427c\gradle-6.1.1\bin")
os.system('{}\gradle clean'.format(Gradle))
os.system('{}\gradle init'.format(Gradle))
os.system('{}\gradle wrapper'.format(Gradle))
os.system('gradlew assembleDebug')
if __name__ == '__main__':
# 游戏工程路径
gradlePath = r"D:\Test\Fina"
StartBuild(gradlePath)
os.system("pause")
- 内网制作android gradle plugin库
-
复制android gradle plugin本地仓库(需在外网下载)C:\Users\lwy.gradle\caches\modules-2\files-2.1
-
利用(ProcessAndroidDependenceFile.py)脚本将文件夹变为可识别仓库
-
修改build.gradle的maven 路径(整个文件)
ProcessAndroidDependenceFile.py:
import os import shutil import sys # 本地缓存路径 srcFolderPath = "C:\Users\lwy\.gradle\caches\modules-2\files-2.1" # 目标路径 dstFolderPath = "D:/Android/repository" class DataInfo: def __init__(self, destPath, srcPath): self.DestPath = destPath self.SrcPath = srcPath def Start(): print("ProcessStart=>" + srcFolderPath) FilesList = [] for root, dirs, files in os.walk(srcFolderPath): for f in files: # print("FileName : " + os.path.join(root, f)) srcPath = os.path.join(root, f) lastIndex = root.rfind('\\') curPath = root[0:lastIndex] filesIndex = curPath.find('files-2.1') filesLen = len('files-2.1') totalLen = filesIndex + filesLen + 1 str_1 = curPath[0:totalLen] str_1 = str_1.replace("Test", "Temp") remainStr = curPath[totalLen:] firstIndex = remainStr.find('\\') str_3 = remainStr[firstIndex + 1:] firstStr = remainStr[0:firstIndex] str_2 = firstStr.replace('.', '\\') destPath = str_1 + str_2 + "\\" + str_3 destPath = destPath.replace("\\", '/') destPath = destPath.replace(srcFolderPath, dstFolderPath) dataInfo = DataInfo(destPath, srcPath) FilesList.append(dataInfo) for item in FilesList: if not os.path.exists(item.DestPath): os.makedirs(item.DestPath) try: shutil.copy(item.SrcPath, item.DestPath) except IOError as e: print("Unable to copy file. %s" % e) except: print("Unexpected error:", sys.exc_info()) print("ProcessFinished...") if __name__ == '__main__': Start()
build.gradle:
// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN allprojects { buildscript { repositories { //google() //jcenter() maven { // 本地路径 url 'D:/Android/repository' metadataSources{ mavenPom() } } } dependencies { classpath 'com.android.tools.build:gradle:4.0.1' } } repositories { google() jcenter() maven { url 'D:/Android/repository' metadataSources{ mavenPom() } } flatDir { dirs "${project(':unityLibrary').projectDir}/libs" } } } task clean(type: Delete) { delete rootProject.buildDir }