* 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)
Receiver
、Task-Affinity
坑位、自定義Theme
、進(jìn)程坑位、AppCompat
、DataBinding
等易于集成:無論插件還是主程序,只需“數(shù)行”就能完成接入
管理成熟:擁有成熟穩(wěn)定的“插件管理方案”,支持插件安裝、升級、卸載、版本管理,甚至包括進(jìn)程通訊、協(xié)議版本、安全校驗(yàn)等
1.2 RePlugin 架構(gòu)
以 360 手機(jī)衛(wèi)士為例:
系統(tǒng)層 —— Android:為 Android Framework 層。只有
ClassLoader
是Hook
的,而AMS
、Resources
等都沒有做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ǔ)插件,如
WebView
、Download
、Share
,甚至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
專用坑位,這樣插件若使用AppCompat
的Theme
時(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-gradle
的 RepluginConfig
類。
第 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ù)
-
rpGenerateDebugBuiltinJson
或rpGenerateReleaseBuiltinJson
等
生成內(nèi)置插件的配置文件(一般很少使用,編譯時(shí)會(huì)自動(dòng)處理)
-
rpGenerateDebugHostConfig
或rpGenerateReleaseHostConfig
等
生成插件們的坑位配置文件(一般很少使用,編譯時(shí)會(huì)自動(dòng)處理)
-
rpShowPluginsDebug
和rpShowPluginsRelease
等
查看所有內(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)制停止宿主程序
-
rpInstallAndRunPluginDebug
或rpInstallAndRunPluginRelease
等
安裝插件到宿主并運(yùn)行(常用任務(wù))
-
rpInstallPluginDebug
或rpInstallPluginRelease
等
僅僅安裝插件到宿主
rpRestartHostApp
重啟宿主程序
-
rpRunPluginDebug
或rpRunPluginRelease
等
僅僅運(yùn)行插件,如果插件前面沒安裝,則執(zhí)行不成功
rpStartHostApp
啟動(dòng)宿主程序
-
rpUninstallPluginDebug
或rpUninstallPluginRelease
僅僅卸載插件,如果完全卸載,還需要執(zhí)行 rpRestartHostAp
任務(wù)