写在前面
在前面有一篇是用Messenger来进行IPC(Android之使用Messenger进行IPC),Messenger是对AIDL的一个封装,也就是其下面还是AIDL,本篇就是直接用AIDL来实现。
我觉得还是要分开多篇来记录,这一篇主要是记录怎么实现,之后再记录一些原理性的东西。
这里是在一道题目的背景下来实现的,所以有些东西我们可以忽略,在这篇博客里我们应该是重点在AIDL上。完整的代码在这里:GitHub。
结构和流程
我们只要关注一个整体的结构先:本Project有三个module,分别是app,licensekeylibrary和serverapp。那么app和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。