開源了一款Android的IPC庫AndLinker,結合了AIDL和Retrofit的特性,支持RxJava

前言

工作中經常會遇到進程間通信的需求,但每次通過AIDL實現又覺得步驟十分的繁瑣。因此用業余時間自己設計并開源了這款IPC庫。設計思路來源于Retrofit通過動態代理生成實現類的這種方式,把AIDL與Retrofit的特性完美的結合起來。

這是你們沒有體驗過的全新方式,只需體驗三分鐘,你就會像我一樣,愛上這款開源庫~

項目地址:https://github.com/codezjx/AndLinker

簡介

AndLinker是一款Android上的IPC (進程間通信) 庫,結合了AIDLRetrofit的諸多特性,且可以與RxJavaRxJava2的Call Adapters無縫結合使用。項目的設計與部分代碼參考了偉大的Retrofit項目。

配置

在項目根目錄的build.gradle中添加jcenter()倉庫

allprojects {
    repositories {
        jcenter()
    }
}

在App的build.gradle中添加如下依賴

dependencies {
    implementation 'com.codezjx.library:andlinker:0.7.1'
}

功能特性

  • 以普通Java接口代替AIDL接口
  • Retrofit一樣生成遠程服務接口的IPC實現
  • 支持的Call Adapters:CallRxJava ObservableRxJava2 Observable & Flowable
  • 支持遠程服務回調機制
  • 支持AIDL的所有數據類型
  • 支持AIDL的所有數據定向tag:inoutinout
  • 支持AIDL的oneway關鍵字

快速開始

使用注解@RemoteInterface修飾遠程服務接口IRemoteService,并實現它

@RemoteInterface
public interface IRemoteService {

    int getPid();

    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}

private final IRemoteService mRemoteService = new IRemoteService() {
    
    @Override
    public int getPid() {
        return android.os.Process.myPid();
    }

    @Override
    public void basicTypes(int anInt, long aLong, boolean aBoolean,
        float aFloat, double aDouble, String aString) {
        // Does something
    }
};

在服務端App中,創建AndLinkerBinder對象,并注冊上面的接口實現。然后在onBind()方法中返回,暴露給客戶端

private AndLinkerBinder mLinkerBinder;

public class RemoteService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
        mLinkerBinder = AndLinkerBinder.Factory.newBinder();
        mLinkerBinder.registerObject(mRemoteService);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mLinkerBinder;
    }
}

在客戶端App中,通過Builder創建AndLinker對象,并通過create()方法生成一個IRemoteService遠程接口的IPC實現

public class BindingActivity extends Activity {

    private AndLinker mLinker;
    private IRemoteService mRemoteService;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mLinker = new AndLinker.Builder(this)
                .packageName("com.example.andlinker")
                .action("com.example.andlinker.REMOTE_SERVICE_ACTION")
                .build();
        mLinker.bind();

        mRemoteService = mLinker.create(IRemoteService.class);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mLinker.unbind();
    }
}

一切就緒,現在mRemoteService對象中的所有方法都是IPC方法,直接調用即可

int pid = mRemoteService.getPid();
mRemoteService.basicTypes(1, 2L, true, 3.0f, 4.0d, "str");

支持數據類型

AndLinker支持AIDL所有數據類型:

  • Java語言中的所有原始類型 (如:intlongcharboolean,等等)
  • String
  • CharSequence
  • Parcelable
  • List (List中的所有元素必須是此列表中支持的數據類型)
  • Map (Map中的所有元素必須是此列表中支持的數據類型)

進階使用

Call Adapters

在客戶端App中,你可以copy并修改遠程服務接口,包裝方法的返回值

@RemoteInterface
public interface IRemoteService {

    Observable<Integer> getPid();

    Call<Void> basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, 
        double aDouble, String aString);
}

AndLinker.Builder中注冊對應的Call Adapter Factory,剩下的步驟基本和Retrofit一致,不再贅述

new AndLinker.Builder(this)
        ...
        .addCallAdapterFactory(OriginalCallAdapterFactory.create()) // Basic
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())  // RxJava2
        .build();

處理遠程服務接口回調

使用@RemoteInterface注解修飾遠程服務回調接口IRemoteCallback

@RemoteInterface
public interface IRemoteCallback {

    void onValueChange(int value);
}

在遠程方法中使用@Callback注解修飾callback參數

void registerCallback(@Callback IRemoteCallback callback);

在客戶端App中,實現上面定義的遠程服務回調接口IRemoteCallback,并且注冊到AndLinker中,就是這么簡單

private final IRemoteCallback mRemoteCallback = new IRemoteCallback() {
    @Override
    public void onValueChange(int value) {
        // Invoke when server side callback
    }
};
mLinker.registerObject(mRemoteCallback);

指定數據定向tag

你可以為遠程方法的參數指定@In@Out,或者@Inout注解,它標記了數據在底層Binder中的流向,跟AIDL中的用法一致

void directionalParamMethod(@In KeyEvent event, @Out int[] arr, @Inout Rect rect);

注意:

  • 所有非原始類型必須指定數據定向tag:@In@Out,或者@Inout,用來標記數據的流向。原始類型默認是@In類型,并且不能指定其他值。
  • 使用@Out或者@Inout修飾的Parcelable參數必須實現SuperParcelable接口,否則你必須手動添加此方法public void readFromParcel(Parcel in)

使用@OneWay注解

你可以在遠程方法上使用@OneWay注解,這會修改遠程方法調用的行為。當使用它時,遠程方法調用不會堵塞,它只是簡單的發送數據并立即返回,跟AIDL中的用法一致

@OneWay
void onewayMethod(String msg);

Proguard配置

proguard-rules.pro文件中添加如下混淆規則,將需要序列化/反序列化的model類給keep掉

-keep class com.example.andlinker.model.** {
    public void readFromParcel(android.os.Parcel);
}

反饋

歡迎各位提issues和PRs!

License

Copyright 2018 codezjx <code.zjx@gmail.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容