提问人:ASD 提问时间:4/9/2023 最后编辑:Frank van PuffelenASD 更新时间:4/9/2023 访问量:167
当应用程序处于前台时,如何接收和显示来自 firebase 的通知?
How to recieve and show up notifications from firebase when app is on foreground?
问:
我正在使用 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 通知,但它们都在应用程序的主类中执行,所以我显然不明白它
答: 暂无答案
评论