Android中使用AIDL实现进程通信
前言
关于使用AIDL实现两个APP(跨进程)通信,我们通常把两个APP分别叫做服务端和客户端。本文不讲原理,只给最简易的案例。
一、服务端APP实现
1. 在src/main/aidl目录下新建一个.aidl文件,然后在.aidl文件中定义需要开放的接口,如下:
package com.test.aidl;
import com.test.aidl.ActionCallback;
interface OpenData {
void cycleData(String linData);
boolean handshake(int cmdNumber);
void listenerData(ActionCallback actionCallback);
}
package com.test.aidl;
interface ActionCallback {
void callback(String jsonData);
}
2. 点击工具栏Bulid模块中的Make Project时,会在build目录下生成编译文件,如下所示:
值得注意的是,编译出来的文件中,默认增加了一个stub内部类,这个stub类是Binder的子类,如下所示:
3.定义一个Service,然后把上一步的Stub类实例化,把Stub的对象return给Service的onBind方法,如下所示:
package com.test.server;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.test.aidl.ActionCallback;
import com.test.aidl.OpenData;
public class ListenerService extends Service {
private static final int NOTIFICATION_ID = 1;
private final OpenData.Stub binder = new OpenData.Stub() {
@Override
public void cycleData(String linData) throws RemoteException {
Log.e("MyAidlData", "------------------cycleData---------------------");
Log.e("MyAidlData", "Data=" + linData);
}
@Override
public boolean handshake(int cmdNumber) throws RemoteException {
Log.e("MyAidlData", "------------------handshake---------------------");
Log.e("MyAidlData", "Data=" + cmdNumber);
return true;
}
@Override
public void listenerData(ActionCallback actionCallback) throws RemoteException {
Log.e("MyAidlData", "------------------listenerData---------------------");
if (actionCallback == null) {
Log.e("MyAidlData", "Data=无效监听");
try {
actionCallback.callback("无效监听");
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Log.e("MyAidlData", "Data=监听成功");
try {
actionCallback.callback("监听成功");
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
};
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
}
注意:Service需要再AndroidManifest.xml中注册,并增加相关属性的申明,如下:
<service
android:name="com.test.server.ListenerService"
android:exported="true"><!--条件测试7————必须为true-->
<!--隐式启动:当有匹配<intent-filter>的意图发送时,系统可能会根据定义的过滤规则选择合适的服务进行启动。这种方式依赖于是否有其他组件发送了符合过滤条件的意图。-->
<intent-filter>
<!--条件测试6————必须要与客户端的action一致-->
<action android:name="AAaaBB"/>
</intent-filter>
</service>
二、客户端APP实现
1. 在src/main/aidl目录下新建一个.aidl文件,然后在.aidl文件中定义需要开放的接口代码,如下:
特别注意:这里的【.aidl文件内容】和【文件路径】必须和服务端APP完全一致。
2. 在客户端APP的AndroidManifest.xml文件中增加必须的权限:
<!--条件测试3————必须-->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />
3. 封装一个AIDL客户端管理类,如下:
package com.test.client;
import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.test.aidl.ActionCallback;
import com.test.aidl.OpenData;
public class AIDLClient {
private AIDLClient() {
}
private static class Holder{
public static final AIDLClient INSTANCE=new AIDLClient();
}
public static AIDLClient getInstance(){
return Holder.INSTANCE;
}
private OpenData openData;
private ServiceConnection connection;
/**
* 1.初始化服务连接
*/
public void initConnection(){
connection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
openData = OpenData.Stub.asInterface(service);
Log.d("初始化链接", "连接成功");
}
public void onServiceDisconnected(ComponentName className) {
openData = null;
Log.d("初始化链接", "连接断开");
}
};
}
/**
* 2.获取链接
* @return
*/
public ServiceConnection getConnection() {
return connection;
}
//Tx (分享出去的数据)___________________________________________________________________
public boolean sendCycleData(String cycleData){
try {
if (openData!=null){
openData.cycleData(cycleData);
return true;
}else {
return false;
}
} catch (RemoteException e) {
Log.e("AIDL链接异常",e.toString());
return false;
}
}
public boolean sendHandShake(int number){
try {
if (openData!=null){
openData.handshake(number);
return true;
}else {
return false;
}
} catch (RemoteException e) {
Log.e("AIDL链接异常",e.toString());
return false;
}
}
//Rx (接收服务端发来的数据————回调方式实现)______________________________________________________
public boolean registerListener(){
try {
if (openData!=null){
//这里new MyCall()后期可以把MyCall也变成单例可能更适合(看需求)
openData.listenerData(new MyCall());
return true;
}else {
return false;
}
} catch (RemoteException e) {
Log.e("AIDL链接异常",e.toString());
return false;
}
}
private class MyCall extends ActionCallback.Stub{
@Override
public void callback(String jsonData) throws RemoteException {
Log.e("绑定服务","回调数据="+jsonData);
}
}
}
4. 把客户端绑定到服务端去,并发送数据,代码如下:
package com.test.client;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//第一步:初始化
AIDLClient.getInstance().initConnection();
//第二步:绑定服务
Intent intent = new Intent();
intent.setAction("AAaaBB");//条件测试6————必须与服务端指定的service的name一致
intent.setPackage("com.test.aidltest1");//这个包名必须写服务端APP的包名
boolean re=bindService(intent, AIDLClient.getInstance().getConnection(), Context.BIND_AUTO_CREATE);
Log.e("绑定服务",re ? "成功":"失败");
//第三步:发送数据
findViewById(R.id.startSend1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AIDLClient.getInstance().sendCycleData("哈哈哈哈");
}
});
findViewById(R.id.startSend2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AIDLClient.getInstance().sendHandShake(666);
}
});
findViewById(R.id.startSend3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AIDLClient.getInstance().registerListener();
}
});
}
}