浅谈java SPI机制在Android 模块化开发中的应用+实例

本文主要介绍使用Java SPI(Service Provider Interface)机制帮助我们在模块化开发中自动组合我们的模块,提高开发效率。

文章后面我会介绍我是如何使用他为uniapp插件实现零配置注入模块的。

在Android日常开发中,模块化的开发已经是一件再平常不过的事情了,一个Android Gradle项目分为若干个子module,在每个module中开发独立的功能模块,在app主模块中引用这些模块,然后在打包成一个App。

这里产生了一个问题, 主module如何自动发现子模块中的服务呢? 当我们移除了一个AAR包,我们如何自动移除这个服务呢? 这里面就花样百出了,有愚蠢的(例如在主项目中维护一张配置表, 每次有修改去改这个配置表)、也有酷炫的。

例如Arouter这个开源库中,通过使用APT(annotation processor tool) 为每个模块生成了路由信息自动编译成java文件,但这种处理过程在各个module之间是相互隔离的,甚至不在同一时间发生。App模块无法得知子模块的路由表!

那么Arouter是如何做的呢? 他使用一个Gradle插件,通过Gradle的transform接口,对java字节码在打包到Dex之前进行修改,遍历每个class文件,将路由表织入到一个class文件预留的空白方法中。这种酷炫的操作虽然也能达到我们的需求,但是他为了修改一个class文件,遍历扫描了所以class文件,会严重拖慢我们的打包速度,项目越大这总影响也越大。

我曾经给Arouter提过issue(https://github.com/alibaba/ARouter/issues/716) , 但是没有被采纳。

其实这个问题,已经被前人遇到并给出了很好的解决方案。Android背靠庞大的java技术栈, 这是Andorid选择Java的一大优势。我们可以从Java开发的其他地方寻早答案。

什么是Java SPI(Service Provider Interface)

通俗的讲就是一个jar包的META-INF/services目录下,包含一个文件,文件名字是接口的全限定类名,内容是实现类的全限定类名,多个实现类用换行符分隔。

我们使用JDK提供的ServiceLoader类,通过ServiceLoader.load或者Service.providers方法拿到实现类的实例。

我们的接口定义和实现可能在不同的jar包中,实现类的jar包只需要在META-INF/services创建接口的全限定类名的文件,内容是实现类的全限定类名
,这样在运行的时候这个实现就能被应用发现并使用。

在Android中META-INF/services目录属于资源文件,打包的时候被打包到apk包的根目录下。

我们知道Android处理资源文件冲突有大致三种方式:1.报错、2.合并、3.覆盖(默认)。 不在gradle脚本中做特殊处理的情况下, 冲突的资源文件会按优先级覆盖, 而META-INF/services我们惊奇的发现他的默认行为是合并。

众所周知,一个APK或者AAR包其实也是一个Jar包,他符合Jar包的标准和规范,Android也部分遵循Jar包的打包、编译流程。这是我们能在Android中使用这种机制的前提。

应用实例

最近技术调研了uniApp,并且要为公司的App开发几个Android插件。查看官方文档,发现每开发一个插件都需要手动编辑package.json, 如果有变动还要手动去修改。这样开发太繁琐,而且容易出错,有没有方法把这些过程自动化, 这对我们之后进行CI集成也是至关重要。

为此,我开发了一个插件开发框架EZUniPlugin , 为开发uniapp或者weex插件提供自动注册的能力,同时提供uniapp文档中没有的功能拓展,简化了开发流程,为自动化、持续集成提供支持!。

解决的思路就是APT + SPI + init content provider。

  • APT

使用注解编译器将我们的插件入口类信息写入到META-INF/services中

  • SPI

在打包过程中多个插件包信息被自动合并到一个文件中

  • init content provider

注册一个 content provider 自动介入App启动过程,读取service获取插件信息,完成插件注册。

全程不需要uniapp提供任何方法,因为uniapp在Android端是基于Weex的,我们只需要实现向Weex注册我们的插件就行了。

现在,我们开发一个插件只需要导出aar包,然后扔到对应目录里,就能直接生效!

如果是开源项目还可以像我一样直接发布到Jcenter(如何发布开源项目到Jcenter),这样连包都不用拷了,只需要在配置文件中添加一个gradle依赖就行了!

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