Android動態載入架構DL的架構與基本原理解析

來源:互聯網
上載者:User

標籤:android   動態載入   外掛程式化   架構   

     轉載請註明出處,本文來自【 Mr.Simple的部落格 】。

我正在參加部落格之星,點擊這裡投我一票吧,謝謝~   前言

最近這一兩年,Android App使用外掛程式化技術開發的數量越來越大,其實還是業務地快速膨脹導致,需求越來越多,App越來越臃腫。雖然手機的記憶體空間不斷地的增大,但是太大的安裝包給使用者也造成了心理壓力。於是大家都會想到外掛程式化的開發方式,把App做成一個平台,而不是一個獨立的app。平台上可以整合各種各樣的功能,功能模組也外掛程式的形式添加進來,這些外掛程式不需要安裝,只需要使用者按需下載到某個位置,然後使用的時候動態載入進來。

 想法都是好的,但是想實現一個相對比較穩定的動態載入架構還是有點難度的,一些大公司都有成熟的動態載入架構,但是他們並沒有開源出來。好在2014年知名CSDN博主任玉剛開源了一款名為DL的Android動態載入架構,該架構簡單、開源、相容性都較為好,如果有需要使用外掛程式化開發的朋友可以嘗試該架構,另外對該開源項目感興趣的朋友也可以貢獻自己的代碼,地址會在文章最後給出。

對於DL的基本情況和使用,本人就不再贅述,作者本人和參與開發的朋友已經有一些較好的文章,詳情請參考,APK動態載入架構(DL)解析、DL動態載入架構技術文檔、Android 使用動態載入架構DL進行外掛程式化開發。在這裡我就簡單介紹一下DL的基本結構與原理,希望能夠一些需要的朋友提供一些有用的資訊。


基本架構

對於Android的動態載入架構來說最重要和最麻煩的點可能基本上有兩個,第一是apk如何在不安裝的情況下運行起來,並且Activity基本的聲明周期能夠正常調用;第二就是Activity內部能夠以R的形式訪問資源檔。關於載入未安裝的apk和Android的資源載入機制請參考如下兩篇文章,Android動態載入jar、apk的實現、Android源碼分析-資源載入機制。我們針對這兩個問題依次給出DL的解決方案。

載入未安裝apk相對比較簡單,就是通過DexClassLoader將apk檔案載入到虛擬機器中,具體可以參考上文給出的文章。這裡我們主要說一下調用Activity生命週期函數的實現。在DL中,有兩個Proxy類,分別為DLProxyActivity、DLProxyFragmentActivity,這兩個類型分別繼承自Activity和FragmentActivity,他們分別代理整合自DLBasePluginActivity和DLBasePluginFragmentActivity的外掛程式Activity類,DLBasePluginActivity和DLBasePluginFragmentActivity又分別繼承自Activity和FragmentActivity,我去!這個時候是不是有點亂了?且聽我慢慢道來~

按照DL的開發規範,你外掛程式的Activity需要繼承自DLBasePluginActivity或者DLBasePluginFragmentActivity,這兩個類中封裝了一些基本的調用邏輯。這裡我們先暫時不用過多理會,重點是看DLProxyActivity、DLProxyFragmentActivity。DL的機制是這樣的,真正在DL通過Intent啟動的Activity只能是DLProxyActivity、DLProxyFragmentActivity,這兩個Activity是在宿主apk中註冊了的,因此能夠直接通過Intent來啟動。而在兩個Proxy實際上只是一個軀殼,他們會自己的生命週期函數中調用外掛程式Activity對應的生命週期函數。這是就引入了一個關鍵的類,DLProxyImpl,這個類負責解析外掛程式apk的資源、ClassLoader、通過反射載入外掛程式Activity,DLProxyImpl載入了外掛程式Activity之後又會調用Proxy Activity的attach方法將外掛程式Activity執行個體傳遞給Proxy Activity,這樣Proxy Activity就得到了外掛程式Activity的執行個體,然後就能在自己的聲明周期函數中調用外掛程式Activity對應的函數。

DLProxyImpl的launchTargetActivity函數:

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)    protected void launchTargetActivity() {        try {            // mClass就是目標外掛程式Activity的類名            Class<?> localClass = getClassLoader().loadClass(mClass);            Constructor<?> localConstructor = localClass.getConstructor(new Class[] {});            // 通過反射構建外掛程式Activity            Object instance = localConstructor.newInstance(new Object[] {});            mPluginActivity = (DLPlugin) instance;            // 將外掛程式Activity注入給Proxy Activity            ((DLAttachable) mProxyActivity).attach(mPluginActivity, mPluginManager);            // 外掛程式activity也擷取到Proxy的引用            mPluginActivity.attach(mProxyActivity, mPluginPackage);            Bundle bundle = new Bundle();            bundle.putInt(DLConstants.FROM, DLConstants.FROM_EXTERNAL);            // 調用外掛程式Activity的onCreate函數,啟動外掛程式Activity            mPluginActivity.onCreate(bundle);        } catch (Exception e) {            e.printStackTrace();        }    }

宿主在載入外掛程式apk時會解析該apk的相關資訊,比如它的預設啟動的Activity,上述形式將apk運行起來,那麼在外掛程式apk中的activity跳轉則需要通過DLIntent類將目標activity的包名、類名傳遞給DL架構,DL內部會進行解析以及相應的載入邏輯。


DLProxyActivity核心代碼: 

public class DLProxyActivity extends Activity implements DLAttachable {    // 外掛程式Activity    protected DLPlugin mRemoteActivity;    // DLProxyImpl載入外掛程式Activity和資源等    private DLProxyImpl impl = new DLProxyImpl(this);    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // Proxy onCreate的時候調用DLProxyImpl的onCreate,載入外掛程式Activity        impl.onCreate(getIntent());    }    // 載入完外掛程式Activity後將外掛程式Activity傳遞給Proxy Activity    @Override    public void attach(DLPlugin remoteActivity, DLPluginManager pluginManager) {        mRemoteActivity = remoteActivity;    }    // 擷取資源,DLProxyImpl載入了外掛程式apk的資源,通過這裡代理資源操作,這樣外掛程式Activity內部就可以通過R訪問資源檔了    @Override    public Resources getResources() {        return impl.getResources() == null ? super.getResources() : impl.getResources();    }    /***********************  以下都是代理外掛程式Activity的生命週期函數  ***********************/    @Override    protected void onStart() {        mRemoteActivity.onStart();        super.onStart();    }    @Override    protected void onRestart() {        mRemoteActivity.onRestart();        super.onRestart();    }    @Override    protected void onResume() {        mRemoteActivity.onResume();        super.onResume();    }    @Override    protected void onPause() {        mRemoteActivity.onPause();        super.onPause();    }    @Override    protected void onStop() {        mRemoteActivity.onStop();        super.onStop();    }    @Override    protected void onDestroy() {        mRemoteActivity.onDestroy();        super.onDestroy();    }    // 代碼省略}

下面我們來看另外一個重點,也就是外掛程式apk的資源載入。關於apk的資源載入機制也請參考上面給出的文章,我們直接看代碼。

    private DexClassLoader createDexClassLoader(String dexPath) {        File dexOutputDir = mContext.getDir("dex", Context.MODE_PRIVATE);        dexOutputPath = dexOutputDir.getAbsolutePath();        // 建立ClassLoader        DexClassLoader loader = new DexClassLoader(dexPath, dexOutputPath, mNativeLibDir,                mContext.getClassLoader());        return loader;    }    // 根據外掛程式apk的路徑構建AssetManager,將其資源所在的路徑添加到AssetManager中,然後通過AssetManager構建一個Resources對象,這個對象就是外掛程式apk的資來源物件,外掛程式apk內部訪問資源時都是通過這個資來源物件    private AssetManager createAssetManager(String dexPath) {        try {            AssetManager assetManager = AssetManager.class.newInstance();            Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);            addAssetPath.invoke(assetManager, dexPath);            return assetManager;        } catch (Exception e) {            e.printStackTrace();            return null;        }    }    private Resources createResources(AssetManager assetManager) {        Resources superRes = mContext.getResources();        Resources resources = new Resources(assetManager, superRes.getDisplayMetrics(),                superRes.getConfiguration());        return resources;    }

這樣,等於是外掛程式Activity的生命週期交給了Proxy Activity代理,而外掛程式的Activity的啟動和資源訪問則交給了DLProxyImpl代理。這樣,通過兩個代理就啟動了外掛程式Activity,並且資源訪問問題也得到瞭解決。

最後我們通過一張圖來看DL的基本結構。

DLPluginManager載入、管理外掛程式包,DLIntent是外掛程式之間跳轉的資訊載體。Base Plugin Activity是外掛程式Activity的基類,封裝代理操作。Proxy Activity代理外掛程式Activity的生命週期函數,也是外掛程式Activity的外殼。DLProxy負責載入外掛程式Activity以及資源操作。這麼一來,整個動態載入架構就運行起來了,更多的細節有興趣的朋友自己去看源碼吧。


後期特性

1. 支援service、靜態廣播、ContentProvider

bug

1. 外掛程式透明主題的支援

2. 完整activity api的重寫


最後給出DL架構github地址,希望更多的人蔘與到DL架構的開發中來。


我正在參加部落格之星,點擊這裡投我一票吧,謝謝~   


Android動態載入架構DL的架構與基本原理解析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.