Android 5.0(L)Service Intent必须在Google Analytics中明确

时间:2014-10-23 14:34:07

标签: android-5.0-lollipop illegalargumentexception

我的代码工作在< 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及更低版本上运行。那么我需要做什么?我将在下面发布相关代码。此外,在我的谷歌搜索期间,我发现了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作为明确意图运行。

11 个答案:

答案 0 :(得分: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 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

答案 1 :(得分:38)

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

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

如果在一般情况下没有合适的库升级,则需要修改源代码(在您的情况下为com.google.analytics.tracking.android.AnalyticsGmsCoreClient.connect()),以便在调用intent.setPackage(packageName)之前调用bindService() intentbindService()电话的第一个参数,packageName是包含代码尝试启动的服务的软件包的名称(在您的情况下&#34; com.google。 android.gms.analytics&#34)。

您可以使用此代码作为示例: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)。

答案 2 :(得分:21)

从Google Analytics v2迁移到v3可以解决我的问题。

答案 3 :(得分:14)

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

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

因为你没有发布你的活动代码,我不知道你现在是怎么开始的,但它应该看起来像这样:

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

答案 4 :(得分:8)

我使用了this,效果很好

[NSAppearance appearanceNamed:NSAppearanceNameAqua]

答案 5 :(得分: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);

答案 6 :(得分: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);

答案 7 :(得分:1)

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

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

答案 8 :(得分:1)

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

https://github.com/khalidb91/GAPlugin

答案 9 :(得分:0)

这对我有用:

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

答案 10 :(得分:-2)

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

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