博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个项目如何编译多个不同签名、包名、资源等,的apk?
阅读量:2356 次
发布时间:2019-05-10

本文共 14451 字,大约阅读时间需要 48 分钟。

作者:徐佳吉

链接:

https://blog.xujiaji.com/post/android-project-one-for-more

1
简介

如题所示!本篇文章就是为了解决这种问题。方便打包和运行的时候能做到无需手动替换配置,即可打包想要的apk。打包的时候,只需选一下想打哪种配置的apk就OK啦。 (^o^)/~

先来看,有需求如下:

  1. 同一个项目

  2. 不同的apk图标

  3. 不同的服务器域名

  4. 不同的包名

  5. 不同的名称

  6. 不同的签名

  7. 不同的第三方key

  8. 不同的版本名版本号

解决思路

  1. 当然最直接的方式不过于每次打不同包的时候都去替换对应的配置,这种方式的麻烦之处不言而喻。

  2. 将所有配置,资源等都配置入项目中,打包的时候,根据选择渠道打包不同配置的apk。(本篇文章就是要讲怎么这么做的)

  3. 相信还有其他的。。。

2
相关的几个要点

1. 首先我们需要知道productFlavors来配置渠道,这里我将渠道用来表示哪种apk,如下我需要配置四种应用:

productFlavors {
  userquhua {}   quhua {}   cuntuba {}   xemh {} }

2. 如果我们选择了某一个渠道,那么运行打包的时候会根据渠道名选择资源文件(可结合第6点一起看)

640?wx_fmt=png

3. 签名可在signingConfigs中配置多个(我将所有签名文件放在了项目跟目录的key文件夹中),这样我们就可以通过signingConfigs指定预制好的签名配置。

signingConfigs {
    userquhuaRelease {
        storeFile file("../key/xxx1.keystore")         storePassword "xxxxxx"         keyAlias "alias"         keyPassword "xxxxxx"     }     quhuaRelease {
        storeFile file("../key/xxx2.keystore")         storePassword "xxxxxx"         keyAlias "alias"         keyPassword "xxxxxx"     }     cuntubaRelease {
        storeFile file("../key/xxx3.keystore")         storePassword "xxxxxx"         keyAlias "alias"         keyPassword "xxxxxx"     }     xemhRelease {
        storeFile file("../key/xxx4.keystore")         storePassword "xxxxxx"         keyAlias "alias"         keyPassword "xxxxxx"     } }

4. 可在build.gradle中配置动态配置java代码调用的常量数据(如:通过该方式我们可根据不同渠道动态配置第三方appid,或其他需要根据渠道而改变的数据)

比如:我们在defaultConfig {} 中定义了:

         

buildConfigField "String", "SERVER_URL", '"http://xx.xxxx.com/"'

此时,您看一下清单文件中manifest标签里的,package的值,假如是:

com.xxx.xx

那么,您就可以在java代码中通过导入文件:

import com.xxx.xx.BuildConfig;

然后调用

BuildConfig.SERVER_URL

它的值就是上边配置的字符串:http://xx.xxxx.com/。

你可以进入BuildConfig看一看,里面还包含了一些当前的包名版本号等信息。

640?wx_fmt=png

5. 在渠道配置那里可以配置对应的包名版本名签名等等

如下所示:

// 省略其他配置... android {
  // 省略其他配置...   productFlavors {
      userquhua {
          applicationId "com.xxx.xx"           versionCode 1           versionName "1.0.0"           signingConfig signingConfigs.userquhuaRelease // 配置签名           String qq_id = '"xxxxxxxxx"' //配置qq appid           buildConfigField "String",           "QQ_ID", qq_id           buildConfigField "String",           "WX_ID", '"wxxxxxxxxxxxxxxxxx"' // 配置微信appid           manifestPlaceholders = [             qq_id: qq_id,             JPUSH_PKGNAME : applicationId,             JPUSH_APPKEY : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx", //JPush 上注册的包名对应的 Appkey.             JPUSH_CHANNEL : "developer-default",           ]       }   }   buildTypes {
    release {
      // 省略其他配置...         signingConfig null  // 置空     }     debug {
      // 省略其他配置...         signingConfig null // 置空     }   } }

这样,如果我们打包userquhua这个渠道,看第2点中介绍选择userquhuaDebug。

然后,最好clean一下项目、然后我们运行项目。

该app的包名就是com.xxx.xx,版本号为1,版本名为1.0.0。

通过BuildConfig调用QQ_ID静态常量,就是该渠道里配置的值,WX_ID同理。

manifestPlaceholders配置也可以这样配置。

签名问题经过个人反复尝试(然后半天就过去了 ̄へ ̄),最终签名如上配置。

需要注意buildTypes中的签名配置signingConfig如果不设置为null,那么打包的是有还是以内置的签名打包。

6. 资源文件替换

再看到第2点的介绍,我们选择运行渠道后,会默认匹配对应渠道下的资源。下面我将xemh渠道的资源目录全部展开一下。

640?wx_fmt=png

如上图这样,只需要资源名字和app目录对应的文件名字一样即可替换。

strings.xml里的应用名,只需要将对应app_name修改既可替换app下strings的app_name,其他不用替换的不用写就行。

7. 打正式包的时候选好渠道,就可以打包不同配置的apk,当然您也可以使用命令的方式。

640?wx_fmt=png

3
其他配置记录

获取当前时间

static def releaseTime() {
    return new Date().format("yyyy-MM-dd-HH.mm", TimeZone.getTimeZone("GMT+8")) }

打包的时候,修改文件名,以方便区别渠道和版本打包时间

applicationVariants.all {
    variant ->         variant.outputs.all {
            outputFileName = "${variant.productFlavors[0].name}-v${variant.productFlavors[0].versionName}-${releaseTime()}.apk"         } }

  • ${variant.productFlavors[0].name}当前渠道名

  • ${variant.productFlavors[0].versionName}当前版本名

  • ${releaseTime()}当前时间

4
其他需要注意的事项

如果您在清单文件AndroidManifest.xml中,有那种以包名开头命名的那种。因为如果包名都改了,有些也需要动态的改变。可以用${applicationId}代替。在打包的时候,会自动替换成当前包名。

比如,类似下配置:

    
        
        
    
    

可改为:

    
        
        
    
    

当然值得注意的是,在代码中我们也不能把包名写死了,可通过BuildConfig得到当前包名

5
我的完整配置,供参考

有关隐私信息的都用xxx替换了

1. 项目根目录的build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript {
    repositories {
        google()         jcenter()     }     dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0'         classpath "io.github.prototypez:save-state:0.1.7"         // NOTE: Do not place your application dependencies here; they belong         // in the individual module build.gradle files     } } allprojects {
    repositories {
        google()         jcenter()         maven { url "https://jitpack.io" }         maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local/' }         flatDir {
            dirs 'libs'         }     } } task clean(type: Delete) {
    delete rootProject.buildDir } ext{
    minSdkVersion               = 16     targetSdkVersion            = 27     compileSdkVersion           = 27     buildToolsVersion           = '27.1.1'     supportLibraryVersion       = '27.1.1'     xmvpVersion                 = '1.2.2'     retrofit2Version            = '2.3.0'     okhttp3Version              = '3.8.1'     butterknifeVersion          = '8.6.0'     rx2Version                  = '2.0.2'     CircleProgressDialogVersion = '1.0.2'     smarttabVersion             = '1.6.1@aar'     adapterHelperVersion        = '2.9.41'     glideVersion                = '4.7.1'     roundedimageviewVersion     = '2.3.0'     eventbusVersion             = '3.0.0'     dispatcherVersion           = '2.4.0'     picture_libraryVersion      = 'v2.2.3'     statusbarutilVersion        = '1.5.1'     okhttpUtilsVersion          = '3.8.0'     constraintVersion           = '1.1.3'     flexboxVersion              = '1.0.0' }

2. app目录下的build.gradle

apply plugin: 'com.android.application' apply plugin: 'save.state' static def releaseTime() {
    return new Date().format("yyyy-MM-dd-HH.mm", TimeZone.getTimeZone("GMT+8")) } android {
    compileSdkVersion rootProject.compileSdkVersion //    buildToolsVersion rootProject.buildToolsVersion     defaultConfig {
        minSdkVersion rootProject.minSdkVersion         targetSdkVersion rootProject.targetSdkVersion         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"         multiDexEnabled true         // config the JSON processing library         javaCompileOptions {
            annotationProcessorOptions {
                arguments = [ serializer : "gson" ]             }         }         ndk {
            abiFilters "armeabi-v7a"         }         renderscriptTargetApi 25         renderscriptSupportModeEnabled true     }     signingConfigs {
        userquhuaRelease {
            storeFile file("../key/xxx.keystore")             storePassword "xxxxxx"             keyAlias "xxx"             keyPassword "xxxxxx"         }         quhuaRelease {
            storeFile file("../key/xxx.keystore")             storePassword "xxxxxxx"             keyAlias "xxx"             keyPassword "xxxxxxx"         }         cuntubaRelease {
            storeFile file("../key/xxx.keystore")             storePassword "xxxxxxx"             keyAlias "xxx"             keyPassword "xxxxxxx"         }         xemhRelease {
            storeFile file("../key/xxx.keystore")             storePassword "xxxxxxx"             keyAlias "xxx"             keyPassword "xxxxxxx"         }     }     flavorDimensions "default"     productFlavors {
        userquhua {
            applicationId "com.xxx.xx"             versionCode 22             versionName "1.7.5"             signingConfig = signingConfigs.userquhuaRelease             String qq_id = '"xxxxxx"'             buildConfigField "String",           "QQ_ID", qq_id // qq appId             buildConfigField "String",         "SINA_ID", '"xxxxxx"' // 新浪appId             buildConfigField "String",           "WX_ID", '"xxxxxx"' // 微信 appId             buildConfigField "String",           "UM_ID", '"xxxxxx"' // 友盟             buildConfigField "String",       "WX_SECRET", '"xxxxxx"' // 微信 secret             buildConfigField "String",   "SINA_REDIRECT", '"http://open.weibo.com/apps/xxxxxx/privilege/oauth"' // 新浪             buildConfigField "String",   "ADHUB_INIT_ID", '"xxxxxx"' // 广告sdk初始化id             buildConfigField "String", "ADHUB_SPLASH_ID", '"xxxxxx"' // 开屏广告id             buildConfigField "String", "ADHUB_BANNER_ID", '"xxxxxx"' // banner广告id             buildConfigField "String",      "SERVER_URL", '"http://xxx.xxx.com/"'             buildConfigField "String",        "LOGO_URL", '"http://file.xxx.com/img/xxx.png"'             manifestPlaceholders = [                     qq_id: qq_id,                     JPUSH_PKGNAME : applicationId,                     JPUSH_APPKEY : "xxxxxx", //JPush 上注册的包名对应的 Appkey.                     JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可.             ]         }         quhua {
            applicationId "com.xxx.xx"             versionCode 1             versionName "1.0.0"             signingConfig = signingConfigs.quhuaRelease             String qq_id = '"xxxxxx"'             buildConfigField "String",           "QQ_ID", qq_id             buildConfigField "String",         "SINA_ID", '"xxxxxx"'             buildConfigField "String",           "WX_ID", '"xxxxxx"'             buildConfigField "String",           "UM_ID", '"xxxxxx"'             buildConfigField "String",       "WX_SECRET", '"xxxxxx"'             buildConfigField "String",   "SINA_REDIRECT", '"http://open.weibo.com/apps/xxxxxx/privilege/oauth"'             buildConfigField "String",   "ADHUB_INIT_ID", '"xxxxxx"' // 广告sdk初始化id             buildConfigField "String", "ADHUB_SPLASH_ID", '"xxxxxx"' // 开屏广告id             buildConfigField "String", "ADHUB_BANNER_ID", '"xxxxxx"' // banner广告id             buildConfigField "String",      "SERVER_URL", '"http://xx.xxx.com/"'             buildConfigField "String",        "LOGO_URL", '"http://file.xxx.com/img/xxx.png"'             manifestPlaceholders = [                     qq_id: qq_id,                     JPUSH_PKGNAME : applicationId,                     JPUSH_APPKEY : "xxxxxx", //JPush 上注册的包名对应的 Appkey.                     JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可.             ]         }         cuntuba {
            applicationId "com.xxx.xx"             versionCode 1             versionName "1.0.0"             signingConfig = signingConfigs.cuntubaRelease             String qq_id = '"xxxxxx"'             buildConfigField "String",           "QQ_ID", qq_id             buildConfigField "String",         "SINA_ID", '"xxxxxx"'             buildConfigField "String",           "WX_ID", '"xxxxxx"'             buildConfigField "String",           "UM_ID", '"xxxxxx"'             buildConfigField "String",       "WX_SECRET", '"xxxxxx"'             buildConfigField "String",   "SINA_REDIRECT", '"http://open.weibo.com/apps/xxxxxx/privilege/oauth"'             buildConfigField "String",   "ADHUB_INIT_ID", '"xxxxxx"' // 广告sdk初始化id             buildConfigField "String", "ADHUB_SPLASH_ID", '"xxxxxx"' // 开屏广告id             buildConfigField "String", "ADHUB_BANNER_ID", '"xxxxxx"' // banner广告id             buildConfigField "String",      "SERVER_URL", '"http://xxx.xxxx.com/"'             buildConfigField "String",        "LOGO_URL", '"http://file.xxx.com/img/xxx.png"'             manifestPlaceholders = [                     qq_id: qq_id,                     JPUSH_PKGNAME : applicationId,                     JPUSH_APPKEY : "xxxxxx", //JPush 上注册的包名对应的 Appkey.                     JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可.             ]         }         xemh {
            applicationId "com.xxx.xx"             versionCode 1             versionName "1.0.0"             signingConfig = signingConfigs.xemhRelease             String qq_id = '"xxxxxx"'             buildConfigField "String",           "QQ_ID", qq_id             buildConfigField "String",         "SINA_ID", '"xxxxxx"'             buildConfigField "String",           "WX_ID", '"xxxxxx"'             buildConfigField "String",           "UM_ID", '"xxxxxx"'             buildConfigField "String",       "WX_SECRET", '"xxxxxx"'             buildConfigField "String",   "SINA_REDIRECT", '"xxxxxx"'             buildConfigField "String",   "ADHUB_INIT_ID", '"xxxxxx"' // 广告sdk初始化id             buildConfigField "String", "ADHUB_SPLASH_ID", '"xxxxxx"' // 开屏广告id             buildConfigField "String", "ADHUB_BANNER_ID", '"xxxxxx"' // banner广告id             buildConfigField "String",      "SERVER_URL", '"http://xx.xxx.com/"'             buildConfigField "String",        "LOGO_URL", '"http://file.xxxxxx.com/img/xxxxxx.png"'             manifestPlaceholders = [                     qq_id: qq_id,                     JPUSH_PKGNAME : applicationId,                     JPUSH_APPKEY : "xxxxxx", //JPush 上注册的包名对应的 Appkey.                     JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可.             ]         }     }     applicationVariants.all {
        variant ->             variant.outputs.all {
                outputFileName = "${variant.productFlavors[0].name}-v${variant.productFlavors[0].versionName}-${releaseTime()}.apk"             }     }     buildTypes {
        release {
            // 不显示Log             buildConfigField "boolean", "LOG_DEBUG", "false"             signingConfig null             minifyEnabled true             zipAlignEnabled true             // 移除无用的resource文件             shrinkResources true             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'         }         debug {
            // 显示Log             buildConfigField "boolean", "LOG_DEBUG", "true"             signingConfig null             minifyEnabled false             zipAlignEnabled false             shrinkResources false         }     }     packagingOptions {
        exclude 'META-INF/DEPENDENCIES.txt'         exclude 'META-INF/NOTICE'         exclude 'META-INF/NOTICE.txt'         exclude 'META-INF/LICENSE'         exclude 'META-INF/LICENSE.txt'     }     compileOptions {
        targetCompatibility JavaVersion.VERSION_1_8         sourceCompatibility JavaVersion.VERSION_1_8     }     dexOptions {
        javaMaxHeapSize "4g" //此处可根据电脑本身配置 数值越大 当然越快         preDexLibraries = false     } } repositories {
    flatDir {
        dirs 'libs', '../adpoymer/libs'     } } dependencies {
    // 省略 }
结束

                        喜欢 就关注吧,欢迎投稿!

640?wx_fmt=jpeg

转载地址:http://afdtb.baihongyu.com/

你可能感兴趣的文章
php-fpm配置
查看>>
Centos 系统时间与当前时间相差和时区解决办法
查看>>
Linux下如何进行FTP设置
查看>>
linux之LVM操作案例
查看>>
由于CentOS的系统安装了epel-release-latest-7.noarch.rpm 导致在使用yum命令时出现Error: xz compression not available问题。
查看>>
php中抽象类和接口的概念与区别
查看>>
php抽象类和接口
查看>>
如何在linux CentOS 上安装chrome 谷歌浏览器
查看>>
laravel5 怎么实现事务
查看>>
GitLab安装说明
查看>>
Git查看、删除、重命名远程分支和tag
查看>>
PHP类中的抽象类,抽象方法,abstract
查看>>
PHP接口类interface的正确使用方法
查看>>
Sencha Touch之Hello World
查看>>
Tab Layout 之单个Activity实现
查看>>
Tab Layout 之多个Activity实现
查看>>
FrameLayout之我见
查看>>
个人解读Activity之一
查看>>
实现自定义布局的Notification
查看>>
AlarmManager的学习与实现
查看>>