插件化概念
個人總結(jié)為:它是由宿主和插件應(yīng)用結(jié)合而成,兩者遵守一些標(biāo)準(zhǔn)規(guī)范的情況下昔榴,插件無需安裝辛藻,即可按需加載使用!
插件化優(yōu)點
- 宿主和插件分開編譯
- 并發(fā)進(jìn)行開發(fā)
- 動態(tài)更新插件
- 按需下載模塊
- 方法數(shù)和變量數(shù) 65536問題
插件化步驟
- 插件化分為宿主應(yīng)用和插件應(yīng)用
- 新建Project - 也就是宿主應(yīng)用
- 新建一個Module互订,具有生命周期接口吱肌,宿主跳插件應(yīng)用需要遵守一些標(biāo)準(zhǔn)規(guī)范
- 新建Table Module - 也就是插件應(yīng)用,同時在BaseActivity里面實現(xiàn)生命周期接口
- Module通過attach方法注入上下文context仰禽,因為插件apk未安裝氮墨,所以不能直接使用插件的上下文
- 插件里面重寫setContextView(),getWindowManger,getClassLoader這些需要使用上下文的方法纺蛆,然后使用注入的that進(jìn)行替換super調(diào)用
- 在宿主app里面創(chuàng)建ProxyActivity,通過插樁的方式進(jìn)行注冊插件的Activity规揪。ProxyActivity里面獲取跳轉(zhuǎn)傳入的className,同時重寫getClassLoader和getResource的方法桥氏,替換為PluginManager創(chuàng)建的ClassLoader和Resource
- 創(chuàng)建PluginManager,單例的形式創(chuàng)建,實現(xiàn)loadPath方法,去加載apk(DexClassLoader)猛铅。因為 未安裝就不能通過getClassLoader的方式Class.forName這樣的方式了
- 加載未安裝apk(DexClassLoader)
- 插件二級Activity的地方回傳到宿主APP里面字支,BaseActivity里面startActivity
主要代碼有:
1、初始化插件的ClassLoader奕坟,插件的主Activity祥款,插件的Resources
object PluginManager {
private lateinit var dexClassLoader:DexClassLoader
private lateinit var resource:Resources
private var entryActivityName:String = ""
fun loadPath(context:Context,path: String){
//獲取插件的ClassLoader
val dexOutFile = context.getDir("dex",Context.MODE_PRIVATE)
dexClassLoader = DexClassLoader(path,dexOutFile.absolutePath,null,context.classLoader)
//插件的第一個Activity
val packageManager = context.packageManager
val packageInfo = packageManager.getPackageArchiveInfo(path,PackageManager.GET_ACTIVITIES)
entryActivityName = packageInfo.activities[0].name
//實例化Resource
val assetManager = AssetManager::class.java.newInstance()
AssetManager::class.java.getDeclaredMethod("addAssetPath",String::class.java).invoke(assetManager,path)
resource = Resources(assetManager,context.resources.displayMetrics,context.resources.configuration)
}
fun getClassLoader() = dexClassLoader
fun getResource() = resource
fun getEntryActivityName() = entryActivityName
}
2、插樁的形式創(chuàng)建ProxyActivity
class ProxyActivity : Activity() {
private var className: String? = null
private var aliPayInterface: IAliPay? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
className = intent.getStringExtra("className")
try {
val activityClass = classLoader.loadClass(className)
val constructor = activityClass.getConstructor(*arrayOf())
val instance = constructor.newInstance(*arrayOf())
aliPayInterface = instance as IAliPay
aliPayInterface!!.attach(this)
val bundle = Bundle()
aliPayInterface!!.onCreate(bundle)
} catch (e: ClassNotFoundException) {
e.printStackTrace()
} catch (e: NoSuchMethodException) {
e.printStackTrace()
} catch (e: SecurityException) {
e.printStackTrace()
} catch (e: InstantiationException) {
e.printStackTrace()
} catch (e: IllegalAccessException) {
e.printStackTrace()
} catch (e: InvocationTargetException) {
e.printStackTrace()
}
}
override fun onStart() {
super.onStart()
aliPayInterface!!.onStart()
}
override fun onResume() {
super.onResume()
aliPayInterface!!.onResume()
}
override fun onPause() {
super.onPause()
aliPayInterface!!.onPause()
}
override fun onStop() {
super.onStop()
aliPayInterface!!.onStop()
}
override fun onDestroy() {
super.onDestroy()
aliPayInterface!!.onDestroy()
}
override fun getClassLoader(): ClassLoader {
return PluginManager.getClassLoader()
}
override fun getResources(): Resources {
return PluginManager.getResource()
}
override fun startActivity(intent: Intent) {
val classNameFromTaoPiaoPiao = intent.getStringExtra("className")
val newIntent = Intent(this, ProxyActivity::class.java)
newIntent.putExtra("className", classNameFromTaoPiaoPiao)
startActivity(newIntent)
}
}
通過插件的classLoader
和傳入的className
獲取到約定規(guī)范的AliPay
接口月杉,然后調(diào)用插件里面主Activity
的生命周期刃跛,同時重寫ProxyActivity
的跳轉(zhuǎn),從而實現(xiàn)插件的二級頁面的跳轉(zhuǎn)苛萎。
詳細(xì)Demo查看Github-GoachAlipay