Android 插件框架機制之預熱篇

關於Android插件框架機制的介紹,我打算分幾章來介紹,這是第一篇也就是預熱篇。
Android 插件框架機制系列文章:
Android 插件框架機制之Small
Android 插件框架機制之DroidPluginjavascript

爲何使用插件化

隨着應用的模塊化的不斷增長,APK的體積不斷增加,方法數極可能會引起64K問題(解決方案),谷歌提供的方案並不完美,並且APK的啓動速度會受影響。java

  • 提升工程的運行速度,每一個模塊做爲一個獨立的插件進行開發和調試。
  • 提升應用的啓動速度,應用啓動時能夠選擇只加載必須的模塊,其餘模塊使用時再加載
  • 多團隊並行開發
  • 在線動態加載或更新模塊
  • 靈活的功能配置

基礎知識

機制

插件化的根本思路就是讓你的應用調用未安裝的apk,jar,dex文件中的方法。
在Android中,系統提供了兩個API可供選擇:android

  • PathClassLoader:只能加載已經安裝到Android系統中的APK文件,這個是另外一種加載思路,可是跟插件化不要緊,這裏不提。
  • DexClassLoader:支持加載外部的APK,Jar,或Dex文件。

    基礎示例

    咱們先寫一個插件APK,新建一個工程,修改MainActivity:
public class MainActivity extends Activity {

    private Activity otherActivity;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        boolean b = false;
        if (savedInstanceState != null) {
            b = savedInstanceState.getBoolean("KEY_START_FROM_OTHER_ACTIVITY", false);
            if (b) {
                this.otherActivity.setContentView(new TBSurfaceView(
                        this.otherActivity));
            }
        }
        if (!b) {
            super.onCreate(savedInstanceState);
            // setContentView(R.layout.main);
            setContentView(new TBSurfaceView(this));
        }
    }

    public void setActivity(Activity paramActivity) {
        this.otherActivity = paramActivity;
    }
}複製代碼

在被加載的Activity中是否是識別和加載資源文件的,因此不能用佈局文件,只能用一個View。git

public class TBSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
    private SurfaceHolder sfh;
    private Thread th;
    private Canvas canvas;
    private Paint paint;

    public TBSurfaceView(Context context) {
        super(context);
        th = new Thread(this);
        sfh = this.getHolder();
        sfh.addCallback(this);
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.RED);
        this.setKeepScreenOn(true);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        th.start();
    }

    private void draw() {
        try {
            canvas = sfh.lockCanvas();
            if (canvas != null) {
                canvas.drawColor(Color.WHITE);
                canvas.drawText("Time: " + System.currentTimeMillis(), 100,
                        100, paint);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (canvas != null) {
                sfh.unlockCanvasAndPost(canvas);
            }
        }
    }

    public void run() {
        while (true) {
            draw();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width,
                               int height) {
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
    }
}複製代碼

而後將生成的apk,不要安裝在手機,而是存入手機,好比咱們就存入sd卡的根目錄,可使用adb命令:github

adb push /Users/xxxxx/file/source/loadActivity/app/build/outputs/apk/app-debug.apk /sdcard/複製代碼

而後咱們新建一個應用,寫一個加載的方法:canvas

public void dex() {


        String apkPath = "/sdcard/app-debug.apk";
        String optPath = "/mnt/sdcard/";
// String libPath = info.activityInfo.applicationInfo.nativeLibraryDir;
        File dexOutputDir = getDir("dex", 0);

        DexClassLoader clsLoader = new DexClassLoader(apkPath, dexOutputDir.getAbsolutePath(),
                null, this.getClass().getClassLoader());
        try {

            Class localClass = clsLoader
                    .loadClass("deep.loadactivity.MainActivity");
            mActivityClass = localClass;
            Constructor localConstructor = localClass.getConstructor(new Class[] {});
            instance = localConstructor.newInstance(new Object[] {});
            mActivityInstance = instance;

            Method localMethodSetActivity = localClass.getDeclaredMethod(
                    "setActivity", new Class[] { Activity.class });
            localMethodSetActivity.setAccessible(true);
            localMethodSetActivity.invoke(instance, new Object[] { this });

            Method methodonCreate = localClass.getDeclaredMethod("onCreate", new Class[] { Bundle.class });
            methodonCreate.setAccessible(true);
            Bundle paramBundle = new Bundle();
            paramBundle.putBoolean("KEY_START_FROM_OTHER_ACTIVITY", true);
            paramBundle.putString("str", "MainActivity");
            methodonCreate.invoke(instance, new Object[] { paramBundle });

        } catch (Exception e) {
            e.printStackTrace();
        }
    }複製代碼

下面主要說一下DexClassLoader:app

DexClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent)複製代碼

dexPath:被解壓的apk路徑,不能爲空。
optimizedDirectory:解壓後的.dex文件的存儲路徑,不能爲空。
libraryPath:庫文件的的搜索路徑,通常來講是 .so 庫文件的路徑,也能夠指明多個路徑。
parent:父親加載器,通常爲ClassLoader.getSystemClassLoader()。框架

說明

在上面的例子中咱們實際上是演示了一下動態加載Activity的方法,Activity被動態加載後,是沒有生命週期的,只是當作一個類來作處理,由上面程序能夠看出,咱們是手動調用onCreate方法的。
固然,咱們也能夠寫一些其餘類或方法進行調用,不必定非要用Activity。maven

開源框架

說完了插件機制,咱們也認識到了插件機制的一些不足,就好比剛纔說的,Activity生命週期沒有了,須要手動調用各個方法,那給咱們的開發帶來了不少不方便,可是網上的一些開源框架,解決了這些不方便,將調用的方法,順序封裝好,咱們只管調用便可。
這些框架,我會在後面的文章中詳細演示。ide

android-pluginmgr

利用DexMaker的動態熱部署功能來實現Activity。

  • 優勢:
    1.插件app不須要任何規則和限制
    2.技術方法相對成熟穩定
  • 缺點:
    1.oom問題突出
    2.只支持Activity,不支持其它組件。

dynamic-load-apk

這是基於代理的方式實現插件框架的,須要按照必定的規則來開發插件APK。

  • 優勢:
    1.插件須要遵循一些規則,更加可控
    2.方案簡單
  • 缺點:
    1.不支持this調用組件中的方法,須要that,有些難理解
    2.不支持隱式調用APK內部的Activity
    3.兼容性問題較多

DynamicAPK

這是攜程實現的一種多APK/DEX加載的插件框架。

  • 優勢:
    1.不多修改便可實現改造
    2.提高工程編譯速度
    3.可實現熱更新
    4.提升App的啓動速度
  • 缺點:
    1.不支持so庫
    2.不支持aar,maven遠程倉庫的依賴

DroidPlugin

這是360實現的一種插件框架,他能夠直接運行第三方獨立得APK。徹底不須要對APK進行修改或安裝。

  • 優勢:
    1.支持四大組件
    2.支持全部系統API
    3.插件與插件之間,插件與宿主之間的代碼和資源徹底隔離
    4.實現了進程管理,佔用內存低
  • 缺點:
    1.不支持自定義資源的Notification
    2.不支持IntentFilter
    3.缺少對Native層的Hook操做
    4.因爲插件與插件,插件與宿主之間徹底隔離,所以,若是須要通訊,須要Android系統級別的通訊方式。

Small

這是一個跨平臺的插件化框架。

  • 優勢:
    1.插件編碼與資源文件的使用與普通開發無差異
    2.經過設定URI,宿主能夠方便地與插件間進行通訊
    3.支持Android IOS HTML5
    *缺點:
    不支持Service的動態註冊。

總結

以上是我對插件調研的一個總結,在後面的演示中,我會將主流的插件化框架進行詳細說明。

相關文章
相關標籤/搜索