从0到1打造一款安卓app之2-Android项目多渠道打包与签名文件配置

204 阅读3分钟

安卓工程-多渠道打包与签名文件配置

生成签名文件官方教程地址

多渠道打包官方教程地址

1.修改buildTypes,新增打包类型

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    compileSdk 31

    defaultConfig {
        applicationId "com.example.android_kotlin"
        minSdk 19
        targetSdk 31
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
//        release {
//            minifyEnabled false
//            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
//        }

        getByName("release") {
            minifyEnabled = true
            proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
        }

        getByName("debug") {
            applicationIdSuffix = ".debug"
            debuggable = true
        }

        create("staging") {
            initWith(getByName("debug"))
            manifestPlaceholders["hostName"] = "internal.example.com"
            applicationIdSuffix = ".debugStaging"
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {

    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

修改后,可以打出三程不同类型的包

release:包名为 defaultConfig里配置的applicationId,如 applicationId "com.example.android_kotlin"

debug:包名为release版本的applicationId加上.debug

staging:包名为release版本的applicationId加上.debugStaging或者.releaseStaging

包名不同,所以可以三个版本安装到同一个设备上而不会相互覆盖

不同的打包类型,生成的BuildConfig内容也不同

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "com.example.android_kotlin.debug";
  public static final String BUILD_TYPE = "debug";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
}

2.添加productFlavors

// Specifies one flavor dimension.
flavorDimensions += "version"
productFlavors {
    create("demo") {
        // Assigns this product flavor to the "version" flavor dimension.
        // If you are using only one dimension, this property is optional,
        // and the plugin automatically assigns all the module's flavors to
        // that dimension.
        dimension = "version"
        applicationIdSuffix = ".demo"
        versionNameSuffix = "-demo"
    }
    create("full") {
        dimension = "version"
        applicationIdSuffix = ".full"
        versionNameSuffix = "-full"
    }
}

修改后可以打出来的包有以下几种选择

demoDebug demoRelease demoStaging fullDebug fullRelease fullStaging

包名不同,并且版本号名称也不同

生成的 demo debug BuildConfig文件内容 如下

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "com.example.android_kotlin.demo.debug";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "demo";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0-demo";
}

配置签名

 signingConfigs {
        create("signing-release") {
            storeFile = file("my_debug_key.jks")
            storePassword = "my_debug_key"
            keyAlias = "my_debug_key"
            keyPassword = "my_debug_key"
        }

        create("signing-debug") {
            storeFile = file("my_debug_key.jks")
            storePassword = "my_debug_key"
            keyAlias = "my_debug_key"
            keyPassword = "my_debug_key"
        }
    }

    buildTypes {
//        release {
//            minifyEnabled false
//            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
//        }

        getByName("release") {
            minifyEnabled = true
            proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
            signingConfig = signingConfigs.getByName("signing-release")
        }

        getByName("debug") {
            applicationIdSuffix = ".debug"
            debuggable = true
            signingConfig = signingConfigs.getByName("signing-debug")
        }

        create("staging") {
            initWith(getByName("debug"))
            manifestPlaceholders["hostName"] = "internal.example.com"
            applicationIdSuffix = ".debugStaging"
            signingConfig = signingConfigs.getByName("signing-release")
        }
    }

3.实现自定义修改打包后的apk的名称,并复制到指定文件夹

在项目根目录下新建buildReleaseApiFile.gradle文件


static def getOutputFileName(variant) {

    def productName = variant.productFlavors[0].name
    def versionCode = variant.versionCode
    def versionName = variant.versionName
    def buildType = variant.buildType.name.contains("release") ? "发布版" : "调试版"

    if(variant.buildType.name.contains("debug")) {
        return "${versionCode}_${versionName}.apk"
    }

    def _date = new Date().format("yyyy-MM-dd-HH-mm")
    def nameMap = [            huawei: "华为应用市场",            xiaomi: "小米应用市场",            other : "其他应用市场",    ]

    return "${nameMap[productName]}_${buildType}__版本名称_${versionName}__版本号_${versionCode}__打包时间_${_date}.apk"
}

android.applicationVariants.all { variant ->
    variant.outputs.all {
        //指定apk文件打包生成的名称
        outputFileName = getOutputFileName(variant)
    }
}


def getApkFileDir() {
    return "${rootProject.projectDir.absolutePath}${File.separator}" +
            "app${File.separator}" +
            "build${File.separator}" +
            "outputs${File.separator}" +
            "apk${File.separator}"
}

//打包完成后,把生成的文件复制到指定文件夹
def copyReleaseFile() {
    println("copyReleaseFile run")
    def path = getApkFileDir()
    file(path)?.listFiles()?.each {
        def _file = file("${it.absolutePath}${File.separator}release")
        _file.listFiles()?.each { apkFile ->
            if (apkFile.absolutePath.endsWith(".apk") && apkFile.exists()) {
                println(apkFile.absolutePath)
                def _from = apkFile.absolutePath
                def _into = "${rootProject.projectDir.absolutePath}${File.separator}" +
                        "outputs${File.separator}${new Date().format("yyyy-MM-dd")}"
                if (!file(_into).exists()) {
                    file(_into)?.mkdirs()
                }
                println("_from:$_from")
                println("_into:$_into")
                copy {
                    from apkFile.absolutePath
                    into _into
                }
                println("delete:${apkFile.absolutePath}")
                apkFile.delete()
            }
        }
    }
}

//在某项task完成后执行相应方法。经测试有点小问题
project.tasks.whenTaskAdded { Task theTask ->
    println("whenTaskAdded:${theTask.name}")
//    if (theTask.name == 'assembleRelease') {
//    if (theTask.name.startsWith("assemble")) {
//        theTask.doLast {
//            // 编译完apk之后再执行自定义task
//            copyReleaseFile()
//        }
//    }
}

//在命令行里执行 gradlew buildReleaseApkFile就会自动执行打包和复制命令
tasks.create("buildReleaseApkFile") {
    doFirst {
        copyReleaseFile()
    }
    doLast {
        delete file(getApkFileDir())
    }
}.dependsOn(":app:assembleRelease")

引入到app下的build.gradle里 apply from: "../buildReleaseApkFile.gradle"

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    compileSdk 31

    defaultConfig {
        applicationId "com.example.android_kotlin"
        minSdk 19
        targetSdk 31
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    //指定打包签名信息
    signingConfigs {
        create("signing-release") {
            storeFile = file("my_debug_key.jks")
            storePassword = "my_debug_key"
            keyAlias = "my_debug_key"
            keyPassword = "my_debug_key"
        }

        create("signing-debug") {
            storeFile = file("my_debug_key.jks")
            storePassword = "my_debug_key"
            keyAlias = "my_debug_key"
            keyPassword = "my_debug_key"
        }
    }

    buildTypes {

        getByName("release") {
            minifyEnabled = true
//            debuggable = true
            proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
            signingConfig = signingConfigs.getByName("signing-release")
        }

        getByName("debug") {
            //配置debug安装包的包名后缀
            applicationIdSuffix = ".debug"
            debuggable = true
            signingConfig = signingConfigs.getByName("signing-debug")
        }

        create("staging") {
            initWith(getByName("debug"))
            manifestPlaceholders["hostName"] = "internal.example.com"
            //配置安装包的包名后缀
            applicationIdSuffix = ".debugStaging"
            signingConfig = signingConfigs.getByName("signing-release")
        }
    }

    flavorDimensions += "version"
    productFlavors {

        create("huawei") {
            //自定义BuildConfig字段属性
            buildConfigField("boolean", "buildConfigBoolean", "true")
            buildConfigField("String", "buildConfigString", ""huawei"")
            buildConfigField("int", "buildConfigInt", "1")
        }

        create("xiaomi") {
            buildConfigField("boolean", "buildConfigBoolean", "true")
            buildConfigField("String", "buildConfigString", ""xiaomi"")
            buildConfigField("int", "buildConfigInt", "1")
        }

        create("other") {
            buildConfigField("boolean", "buildConfigBoolean", "true")
            buildConfigField("String", "buildConfigString", ""other"")
            buildConfigField("int", "buildConfigInt", "1")
        }
    }


    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }
}

apply from: "../buildReleaseApkFile.gradle"

dependencies {

    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}