2020-5-29
AS4.0正式發佈了. 下載地址
2019-01-15
跟上時代的步伐, AS3.3正式發佈了. 下載地址
文章目錄
Gradle4.0 修改apk輸出目錄和文件名
android {
applicationVariants.all { variant ->
if (variant.buildType.name != "debug") {
variant.packageApplicationProvider.get().outputDirectory = rootProject.file("/apk")
}
variant.outputs.forEach {
it.apkData.outputFileName = "test.apk"
}
}
}
流程分析方法:點擊查看
Gradle3.3 修改apk輸出目錄和文件名
Gradle3.3 以上的方法
/*Gradle3.3 以上的方法*/
applicationVariants.all { variant ->
if (variant.buildType.name != "debug") {
variant.getPackageApplicationProvider().get().outputDirectory = new File(project.rootDir.absolutePath + "/apk")
}
variant.getPackageApplicationProvider().get().outputScope.apkDatas.forEach { apkData ->
apkData.outputFileName = ((project.name != "app") ? project.name : rootProject.name) + "-" +
variant.versionName + "_" +
variant.flavorName + "_" +
variant.buildType.name + "_" +
".apk"
}
}
以下是舊文:
同樣的, Gradle 插件也更新到了3.0, 但是當我們更新到3.0的時候, 很多dsl 無法使用了, 其中就有一個本人比較喜歡的api改變了, 就是修改打包生成的APK文件名.
在未更新之前:
getApplicationVariants().all { variant ->
variant.outputs.each { output ->
def fileName = "AppName-${defaultConfig.versionName}_" +
"${releaseTime()}_" +
"${variant.productFlavors[0].name}_" +
"${variant.buildType.name}_" +
"${if (variant.signingConfig == null) "unsigned" else variant.signingConfig.name}.apk"
//可以通過這個方法修改輸出文件名
output.outputFile = new File(output.outputFile.parent, fileName)
}
}
更新3.0之後, 上面的方法就會報錯.
Gradle3.0 以下方法修改
android {
...
applicationVariants.all { variant ->
//這個修改輸出的APK路徑
if (variant.buildType.name != "debug") {//防止AS無法安裝debug包(apk)
variant.getPackageApplication().outputDirectory = new File(project.rootDir.absolutePath + "/apk")
}
variant.getPackageApplication().outputScope.apkDatas.forEach { apkData ->
//這個修改輸出APK的文件名
apkData.outputFileName = "AppName-" +
variant.versionName + "_" +
apk_time + "_" +
variant.flavorName + "_" +
variant.buildType.name + "_" +
variant.signingConfig.name +
".apk"
}
}
...
}
具體的API更改說明可以查看:
https://developer.android.google.cn/studio/build/gradle-plugin-3-0-0-migration.html#variant_api
據說是爲了加快編譯速度.
同時
更新到Gradle 3.0之後,如果你有 productFlavors
, 那麼必須定義 flavorDimensions
, 其次生成的apk name會根據productFlavors.name
命名.
android {
...
flavorDimensions "type" //這個是必須的
...
productFlavors{
dev{
dimension "type" //並且必須使用這個dimension
}
pre{
dimension "type" //並且必須使用這個dimension
}
apk{
dimension "type" //並且必須使用這個dimension
}
}
}
apk名如下:
dev-debug.apk
dev-release.apk
pre-debug.apk
pre-release.apk
apk-debug.apk
apk-release.apk
如果你聲明瞭多個 productFlavors
, 那麼每個都要使用, 否則會編譯不過.
android {
...
flavorDimensions "type", "type2"
...
productFlavors{
dev{
dimension "type"
}
pre{
dimension "type"
}
apk{
dimension "type2" //type2 也必須使用
}
}
}
這樣生成的apk名字就會是 (type 對應的 productFlavors.name
)+ (type2 對應的 productFlavors.name
) .
上面的就會是:
devApk-debug.apk
devApk-release.apk
preApk-debug.apk
preApk-release.apk
這樣就可以通過productFlavors.name
達到修改APK的文件名.
修改AAR輸出路徑,和AAR文件名.
分析步驟:
- 通過
DSL
語句, 拿到對應的Java
處理類 - 通過
Java
處理類, 找到對應的成員變量
進行修改.
a.LibraryPlugin
//DSL語句
apply plugin: 'com.android.library'
//拿到插件對應的Java類
println project.plugins.findPlugin("com.android.library").class
輸出結果:
//找到Java類LibraryPlugin
class com.android.build.gradle.LibraryPlugin
b.LibraryExtension
android {
compileSdkVersion 28
defaultConfig {
...
}
buildTypes {
...
}
//DSL語句
println it.class
}
輸出結果:
//找到Java類LibraryExtension
class com.android.build.gradle.LibraryExtension_Decorated
c.LibraryVariantImpl
通過查看LibraryExtension
類源碼, 找到方法.
public DefaultDomainObjectSet<LibraryVariant> getLibraryVariants() {
return libraryVariantList;
}
打印此方法所有值:
android {
compileSdkVersion 28
defaultConfig {
...
}
buildTypes {
...
}
//DSL語句
libraryVariants.all { variant ->
println variant.class
}
}
輸出結果:
//找到關鍵類LibraryVariantImpl
class com.android.build.gradle.internal.api.LibraryVariantImpl_Decorated
d.LibraryVariantOutputImpl
通過查看類LibraryVariantImpl
的源碼和繼承關係, 找到方法:
@NonNull
@Override
public DomainObjectCollection<BaseVariantOutput> getOutputs() {
return outputs;
}
枚舉打印輸出:
variant.outputs.all { output ->
println output.class
}
//找到關鍵類LibraryVariantOutputImpl
class com.android.build.gradle.internal.api.LibraryVariantOutputImpl_Decorated
e.apkData
通過查看LibraryVariantOutputImpl
源碼, 找到方法和成員變量:
//關鍵成員
@NonNull protected final ApkData apkData;
//方法
@Override
@NonNull
protected ApkData getApkData() {
return apkData;
}
f.outputFileName
通過查看ApkData
源碼, 找到成員變量:
//找到關鍵點, 見名知意.肯定是用來修改文件名的.
private String outputFileName;
通過查看LibraryVariantOutputImpl
源碼, 還找到方法:
//關鍵方法getOutputFile,
//在老版本的android build gradle中,
//可以直接通過outputFile成員變量, 修改路徑和文件名.
//新版本不行了, 區別就在下面的方法中.
@NonNull
@Override
public File getOutputFile() {
Zip packageTask = getPackageLibrary();
if (packageTask != null) {
return new File(packageTask.getDestinationDir(), apkData.getOutputFileName());
} else {
return super.getOutputFile();
}
}
通過上面方法的getOutputFile
, 能知道.
文件名由apkData.getOutputFileName()
決定;
文件路徑由packageTask.getDestinationDir()
決定.
so
文件路徑修改
output.packageLibrary.destinationDir = new File(project.rootDir.absolutePath + "/aar")
仔細觀察會發現packageLibrary
在LibraryVariantImpl
類中, 就有方法可以獲取:
//AS 3.0版本
@Override
@Nullable
public Zip getPackageLibrary() {
variantData
.getScope()
.getGlobalScope()
.getDslScope()
.getDeprecationReporter()
.reportDeprecatedApi(
"variant.getPackageLibraryProvider()",
"variant.getPackageLibrary()",
TASK_ACCESS_DEPRECATION_URL,
DeprecationReporter.DeprecationTarget.TASK_ACCESS_VIA_VARIANT);
return variantData.getTaskContainer().getBundleLibraryTask().getOrNull();
}
//AS 3.3版本
@Nullable
@Override
public TaskProvider<Zip> getPackageLibraryProvider() {
//noinspection unchecked
return (TaskProvider<Zip>) variantData.getTaskContainer().getBundleLibraryTask();
}
最終修改方式如下:
android {
...
libraryVariants.all { variant ->
if (variant.buildType.name != "debug") {
variant.getPackageLibraryProvider().get().destinationDir = new File(project.rootDir.absolutePath + "/apk")
}
variant.outputs.all { output ->
output.apkData.outputFileName = ((project.name != "app") ? project.name : rootProject.name) + "-" +
defaultConfig.versionName + "_" +
variant.buildType.name +
".aar"
}
}
...
}
如果對分析過程感興趣的童學可以 點擊此處閱讀
羣內有各(pian)種(ni)各(jin)樣(qun)
的大佬,等你來撩.
聯繫作者
請使用QQ掃碼加羣, 小夥伴們在等着你哦!
關注我的公衆號, 每天都能一起玩耍哦!