Android 定制化apk生成
日常开发过程中,经常会遇到定制化的app,但所谓的定制化,往往只是更改其中的一部分数据,或者更改不一样的功能,那么一般的做法也就是所谓的多渠道打包。
但是多渠道打包的缺点就是首先需要知道有多少渠道。如果增加了渠道,还需要手动编辑build.gradle配置,然后再次生成。
其实我们所说的渠道一般指的是应用商店的渠道,大的应用商店屈指可数,所以直接配置多渠道打包,也未尝不可,新增加一个应用商店那就手动添加一次。应用商店这种基础服务,不会一天出现好多,基本在市场初期就已经奠定基础了。
但是并不是所有app都会上架到应用商店的,有一些apk只能去固定的地方下载,特别是toB的app。
比如,我们原来是做web端的服务,一开始做的是PC端的,然后又做了移动端H5。由于服务是sass服务,对于每个租户来说都有其固定域名,租户访问服务都去访问自己的域名。由于移动端H5体验并不是很好,一次开发应用就显示十分必要,那么怎么区分租户app呢?
最简单的形式是给每个租户定制化app[比如更改生成app的名字等],假如我们现有100个租户,每天新增十个,那么我如何动态更改呢?
手动更改太累了
那么有没有什么办法,可以避免手动操作呢?
使用gradle,我们可以在build.gradle中编辑
android { compileSdkVersion 28 buildToolsVersion "29.0.0" defaultConfig { applicationId "cn.kanyun.tenant" minSdkVersion 24 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" flavorDimensions "default" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' buildConfigField "String", "BASE_URL", APP_DYM_URL } debug { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' // buildConfigField可以增加自动生成的BuildConfig类的变量 buildConfigField "String", "BASE_URL", APP_DYM_URL } } productFlavors { // WUMEI{ // applicationId "wumei.kanyun.cn" // manifestPlaceholders=[app_name:"物美"] // } // SUNING{ // applicationId "suning.kanyun.cn" // manifestPlaceholders=[app_name:"苏宁"] // } dym { applicationId APP_DYM_ID manifestPlaceholders = [app_name: APP_DYM_NAME] } } }
我们通过编辑其中的 productFlavors 和 buildTypes 就可以了
上述就是所谓的多渠道打包
我们所要做的就是在多渠道打包中添加点别的东西
注意 标黄 的部分,那个部分定义的是变量
那么这个变量定义在哪里呢?
其定义在 gradle.properties 文件中
配置了这些变量,就可以在build.gradle中就可以读取到了。
那么当有新租户来的时候,只需要后台修改gradle.properties文件,然后运行构建脚本就可以生成apk了。
但是这算是全部了吗?
并不是这样的。
这样其实也就定制了app的名字而已。
前面说过由于我们的服务是sass服务,每个租户都有其固定域名,因此每个app发出的请求都有其固定前缀。
我使用的是 Retrofit 框架
Retrofit retrofit = new Retrofit.Builder() .baseUrl(Constant.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖) .build();
可以看到 baseUrl() 方法,里面就是固定的前缀。
那么问题就是如果让读取到gradle.properties中配置的 固定前缀呢(其实也就是租户域名) ,打包好的apk是没有gradle.properties的。
那么只有一个可能,那就是在打包时,就将 固定前缀 赋值到 Constant.BASE_URL
来看Constant类
public class Constant { public static final String BASE_URL = BuildConfig.BASE_URL; }
这个类只有一行代码,可以看到 有一个 BuildConfig 类,
这个类是哪里来的呢?我自己并没有定义过这个类
来看看这个类的定义
可以看到这类中的部分字段的值,就是之前在gradle.properties中定义的。
那么这个BuildConfig这个类是哪里来的呢?
实际上这个BuildConfig 类是自动生成的类,类似于R.class
这个类是根据build.gradle配置文件自动生成的。生成后不能修改,只能修改配置文件。
其中最重要的就是 需要修改 buildTypes 下的
buildConfigField 配置。
关于这个类,可以查看 https://www.jianshu.com/p/274c9d95cf76
总之,通过修改,我们终于可以实现定制化打包了。
现在我们的服务更加完善了,用户填写了一些基础信息并注册完成后,后台通过CI/CD 下载app源码 -> 根据用户信息修改gradle.properties文件 -> 构建生成 等一系列操作 。之后我们就会直接给用户生成定制化的app下载链接,是不是更方便了。