RePlugin 插件化框架介紹與使用說明

RePlugin GitHub 主頁

RePlugin Wiki 主頁

RePlugin 原理剖析

全面插件化:RePlugin 的使命

* RePlugin 介紹

  * 主要優(yōu)勢

  * RePlugin 架構(gòu)

* 快速上手

  * 針對主程序開發(fā)者

    * 將 RePlugin 接入到你的主程序

    * 安裝一個(gè)插件

    * 打開一個(gè)插件的 Activity

  * 針對插件開發(fā)者

    * 將現(xiàn)有工程 → RePlugin 插件

    * 聲明一個(gè)插件的 Activity

    * 打開一個(gè)插件的 Activity

* 調(diào)試與運(yùn)行

  * 調(diào)試宿主

    * 環(huán)境配置

      * 倉庫配置

      * 插件使用配置

    * 插件的 Gradle 任務(wù)

  * 調(diào)試插件

    * 環(huán)境配置

      * 倉庫配置

      * 插件使用配置

    * 插件的 Gradle 任務(wù)

一、RePlugin 介紹

RePlugin 是一套完整的、穩(wěn)定的、適合全面使用的,占坑類插件化方案。我們“逐詞”拆開來解釋這個(gè)定義:

  • 完整的:讓插件運(yùn)行起來“像單品那樣”,支持大部分特性

  • 穩(wěn)定的:如此靈活完整的情況下,其框架崩潰率僅為業(yè)內(nèi)很低的“萬分之一”

  • 適合全面使用的:其目的是讓應(yīng)用內(nèi)的“所有功能皆為插件”

  • 占坑類:以穩(wěn)定為前提的 Manifest 占坑思路

  • 插件化方案:基于 Android 原生 API 和語言來開發(fā),充分利用原生特性

1.1 主要優(yōu)勢

  • 極其靈活:主程序無需升級(無需在 Manifest 中預(yù)埋組件),即可支持新增的四大組件,甚至全新的插件

  • 非常穩(wěn)定Hook 點(diǎn)僅有一處(ClassLoader),無任何 Binder Hook!如此可做到其崩潰率僅為“萬分之一”,并完美兼容市面上近乎所有的 Android ROM

  • 特性豐富:支持近乎所有在“單品”開發(fā)時(shí)的特性。包括靜態(tài) ReceiverTask-Affinity 坑位、自定義 Theme、進(jìn)程坑位、AppCompatDataBinding

  • 易于集成:無論插件還是主程序,只需“數(shù)行”就能完成接入

  • 管理成熟:擁有成熟穩(wěn)定的“插件管理方案”,支持插件安裝、升級、卸載、版本管理,甚至包括進(jìn)程通訊、協(xié)議版本、安全校驗(yàn)等

1.2 RePlugin 架構(gòu)

RePlugin 架構(gòu)圖

以 360 手機(jī)衛(wèi)士為例:

  • 系統(tǒng)層 —— Android:為 Android Framework 層。只有 ClassLoaderHook 的,而 AMSResources 等都沒有做 Hook,確保了其穩(wěn)定性。

  • 框架層 —— RePlugin 框架RePlugin 框架層,只有 RePlugin 是對“上層完全公開”的,其余均為 Internal,或“動(dòng)態(tài)編譯方案”生效后的調(diào)用,對開發(fā)者而言是“無需關(guān)心”的。

  • 插件層 —— 各插件“標(biāo)藍(lán)部分”是各插件,包括大部分的業(yè)務(wù)插件(如體檢、清理、桌面插件等)。而其中“標(biāo)黃部分”是支撐一個(gè)應(yīng)用的各種基礎(chǔ)插件,如 WebViewDownloadShare,甚至 Protobuf 都能成為基礎(chǔ)插件。

二、快速上手

RePlugin 的使用方法非常簡單易懂,大部分情況下和“單品”開發(fā)無異。以下分別針對:主程序(接入 RePlugin)和插件(研發(fā) RePlugin 插件)來進(jìn)行導(dǎo)引,以便適用于不同的團(tuán)隊(duì)成員。

2.1 針對主程序開發(fā)者

2.1.1 將 RePlugin 接入到你的主程序

只需三步,就能讓你的 “主程序” 接入 RePlugin

注意:目前有開發(fā)同學(xué)反饋,開啟 Instant Run 時(shí)可能會(huì)出現(xiàn)運(yùn)行時(shí)異常情況,請臨時(shí)關(guān)掉此功能后再試。

有關(guān)“混淆”:

RePlugin 的 AAR 自帶 Proguard 文件,你無需關(guān)心,直接引入 AAR 即可生效。此外,其內(nèi)部僅 Keep 了關(guān)鍵的接口類,大部分都是允許被混淆的,故對應(yīng)用來說也沒有影響。

第 1 步:添加 RePlugin Host Gradle 依賴

在項(xiàng)目根目錄的 build.gradle(注意:不是 app/build.gradle) 中添加 replugin-host-gradle 依賴:

buildscript {
    dependencies {
        classpath 'com.qihoo360.replugin:replugin-host-gradle:2.3.1'
        ...
    }
}

第 2 步:添加 RePlugin Host Library 依賴

app/build.gradle 中應(yīng)用 replugin-host-gradle 插件,并添加 replugin-host-lib 依賴:

android {
    // ATTENTION!!! Must CONFIG this to accord with Gradle's standard, and avoid some error
    defaultConfig {
        // 如果已經(jīng)有一個(gè) applicationId 則無需再添加
        applicationId "com.qihoo360.replugin.sample.host"
        ...
    }
    ...
}

// ATTENTION!!! Must be PLACED AFTER "android{}" to read the applicationId
// 注意!必須放在 “android{ }” 塊后面,因?yàn)橐茸x取 applicationId
apply plugin: 'replugin-host-gradle'

/**
 * 配置項(xiàng)均為可選配置,默認(rèn)無需添加
 * 更多可選配置項(xiàng)參見replugin-host-gradle的RepluginConfig類
 * 可更改配置項(xiàng)參見 自動(dòng)生成RePluginHostConfig.java
 */
repluginHostConfig {
    /**
     * 是否使用 AppCompat 庫
     * 不需要個(gè)性化配置時(shí),無需添加
     */
    useAppCompat = true
    /**
     * 背景不透明的坑的數(shù)量
     * 不需要個(gè)性化配置時(shí),無需添加
     */
    countNotTranslucentStandard = 6
    countNotTranslucentSingleTop = 2
    countNotTranslucentSingleTask = 3
    countNotTranslucentSingleInstance = 2
}

dependencies {
    implementation 'com.qihoo360.replugin:replugin-host-lib:2.3.1'
    ...
}
以下內(nèi)容請務(wù)必注意:
  • 請一定要確保符合 Gradle 開發(fā)規(guī)范,即“必須將包名寫在applicatonId”,而非 AndroidManifest.xml 中(通常從 Eclipse 遷移過來的項(xiàng)目可能出現(xiàn)此問題)。如果不這么寫,則有可能導(dǎo)致運(yùn)行時(shí)出現(xiàn) “Failed to find provider info for com.ss.android.auto.loader.p.main” 的問題。具體可參見 #87 Issue 的問答

  • 請將 apply plugin: 'replugin-host-gradle' 放在 android{ } 塊之后,防止出現(xiàn)無法讀取 applicationId,導(dǎo)致生成的坑位出現(xiàn)異常

  • 如果你的應(yīng)用需要支持 AppComat,則除了在主程序中引入 AppComat-v7 包以外,還需要在宿主的 build.gradle 中添加下面的代碼,若不支持 AppComat 則請不要設(shè)置此項(xiàng):

repluginHostConfig {
    useAppCompat = true
}

開啟 useAppCompat 后,RePlugin 會(huì)在編譯期生成 AppCompat 專用坑位,這樣插件若使用 AppCompatTheme 時(shí)就能生效了。若不設(shè)置,則可能會(huì)出現(xiàn) “IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.” 的異常。

  • 如果你的應(yīng)用需要個(gè)性化配置坑位數(shù)量,則需要在宿主的 build.gradle 中添加下面的代碼:
repluginHostConfig {
     /**
     * 背景不透明的坑的數(shù)量
     */
    countNotTranslucentStandard = 6
    countNotTranslucentSingleTop = 2
    countNotTranslucentSingleTask = 3
    countNotTranslucentSingleInstance = 2
}
  • 筆者在導(dǎo)入了上述依賴庫之后,進(jìn)行同步項(xiàng)目時(shí),遇到了如下問題:Gradle sync failed: No signature of method: com.android.build.gradle.internal.scope.VariantScopeImpl.getMergeAssetsTask() is applicable for argument types: () values: []。這是因?yàn)?Google 對 3.2.0 版本之后的 Gradle 構(gòu)建工具做了一些修改(筆者用的是 3.2.1),RePlugin 官方還沒有對此用兼容性處理。 解決方法也很簡單,把項(xiàng)目根目錄的 build.gradle(注意:不是 app/build.gradle)中的
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
    }

改為

    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.4'
    }

即可,具體參見 #Issue 640

更多可選配置項(xiàng)請參見 replugin-host-gradleRepluginConfig 類。

第 3 步:配置 Application 類

讓工程的 Application 直接繼承自 RePluginApplication。筆者發(fā)現(xiàn),如果應(yīng)用導(dǎo)入了 RePlugin,但是不配置 Application 類的話,那么應(yīng)用程序?qū)o法運(yùn)行。詳情請看這里 #Issue 46 sample 運(yùn)行報(bào)錯(cuò)

如果你的工程已有 Application 類,則可以將基類切換到 RePluginApplication 即可。或者你也可以用“非繼承式”接入。

public class MainApplication extends RePluginApplication {
}

既然聲明了 Application,自然還需要在 AndroidManifest 中配置這個(gè) Application

    <application
        android:name=".MainApplication"
        ... />
備選:“非繼承式”配置 Application

若你的應(yīng)用對 Application 類繼承關(guān)系的修改有限制,或想自定義 RePlugin 加載過程(慎用!),則可以直接調(diào)用相關(guān)方法來使用 RePlugin

public class MainApplication extends Application {

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);

        RePlugin.App.attachBaseContext(this);
        ....
    }

    @Override
    public void onCreate() {
        super.onCreate();
        
        RePlugin.App.onCreate();
        ....
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();

        /* Not need to be called if your application's minSdkVersion > = 14 */
        RePlugin.App.onLowMemory();
        ....
    }

    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);

        /* Not need to be called if your application's minSdkVersion > = 14 */
        RePlugin.App.onTrimMemory(level);
        ....
    }

    @Override
    public void onConfigurationChanged(Configuration config) {
        super.onConfigurationChanged(config);

        /* Not need to be called if your application's minSdkVersion > = 14 */
        RePlugin.App.onConfigurationChanged(config);
        ....
    }
}
針對“非繼承式”的注意點(diǎn):
  • 所有方法必須在 UI 線程來“同步”調(diào)用。切勿放到工作線程,或者通過 post 方法來執(zhí)行

  • 所有方法必須一一對應(yīng),例如 RePlugin.App.attachBaseContext() 方法只在 Application.attachBaseContext() 中調(diào)用

  • 請將 RePlugin.App 的調(diào)用方法,放在“僅次于 super.xxx()方法的后面

2.1.2 安裝一個(gè)插件

這部分內(nèi)容請看 RePlugin 關(guān)于插件管理

2.1.3 打開一個(gè)插件的 Activity

這部分內(nèi)容請看 RePlugin 關(guān)于插件的組件

2.2 針對插件開發(fā)者

2.2.1 將現(xiàn)有工程 → RePlugin 插件

只需兩步,就能讓你的 App 變成 “RePlugin 插件”:

有關(guān)“混淆”:

RePlugin 的 AAR 自帶 Proguard 文件,你無需關(guān)心,直接引入 AAR 即可生效。此外,其內(nèi)部僅 Keep 了關(guān)鍵的接口類,大部分都是允許被混淆的,故對應(yīng)用來說也沒有影響。

第 1 步:添加 RePlugin Plugin Gradle 依賴

在項(xiàng)目根目錄的 build.gradle(注意:不是 app/build.gradle) 中添加 replugin-plugin-gradle 依賴:

buildscript {
    dependencies {
        classpath 'com.qihoo360.replugin:replugin-plugin-gradle:2.3.1'
        ...
    }
}

第 2 步:添加 RePlugin Plugin Library 依賴

app/build.gradle 中應(yīng)用 replugin-plugin-gradle 插件,并添加 replugin-plugin-lib 依賴:

apply plugin: 'replugin-plugin-gradle'

dependencies {
    implementation 'com.qihoo360.replugin:replugin-plugin-lib:2.3.1'
    ...
}

接下來你就可以像單品那樣,開你的插件。生成出來的是 APK,既可以“安裝到設(shè)備”,又可以“作為插件”使用。

2.2.2 聲明一個(gè)插件的 Activity

這部分內(nèi)容請看 RePlugin 關(guān)于插件的組件

2.2.3 打開一個(gè)插件的 Activity

這部分內(nèi)容請看 RePlugin 關(guān)于插件的組件

三、調(diào)試與運(yùn)行

3.1 調(diào)試宿主

3.1.1 環(huán)境配置

3.1.1.1 倉庫配置
buildscript {
    repositories {
        maven { url 'https://dl.google.com/dl/android/maven2/' }
        google()
        jcenter()
    }
    dependencies {
        ...
        classpath 'com.qihoo360.replugin:replugin-host-gradle:2.3.1'
    }
}
3.1.1.2 插件使用配置
// ATTENTION!!! Must be PLACED AFTER "android{}" to read the applicationId
apply plugin: 'replugin-host-gradle'

repluginHostConfig {
    /**
     * 是否使用 AppCompat 庫
     * 不需要個(gè)性化配置時(shí),無需添加
     */
    useAppCompat = true
}

apply plugin 盡量放在 android 配置之后,因?yàn)榭梢宰詣?dòng)讀取 android中 的配置項(xiàng),方便以后升級。簡單的說,就是放在你 build.gradle 文件末尾即可。

3.1.2 插件的 Gradle 任務(wù)

  • rpGenerateDebugBuiltinJsonrpGenerateReleaseBuiltinJson

生成內(nèi)置插件的配置文件(一般很少使用,編譯時(shí)會(huì)自動(dòng)處理)

  • rpGenerateDebugHostConfigrpGenerateReleaseHostConfig

生成插件們的坑位配置文件(一般很少使用,編譯時(shí)會(huì)自動(dòng)處理)

  • rpShowPluginsDebugrpShowPluginsRelease

查看所有內(nèi)置插件的信息

3.2 調(diào)試插件

3.2.1 環(huán)境配置

3.2.1.1 倉庫配置
buildscript {
    repositories {
        maven { url 'https://dl.google.com/dl/android/maven2/' }
        google()
        jcenter()
    }
    dependencies {
        ...
        classpath 'com.qihoo360.replugin:replugin-plugin-gradle:2.3.1'
    }
}
3.2.1.2 插件使用配置
apply plugin: 'replugin-plugin-gradle'

repluginPluginConfig {
    //插件名
    pluginName = "demo1"
    //宿主app的包名
    hostApplicationId = "com.qihoo360.replugin.sample.host"
    //宿主app的啟動(dòng)activity
    hostAppLauncherActivity = "com.qihoo360.replugin.sample.host.MainActivity"
}

apply plugin 需要放在 android 配置之后,因?yàn)樾枰x取 android 中的配置項(xiàng)。簡單的說,就是放在你 build.gradle 文件末尾即可。

3.2.2 插件的 Gradle 任務(wù)

一些 Gradle 任務(wù)依賴宿主,需要在宿主中添加 RePlugin.enableDebugger(base, BuildConfig.DEBUG); 這行代碼

  • rpForceStopHostApp

強(qiáng)制停止宿主程序

  • rpInstallAndRunPluginDebugrpInstallAndRunPluginRelease

安裝插件到宿主并運(yùn)行(常用任務(wù))

  • rpInstallPluginDebugrpInstallPluginRelease

僅僅安裝插件到宿主

  • rpRestartHostApp

重啟宿主程序

  • rpRunPluginDebugrpRunPluginRelease

僅僅運(yùn)行插件,如果插件前面沒安裝,則執(zhí)行不成功

  • rpStartHostApp

啟動(dòng)宿主程序

  • rpUninstallPluginDebugrpUninstallPluginRelease

僅僅卸載插件,如果完全卸載,還需要執(zhí)行 rpRestartHostAp 任務(wù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,397評論 1 372
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內(nèi)容