Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android 5.0 (L) Service Intent must be explicit in Google analytics

My code worked in <5 but in Android 5.0 I'm running into an issue that I don't quite understand.

10-23 10:18:18.945: E/AndroidRuntime(8987): java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.google.android.gms.analytics.service.START (has extras) } 

My code works, even now, on 4.4.4 and below. So what do I need to do? I'll post relative code below. Also, during my googling I found this post about java.lang.IllegalArgumentException: Service Intent must be explicit in regard to Android 5.0 but I don't understand what it means.

Manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android"     package="xxxxx.android.phone.xxxxx"     android:versionCode="3"     android:versionName="v1.2.4065" >      <uses-sdk android:minSdkVersion="12"         android:targetSdkVersion="21" />      <!-- Required for Google Analytics -->     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />      <!-- For push notifications (GCM) -->     <permission android:name="xxxxx.android.phone.xxxxx.permission.C2D_MESSAGE" android:protectionLevel="signature" />     <uses-permission android:name="xxxxx.android.phone.xxxxx.permission.C2D_MESSAGE" />     <!-- App receives GCM messages. -->     <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />     <!-- GCM connects to Google Services. -->     <uses-permission android:name="android.permission.INTERNET" />      <!-- GCM requires a Google account. -->     <uses-permission android:name="android.permission.GET_ACCOUNTS" />     <!-- Keeps the processor from sleeping when a message is received. -->     <uses-permission android:name="android.permission.WAKE_LOCK" />     <!-- GCM - We handle notifications differently if the app is running -->     <uses-permission android:name="android.permission.GET_TASKS" />       <!-- Caching -->     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />      <!-- The event subscribe button adds events to the calendar --> <!--    <uses-permission android:name="android.permission.WRITE_CALENDAR" /> --> <!--    <uses-permission android:name="android.permission.READ_CALENDAR" />  -->      <supports-screens         android:resizeable="true"         android:smallScreens="false"         android:normalScreens="true"         android:largeScreens="true"         android:xlargeScreens="true"         android:anyDensity="true" />      <application         android:name="xxxxx.xxxxxApplication"         android:icon="@drawable/app_icon"         android:label="@string/app_name"         android:allowBackup="true"         android:largeHeap="true" >         <receiver              android:name="com.google.android.gcm.GCMBroadcastReceiver"              android:permission="com.google.android.c2dm.permission.SEND" >             <intent-filter>                 <action android:name="com.google.android.c2dm.intent.RECEIVE" />                 <category android:name="xxxxx.android.phone.xxxxx" />             </intent-filter>             <intent-filter>                 <action android:name="com.google.android.c2dm.intent.REGISTRATION" />                 <category android:name="xxxxx.android.phone.xxxxx" />             </intent-filter>         </receiver>          <receiver              android:name="xxxxx.ConnectivityReceiver"             android:enabled="false" >             <intent-filter>                 <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />             </intent-filter>         </receiver>          <activity              android:name=".SplashActivity"             android:configChanges="locale|orientation"              android:theme="@style/Theme.Splash"             android:screenOrientation="portrait"             android:noHistory="true" >             <intent-filter >                 <action android:name="android.intent.action.MAIN" />                 <category android:name="android.intent.category.LAUNCHER" />             </intent-filter>         </activity>         <activity             android:label="@string/app_name"             android:theme="@style/Theme"             android:windowSoftInputMode="adjustPan|stateVisible"             android:name=".LoginActivity"             android:configChanges="locale|orientation|screenSize"              android:screenOrientation="portrait" >         </activity>         <activity              android:name=".MainActivity"              android:theme="@style/Theme"             android:configChanges="locale|orientation|screenSize"              android:screenOrientation="portrait"             android:windowSoftInputMode="adjustPan|stateVisible" />          <activity              android:name=".CountryPickerActivity"              android:theme="@style/Theme.Floating"             android:configChanges="locale|orientation|screenSize"              android:screenOrientation="portrait"             android:windowSoftInputMode="adjustPan|stateVisible" />         <activity              android:name=".EventPickerActivity"              android:theme="@style/Theme.Floating"             android:configChanges="locale|orientation|screenSize"              android:screenOrientation="portrait"             android:windowSoftInputMode="adjustPan|stateVisible" />         <activity              android:name=".TutorialActivity"             android:theme="@style/Theme.Transparent"             android:configChanges="locale|orientation|screenSize"             android:screenOrientation="portrait" />          <activity              android:name=".VideoPlayerActivity"              android:theme="@style/Theme"             android:configChanges="orientation|screenSize" />          <service android:name=".GCMIntentService" android:enabled="true" />         <meta-data android:name="com.crashlytics.ApiKey" android:value="xxxxxxxxxxxxxxxx"/>     </application>  </manifest> 

GCMIntentService.java

public class GCMIntentService extends GCMBaseIntentService { private static final int ATTEMPTS_MAX = 3;  final static boolean USE_DEV = false; final static String XXXXX = "https://xxxxx/api.php"; final static String XXXXX = "http://dev.xxxxx/api.php"; final static String SUBSCRIPTION_KEY = "xxxxxxxxxxxxxxx"; // unique per app      public GCMIntentService() {         super(xxxxxx.SENDER_ID);         if(GCMIntentService.USE_DEV) {             host = XXXXX;         } else {             host = XXXXX;         }     }      ...  } 

** EDIT **

The more I look at this issue the more I think it's not in GCMIntentService.java. I should have posted my stack trace before which is:

10-23 13:17:08.095: E/AndroidRuntime(10560): FATAL EXCEPTION: GAThread 10-23 13:17:08.095: E/AndroidRuntime(10560): Process: xxxxx.android.phone.xxxxx, PID: 10560 10-23 13:17:08.095: E/AndroidRuntime(10560): java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.google.android.gms.analytics.service.START (has extras) } 10-23 13:17:08.095: E/AndroidRuntime(10560):    at android.app.ContextImpl.validateServiceIntent(ContextImpl.java:1674) 10-23 13:17:08.095: E/AndroidRuntime(10560):    at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1773) 10-23 13:17:08.095: E/AndroidRuntime(10560):    at android.app.ContextImpl.bindService(ContextImpl.java:1751) 10-23 13:17:08.095: E/AndroidRuntime(10560):    at android.content.ContextWrapper.bindService(ContextWrapper.java:538) 10-23 13:17:08.095: E/AndroidRuntime(10560):    at com.google.analytics.tracking.android.AnalyticsGmsCoreClient.connect(AnalyticsGmsCoreClient.java:82) 10-23 13:17:08.095: E/AndroidRuntime(10560):    at com.google.analytics.tracking.android.GAServiceProxy.connectToService(GAServiceProxy.java:279) 10-23 13:17:08.095: E/AndroidRuntime(10560):    at com.google.analytics.tracking.android.GAServiceProxy.createService(GAServiceProxy.java:163) 10-23 13:17:08.095: E/AndroidRuntime(10560):    at com.google.analytics.tracking.android.GAThread.init(GAThread.java:95) 10-23 13:17:08.095: E/AndroidRuntime(10560):    at com.google.analytics.tracking.android.GAThread.run(GAThread.java:493) 

So I'm going to try to run GA as explicit intent.

like image 770
Jacksonkr Avatar asked Oct 23 '14 14:10

Jacksonkr


People also ask

What is intent explain implicit intent with example?

In android, Implicit Intents won't specify any name of the component to start instead, it declare an action to perform and it allows a component from other apps to handle it. For example, by using implicit intents we can request another app to show the location details of the user or etc.

What is not specified by implicit intent?

Implicit Intent doesn't specifiy the component. In such case, intent provides information of available components provided by the system that is to be invoked.

What is intent and intent filter in android?

An intent filter declares the capabilities of its parent component — what an activity or service can do and what types of broadcasts a receiver can handle. It opens the component to receiving intents of the advertised type, while filtering out those that are not meaningful for the component.


2 Answers

If you're trying to use Google's Licensing mechanism, solution that worked for me:

// explicit Intent, safe Intent serviceIntent = new Intent(ILicensingService.class.getName()); serviceIntent.setPackage("com.android.vending"); boolean bindResult = mContext.bindService(serviceIntent, this, Context.BIND_AUTO_CREATE); 

This is located in com/google/android/vending/licensing/LicenseChecker.java. Do a search for "Base64.decode("

Edit:

Adding reference to Google Licensing java file that has to be patched:

com.google.android.vending.licensing.LicenseChecker.checkAccess(LicenseChecker.java:150) 

patch:

new String( -    Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U="))), +    Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U="))) +    .setPackage("com.android.vending"), // this fix the 'IllegalArgumentException: Service Intent must be explicit'      this, // ServiceConnection. 

Source: https://code.google.com/p/android/issues/detail?id=78505#c19

like image 112
milosmns Avatar answered Sep 29 '22 10:09

milosmns


Since Android 5.0 (Lollipop) bindService() must always be called with an explicit intent. This was previously a recommendation, but since Lollipop it is enforced: java.lang.IllegalArgumentException: Service Intent must be explicit is thrown every time a call to bindService() is made using implicit intents. The difference between implicit and explicit intents is that the latter specifies the component to start by name (the fully-qualified class name). See the documentation about intent types here.

The issue you are having is due to not having upgraded to a newer version of the google libraries, which comply with Android's restrictions on implicit intents when binding a service on Android 5 Lollipop. To fix the issue, you can upgrade the library to a newer version if available, or update the library code yourself and build your project with the modified version.

If there's no suitable library upgrade in the general case, you need to modify the source code (in your case com.google.analytics.tracking.android.AnalyticsGmsCoreClient.connect()) to call intent.setPackage(packageName) before calling bindService() where intent is the first argument of the bindService() call and packageName is the name of the package containing the service the code is attempting to start (in your case "com.google.android.gms.analytics").

You can use this code as an example how to do this: Unity's updated version of the Google Licensing Library (LVL) which calls bindService with an explicit intent and does not result in IllegalArgumentException.

Yet another way to get around the problem is to rebuild your project and the google libraries using targetSDK no later than 19. This will make it run without crashing on Lollipop but is the less secure option and prevents you from using SDK functionality introduced in later versions (for Android 5).

like image 20
Maria Avatar answered Sep 29 '22 11:09

Maria