Android之使用AIDL进行IPC(一)

来源:互联网 发布:三国吴国知乎 编辑:程序博客网 时间:2024/06/04 22:47

写在前面

在前面有一篇是用Messenger来进行IPC(Android之使用Messenger进行IPC),Messenger是对AIDL的一个封装,也就是其下面还是AIDL,本篇就是直接用AIDL来实现。

我觉得还是要分开多篇来记录,这一篇主要是记录怎么实现,之后再记录一些原理性的东西。

这里是在一道题目的背景下来实现的,所以有些东西我们可以忽略,在这篇博客里我们应该是重点在AIDL上。完整的代码在这里:GitHub。

结构和流程

我们只要关注一个整体的结构先:本Project有三个module,分别是app,licensekeylibrary和serverapp。那么app和serverapp就是两个不同的进程,我们要实现的是这两者的交互,

Created with Raphaël 2.1.0appappserverappserverapp提交生成证书的数据对数据进行处理返回证书提交校验数据对数据进行校验返回校验结果

licensekeylibrary是一个依赖库,他们两者都有依赖,主要是在这个题目下用来做一些分装和工具类的提供而已。

服务端

先看下服务端的项目结构:
这里写图片描述
当我们右键新建AIDL文件的时候,AS就会自动帮我们建立aidl文件夹(就蓝色的那个),所以之后我们的aidl文件都写在这个文件夹下即可,而且因为客户端也是要跟服务端一样有同样的aidl文件,所以拷贝也方便。

接口准备

首先新建ILicense.aidl文件:

// ILicense.aidlpackage com.jdnew.serverapp.aidl;// Declare any non-default types here with import statementsimport com.jdnew.serverapp.aidl.RootLicenseData;interface ILicense {   RootLicenseData returnLicense(String licenseData);   String returnCheckResult(String submitData);}

这里主要是建立与客户端通信的接口,returnLicense方法主要是接收客户端提交的licenseData,然后经过一系列处理后返回RootLicenseData 对象给客户端;returnCheckResult方法也类似,主要是接收客户端提交的submitData,然后返回String校验结果给客户端。
因为我们这里用到了一个自定义类RootLicenseData,所以有几个地方要注意,首先这个类必须实现Parcelable:

public class RootLicenseData implements Parcelable {    private String license;    private byte[] rsaPublicKey;    public String getLicense() {        return license;    }    public void setLicense(String license) {        this.license = license;    }    public byte[] getRsaPublicKey() {        return rsaPublicKey;    }    public void setRsaPublicKey(byte[] rsaPublicKey) {        this.rsaPublicKey = rsaPublicKey;    }    public RootLicenseData (String license , byte[] rsaPublicKey){        this.license = license;        this.rsaPublicKey = rsaPublicKey;    }    protected RootLicenseData(Parcel in) {        license = in.readString();        rsaPublicKey = in.createByteArray();    }    public static final Creator<RootLicenseData> CREATOR = new Creator<RootLicenseData>() {        @Override        public RootLicenseData createFromParcel(Parcel in) {            return new RootLicenseData(in);        }        @Override        public RootLicenseData[] newArray(int size) {            return new RootLicenseData[size];        }    };    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel parcel, int i) {        parcel.writeString(license);        parcel.writeByteArray(rsaPublicKey);    }}

另外它需要一个同名的aidl文件,RootLicenseData.aidl

// RootLicenseData.aidlpackage com.jdnew.serverapp.aidl;// Declare any non-default types here with import statementsparcelable RootLicenseData;

创建完后记得rebuild一下,让IDE自动生成一些东西。

服务端实现

一些基础的弄好后,就要开始服务端的实现,部分代码如下:

public class LicenseService extends Service {    private final String TAG = "LicenseService";    private Binder linsenseBinder = new ILicense.Stub() {        @Override        public com.jdnew.serverapp.aidl.RootLicenseData returnLicense(String licenseData) throws RemoteException {           //对传入的licenseData做处理然后写入到rootLicenseData里返回            RootLicenseData rootLicenseData = new RootLicenseData(licenseKey, rsaPublicKey);            return rootLicenseData;        }        @Override        public String returnCheckResult(String submitData) throws RemoteException {           //对传入的submitData做处理,并返回String结果           return "result";    };    @Nullable    @Override    public IBinder onBind(Intent intent) {        return linsenseBinder;    }}

注册服务

接着在serverapp的Manifest文件里注册该服务:

<service android:name="com.jdnew.serverapp.service.LicenseService"            android:exported="true">            <intent-filter>                <category android:name="android.intent.category.DEFAULT"/>                <action android:name="com.jdnew.serverapp.service.LicenseService"/>            </intent-filter>        </service>

好了,接下来看app客户端:

客户端

前面说过,客户端需要与服务端同样的aidl,所以我们把服务端的拷贝过来:
这里写图片描述

然后是调用Service的代码:

private ILicense mILicense;    private ServiceConnection mServiceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            mILicense = ILicense.Stub.asInterface(service);        }        @Override        public void onServiceDisconnected(ComponentName name) {        }    };

然后就是对ILicense的使用(部分代码如下):

public void genLicenseKey(String name) {           RootLicenseData rootLicenseData = mILicense.returnLicense(genLicenseKeyUtil.getDataToGenLicense(name)) ;    }    public void submitData(String licenseKey) {        try {            String result = mILicense.returnCheckResult(submitData);            if (result.equals("true")) {              mIRegistView1.checkLicenseKeySuccess("验证成功");            }else {                mIRegistView1.checkLicenseKeyFailed("验证失败");            }        } catch (RemoteException e) {            e.printStackTrace();        }    }

然后绑定服务即可:

Intent intent = new Intent();        intent.setAction("com.jdnew.serverapp.service.LicenseService");        intent.setPackage("com.jdnew.serverapp");        mContext.bindService(intent , mServiceConnection , Context.BIND_AUTO_CREATE);

记得这里Intent要setPackage,不然在5.0以上会报错。
这样我们就完成了一个简单的AIDL。