Android multi-channel package of practical operation (change the package name, icon, theme resources, constant replacement, third-party SDK Appkey configuration)

Recently doing a generic version of the membership system, giving different companies used previously by switching version branch to manage, and found the back is really tedious and pain management, just need to change the different constants, themes resources, package name, icon the like, subject code logic functions substantially unchanged.

Prior knowledge of the use of excessive channel package, in fact, there can be packed this pain point by Gradle multi-channel, also stepped up during the pit, to be recorded here

table of Contents

First, by productFlavors configure different channels / environment

Two, manifestPlaceholders placeholders

Third, understand the difference ApplicationId and the PackageName

Fourth, replace the resource file

Fifth, packaging and debugging compile and install a different version of the channel

The following configuration to complete this project actually has two channels equivalent to different members of the two companies to use configuration app



apply plugin: 'com.android.application'
def releaseTime() {
    return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}
//加载本地文件
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.ablegenius.member"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 101
        versionName "1.0.101"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

        multiDexEnabled true

        ndk {
            //选择要添加的对应cpu类型的.so库。
            abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "arm64-v8a", "x86_64"
            //, 'mips', 'mips64'
        }

        // 渠道配置 gradle 3.0.0 以上需要有这个
        flavorDimensions "app"
    }

    signingConfigs {

        AblegeniusMemberConfig {
            //第一种:使用gradle直接签名打包
            /*  keyAlias 'dongwang'
            keyPassword '123123'
            storeFile file('src/main/WineverzhudiStoreFile.jks')
            storePassword '123123'*/

            //第二种:为了保护签名文件,把它放在local.properties中并在版本库中排除
            // ,不把这些信息写入到版本库中(注意,此种方式签名文件中不能有中文)

            storeFile file(properties.getProperty("keystroe_storeFile"))
            storePassword properties.getProperty("keystroe_storePassword")
            keyAlias properties.getProperty("keystroe_keyAlias")
            keyPassword properties.getProperty("keystroe_keyPassword")

            v2SigningEnabled false
        }

    }

    // 多渠道/多环境 的不同配置
    productFlavors {


        SatayKing {
            //此处的常量都会通过Gradle 在 BuildConfig.java 文件中生成 , 你可以直接在Class中使用 BuildConfig.XXXX 进行使用
            // 每个环境包名不同
            applicationId "com.ablegenius.member.satayking"
            // 动态添加 string.xml 字段;
            // 注意,如果在这添加,在 string.xml 不能有这个字段,会重名!!!这里使用资源文件覆盖的方式来处理应用名称
//            resValue "string", "app_name", "沙嗲王會員x"
            resValue "bool", "auto_updates", 'false'
            // 动态修改 常量 字段
            buildConfigField "String", "MAIN_H5_URL", '"https://xxxxxxx22/index.html"'
            //服務器請求地址
            buildConfigField "String", "SERVER_URL", '"https://cloudxxxx22/a"'
           //一些常量
            buildConfigField "String", "company", '"SatayKing"'
            buildConfigField "String", "serial", '"xxxxx"'
            buildConfigField "int", "ENVIRONMENTInt", '2'
            // 修改 AndroidManifest.xml 里渠道变量
            manifestPlaceholders = [CHANNEL_VALUE: "SatayKing"
                                    , app_icon   : "@mipmap/ic_launcher_shadiewang",
                                    //此方式可直接在 manifest 中通过 ${icon} 进行占位引用; 或者在main同级中创建不同渠道后创建 res 资源文件
                                    icon         : "@mipmap/ic_launcher_shadiewang",
                                    //极光相关
                                    JPUSH_PKGNAME: applicationId,
                                    JPUSH_APPKEY : "xxxxxxx", //JPush上注册的包名对应的appkey.
                                    JPUSH_CHANNEL: "developer-default", //暂时填写默认值即可.
                                    //Google Map 相关
                                    GoogleMapKey : "AIzaSyCLJ9Gng-xxxxx",

            ]

        }

        WineverHK {

            dimension "app"

            applicationId "com.ablegenius.member.wineverzhudi"

//            resValue "string", "app_name", "築地日本料理"
            resValue "bool", "auto_updates", 'true'
            resValue "drawable", "isrRank", 'true'
         
            buildConfigField "String", "MAIN_H5_URL", '"http://xxxxindex.html"'
            buildConfigField "String", "SERVER_URL", '"http://cloud.xxxx/a"'

            buildConfigField "String", "company", '"WineverHK"'
            buildConfigField "String", "serial", '"xxxx"'


            manifestPlaceholders = [CHANNEL_VALUE: "WineverHK"
                                    , app_icon   : "@mipmap/ic_launcher_zhudi",
                                    icon         : "@mipmap/ic_launcher_zhudi",

                                    JPUSH_PKGNAME: applicationId,
                                    JPUSH_APPKEY : "247aef555a20e8836d1ac361", //JPush上注册的包名对应的appkey.
                                    JPUSH_CHANNEL: "developer-default", //暂时填写默认值即可.

                                    GoogleMapKey : "AIzaSyCtAVjIVmGdnP44W2Nk8DjCT_OJISYUVxA",
            ]
        }


    }

    buildTypes {
        release {
            // release模式下,不显示log
            buildConfigField("boolean", "LOG_DEBUG", "false")
            // 为版本名添加后缀
//            versionNameSuffix "-relase"
            // 不开启混淆
            minifyEnabled false
            // 移除无用的resource文件
            shrinkResources false
            // 开启ZipAlign优化
            zipAlignEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

            signingConfig signingConfigs.AblegeniusMemberConfig


        }

        debug {

            // debug模式下,显示log
            buildConfigField("boolean", "LOG_DEBUG", "true")

            //为已经存在的applicationId添加后缀
//            applicationIdSuffix ".debug"
            // 为版本名添加后缀
            versionNameSuffix "-debug"
            // 不开启混淆
            minifyEnabled false
            // 不开启ZipAlign优化
            zipAlignEnabled false
            // 不移除无用的resource文件
            shrinkResources false

            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.AblegeniusMemberConfig
        }
    }

    // 3.0 gradle 批量打包
    android.applicationVariants.all { variant ->
        variant.outputs.all {
            //输出apk名称为:渠道名_版本名_时间.apk
            outputFileName = "${variant.productFlavors[0].name}Member_v${defaultConfig.versionName}_${releaseTime()}.apk"
        }
    }

    sourceSets {
        SatayKing { res.srcDirs = ['src/SatayKing/res', 'src/SatayKing/res/'] }
        WineverHK { res.srcDirs = ['src/WineverHK/res', 'src/WineverHK/res/'] }
        main { res.srcDirs = ['src/main/res', 'src/main/res/'] }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation xxxx
}

First, by productFlavors configure different channels / environment

productFlavors {
    SatayKing {
        applicationId "com.ablegenius.member.satayking"
    }

    WineverHK {
        applicationId "com.ablegenius.member.wineverzhudi"
    }
}

 

Note here that, in defaultConfig in, we should all write a default applicationId of.
After testing, different environmental package name productFlavors setting overrides defaultConfig inside the set,
so we can speculate, order it performs should be the first implementation of the default, then execute sub-channels, if the conflict will cover the treatment, which is very logical.

Two, manifestPlaceholders placeholders

Project to use third-party SDK Aurora, GoogleMap other configurations, we all know need to be pushed Aurora push registered under a different package name JPush package name corresponding appkey talent, how to modify it?

ManifestPlaceholders used to define the constant [] GoogleMapKey,
using "$ {GoogleMapKey}" in AndroidManifest.xml by mass,

<application
android:icon="${icon}"
      android:label="${app_name}"
      xxxxx>
      <!--渠道配置-->
      <meta-data
          android:name="CHANNEL"
          android:value="${CHANNEL_VALUE}" />


      <!-- Google Map Key -->   
      <meta-data
          android:name="com.google.android.geo.API_KEY"
          android:value="${GoogleMapKey}" /> 

<!--  极光推送-->
    
      <!-- User defined. 用户自定义的广播接收器-->
      <receiver
          android:name="com.ablegenius.member.receiver.JpushReceiver"
          android:enabled="true">
          <!--android:process=":remote"广播运行在远端单独进程中 ,调试断点无法执行需要关闭 或者 debug时候选择 remote ! -->
          <intent-filter>
            
            xxxxx
              <!--推送包名必须一致使用Gradle中的常量才是最终的 -->
              <category android:name="${applicationId}" />
          </intent-filter>
      </receiver>

</application>

app name and icon here can be used placeholders way quote,

Tpis: If this is the way to modify the application name, application name defined in the outer noted, defined by resValue String constants need to use a further single quotes string, ' "application name"'
            resValue "string", "app_name", "築地日本料理"

Third, understand the difference ApplicationId and the PackageName

Debug, and package names to Gradle out of applicationId for the final package name, not the final will be in the Manifest is modified, map making key verification when the package name should be filled ApplicationId, rather than packageName

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.ablegenius.member">     

Fourth, replace the resource file

Each application resource layout theme styles, start page icon, application name may be different, then how to do it? Google practices:

Created in the same directory with the main channel named after the folder, and then create a resource file (to be consistent with the main path in), and then packaged when gradle will replace or merge its own resources. Replace images and merge color principle is similar. We must use the name of unity!

Creating res files in the folder corresponding channels, pay attention to the channel for the main directory folder in the same level, to create res: src / channel name / res

image.png

Fifth, packaging and debugging compile and install a different version of the channel

Select a different channel, Gradle automatically compiles the specified channel, and then run the project to

image.png

The default installation channels which require multi-channel package after many channels, you need to do to switch Build in

You can also order packaging: ./gradlew assembleRelease

Finally, if you have a third party involved Appkey like this be sure to check good, and SHA1 value and other configurations

reference:

Gradle multi-channel package (dynamic set App name, application icons, replaced by a constant, change the package name, change the channel)

Android Gradle achieve multi-channel customized package

PackageName with the difference ApplicationId

Published 26 original articles · won praise 19 · views 40000 +

Guess you like

Origin blog.csdn.net/a23006239/article/details/84977279