web-dev-qa-db-ja.com

Android 5.0(L)サービス分析はGoogleアナリティクスで明示的に指定する必要があります

私のコードは<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を明示的な意図として実行しようとします。

68
Jacksonkr

Googleアナリティクスv2からv3に移行すると、問題が解決します。

21
nickkadrov

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

44
milosmns

Android 5.0(Lollipop)以降、bindService()は常に明示的な目的で呼び出す必要があります。これは以前は推奨事項でしたが、Lollipop以降では強制されます。暗黙のインテントを使用してbindService()の呼び出しが行われるたびにJava.lang.IllegalArgumentException: Service Intent must be explicitがスローされます。暗黙的意図と明示的意図の違いは、後者が名前(完全修飾クラス名)で開始するコンポーネントを指定することです。 インテントタイプに関するドキュメントを参照してください。

発生している問題は、Android 5 Lollipopでサービスをバインドする際の暗黙的なインテントに関するAndroidの制限に準拠するGoogleライブラリの新しいバージョンにアップグレードしていないことが原因です。この問題を修正するには、ライブラリを新しいバージョンにアップグレードし(使用可能な場合)、ライブラリコードを自分で更新して、変更したバージョンでプロジェクトをビルドします。

一般的なケースで適切なライブラリのアップグレードがない場合は、com.google.analytics.tracking.Android.AnalyticsGmsCoreClient.connect()を呼び出す前にintent.setPackage(packageName)を呼び出すようにソースコードを変更する必要があります(bindService())。ここで、intentbindService()呼び出しの最初の引数とpackageNameは、コードが開始しようとしているサービスを含むパッケージの名前です(この場合は「com.google.Android.gms.analytics」)。

これを行う方法の例として、このコードを使用できます。 nityのGoogle Licensing Library(LVL)の更新バージョン。明示的な意図でbindServiceを呼び出し、IllegalArgumentExceptionになりません。

さらに問題を回避する別の方法は、19以下でtargetSDKを使用してプロジェクトとgoogleライブラリを再構築することです。これにより、Lollipopでクラッシュすることなく実行されますが、安全性が低いオプションであり、以降のバージョンで導入されたSDK機能を使用できなくなります(Android 5の場合)。

38
Maria

私はこの問題を自分で抱えていました。問題は、サービスを開始するアクティビティにあります。

基本的に、明示的なインテントは、サービスの開始時にインテント内でサービスに直接名前を付けます。より詳細な説明については、 http://developer.Android.com/guide/components/intents-filters.html を参照してください。

アクティビティコードが投稿されていないため、今どのように開始しているのかわかりませんが、おそらく次のようになります。

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

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

私は、ユーザーが古いデバイスを使用できるようにするプロジェクトに取り組んでいます。 Mariasの回答に記載されているものと同じソリューションを思い付きましたが、API [4](アイスクリームサンドイッチ== SDK 14)以降でのみ使用できるため、setPackage呼び出しの条件ステートメントを追加しました。 。それ以下のバージョン用に開発している場合、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);
4
kumaheiyama

別のアプリケーションにあるサービスを開始したい場合、これを使用できます:

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

これは私のために働いた。これはAndroid SDK 21を使用してLollipopで働いた。

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

このエラーが表示されるPhoneGap/Cordovaユーザーの場合、準公式のGAPluginが非推奨のGoogle Analytics v2 libを使用しているためです。 khalidb91はそれを分岐し、v3に更新しました。この記事の執筆時点では、半公式のプラグインにはマージされていません。彼のフォークからコードを取得し、plugins/com.Adobe.plugins.GAPluginへの直接の置き換えとしてドロップすれば、クラッシュすることはありません。ありがとうkhalidb91!

https://github.com/khalidb91/GAPlugin

1
pmont

これは私のために働く:

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