from:http://code.google.com/p/android-application-plug-ins-frame-work/

介紹

這個(gè)框架的初衷,是為了方便讓程序模塊化、插件化,將一個(gè)apk應(yīng)用拆分為多個(gè)apk。
不明白這個(gè)插件化、模塊化是怎么回事的話,可以看看騰訊微信的安卓客戶端中的插件配置。
在這里我會(huì)以騰訊微信為例,如何使用這個(gè)框架。 (騰訊微信并不是真正的插件化,它是偽的,插件并非與它的主程序分離開,結(jié)果就是每次插件的更新,都必須以整個(gè)程序的更新為代價(jià))

都能干啥

框架的思想,主要是通過(guò)apk清單文件中的sharedUserId屬性來(lái)吧多個(gè)apk融合為單一的dalvik虛擬機(jī),也就是融合為一個(gè)進(jìn)程,這樣就變相逾越了android框架中不同apk權(quán)限不同無(wú)法互通的鴻溝(rpc啦什么的其它的畢竟不如這個(gè)來(lái)的實(shí)在)。
從最簡(jiǎn)單的皮膚插件到復(fù)雜的涉及數(shù)據(jù)庫(kù)的拓展功能,從普通activity跳轉(zhuǎn)到把插件的activity轉(zhuǎn)變?yōu)関iew并附加到主程序中的拓展功能,都是可以通過(guò)本框架來(lái)實(shí)現(xiàn)的,當(dāng)然,本框架只是提供了一種途徑,如何編碼還得靠自己。
本人能力有限,可能有一些錯(cuò)誤、疏漏或者不足之處,請(qǐng)不吝指教,我的博客地址在左下角,或者我的郵箱,都可以聯(lián)系到我。
ps:下面會(huì)以騰訊微信為例,這里聲明一下,本人沒有對(duì)微信安卓客戶端進(jìn)行任意形式的反編譯與破解工作,只是看球半天進(jìn)行簡(jiǎn)單的猜測(cè)而已。

框架結(jié)構(gòu)

本插件框架由三個(gè)包組成:

  • org.igeek.android.pluginframework 這個(gè)包種類是框架的主要操作類
    1. PluginBuilder 組裝插件
    2. PluginDescription 組裝用戶自定義的插件描述
    3. PluginInvoke 插件功能調(diào)用
    4. PluginSearch 查找插件
  • org.igeek.android.pluginframework.annotation 未來(lái)可能會(huì)考慮使用注解
    1. PluginDescription 用于用戶自定義描述類的注解
    2. PluginFeature 用于插件類的注解
    3. PluginMethod 用于插件類方法的注解
  • org.igeek.android.pluginframework.beans 框架內(nèi)部使用的一些beans
    1. Plugin 插件包
    2. PluginFeature 插件類
    3. PluginFeatureMethod 插件方法
  • org.igeek.android.pluginframework.util 一些工具類
    1. XMLParse 插件包

如何使用

以騰訊微信為例,雖然從表面來(lái)看,它是插件化的多種功能的一種集成。但是,這都是虛的,每次更新時(shí)你會(huì)發(fā)現(xiàn),哪怕一個(gè)小小的功能添加,都會(huì)讓用戶更新整個(gè)程序,截至目前(2011-12-17),微信讓我更新到3.5,修復(fù)了一些小bug,增加了1個(gè)插件功能,以及其它的小改進(jìn),就得讓我下載并升級(jí)整個(gè)程序,6.8m啊。。
在工程開發(fā)時(shí),預(yù)留插件的使用、管理頁(yè)面,如:

這是微信的插件瀏覽頁(yè)面,所有可暴露在這里的插件都會(huì)被列出來(lái)

 這是微信的插件管理界面,可以卸載安卓,但這些都是虛的,可能只是把服務(wù)關(guān)了,并非真正的卸載

主程序(APK)

  • 、主程序清單
首先為工程想好一個(gè)名字,并在清單中加入sharedUserId屬性,屬性值就是想好的那個(gè)名字,例如微信:com.qq.weixin
   android:sharedUserId="com.qq.weixin"
  • 、為插件描述寫一個(gè)類
 這就是插件描述

首先在主程序中單獨(dú)建立一個(gè)包,并寫一個(gè)類,這個(gè)類相當(dāng)于一個(gè)bean,具有相應(yīng)的插件描述信息的字段,如微信,那么這個(gè)bean的字段就有 插件名:漂流瓶 插件logo:那個(gè)人頭 插件描述:描述信息...

這個(gè)類在主程序中不會(huì)很多的使用,只會(huì)讀取框架返回的插件的bean。

  • 、引入本框架的jar包或?qū)朐创a

正式編碼時(shí),可在任何地方調(diào)用框架。具體步驟是這樣的
1、查找插件 本框架是根據(jù)sharedUserId來(lái)查找插件。它首先會(huì)根據(jù)自身apk的sharedUserId值來(lái)查找系統(tǒng)中具有相同屬性的包并加載。
  • ??以說(shuō),插件apk的sharedUserId值也應(yīng)與主程序相同
        //首先,就是查找插件
        PluginSearch psearch=new PluginSearch();
        //第一次獲得的是簡(jiǎn)要的插件描述
        List<Plugin>  plugins=psearch.getPlugins(this);
       
        //然后將插件再組裝一下
        PluginBuilder pbuilder=new PluginBuilder(this);
        //將用戶所定義插件描述融合進(jìn)去
        plugins=pbuilder.buildPluginsDescrition(plugins);

這樣就把所有插件找到手了,很簡(jiǎn)單吧?

1、調(diào)用插件 找到插件后肯定是調(diào)用,最簡(jiǎn)單應(yīng)用,就是靠Button按鈕來(lái)調(diào)用
比如微信的搖一搖,點(diǎn)了它就觸發(fā)框架的插件調(diào)用
        @Override
        public void onClick(View v) {
                //新建一個(gè)插件調(diào)用類
                PluginInvoke pi=new PluginInvoke(AndroidPluginFrameworkActivity.this);
       
               
                //這是真正的調(diào)用
                //三個(gè)參數(shù),第一個(gè)是Plugin類型,第二個(gè)是PluginFeature,第三個(gè)PluginFeatureMethod
                pi.invoke(plug, pf, fm);
               
        }
        });

插件程序(APK)

  • 、插件程序清單

同主程序的清單文件一樣,sharedUserId必須有且和主程序的一樣 插件的activity的意圖過(guò)濾描述必須是這樣 示例:

 <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
  • 、插件程序的功能
插件可以包含任意類,如同一個(gè)普通的apk工程一樣。
但是,向主程序提供調(diào)用的類,必須是個(gè)activity,方法必須是無(wú)返回值的,有且只有一個(gè)Context參數(shù),框架會(huì)反射這個(gè)方法,并將主程序的context句柄傳入,也就是,不管你用不用這個(gè)context,他都是被框架傳入的。
如果主程序規(guī)定了描述類,也就是框架中需要PluginDescription來(lái)調(diào)用的bean,在插件工程中,也必須有主程序這個(gè)bean,包名也必須一樣。插件程序可以直接繼承或者更改這個(gè)bean的字段,方便主程序去獲取這個(gè)插件的描述信息。這種方式,是避過(guò)框架,給主程序一種方便。
  • 、插件程序的plugin.xml配置
http://android-application-plug-ins-frame-work.googlecode.com/files/plugin.xml plugin.xml不能改名,必須放在工程的 assets 目錄下。
內(nèi)容大致是這樣:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 這個(gè)xml配置文件放在插件工程的 assets 目錄下 -->


<!-- 插件提供的功能(類) -->
<plugin-features>

        <!-- 描述類,這個(gè)是自定義的 -->
        <!-- 這個(gè)描述類使用戶定義的,在主程序中必須有,插件工程中也必須有,并被繼承 -->
        <description name="org.pakage.name.and.description.name"/>
       
        <!-- 這是一個(gè)功能(類),必須是activity的子類 -->
        <feature name="org.pakage.name.and.activity.name1">
       
                <!-- 這是一個(gè)方法 -->
                <!-- name 方法名 -->
                <method need-context="true" name="methodName1" >描述信息</method>
                <method need-context="true" name="methodName2" >描述信息</method>
               
        </feature>
       
        <feature name="org.pakage.name.and.activity.name2">
                <method need-context="true" name="methodName1" >描述信息</method>
        </feature>
</plugin-features>
按著上面的套路來(lái)配置,就很容易了。

最后

上面說(shuō)的比較泛,最好還是看看示例工程,里面包含了一個(gè)主程序和兩個(gè)插件擴(kuò)展,總共是4個(gè)工程,也就是說(shuō),在用戶端是4個(gè)apkhttp://android-application-plug-ins-frame-work.googlecode.com/files/demo.zip