XIPC
一個Android通用的IPC(進程通信)框架。該項目主要是模仿餓了么開源項目Hermes的設計進行的自我理解改寫。
演示(請star支持)

apk下載
特征
支持自定義服務接口實現(xiàn)進程通信,無需定義AIDL接口,所有IPC通信就像調用本地函數(shù)一樣簡單。
支持自定義接口服務(服務發(fā)現(xiàn))、獲取單例和獲取工具類方法。
支持進程通信的接口回調。
支持接口回調的線程控制。
擁有垃圾回收機制,防止接口回調內存泄漏。
支持跨進程和跨應用通信。
實現(xiàn)原理
該框架主要使用以下技術實現(xiàn):
注解反射
動態(tài)代理
AIDL
服務綁定
進程間垃圾回收
如何使用
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);
//本地只需要注冊實現(xiàn),無需注冊接口
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");
如何實現(xiàn)跨應用通信
1.接口定義和實現(xiàn)
(1)首先我們需要定義一套統(tǒng)一的交互接口。使用@ClassName和@MethodName進行修飾。
@ClassName("ComputeService")
public interface IComputeService {
/**
* 計算
* @param value1 值1
* @param symbol 算數(shù)符號
* @param value2 值2
* @return
*/
@MethodName("calculate")
float calculate(float value1, String symbol, float value2);
}
(2)根據(jù)定義的接口,進行具體實現(xiàn)。使用@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)注冊接口和實現(xiàn)類。對于調用App而言,只需要注冊接口即可;對于被調用App而言,只需要注冊實現(xiàn)類和回調接口即可。統(tǒng)一在Application的onCreate中進行注冊。
//被調用App,無需注冊接口
XIPC.register(UserManager.class);
XIPC.register(LoadingTask.class);
XIPC.register(FileUtils.class);
XIPC.register(LoadingCallback.class);
XIPC.register(ComputeService.class);
//調用App,只需要注冊接口和回調函數(shù)
XIPC.register("com.xuexiang.remotedemo.service");//該方法注冊包名下的所有定義的服務接口
(2)被調用App需在manifest中注冊IPC通信服務??梢允褂媚J的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)當然你也可以設置綁定的監(jiān)聽回調,以判斷服務綁定是否成功。
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的對應實現(xiàn)類有
相同的包名和類名,那么就沒有必要在類和接口上加@ClassName注解。但是要注意使用ProGuard后類名和包名仍要保持一致。如果接口和類里面對應的方法有相同的名字,那么也沒有必要在方法上加上
@MethodName注解,同樣注意ProGuard的使用后接口內的方法名字必須仍然和類內的對應方法名字相同。如果接口和實現(xiàn)類中有任意一個使用了
@ClassName和@MethodName修飾,那么另一個也一定要使用相同的@ClassName和@MethodName修飾,否則將報錯。假設進程B需要訪問進程A, 如果進程A使用了
@ClassName注解標識的類,那么進程B也要對其對應的接口上加上相同的@ClassName注解,并且進程A在進程B訪問該接口之前,必須要注冊。 否則進程B使用XIPC.getService()、XIPC.getInstance()或XIPC.getUtilityClass()訪問進程A時,XIPC在進程A中找不到匹配的類。所有注冊的接口類不可以是匿名類和局部類。
總之為了防止出現(xiàn)各種各樣不匹配或者找不到的問題,最好還是使用@ClassName和@MethodName注解,進行一一對應修飾并在Application的onCreate中進行注冊。
在接口定義方面
如果你不想讓一個類或者函數(shù)被其他進程訪問,可以在上面加上
@WithinProcess注解。使用XIPC跨進程調用函數(shù)的時候,傳入?yún)?shù)的類型可以是原參數(shù)類型的子類,千萬注意不可以是匿名類和局部類,但是回調函數(shù)例外。
在接口的參數(shù)方面,如果被調用的接口函數(shù)的參數(shù)類型和返回值類型是int、double等基本類型或者String、Object這樣的Java通用類型無需多余操作。但是千萬注意,這里目前不支持參數(shù)的類型是數(shù)組。如果需要用到數(shù)組作為參數(shù),可以使用自定義對象去包一下數(shù)組,再進行使用。
對于接口參數(shù)類型是自定義的類,并且兩個進程分別屬于兩個不同app,那么你必須在兩個app中都定義這個類,且必須保證代碼混淆后,兩個類仍然有相同的包名和類名。不過你可以適用
@ClassName和@MethodName注解,這樣包名和類名在混淆后不同也不要緊了。如果被調用的函數(shù)有回調參數(shù),那么函數(shù)定義中這個參數(shù)必須是一個接口,不能是抽象類。
在接口回調方面
需要特別注意回調函數(shù)運行的線程。如果進程A調用進程B的函數(shù),并且傳入一個回調函數(shù)供進程B在進程A進行回調操作,那么默認這個回調函數(shù)將運行在進程A的主線程(UI線程)。如果你不想讓回調函數(shù)運行在主線程,那么在接口聲明的函數(shù)的對應的回調參數(shù)之前加上
@Background注解。如果回調函數(shù)有返回值的話,請使用
@Background注解讓它運行在后臺線程。如果運行在主線程,那么返回值始終為null。在回調函數(shù)的引用方面,框架持有回調函數(shù)的強引用,這個可能會導致內存泄漏。為了解決該問題,你可以在接口聲明的對應回調參數(shù)前加上@WeakRef注解,這樣XIPC持有的就是回調函數(shù)的弱引用。如果進程的回調函數(shù)被回收了,而對方進程還在調用這個函數(shù)(對方進程并不會知道回調函數(shù)被回收),這個不會有任何影響,也不會造成崩潰。如果回調函數(shù)有返回值,那么就返回null。
@Background和@WeakRef注解,必須在接口中對應的函數(shù)參數(shù)前進行添加。如果加在其他地方,將不會有任何作用。
其他方面
調用函數(shù)的時候,任何Context在另一個進程中都會變成對方進程的application context。
接口參數(shù)的數(shù)據(jù)傳遞默認是基于Json的。
在使用過程中,出現(xiàn)任何錯誤,都會有相關日志記錄,你只需要執(zhí)行
XIPC.debug打開調試即可看見日志。
混淆配置
# xipc
-keep @com.xuexiang.xipc.annotation.* class * {*;}
-keep class * {
@com.xuexiang.xipc.annotation.* <fields>;
}
-keepclassmembers class * {
@com.xuexiang.xipc.annotation.* <methods>;
}