Android 5.0 不再允许使用隐式Intent来启动Service



     最近运行了一下我以前做的一个启动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)

[java]  view plain  copy
 print ?
  1. private void validateServiceIntent(Intent service) {    
  2.     if (service.getComponent() == null && service.getPackage() == null) {    
  3.         if (true || getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {    
  4.             Log.w(TAG, "Implicit intents with startService are not safe: " + service    
  5.                     + " " + Debug.getCallers(23));    
  6.             //IllegalArgumentException ex = new IllegalArgumentException(    
  7.             //        "Service Intent must be explicit: " + service);    
  8.             //Log.e(TAG, "This will become an error", ex);    
  9.             //throw ex;    
  10.         }    
  11.     }    
  12. }    

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

[java]  view plain  copy
 print ?
  1. private void validateServiceIntent(Intent service) {    
  2.     if (service.getComponent() == null && service.getPackage() == null) {    
  3.         if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {    
  4.             IllegalArgumentException ex = new IllegalArgumentException(    
  5.                     "Service Intent must be explicit: " + service);    
  6.             throw ex;    
  7.         } else {    
  8.             Log.w(TAG, "Implicit intents with startService are not safe: " + service    
  9.                     + " " + Debug.getCallers(23));    
  10.         }    
  11.     }    
  12. }    
     也就是说在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官方建议):

[java]  view plain  copy
 print ?
  1. Intent mIntent = new Intent();  
  2. mIntent.setAction("XXX.XXX.XXX");  
  3. mIntent.setPackage(getPackageName());  
  4. context.startService(mIntent);  

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

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

[java]  view plain  copy
 print ?
  1. public static Intent getExplicitIntent(Context context, Intent implicitIntent) {  
  2.         // Retrieve all services that can match the given intent  
  3.         PackageManager pm = context.getPackageManager();  
  4.         List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);  
  5.         // Make sure only one match was found  
  6.         if (resolveInfo == null || resolveInfo.size() != 1) {  
  7.             return null;  
  8.         }  
  9.         // Get component info and create ComponentName  
  10.         ResolveInfo serviceInfo = resolveInfo.get(0);  
  11.         String packageName = serviceInfo.serviceInfo.packageName;  
  12.         String className = serviceInfo.serviceInfo.name;  
  13.         ComponentName component = new ComponentName(packageName, className);  
  14.         // Create a new intent. Use the old one for extras and such reuse  
  15.         Intent explicitIntent = new Intent(implicitIntent);  
  16.         // Set the component to be explicit  
  17.         explicitIntent.setComponent(component);  
  18.         return explicitIntent;  
  19.     }  
调用函数:

[java]  view plain  copy
 print ?
  1. Intent mIntent = new Intent();  
  2. mIntent.setAction("XXX.XXX.XXX");  
  3. Intent eintent = new Intent(getExplicitIntent(mContext,mIntent));  
  4. context.startService(eintent);  

你可能感兴趣的:(Android 5.0 不再允许使用隐式Intent来启动Service)