绑定到Android上的AIDL远程服务

qltillow  于 2022-12-31  发布在  Android
关注(0)|答案(1)|浏览(135)

我有一个Android应用程序,它指定了两个AIDL文件和一个服务。这个服务应该从另一个应用程序调用AIDL上定义的方法。我已经按照Android Documentation on AIDL实现了AIDL文件和服务(见下面的代码)。
然后,我创建了一个非常简单的客户端应用(如下所示)来绑定到服务并调用AIDL文件中定义的方法。然而,bindService总是返回false,并指出找不到Intent。以下是我尝试在客户端正确引用Intent的一些事情:

Intent intent = new Intent("a.b.c.service");
intent.setPackage("a.b.c");

---

Intent intent = new Intent("service");
intent.setPackage("a.b.c");

---

Intent intent = new Intent();
intent.setClassName("a.b.c", "a.b.c.services.MyService");

---

Intent intent = new Intent();
intent.setClassName("a.b.c.services", "a.b.c.services.MyService");

---

Intent intent = new Intent();
intent.setClassName("a.b.c", ".services.MyService");

---

Intent intent = new Intent();
intent.setAction("service");
intent.setPackage("a.b.c");
intent.setClassName("a.b.c", ".services.MyService");

---

Intent intent = new Intent();
intent.setAction("service");
intent.setClassName("a.b.c", ".services.MyService");

如果我从服务所在的同一应用程序尝试,我可以使用以下命令,它将正常工作:

Intent intent = new Intent(this, MyService.class);

但由于这是一个远程服务,我无法从客户端应用程序访问MyService类,因此无法找到任何使其工作的方法。
我想知道通过很多StackOverflow职位没有任何运气。
Android: Binding to a remote service如何使用AIDL远程服务来处理不同客户端的并发请求?Android Bind Service returns false every time
在这种情况下,我应该如何说明我的意图?
先谢了。
相关代码:

    • I服务接口辅助工具**
package a.b.c;

import a.b.c.IServiceInterfaceGetStuffCallback;

interface IServiceInterface
{
    void getStuff(String arg1, IServiceInterfaceGetStuffCallback callback);
}
    • I服务接口获取内容回调**
package a.b.c;

interface IServiceInterfaceGetStuffCallback
{
    void onGetStuffResponse(String arg1, boolean arg2, int arg3, int arg4);
}

a.b.c./services/MyService.java

public class MyService extends Service
{
    private final MyService self = this;
    private MyServiceHandler handler = null;
    private final HandlerThread handlerThread = new HandlerThread("AidlServiceThread");

    //Callbacks
    private final ArrayList<IServiceInterfaceGetStuffCallback> getStuffCallbacks = new ArrayList<>();

    private final int MY_SERVICE_GET_STUFF_MSG                                   = 1;

    public MyService()
    {
    }

    @Override
    public IBinder onBind(Intent intent)
    {
        // Handler Thread handling all callback methods
        handlerThread.start();
        handler = new MyServiceHandler(handlerThread.getLooper());

        return mBinder;
    }

    IServiceInterface.Stub mBinder = new IServiceInterface.Stub()
    {
        @Override
        public void getStuff(String arg1, IServiceInterfaceGetStuffCallback callback) throws RemoteException
        {
            //Register the callback internally
            getStuffCallbacks.add(callback);
            final int cbIndex = getStuffCallbacks.size() - 1;

            getStuff((arg1, arg2, arg3, arg4) ->
            {
                MyServiceResponse response = new MyServiceResponse();
                response.arg1 = arg1;
                response.arg2 = arg2;
                response.arg3 = arg3;
                response.arg4 = arg4;

                Message message = handler.obtainMessage();
                message.arg1 = cbIndex;
                message.obj = response;
                message.what = MY_SERVICE_GET_STUFF_MSG;

                handler.sendMessage(message);
            });
        }
    };

    private class MyServiceHandler extends Handler
    {
        int callbackIndex = 0;

        MyServiceHandler (Looper looper)
        {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg)
        {
            callbackIndex = msg.arg1;
            MyServiceHandler response = (MyServiceHandler)msg.obj;

            switch (msg.what)
            {
                case MY_SERVICE_GET_STUFF_MSG:
                {
                    try
                    {                        
getStuffCallbacks.get(callbackIndex).onGetStuffResponse(response.arg1, response.arg2, response.arg3, response.arg4);
                    }
                    catch (RemoteException e)
                    {
                        e.printStackTrace();
                    }

                    break;
                }
                default:
                    break;
            }
        }
    }

    private static class MyServiceResponse
    {
        public String arg1;
        public boolean arg2;
        public int arg3;
        public int arg4;
    }
}
    • Android清单**
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="a.b.c">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />

    <permission
        android:name="a.b.c.myservice"
        android:protectionLevel="signature" />

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|keyboard|colorMode|density|navigation|fontScale|layoutDirection|locale|mcc|mnc|smallestScreenSize|touchscreen|uiMode">

        (...)

        <service
            android:name="a.b.c.services.MyService"
            android:enabled="true"
            android:exported="true"
            android:permission="a.b.c.myservice">
            <intent-filter>
                <action android:name="a.b.c.myservice" />
            </intent-filter>
        </service>
    </application>

</manifest>

Client app - MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener
{
    private final String TAG = "aidltest";

    MainActivity self = this;
    IServiceInterface service = null;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.btn_get_stuff).setOnClickListener(this);
    }

    @Override
    public void onClick(View view)
    {
        if (view.getId() == R.id.btn_get_stuff)
            getStuff();
    }

    void getStuff()
    {
        Log.e(TAG, "getStuff invoked");

        Intent intent = new Intent("a.b.c.myservice");
        intent.setPackage("a.b.c");

        boolean res = getApplicationContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);

        Log.e(TAG, "Service binding result: " + res);
    }

    private ServiceConnection serviceConnection = new ServiceConnection()
    {
        public void onServiceConnected(ComponentName className, IBinder service)
        {
            // This is called when the connection with the service has been
            // established, giving us the service object we can use to
            // interact with the service.  We are communicating with our
            // service through an IDL interface, so get a client-side
            // representation of that from the raw service object.
            self.service = IServiceInterface.Stub.asInterface(service);

            Log.e(TAG, "ServiceInterface attached");
        }

        public void onServiceDisconnected(ComponentName className)
        {
            service = null;
            Log.e(TAG, "Service disconnected");
        }
    };
}
myzjeezk

myzjeezk1#

以下更改对我有效:
1.按如下方式调整清单:

<service
    android:name="a.b.c.services.MyService"
    android:enabled="true"
    android:exported="true"
    android:permission="a.b.c.myservice">
    <intent-filter>
        <action android:name="a.b.c.myservice" />
        <category android:name="android.intent.category.DEFAULT"/>  <---- NEW LINE
    </intent-filter>
</service>

1.运行adb shell pm list packages并获取您声明服务的apk的软件包id,这是在步骤3中构建Intent所需的。
1.调整getStuff方法,如下所示:

void getStuff() {
    Log.e(TAG, "getStuff invoked");

    Intent intent = new Intent("a.b.c.myservice");  // This is the value you used in the action for your service as declared in the manifest.
    intent.setPackage(PACKAGE_ID); // This is the value you retrieved in step 2.

    boolean res = getApplicationContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);

    Log.e(TAG, "Service binding result: " + res);
}

相关问题