XIPC 一個(gè)Android通用的IPC(進(jìn)程通信)框架识椰。

XIPC

項(xiàng)目地址

一個(gè)Android通用的IPC(進(jìn)程通信)框架。該項(xiàng)目主要是模仿餓了么開源項(xiàng)目Hermes的設(shè)計(jì)進(jìn)行的自我理解改寫叫胖。

演示(請(qǐng)star支持)

demo.gif

apk下載

遠(yuǎn)程服務(wù)應(yīng)用

服務(wù)調(diào)用應(yīng)用

特征

  • 支持自定義服務(wù)接口實(shí)現(xiàn)進(jìn)程通信,無需定義AIDL接口她奥,所有IPC通信就像調(diào)用本地函數(shù)一樣簡(jiǎn)單瓮增。

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

  • 支持進(jìn)程通信的接口回調(diào)绷跑。

  • 支持接口回調(diào)的線程控制。

  • 擁有垃圾回收機(jī)制凡资,防止接口回調(diào)內(nèi)存泄漏砸捏。

  • 支持跨進(jìn)程和跨應(yīng)用通信。

實(shí)現(xiàn)原理

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

  • 注解反射

  • 動(dòng)態(tài)代理

  • AIDL

  • 服務(wù)綁定

  • 進(jìn)程間垃圾回收

詳細(xì)實(shí)現(xiàn)原理請(qǐng)點(diǎn)擊查看

如何使用

1.先在項(xiàng)目根目錄的 build.gradle 的 repositories 添加:

allprojects {
     repositories {
        ...
        maven { url "https://jitpack.io" }
    }
}

2.然后在dependencies添加:

dependencies {
  ...
  implementation 'com.github.xuexiangjys:XIPC:1.0.1'
}

3.最后在Application中注冊(cè)接口服務(wù):

XIPC.init(this);
XIPC.debug(BuildConfig.DEBUG);

//本地只需要注冊(cè)實(shí)現(xiàn)隙赁,無需注冊(cè)接口
XIPC.register(UserManager.class);
XIPC.register(LoadingTask.class);
XIPC.register(FileUtils.class);
XIPC.register(LoadingCallback.class);
XIPC.register(ComputeService.class);

//遠(yuǎn)程注冊(cè)接口
//注冊(cè)包名下的所有定義的服務(wù)接口
XIPC.register("com.xuexiang.remotedemo.service");


如何實(shí)現(xiàn)跨應(yīng)用通信

1.接口定義和實(shí)現(xiàn)

(1)首先我們需要定義一套統(tǒng)一的交互接口垦藏。使用@ClassName@MethodName進(jìn)行修飾。

@ClassName("ComputeService")
public interface IComputeService {
    /**
     * 計(jì)算
     * @param value1 值1
     * @param symbol 算數(shù)符號(hào)
     * @param value2 值2
     * @return
     */
    @MethodName("calculate")
    float calculate(float value1, String symbol, float value2);
}

(2)根據(jù)定義的接口伞访,進(jìn)行具體實(shí)現(xiàn)掂骏。使用@ClassName@MethodName進(jìn)行修飾。這里需要注意注解中的內(nèi)容要和之前定義的接口一一對(duì)應(yīng)厚掷。

@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.注冊(cè)

(1)注冊(cè)接口和實(shí)現(xiàn)類芭挽。對(duì)于調(diào)用App而言,只需要注冊(cè)接口即可蝗肪;對(duì)于被調(diào)用App而言,只需要注冊(cè)實(shí)現(xiàn)類和回調(diào)接口即可蠕趁。統(tǒng)一在Application的onCreate中進(jìn)行注冊(cè)薛闪。

//被調(diào)用App,無需注冊(cè)接口
XIPC.register(UserManager.class);
XIPC.register(LoadingTask.class);
XIPC.register(FileUtils.class);
XIPC.register(LoadingCallback.class);
XIPC.register(ComputeService.class);

//調(diào)用App俺陋,只需要注冊(cè)接口和回調(diào)函數(shù)
XIPC.register("com.xuexiang.remotedemo.service");//該方法注冊(cè)包名下的所有定義的服務(wù)接口

(2)被調(diào)用App需在manifest中注冊(cè)IPC通信服務(wù)豁延。可以使用默認(rèn)的IPCService0服務(wù)腊状,也可以繼承IPCService進(jìn)行自定義通信服務(wù)诱咏。

<service
    android:name="com.xuexiang.xipc.core.channel.IPCService$IPCService0"
    android:process=":remote"
    android:exported="true" />

3.服務(wù)綁定

(1)在調(diào)用前,請(qǐng)先進(jìn)行綁定缴挖,綁定IPC通信服務(wù)袋狞。

XIPC.connectApp(getContext(), "com.xuexiang.xipcdemo"); //這里設(shè)置的是被調(diào)用App的包名

(2)當(dāng)然你也可以設(shè)置綁定的監(jiān)聽回調(diào),以判斷服務(wù)綁定是否成功。

XIPC.setIPCListener(new IPCListener() {
        @Override
        public void onIPCConnected(Class<? extends IPCService> service) {
            ToastUtils.toast("IPC服務(wù)已綁定苟鸯!");
        }
    });

4.獲取實(shí)例訪問

XIPC提供三種訪問的方式:

  • getService: 新建獲取一般定義的服務(wù)接口同蜻。

  • getInstance: 獲取單例。

  • getUtilityClass: 獲取工具類早处。

IComputeService computeService = XIPC.getService(IComputeService.class);
ToastUtils.toast("3*4=" + computeService.calculate(3 , "*", 4));

5.服務(wù)解綁

當(dāng)不再需要服務(wù)訪問時(shí)湾蔓,我們需要及時(shí)地進(jìn)行服務(wù)解綁,回收資源砌梆。

XIPC.disconnect(getContext());

注意事項(xiàng)

在接口注冊(cè)方面

  • 如果兩個(gè)進(jìn)程屬于兩個(gè)不同的app(分別叫App A和App B)默责。App A想訪問App B的一個(gè)類,并且App A的接口和App B的對(duì)應(yīng)實(shí)現(xiàn)類有相同的包名和類名咸包,那么就沒有必要在類和接口上加@ClassName注解桃序。但是要注意使用ProGuard后類名和包名仍要保持一致。

  • 如果接口和類里面對(duì)應(yīng)的方法有相同的名字诉儒,那么也沒有必要在方法上加上@MethodName注解葡缰,同樣注意ProGuard的使用后接口內(nèi)的方法名字必須仍然和類內(nèi)的對(duì)應(yīng)方法名字相同。

  • 如果接口和實(shí)現(xiàn)類中有任意一個(gè)使用了@ClassName@MethodName修飾忱反,那么另一個(gè)也一定要使用相同的@ClassName@MethodName修飾泛释,否則將報(bào)錯(cuò)。

  • 假設(shè)進(jìn)程B需要訪問進(jìn)程A, 如果進(jìn)程A使用了@ClassName注解標(biāo)識(shí)的類温算,那么進(jìn)程B也要對(duì)其對(duì)應(yīng)的接口上加上相同的@ClassName注解怜校,并且進(jìn)程A在進(jìn)程B訪問該接口之前,必須要注冊(cè)注竿。 否則進(jìn)程B使用XIPC.getService()茄茁、XIPC.getInstance()XIPC.getUtilityClass()訪問進(jìn)程A時(shí),XIPC在進(jìn)程A中找不到匹配的類巩割。

  • 所有注冊(cè)的接口類不可以是匿名類和局部類裙顽。

總之為了防止出現(xiàn)各種各樣不匹配或者找不到的問題,最好還是使用@ClassName@MethodName注解宣谈,進(jìn)行一一對(duì)應(yīng)修飾并在Application的onCreate中進(jìn)行注冊(cè)愈犹。

在接口定義方面

  • 如果你不想讓一個(gè)類或者函數(shù)被其他進(jìn)程訪問,可以在上面加上@WithinProcess注解闻丑。

  • 使用XIPC跨進(jìn)程調(diào)用函數(shù)的時(shí)候漩怎,傳入?yún)?shù)的類型可以是原參數(shù)類型的子類,千萬注意不可以是匿名類和局部類嗦嗡,但是回調(diào)函數(shù)例外勋锤。

  • 在接口的參數(shù)方面,如果被調(diào)用的接口函數(shù)的參數(shù)類型和返回值類型是int侥祭、double等基本類型或者String叁执、Object這樣的Java通用類型無需多余操作茄厘。但是千萬注意,這里目前不支持參數(shù)的類型是數(shù)組徒恋。如果需要用到數(shù)組作為參數(shù)蚕断,可以使用自定義對(duì)象去包一下數(shù)組,再進(jìn)行使用入挣。

  • 對(duì)于接口參數(shù)類型是自定義的類亿乳,并且兩個(gè)進(jìn)程分別屬于兩個(gè)不同app,那么你必須在兩個(gè)app中都定義這個(gè)類径筏,且必須保證代碼混淆后葛假,兩個(gè)類仍然有相同的包名和類名。不過你可以適用@ClassName@MethodName注解滋恬,這樣包名和類名在混淆后不同也不要緊了聊训。

  • 如果被調(diào)用的函數(shù)有回調(diào)參數(shù),那么函數(shù)定義中這個(gè)參數(shù)必須是一個(gè)接口恢氯,不能是抽象類带斑。

在接口回調(diào)方面

  • 需要特別注意回調(diào)函數(shù)運(yùn)行的線程。如果進(jìn)程A調(diào)用進(jìn)程B的函數(shù)勋拟,并且傳入一個(gè)回調(diào)函數(shù)供進(jìn)程B在進(jìn)程A進(jìn)行回調(diào)操作勋磕,那么默認(rèn)這個(gè)回調(diào)函數(shù)將運(yùn)行在進(jìn)程A的主線程(UI線程)。如果你不想讓回調(diào)函數(shù)運(yùn)行在主線程敢靡,那么在接口聲明的函數(shù)的對(duì)應(yīng)的回調(diào)參數(shù)之前加上@Background注解挂滓。

  • 如果回調(diào)函數(shù)有返回值的話,請(qǐng)使用@Background注解讓它運(yùn)行在后臺(tái)線程啸胧。如果運(yùn)行在主線程赶站,那么返回值始終為null。

  • 在回調(diào)函數(shù)的引用方面纺念,框架持有回調(diào)函數(shù)的強(qiáng)引用贝椿,這個(gè)可能會(huì)導(dǎo)致內(nèi)存泄漏。為了解決該問題陷谱,你可以在接口聲明的對(duì)應(yīng)回調(diào)參數(shù)前加上@WeakRef注解团秽,這樣XIPC持有的就是回調(diào)函數(shù)的弱引用。如果進(jìn)程的回調(diào)函數(shù)被回收了叭首,而對(duì)方進(jìn)程還在調(diào)用這個(gè)函數(shù)(對(duì)方進(jìn)程并不會(huì)知道回調(diào)函數(shù)被回收),這個(gè)不會(huì)有任何影響踪栋,也不會(huì)造成崩潰焙格。如果回調(diào)函數(shù)有返回值,那么就返回null夷都。

  • @Background@WeakRef注解眷唉,必須在接口中對(duì)應(yīng)的函數(shù)參數(shù)前進(jìn)行添加。如果加在其他地方,將不會(huì)有任何作用冬阳。

其他方面

  • 調(diào)用函數(shù)的時(shí)候蛤虐,任何Context在另一個(gè)進(jìn)程中都會(huì)變成對(duì)方進(jìn)程的application context。

  • 接口參數(shù)的數(shù)據(jù)傳遞默認(rèn)是基于Json的肝陪。

  • 在使用過程中驳庭,出現(xiàn)任何錯(cuò)誤,都會(huì)有相關(guān)日志記錄氯窍,你只需要執(zhí)行XIPC.debug打開調(diào)試即可看見日志饲常。

混淆配置

# 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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市狼讨,隨后出現(xiàn)的幾起案子贝淤,更是在濱河造成了極大的恐慌,老刑警劉巖政供,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件播聪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡布隔,警方通過查閱死者的電腦和手機(jī)离陶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來执泰,“玉大人枕磁,你說我怎么就攤上這事∈趿撸” “怎么了计济?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)排苍。 經(jīng)常有香客問我沦寂,道長(zhǎng),這世上最難降的妖魔是什么淘衙? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任传藏,我火速辦了婚禮,結(jié)果婚禮上彤守,老公的妹妹穿的比我還像新娘毯侦。我一直安慰自己,他們只是感情好具垫,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布侈离。 她就那樣靜靜地躺著,像睡著了一般筝蚕。 火紅的嫁衣襯著肌膚如雪卦碾。 梳的紋絲不亂的頭發(fā)上铺坞,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音洲胖,去河邊找鬼济榨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛绿映,可吹牛的內(nèi)容都是我干的擒滑。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼绘梦,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼橘忱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起卸奉,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤钝诚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后榄棵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凝颇,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年疹鳄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拧略。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瘪弓,死狀恐怖垫蛆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情腺怯,我是刑警寧澤袱饭,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站呛占,受9級(jí)特大地震影響虑乖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晾虑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一疹味、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧帜篇,春花似錦糙捺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至逃沿,卻和暖如春婴渡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背凯亮。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工边臼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人假消。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓柠并,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親富拗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子臼予,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容