Android 5.0 (Lollipop) Service Intent must be expl

2019-03-06 05:14发布

问题:

I am working on a widget and code is working fine on pre Lollipop devices but when I run my code on Lollipop, it gives me error Service Intent must be explicit: Intent { act=org.clangen.widget.clock.action.UPDATE }. I have Google this error but I did't understand even this [question] Android 5.0 (L) Service Intent must be explicit in Google analytics. Here is the logcat

02-19 15:07:21.888: E/AndroidRuntime(31621): FATAL EXCEPTION: main
02-19 15:07:21.888: E/AndroidRuntime(31621): Process: com.brainlogix.mezanhijricaleandarapp, PID: 31621
02-19 15:07:21.888: E/AndroidRuntime(31621): java.lang.RuntimeException: Unable to start receiver com.brainlogix.widget.ClockWidget: java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=org.clangen.widget.clock.action.UPDATE }
02-19 15:07:21.888: E/AndroidRuntime(31621):    at android.app.ActivityThread.handleReceiver(ActivityThread.java:2586)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at android.app.ActivityThread.access$1700(ActivityThread.java:144)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1355)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at android.os.Handler.dispatchMessage(Handler.java:102)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at android.os.Looper.loop(Looper.java:135)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at android.app.ActivityThread.main(ActivityThread.java:5221)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at java.lang.reflect.Method.invoke(Native Method)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at java.lang.reflect.Method.invoke(Method.java:372)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
02-19 15:07:21.888: E/AndroidRuntime(31621): Caused by: java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=org.clangen.widget.clock.action.UPDATE }
02-19 15:07:21.888: E/AndroidRuntime(31621):    at android.app.ContextImpl.validateServiceIntent(ContextImpl.java:1674)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1703)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at android.app.ContextImpl.startService(ContextImpl.java:1687)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at android.content.ContextWrapper.startService(ContextWrapper.java:515)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at android.content.ContextWrapper.startService(ContextWrapper.java:515)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at com.brainlogix.widget.ClockWidget.onUpdate(ClockWidget.java:122)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at android.appwidget.AppWidgetProvider.onReceive(AppWidgetProvider.java:66)
02-19 15:07:21.888: E/AndroidRuntime(31621):    at android.app.ActivityThread.handleReceiver(ActivityThread.java:2579)
02-19 15:07:21.888: E/AndroidRuntime(31621):    ... 9 more

Here is widget class with inner service

public class ClockWidget extends AppWidgetProvider {

    private static final String SHOW_POPUP_DIALOG_ACTION = "com.brainlogix.widget.Widget_PopUp";

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);

        context.startService(new Intent(UpdateService.ACTION_UPDATE));
    }

    public static final class UpdateService extends Service {       
        static final String ACTION_UPDATE = "org.clangen.widget.clock.action.UPDATE";           
        @Override
        public void onCreate() {
            super.onCreate();
            registerReceiver(mTimeChangedReceiver, sIntentFilter);
        }

        @Override
        public void onDestroy() {
            super.onDestroy();
            unregisterReceiver(mTimeChangedReceiver);
        }

        @Override
        public void onStart(Intent intent, int startId) {
            super.onStart(intent, startId);
        }

        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }       
        private void update() {
        //some code
        }   
        private final BroadcastReceiver mTimeChangedReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                final String action = intent.getAction();

                if (action.equals(Intent.ACTION_TIME_CHANGED)
                        || action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
                    // some code
                }
                update();
            }
        };
    }
}

Here is my manifest file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.brainlogix.mezanhijricaleandarapp"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="21" />

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/CustomTheme" >

       <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

        <receiver
            android:name="com.brainlogix.widget.ClockWidget"
            android:label="@string/widget_name" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/clock_widget" />
        </receiver>

        <service
            android:name="com.brainlogix.widget.ClockWidget$UpdateService"
            android:label="UpdateService" >
            <intent-filter>
                <action android:name="org.clangen.widget.clock.action.UPDATE" />
            </intent-filter>
        </service>
        <receiver android:name="com.brainlogix.widget.ClockWidget" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/demo_widget_provider" />
        </receiver>
        <receiver
            android:name="com.brainlogix.widget.MyWidgetIntentReceiver"
            android:label="@string/widget_name" >
            <intent-filter>
                <action android:name="com.javatechig.intent.action.UPDATE_WIDGET" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/demo_widget_provider" />
        </receiver>        
    </application>
</manifest>

回答1:

Instantiating an Intent with only an action creates what is referred to as an implicit Intent, since any component registered to handle that action will be started in order to do so. As of Lollipop, Services can no longer be started with implicit Intents due to security concerns. You merely need to be specific about the class the Intent is meant for; i.e., use an explicit Intent.

context.startService(new Intent(context, UpdateService.class));

You should also remove the <intent-filter> element from the Service in the manifest, as that is what allows your Service to be started with an implicit Intent, which is no longer allowed.