咱們在組件化的過程,業務被拆分至獨立的Module中,一些公用組件會在各個Module中經過APT生成一些須要被註冊至組件中的信息類,好比EventBus生成的Index類。咱們這邊RN定製的Plugin是跟隨各自module,須要被註冊。還有,各Module對外提供的api接口的話,也須要被註冊。android
另外,有些組件爲某些Module特有,須要在App啓動的時候就要初始化,有些須要在主線程中初始化,有些爲不阻塞主線程能夠在非主線程中初始化。git
在組件化以前,咱們是在Main Module經過硬編碼來進行註冊,在Application中堆積各個組件的初始化邏輯。github
有沒有更好的解決方式?api
首先,將問題分解抽象:app
A a = new A() B b = new B() b.shoot(a.get()) A爲Module定義的一個類,經過get方法能夠得到被註冊的信息,B爲組件定義的一個類,在shoot方法中實現註冊邏輯。
AB組合意味着須要代碼注入,代碼注入使用的技術方案是Gradle Transform + ASM。AB分別實現約定的接口,再用註解標記。在編譯時,經過Gradle Transform + ASM,經過註解找到AB,生成上述格式的代碼並注入到合適的位置。ide
採用的方式是預先定義一個空方法,經過註解標記,並在適當時機調用這個空方法。在編譯時經過註解找到AB和空方法,生成上述格式的代碼並注入到這個空方法中。函數
以上是有關組件註冊方面的解決思路,而模塊中的組件初始化有點不一樣,由於其不須要入參。 但能夠直接在方法函數中實現初始化邏輯,好比:組件化
A a = new A() a.shoot() 模塊定義一個類A,實現約定的接口,在shoot方法中作實現初始化邏輯。
其他和組件註冊方式相相似,主要在注入的代碼邏輯上有所不一樣。gradle
具體的實現方式實際上是借鑑了弓箭耙的模式。ui
弓箭耙模式:
提供模塊相關類(須要被註冊的信息)的載體。
方法函數,即實現註冊邏輯的載體。
將被注入的空方法。
在根項目的build.gradle中添加插件依賴:
buildscript { ... dependencies { ... classpath 'com.eastwood.tools.plugins:auto-inject:1.0.0' } }
在模塊的build.gradle中添加註解庫依賴:
dependencies { ... implementation 'com.eastwood.common:auto-inject:1.0.0' }
在主模塊的build.gradle中引用插件:
apply plugin: 'auto-inject' autoInject { showLog = true ignorePackages = ['android', 'com/google'] }
預先定義一個空方法並調用,在方法上標記@AutoTarget,例如:
public class App extends Application { public EventBusBuilder eventBusBuilder; @Override public void onCreate() { super.onCreate(); eventBusBuilder = EventBus.builder(); // add config to eventBusBuilder addIndex2EventBus(); eventBusBuilder.build(); } @AutoTarget void addIndex2EventBus() {} }
addIndex2EventBus
方法將被注入代碼。
新建一個類,並實現IAutoArrow接口,在get方法中返回須要被註冊的信息類。例如:
@AutoArrow(model = "eventBusIndex") public class ModuleBAutoArrow implements IAutoArrow<SubscriberInfoIndex> { @Override public SubscriberInfoIndex get() { return new ModuleBEventBusIndex(); } }
新建一個類,並實現IAutoBow接口,在shoot方法中獲取入參並執行具體的註冊邏輯。例如:
@AutoBow(target = "addIndex2EventBus", model = "eventBusIndex", context = true) public class EventBusAutoBow implements IAutoBow<SubscriberInfoIndex> { private App app; EventBusAutoBow(Application application) { app = (App) application; } @Override public void shoot(SubscriberInfoIndex index) { app.eventBusBuilder.addIndex(index); } }
其中 context
用於聲明EventBusAutoBow被實例化時是否須要上下文,這個上下文是被@AutoTarget
標記的方法在運行時的上下文。爲 true
時,該類需定義一個以上下文作爲惟一入參的構造函數。
新建一個類,並實現IAutoBowArrow接口,在shoot方法中執行相關邏輯。
@AutoBowArrow(target = "init") public class InitAutoBowArrow implements IAutoBowArrow { @Override public void shoot() { // ... } }
打包成apk後,@AutoTarget標記的方法將會被注入具備固定結構的代碼,例如:
// @AutoArrow + @AutoBow + @AutoTarget 組合 @AutoTarget void addIndex2EventBus() { ModuleBAutoArrow moduleBAutoArrow = new ModuleBAutoArrow(); EventBusAutoBow eventBusAutoBow = new EventBusAutoBow(this); eventBusAutoBow.shoot(moduleBAutoArrow.get()); ... eventBusAutoBow.shoot(***.get()); } // @AutoBowArrow + @AutoTarget 組合 @AutoTarget void init() { InitAutoBowArrow initAutoBowArrow = new InitAutoBowArrow(); initAutoBowArrow.shoot(); ... }
本文並無詳細深刻解釋Gradle Transform + ASM如何查找到類和方法並注入,源碼已上傳至github,方便自行研究。
github地址:https://github.com/EastWoodYang/AutoInject