处理 Lollipop 中的隐含意图未来弃用

Posted

技术标签:

【中文标题】处理 Lollipop 中的隐含意图未来弃用【英文标题】:Dealing with implicit intent future deprecation in Lollipop 【发布时间】:2015-03-14 21:32:42 【问题描述】:

为了将数据传输到其他应用程序,我一直在使用隐式意图,如下例所示:

Intent intent = new Intent();
intent.setAction("com.example.OpenURL");
intent.putExtra("URL_TO_OPEN", url_string);
sendOrderedBroadcastAsUser(intent);

Intent intent = new Intent();
intent.setAction("com.example.CreateUser");
intent.putExtra("Username", uname_string);
intent.putExtra("Password", pw_string);
sendBroadcast(intent);

Intent intent = new Intent();
intent.setAction("com.example.BackupUserData");
intent.setData(file_uri);
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
sendBroadcast(intent);

但在 android 5.0 中不再推荐这种行为

http://developer.android.com/about/versions/android-5.0-changes.html

绑定到服务

Context.bindService() 方法现在需要显式 Intent,并抛出 如果给出隐含意图,则例外。为确保您的应用安全,请使用 启动或绑定服务时的明确意图,并且不声明意图 服务的过滤器。

来自android源代码更准确地说是“ContextImpl”类:

private void validateServiceIntent(Intent service) 
        if (service.getComponent() == null && service.getPackage() == null) 
            if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) 
                IllegalArgumentException ex = new IllegalArgumentException(
                        "Service Intent must be explicit: " + service);
                throw ex;
             else 
                Log.w(TAG, "Implicit intents with startService are not safe: " + service
                        + " " + Debug.getCallers(2, 3));
            
        
    

我该如何处理?

【问题讨论】:

更改只影响 bindService,从您发布的代码来看,您正在执行 sendBroadcast,AFAIK 它不应该影响您。 它说“在启动或绑定您的服务时” 根据您问题中的代码,您没有服务。 我明白了这里的重点,这些只是您可以用 startservice() 替换 sendbroadcast() 的示例。重要的部分是意图的构建。 【参考方案1】:

是的,当在装有 Android 5.0 的设备上运行时,此代码将显示警告(如果您的应用的 targetSdkVersion 小于 21)或直接崩溃(如果针对 Lollipop 本身)。检查source code for validateServiceIntent() in ContextImpl.java

此代码很危险,因为它可能允许恶意接收者注册自己并拦截(或更改)这些调用。

最合理的选择可能是使用Intent.setPackage() 指定您要调用的应用程序的包名。以这种方式完成后,意图不再是隐含的,它将起作用。例如:

   intent.setPackage("com.example.app");

当然,如果接收器在您的应用内,还有更简单的替代方案(但从您对问题的描述来看,情况似乎并非如此)。

【讨论】:

你能提供一个完整的例子吗? @An-droid 实际上,它只是在调用startService()(或类似方法)之前添加该行。您的问题是“通用的”还是您手头有更具体的问题? @CommonsWare 我的意思是,对于这次检查来说,这已经足够明确了。问题中的 Intent 都提供了一个动作,如果它在另一个应用程序中,您很少会知道处理它们的类。 @matiash 设置包不足以使意图明确。请参阅我的答案以获取更多详细信息***.com/a/28150873/624109 @Muzikant 恐怕不得不反对。我的观点与我对 CommonsWare 的观点相同,尽管他迟到了删除他的评论:任何适用于 KITKAT 的“正确”服务 Intent 都将通过添加包名称在 Lollipop 上运行——它不一定是“完全明确的”,但为此新检查定义的足够明确。我已经对此进行了测试,例如使用 GCM 调用,该调用曾经有效,但在针对 API 21 时被破坏。【参考方案2】:

正如在其他 cmets 和答案中所说,更改仅与 bindService 相关,与 sendBroadcast 无关,因此如果是这种情况(如您的示例代码中所示) - 您无需更改任何内容。

如果您确实使用bindService,将隐式 Intent 转换为显式 Intent 的方法是使用 ComponentName 并使用 setComponentsetClass 方法将其设置在服务 Intent 上。

来自Intent 类文档:

意图解析

您将使用两种主要形式的意图。

Explicit Intents 已经指定了一个组件(通过 setComponent(ComponentName) 或 setClass(Context, Class)),其中 提供要运行的确切类。通常这些不包括任何 其他信息,只是作为应用程序启动的一种方式 当用户与 应用。隐式意图没有指定组件;反而, 它们必须包含足够的信息,以便系统确定哪个 可用组件中的一个最好是针对该意图运行。

【讨论】:

这是正确答案。绑定服务更改对用于活动和广播的隐式 Intent 没有影响。【参考方案3】:

正如@Commonsware 在他的blog 中指出的那样,解决此问题的三种方法是:

1。解决服务()

Intent i = new Intent("serviceName");
ResolveInfo info = ctx.getPackageManager().resolveService(i, Context.BIND_AUTO_CREATE);
i.setComponent(new ComponentName(info.serviceInfo.packageName,info.serviceInfo.name));

并使用意图绑定服务。

2。 queryIntentServices()

Intent i = new Intent("serviceName");

List<ResolveInfo> infos = ctx.getPackageManager().queryIntentServices(i,Context.BIND_AUTO_CREATE);

if (infos.isEmpty()) 
   throw new IllegalStateException("no service found");

if (infos.size() > 1) 
   throw new SecurityException("multiple services found, could be a security issue");


i.setComponent(new ComponentName(infos.get(0).serviceInfo.packageName, infos.get(0).serviceInfo.name));

如果查询返回多个信息,这可能意味着恶意服务正在监听。

3。 setPackage()

如果你有包名,你可以像@matiash在他的帖子中所说的那样设置包名:

Intent i = new Intent(MyClass.class.getName());
i.setPackage(MyClass.class.getPackage().getName())

【讨论】:

以上是关于处理 Lollipop 中的隐含意图未来弃用的主要内容,如果未能解决你的问题,请参考以下文章

具有隐含意图的自定义权限

卸载应用程序的隐含意图?

隐含意图:将图像从画廊分享到我的应用程序

install_referrer 意图弃用

在 Android 5.0 Lollipop 上不支持 calendarViewShown

Android Lollipop 应用通知设置