Android apk打包那些事

1、如何在app级别的gradle.build文件中增加自动签名

在android {}中增加以下配置

 // 增加自动签名的内容
    signingConfigs {
        config {
            keyAlias KEY_ALIAS
            keyPassword KEY_PASSWORD
            storeFile file(STORE_FILE)
            storePassword STORE_PASSWORD
        }
    }
    buildTypes {
        debug {
            // 增加签名设置
            signingConfig signingConfigs.config
        }
        release {
            // 增加签名设置
            signingConfig signingConfigs.config
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

我们预先在gradle.properties文件中藏好了签名的信息:

KEY_ALIAS=test
KEY_PASSWORD=test
STORE_FILE=D\:\\Android\\sinatrue\\test_sign.jks
STORE_PASSWORD=test

然后在signingConfigs{} 中引用了gradle.properties中的签名信息。
之后在buildTypes{} 中增加签名设置。
这样一来,构建出来的apk文件就自动打上了签名。

2、如何根据不同的ABI生成不同的apk

在gradle.build文件中的android {}中增加以下配置

    splits {

        // Configures multiple APKs based on ABI.
        abi {

            // Enables building multiple APKs per ABI.
            enable true

            // By default all ABIs are included, so use reset() and include to specify that we only
            // want APKs for x86 and x86_64.

            // Resets the list of ABIs that Gradle should create APKs for to none.
            reset()

            // Specifies a list of ABIs that Gradle should create APKs for.
            include "x86", "x86_64", "arm64-v8a", "armeabi-v7a"

            // Specifies that we do not want to also generate a universal APK that includes all ABIs.
            universalApk false
        }
    }
  • enable true 是否开启根据ABI生成多个apk;
  • reset() 清空ABI列表;
  • include 设置具体需要的ABI;
  • universalApk false 是否生成一个包含所有ABI的apk文件。

设置好之后,双击击构建脚本,就可以生成不同ABI的apk文件。


image.png

3、如何修改构建出的apk文件名

在app级别的gradle.build文件的android {}中添加下面代码:

    android.applicationVariants.all {
        variant ->
            variant.outputs.all { output ->
                outputFileName = "xxx.apk"
            }
    }

"xxx"就是最终得到的文件名,文件格式是apk。

4、如何实现多渠道打包

假如现在我一套代码需要打包成如图所示的四个apk文件:


image.png

它们分别是应用名“accountbook”、“notebook”和蓝色启动图标、红色启动图标的组合。

4.1、定义风格维度

在app级别的gradle.build文件的android {}中定义风格维度。有多少项就会有多少维度。下面定义了'appName', 'iconColor'两个维度。

flavorDimensions 'appName', 'iconColor'
4.2、定义每个维度对应有多少风格

如本例中appName 有 accountbook 和 notebook 两种风格;iconColor 有 redIcon 和 blueIcon 两种风格。
最终编译出来的产品,就是两个维度风格的组合。
如本例中共有accountbookredIcon、accountbookblueIcon、notebookredIcon、notebookblueIcon四种产品。

productFlavors {
        accountbook {
            dimension 'appName'
            applicationId 'com.stranger.accountbook'
            applicationIdSuffix '.endaccountbook'
            versionCode 66
            versionName 'a1'
            versionNameSuffix 'a2'
        }
        notebook {
            dimension 'appName'
            applicationId 'com.stranger.notebook'
            applicationIdSuffix '.endnotebook'
            versionCode 77
            versionName 'n1'
            versionNameSuffix 'n2'
        }
        redIcon {
            dimension 'iconColor'
            applicationId 'com.stranger.redIcon'
            applicationIdSuffix '.endredIcon'
            versionCode 88
            versionName 'r1'
            versionNameSuffix 'r2'
        }
        blueIcon {
            dimension 'iconColor'
            applicationId 'com.stranger.blueIcon'
            applicationIdSuffix '.endblueIcon'
            versionCode 99
            versionName 'b1'
            versionNameSuffix 'b2'
        }
    }
4.3、得到每个产品的构建脚本

点击sync之后,就可以在androidstudio的右边脚本栏的build中看到每一个产品对应的构建脚本。


image.png
4.4、如何将具体的某一个apk安装到手机、模拟器

此时点击Androidstudio的工具栏的绿色三角,安装的是上面组合中的第一个组合的apk。


image.png

想要安装具体某一个的apk,可以在右边脚本栏的install脚本中找到具体脚本。点击想安装的即可安装到手机、模拟器。


image.png
4.5、怎么做到将差异资源分别打包到各个产品apk

上面的步骤,虽然已经可以打包得到四个apk文件,但是它们的名称和启动图标都是一样的。如何做到将差异资源打包到四个apk中呢?
记得我们做多语言适配、横竖屏布局文件的做法吧?这里是类似的。

  • 4.5.1、我们首先在app目录下创建与main文件夹同级的文件夹,名称分别是我们再productFlavors{}中定义的四种productFlavor。


    image.png
  • 4.5.2、appName维度我们需要不同的应用名称,所以我们在accountbook和notebook中创建和main同路径同文件名的strings.xml


    image.png

    然后分别在它们中定义app_name。注意name和main中的保持一致,都是“app_name”。


    image.png

    image.png

    通过上面的步骤,我们就可以打包出不同应用名的apk了。
  • 4.5.3 在redicon和blueicon中创建启动图标。
    image.png

    不要看到上面这么多mipmap的目录就觉得很复杂,其实就是在redIcon中创建了红色启动图标、在blueIcon中创建了蓝色启动图标而已。(复习一下启动图标相关知识?
    创建好的图标名称依然叫ic_launcher,和main中保持一致。

经过上面的工作,我们现在就可以构建出不同应用名不同启动图标的apk了。


image.png

安装到手机上,就是下面的样子:


image.png
4.6、差异代码怎么办

上面的做法只是实现了差异资源的打包。那如果我每个产品还有差异代码呢,这时候该怎么办?
其实,编译生成的BuildConfig类就包含了我们的productFlavors的信息。我们可以在代码中判断当前属于哪一个productFlavor,从而做出差异化处理。

 if (BuildConfig.FLAVOR_appName == "accountbook" && BuildConfig.FLAVOR_iconColor == "redIcon") {
            //do something different.
        }
        if (BuildConfig.FLAVOR_appName == "accountbook" && BuildConfig.FLAVOR_iconColor == "blueIcon") {
            //do something different.
        }
        if (BuildConfig.FLAVOR_appName == "notebook" && BuildConfig.FLAVOR_iconColor == "redIcon") {
            //do something different.
        }
        if (BuildConfig.FLAVOR_appName == "notebook" && BuildConfig.FLAVOR_iconColor == "blueIcon") {
            //do something different.
        }
4.7、applicationId和versionName的拼接问题

再来看一下,我们的productFlavors是这样定义的:

productFlavors {
        accountbook {
            dimension 'appName'
            applicationId 'com.stranger.accountbook'
            applicationIdSuffix '.endaccountbook'
            versionCode 66
            versionName 'a1'
            versionNameSuffix 'a2'
        }
        notebook {
            dimension 'appName'
            applicationId 'com.stranger.notebook'
            applicationIdSuffix '.endnotebook'
            versionCode 77
            versionName 'n1'
            versionNameSuffix 'n2'
        }
        redIcon {
            dimension 'iconColor'
            applicationId 'com.stranger.redIcon'
            applicationIdSuffix '.endredIcon'
            versionCode 88
            versionName 'r1'
            versionNameSuffix 'r2'
        }
        blueIcon {
            dimension 'iconColor'
            applicationId 'com.stranger.blueIcon'
            applicationIdSuffix '.endblueIcon'
            versionCode 99
            versionName 'b1'
            versionNameSuffix 'b2'
        }
    }

我们为每一个productFlavor都定义了applicationId、versionCode、applicationIdSuffix 、versionName 、versionNameSuffix 。
最后会拼接处什么样的applicationId和versionName 呢?
在Androidstudio中双击其中一个apk文件,自动打开apk分析器,点击里面的AndroidManifest.xml,可以看到拼接结果。


image.png

这个package应该就是拼接后的applicationId吧。不信的话我们再打开output-metadata.json文件。


image.png

从结果可以看出,

  • 只有第一个维度的applicationId、versionCode、versionName会完整拼接,后面维度的都被忽略了。
  • 所有维度applicationIdSuffix 、versionNameSuffix ,都会被拼接。

所以,我们保留第一维度的applicationId、versionCode、versionName,其它维度的applicationId、versionCode、versionName删除;
而第一维度的各种后缀似乎并不需要,所以将它们删除。
总的来说就是第一维度定义前缀,后面维度定义后缀。
假如我们修改成下面的样子:

productFlavors {
        accountbook {
            dimension 'appName'
            applicationId 'com.stranger.accountbook'
            versionCode 66
            versionName 'a1'
        }
        notebook {
            dimension 'appName'
            applicationId 'com.stranger.notebook'
            versionCode 77
            versionName 'n1'
        }
        redIcon {
            dimension 'iconColor'
            applicationIdSuffix '.endredIcon'
            versionNameSuffix 'r2'
        }
        blueIcon {
            dimension 'iconColor'
            applicationIdSuffix '.endblueIcon'
            versionNameSuffix 'b2'
        }
    }

我们生成的apk文件名也修改一下:

    android.applicationVariants.all {
        variant ->
            variant.outputs.all { output ->
                def abiName = output.getFilter(com.android.build.OutputFile.ABI)
                outputFileName = "${productFlavors[0].name}-${productFlavors[1].name}-$buildType.name-${abiName}-${productFlavors[0].versionName}-${productFlavors[1].versionNameSuffix}.apk"
            }
    }

{productFlavors[0].name}第一个风格维度包含的名称,在这里值是accountbook或notebook;
{productFlavors[1].name}第二个风格维度包含的名称,在这里值是redIcon或blueIcon;
{buildType.name}是构建类型,即debug或release;
{abiName}就是我们定义的不同ABI的名称;
{productFlavors[0].versionName}第一个风格维度的versionName,即accountbook或notebook的versionName;
{productFlavors[1].versionNameSuffix}第二个风格维度的versionNameSuffix,即redIcon或blueIcon的versionNameSuffix 。

如此一来,我们就可以构建出不同应用名、不同启动图标所对应不同ABI的apk文件,而且apk文件的名称分别对应的信息所拼成。


image.png

5、最后

最后贴上以上设置的所有内容:

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.2"

    defaultConfig {
        applicationId "com.stranger.testflavor"
        minSdkVersion 16
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    // 增加自动签名的内容
    signingConfigs {
        config {
            keyAlias KEY_ALIAS
            keyPassword KEY_PASSWORD
            storeFile file(STORE_FILE)
            storePassword STORE_PASSWORD
        }
    }
    buildTypes {
        debug {
            // 增加签名设置
            signingConfig signingConfigs.config
        }
        release {
            // 增加签名设置
            signingConfig signingConfigs.config
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    splits {

        // Configures multiple APKs based on ABI.
        abi {

            // Enables building multiple APKs per ABI.
            enable true

            // By default all ABIs are included, so use reset() and include to specify that we only
            // want APKs for x86 and x86_64.

            // Resets the list of ABIs that Gradle should create APKs for to none.
            reset()

            // Specifies a list of ABIs that Gradle should create APKs for.
            include "x86", "x86_64", "arm64-v8a", "armeabi-v7a"

            // Specifies that we do not want to also generate a universal APK that includes all ABIs.
            universalApk false
        }
    }

    android.applicationVariants.all {
        variant ->
            variant.outputs.all { output ->
                def abiName = output.getFilter(com.android.build.OutputFile.ABI)
                outputFileName = "${productFlavors[0].name}-${productFlavors[1].name}-$buildType.name-${abiName}-${productFlavors[0].versionName}-${productFlavors[1].versionNameSuffix}.apk"
            }
    }

    flavorDimensions 'appName', 'iconColor'
    productFlavors {
        accountbook {
            dimension 'appName'
            applicationId 'com.stranger.accountbook'
            versionCode 66
            versionName 'a1'
        }
        notebook {
            dimension 'appName'
            applicationId 'com.stranger.notebook'
            versionCode 77
            versionName 'n1'
        }
        redIcon {
            dimension 'iconColor'
            applicationIdSuffix '.endredIcon'
            versionNameSuffix 'r2'
        }
        blueIcon {
            dimension 'iconColor'
            applicationIdSuffix '.endblueIcon'
            versionNameSuffix 'b2'
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352