Android中使用AIDL实现进程通信

前言

关于使用AIDL实现两个APP(跨进程)通信,我们通常把两个APP分别叫做服务端和客户端。本文不讲原理,只给最简易的案例。

一、服务端APP实现

1. 在src/main/aidl目录下新建一个.aidl文件,然后在.aidl文件中定义需要开放的接口,如下:

java 复制代码
package com.test.aidl;

import com.test.aidl.ActionCallback;

interface OpenData {

    void cycleData(String linData);

    boolean handshake(int cmdNumber);

    void listenerData(ActionCallback actionCallback);

}
java 复制代码
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方法,如下所示:

java 复制代码
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中注册,并增加相关属性的申明,如下:

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文件中增加必须的权限:

xml 复制代码
<!--条件测试3------------必须-->
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />

3. 封装一个AIDL客户端管理类,如下:

java 复制代码
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. 把客户端绑定到服务端去,并发送数据,代码如下:

java 复制代码
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();
            }
        });

    }
}

有问题,评论区见!

相关推荐
androidwork3 小时前
Android LinearLayout、FrameLayout、RelativeLayout、ConstraintLayout大混战
android·java·kotlin·androidx
每次的天空3 小时前
Android第十三次面试总结基础
android·面试·职场和发展
wu_android3 小时前
Android 相对布局管理器(RelativeLayout)
android
李斯维5 小时前
循序渐进 Android Binder(二):传递自定义对象和 AIDL 回调
android·java·android studio
androidwork5 小时前
OkHttp 3.0源码解析:从设计理念到核心实现
android·java·okhttp·kotlin
像风一样自由6 小时前
【001】frida API分类 总览
android·frida
casual_clover6 小时前
Android 之 kotlin 语言学习笔记四(Android KTX)
android·学习·kotlin
移动开发者1号7 小时前
Android 大文件分块上传实战:突破表单数据限制的完整方案
android·java·kotlin
移动开发者1号7 小时前
单线程模型中消息机制解析
android·kotlin
每次的天空10 小时前
Android第十五次面试总结(第三方组件和adb命令)
android