從ClassLoader到Android插件化以及熱更新原理

ClassLoader

關於ClassLoader,一看你就懂,超詳細java中的ClassLoader詳解,android的Classloader有些不一樣Android插件化開發之動態加載基礎之ClassLoader工做機制前端

Android插件化

最經換了工做,公司的項目比較龐大,不少地方都運用了插件化,插件化說簡單就是把部分功能進行打包成專門的apk、dex等文件,當宿主app須要用到此功能的時候纔去加載插件;插件不只能夠實現一些功能的熱插拔;以及不須要去安裝app,只是在使用到的狀況下再去下載,這樣就減少宿主的apk的體積;還能夠去經過更新插件來完成功能的更新。插件化技術已經比較成熟了,不少大公司的產品也都是使用插件化開發,也有不少比較成熟的插件化框架,例如DynamicAPK、RePlugin 、Small等等java

插件化的原理

android裏面有PathClassLoader以及DexClassLoader:android

  • PathClassLoader用於加載data/app下的dex、apk、class文件,這個目錄就對應了咱們安裝的一些應用
  • DexClassLoader能夠用來加載外部的一些dex、apk、class文件

咱們能夠加載其餘地方的dex、apk文件了,並使用相應的class文件數組

咱們還須要獲取資源文件微信

//建立AssetManager對象 
AssetManager assets = new AssetManager();
 //將apk路徑添加到AssetManager中
  if (assets.addAssetPath(resDir) == 0){              
    return null;  
}
 //建立Resource對象

r = new Resources(assets, metrics, getConfiguration(), compInfo);
複製代碼

只要將插件apk的路徑加入到AssetManager中,便可以實現對插件資源的訪問。app

具體實現時,因爲AssetManager並非一個public的類,須要經過反射去建立,而且部分Rom對建立的Resource類進行了修改,因此須要考慮不一樣Rom的兼容性。框架

還有一個問題就是插件的activity沒有進行註冊,咱們在宿主中註冊一個空的Activity,專門用來加載插件app中的activity,這個Activity叫ProxyActivity。咱們還須要配置一下ProxyActivityide

class ProxyActivity : AppCompatActivity() {

    /**
     * 要跳轉的activity的name
     */
    private var className = ""
    private var appInterface: AppInterface? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        /**
         * step1:獲得插件app的activity的className
         */
        className = intent.getStringExtra("className")
        /**
         * step2:經過反射拿到class,
         * 但不能用如下方式
         * classLoader.loadClass(className)
         * Class.forName(className)
         * 由於插件app沒有被安裝!
         * 這裏咱們調用咱們重寫過多classLoader
         */
        var activityClass = classLoader.loadClass(className)
        var constructor = activityClass.getConstructor()
        var instance = constructor.newInstance()

        appInterface = instance as?AppInterface
        appInterface?.attach(this)
        var bundle = Bundle()
        appInterface?.onCreate(bundle)

    }

    override fun onStart() {
        super.onStart()
        appInterface?.onStart()
    }

    override fun onResume() {
        super.onResume()
        appInterface?.onResume()
    }

    override fun onDestroy() {
        super.onDestroy()
        appInterface?.onDestroy()
    }

    override fun getClassLoader(): ClassLoader {
        //不用系統的ClassLoader,用dexClassLoader加載
        return PluginManager.getInstance().getDexClassLoader() as? ClassLoader
                ?: super.getClassLoader()
    }

    override fun getResources(): Resources {
        //不用系統的resources,本身實現一個resources
        return PluginManager.getInstance().getResources() ?: super.getResources()
    }
}
複製代碼

還有在使用context的時候,須要使用ProxyActivity的context,由於插件沒有上下文,須要依賴宿主的上下文源碼分析

Android熱更新

熱修復也是比較熱門的技術,熱修復的框架也是有不少,阿里AndFix(native解決方案,不須要冷啓動)、QQ空間(Dex分包方案)、美團Robust (Instant Run 熱插拔原理)、微信Tinker,這些框架的原理各有不一樣。tinker就是經過ClassLoader來實現熱修復的原理。this

QQ空間超級補丁,「超級補丁」不少狀況下意味着補丁文件很大,而將這樣一個大文件夾加載在內存中構建一個Element對象,插入到數組最前端是須要耗費時間的,無疑會印象應用啓動的速度。所以Tinker 提出了另一種思路,Tinker的思路是這樣的,經過修復好的class.dex 和原有的class.dex比較差生差量包補丁文件patch.dex,在手機上這個patch.dex又會和原有的class.dex 合併生成新的文件fix_class.dex,用這個新的fix_class.dex 總體替換原有的dexPathList的中的內容,能夠說是從根本上把bug給幹掉了。有興趣的同窗能夠看看鴻翔的這篇分析Android 熱修復 Tinker 源碼分析之DexDiff / DexPatch

相關文章
相關標籤/搜索