写点什么

网易 Android 工程模板化实践

2016 年 11 月 20 日

背景

我们网易前端技术部 - 移动技术组作为公司的移动端基础技术部门,主要为其他部门提供解决方案、技术支持和产品孵化。在几年的积累过程中,我们拥有一些自己的框架和 SDK,如轻应用框架、热更新 SDK、网络请求库、本地存储库、页面管理等,服务过网易新闻、云音乐、考拉、易信等亿级产品,先后孵化过青果摄像头、二次元 Gacha、严选等重要产品。

在多年的 Android 开发中,对于 Android 端产品开发,我们有如下几点体会:

  1. 产品孵化排期紧张

产品经理一般关心的是具体的业务逻辑,而前期基础模块的搭建,如各模块如何组织,使用代码结构如何选择,图片、网络、本地存储等选用哪个 sdk 等,一般不会有专门排期。
2. 基础模块的需求具有相似性

内容型产品,其搭建的基础模块基本上都会包含图片显示、网络请求、本地存储、通信等。
3. 基础模块的选型和工具类具有可重用性

网上相关的第三方库有很多,当然一般的公司也是会有自己开发或者维护的各个基础 SDK。很多时候,SDK 选型会更偏向于自己公司开发维护的 SDK,或者选择自己最熟悉,或最主流、最可靠的 SDK。因此当开发多个相同类型产品时,这里的技术选型是可重用的。
4. 网络请求的代码具有机械性

客户端开发需要根据网络接口协议,编写相关的 GET、POST 等请求代码和对应的 JavaBean,这部分的代码编写其实是非常机械的。

网易工程模板是什么?

对于各个基础模块,我们团队封装了自己的 SDK,如网络库、本地存储库、页面管理库、图片库等。使用我们的工程模板生成的初始工程,就已经包含了我们提供的基础模块,产品团队的开发不需要再花费重复的时间做技术调研、选型、SDK 封装集成等工作,而只需要关心自己的业务逻辑编写。我们期望产品团队只需 1 分钟就能得到自己的初始工程,并能马上投入业务逻辑开发,既能缩短开发周期,也能保证工程代码质量。

此外,我们也提供了 Android Studio 插件 (NEIPlugin),集成插件后,就能在 Android Studio 中通过菜单点击自动下载集成我们的工程模板,也能自动生成网络请求相关的代码。

(点击放大图像)

代码生成结果示例

Android 模板工程实现

最初我们使用终端脚本命令的方式,通过文件拷贝和文本查找替换(主要是替换包名等)的方式实现。但终归对 Android 开发人员不太友好,毕竟大家更习惯使用 Android Studio 生成工程。所幸,强大的 Android Studio 已经提供了较为全面的模板功能,这里大概可以分为以下几类:

  • 工程模板 (本文内容)
  • 文件模板
  • 注释模板
  • 编码模板 (Living Template)

Android 工程模板基础知识

工程模板实例介绍

对于 Android Studio,模板位置:

Windows 的路径在 ${android studio 安装路径}/plugins/android/lib/templates/

MacOS 的路径在 ${Android Studio.app 存放路径}/Contents/plugins/android/lib/templates/

有关模板的文件夹:

  1. activities:工程模板相关,如 EmptyActivity 文件夹用于创建一个空页面的模板,GoogleMapsActivity 文件夹对应创建一个地图页面的模板等
  2. gradle:放置了 gradle 模板,用于在新建工程的根目录下生成 gradle 文件夹,支持用户不用安装 gradle 就能使用 gradlew 命令
  3. gradle-project:工程模板相关,用于构建 module,Android Project,Java Library 等
  4. other:构建文件模板等

这里我们关心的是 activities 文件夹里面的内容

首先查看下 EmtpyActivity (空白页面模板) 里面的内容

  1. globals.xml.ftl: 全局变量文件,保存一些全局变量,当中可以引用其他文件的全局变量
  2. recipe.xml.ftl: 配置要引用的模板路径以及文件的生成规则
  3. template.xml: 模板的配置信息,包括模板的显示图标,界面的表现,全局变量文件和执行文件的指定等

(点击放大图像)

Android Studio 使用的是 FreeMarker 模板引擎,所以文件后缀都是 .ftl

常用标签使用

  • ${}: FreeMarker 的语法,如 ${packageName}, ${superClass} 是 globals.xml.ftl 全局变量文件或 template.xml.ftl 中定义变量引用

  • <#if></#if>: FreeMarker 的语法,条件判断语句

  • <#include>: FreeMarker 的语法,包含语句

  • copy: 将文件或者文件夹从 from 标签拷贝到 to 标签指定的路径

  • instantiate: 将文件或者文件夹,执行 FreeMarker 语法,从 from 标签实例化到 to 标签指定的路径

  • merge: 合并 from 和 to 标签分别指定的文件

  • open: 在工程打开后,默认打开指定的文件

    实例:使用空白页面模板生成工程并打开后,可以看到默认打开了 MainActivity.java 和 activity_main.xml 文件

工程模板创建

新建 HTTemplate 文件夹内容如下:

  1. template.xml

指定模板名、描述、最低支持 sdk 版本、类别等,输入界面要求指定包名和 Application 类名
2. globals.xml.ftl

引用公共文件内容
3. recipe.xml.ftl

  • merge AndroidManifest.xml 文件
  • copy 或者 merge 资源文件
  • copy 或 instantiate java 代码
  • merge build.gradle 文件
  • merge settings.gradle 文件
  • copy lib 文件夹里面的全部内容
  • copy module 工程
  • copy proguard-rules.pro 文件
  1. root 文件夹

放置相关模板源文件,其中将源工程中依赖于配置的代码,按照 FreeMarker 语法进行替换
5. 添加工程模板图标,并在 template.xml 中添加引用

(点击放大图像)

settings.gradle 合并

查看 RecipeMergeUtils.mergeGradleSettingsFile 方法,基本逻辑如下:

  • 读取目标文件的每一行内容,并判断每行内容的开头是否是 include 开头

    • 是:在 include 后面插入内容
    • 否:抛出异常
  • 返回合并的内容

build.gradle 合并

查看 GradleFileMerger.mergeGradleFiles 方法,里面会调用 mergePsi 方法,其基本逻辑如下:

  • 读取文件 source 和 dest 文件的内容,并转化得到 GroovyFile 类型对象
  • 执行 mergePsi 方法

这里 mergePsi 执行合并的逻辑是

(点击放大图像)

小结和后续工作

到此,基本上完成了我们原先期望实现的工程模板和网络请求代码自动生成的工作:

  1. 提供 ht-template 支持生成我们的模板工程
  2. 提供 Android Studio 插件 (NEIPlugin)
  • 支持 ht-template 的下载安装
  • nei-toolkit 和 Node.js 的下载安装
  • nei-toolkit 和 Node.js 的使用,生成网络请求代码

这里还是有一些因为 Android 工程模板自身的限制而无法完成的内容点:

  1. 无法在 settings.gradle 指定 module 路径
  2. 无法合并 proguard-rules.pro 文件,暂时生成 proguard-rules.pro.template 文件
  3. 由于 build.gradle 对 apply 命令合并会出错和无法合并 dependencies 中的 apt 命令,所以无法在 build.gradle 中集成 ht-universalrouter

再次,除了网络请求代码编写是机械性的,其他的基于我们的工程模板生成的初始工程,也存在一定的代码编写机械性:初始页面代码生成、RecycleView 中的各个 ViewHolder 类、本地数据读取保存等,而这些工作将会是我们的后续工作。

标题

Q:本次的分享是不是需要有 idea 的插件化知识背景?

A:idea 插件开发的内容,可以查看官方文档 http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/setting_up_environment.html ,里面有比较详细的介绍。

如果需要自己学习插件开发的话,就需要学习官方文档,不过我的分享中并没有讲述插件开发中的一些细节,应该不会有影响。

这次大家如果觉得听起来有点难,我想应该是这次分享需要有工程模板开发的背景,不然确实会有点难。

推荐下这篇文章,可以入门下工程模板开发的内容:

Mobile App Development: Tutorial How To Create Custom Android Code Templates

Q:请问 neitoolkit 是做什么的?

A:neitoolkit 在移动端,是一个配合我们的 NEI 接口管理平台( http://nei.hz.netease.com/ ),用来生成网络请求相关代码的一个工具,当然可以查看 README 介绍

  • 支持根据 NEI 平台 定制生成项目初始结构及代码
  • 支持 NEJ 发布工具 配置文件自动生成
  • 支持 Fiddler 和 Charles 工具代理本地模拟数据,接口配置文件导出
  • 支持自动生成移动端数据模型、请求类代码
  • 支持自动导出模拟数据
  • 集成了本地模拟容器

Q:请问上文的 runtime 怎么理解呀?

A:这里的 Runtime,其实就是执行了 java 中的 Runtime.getRuntime().exec(command); 方法。

这个方法的作用就是执行 sh (windows 中 cmd) 中的脚本命令。

Q:如果模版中有需要 apt 处理的代码,模版是不支持的是么?

A:恩,工程模板是不支持的,dependencies 中 非 compile 命令全部都是不支持的,这个可以从前面的源码分析中看出来。

嘉宾介绍

张云龙,网易 Android 开发工程师,就职于杭研前端技术部移动技术组。曾负责网易严选、二次元 Gacha、校园部落 Android 端;是网易移动端标准化项目、动态化框架和青果摄像头主开发,网易微专业讲师。


感谢徐川对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2016 年 11 月 20 日 16:235269

评论

发布
暂无评论
发现更多内容

智能云网:从时代所需,到运营商所向

脑极体

AI数学基础之:奇异值和奇异值分解

程序那些事

人工智能 机器学习 程序那些事 矩阵运算

使用 Tye 辅助开发 k8s 应用竟如此简单(五)

newbe36524

微服务 netcore 全链路追踪 dotnet dapr

改变认知,到写作方式的改变

数列科技杨德华

28天写作

面试中经常问到的动态代理到底是什么

废材姑娘

Java

地表建筑物识别 Dayo2

Tango

七日更 28天写作 2月春节不断更

「极客时间」课程购买用例

西西里奇

树莓派语音控制的一次小尝试

水战龟

树莓派

极客大学·产品经理训练营·第四章作业(第五周)

二大爷

极客大学产品经理训练营

内娱完蛋了?不如让5G“出道”来抢救一下

脑极体

Linux c 开发 - 内存管理器ptmalloc

赖猫

Linux 后台开发 内存管理

作业5

瑾瑾呀

悟透前端 | javascript数组之includes、reduce

devpoint

ES6 includes reduce

Elasticsearch Validate API

escray

elastic 七日更 28天写作 死磕Elasticsearch 60天通过Elastic认证考试 二月春节不断更

【编程小白福利】办公自动化--从VBA到Python

Tango

七日更 28天写作 2月 办公自动化 IT蜗壳

gRPC库C++构建及示例

长不胖的Garfield

c++ gRPC

深度集成 Flink: Apache Iceberg 0.11.0 最新功能解读

DataFunTalk

产品经理训练营-第五周作业

月亮 😝

2021金三银四必备:Java后端开发面试总结【25个技术专题】

比伯

Java 编程 架构 面试 计算机

翻译:《实用的Python编程》02_04_Sequences

codists

Python 人工智能 面试 数据结构与算法 序列

流程图

王一凡

处理 Exception 的几种实践,很优雅,被很多团队采纳!

xcbeyond

Java 异常处理 28天写作

产品经理训练营 - 第五次作业

Jophie

产品经理训练营

产品训练营作业:流程图

Geek_06d2e5

框架效应如何影响人的决策?「Day 4」

道伟

心理 决策 28天写作

「产品经理训练营」第五周 作业记录

玲玲

Java 训练营第一周习题:02 加载字节码文件

现实中游走

Java

一名青少年创客导师

厌倦你

编程

【计算机内功修炼】九:程序员应如何理解协程

码农的荒岛求生

线程 操作系统 进程 协程

产品经理训练营-第五周学习总结

月亮 😝

28天瞎写的第二百四十二天:正念冥想,我要想什么?

树上

冥想 28天写作 正念

4月17日 HarmonyOS 开发者日·上海站

4月17日 HarmonyOS 开发者日·上海站

网易 Android工程模板化实践-InfoQ