您的位置:首页 > 移动开发 > Android开发

Android 5.0 禁止使用隐式Intent来启动Service.异常:service intent must be explicit

2016-02-02 15:59 776 查看
Android 5.0 禁止使用隐式Intent来启动Service.异常:service intent must be explicit

     最近运行了一下我以前做的一个启动service的demo程序,发现!不!好!用!了!看了一下Log异常:service intent must be explicit.什么鬼?什么鬼?什么鬼!上网查了一下,原来从Android 5.0 开始,google出于安全的角度禁止了隐式声明Intent来启动Service.也禁止使用Intent filter.否则就会抛这个个异常出来. 

    


问题分析

首先比对Android 4.4 与 Android 5.0 的区别:

     Android 4.4:链接:(/frameworks/base/core/java/android/app/ContextImpl.java

private void validateServiceIntent(Intent service) {
if (service.getComponent() == null && service.getPackage() == null) {
if (true || getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {
Log.w(TAG, "Implicit intents with startService are not safe: " + service
+ " " + Debug.getCallers(2, 3));
//IllegalArgumentException ex = new IllegalArgumentException(
//        "Service Intent must be explicit: " + service);
//Log.e(TAG, "This will become an error", ex);
//throw ex;
}
}
}


     Android 5.0:链接:(/frameworks/base/core/java/android/app/ContextImpl.java

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));
}
}
}
     也就是说在5.0里面,如果targetSdkVersion>=LOLLIPOP 就会报异常:“service intent must be explicit”,这就说明1.targetSdkVersion>=LOLLIPOP 2.手机系统为5.0以上版本 3.程序采用隐式Intent调用Service,这三个条件是问题发生的充分必要条件。

     另外一点值得注意的是:盲目将程序targetSdkVersion提高容易导致用户手中的软件无法再升级(因为版本的升级功能通常是采用Service的方式)。

解决方案     参考博文:http://blog.csdn.net/vrix/article/details/45289207


方案一:设置Action和packageName(google官方建议):

Intent mIntent = new Intent();
mIntent.setAction("XXX.XXX.XXX");
mIntent.setPackage(getPackageName());
context.startService(mIntent);


方案二:将隐式启动转换为显示启动

实现转换函数:(参考:http://developer.android.com/goo
... tml#billing-service)

public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
}
调用函数:

Intent mIntent = new Intent();
mIntent.setAction("XXX.XXX.XXX");
Intent eintent = new Intent(getExplicitIntent(mContext,mIntent));
context.startService(eintent);


// 如果觉得不错,记得顶我哦! 顶我!顶我!顶我!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息