如何选择处理意图的服务

时间:2012-01-25 02:43:47

标签: android android-intent android-service

我有一个应用程序,它使用应用程序包中包含的服务。

我现在正在制作一个新应用程序,该应用程序使用相同服务的新版本,捆绑在自己的应用程序包中。

如果设备上只安装了一个应用程序,则可以正常使用。但是,如果两个应用程序都安装在设备上,则它们都使用最近最少安装的软件包中的服务 - 即最旧的软件包。这有问题有两个原因: 1)旧服务不处理新呼叫(显然) 2)当使用与其他应用程序捆绑在一起的服务时,服务最终会使用其他应用程序保存的数据而不是自己的数据。

短期来说,我真的只想让每个应用与自己的服务版本进行对话。是否可以在不使每个捆绑服务响应独特意图并让每个应用程序使用该独特意图的情况下执行此操作?

长期来看,选择让两个应用程序与最新版本的服务进行通信,并让它们共享数据,以及在卸载任一应用程序时都能玩得很好。这样做的正确方法是什么?这些数据主要存储在SQLite数据库中,该数据库存储在Context.getDatabasePath()指定的位置,这当然是应用程序特定的,如果卸载该应用程序则擦除。

这是我到目前为止所尝试的内容:

我可以使用PackageManager.queryIntentServices()获取两个版本服务的ResolveInfo列表。通过查看ResolveInfo.serviceInfo.applicationInfo.packageName,我可以知道哪个是哪个。但是,似乎没有任何方法可以使用ResolveInfo来指定我想要处理意图的两个服务中的哪一个。

这似乎应该做正确的事情:

serviceIntent.setPackage(context.getApplicationContext().getApplicationInfo().packageName);

因为packageName与我想要匹配的那个相同。实际上,当我使用修改后的意图调用queryIntentServices时,我会得到一个仅包含我的包中的服务的列表。但是,当我尝试使用该intent尝试bindService时,它会抛出一个安全异常。

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

基于一些谷歌搜索,我也尝试通过这样做来创建意图:

Intent serviceIntent = new Intent().setClassName(
    "my.service.package.name",
    "my.service.package.name.ServiceClassName");

根本不解决任何服务。

我还尝试将AndroidManifest.xml中的服务条目中的android:exported=更改为true,false或未指定,在两个应用程序中的各种组合中都无济于事。 (我希望如果我将它们都设置为false,那么每个应用程序只能看到它自己的服务副本。)

2 个答案:

答案 0 :(得分:3)

这是一个有效的解决方案:

在清单中添加服务的元数据。名称应该类似于“service launcher”,并且值必须与intent过滤器中的操作名称相同。

<meta-data android:name="Service Launcher"
           android:value="your.service.action.string.here" />

<intent-filter>
    <action android:name="your.service.action.string.here" />
</intent-filter>

然后在您的代码中添加一个访问方法来获取元数据并使用它来构建Intent。

public static String getServiceIntentAction(Context context) {
    String action = "";
    try {
        PackageManager pm = context.getPackageManager();
        android.content.ComponentName cn = new android.content.ComponentName(context.getPackageName(), "com.your.ServiceClass");
        android.content.pm.ServiceInfo si = pm.getServiceInfo(cn, PackageManager.GET_META_DATA);
        action = si.metaData.getString("Service Launcher");
    } catch(android.content.pm.PackageManager.NameNotFoundException nnfe) {}
    return action;
}

然后构建Intent以启动服务的任何东西都会调用此方法。他们的应用程序中的每个服务用户都可以使用不同的操作,只使用一个版本的库与他们的应用程序进行通信,而只更改清单。

要让这两个应用使用相同的服务,该服务可能应该作为自己的实体安装。

答案 1 :(得分:0)

您是否尝试过使用类别?对于意图中的每个类别,潜在接收组件必须匹配每个类别以被视为接收者。

服务A的类别为“1”,并且类别“1”的意图去那里。 服务B的类别为“1”,类别为“2”(假设它仍然支持版本“1”中的所有内容。有了这个,较旧的应用程序可以与较新的服务通信,但较新的应用程序无法与较旧的服务通信。