這篇文章基于 Replugin2.2版本的,后續可能會隨著框架改動和bug修復有些問題可能就不存在了。如果你跟我一樣也是對插件化開發躍躍欲試,又在里面栽跟頭了,我想本片文章可能會對大家提供點小小的幫助。最終問題的解決還是離不開對框架原理的熟悉。否則遇到了問題也不知道從何下手。孤陋寡聞的我可能踩了一些很低級的錯誤,還望各位大大們在發現本文講得不對的地方指正。
目錄
- 插件使用宿主的對象
- v7包
- 插件橫屏
- 熱更新插件
- 坑位之顯示Intent無效
- 插件和宿主同工程的問題
- 幽靈魔術
插件使用宿主的對象
1.我想在插件中使用宿主的new出來的對象,但是如果在插件中和宿主中同時依賴一份資源是無法使用的,會報類轉化異常。比如宿主和插件都要用okhttp3,但是我不想插件中也要初始化一個。
答:
只在宿主中通過dependencies的方式依賴一下,然后將工程切換成Project模式。如下圖
找到這個依賴文件,在jar文件上右鍵打開目錄。
將這個jar文件拷貝到你的插件目錄下。然后通過provided的方式進行編譯依賴。
provided files('libs/xxx.jar')
注意,provided僅僅是編譯依賴,不會打包進apk包里。這樣當Replugin框架在dex加載的時候拿到的就是宿主的class。就不會造成類轉化異常了。
小技巧提示:
如果你的插件需要公共host里面的一些類和基礎服務。(注意不含資源,資源指圖片和xml)
可以在host里剝離出一個模塊,讓host去依賴它,然后將該模塊打包成jar的方式,提供給插件使用。猶如sdk的開發模式,但是一定要注意務必使用provided關鍵字。莫打包進去了。
模塊打包成jar的方式如下:
在依賴模塊中的gradle里添加配置:
android {
lintOptions {
abortOnError false
}
}
//注意makeJar放在外層
task makeJar(type: Jar, dependsOn: ['build']) {
destinationDir = file('build/outputs/jar/')
baseName = "AppSDK"
version = "1.0.0"
from('build/intermediates/classes/debug')
exclude('**/BuildConfig.class')
exclude('**/BuildConfig\$*.class')
exclude('**/R.class')
exclude('**/R\$*.class')
include('**/*.class')
}
打開gradle命令列表(在as的右側,看到沒?)
找到該模塊的的other選項
找到 makeJar
ok,這樣就編譯好了,接下來復制到插件的libs里 provided files一下即可。
這里比較麻煩的事是,每當你修改過這個依賴模塊的代碼都需要重寫打包一份jar。項目上線后如果宿主沒有升級,那么最好不要改動依賴模塊中的代碼。
v7包
1.插件布局加載后莫名其妙的多了一些外邊距,無法全屏 獨立運行是正常的
答:
插件不能共享資源宿主的v7包,注意如果你違反這條去嘗試開發插件。會導致你的插件apk布局莫名其妙的多出一些邊距。
注意:
即便插件中你沒有依賴v7包,也是可以使用AppCompatActivity的。但是包里不會包含v7包的資源。
是因為SdkVersion版本過高所以可以直接使用。
解決辦法:
在插件中單獨依賴一份v7包,而不是共享宿主的。
2.插件中加載的布局是上一個宿主的布局
答:
你使用了基礎的Activity,沒有使用v7包里的AppCompatActivity并且關閉了 useAppCompat = false
解決辦法:
如果你的拋資源找不到錯誤,先嘗試使用RePlugin.getPluginContext() 取獲取資源。
加載布局文件配合 LayoutInflater.from()。塞入View。或者直接替換成AppCompatActivity就沒有這個問題了。(推薦用AppCompatActivity問題會少很多)
插件橫屏
插件目前manifest配置了橫屏是無效的。這也許是坑位導致的,可以動態在onCreate的時候改變一下
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
·····
}
熱更新插件
wiki文檔里已經講過了,對于沒有啟動(加載過)的插件是可以安裝后就運行的。但是若插件被啟動過或正在運行時則不行。針對特殊的應用場景不得不重啟app,而且還是主動重啟。
那么發現如果開啟了 persistentEnable = true 常駐應用內存。(就是一個服務)會導致即便重啟了app,插件安裝后還是沒有被更新。這里迫使我關掉了persistentEnable選項,隨后重啟后就成功更新了。注意我這里說的重啟是非root下,應用自己殺死自己,而非用戶主動kill掉。
坑位之顯示Intent無效
比如廣播,這種如果你試圖在配置文件中靜態注冊的方式去聲明一個廣播。并沒有給出。簡單來說就是intent-filter沒有設置。
正確的做法是使用隱式Intent。
代碼如下:
<receiver android:name=".xxx$AlarmReceiver" >
<intent-filter>
<action android:name="xxx" />
</intent-filter>
</receiver>
Intent intent = new Intent();
intent.setAction("xxx");
這樣就可以了。因為坑位上目前沒有使用顯示調用的方式。
插件和宿主同工程的問題
如果你還沒有建項目,兄弟,聽我一句勸。別建在同一個工程下。如果你已經建立了,趕快剝離。有毒 有毒。準備折騰死就放在一起吧。后面的毛病越來越多。雖然我之前也是放在了一個工程下強行編譯過去了。但是實際后面的體驗告訴我出了很多問題。
1.編譯會滿,資源占用更多。
2.開發混亂,不利于管理。
3.莫名其妙的打包錯誤。比如下方這樣的:(注意:這個錯誤是突然莫名其妙出現的,我發誓在出錯誤之前沒有碰過依賴和gradle里的配置。)
* What went wrong:
Execution failed for task ':app:rpGenerateReleaseBuiltinJson'.
> java.util.zip.ZipException: zip file is empty
詳細日志省略,見Issues:
https://github.com/Qihoo360/RePlugin/issues/380
幽靈魔術
什么叫幽靈魔術問題?就和變魔術一樣,我好像沒有改什么邏輯性的代碼,突然bug又好了。
多半是你動了rePlugin中的gradle里的配置項,可能留下了上一次的緩存在里面,你要做的就是每當改動了gradle里的配置最好搭配Clean Project一下。如下圖:
然后有其他問題可以去參考https://github.com/Qihoo360/RePlugin/issues。如果找不到的情況下可以加官方的群。里面還是比較活躍的。
這里再次說明一個問題,跑demo玩測一測和距離正式項目使用還是有很大的區別的。很多問題在demo里看不出來的,只有真正用的時候才會踩到。盡管說replugin的文章說只hook了一個點來確保穩定性。但是由于開發人員對框架本身的不夠熟悉,和存在的一些bug。導致接入成本不能說極低了。如果要考慮團隊使用,最好由提前做有一個人來做預研接入再推廣給大家使用。熟悉這種模式后,可能會是如虎添翼。