Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to choose which service to handle an intent
    text
    copied!<p>I have an app which uses a service that is included in the application's package.</p> <p>I am now making a new app which uses a newer version the same service, bundled within its own application package.</p> <p>If only one app is installed on the device, this works fine. However, if both apps are installed on the device, they both use the service from whichever package was least recently installed -- i.e., the oldest one. This is problematic for two reasons: 1) the old service doesn't handle the new calls (obviously) 2) when using the service bundled with the other app, the service ends up using that other app's saved data instead of its own.</p> <p>Short-term, I really just want each app to talk to its own version of the service. Is it possible to do this without making each bundled service respond to a unique intent, and having each app use that unique intent?</p> <p>Long-term, it would be nice to optionally have both apps talk to the newest version of the service, and have them share data, and play nice with either app getting uninstalled. What's the right way to do that? The data is primarily in an SQLite database, which gets stored where <code>Context.getDatabasePath()</code> specifies, which is of course application-specific and wiped if that application is uninstalled.</p> <p>Here's what I've tried so far:</p> <p>I can use <code>PackageManager.queryIntentServices()</code> to get a list of ResolveInfo with both versions of the service. By looking at <code>ResolveInfo.serviceInfo.applicationInfo.packageName</code>, I can tell which is which. However, there doesn't seem to be any way to use that ResolveInfo to specify which of the two services I want to handle the intent.</p> <p>This seems like it should do the right thing:</p> <pre><code>serviceIntent.setPackage(context.getApplicationContext().getApplicationInfo().packageName); </code></pre> <p>as that packageName is the same as the one I want to match. Indeed, when I call <code>queryIntentServices</code> with that modified intent I get a list back containing only the service within my package. However, when I try to bindService with that intent, it throws a security exception.</p> <pre><code>java.lang.RuntimeException: Unable to bind to service my.service.package.name.MyServiceClass@40531558 with Intent { act=my.intent.string pkg=my.app.package.name }: java.lang.SecurityException: Not allowed to start service Intent { act=RuntimeException: Unable to bind to service my.service.package.name.MyServiceClass } without permission private to package </code></pre> <p>Based on some googling, I have also tried creating the intent by doing:</p> <pre><code>Intent serviceIntent = new Intent().setClassName( "my.service.package.name", "my.service.package.name.ServiceClassName"); </code></pre> <p>That doesn't resolve to any services at all.</p> <p>I have also tried changing <code>android:exported=</code> in the service entry in the AndroidManifest.xml to true, false, or not specified, in various combinations in both apps, to no avail. (I was hoping that if I set them both to false, then each app would only be able to see its own copy of the service.)</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload