Android Studio使用Gradle实现自动打包,签名,自定义apk文件名,多渠道打包,集成系统签名证书【附效果图附源码】

转载请注明出处,原文地址:http://blog.csdn.net/lucherr/article/details/72436018


        接触Android Stuidio有一阵子了,之前用的时候有很多小问题,不过现在的版本感觉已经很好用了,所以准备彻底从Eclipse转战Android Stuidio,这段时间把以前经常使用的公用库都从Eclipse移植过来了,今天研究了一下在Android Studio下进行打包签名之类的操作,其实主要是研究Gradle了,以前没有用过Gradle,但是早就耳闻Gradle是非常强大的构建系统,经过一天的奋战,最终实现了通过Gradle脚本来实现打包,签名,自定义文件名,多渠道打包,集成系统签名证书的功能,现在整理成一个demo来记录下实现的要点,以供大家参考和以后查阅。ps:这篇博客是这几天的第三篇博客了,算是弥补下这两年多的空缺:)


开始之前先看看作者的主要开发环境:
System:              Ubuntu14.04   
Android Studio:     V2.3.1
Gradle:                  V3.3


(一)先看下效果图

在Terminal里进入.config文件夹,执行./build.sh,或者直接从文件管理器里双击build.sh文件,打包任务开始。

Android Studio使用Gradle实现自动打包,签名,自定义apk文件名,多渠道打包,集成系统签名证书【附效果图附源码】_第1张图片


然后就交给Gradle了,下图是执行完成时的截图,桌面右上角弹出通知,build/outputs/apk下生成签名并且按照指定规则命名后的apk

Android Studio使用Gradle实现自动打包,签名,自定义apk文件名,多渠道打包,集成系统签名证书【附效果图附源码】_第2张图片


(二)build.gradle配置说明

引用自:http://blog.csdn.net/jjwwmlp456/article/details/45057067 在此表示感谢

在android{}模块中可以包含以下直接配置项:
defaultConfig{} 默认配置,是ProductFlavor类型。它共享给其他ProductFlavor使用
sourceSets{ } 源文件目录设置,是AndroidSourceSet类型。
buildTypes{ } BuildType类型
signingConfigs{ } 签名配置,SigningConfig类型
productFlavors{ } 产品风格配置,ProductFlavor类型
testOptions{ } 测试配置,TestOptions类型
aaptOptions{ } aapt配置,AaptOptions类型
lintOptions{ } lint配置,LintOptions类型
dexOptions{ } dex配置,DexOptions类型
compileOptions{ } 编译配置,CompileOptions类型
packagingOptions{ } PackagingOptions类型
jacoco{ } JacocoExtension类型。 用于设定 jacoco版本
splits{ } Splits类型。


(三)脚本构建

下面所说的某些脚本AS会自动生成默认配置,某些可以通过File>Project Structure进行添加,然后可以在此基础上进行修改。

Android Studio使用Gradle实现自动打包,签名,自定义apk文件名,多渠道打包,集成系统签名证书【附效果图附源码】_第3张图片


1.添加签名脚本,指定签名文件相关配置

签名功能可以使用Build>Generate Signed APK来实现,不过作者追求的是全自动化,完全交给Gradle,提高效率哈哈,多说一句,这里的证书也可以是eclipse下生成的.keystore文件

    //签名配置
    signingConfigs {
        config {
            keyAlias 'lucher' //key别名
            keyPassword 'lucher' //key密码,最好不要配置在脚本里
            storeFile file('/home/lucher/main/sign/lucher.jks') //证书路径,证书最好不要放入项目源码
            storePassword 'lucher' //证书密码,最好不要配置在脚本里
        }
    }

2.添加编译类型脚本(AS会自动生成默认的release配置)
    //编译类型
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.config //加入签名配置
        }
        debug {//debug类型
            debuggable true  //启用debug的buildType配置
        }
        custom {//自定义类型
            minifyEnabled false
            renderscriptDebuggable true
        }
    }

3.添加产品风格配置脚本,可用于多渠道打包

友盟统计是使用较多的渠道统计工具,按照友盟官方文档说明,渠道信息需要在AndroidManifest.xml中配置如下值:

这个功能可以通过该脚本来配置,为不同渠道定义不同Value(还可以为不同产品配置不同的应用名称,通过manifestPlaceholders = [  APP_NAME  : "app-name"]来配置,然后需要把AndroidManifest.xml里application标签下的label改为: android:label="${APP_NAME}",该脚本在示例源码里没有加入)

    //产品风格配置,可用于多渠道打包
    productFlavors {
        //百度推广渠道
        baidu {
            applicationId "com.lucher.myapplication"
            versionCode 1
            versionName "1.0"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
 	    manifestPlaceholders = [  APP_NAME  : "app-百度"] //自定义App名称,需要把AndroidManifest.xml里的label改为: android:label="${APP_NAME}"
        }
        //360推广渠道
        qh360 {
            applicationId "com.lucher.myapplication"
            versionCode 1
            versionName "1.0"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "qh360"]
            manifestPlaceholders = [  APP_NAME  : "app-360"] //自定义App名称,需要把AndroidManifest.xml里的label改为: android:label="${APP_NAME}"
        }
        //豌豆荚推广渠道
        wandoujia {
            applicationId "com.lucher.myapplication"
            versionCode 1
            versionName "1.0"
	    manifestPlaceholders = [  APP_NAME  : "app-豌豆荚"] //自定义App名称,需要把AndroidManifest.xml里的label改为: android:label="${APP_NAME}"
        }
    }

4.添加自定义apk名称脚本

有时候需要让apk以指定的规则来命名,可以通过该脚本来实现,本例中命名规则为:

module_flavor-version-time-buildtype.apk

在build.gradle里定义获取当前时间方法(方法定义需要放在android之外)

	//获取当前时间
	def getCurrentTime() {
	    return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
	}

在android的android.applicationVariants.all方法里修改apk文件名

        //apk文件重命名
        android.applicationVariants.all { variant ->
            variant.outputs.each { output ->
                def outputFile = output.outputFile
                if (outputFile != null && outputFile.name.endsWith('.apk')) {
                    def buildType = variant.buildType.name
                    //这里修改apk文件名,格式为 module_flavor-version-time-buildtype.apk
                    def fileName = "app_${variant.productFlavors[0].name}-V${defaultConfig.versionName}-${getCurrentTime()}-${buildType}.apk"
                    output.outputFile = new File(outputFile.parent, fileName)
                }
            }
        }


(四)编译命令

注:在使用编译命令之前请确保gradle已经加入环境变量,如果没加入可以通过./gradlew替代gradle(只能在项目根目录下使用

1编译所有productFlavor及对应所有buildType的apk,相当于按照所有productFlavor和buildType的笛卡尔乘积生成对应的apk,本例中分别有三种productFlavor和三种buildType,生成了9个apk文件
$gradle assemble   //仅仅执行项目打包所必须的任务集
$gradle build           //执行项目打包所必须的任务集,以及执行自动化测试,所以会较慢
如果当前Project包含多个Module,在Project根目录执行gradle assemble会编译所有的Module

2编译指定productFlavor及buildType的apk
$gradle assemble[productFlavor][buildType]
如果缺失某参数,则会把该参数的所有配置都进行编译,即如果运行gradle assembleflavor,则会编译出flavor所有buildType的apk
例如:
$gradle assemble
$gradle assembleflavorRelease 
$gradle assembleflavorDebug

注:gradle支持命令缩写,上面两个命令也可以写成如下格式
$gradle a
$gradle ass
$gradle aR
$gradle assflavorR
$gradle aD
$gradle assflavorD


(五)集成系统签名证书

如果项目需要使用系统权限,则需要在AndroidManifest.xml文件里加入如下属性:

android:sharedUserId="android.uid.system"

加入该属性后apk需要用系统签名才能正常使用。
作者常用的是如下两种方法:
1.android源码环境下签名

需要源码环境,太麻烦
2.对apk进行重新签名

通过下面的命令进行签名

java -jar signapk.jar platform.x509.pem platform.pk8 demo.apk demo_s.apk

这两个方法除了麻烦,还有一个问题:没法直接在开发工具里调试,这是硬伤啊,以前基本都是先打包然后进行重新签名

今天了解到还有另外一个方法可以解决上面的问题,就是把系统签名相关信息导入到已经存在的签名文件里(可以是.jks或者.keystore)

这需要使用一个开源库keytool-importkeypair:https://github.com/getfatday/keytool-importkeypair

使用方法,以lucher.jks为例(需要在linux环境下执行,本例中用到的系统证书是从某系统源码里导出来的,在源码中的路径为:android/build/target/product/security/):

下载keytool-importkeypair,然后把platform.x509.pem platform.pk8 keytool-importkeypair lucher.jks放到同一个文件夹下,执行如下命令即可:
./keytool-importkeypair -k [jks文件名] -p [jks的密码] -pk8 platform.pk8 -cert platform.x509.pem -alias [jks的别名]
本例使用的命令为:
$./keytool-importkeypair -k lucher.jks -p lucher -pk8 platform.pk8 -cert platform.x509.pem -alias lucher
执行成功后会把系统签名信息导入到lucher.jks里,然后签名的方法同上面所说的方法一样,这里不在赘述

最后再强调一点:如果要直接在AS里通过Run运行,需要给Debug模式加上签名信息,或者可以通过左侧的Build Variant选择加入签名配置的模式运行


(六)进阶配置

一,把签名配置从源码移除

如果按照上面所述的方法进行签名配置的话,存在两个问题:

一是密码直接明文显示在gradle里,有严重安全隐患

二是如果多个人同时开发项目,证书的路径各不相同,各自需要修改证书路径.

解决办法:

对于问题一,可以让密码从终端控制行获取,但是这样在打包的时候还需要输入密码,怪麻烦的,跟我追求的完全自动化不符,所以不采用,这种方法可以查询相关资料

对于问题二,我的想法是把签名相关的配置从项目里分离出来,存放到本地配置文件,然后添加一个不需要提交到代码管理工具的配置文件,在该文件里指定分离出来的签名配置文件路径,最后在项目的gradle里加载该配置,这个想法同样可以解决问题一,把密码也写入到这个本地配置文件里

有了这个思路,然后就是研究怎么实现了,经过查阅资料,最后参考下面文章的方法实现了该功能:

https://www.timroes.de/2013/09/22/handling-signing-configs-with-gradle/

值得一提的是:该文章的方法是在gradle.properties里添加的本地签名配置文件路径,不过gradle.properties也加入了版本控制,所以作者使用另一个方法来实现,在项目根目录下新建.config/signgradle.txt文件

在该文件里指定了本地签名配置文件路径,本例为:

/home/lucher/main/sign/sign.gradle


下面说下具体实现步骤:
1.把需要签名的相关配置存放到本地的文件里,然后在项目里加载进来

在项目根目录新建 .config/signgradle.txt文件,内容为签名配置文件地址
/home/lucher/main/sign/sign.gradle

2.sign.gradle加入如下内容

android {
    signingConfigs {
        release {
            storeFile file('/home/lucher/main/sign/lucher.jks') //绝对路径
            storePassword "lucher"
            keyAlias "lucher"
            keyPassword "lucher"
        }
    }
    //编译类型
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        }
    }
}

3.在需要加入签名的gradle文件中加载该签名gradle文件
    //加载签名信息
    File configFile = file('../.config/signgradle.txt')
    if (configFile.exists()) {
        def signGradlePath = configFile.newReader().readLine().trim()
        println 'lucher, path:' + signGradlePath
        if (file(signGradlePath).exists()) {
            apply from: signGradlePath
        }
    }

4.移除原build.gradle文件中buildTypes/realease的定义

5.执行编译打包命令即可


二,编写编译脚本

Linux下编写shell脚本,Windows下编写bat脚本

本例只编写了shell脚本,即工程中.config/build.sh,内容如下:

#快速编译打包apk脚本

echo  " **************************打包开始 ************************** "
sleep 1
#执行打包命令前,需要先定位到项目根目录
cd ..
#执行打包命令
gradle a

echo -e "**************************打包完成************************** "

#桌面右上角弹出通知
notify-send build.sh "打包完成!"
然后就可以直接通过./build.sh或者在文件管理器里双击build.sh文件来打包了,非常方便:)

内容有误还望指出


最后给出文中涉及到的资源下载地址,包括示例源码,签名配置信息,keytool-importkeypair(效果图中的app2是打酱油的,为了缩减文件,资源源码中已经去掉)

http://download.csdn.net/detail/lucherr/9845187


你可能感兴趣的:(学习笔记-android,studio)