(2)Android插件化編程思想

本篇博客是學習《Android插件化開發指南》的一個總結

1. 插件化的優勢

a> 快速修復應用中的bug,不需要重新發版本

b> 快速響應需求,能夠將應用業務的變化動態的發佈給用戶

其實以上的兩個優點也可以總結成一個,就是用戶重新不要重新下載安裝APK,就可以更新APK的功能。

2. 插件化編程需要了解和掌握的知識

   a>對Android的框架知識需要有一定的瞭解。因爲在編寫應用 的過程中我們可以需要在應用運行的過程中在原生的邏輯之上增加我們自己的邏輯,或者繞過Android原生的某些限制,所以就需要我們對Android內置的系統服務有一定的瞭解,才能更好的實現我們想要的邏輯,其中比較重要的就是AMS,PMS,WMS以及與這三個相關的類和方法,

   b>Android四大組件的運行原理也必須要清楚。

   c> java反射技術。反射是java自身的技術和Android沒有關係,但是Android是基於java開發的,那麼我們就可以利用反射這一技術實現我們想要的功能。在插件化編程中,針對某些對象和方法的原生的實現邏輯,但是有些對象在Android內置的類中是私有的,正常的情況下我們是沒有辦法獲取到的,此時就需要利用反射的方法,來獲取這些私有的變量,修改他們的邏輯。

   d>java的類加載機制也必須要清楚,不僅是理論上的,需要能夠結合實際的需求去使用。在插件化編程中,原生的APP中的對象和方法想要調用插件APP中的對象和方法,必須要藉助類加載器將插件中的對象和方法加載到虛擬機中。所以針對插件APK中的對象和方法到底應該以什麼樣的方式進行加載就是一個值得考慮的問題。

   e>代理模式。代理模式也是一個在插件化編程中必須要用到的方法,代理又分爲靜態代理和動態代理,動態代理就需要用到反射的方法。採用靜態代理需要爲每一個被代理的對象配置一個代理類,如果被代理的對象很多的話,就會增加很多的代碼,使用項目編程臃腫;動態代理可以一個代理類代理多個對象 ,增加了代碼的複用,減少代碼量。代理模式的目的主要也是爲了靈活的控制被代理對象的行爲,在插件化編程時主要的作用是在Android原生的邏輯之上,增加我們自己想要的邏輯,這一方式通常稱爲Hook,就是用我們自己寫的對象,替換Android中原本的對象。即用我們自己的對象代理了原生的對象。

3.插件化編程具體的實現

   在應用插件化的時候我們主要需要解決以下的問題:

    a>對Android四大組件的插件化

    針對應用開發來講最重要的就是Android的四大組件(Activity,Service,Provider,Broadcast),這四者幾乎構成了一個APK的全部。以下我們分別總結針對四大組件的插件化.

   Activity:對於Activity的插件化,我們需要解決以下幾個問題:

    (1)宿主App中的Activity如何啓動插件App中的Activity

       我們都知道想要在啓動任何的四大組件,都必須要在Manifest文件中聲明,如果啓動一個沒有在Manifest中聲明的Activity就會報錯。爲什麼會報錯呢,因爲AMS在啓動一個Activity的時候會去檢查該Activity是否被定義在Manifest中,如果不在就會報Activity Not Found的異常。因爲我們的插件是後來才加的,一開始宿主App也不會知道我們要啓動什麼Activity,所以插件中的Activity是不會定義在Manifest文件中,此時如果我們想要啓動插件中的Activity,

       需要解決兩個問題

       1)要能夠加載我們所啓動的Activity

       在Java中類的加載是通過ClassLoader進行加載的,每一個Apk最後都會被系統編譯成對應的dex文件,應用的啓動都依賴以 相應的ClassLoader對Class的加載,有兩種ClassLoader  (a)PathClassLoader (b)DexClassLoader。PathClassLoader只能加載已經安裝到系統的APK,而DexClassLoader則主要用來加載jar,apk,dex文件,針對我們的插件APK,想要運行,就可以利用DexClassLoader將其加載到系統中。我們需要new一個 DexClassLoader對象並傳遞插件APK的路徑。

       2)需要讓AMS認爲插件中的Activity是定義在Manifest中。

      如何讓AMS認爲插件中的Activity是在Mainfest中定義過的呢,因爲AMS會去檢查我們要啓動的Activity是否在Manifest中定義,如果我們能夠繞過檢查點,就可以,怎麼做呢,我們事先在Manifest中定義幾個空的Activity ,當我們想要啓動插件的Activity的時候,我們先啓動預定的那些Activity,等過AMS 的檢查點之後,再將預定義的Activity替換回插件中的Activity。

      通過查看Android系統的源碼,發現其實Activity的實例化就是利用反射的方法生成Activity對象,所以在啓動的插件Activity的時候,我們也需要利用反射的方法生成插件中的Activity對象,在反射的時候需要傳遞ClassLoader對象,那麼此時的ClassLoader就需要傳遞我們new出來的DexClassLoader. 因爲宿主APP的ClassLoader是不知道插件APP中的類的信息的,只有根據插件app的信息生成的插件的DexClassLoader才能夠加載插件的類。

     思路就是這樣一種思路,具體要在什麼地方替換,就是具體的實現問題了。

    (2)插件中的Activity如何啓動宿主App中的Activity

        插件中的Activity啓動宿主App中的Activity應該沒有什麼特別的,按照我們通常方法調用就可以

      (3)   插件中Activity的啓動模式的處理

        採用插件方式啓動的插件Activity只能使用標準模式啓動,所以如果想支持SingleTop,SingleInstance,SingleTask就必須我們自己來手動實現。書中說的方法是通過佔位的方式,預先在宿主App中設置好對應的啓動類型的Activity,然後將我們的Activity和預先設置好的Activity對應起來,當我們啓動插件中的Activity的時候,先找到插件Activity對應的在宿主App中預設的Activity進行啓動,在啓動的過程中宿主中預設的Activity是有啓動模式的,所以我們插件中的Activity,也就有啓動模式了。

   Service:對於Service

    (1)如何啓動宿主中的插件中的Service,與Activity不同的是Activity可以有多個實例對象,而Service只有一個實例對象

       針對Service的插件化需要我們針對插件中的每一個Service在宿主app中預先放置一個預製的Service,因爲對同一個 service多次啓動只會有一個Service實例。所以我們的插件中的Service必須和預製的Service一一對應。思路和Acitivity的插件化是一樣的通過欺騙AMS進行。在AMS中我們將我們要啓動的Service替換爲之前預定義的Service,而真正要啓動service的時候,再換回我們要啓動的Service

      (2)   Service的生命週期函數的調用

      bindService unBindService

    Provider和Broadcast的生命週期比較簡單,所以處理上沒有Activity和Service那麼繁瑣。

b>對資源的插件化

 針對資源訪問,最大的一個問題就是插件App中的資源ID有可能和宿主App中的資源ID產生衝突,應用不知道該找哪一個資源。

   (1)合併dex文件,修改插件資源的前綴,以區別於宿主App中的資源的Id

   (2)不和並的話,爲每一個 插件生成各自的AssetManager,訪問插件的資源用插件的AssetManager,訪問宿主的AssetManager用宿主的AssetManager

4.其他一些相關的技術

a>針對Fragment的插件化

b>Activity和HTML之間的相互調用

c>插件的混淆

d>增量更新

e>對so文件的插件化

f>APK打包流程的Hook

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章