前言
关于使用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() {@Overridepublic void cycleData(String linData) throws RemoteException {Log.e("MyAidlData", "------------------cycleData---------------------");Log.e("MyAidlData", "Data=" + linData);}@Overridepublic boolean handshake(int cmdNumber) throws RemoteException {Log.e("MyAidlData", "------------------handshake---------------------");Log.e("MyAidlData", "Data=" + cmdNumber);return true;}@Overridepublic 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();}}}};@Overridepublic IBinder onBind(Intent intent) {return binder;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return START_STICKY;}}
注意:Service需要再AndroidManifest.xml中注册,并增加相关属性的申明,如下:
<serviceandroid: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{@Overridepublic 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 {@Overrideprotected 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() {@Overridepublic void onClick(View v) {AIDLClient.getInstance().sendCycleData("哈哈哈哈");}});findViewById(R.id.startSend2).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {AIDLClient.getInstance().sendHandShake(666);}});findViewById(R.id.startSend3).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {AIDLClient.getInstance().registerListener();}});}
}