YDL Android 组件化实践与拓展(3) - 马甲包自动化组装解决方案

概述

概念

马甲包:和主产品包拥有同样的内容和功能,除了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)
          ...
        })
    });
};

使用示例

image

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');

使用示例

sync 使用示例

模板项目

项目目录

image

实现

  • 脚手架合并项目配置信息后写入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开发工程师工作量,降低应用开发成本,解决了后期迭代更新不及时的问题。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容