概述
概念
马甲包:和主产品包拥有同样的内容和功能,除了icon和应用名称不能完全一致,其他基本一致。
主包:主APP
马甲包的好处:
- 占领搜索资源位,获取更多业务资源;
- 为主包引流,提高主包品牌影响力;
- 规避风险,预防万一。就像哔哩哔哩一样。哔哩哔哩刚下架了,他的马甲立马就顶上了。
存在问题
雷同问题
页面不可完全雷同,需要修改页面色调、主图、模块、样式。
长期维护
马甲是需要长期维护。如果一个马甲做得很好,那么完全可以将其独立出来作为精品马甲,其实就是独立APP,必要的时候,如果主包遭遇不测可以将马甲作为新的主包顶上。
方案
需要解决的问题
- 使用新的icon、包名、应用名
- 页面样式避免与主包完全雷同
- 尽可能更多的复用现有代码逻辑
- 后期维护起来不可成本太高
解决思路
- 应用基础信息可配置化
- 应用页面样式可动态设置
- 根据配置信息依赖指定业务组件
- 拆分壳应用与马甲包lib,创建脚本自动更新马甲包lib
实践
马甲包脚手架
脚手架
前端概念
随着前端工程化的概念越来越深入人心,脚手架的出现就是为减少重复性工作而引入的命令行工具,摆脱ctrl + c, ctrl + v,此话zenjiang? 现在新建一个前端项目,已经不是在html头部引入css,尾部引入js那么简单的事了,css都是采用Sass或则Less编写,在js中引入,然后动态构建注入到html中;除了学习基本的js,css语法和热门框架,还需要学习构建工具webpack,babel这些怎么配置,怎么起前端服务,怎么热更新;为了在编写过程中让编辑器帮我们查错以及更加规范,我们还需要引入ESlint;甚至,有些项目还需要引入单元测试(Jest)。对于一个更入门的人来说,这无疑会让人望而却步。而前端脚手架的出现,就让事情简单化。
一键命令,新建一个工程,再执行两个npm命令,跑起一个项目。在入门时,无需关注配置什么的,只需要开心的写代码;另外,对于很多系统,他们的页面相似度非常高,所以就可以基于一套模板来搭建,虽然是不同的人开发,但用脚手架来搭建,相同的项目结构与代码书写规范,是很利于项目的后期维护的;以上就是为什么脚手架存在的意义, 让项目从"搭建-开发-部署"更加快速以及规范 (出自于某乎达人)。
项目说明
只需运行命令行输入Android 基础项目信息如应用名、版本号、包名
即可收获一个可以直接运行的定制化Android项目
脚手架环境
- node: v9.2.0
命令
init | generate vest template.
- 引入inquirer.js 交互式命令行工具,定义 question
- 接收输入信息
- 拉取模板项目
- 写入输入信息
- 提示帮助
核心代码
function create() {
inquirer.prompt(questions).then(function(answers) {
let _answers = JSON.parse(JSON.stringify(answers))
let { name, version, applicationID} = _answers
const spinner = ora('downloading template'),
tmp = path.resolve(process.cwd(), name)
...
spinner.start();
if (exists(tmp)) rm(tmp);
download(`http://xxx/vest-template`, tmp, { clone: true } ,function(err) {
spinner.stop()
if (err) logger.fatal('Failed to download repo ' + TEMPLATE + ': ' + err.message.trim())
...
changeFile(tmp + '/config/vest.app.js', `${TEMPLATE}-name`, name)
...
})
});
};
使用示例
sync | sync vest project config
- 使用fs读取项目配置文件自定义信息,包括:
- 目标业务组件
- 应用样式
- 应用图标
- 三方SDK配置信息
- 写入自定义配置信息至Android项目
核心代码
let thirdSdkArr = new Array();
thirdSdkArr.push(thirdSdkPrefix)
thirdSdkArr.push("APPLICATIONID=" + vestApp.applicationId)
thirdSdkArr.push("APP_NAME=" + vestApp.appName)
thirdSdkArr.push("VERSIONNAME=" + vestApp.version)
thirdSdkArr.push("APP_FFROM=" + vestApp.ffrom)
Object.keys(compileThirdSdk).forEach(function (key) {
thirdSdkArr.push(key + "=" + compileThirdSdk[key])
});
thirdSdkArr.push(thirdSdkEndfix)
let thirdSdkStr = thirdSdkArr.join("\n");
let sdkPreIndex = propertiesContent.lastIndexOf(thirdSdkPrefix)
let sdkEndIndex = propertiesContent.lastIndexOf(thirdSdkEndfix) + thirdSdkPrefix.length - 1;
let sdkEndStr = (propertiesContent.slice(sdkEndIndex, propertiesContent.length).length !== 0 ? "\n" + propertiesContent.slice(sdkEndIndex, propertiesContent.length) : "")
fs.writeFileSync(propertiesPath, propertiesContent.slice(0, sdkPreIndex).concat(thirdSdkStr, sdkEndStr), 'utf8');
使用示例
模板项目
项目目录
实现
脚手架合并项目配置信息后写入vest.properties文件
-
编写 build.gradle 脚本
读取vest.properties
-
写入配置信息至buildConfigField中
new HashMap<String, String>((Map) vestProperties).each { buildConfigField "String",it.key, "\"${it.value}\"" }
-
写入配置信息至manifestPlaceholders中
manifestPlaceholders = new HashMap<String, String>((Map) vestProperties)
脚手架读取vest.modules.js,写入modules.json文件至Android 项目下的app/src/main/assets目录下
-
应用开启时,读取assets目录下modules.json文件,序列化为实例对象
fun init(context: Context) { val assertsFile = getAssertsFile(context, "modules.json") if (assertsFile == null) { LogUtil.e("请先运行 vest sync 命令初始化配置文件") return } val configJson = String(assertsFile) if (TextUtils.isEmpty(configJson)) { LogUtil.e("请先运行 vest sync 命令初始化配置文件") return } modulesConfigBean = GsonProvider.getGson().fromJson(configJson, ModulesConfigBean::class.java) }
使用配置信息实例对象初始化应用
总结
本马甲包自动组装方案使用配置文件和脚手架相配合,屏蔽Android项目信息,使其在使用时只需配置完成后运行脚手架命令就可得到定制化的Android项目。
后期添加管理后台,部署至服务器上后开发阶段可以完全不需要Android开发人员介入,只需定期更新版本。
极大减少Android开发工程师工作量,降低应用开发成本,解决了后期迭代更新不及时的问题。