Adroid動態加載Apk-插件化技術框架(動態代理方案)

技術:Android + java +動態加載+插件化
 

概述

爲何要使用插件化?在開發中,一個項目只會越作越大。初始版本多是單一功能,後續可能加上各類風馬牛不相及的功能。因此我認爲插件化可使得業務分離的更完全,一人負責哪幾個模塊,問題也能快速定位。可是也會帶來問題:插件和插件之間的交互的複雜性更高、底層支持庫由於多個插件須要使用相同的代碼可能會變得很大。因此插件化看似解耦了程序員的職責,實際上對於代碼質量的要求更高。   實現插件化,最快的方法就是找一個第三方框架。可是要想真正理解,須要真正本身寫一個.下面本文就帶你們寫一個動態加載插件化的框架

詳細

 

Android動態加載Apk-插件化技術(動態代理方案)html

一.概述java

 

爲何要使用插件化?在開發中,一個項目只會越作越大。初始版本多是單一功能,後續可能加上各類風馬牛不相及的功能。因此我認爲插件化可使得業務分離的更完全,一人負責哪幾個模塊,問題也能快速定位。可是也會帶來問題:插件和插件之間的交互的複雜性更高、底層支持庫由於多個插件須要使用相同的代碼可能會變得很大。因此插件化看似解耦了程序員的職責,實際上對於代碼質量的要求更高。android

  要想實現插件化,最快的方法就是找一個第三方框架接入。可是要想真正理解,須要真正本身寫一個.下面本文就帶你們寫一個動態加載插件化的框架程序員



二. 什麼是插件化微信

 

1. 主App(宿主App)加載插件apk的實現app

2. 每一個業務組件模塊造成一個獨立的Apk, 而後經過主App動態加載部署業務組件模塊Apk的一種方案

框架

三.效果演示圖&應用場景ide

1.效果演示圖:性能

1551677279143090192.png 1551677395686035818.png

 

2.實際開發中,好比微信和支付寶的以下頁面就是典型的插件化應用場景優化

1551677447098003903.jpg 1551677489063007128.jpg

 

三.插件化的優勢好處

1. 業務組件解耦,可以實現業務組件模塊的熱插拔

2. 更改產品迭代模式,可分爲主App和次Apk(動態加載業務組件模塊)

3. 改善產品更新過程,能夠在不影響用戶的狀況下實現業務組件模塊更新以及重要Bug修復

4. 減輕主App的內存和CPU佔用,提升應用的性能.

四.插件化的思想

動態加載Apk的主要思想是:主App是被系統(PMS)安裝,被系統(AMS)調用,整個過程都是由系統提供的,而插件Apk並不是一個真正的Apk,只是一個打包成Apk的一個組件模塊,由於它並不是被系統安裝調用.簡言之,須要講插件Apk當作一個」非Apk」文件,只是一個結構比較複雜的壓縮打包成Apk格式的文件.調用插件即用某種特殊技術手段打開文件並執行其相關代碼.

五.插件化的步驟-分析主App

1.主APp打包完成解壓後,會有dex,images,xml,asset等類型文件

2.Dex靠PathClassLoader加載運行

3.圖片以及xml等資源依靠Resources&AssetManager加載管理

六.插件化的實現流程

 

1551676499854069490.png

 

六. 插件化的代碼實現步驟

1.建立DexClassLoader加載插件化Apk相關代碼,核心代碼以下:

/**'
 * 建立DexClassLoader
 */
private DexClassLoader createDexClassLoader(String apkPath) {
    File file = mContext.getDir("dex",Context.MODE_PRIVATE);
    return new DexClassLoader(apkPath,file.getAbsolutePath(),null,mContext.getClassLoader());
}

 

 

2.建立Resources&AssetManager來加載插件化Apk的資源

/**
 * 獲取到插件中的Resource
 */
private Resources createResources(AssetManager am) {
    Resources resources = mContext.getResources();
    return new Resources(am,resources.getDisplayMetrics(),resources.getConfiguration());
}

/**
 * 獲取插件的AssetManager
 */
private AssetManager createAssetManager(String apkPath) {
    try {
        AssetManager am = AssetManager.class.newInstance();
        Method method = AssetManager.class.getDeclaredMethod("addAssetPath",String.class);
        method.invoke(am,apkPath);
        return am;
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    return null;
}

 

 

3.管理插件Apk裏的組件(如Activity)的生命週期

 

package com.czm.pluginlib;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

/**
 * Created by caizhiming on 2018/3/3.
 */

public interface IPlugin {

    int FROM_INTERNAL = 0;//內部跳轉
    int FROM_EXTERNAL = 1;//外部跳轉

    void attach(Activity activity);

    void onCreate(Bundle bundle);
    void onStart();
    void onRestart();
    void onActivityResult(int requestCode, int resultCode, Intent data);
    void onResume();
    void onPause();
    void onStop();
    void onDestroy();
}

 

4.經過代理模式實現對插件Apk裏面組件的管理

@Override
protected void onCreate( Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mClassName = getIntent().getStringExtra("className");
    mPluginApk = XCPluginManager.getInstance().getPluginApk();

    launchPluginActivity();
}

private void launchPluginActivity() {
    if(mPluginApk == null){
        throw new RuntimeException("請先加載插件Apk");
    }
    try {
        //clazz 就是Activity的實例對象,可是該對象沒有生命週期,沒有上下文環境
        Class<?> clazz = mPluginApk.mDexClassLoader.loadClass(mClassName);
        Object object = clazz.newInstance();
        if(object instanceof IPlugin) {
            mIPlugin = (IPlugin) object;
            mIPlugin.attach(this);
            Bundle bundle = new Bundle();
            bundle.putInt("FROM",IPlugin.FROM_EXTERNAL);
            mIPlugin.onCreate(bundle);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Override
public Resources getResources() {
    if(mPluginApk != null) {
        return mPluginApk.mResources;
    } else {
        return super.getResources();
    }
}

@Override
public AssetManager getAssets() {
    if(mPluginApk != null) {
        return mPluginApk.mAssetManager;
    }else {
        return super.getAssets();
    }
}

@Override
public ClassLoader getClassLoader() {
    if(mPluginApk != null) {
        return mPluginApk.mDexClassLoader;
    }else {
        return super.getClassLoader();
    }
}

 

以上就是實現插件化的主要過程步驟,具體細節優化讀者能夠本身擴展優化補充.

 

七.項目代碼目錄結構圖

 

apkplugin.png

注:本文著做權歸做者,由demo大師發表,拒絕轉載,轉載須要做者受權

相關文章
相關標籤/搜索