两个APK间通过AIDL进行binder通信

参考文章:两个APK间通过AIDL进行binder通信

server端 

创建一个空项目,在项目里面添加如下内容

//MyService.java
package com.example.binderserver;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class MyService extends Service {
    private class MyBinder extends MyInterface.Stub {
        @Override
        public int add(int a, int b) throws RemoteException {
            return a + b;
        }
    }
    private IBinder mBinder = new MyBinder();

    public MyService() {

    }
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}
// MyInterface.aidl
package com.example.binderserver;

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

interface MyInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    int add(int a, int b);
}

aidl文件的创建如下(aidl文件并不会创建在你指定的目录,AS会为aidl文件生成专门的目录):

//AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.binderserver">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.BinderServer"
        tools:targetApi="31" >

        <service android:name=".MyService"
            android:enabled="true"
            android:exported="true">

            <intent-filter>
                <action android:name="com.example.binderserver.MyService"/>
            </intent-filter>

        </service>



    </application>

</manifest>

需要注意的是server没有activity,只有service,所以我们在配置工程的时候配置没有activity启动


目录结构如下:

Client端

创建项目

//MainActivity.java
package com.example.binderclient;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;

import com.google.android.material.snackbar.Snackbar;

import androidx.appcompat.app.AppCompatActivity;

import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;

import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;

import com.example.binderclient.databinding.ActivityMainBinding;

import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;

import com.example.binderserver.MyInterface;

public class MainActivity extends AppCompatActivity {
    private String TAG = "QMH";
    private AppBarConfiguration appBarConfiguration;
    private ActivityMainBinding binding;
    private MyInterface myInterface;
    Button button2;
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.i(TAG, "onServiceConnection");
            myInterface = MyInterface.Stub.asInterface(iBinder);
            try {
                int result = myInterface.add(2, 3);
                Log.i(TAG, "result1111:" + result);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        setSupportActionBar(binding.toolbar);

        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);

        Intent intent = new Intent("com.example.binderserver.MyService");
        intent.setPackage("com.example.binderserver");
        boolean b = bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
        Log.i(TAG, "onCreate : " + b );

        binding.fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        button2 = (Button) findViewById(R.id.button);

        button2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                try {
                    int result = myInterface.add(2, 3);
                    Log.i(TAG, "result1111:" + result);
                } catch (RemoteException e) {
                    Log.i(TAG, "111111111" + e.toString());
                }

            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        return NavigationUI.navigateUp(navController, appBarConfiguration)
                || super.onSupportNavigateUp();
    }
}
//activity_main.xml   就只多添加了一个按钮button
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/Theme.BinderClient.AppBarOverlay">

    </com.google.android.material.appbar.AppBarLayout>

    <include layout="@layout/content_main" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_marginEnd="@dimen/fab_margin"
        android:layout_marginBottom="16dp"
        app:srcCompat="@android:drawable/ic_dialog_email" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button11111" />

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/Theme.BinderClient.PopupOverlay" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>
//注意添加queries    Android 11 之后启动service需要权限
//AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.binderclient">

    <queries>
        <package android:name="com.example.binderserver" />
        <package android:name="com.example.binderclient" />
    </queries>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.BinderClient"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.BinderClient.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

把server端的aidl文件移动过来,注意包名,类名,接口名,及其里面的代码需要保证完全一致,否则会报错

// MyInterface.aidl
package com.example.binderserver;

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

interface MyInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    int add(int a, int b);
}

目录结构如下:

异常

异常1

Client端启动Server端之后调用add方法报错:Binder invocation to an incorrect interface

当进行AIDL跨进程通讯时,如果抛出 Binder invocation to an incorrect interface ,则主要是因为2种情况。

1、最普遍的,客户端 VS 服务端 的AIDL必须保证完全一样,包括包名,类名,接口名,及其里面的代码。否则会抛出以上异常

2、如果第一条符合,则检查下调用的服务是否正确,如果调用的服务不一致或者 服务中返回给客户端的Binder不是客户端想要的,则也会抛出以上异常。

3、如果以上2点,确定没问题,请参考第2点,必定是客户端和服务端的AIDL某处相关代码不一致导致。

我出现这个问题是因为我在Client端创建的aidl文件,然后把server端的aidl文件内容拷贝过来。但是两个文件的包名是不一样的,所以出错了

异常2

通过am startservice -n 启动server端的时候报错。

这好像不是一个异常,服务好像就是启动不起来。我把client端打开之后,server端就可以起来了。

异常3

AppsFilter: interaction: ***BLOCKED 错误

//启动client的时候出现下面log,表示无法启动server端
03-20 16:52:31.209  1371  2038 I AppsFilter: interaction: PackageSetting{524890e com.example.binderclient/10088} -> PackageSetting{5ebfadb com.example.binderserver/10087} BLOCKED
03-20 16:52:31.209  1371  2038 W ActivityManager: Unable to start service Intent { act=com.example.binderserver.MyService pkg=com.example.binderserver } U=0: not found

在 Android 11 ® 上有时跨APP 访问别的进程里面的数据,或者绑定服务的时候会出现这样的问题 

这是 Android 11 增加了安全限制,需要在AndroidManifest.xml清单文件中加入query权限申请,才能检测到手机上安装的三方应用包安装状态

解决办法:
1) 降低SDK版本

修改build.gradle,降低SDK版本为Android 29

或者

2)修改目标软件可见性
在AndroidManifest.xml中添加queries标签声明需要用到的应用包名

<manifest package="com.example.test">
    <queries>
        <package android:name="com.example.service" />
        <package android:name="com.example.client" />
    </queries>
    ...
</manifest>

 

posted @ 2023-03-20 18:13  kongbursi  阅读(177)  评论(0编辑  收藏  举报