要将数据传输到其他应用程序,我一直在使用隐式意图,如下例所示:
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" class:
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));
}
}
}
我该如何处理?
答案 0 :(得分:19)
是的,在使用Android 5.0的设备中运行时,此代码会显示警告(如果您的应用targetSdkVersion
<21)或直接崩溃(如果定位Lollipop本身)。查看source code for validateServiceIntent()
in ContextImpl.java
:
此代码很危险,因为它可能允许恶意接收者自行注册并拦截(或更改)这些调用。
最合理的替代方法可能是使用Intent.setPackage()
指定要呼叫的应用的包名称。当这样做时,意图不再是隐含的,它将起作用。例如:
intent.setPackage("com.example.app");
当然,如果接收器位于您的应用内部,则有更简单的替代方案(但从您对问题的描述来看似乎并非如此)。
答案 1 :(得分:2)
正如其他评论和答案所述,此更改仅与bindService
相关,而非sendBroadcast
,因此,如果情况如此(如您的示例代码中所示) - 您不要# 39;不需要改变任何东西。
如果您使用bindService
,那么对显式Intent进行隐式Intent的方法是使用ComponentName
并使用setComponent
或{{在服务Intent上设置它3}}方法。
来自Intent
课程文档:
意图解决方案
您将使用两种主要形式的意图。
Explicit Intents指定了一个组件(通过 setComponent(ComponentName)或setClass(Context,Class)),其中 提供要运行的确切类。通常这些不包括任何 其他信息,只是一种应用程序启动的方式 当用户与之交互时,它具有的各种内部活动 应用。隐含意图没有指定组件;代替, 他们必须包含足够的信息供系统确定 可用组件最好为该意图运行。
答案 2 :(得分:1)
正如@Commonsware在blog中所指出的,解决这个问题的3种方法是:
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));
并使用意图绑定服务。
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));
如果查询返回多个信息,这可能意味着恶意服务正在监听。
如果你有包名,你可以设置包名为@matiash在帖子中说:
Intent i = new Intent(MyClass.class.getName());
i.setPackage(MyClass.class.getPackage().getName())