個人gradle多渠道打包記錄

關於android數字簽名的做用,參見:http://blog.sina.com.cn/s/blog_4a4f9fb50101db1f.htmlhtml

生成keystore

參見官網簽名說明文檔:http://developer.android.com/intl/zh-cn/tools/publishing/app-signing.htmlpython

在android studio中

build->generate signed APK->create new.按順序填寫以後生成簽名所需的keystore文件。

android

用命令行

keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000git

按上圖命令分別輸入的是簽名文件名,別名,指明生成的是2048位RSA祕鑰,簽名有效期。github

個人打包記錄

這部份內容參考自:http://www.stormzhang.com/devtools/2015/01/15/android-studio-tutorial6/android-studio

android studio 多渠道打包CMD命令:gradle assembleRelease
須要在命令提示行(管理員)中定位到項目位置,而後輸入gradle初始化gradle環境,而後輸入如上命令。app

個人gradle打包示例一

android studio中build.gradle示例配置以下,將所有渠道名寫入channel.txt文件中,放到app文件夾下面,並將keystore文件放到相同位置。新添加渠道的時候不須要改動build.gradle文件,只需在channel.txt文件中添加新的渠道名就能夠了。打包完成以後會生成未簽名與簽名的兩種apk包:gradle

apply plugin: 'com.android.application'

def releaseTime() {
    return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}

def keyStore = file('sign.keystore')

android {
    compileSdkVersion 22
    buildToolsVersion "23.0.0"

    defaultConfig {
        applicationId "com.zrp.test"
        minSdkVersion 9
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }

    packagingOptions {
        exclude 'META-INF/DEPENDENCIES.txt'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/dependencies.txt'
        exclude 'META-INF/LGPL2.1'
    }

    // Remove warnings
    lintOptions {
        checkReleaseBuilds false
        // Or, if you prefer, you can continue to check for errors in release builds,
        // but continue the build even when errors are found:
        abortOnError false
    }

    // productFlavors
    productFlavors {
        def path = "./channel.txt"
        file(path).eachLine { channel ->
            "$channel" {
                manifestPlaceholders = [UMENG_VALUE: channel]
            }
        }
    }

    signingConfigs {
        app {
            storeFile file('sign.keystore')
            storePassword project.hasProperty('STOREPASS') ? STOREPASS : '你的祕鑰庫口令'
            keyAlias project.hasProperty('KEYALIAS') ? KEYALIAS : '別名'
            keyPassword project.hasProperty('KEYPASS') ? KEYPASS : '祕鑰口令'
        }
    }

    buildTypes {
        release {
            // 不顯示Log
            buildConfigField "boolean", "LOG_DEBUG", "false"

            debuggable false
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            if (keyStore.exists()) {
                println "using test key"
                signingConfig signingConfigs.app
            } else {
                println "---------------using default key---------------"
            }

            android.applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    def outputFile = output.outputFile
                    if (outputFile != null && outputFile.name.endsWith('.apk')) {
                        // 輸出apk名稱爲test_v1.0_2015-01-15_wandoujia.apk
                        def fileName = "test_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk"
                        output.outputFile = new File(outputFile.parent, fileName)
                    }
                }
            }
        }
    }
}
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.android.support:appcompat-v7:22.+'
}

如上gradle文件中,若是未使用簽名文件打包,會出現INSTALL_PARSE_FAILED_NO_CERTIFICATES,或INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION錯誤,致使安裝失敗。因此,必定要使用簽名文件進行打包簽名,否則用會致使應用安裝失敗!ui

個人gradle打包示例二

apply plugin: 'com.android.application'

def releaseTime() {
    return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}

android {
    compileSdkVersion 22
    buildToolsVersion '23.0.0'

    defaultConfig {
        applicationId "com.zrp.test"
        minSdkVersion 9
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"

        // dex突破65535的限制
        multiDexEnabled true
        // 默認是umeng的渠道
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: "umeng"]
    }

    lintOptions {
        abortOnError false
    }

    signingConfigs {
        debug {
            // No debug config
        }

        release {
            storeFile file("../sign.keystore")
            storePassword "祕鑰庫口令"
            keyAlias "別名"
            keyPassword "祕鑰口令"
        }
    }

    buildTypes {
        debug {
            // 顯示Log
            buildConfigField "boolean", "LOG_DEBUG", "true"

            versionNameSuffix "-debug"
            minifyEnabled false
            zipAlignEnabled false
            shrinkResources false
            signingConfig signingConfigs.debug
        }

        release {
            // 不顯示Log
            buildConfigField "boolean", "LOG_DEBUG", "false"

            minifyEnabled true
            zipAlignEnabled true
            // 移除無用的resource文件
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release

            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    def outputFile = output.outputFile
                    if (outputFile != null && outputFile.name.endsWith('.apk')) {
                        // 輸出apk名稱爲test_v1.0_2015-01-15_wandoujia.apk
                        def fileName = "test_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk"
                        output.outputFile = new File(outputFile.parent, fileName)
                    }
                }
            }
        }
    }

    // 友盟多渠道打包
    productFlavors {
        wandoujia {}
//        _360 {}
//        baidu {}
//        xiaomi {}
//        tencent {}
//        taobao {}
    }

    productFlavors.all { flavor ->
        flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.+'
}

若是在打包的時候報Unable to compute hash of /../AndroidStudioProjects/../classes.jar錯誤,說明在打包混淆的時候須要keep一些文件,讓他們不要被混淆。
能夠在proguard-rules.pro文件中添加keep,單獨添加的第三方包須要再次添加。google

打包完成以後生成的簽名包在.\app\build\outputs\apk文件夾下。

美團的打包方案(現階段最快)

這個方案依賴於google的簽名機制,若是google改變android的簽名機制的話這個方案就沒法使用了
Github上有人寫了這個方法的庫:https://github.com/GavinCT/AndroidMultiChannelBuildTool,其博客講解網址爲:http://www.cnblogs.com/ct2011/p/4152323.html

美團的打包原文網址:http://tech.meituan.com/mt-apk-packaging.html
以下爲原文摘抄內容:

META-INF
若是能直接修改apk的渠道號,而不須要再從新簽名能節省很多打包的時間。幸運的是咱們找到了這種方法。直接解壓apk,解壓後的根目錄會有一個META-INF目錄,以下圖所示:

若是在META-INF目錄內添加空文件,能夠不用從新簽名應用。所以,經過爲不一樣渠道的應用添加不一樣的空文件,能夠惟一標識一個渠道。

下面的python代碼用來給apk添加空的渠道文件,渠道名的前綴爲mtchannel_:

import zipfile
zipped = zipfile.ZipFile(your_apk, 'a', zipfile.ZIP_DEFLATED) 
empty_channel_file = "META-INF/mtchannel_{channel}".format(channel=your_channel)
zipped.write(your_empty_file, empty_channel_file)

添加完空渠道文件後的目錄,META-INFO目錄多了一個名爲mtchannel_meituan的空文件:

接下來就能夠在Java代碼中讀取空渠道文件名了:

public static String getChannel(Context context) {
        ApplicationInfo appinfo = context.getApplicationInfo();
        String sourceDir = appinfo.sourceDir;
        String ret = "";
        ZipFile zipfile = null;
        try {
            zipfile = new ZipFile(sourceDir);
            Enumeration<?> entries = zipfile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = ((ZipEntry) entries.nextElement());
                String entryName = entry.getName();
                if (entryName.startsWith("mtchannel")) {
                    ret = entryName;
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (zipfile != null) {
                try {
                    zipfile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        String[] split = ret.split("_");
        if (split != null && split.length >= 2) {
            return ret.substring(split[0].length() + 1);

        } else {
            return "";
        }
    }

這樣,每打一個渠道包只需複製一個apk,在META-INF中添加一個使用渠道號命名的空文件便可。這種打包方式速度很是快,900多個渠道不到一分鐘就能打完。

相關文章
相關標籤/搜索