【问题标题】:Android 5.0 (L) Service Intent must be explicit in Google analyticsAndroid 5.0 (L) Service Intent 必须在 Google 分析中明确
【发布时间】:2014-10-23 14:34:07
【问题描述】:

我的代码在

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 及更低版本上运行。那么我需要做什么呢?我将在下面发布相关代码。另外,在我的谷歌搜索过程中,我发现了这个post about java.lang.IllegalArgumentException: Service Intent must be explicit in regard to 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 作为显式意图运行。

【问题讨论】:

标签: android-5.0-lollipop illegalargumentexception


【解决方案1】:

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

【讨论】:

  • 我们是否需要对清单中的服务进行意图过滤?那里的价值应该是什么?
  • @AshutoshNigam 我保持一切原样,所以通常按照文档中的说明在清单中声明服务。
  • 这应该是公认的答案,因为它解决了 Android Lollipop 中的问题。
  • 如何找到上面的java文件?
  • @h_k 我假设您已经从 SDK extras 导入了许可库项目,当您进行导入时,您将拥有此类可用(即使用于编辑,但不要这样做)
【解决方案2】:

从 Android 5.0 (Lollipop) 开始,必须始终以明确的意图调用 bindService()。这是以前的建议,但自从 Lollipop 以来,它被强制执行:java.lang.IllegalArgumentException: Service Intent must be explicit 每次使用隐式意图调用 bindService() 时都会抛出。 隐式意图和显式意图之间的区别在于后者指定组件以名称(完全限定的类名)开头。 See the documentation about intent types here.

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

如果在一般情况下没有合适的库升级,您需要修改源代码(在您的情况下为com.google.analytics.tracking.android.AnalyticsGmsCoreClient.connect())在调用intent.setPackage(packageName)之前调用bindService(),其中intent是@的第一个参数987654329@ call 和 packageName 是包含代码尝试启动的服务的包的名称(在您的情况下为“com.google.android.gms.analytics”)。

您可以使用此代码作为示例如何执行此操作:Unity's updated version of the Google Licensing Library (LVL) which calls bindService with an explicit intent and does not result in IllegalArgumentException.

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

【讨论】:

  • 以上答案导致我的许可证检查失败,但 Unity 解决方案有效。谢谢,+1
  • 我设置了 targetSDK= 18 但仍然遇到这个问题。
【解决方案3】:

从 Google Analytics v2 迁移到 v3 为我解决了这个问题。

【讨论】:

  • 嘿!我正在使用分析 v4,今天我在棒棒糖 LGE 设备(Nexus 5)上遇到了这个异常。任何指针。我创建了一个单独的文件,负责发送屏幕名称和事件。 TrackerName 是 App_Tracker。
  • 我没有尝试使用v4,但可能是因为其他服务而出现此问题。尝试完全关闭它。
  • @AnkitGarg 听起来我们在谈论不同的软件,因为 Google Analytics SDK 仍然只在 3 的主要版本中。
  • 这很奇怪,我遇到了同样的错误 Google Analytics v3... 我想我会尝试最新版本。
  • 我使用的是 v3 版本,但在 targetSdkVersion=21 的 android 5.0 设备中仍然出现相同的错误。但我没有在 android 5.0 设备中使用 targetSdkVersion=19 得到这个错误。我不明白原因。我能做什么?
【解决方案4】:

我自己也遇到了这个问题。问题在于您正在启动服务的活动。

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

既然你没有发布你的活动代码,我不知道你现在是如何开始的,但它应该看起来像这样:

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

【讨论】:

  • 仍然不确定发生了什么。我的主要活动很大,所以我应该发布我的onCreate 吗?这就是启动 GA 服务的地方。
  • 好的,只需发布​​服务的启动位置即可。
  • 内在意图是问题,但在 GA(谷歌分析)库中。我本来打算升级到新版本(3.0),所以我只是从 2 迁移到 3 和 viola。
  • 这为我解决了。我使用的是new Intent(ISomeService.class.getName());,它在 4.4 中运行良好,但在 5.0 中不行。将该行切换到new Intent(getApplicationContext(), ISomeService.class); 后,它又开始工作了。请注意,我在 4.4 中已经对此发出警告,我只是选择忽略它,因为我只是在编写一次性测试类。
  • 小更新:错误确实消失了,但现在我无法连接到服务。我将目标 sdk 设置为 19,直到 Google talks to Google 和一些 fix 弹出。
【解决方案5】:

我用过this,效果很好

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

【讨论】:

    【解决方案6】:

    我正在开展一个项目,我们希望允许用户使用旧设备。我想出了与 Marias 回答中提到的解决方案相同的解决方案,但是我为 setPackage 调用添加了条件语句,因为它仅在 API 4(冰淇淋三明治 == 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);
    

    【讨论】:

      【解决方案7】:

      如果你想启动另一个应用程序中的服务。你可以使用这个:

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

      【讨论】:

        【解决方案8】:

        这对我有用..这在棒棒糖中使用 android sdk 21..

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

        【讨论】:

        • 如果 ServiceClassName 在其他 apk 中怎么办?
        【解决方案9】:

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

        https://github.com/khalidb91/GAPlugin

        【讨论】:

          【解决方案10】:

          这对我有用:

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

          【讨论】:

            【解决方案11】:

            如果你正在尝试启动服务,可以这样尝试:

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

            【讨论】:

            • typeof 不是正确的 Java 方法。
            猜你喜欢
            • 2015-02-12
            • 1970-01-01
            • 1970-01-01
            • 2015-01-26
            • 2015-01-26
            • 2014-08-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多