美文网首页Android技术知识Android精选
技术:Android打包签名总结

技术:Android打包签名总结

作者: 玉圣 | 来源:发表于2017-07-06 18:33 被阅读2563次

    题外话

    一个人做项目的开发和维护,个人觉得还是挺不错的,很自由。当然,也会遇到各种各样的问题,都要自己解决处理,毕竟一个人,但这也是提升个人技术的最快途径。

    最近项目上线相对比较频繁,一个基础产品(主要产品,称之为base吧),还有一个作为马甲产品(称之为mP1吧,鬼知道以后会不会有更多马甲),两个产品每两周就要各上一个版本,每个都要打好几十个包,这在之前,是很痛苦的。试想一个场景:

    快要下班了,领导问马甲产品的功能都做得差不多了吧,好,那就今天马甲产品上线。那就开始打包吧,需要打60个包呀,好,一切都检查好了,觉得没问题了,那就快马加鞭的开始打包吧,在命令行输入gradlew assembleRelease ,就开始了漫长的等待,要下班啊,着急啊,死死地盯着命令行那一动不动的百分号进度···

    终于到了99%,结果无意间发现项目的版本号没有+1,我去,想死的心都有了~~~

    后续情景可以自行脑补了,于是,痛定思痛,决定第二天来了,一定要找到一种省时省力的打包方式。这就是下文的由来。

    打包进化的三个版本

    注意:考虑到多马甲产品,工程里的Java文件的packageName统一,只修改应用的applicationId即可

    版本一:复制项目,单独打包

    1、将基础工程复制一份,作为马甲项目,只看app/build.gradle 文件:

    apply plugin: 'com.android.application'
    
    def releaseTime() {
        return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
    }
    
    android {
        compileSdkVersion 25
        buildToolsVersion '25.0.2'
        useLibrary 'org.apache.http.legacy'
    
        defaultConfig {
            applicationId "com.ylzt.mP1"
            minSdkVersion 16
            targetSdkVersion 25
            versionCode 10
            versionName "1.0"
    
            ndk {
                //选择要添加的对应cpu类型的.so库。
                abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a'
                // 还可以添加 'x86', 'x86_64', 'mips', 'mips64'
            }
    
           multiDexEnabled true
        }
    
        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
            disable "MissingTranslation"
        }
        //打包渠道
        productFlavors {
            "0010001" {}
            "0010002" {}
            "0010003" {}
            "0010004" {}
            "0010005" {}
            "0010006" {}
            "0010007" {}
            "0010008" {}
            "0010009" {}
            "0010010" {}
            "0010011" {}
            "0010012" {}
            "0010013" {}
            "0010014" {}
            "0010015" {}
            "0010016" {}
            "0010017" {}
            "0010018" {}
            "0010019" {}
            "0010020" {}
            "0010021" {}
            "0010022" {}
            "0010023" {}
            "0010024" {}
            "0010025" {}
            "0010026" {}
            "0010027" {}
            "0010028" {}
            "0010029" {}
            "0010030" {}
            "0010031" {}
            "0010032" {}
            "0010033" {}
            "0010034" {}
            "0010035" {}
            "0010036" {}
            "0010037" {}
            "0010038" {}
            "0010039" {}
            "0010040" {}
            "0010041" {}
            "0010042" {}
            "0010043" {}
            "0010044" {}
            "0010045" {}
            "0010046" {}
            "0010047" {}
            "0010048" {}
            "0010049" {}
            "0010050" {}
            "0010051" {}
            "0010052" {}
            "0010053" {}
            "0010054" {}
            "0010055" {}
            "0010056" {}
            "0010057" {}
            "0010058" {}
            "0010059" {}
            "0010060" {}
        }
    
        productFlavors.all {
            flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
        }
    
        signingConfigs {
            debug {
                // No debug config
                storeFile file("C:/Users/dev-android/.android/debug.keystore")
    
                storePassword "xxxxxx"
                keyAlias "xxx"
                keyPassword "xxxxxx"
    
            }
    
            release {
                storeFile file("D:/keystore/xxx.keystore")
    
                storePassword "xxxxxx"
                keyAlias "xxx"
                keyPassword "xxxxxx"
            }
        }
    
        buildTypes {
            debug {
                minifyEnabled false
                proguardFiles 'proguard-rules.pro'
            }
    
            release {
                // 不显示Log
                buildConfigField "boolean", "LOG_DEBUG", "false"
    
                // 是否进行混淆
                minifyEnabled true
                // 混淆文件的位置
                proguardFiles 'proguard-rules.pro'
                signingConfig signingConfigs.release
    
                shrinkResources true  // 移除无用的resource文件
            }
        }
    }
    
    dependencies {
        compile fileTree(include: ['*.jar'], dir: 'libs')
        testCompile 'junit:junit:4.12'
        compile 'com.android.support:appcompat-v7:25.1.0'
        compile 'com.android.support:recyclerview-v7:25.1.0'
    
        /*依赖module*/
        compile project(':..:LibModules/:core')
    
        //图片上传
        compile files('libs/httpmime-4.1.1.jar')
        //unzip
        compile files('libs/apache-ant-zip.jar')
        //wx
        compile files('libs/libammsdk.jar')
    
        ······
    }
    

    这里的所有渠道都用编号表示,第二位1就是代表的第一个马甲产品mP1,基础产品的第二位是0(例如:0000001),这是为了区分各个产品,通过不同编号来对应各个渠道。

    这里和基础产品不同的有两处:
    第一:applicationId "com.ylzt.mP1" ,基础的为applicationId "com.ylzt"
    第二处:就是上面所说的,渠道编号的第二位不同

    其他不同的,就是代码里的逻辑了,或者页面UI之类的,这个就不说了。

    2、修改完app/build.gradle 之后,直接在window命令行中输入命令即可:

    Y:\>cd Y:\WorkPlaces\AndroidStudioWP\ApplicationDemos\app
    Y:\WorkPlaces\AndroidStudioWP\ApplicationDemos\app>gradlew assembleRelease
    
    命令行截图

    缺点:
    耗时——渠道越多,所用时间越长
    繁琐——多一个马甲,就需要在多复制一份工程
    笨拙——一处修改,所有的马甲都需要修改
    ......


    版本二:整合项目,变量控制打包

    思路:通过gradle的productFlavors属性创建多个不同版本的App

    要点:

    1、packageName和applicationId的区别:
    packageName即为包名,资源文件(R文件和四大组件等)的路径
    applicationId作为应用的唯一标识
    [参考官方文档ApplicationId versus PackageName(需要翻墙)]

    具体步骤:

    1、创建版本文件夹:
    在src目录下建立相应的版本文件夹,需要多少个版本就创建多少个文件夹,如图所示:

    多版本目录图示 文件内容详情图示

    注:在多版本目录图示中
    红框标注的文件是唯一的
    蓝绿色框标注的文件表示可以同时存在各个版本之中,但不能出现在main目录中
    蓝紫色框标注的文件都可以存在个目录中

    这就涉及到了合并规则:
    a、图片、音频、 XML 类型的 Drawable 等资源文件,将会进行文件级的覆盖
    b、字符串、颜色值、整型等资源以及 AndroidManifest.xml ,将会进行元素级的覆盖
    c、代码资源,同一个类, buildTypes 、 productFlavors 、 main 中只能存在一次,否则会有类重复的错误,但可以存在相同的包目录
    覆盖等级为:buildTypes > productFlavors > main

    简言之:[详见‘文件内容详情图示’]
    main目录中资源代码内容都是公共的,java目录下的代码文件是唯一的,其他版本目录不可存在;res目录下的资源文件(如string.xml)可以在其他版本目录存在,但其中的文件内容必须是唯一的。
    其他各版本目录下的可以存在名称相同的文件,文件中的资源代码内容皆为各自定制独有的

    具体请看官网:https://developer.android.com/studio/build/manifest-merge.html (需要翻墙)

    2、更换各自版本资源代码内容:
    基础版本或者马甲的页面风格各不相同,可能还会有某处的逻辑跳转等也不相同,因此,需要在相应的文件夹中放入定制化的代码或者资源文件,如图标,启动页等【例如‘文件内容详情图示’中所示的app_name就需要更换成各自版本的名称】

    3、配置产品变体版本:
    在app的app/build.gradle 文件中加入

    productFlavors {
            base {    //基础版本
                applicationId "com.ylzt.apcapp"
                versionCode 20
                versionName "2.0"
            }
    
            mP1 {    //马甲1
                applicationId "com.ylzt.apcapp.mp1"
                versionCode 10
                versionName "1.0"
            }
        }
    

    其中可构建的内容还有很多,具体可以参考:https://developer.android.com/studio/build/build-variants.html

    4、配置友盟渠道:
    一个产品版本的时候,是要把友盟各个渠道都配置到productFlavors 中的,如下:

    productFlavors {
            playStore {}
            miui {}
            wandoujia {}
            //......
    }
    

    还有在AndroidManifest.xml中配置标签:

    <meta-data
                android:name="UMENG_CHANNEL"
                android:value="${UMENG_CHANNEL_VALUE}" />
    

    但是现在将产品作为构建变体,所以就需要使用组合了,即flavorDimensions 属性,来创建两种模式,一种作为产品变体(“verf”),一种作为渠道变体(“channel”),将各个变体进行分组,并通过dimension 来区分所要构建的变体类型,即可完成相应的组合。
    注:其中的vcase变量是用来区分产品的,在上面版本一中提到了。fname是用来过滤版本的

    配置如下:

        def vcase     //版本马甲编号,第二版打包方式定义变量
        flavorDimensions "verf", "channel"    //第二版打包方式
        productFlavors {
            base {    //基础版本
                dimension "verf"
                applicationId "com.ylzt.apcapp.debug"
    //            applicationId "com.ylzt.apcapp"
                vcase = "0"
                fname = "base"
                versionCode 20
                versionName "2.0"
                if (applicationId.endsWith('.debug')) { //debug
                    manifestPlaceholders = [
                            JPUSH_APPKEY: "e3b5c9a23c91fe0154ce1e97",
                            JPUSH_PKGNAME: "com.ylzt.apcapp.debug"
                    ]
                } else {    //release
                    manifestPlaceholders = [
                            JPUSH_APPKEY: "0cf7784913f4ec3ce1cf0eb8",
                            JPUSH_PKGNAME: "com.ylzt.apcapp"
                    ]
                }
            }
    
            mP1 {    //马甲1
                dimension "verf"
                applicationId "com.ylzt.apcapp.mp1.debug"
    //            applicationId "com.ylzt.apcapp.mp1"
    //            vcase = "1"
    //            fname = "mP1"
                versionCode 10
                versionName "1.0"
                if (applicationId.endsWith('.debug')) { //debug
                    manifestPlaceholders = [
                            JPUSH_APPKEY: "e1313b5e0150cf749cee9784",
                            JPUSH_PKGNAME: "com.ylzt.apcapp.mp1.debug"
                    ]
                } else {    //release
                    manifestPlaceholders = [
                            JPUSH_APPKEY: "c9a21c73c91f3cef0f4eceb8",
                            JPUSH_PKGNAME: "com.ylzt.apcapp.mp1"
                    ]
                }
            }
    
            //第二版打包方式
            //友盟各个渠道编号
            "00${vcase}0001" { dimension "channel" }
            "00${vcase}0002" { dimension "channel" }
            "00${vcase}0003" { dimension "channel" }
            "00${vcase}0004" { dimension "channel" }
            "00${vcase}0005" { dimension "channel" }
            "00${vcase}0006" { dimension "channel" }
            "00${vcase}0007" { dimension "channel" }
            "00${vcase}0008" { dimension "channel" }
            "00${vcase}0009" { dimension "channel" }
            "00${vcase}0010" { dimension "channel" }
            "00${vcase}0011" { dimension "channel" }
            "00${vcase}0012" { dimension "channel" }
            "00${vcase}0013" { dimension "channel" }
            "00${vcase}0014" { dimension "channel" }
            "00${vcase}0015" { dimension "channel" }
            "00${vcase}0016" { dimension "channel" }
            "00${vcase}0017" { dimension "channel" }
            "00${vcase}0018" { dimension "channel" }
            "00${vcase}0019" { dimension "channel" }
            "00${vcase}0020" { dimension "channel" }
            "00${vcase}0021" { dimension "channel" }
            "00${vcase}0022" { dimension "channel" }
            "00${vcase}0023" { dimension "channel" }
            "00${vcase}0024" { dimension "channel" }
            "00${vcase}0025" { dimension "channel" }
            "00${vcase}0026" { dimension "channel" }
            "00${vcase}0027" { dimension "channel" }
            "00${vcase}0028" { dimension "channel" }
            "00${vcase}0029" { dimension "channel" }
            "00${vcase}0030" { dimension "channel" }
            "00${vcase}0031" { dimension "channel" }
            "00${vcase}0032" { dimension "channel" }
            "00${vcase}0033" { dimension "channel" }
            "00${vcase}0034" { dimension "channel" }
            "00${vcase}0035" { dimension "channel" }
            "00${vcase}0036" { dimension "channel" }
            "00${vcase}0037" { dimension "channel" }
            "00${vcase}0038" { dimension "channel" }
            "00${vcase}0039" { dimension "channel" }
            "00${vcase}0040" { dimension "channel" }
            "00${vcase}0041" { dimension "channel" }
            "00${vcase}0042" { dimension "channel" }
            "00${vcase}0043" { dimension "channel" }
            "00${vcase}0044" { dimension "channel" }
            "00${vcase}0045" { dimension "channel" }
            "00${vcase}0046" { dimension "channel" }
            "00${vcase}0047" { dimension "channel" }
            "00${vcase}0048" { dimension "channel" }
            "00${vcase}0049" { dimension "channel" }
            "00${vcase}0050" { dimension "channel" }
            "00${vcase}0051" { dimension "channel" }
            "00${vcase}0052" { dimension "channel" }
            "00${vcase}0053" { dimension "channel" }
            "00${vcase}0054" { dimension "channel" }
            "00${vcase}0055" { dimension "channel" }
            "00${vcase}0056" { dimension "channel" }
            "00${vcase}0057" { dimension "channel" }
            "00${vcase}0058" { dimension "channel" }
            "00${vcase}0059" { dimension "channel" }
            "00${vcase}0060" { dimension "channel" }
            /**/
        }
    
        productFlavors.all { flavor ->
            if (dimension=="channel") {
                flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
            }
        }
    
        //变种过滤
        variantFilter { variant ->
            def names = variant.flavors*.name
            // To check for a certain build type, use variant.buildType.name == "<buildType>"
            if (!names.contains(fname)) {
                // Gradle ignores any variants that satisfy the conditions above.
                setIgnore(true)
            }
        }
    

    在测试运行的时候,可以选择相应的版本进行运行,如图:

    构建变体选择图示

    5、相关问题总结:

    • 问题一:微信分享支付的回调
      根据文档微信分享必须在对应的包名下创建wxapi/WXEntryActivity 才能回调,所以需要在各自的目录下新建各自版本的wxapi/WXEntryActivity 来保证唯一(注意包名),并在各版本下的AndroidManifest.xml中注册,如图:
    微信回调Java文件base目录图示 微信回调Java文件mp1目录图示 AndroidManifest.xml图示
    • 问题二:极光推送相关问题:
      极光推送比较坑爹的是,开发环境和生产环境不能使用同一个appkey,所以面临的问题就是:有多少个产品应用,就需要申请双倍的appkey,比如上面我们有base和mP1两个产品,就需要申请四个appkey,分别为:
      base的appkey:xxxxxxbase
      base的debug_appkey:xxxxxxbaseDebug
      mP1的appkey:xxxxxxmP1
      mP1的debug_appkey:xxxxxxmP1Debug

    注:这里的后缀用于区分而已,实际appkey形如:cce012wwf66bd554999a56w6

    当然了,每一个的包名都不能相同,对于这种情况,就需要在构建变体的时候,通过后缀来判断使用哪一个appkey了:

    productFlavors {
            base {    //基础版本
                applicationId "com.ylzt.apcapp.debug"  //打包的时候关闭注释
    //            applicationId "com.ylzt.apcapp"  //打包的时候打开注释
                versionCode 20
                versionName "2.0"
                if (applicationId.endsWith('.debug')) { //debug
                    manifestPlaceholders = [
                            JPUSH_APPKEY: "e3b5c9a23c91fe0154ce1e97",
                            JPUSH_PKGNAME: "com.ylzt.apcapp.debug"
                    ]
                } else {    //release
                    manifestPlaceholders = [
                            JPUSH_APPKEY: "0cf7784913f4ec3ce1cf0eb8",
                            JPUSH_PKGNAME: "com.ylzt.apcapp"
                    ]
                }
            }
    
            mP1 {    //马甲1
                applicationId "com.ylzt.apcapp.mp1.debug"  //打包的时候关闭注释
    //            applicationId "com.ylzt.apcapp.mp1"  //打包的时候打开注释
                versionCode 10
                versionName "1.0"
                if (applicationId.endsWith('.debug')) { //debug
                    manifestPlaceholders = [
                            JPUSH_APPKEY: "e1313b5e0150cf749cee9784",
                            JPUSH_PKGNAME: "com.ylzt.apcapp.mp1.debug"
                    ]
                } else {    //release
                    manifestPlaceholders = [
                            JPUSH_APPKEY: "c9a21c73c91f3cef0f4eceb8",
                            JPUSH_PKGNAME: "com.ylzt.apcapp.mp1"
                    ]
                }
            }
        }
    

    在AndroidManifest.xml中配置极光相关代码:

            <meta-data
                android:name="JPUSH_CHANNEL"
                android:value="developer-default" />
            <meta-data
                android:name="JPUSH_APPKEY"
                android:value="${JPUSH_APPKEY}" />
    
            <!-- 包名引用举例-->
            <activity
                android:name="cn.jpush.android.ui.PushActivity"
                android:configChanges="orientation|keyboardHidden"
                android:exported="false"
                android:theme="@android:style/Theme.NoTitleBar">
                <intent-filter>
                    <action android:name="cn.jpush.android.ui.PushActivity" />
    
                    <category android:name="android.intent.category.DEFAULT" />
                    <category android:name="${JPUSH_PKGNAME}" />
                </intent-filter>
            </activity>
    
    

    通过这种方式就可以分别使用各自环境下的appkey了,不过有一点麻烦的是发版打包的时候,需要手动打开和关闭相应的注释。

    我也考虑过使用applicationIdSuffix ".debug" ,即在配置debug 的时候使用applicationIdSuffix 属性,这样就可以不用去手动打开和关闭注释,因为这两个环境下的applicationId只是差一个“.debug”的后缀而已。但是这样会出现一个问题,就是在开发环境下,会收不到极光推送的消息,原因何在呢?

    可以肯定的是,debug版本的应用并未注册到极光推送的服务器上,即并未获得RegistrationId。我个人觉得,实际已经注册了,但是注册的是release版本,即生产环境的版本。这其中似乎是引用的问题,下面我用伪代码以base版本为例来说一说我的猜测:

    applicationIdSuffix = ".debug"
    applicationId = "com.ylzt.apcapp"
    applicationId_result = applicationId + applicationIdSuffix  //com.ylzt.apcapp.debug
    if (applicationId.endsWith('.debug')) { //debug
        manifestPlaceholders = [
            JPUSH_APPKEY: "e1313b5e0150cf749cee9784",
            JPUSH_PKGNAME: "com.ylzt.apcapp.mp1.debug"
         ]
     } else {    //release
        manifestPlaceholders = [
            JPUSH_APPKEY: "c9a21c73c91f3cef0f4eceb8",
            JPUSH_PKGNAME: "com.ylzt.apcapp.mp1"
        ]
    }
    

    个人觉得两种可能,一种就是伪代码中所示的,是用applicationId_result 作为最终的applicationId的引用;另一种就是applicationId没有及时赋值,虽然是用applicationId作为应用,但是当完成赋值的时候,已经执行了if语句了。

    所以才会出现上面我说到的情况,当然,这是本人愚见,若有哪位大神知道原因和解决方案,欢迎留言指正,谢谢。

    6、修改完app/build.gradle 之后,直接在window命令行中输入命令即可:

    Y:\>cd Y:\WorkPlaces\AndroidStudioWP\ApplicationDemos\app
    Y:\WorkPlaces\AndroidStudioWP\ApplicationDemos\app>gradlew assembleRelease
    
    命令行截图

    缺点:
    耗时——渠道越多,所用时间越长
    ......


    版本三:整合项目,神器打包

    到此,放大招了,成为终极打包版本吧,用到的神器就是Walle,参考:https://github.com/Meituan-Dianping/walle

    注意:
    参考中给定的渠道channel文件是放在app文件夹同级目录中的,而由于本人的项目中的渠道是自定义的编码,每个产品的第二位都不一样,所以就需要放到各自版本的目录之中,位置如图:

    渠道目录图示

    闲话少说,直接上代码:

    build.gradle:

    apply plugin: 'com.android.application'
    apply plugin: 'walle'
    
    def releaseTime() {
        return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
    }
    
    def fname     //版本马甲名称
    android {
        compileSdkVersion 25
        buildToolsVersion "25.0.2"
        defaultConfig {
            applicationId "com.ylzt.apcapp"
            minSdkVersion 15
            targetSdkVersion 25
    
            ndk {
                //选择要添加的对应cpu类型的.so库。
                abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a'
                // 还可以添加 'x86', 'x86_64', 'mips', 'mips64'
            }
    
            multiDexEnabled true
    
            versionCode 1
            versionName "1.0"
        }
    
        signingConfigs {
            debug {
                storeFile file("debug.keystore")
    
                storePassword "123456"
                keyAlias "ylzt"
                keyPassword "123456"
    
            }
    
            release {
                storeFile file("Y:/ylzt.keystore")
    
                storePassword "123456"
                keyAlias "ylzt"
                keyPassword "123456"
            }
        }
    
        buildTypes {
            debug {
                minifyEnabled false
                proguardFiles 'proguard-rules.pro'
            }
    
            release {
                // 不显示Log
                buildConfigField "boolean", "LOG_DEBUG", "false"
    
                // 是否进行混淆
                minifyEnabled true
                // 混淆文件的位置
                proguardFiles 'proguard-rules.pro'
                signingConfig signingConfigs.release
    
                shrinkResources true  // 移除无用的resource文件
            }
        }
    
        productFlavors {
            base {    //基础版本
                applicationId "com.ylzt.apcapp.debug"
    //            applicationId "com.ylzt.apcapp"
                fname = "base"  //需要手动修改,以改变要打包的项目
                versionCode 20
                versionName "2.0"
                if (applicationId.endsWith('.debug')) { //debug
                    manifestPlaceholders = [
                            JPUSH_APPKEY: "e3b5c9a23c91fe0154ce1e97",
                            JPUSH_PKGNAME: "com.ylzt.apcapp.debug"
                    ]
                } else {    //release
                    manifestPlaceholders = [
                            JPUSH_APPKEY: "0cf7784913f4ec3ce1cf0eb8",
                            JPUSH_PKGNAME: "com.ylzt.apcapp"
                    ]
                }
            }
    
            mP1 {    //马甲1
                applicationId "com.ylzt.apcapp.mp1.debug"
    //            applicationId "com.ylzt.apcapp.mp1"
    //            fname = "mP1"  //需要手动修改,以改变要打包的项目
                versionCode 10
                versionName "1.0"
                if (applicationId.endsWith('.debug')) { //debug
                    manifestPlaceholders = [
                            JPUSH_APPKEY: "e1313b5e0150cf749cee9784",
                            JPUSH_PKGNAME: "com.ylzt.apcapp.mp1.debug"
                    ]
                } else {    //release
                    manifestPlaceholders = [
                            JPUSH_APPKEY: "c9a21c73c91f3cef0f4eceb8",
                            JPUSH_PKGNAME: "com.ylzt.apcapp.mp1"
                    ]
                }
            }
    
        }
    
        //变种过滤
        variantFilter { variant ->
            def names = variant.flavors*.name
            // To check for a certain build type, use variant.buildType.name == "<buildType>"
            if (!names.contains(fname)) {
                // Gradle ignores any variants that satisfy the conditions above.
                setIgnore(true)
            }
        }
    }
    
    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile 'com.android.support:appcompat-v7:25.3.1'
        compile 'com.android.support:design:25.3.1'
        testCompile 'junit:junit:4.12'
    
        /*依赖module*/
        compile project(':..:LibsModules/:core')
    
        compile 'com.umeng.analytics:analytics:latest.integration'
        //wx
        compile files('libs/libammsdk.jar')
        compile files('libs/SocialSDK_WeChat_Simplify.jar')
    
        compile 'com.meituan.android.walle:library:1.1.4'
    }
    
    
    
    //第三版打包方式:walle打包方式,详见https://github.com/Meituan-Dianping/walle
    walle {
        // 指定渠道包的输出路径
        apkOutputFolder = new File("${project.buildDir}/outputs/channels");
        // 定制渠道包的APK的文件名称
        apkFileNameFormat = '${flavorName}_0${versionCode}_${channel}.apk';
        // 渠道配置文件
    //    channelFile = new File("${project.getProjectDir()}/channel")
        channelFile = new File("${project.getProjectDir()}/src/${fname}/channel")
    }
    

    注:其中需要手动修改的地方已经写了注释,即以fname变量来控制打包工程,在变种过滤(variantFilter)中已经做了相应的判断

    用这种方式打包确实很爽,不到一分钟,60个包全部完成,妈妈再也不用担心我打包耗时了~~~

    结语

    经过三个版本的演化,从中学到了不少,gradle的知识还有很多需要学习,希望大家能共同进步。
    当然了,其中还有许多要改进的地方,还没有完全做到全自动化,有兴趣的同学可以看一看云打包的相关资料,有好的学习资料也希望大家多多分享。

    相关资料:

    https://developer.android.com/studio/build/build-variants.html(需要翻墙)
    https://developer.android.com/studio/build/manifest-merge.html(需要翻墙)

    https://segmentfault.com/a/1190000002910311
    https://github.com/Meituan-Dianping/walle
    http://tech.meituan.com/android-apk-v2-signature-scheme.html

    http://www.jianshu.com/p/c90e21bf4e23?utm_campaign=haruki&utm_content=note&utm_medium=reader_share&utm_source=qq

    相关文章

      网友评论

        本文标题:技术:Android打包签名总结

        本文链接:https://www.haomeiwen.com/subject/idafhxtx.html