XIPC 一個Android通用的IPC(程序通訊)框架
XIPC
一個Android通用的IPC(程序通訊)框架。該專案主要是模仿餓了麼開源專案Hermes的設計進行的自我理解改寫。
關於我
特徵
-
支援自定義服務介面實現程序通訊,無需定義AIDL介面,所有IPC通訊就像呼叫本地函式一樣簡單。
-
支援自定義介面服務(服務發現)、獲取單例和獲取工具類方法。
-
支援程序通訊的介面回撥。
-
支援介面回撥的執行緒控制。
-
擁有垃圾回收機制,防止介面回撥記憶體洩漏。
-
支援跨程序和跨應用通訊。
實現原理
該框架主要使用以下技術實現:
-
註解反射
-
動態代理
-
AIDL
-
服務繫結
-
程序間垃圾回收
演示(請star支援)
apk下載
如何使用
1.先在專案根目錄的 build.gradle 的 repositories 新增:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
2.然後在dependencies新增:
dependencies { ... implementation 'com.github.xuexiangjys:XIPC:1.0.1' }
3.最後在Application中註冊介面服務:
XIPC.init(this); XIPC.debug(BuildConfig.DEBUG); //本地只需要註冊實現,無需註冊介面 XIPC.register(UserManager.class); XIPC.register(LoadingTask.class); XIPC.register(FileUtils.class); XIPC.register(LoadingCallback.class); XIPC.register(ComputeService.class); //遠端註冊介面 //註冊包名下的所有定義的服務介面 XIPC.register("com.xuexiang.remotedemo.service");
如何實現跨應用通訊
1.介面定義和實現
(1)首先我們需要定義一套統一的互動介面。使用@ClassName
和@MethodName
進行修飾。
@ClassName("ComputeService")
public interface IComputeService {
/**
* 計算
* @param value1 值1
* @param symbol 算數符號
* @param value2 值2
* @return
*/
@MethodName("calculate")
float calculate(float value1, String symbol, float value2);
}
(2)根據定義的介面,進行具體實現。使用@ClassName
和@MethodName
進行修飾。這裡需要注意註解中的內容要和之前定義的介面一一對應。
@ClassName("ComputeService")
public class ComputeService implements IComputeService {
@Override
@MethodName("calculate")
public float calculate(float value1, String symbol, float value2) {
float result;
switch(symbol) {
case "+":
result = value1 + value2;
break;
case "-":
result = value1 - value2;
break;
case "*":
result = value1 * value2;
break;
case "/":
result = value1 / value2;
break;
default:
result = value1 + value2;
break;
}
return result;
}
}
2.註冊
(1)註冊介面和實現類。對於呼叫App而言,只需要註冊介面即可;對於被呼叫App而言,只需要註冊實現類和回撥介面即可。統一在Application的onCreate中進行註冊。
//被呼叫App,無需註冊介面
XIPC.register(UserManager.class);
XIPC.register(LoadingTask.class);
XIPC.register(FileUtils.class);
XIPC.register(LoadingCallback.class);
XIPC.register(ComputeService.class);
//呼叫App,只需要註冊介面和回撥函式
XIPC.register("com.xuexiang.remotedemo.service");//該方法註冊包名下的所有定義的服務介面
(2)被呼叫App需在manifest
中註冊IPC通訊服務。可以使用預設的IPCService0
服務,也可以繼承IPCService
進行自定義通訊服務。
<service
android:name="com.xuexiang.xipc.core.channel.IPCService$IPCService0"
android:process=":remote"
android:exported="true" />
3.服務繫結
(1)在呼叫前,請先進行繫結,繫結IPC通訊服務。
XIPC.connectApp(getContext(), "com.xuexiang.xipcdemo"); //這裡設定的是被呼叫App的包名
(2)當然你也可以設定繫結的監聽回撥,以判斷服務繫結是否成功。
XIPC.setIPCListener(new IPCListener() {
@Override
public void onIPCConnected(Class<? extends IPCService> service) {
ToastUtils.toast("IPC服務已繫結!");
}
});
4.獲取例項訪問
XIPC提供三種訪問的方式:
-
getService: 新建獲取一般定義的服務介面。
-
getInstance: 獲取單例。
-
getUtilityClass: 獲取工具類。
IComputeService computeService = XIPC.getService(IComputeService.class);
ToastUtils.toast("3*4=" + computeService.calculate(3 , "*", 4));
5.服務解綁
當不再需要服務訪問時,我們需要及時地進行服務解綁,回收資源。
XIPC.disconnect(getContext());
注意事項
在介面註冊方面
-
如果兩個程序屬於兩個不同的app(分別叫App A和App B)。App A想訪問App B的一個類,並且App A的介面和App B的對應實現類有
相同的包名和類名
,那麼就沒有必要在類和介面上加@ClassName
註解。但是要注意使用ProGuard後類名和包名仍要保持一致。 -
如果介面和類裡面對應的方法有相同的名字,那麼也沒有必要在方法上加上
@MethodName
註解,同樣注意ProGuard的使用後接口內的方法名字必須仍然和類內的對應方法名字相同。 -
如果介面和實現類中有任意一個使用了
@ClassName
和@MethodName
修飾,那麼另一個也一定要使用相同的@ClassName
和@MethodName
修飾,否則將報錯。 -
假設程序B需要訪問程序A, 如果程序A使用了
@ClassName
註解標識的類,那麼程序B也要對其對應的介面上加上相同的@ClassName註解,並且程序A在程序B訪問該介面之前,必須要註冊。 否則程序B使用XIPC.getService()
、XIPC.getInstance()
或XIPC.getUtilityClass()
訪問程序A時,XIPC在程序A中找不到匹配的類。 -
所有註冊的介面類不可以是匿名類和區域性類。
總之為了防止出現各種各樣不匹配或者找不到的問題,最好還是使用@ClassName
和@MethodName
註解,進行一一對應修飾並在Application的onCreate中進行註冊。
在介面定義方面
-
如果你不想讓一個類或者函式被其他程序訪問,可以在上面加上
@WithinProcess
註解。 -
使用XIPC跨程序呼叫函式的時候,傳入引數的型別可以是原引數型別的子類,千萬注意不可以是匿名類和區域性類,但是回撥函式例外。
-
在介面的引數方面,如果被呼叫的介面函式的引數型別和返回值型別是int、double等基本型別或者String、Object這樣的Java通用型別無需多餘操作。但是千萬注意,這裡目前不支援引數的型別是陣列。如果需要用到陣列作為引數,可以使用自定義物件去包一下陣列,再進行使用。
-
對於介面引數型別是自定義的類,並且兩個程序分別屬於兩個不同app,那麼你必須在兩個app中都定義這個類,且必須保證程式碼混淆後,兩個類仍然有相同的包名和類名。不過你可以適用
@ClassName
和@MethodName
註解,這樣包名和類名在混淆後不同也不要緊了。 -
如果被呼叫的函式有回撥引數,那麼函式定義中這個引數必須是一個介面,不能是抽象類。
在介面回撥方面
-
需要特別注意回撥函式執行的執行緒。如果程序A呼叫程序B的函式,並且傳入一個回撥函式供程序B在程序A進行回撥操作,那麼預設這個回撥函式將執行在程序A的主執行緒(UI執行緒)。如果你不想讓回撥函式執行在主執行緒,那麼在介面宣告的函式的對應的回撥引數之前加上
@Background
註解。 -
如果回撥函式有返回值的話,請使用
@Background
註解讓它執行在後臺執行緒。如果執行在主執行緒,那麼返回值始終為null。 -
在回撥函式的引用方面,框架持有回撥函式的強引用,這個可能會導致記憶體洩漏。為了解決該問題,你可以在介面宣告的對應回撥引數前加上@WeakRef註解,這樣XIPC持有的就是回撥函式的弱引用。如果程序的回撥函式被回收了,而對方程序還在呼叫這個函式(對方程序並不會知道回撥函式被回收),這個不會有任何影響,也不會造成崩潰。如果回撥函式有返回值,那麼就返回null。
-
@Background
和@WeakRef
註解,必須在介面中對應的函式引數前進行新增。如果加在其他地方,將不會有任何作用。
其他方面
-
呼叫函式的時候,任何Context在另一個程序中都會變成對方程序的application context。
-
介面引數的資料傳遞預設是基於Json的。
-
在使用過程中,出現任何錯誤,都會有相關日誌記錄,你只需要執行
XIPC.debug
開啟除錯即可看見日誌。
混淆配置
# xipc
-keep @com.xuexiang.xipc.annotation.* class * {*;}
-keep class * {
@com.xuexiang.xipc.annotation.* <fields>;
}
-keepclassmembers class * {
@com.xuexiang.xipc.annotation.* <methods>;
}
特別感謝
https://github.com/Xiaofei-it/Hermes