Ответ 1
Миграция из Google Analytics v2 в v3 решила проблему для меня.
Мой код работал в < 5, но в Android 5.0 у меня возникла проблема, которую я не совсем понимаю.
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) }
Мой код работает, даже сейчас, на 4.4.4 и ниже. Так что мне нужно делать? Я отправлю относительный код ниже. Кроме того, во время моего googling я нашел это сообщение о java.lang.IllegalArgumentException: служебное намерение должно быть явным в отношении Android 5.0, но я не понимаю, что это значит.
<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>
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;
}
}
...
}
Чем больше я смотрю на этот вопрос, тем больше я думаю, что это не в GCMIntentService.java
. Я должен был опубликовать трассировку стека, перед которой:
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)
Итак, я попытаюсь запустить GA как явное намерение.
Миграция из Google Analytics v2 в v3 решила проблему для меня.
Если вы пытаетесь использовать механизм лицензирования Google, решение, которое сработало для меня:
// 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);
Это находится в com/google/android/vending/licensing/LicenseChecker.java
. Сделайте поиск "Base64.decode(
"
Edit:
Добавление ссылки на java файл Google Licensing, который должен быть исправлен:
com.google.android.vending.licensing.LicenseChecker.checkAccess(LicenseChecker.java:150)
патч:
new String(
- Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U="))),
+ Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U=")))
+ .setPackage("com.android.vending"), // this fix the 'IllegalArgumentException: Service Intent must be explicit'
this, // ServiceConnection.
Источник: https://code.google.com/p/android/issues/detail?id=78505#c19
Так как Android 5.0 (Lollipop) bindService() всегда должен вызываться с явным намерением. Ранее это была рекомендация, но с Lollipop она соблюдалась: java.lang.IllegalArgumentException: Service Intent must be explicit
бросается каждый раз, когда вызов bindService()
выполняется с использованием неявных намерений.
Разница между неявными и явными намерениями заключается в том, что последний указывает компонент для запуска по имени (полное имя класса).
См. документацию о типах целей здесь.
Проблема, с которой вы столкнулись, связана с тем, что она не обновилась до более новой версии библиотек google, которая соответствует ограничениям Android на неявные намерения при привязке службы на Android 5 Lollipop. Чтобы устранить проблему, вы можете обновить библиотеку до более новой версии, если она есть, или обновить код библиотеки самостоятельно и создать проект с измененной версией.
Если в общем случае нет подходящего обновления библиотеки, вам необходимо изменить исходный код (в вашем случае com.google.analytics.tracking.android.AnalyticsGmsCoreClient.connect()
), чтобы вызвать intent.setPackage(packageName)
перед вызовом bindService()
, где intent
- это первый аргумент bindService()
call и packageName
- это имя пакета, содержащего сервис, который пытается запустить код (в вашем случае "com.google.android.gms.analytics" ).
Вы можете использовать этот код в качестве примера, как это сделать: Unity обновленная версия библиотеки лицензирования Google (LVL), которая вызывает bindService с явным намерением и не приводит к ошибке IllegalArgumentException.
Еще один способ обойти эту проблему состоит в том, чтобы перестроить ваш проект и библиотеки google с помощью targetSDK не позднее 19. Это заставит его работать без сбоев на Lollipop, но является менее безопасным вариантом и не позволяет вам использовать введенные функции SDK в более поздних версиях (для Android 5).
У меня была сама проблема. Проблема заключается в вашей деятельности, которая начинает ваш сервис.
В принципе, явное намерение называет службу непосредственно в намерении при запуске службы. См. http://developer.android.com/guide/components/intents-filters.html для более подробного объяснения.
Так как у вас нет кода активности, я не знаю, как вы его начинаете сейчас, но он должен выглядеть примерно так:
Intent startIntent = new Intent(this, ServiceToStart.class);
this.startService(startIntent); // or bindService(...)
Я использовал этот, и он отлично работает
public static Intent createExplicitFromImplicitIntent(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;
}
Я работаю над проектом, в котором мы хотим разрешить пользователям использовать старые устройства. Я придумал то же самое решение, что и упомянутое в Marias, но я добавил условный оператор для вызова setPackage
, поскольку он доступен только в API 4 (Ice Cream Sandwich == SDK 14) и выше. Если вы разрабатываете версии ниже того, что я считаю, вам не нужно включать вызов setPackage
.
В функции com.google.android.vending.licensing.LicenseChecker.checkAccess(callback)
Intent serviceIntent = new Intent(new String(
Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U=")));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
serviceIntent.setPackage("com.android.vending");
}
boolean bindResult =
mContext.bindService(
serviceIntent,
this, // ServiceConnection.
Context.BIND_AUTO_CREATE);
Если вы хотите запустить службу, которая находится в другом приложении, вы можете использовать это:
Intent serviceIntent = new Intent("action name for the service");
serviceIntent.setPackage("the PackageName for which the service in)");//the destination packageName
context.startService(serviceIntent);
Это сработало для меня... Это работало на леденец, используя android sdk 21..
Intent intent = new Intent(this, Class.forName(ServiceClassName.class.getName()));
bindService(intent,serviceConnection, Service.BIND_AUTO_CREATE);
Для пользователей PhoneGap/Cordova, которые видят эту ошибку, это потому, что полуофициальный GAPlugin использует устаревшую версию Google Analytics v2 lib. khalidb91 разветкил его и обновил до v3, который на момент написания не был объединен в полуофициальный плагин. Возьмите код из его вилки, опустите его как прямую замену плагинам /com.adobe.plugins.GAPlugin и больше никаких сбоев. Спасибо khalidb91!
Это работает для меня:
Intent intent = new Intent(ACTION);
intent.setPackage(context.getPackageName());
context.startService(intent);
Если вы пытаетесь запустить сервис, попробуйте его следующим образом:
var intent = new Intent (this,typeof(MyBoundService));
var serviceConnection = new MyBindServiceConnection (this);
BindService (intent, serviceConnection, Bind.AutoCreate);