展开说说:Android服务之实现AIDL跨应用通信

前面几篇总结了Service的使用和源码执行流程,这里再简单分析一下如果需要Service跨进程通信该怎样做。AIDL(Android Interface Definition Language)Android接口定义语言,用于实现 Android 两个进程之间进行进程间通信(IPC)。

AIDL技术跨进程通信可以理解为是服务端和客户端之间的通信(IPC),定义Service的进程称为服务端,调用服务的进程就是客户端。

分析一下服务端生成aidl、定义Service已经再客户端调用服务。本文使用的两个APP实现,服务端是app,客户端是otherapp。

1、首先准备两个Android工程

我这里就是建一个project然后建两个module,您也可以建两个project反正最后都是安装到同一个手机的两个APP。

2、服务端工程新建aidl文件

建议直接通过鼠标右键-> New -> AIDL -> AIDL File新建一个 adil 文件,build 后生成对应的 java 类。

AIDL文件,setName是我定义的方法:

// IMyAidlInterface.aidl
package com.example.testdemo;

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

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    /**
     * 自定义方法
     */
     void setName(String name);
}

自动生成的java文件:

这里内容不少,里面有个内部类名字叫Stub

public static abstract class Stub extends android.os.Binder implements com.example.testdemo.IMyAidlInterface{

}

Stub 类可以看到我们定义的setName方法。

注意不管你aidl文件名字叫什么编译后的java文件都是在Stub 类定义你的方法。

3、服务端定义Service并创建对应的 Stub 对象;

/**
 * AIDL的服务端
 */
public class MyService extends Service {
    public static final String TAG = "MyService";
    private boolean setServiceRunning = true;

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: " );
        return mStub;
    }

    IMyAidlInterface.Stub mStub = new IMyAidlInterface.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public void setName(String name) throws RemoteException {
            Log.e(TAG, "setName:  收到other说的name= "+name );
        }
    };
}

清单文件注册:

<service
    android:name="com.example.testdemo.service.MyService"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <category android:name="android.intent.category.DEFAULT"></category>
    </intent-filter>
</service>

4、客户端要将服务端这个aidl文件拷贝过来,准备和服务端一模一样的生活环境, 两端的aidl 文件和所在包名必须一致

Intent intentService = new Intent();
intentService.setComponent(new ComponentName("com.example.testdemo","com.example.testdemo.service.MyService"));
boolean b = bindAidl(intentService);
private boolean bindAidl(Intent intent) {
    ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.e(TAG, "onServiceConnected: " );
            IMyAidlInterface iMyAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder);
            //连接成功,调用绑定的service中的方法
            try {
                iMyAidlInterface.setName("Hello 服务端,我是Server端");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.e(TAG, "onServiceDisconnected: " );
        }

        @Override
        public void onBindingDied(ComponentName name) {
            Log.e(TAG, "onBindingDied: " );
        }

        @Override
        public void onNullBinding(ComponentName name) {
            Log.e(TAG, "onNullBinding: " );
        }

    };
    boolean b = bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    Log.e(TAG, "onClick: start-bind   结果="+b);
    return b;
}

注意:

第一:上面代码intentService.setComponent(new ComponentName("com.example.testdemo","com.example.testdemo.service.MyService"));中创建ComponentName实例的第一个参数是应用的包名,不携带类的上层路径;第二个参数是你定义的服务这个Java文件的全类名

第二:bindService方法如果返回报错,需要在androidManifest,xml中加入
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
    tools:ignore="QueryAllPackagesPermission" />
 <queries>
     <package android:name="com.example.testdemo"/>
 </queries>
第三:如果加了上面第二点这些导致项目编译失败,报错"manifest merger failed xxxx " ,需要把根工程里的build.gradle中的classPath升级到3.5.4或以上,比如classpath "com.android.tools.build:gradle:3.5.4"

才疏学浅,如有错误,欢迎指正,多谢。

相关推荐

  1. Android基础-AIDL实现

    2024-07-10 07:34:03       15 阅读
  2. Android进程通信广播

    2024-07-10 07:34:03       21 阅读
  3. Android binder 匿名服务实现双向通信

    2024-07-10 07:34:03       16 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 07:34:03       4 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 07:34:03       5 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 07:34:03       4 阅读
  4. Python语言-面向对象

    2024-07-10 07:34:03       4 阅读

热门阅读

  1. RTK_ROS_导航(4):ROS中空地图的生成与加载

    2024-07-10 07:34:03       10 阅读
  2. PCL + Qt + Ribbon 风格(窗口自由组合) demo展示

    2024-07-10 07:34:03       17 阅读
  3. Android Studio Download Gradle 时慢问题解决

    2024-07-10 07:34:03       6 阅读
  4. ASPICE是汽车软件开发中的质量保证流程

    2024-07-10 07:34:03       11 阅读
  5. 游戏开发面试题2

    2024-07-10 07:34:03       12 阅读
  6. 4.10-7.9

    2024-07-10 07:34:03       10 阅读
  7. Django ModelForm用法详解 —— Python

    2024-07-10 07:34:03       9 阅读
  8. uWSGI 配置 python django 进行发布

    2024-07-10 07:34:03       8 阅读
  9. 源码编译安装LAMP

    2024-07-10 07:34:03       10 阅读