How to call remote android service (IPC) from widget / local service?

I am trying to remotely control live wallpapers from a widget. They are in the same APK, but obviously in different processes. It is not enough for me to cause the “activity” of live wallpapers, since this is a different process. The widget has simple buttons that when clicked

So what (I think) I need is IPC and AIDL.

First I created AIDL on a wallpaper that worked great. It has three methods without additional parameters. But when I added the client to the widget, I got an error telling me that I can not bind to this remote interface, because the widget is already a BroadcastListener. I tried to get button controls without requiring the widget to be a BroadcastListener, but that seems impossible.

Well no problem, right? I just created a service in widgets bound to the remote interface, because although the widget is a broadcast module, there is no service, and everything should be fine.

Or so I thought.

Well, I get widget buttons to call the widget service. Binding to a remote service gives me the following warning:

Unable to start Intent service (act = com.blabla.IRemoteService): not found.

I use getApplicationContext () in the widget service to bind to the remote file. I have a widget service in the manifest, but I do not have a remote service. When I put it there, I get a non-specific InstantiationException.

In Widget Service onStart (), I do this:

getApplicationContext().bindService(new Intent(IWallpaperRemote.class.getName()), mConnection, Context.BIND_AUTO_CREATE); 

I also have...

 private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { mService = IWallpaperRemote.Stub.asInterface(service); isBound = true; Log.i("WidgetServiceConnection", "binding to service succeeded"); } public void onServiceDisconnected(ComponentName className) { mService = null; isBound = false; Log.i("WidgetServiceConnection", "binding to service lost!"); } }; 

My question is: has anyone ever successfully deleted a remote call from a widget to another application? Considering that we are talking about live wallpapers here, and that I am not interested in causing activity in the widget process, but they call function calls inside live wallpapers, what parameters do I have, except for IPC, if any?

And if IPC is the way to go here, what am I doing wrong?

+4
source share
1 answer

I found the answer to my question. To make it easier for others, here is a solution:

When executing a remote service, you must write AIDL, which will be compiled as a stub interface, implementations of this interface (that is, code that executes when someone calls remote methods), and a class that extends "Service", which returns the implementation class to onBind () method. (Normal local service returns null in this method)

Now I do not understand that you MUST have a service definition in the manifest - WITH INTENT FILTER!

Let's say your AIDL is called IRemoteService.aidl, then you have a RemoteService class that looks like this:

 public class RemoteService extends Service { public IBinder onBind(Intent intent) { Log.i("RemoteService", "onBind() called"); return new RemoteServiceImpl(); } /** * The IRemoteInterface is defined through IDL */ public class RemoteServiceImpl extends IRemoteService.Stub { public void remoteDetonateBirthdayCake() throws RemoteException { //your code here } }; } 

In the Android manifest, you want:

 <service android:name="RemoteService"> <intent-filter> <action android:name="com.sofurry.favorites.IRemoteService"></action> </intent-filter> </service> 

Note the name of the service: "RemoteService", not "IRemoteService" or even "RemoteServiceImpl". You need the name of the class that extends the "Service", whose onBind method we have redefined.

To complete this thing, here is the client-side code - and yes, this code also works from another service, for example, from what you started with your widget;)

 IRemoteService mService; RemoteServiceConnection mConnection = new RemoteServiceConnection(); getApplicationContext().bindService(new Intent(IRemoteService.class.getName()), mConnection, Context.BIND_AUTO_CREATE); 

... where RemoteServiceConnection can be an inner class, for example:

 class RemoteServiceConnection implements ServiceConnection { public void onServiceConnected(ComponentName className, IBinder service ) { mService = IRemoteService.Stub.asInterface(service); isBound = true; } public void onServiceDisconnected(ComponentName className) { mService = null; isBound = false; } }; 

And now you can call ..

 mService.remoteDetonateBirthdayCake(); 

In conclusion: make sure that the android manifest has a service stanza, set the “name” to a class that returns the actual implementation in its onBind () method, and you should also have an intent filter with an action definition that points to the AIDL interface.

Tip. If you are calling remote services from an application inside another APK, add the "category" element to the intent filter and set it to DEFAULT.

+13
source

Source: https://habr.com/ru/post/1335128/


All Articles