当应用程序处于前台时,如何接收和显示来自 firebase 的通知?

How to recieve and show up notifications from firebase when app is on foreground?

提问人:ASD 提问时间:4/9/2023 最后编辑:Frank van PuffelenASD 更新时间:4/9/2023 访问量:167

问:

我正在使用 kivy 框架(在 python 上)开发一个应用程序,我使用 pushyy,它是一个库,让我可以在应用程序处于后台时接收和显示通知,但我不知道如何让它们在应用程序处于前台时显示,文档如下:

P.S.:我是java的新手,所以如果这对你来说不难,请你回答更多细节,Thanl you!

ContextHolder.java:

// Copyright 2020 The Chromium Authors. All rights reserved.
package org.kivy.plugins.messaging;

import android.content.Context;
import android.util.Log;

public class ContextHolder {
    private static Context applicationContext;

    public static Context getApplicationContext() {
        return applicationContext;
    }

    public static void setApplicationContext(Context applicationContext) {
        Log.d("KVFireContextHolder", "received application context.");
        ContextHolder.applicationContext = applicationContext;
    }
}

KivyFirebaseMessagingBackgroundExecutor.java:

// Copyright 2020 The Chromium Authors. All rights reserved.
package org.kivy.plugins.messaging;

import android.util.Log;

import java.util.concurrent.atomic.AtomicBoolean;

public class KivyFirebaseMessagingBackgroundExecutor {
private static AtomicBoolean started = new AtomicBoolean(false);
    public static void startBackgroundPythonService() {

        Log.d("BackgroundExecutor", "Starting background service");
        ru.asoms.myapp.ServicePythonnotificationhandler.start(ContextHolder.getApplicationContext(), "");
        Log.d("BackgroundExecutor", "Background service started");

    }

}

KivyFirebaseMessagingBackgroundService.java:

// Copyright 2020 The Chromium Authors. All rights reserved.
package org.kivy.plugins.messaging;


import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;

import com.google.firebase.messaging.RemoteMessage;

import java.util.Map;
import java.util.concurrent.CountDownLatch;

public class KivyFirebaseMessagingBackgroundService extends JobIntentService {
    private static final String TAG = "KVFireMsgService";

    /**
     * Schedule the message to be handled by the {@link KivyFirebaseMessagingBackgroundService}.
     */
    public static void enqueueMessageProcessing(Context context, Intent messageIntent) {
        enqueueWork(
                context,
                KivyFirebaseMessagingBackgroundService.class,
                KivyFirebaseMessagingUtils.JOB_ID,
                messageIntent);
    }

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

    @Override
    protected void onHandleWork(@NonNull final Intent intent) {


        // There were no pre-existing callback requests. Execute the callback
        // specified by the incoming intent.
        final CountDownLatch latch = new CountDownLatch(1);

        new Handler(getMainLooper())
                .post(new Runnable() {
                          @Override
                          public void run() {
                              RemoteMessage remoteMessage =
                                      intent.getParcelableExtra(KivyFirebaseMessagingUtils.EXTRA_REMOTE_MESSAGE);
                              if (remoteMessage != null) {
                                  Map<String, Object> remoteMessageMap =
                                          KivyFirebaseMessagingUtils.remoteMessageToMap(remoteMessage);
                                  remoteMessageMap.put("unique_key", Math.random() + "");
                                  PlatformIntermediate.addbackroundMessage(remoteMessageMap, ContextHolder.getApplicationContext());
                              }
                              // End
                              latch.countDown();
                          }
                      }
                );

        try {
            latch.await();
        } catch (InterruptedException ex) {
            Log.i(TAG, "Exception waiting to execute Python callback", ex);
        }
    }
}

KivyFireBaseMessagingReceiver.java:

// Copyright 2020 The Chromium Authors. All rights reserved.
package org.kivy.plugins.messaging;


import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.google.firebase.messaging.RemoteMessage;
import java.util.HashMap;


public class KivyFirebaseMessagingReceiver extends BroadcastReceiver {
    private static final String TAG = "FLTFireMsgReceiver";
    static HashMap<String, RemoteMessage> notifications = new HashMap<>();

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "broadcast received for message");
        if (ContextHolder.getApplicationContext() == null) {
            ContextHolder.setApplicationContext(context.getApplicationContext());
        }

        RemoteMessage remoteMessage = new RemoteMessage(intent.getExtras());

        // Store the RemoteMessage if the message contains a notification payload.
        if (remoteMessage.getNotification() != null) {
            notifications.put(remoteMessage.getMessageId(), remoteMessage);
            KivyFirebaseMessagingStore.getInstance().storeFirebaseMessage(remoteMessage);
        }

        //  |-> ---------------------
        //      App in Foreground
        //   ------------------------
        if (KivyFirebaseMessagingUtils.isApplicationForeground(context)) {
            Log.d(TAG, "Setting the foreground. BTW, title is " + remoteMessage.getNotification().getTitle());
            PlatformIntermediate.setForegroundMessage(KivyFirebaseMessagingUtils.remoteMessageToMap(remoteMessage));
            return;
        }



        //  |-> ---------------------
        //    App in Background/Quit
        //   ------------------------
        Log.d(TAG, "App in Background/Quit " + remoteMessage.getNotification().getTitle());
//        HashMap<String, Object> payload = new HashMap<>();
//        payload.put("unique_key", Math.random());
//        payload.put("payload_type", "BACKGROUND_MSG");
//        payload.put("data", KivyFirebaseMessagingUtils.remoteMessageToMap(remoteMessage));
//        Gson gson = new Gson();
//        String json = gson.toJson(payload);
//        backgroundMessages.put(Math.random()+"",json);
//        com.waterfall.youtube.ServicePythonnotificationhandler.start(org.kivy.android.PythonActivity.mActivity, json);
        // Issue with above is it relies on the Python service to be not running. Moment it's already running and you try starting
        // it, Android won't allow that.

        Intent onBackgroundMessageIntent =
                new Intent(context, org.kivy.plugins.messaging.KivyFirebaseMessagingBackgroundService.class);
        onBackgroundMessageIntent.putExtra(
                KivyFirebaseMessagingUtils.EXTRA_REMOTE_MESSAGE, remoteMessage);
        org.kivy.plugins.messaging.KivyFirebaseMessagingBackgroundService.enqueueMessageProcessing(
                context, onBackgroundMessageIntent);
    }
}

KivyFirebaseMessagingService.java:

// Copyright 2020 The Chromium Authors. All rights reserved.
package org.kivy.plugins.messaging;



import androidx.annotation.NonNull;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class KivyFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onNewToken(@NonNull String token) {
        PlatformIntermediate.token = token;
    }

    @Override
    public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
        // Added for commenting purposes;
        // We don't handle the message here as we already handle it in the receiver and don't want to duplicate.
    }
}

KivyFirebaseMessagingStore.java:

// Copyright 2020 The Chromium Authors. All rights reserved.
package org.kivy.plugins.messaging;


import android.content.Context;
import android.content.SharedPreferences;
import com.google.firebase.messaging.RemoteMessage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class KivyFirebaseMessagingStore {
    private static final String PREFERENCES_FILE = "io.flutter.plugins.firebase.messaging";
    private static final String KEY_NOTIFICATION_IDS = "notification_ids";
    private static final int MAX_SIZE_NOTIFICATIONS = 20;
    private static KivyFirebaseMessagingStore instance;
    private final String DELIMITER = ",";
    private SharedPreferences preferences;

    public static KivyFirebaseMessagingStore getInstance() {
        if (instance == null) {
            instance = new KivyFirebaseMessagingStore();
        }
        return instance;
    }

    private SharedPreferences getPreferences() {
        if (preferences == null) {
            preferences =
                    ContextHolder.getApplicationContext()
                            .getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE);
        }
        return preferences;
    }

    public void setPreferencesStringValue(String key, String value) {
        getPreferences().edit().putString(key, value).apply();
    }

    public String getPreferencesStringValue(String key, String defaultValue) {
        return getPreferences().getString(key, defaultValue);
    }

    public void storeFirebaseMessage(RemoteMessage remoteMessage) {
        String remoteMessageString =
                new JSONObject(KivyFirebaseMessagingUtils.remoteMessageToMap(remoteMessage)).toString();
        setPreferencesStringValue(remoteMessage.getMessageId(), remoteMessageString);

        // Save new notification id.
        // Note that this is using a comma delimited string to preserve ordering. We could use a String Set
        // on SharedPreferences but this won't guarantee ordering when we want to remove the oldest added ids.
        String notifications = getPreferencesStringValue(KEY_NOTIFICATION_IDS, "");
        notifications += remoteMessage.getMessageId() + DELIMITER; // append to last

        // Check and remove old notification messages.
        List<String> allNotificationList =
                new ArrayList<>(Arrays.asList(notifications.split(DELIMITER)));
        if (allNotificationList.size() > MAX_SIZE_NOTIFICATIONS) {
            String firstRemoteMessageId = allNotificationList.get(0);
            getPreferences().edit().remove(firstRemoteMessageId).apply();
            notifications = notifications.replace(firstRemoteMessageId + DELIMITER, "");
        }

        setPreferencesStringValue(KEY_NOTIFICATION_IDS, notifications);
    }

    public RemoteMessage getFirebaseMessage(String remoteMessageId) {
        String remoteMessageString = getPreferencesStringValue(remoteMessageId, null);
        if (remoteMessageString != null) {
            try {
                Map<String, Object> argumentsMap = new HashMap<>(1);
                Map<String, Object> messageOutMap = jsonObjectToMap(new JSONObject(remoteMessageString));
                // Add a fake 'to' - as it's required to construct a RemoteMessage instance.
                messageOutMap.put("to", remoteMessageId);
                argumentsMap.put("message", messageOutMap);
                return KivyFirebaseMessagingUtils.getRemoteMessageForArguments(argumentsMap);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public void removeFirebaseMessage(String remoteMessageId) {
        getPreferences().edit().remove(remoteMessageId).apply();
        String notifications = getPreferencesStringValue(KEY_NOTIFICATION_IDS, "");
        if (!notifications.isEmpty()) {
            notifications = notifications.replace(remoteMessageId + DELIMITER, "");
            setPreferencesStringValue(KEY_NOTIFICATION_IDS, notifications);
        }
    }

    private Map<String, Object> jsonObjectToMap(JSONObject jsonObject) throws JSONException {
        Map<String, Object> map = new HashMap<>();
        Iterator<String> keys = jsonObject.keys();
        while (keys.hasNext()) {
            String key = keys.next();
            Object value = jsonObject.get(key);
            if (value instanceof JSONArray) {
                value = jsonArrayToList((JSONArray) value);
            } else if (value instanceof JSONObject) {
                value = jsonObjectToMap((JSONObject) value);
            }
            map.put(key, value);
        }
        return map;
    }

    public List<Object> jsonArrayToList(JSONArray array) throws JSONException {
        List<Object> list = new ArrayList<>();
        for (int i = 0; i < array.length(); i++) {
            Object value = array.get(i);
            if (value instanceof JSONArray) {
                value = jsonArrayToList((JSONArray) value);
            } else if (value instanceof JSONObject) {
                value = jsonObjectToMap((JSONObject) value);
            }
            list.add(value);
        }
        return list;
    }
}

KivyFirebaseMessagingUtils.java:

// Copyright 2020 The Chromium Authors. All rights reserved.
package org.kivy.plugins.messaging;

import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.content.Context;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.RemoteMessage;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

class KivyFirebaseMessagingUtils {
    static final String IS_AUTO_INIT_ENABLED = "isAutoInitEnabled";
    static final String SHARED_PREFERENCES_KEY = "io.flutter.firebase.messaging.callback";
    static final String ACTION_REMOTE_MESSAGE = "io.flutter.plugins.firebase.messaging.NOTIFICATION";
    static final String EXTRA_REMOTE_MESSAGE = "notification";
    static final String ACTION_TOKEN = "io.flutter.plugins.firebase.messaging.TOKEN";
    static final String EXTRA_TOKEN = "token";
    static final int JOB_ID = 2020;
    private static final String KEY_COLLAPSE_KEY = "collapseKey";
    private static final String KEY_DATA = "data";
    private static final String KEY_FROM = "from";
    private static final String KEY_MESSAGE_ID = "messageId";
    private static final String KEY_MESSAGE_TYPE = "messageType";
    private static final String KEY_SENT_TIME = "sentTime";
    private static final String KEY_TO = "to";
    private static final String KEY_TTL = "ttl";

    static Map<String, Object> remoteMessageToMap(RemoteMessage remoteMessage) {
        Map<String, Object> messageMap = new HashMap<>();
        Map<String, Object> dataMap = new HashMap<>();

        if (remoteMessage.getCollapseKey() != null) {
            messageMap.put(KEY_COLLAPSE_KEY, remoteMessage.getCollapseKey());
        }

        if (remoteMessage.getFrom() != null) {
            messageMap.put(KEY_FROM, remoteMessage.getFrom());
        }

        if (remoteMessage.getTo() != null) {
            messageMap.put(KEY_TO, remoteMessage.getTo());
        }

        if (remoteMessage.getMessageId() != null) {
            messageMap.put(KEY_MESSAGE_ID, remoteMessage.getMessageId());
        }

        if (remoteMessage.getMessageType() != null) {
            messageMap.put(KEY_MESSAGE_TYPE, remoteMessage.getMessageType());
        }

        if (remoteMessage.getData().size() > 0) {
            Set<Map.Entry<String, String>> entries = remoteMessage.getData().entrySet();
            for (Map.Entry<String, String> entry : entries) {
                dataMap.put(entry.getKey(), entry.getValue());
            }
        }

        messageMap.put(KEY_DATA, dataMap);
        messageMap.put(KEY_TTL, remoteMessage.getTtl());
        messageMap.put(KEY_SENT_TIME, remoteMessage.getSentTime());

        if (remoteMessage.getNotification() != null) {
            messageMap.put(
                    "notification", remoteMessageNotificationToMap(remoteMessage.getNotification()));
        }

        return messageMap;
    }

    private static Map<String, Object> remoteMessageNotificationToMap(
            RemoteMessage.Notification notification) {
        Map<String, Object> notificationMap = new HashMap<>();
        Map<String, Object> androidNotificationMap = new HashMap<>();

        if (notification.getTitle() != null) {
            notificationMap.put("title", notification.getTitle());
        }

        if (notification.getTitleLocalizationKey() != null) {
            notificationMap.put("titleLocKey", notification.getTitleLocalizationKey());
        }

        if (notification.getTitleLocalizationArgs() != null) {
            notificationMap.put("titleLocArgs", Arrays.asList(notification.getTitleLocalizationArgs()));
        }

        if (notification.getBody() != null) {
            notificationMap.put("body", notification.getBody());
        }

        if (notification.getBodyLocalizationKey() != null) {
            notificationMap.put("bodyLocKey", notification.getBodyLocalizationKey());
        }

        if (notification.getBodyLocalizationArgs() != null) {
            notificationMap.put("bodyLocArgs", Arrays.asList(notification.getBodyLocalizationArgs()));
        }

        if (notification.getChannelId() != null) {
            androidNotificationMap.put("channelId", notification.getChannelId());
        }

        if (notification.getClickAction() != null) {
            androidNotificationMap.put("clickAction", notification.getClickAction());
        }

        if (notification.getColor() != null) {
            androidNotificationMap.put("color", notification.getColor());
        }

        if (notification.getIcon() != null) {
            androidNotificationMap.put("smallIcon", notification.getIcon());
        }

        if (notification.getImageUrl() != null) {
            androidNotificationMap.put("imageUrl", notification.getImageUrl().toString());
        }

        if (notification.getLink() != null) {
            androidNotificationMap.put("link", notification.getLink().toString());
        }

        if (notification.getNotificationCount() != null) {
            androidNotificationMap.put("count", notification.getNotificationCount());
        }

        if (notification.getNotificationPriority() != null) {
            androidNotificationMap.put("priority", notification.getNotificationPriority());
        }

        if (notification.getSound() != null) {
            androidNotificationMap.put("sound", notification.getSound());
        }

        if (notification.getTicker() != null) {
            androidNotificationMap.put("ticker", notification.getTicker());
        }

        if (notification.getVisibility() != null) {
            androidNotificationMap.put("visibility", notification.getVisibility());
        }

        if (notification.getTag() != null) {
            androidNotificationMap.put("tag", notification.getTag());
        }

        notificationMap.put("android", androidNotificationMap);
        return notificationMap;
    }

    /**
     * Identify if the application is currently in a state where user interaction is possible. This
     * method is called when a remote message is received to determine how the incoming message should
     * be handled.
     *
     * @param context context.
     * @return True if the application is currently in a state where user interaction is possible,
     *     false otherwise.
     */
    static boolean isApplicationForeground(Context context) {
        KeyguardManager keyguardManager =
                (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);

        if (keyguardManager != null && keyguardManager.isKeyguardLocked()) {
            return false;
        }

        ActivityManager activityManager =
                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        if (activityManager == null) return false;

        List<ActivityManager.RunningAppProcessInfo> appProcesses =
                activityManager.getRunningAppProcesses();
        if (appProcesses == null) return false;

        final String packageName = context.getPackageName();
        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
                    && appProcess.processName.equals(packageName)) {
                return true;
            }
        }

        return false;
    }

    // Extracted to handle multi-app support in the future.
    // arguments.get("appName") - to get the Firebase app name.
    static FirebaseMessaging getFirebaseMessagingForArguments(Map<String, Object> arguments) {
        return FirebaseMessaging.getInstance();
    }

    /**
     * Builds an instance of {@link RemoteMessage} from Flutter method channel call arguments.
     *
     * @param arguments Method channel call arguments.
     * @return RemoteMessage
     */
    static RemoteMessage getRemoteMessageForArguments(Map<String, Object> arguments) {
        @SuppressWarnings("unchecked")
        Map<String, Object> messageMap =
                (Map<String, Object>) Objects.requireNonNull(arguments.get("message"));

        String to = (String) Objects.requireNonNull(messageMap.get("to"));
        RemoteMessage.Builder builder = new RemoteMessage.Builder(to);

        String collapseKey = (String) messageMap.get("collapseKey");
        String messageId = (String) messageMap.get("messageId");
        String messageType = (String) messageMap.get("messageType");
        Integer ttl = (Integer) messageMap.get("ttl");

        @SuppressWarnings("unchecked")
        Map<String, String> data = (Map<String, String>) messageMap.get("data");

        if (collapseKey != null) {
            builder.setCollapseKey(collapseKey);
        }

        if (messageType != null) {
            builder.setMessageType(messageType);
        }

        if (messageId != null) {
            builder.setMessageId(messageId);
        }

        if (ttl != null) {
            builder.setTtl(ttl);
        }

        if (data != null) {
            builder.setData(data);
        }

        return builder.build();
    }
}

PlatformIntermediate.java:

package org.kivy.plugins.messaging;

import android.content.Context;
import android.util.Log;

import com.google.gson.Gson;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

public class PlatformIntermediate {
    private static HashMap<String, Object> _foregroundMessage = new HashMap<String, Object>();
    final public static HashMap<String, Object> backgroundMessages = new HashMap<String, Object>();
    public static String token = "";
    private static final String BACKGROUND_MSG_FILE_NAME = "/background_messages.json";

    public static String getForegroundMessage() {
        return new Gson().toJson(_foregroundMessage);
    }

    public static void setForegroundMessage(Map<String, Object> msg) {
        HashMap<String, Object> copy = new HashMap<String, Object>(msg);
        _foregroundMessage = copy;

        _foregroundMessage.put("unique_key", Math.random());
        Log.d("PlatformIntermediate", "setForegroundMessage worked " + _foregroundMessage.toString());
    }

    public static void addbackroundMessage(Map<String, Object> remoteMessageMap, Context context) {
        try {
            ru.asoms.myapp.ServicePythonnotificationhandler.start(org.kivy.android.PythonActivity.mActivity, "");
        } catch (Exception e) {
            Log.d("PlatformIntermediate", "Exception occurred while trying to start service: " + e.getMessage());
        }
        backgroundMessages.put(remoteMessageMap.get("unique_key").toString(), remoteMessageMap);

        // Read stored json
        String jsonText = readBackgroundFile(context);

        Map<String, Object> map = new HashMap<String, Object>();
        if (jsonText.length() > 0) {
            map = (Map<String, Object>) new Gson().fromJson(jsonText, map.getClass());
        }
        boolean shouldRecreateFile = false;
        // Merge with map where key does not exist or create file if map size is 0
        if (map.size() == 0) {
            shouldRecreateFile = true;
        } else {
            for (String key : map.keySet()) {
                if (backgroundMessages.get(key) == null) {
                    backgroundMessages.put(key, map.get(key));
                    shouldRecreateFile = true;
                }
            }
        }
        // Write to file
        if (shouldRecreateFile) {
//            deleteBackgroundFile(context);
            writeBackgroundFile(new Gson().toJson(backgroundMessages), context);

        }
        Log.d("PlatformIntermediate", "New message added, recreated: "+shouldRecreateFile +" "+context.getFilesDir().getPath());
        if(shouldRecreateFile == false){
            Log.d("PlatformIntermediate", map.toString());

        }
    }

    public static void writeBackgroundFile(String data, Context context) {
        try (Writer writer = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(context.getFilesDir().getPath()+BACKGROUND_MSG_FILE_NAME), "utf-8"))) {
            writer.write(data);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String readBackgroundFile(Context context) {
        String ret = "";
        try (BufferedReader br = new BufferedReader(new FileReader(context.getFilesDir().getPath()+BACKGROUND_MSG_FILE_NAME))) {
            StringBuilder sb = new StringBuilder();
            String line = br.readLine();
            while (line != null) {
                sb.append(line);
                sb.append("\n");
                line = br.readLine();
            }
            ret = sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ret;
    }
}

我是 java 的新手,所以我在前台搜索 firebase 通知,但它们都在应用程序的主类中执行,所以我显然不明白它

python java firebase firebase-cloud-messaging

评论

0赞 Сергей Кох 4/9/2023
请修剪您的代码,以便更轻松地找到您的问题。请遵循以下准则,创建一个最小的可重现示例

答: 暂无答案