【问题标题】:Android service always runs even when app is not running即使应用程序未运行,Android 服务也始终运行
【发布时间】:2023-03-02 23:24:02
【问题描述】:

我想创建一个始终在后台运行的 android 服务,即使我们没有打开像 gmail 服务或 whatsapp 服务这样的应用程序,这样我们就可以在应用程序关闭时收到通知(但不是强制关闭)。即使应用程序关闭,我也想获得 gcm 通知,就像我们从最近的应用程序中换出应用程序一样。

现在,当我通过长按主页按钮关闭应用程序并将其交换应用程序关闭 ao 的所有组件时,我无法收到 gcm 通知。

我知道当应用程序被强制关闭时我们无法收到 gcm 通知。

我在这个问题上纠结了很久。有人知道如何处理这个问题

public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        ComponentName comp = new ComponentName(context.getPackageName(),
                GCMNotificationIntentService.class.getName());
        startWakefulService(context, (intent.setComponent(comp)));
        setResultCode(Activity.RESULT_OK);
        }
}

清单文件

    <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="xxxx"
    android:installLocation="internalOnly">

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />


    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATUS_AND_IDENTITY" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.VIBRATE" />


    <permission
        android:name="xxxx.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />

    <uses-permission android:name="xxxx.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="stateHidden" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>


        //it overrides WakefulBroadcastReceiver
        <receiver
            android:name=".gcm.GcmBroadcastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />

                <category android:name="xxxx" />
            </intent-filter>
        </receiver>

        //it overrides IntentService
        <service android:name=".gcm.GCMNotificationIntentService" />

    </application>

</manifest> 

   public class GCMNotificationIntentService extends IntentService {
    // Sets an ID for the notification, so it can be updated
    public static final int notifyID = 9001;
    private static final String TAG = GCMNotificationIntentService.class.getSimpleName();

    NotificationCompat.Builder builder;

    public GCMNotificationIntentService() {
        super("GcmIntentService");
    }


    @Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        String messageType = gcm.getMessageType(intent);
        if (!extras.isEmpty()) {
            if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
                    .equals(messageType)) {
                sendNotification("Send error: " + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
                    .equals(messageType)) {
                sendNotification("Deleted messages on server: "
                        + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
                    .equals(messageType)) {

                String incomingMessage = extras.get(ApplicationConstants.MSG_KEY)+"";
                String type = identifyHeaders(incomingMessage);
                String processedString = removeHeaders(incomingMessage, type);

                if(type.equals(NOTIFICATION_MESSAGE)) {
                    sendNotification(processedString);
                }else if(type.equals(NOTIFICATION_PHONE_CHANGE)){
                }
            }
        }
        GcmBroadcastReceiver.completeWakefulIntent(intent);
    }

    //this methos is for sending notification to notification bar
    private void sendNotification(String msg) {

    }

}

更新的 GCM 服务代码

public class GCMNotificationIntentService extends Service {
    // Sets an ID for the notification, so it can be updated
    public static final int notifyID = 9001;
    private static final String TAG = GCMNotificationIntentService.class.getSimpleName();

    public GCMNotificationIntentService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Log.d(TAG, "Service started");
        processIntent(intent);

        return START_STICKY;
    }

    void processIntent(Intent intent){

        Log.d(TAG, "notification received");

        Bundle extras = intent.getExtras();
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        String messageType = gcm.getMessageType(intent);
        if (!extras.isEmpty()) {
            if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
                    .equals(messageType)) {
                sendNotification("Send error: " + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
                    .equals(messageType)) {
                sendNotification("Deleted messages on server: "
                        + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
                    .equals(messageType)) {

                String incomingMessage = extras.get(ApplicationConstants.MSG_KEY)+"";
                String type = identifyHeaders(incomingMessage);
                String processedString = removeHeaders(incomingMessage, type);

                if(type.equals(NOTIFICATION_MESSAGE)) {
                    sendNotification(processedString);
                }else if(type.equals(NOTIFICATION_PHONE_CHANGE)){
                    updatePhoneNumber(processedString);
                }
            }
        }

        GcmBroadcastReceiver.completeWakefulIntent(intent);
    }



    private void sendNotification(String msg) {
        Intent resultIntent = new Intent(this, WelcomeScreen.class);
        resultIntent.putExtra("msg", msg);
        resultIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_SINGLE_TOP);

        PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0,
                resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder mNotifyBuilder;
        NotificationManager mNotificationManager;
        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        mNotifyBuilder = new NotificationCompat.Builder(this)
                .setContentTitle("GOODSERVICE")
                .setContentText("NEW LEAD FROM GOODSERVICE")
                .setSmallIcon(R.drawable.ic_launcher);

        mNotifyBuilder.setContentIntent(resultPendingIntent);

        // Set Vibrate, Sound and Light
        int defaults = 0;
        defaults = defaults | Notification.DEFAULT_LIGHTS;
        defaults = defaults | Notification.DEFAULT_VIBRATE;

        mNotifyBuilder.setDefaults(defaults);
        // Set the content for Notification
        mNotifyBuilder.setContentText("NEW LEAD FROM GOODSERVICE");
        // Set autocancel
        mNotifyBuilder.setAutoCancel(true);
        Uri soundTest =  Settings.System.DEFAULT_RINGTONE_URI;
        mNotifyBuilder.setSound(soundTest);
        // Post a notification
        mNotificationManager.notify(notifyID, mNotifyBuilder.build());
        Intent intentone = new Intent(this, HomeActivity.class);
        intentone.putExtra("msg", msg);
        intentone.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        this.startActivity(intentone);
    }

}

这就是我调用此服务的方式

    ComponentName comp = new ComponentName(context.getPackageName(),
            GCMNotificationIntentService.class.getName());
    startWakefulService(context, (intent.setComponent(comp)));
    startWakefulService(context, (intent.setComponent(comp)));
    setResultCode(Activity.RESULT_OK);

【问题讨论】:

  • 您的服务已被破坏,因为您破坏了生成服务的进程(长按关闭)。我希望您的服务不绑定到您的 Activity,但由于您的进程已被终止,因此您的服务也是如此。理想情况下,Android 应该重新启动所有这些被破坏的服务,但它们将从头开始。
  • 使用 START_STICKY developer.android.com/reference/android/app/… 或使用 startForeground(int,Notification) 但这会一直向用户显示通知,我认为这不是 gcm 的理想选择
  • 我添加了一张图片,其中应用程序的服务始终在前台运行。你试过做这样的事情吗?我已经尝试过这些选项,但是当我长按关闭时服务正在停止
  • 你知道gcm的任何方法吗?
  • 进程死了 ---> 所有组件都死了(活动、服务等)。在你的 onStartCommand() 中返回 Service.START_STICKY,Android 会在进程被杀死时重启你的服务!

标签: android android-layout android-activity android-service


【解决方案1】:

IntentService 不会在后台连续运行。它们只会运行一次,当它们完成时,它们将被销毁。 你应该检查Service。即使应用程序关闭,它们也不会被销毁。 覆盖其函数onStartCommandCheck this answer for more detailed difference.

【讨论】:

  • 即使应用程序关闭,它们也不会被破坏哦,它们是。但不同的是他们可以自己重启
【解决方案2】:

您正在寻找WakefulBroadcastReceiverIntentService

这将帮助你https://developer.android.com/google/gcm/client.html

【讨论】:

  • 我已经实现了它,但问题是当我长按关闭时,我停止收到通知,因为我的应用程序的所有组件都已关闭。我正在考虑一种打开应用程序组件的方式,以便我可以获取 GCM 通知
  • 这不起作用,因为当您强制关闭应用程序时,它的后台服务也会关闭。尝试强制关闭 gmail 和 whatsapp 你也不会收到他们的通知。
  • 但这不是强制关闭的。我从最近的应用程序中换掉了whatsapp,而不是收到通知。强制关闭是当我进入设置->应用程序->强制关闭
  • 我在最近的应用程序中没有显示应用程序时粘贴了一张图片,我们可以看到 Whatsapp 和 Facebook 正在运行 1 个进程和 1 个服务,我相信这就是为什么我们可以在应用程序关闭时收到通知
  • 好吧,当你长按返回按钮时,强制关闭。从最近的应用程序中滑出是不同的。这不会关闭后台服务。如果您正确地实现了IntentServiceWakefulBroadcastReceiver,那么从最近刷出应该不会影响GCM 的工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多