26
2017
09

Android之使用AIDL进行IPC(一)

写在前面

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

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

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

结构和流程

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

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

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

服务端

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

接口准备

首先新建ILicense.aidl文件:

// ILicense.aidl
package com.jdnew.serverapp.aidl;

// Declare any non-default types here with import statements
import 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.aidl
package com.jdnew.serverapp.aidl;

// Declare any non-default types here with import statements

parcelable 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。

上一篇:访问Google的两种方法 下一篇:java之环境变量