android - 如何选择哪个服务来处理 Intent

标签 android android-intent android-service

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

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

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

短期内,我真的只是希望每个应用程序都能与自己的服务版本对话。是否可以在不让每个 bundle 服务响应独特 Intent 并让每个应用程序使用该独特 Intent 的情况下做到这一点?

从长远来看,最好选择让两个应用程序都与最新版本的服务通信,并让它们共享数据,并在任一应用程序被卸载时都能正常运行。正确的做法是什么?数据主要存储在 SQLite 数据库中,存储在 Context.getDatabasePath() 指定的位置,这当然是特定于应用程序的,如果卸载该应用程序,则会被删除。

这是我迄今为止尝试过的:

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

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

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

因为该 packageName 与我要匹配的 packageName 相同。事实上,当我使用修改后的 Intent 调用 queryIntentServices 时,我会得到一个仅包含包中服务的列表。但是,当我尝试以该 Intent 绑定(bind)Service 时,它​​会引发安全异常。

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 :

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

这根本无法解析任何服务。

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

最佳答案

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

在 list 中添加服务的元数据。名称应该类似于“服务启动器”,并且值必须与 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 来启动服务的内容都会调用此方法。应用中该服务的每个用户都可以执行不同的操作,仅使用一个版本的库和 list 更改来与其应用进行通信。

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

关于android - 如何选择哪个服务来处理 Intent ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8997258/

相关文章:

Android TV ADT-1 adb 连接端口已更改?

javascript - 如何替换android中的所有匹配字符串

android - 在 Android API <21 中使用 Job Scheduler

android - 如何为 Android 26+ 实现强大的闹钟应用程序

android - 信号 11 (SIGSEGV),使用 Bump API 时 android 中的故障地址

android - 当应用两个连续的 setContentView 时,第一个 View 不可见

java - 在没有源代码的情况下编辑APK?

java - 错误 : java. lang.SecurityException:权限拒绝:以另一种风格启动 Intent

android - 使用 Intent 重新启动当前 Activity

android - 在 Activity 之间传递 Parcelable 项目