XIPC 一個Android通用的IPC(進程通信)框架。

XIPC

項目地址

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

演示(請star支持)

demo.gif

apk下載

遠程服務應用

服務調用應用

特征

  • 支持自定義服務接口實現(xiàn)進程通信,無需定義AIDL接口,所有IPC通信就像調用本地函數(shù)一樣簡單。

  • 支持自定義接口服務(服務發(fā)現(xiàn))、獲取單例和獲取工具類方法。

  • 支持進程通信的接口回調。

  • 支持接口回調的線程控制。

  • 擁有垃圾回收機制,防止接口回調內存泄漏。

  • 支持跨進程和跨應用通信。

實現(xiàn)原理

該框架主要使用以下技術實現(xiàn):

  • 注解反射

  • 動態(tài)代理

  • AIDL

  • 服務綁定

  • 進程間垃圾回收

詳細實現(xiàn)原理請點擊查看

如何使用

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>;
}

特別感謝

https://github.com/Xiaofei-it/Hermes

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容