Android 5.0(L)服务意图必须在Google Analytics(分析)中明确显示


68

我的代码在<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及更低版本。那我该怎么办?我将在下面发布相关代码。另外,在谷歌搜索期间,我发现了有关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>

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;
        }
    }

    ...

}

**编辑**

我对这个问题的关注程度越高,就越不觉得这个问题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。


不幸的是,我对此领域不太了解,但是这是有关许可服务和明确意图的关于reddit的帖子;reddit.com/r/androiddev/comments/2jspqi/…
harism 2014年

Answers:


21

从Google Analytics(分析)第2版迁移到第3版为我解决了这个问题。


3
嘿! 我正在使用Analytics v4,今天在棒棒糖LGE设备(Nexus 5)上遇到了此异常。任何指针。我创建了一个单独的文件,该文件将负责发送屏幕名称和事件。TrackerName为App_Tracker。
Ankit Garg 2014年

1
我没有尝试使用v4,但由于其他服务,您可能遇到此问题。尝试将其完全关闭。
nickkadrov 2014年

1
@AnkitGarg这听起来像我们谈论不同的软件,因为谷歌Analytics(分析)SDK目前还只是在3大版本
Jacksonkr

太奇怪了,我收到了相同的错误Google Analytics v3 ...我想我会尝试最新版本。
arne.jans 2014年

2
我正在使用版本v3,但在targetSdkVersion = 21的android 5.0设备中仍然出现相同的错误。但是我在Android 5.0设备中没有获得targetSdkVersion = 19的错误。我不明白原因。我能做什么?
realuser 2014年

44

如果您尝试使用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(

编辑:

添加对必须打补丁的Google许可Java文件的引用:

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


我们是否需要清单中的服务具有意图过滤器?那里的价值是多少?
Ashutosh Nigam,2015年

@AshutoshNigam我将所有内容保持不变,因此通常按照文档中的说明在清单中声明该服务。
milosmns,2015年

这是可以接受的答案,因为它解决了Android Lollipop中的问题。
IgorGanapolsky'3

我如何找到上面的java文件?
h_k 2015年

@h_k我以为您已经从SDK Extras导入了许可库项目,当您进行导入时,您将可以使用该类(即使用于编辑,但不要这样做)
milosmns

38

由于Android 5.0(Lollipop)bindService()必须始终以明确的意图被调用。以前这是一个建议,但是由于Lollipop被强制执行:java.lang.IllegalArgumentException: Service Intent must be explicit 每次bindService()使用隐式Intent进行调用时都会抛出该错误。隐式意图和显式意图之间的区别在于,后者通过名称(完全限定的类名)指定组件。 请参阅此处有关意图类型的文档。

您遇到的问题是由于尚未升级到较新版本的Google库,这些库在Android 5 Lollipop上绑定服务时符合Android对隐式意图的限制。要解决此问题,您可以将库升级到较新的版本(如果可用),或者自己更新库代码并使用修改后的版本构建项目。

如果通常情况下没有合适的库升级,则需要在调用where之前修改其源代码(在您的情况下 com.google.analytics.tracking.android.AnalyticsGmsCoreClient.connect()),以intent.setPackage(packageName)在调用bindService()whereintent是调用的第一个参数,bindService()并且packageName是包含该代码正在尝试服务的软件包的名称开始(在您的情况下为“ com.google.android.gms.analytics”)。

您可以使用以下代码作为操作方法的示例:Unity的Google许可库(LVL)的更新版本,该版本以明确的意图调用bindService且不会导致IllegalArgumentException。

解决该问题的另一种方法是在不迟于19的时间使用targetSDK重建项目和google库。这将使其运行而不会在Lollipop上崩溃,但是安全性较差,并且会阻止您使用更高版本中引入的SDK功能(适用于Android 5)。


以上答案导致我的许可证检查失败,但是Unity解决方案有效。谢谢,+ 1
马库斯(Marcus)2015年

我将targetSDK设置为18,但仍然遇到此问题。

14

我本人只是有这个问题。问题出在启动服务的活动之内。

基本上,显式意图在服务启动时直接在意图中命名服务。有关更深入的说明,请参见http://developer.android.com/guide/components/intents-filters.html

既然您没有发布活动代码,所以我现在不知道如何启动它,但是它可能看起来像这样:

Intent startIntent = new Intent(this, ServiceToStart.class);
this.startService(startIntent); // or bindService(...)

仍然不确定发生了什么。我的主要活动是巨大的,所以我应该发布我的文章onCreate吗?这就是GA服务启动的地方。
2014年

当然,只需发布​​服务开始的地方。
乔·格兰德

1
问题的本质是问题,但存在于GA(Google Analytics(分析))库中。我一直打算升级到新版本(3.0),所以我只是从2迁移到3,然后是中提琴。
2014年

4
这为我解决了。我正在使用new Intent(ISomeService.class.getName());,它在4.4中可以正常工作,但在5.0中却不能。将那条线切换到后new Intent(getApplicationContext(), ISomeService.class);,它再次开始工作。请注意,在4.4中我已经对此有所警告,我只是选择忽略它,因为我只写了一个一次性测试类。
丹尼尔(Daniel)

小更新:错误确实消失了,但是现在我无法连接到该服务。我将目标sdk设置为19,直到GoogleGoogle进行对话并弹出一些修复程序为止。
丹尼尔(Daniel)

8

我用这个和它的伟大工程

 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;
 }

4

我正在一个项目中,我们希望允许用户使用旧设备。我想出了与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);

2

如果要启动另一个应用程序中的服务,则可以使用以下方法:

Intent serviceIntent = new Intent("action name for the service");
serviceIntent.setPackage("the PackageName for which the service in)");//the destination packageName
context.startService(serviceIntent);

1

这对我有用..这在使用Android SDK 21的棒棒糖中工作。

Intent intent = new Intent(this, Class.forName(ServiceClassName.class.getName()));
bindService(intent,serviceConnection, Service.BIND_AUTO_CREATE);

4
如果ServiceClassName在其他apk中怎么办?
史莱尼克

1

对于看到此错误的PhoneGap / Cordova用户,是因为半官方的GAPlugin使用了已弃用的Google Analytics(分析)v2库。khalidb91对其进行了分叉,并更新至v3,截至撰写本文时,该v3尚未合并到半官方插件中。从他的叉子中抓取代码,将其直接替换为plugins / com.adobe.plugins.GAPlugin,不再崩溃。谢谢khalidb91!

https://github.com/khalidb91/GAPlugin


0

这对我有用:

Intent intent = new Intent(ACTION);
intent.setPackage(context.getPackageName());
context.startService(intent);

-2

如果您要启动服务,请尝试以下方式:

var intent = new Intent (this,typeof(MyBoundService));
var serviceConnection = new MyBindServiceConnection (this);
BindService (intent, serviceConnection, Bind.AutoCreate);

2
typeof不是正确的Java方法。
罗曼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.