【问题标题】:Push Notification shows Alert containing JSON with cordova-plugin-fcm, cordova, angular, and firebase with App in Foreground推送通知显示 Alert 包含 JSON 与 cordova-plugin-fcm、cordova、angular 和 firebase 与 App in Foreground
【发布时间】:2018-10-02 18:42:47
【问题描述】:

我有一个 Cordova/Angular 应用程序,它使用 firebase 通过 cordova-plugin-fcm 插件进行推送通知。当应用程序关闭/在后台时,通知会正确显示在栏中,但是当通过点击栏通知(或已经打开)打开应用程序时,通知本身只是一个包含 JSON 警报对象的警报框,而不是格式化的通知。

public class MyFirebaseMessagingService extends FirebaseMessagingService {

private static final String TAG = "FCMPlugin";
String message = "";
String title = "";

/**
 * Called when message is received.
 *
 * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
 */
// [START receive_message]
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // If the application is in the foreground handle both data and notification messages here.
    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
    Log.d(TAG, "==> MyFirebaseMessagingService onMessageReceived");
    if (remoteMessage.getData().size() > 0) {
        message = getDataWithKey(remoteMessage.getData(), "message");
        title = getDataWithKey(remoteMessage.getData(), "title");
    }

    if( remoteMessage.getNotification() != null){
        Log.d(TAG, "\tNotification Title: " + remoteMessage.getNotification().getTitle());
        Log.d(TAG, "\tNotification Message: " + remoteMessage.getNotification().getBody());
    };

    Map<String, Object> data = new HashMap<String, Object>();
    data.put("wasTapped", false);
    for (String key : remoteMessage.getData().keySet()) {
            Object value = remoteMessage.getData().get(key);
            Log.d(TAG, "\tKey: " + key + " Value: " + value);
            data.put(key, value);
    };

    Log.d(TAG, "\tNotification Data: " + data.toString());
    FCMPlugin.sendPushPayload( data );
    sendNotification(title, message, data);
}
// [END receive_message]

private String getDataWithKey(Map<String, String> params, String fieldKey) {
    String data = "";
    try {
        for (Map.Entry<String, String> param : params.entrySet()) {
            String key = param.getKey();
            String value = param.getValue();
            if(key.contentEquals(fieldKey)){
                if(!value.isEmpty()) {
                    data = value;
                }
            }
        }
    }
    catch (Exception ex){
        Log.e(TAG, "  getDataWithKey -- " + ex.getMessage());
    }
    return data;
}

/**
 * Create and show a simple notification containing the received FCM message.
 *
 * @param messageBody FCM message body received.
 */
private void sendNotification(String title, String messageBody, Map<String, Object> data) {

    Intent intent = new Intent(this, FCMPluginActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    for (String key : data.keySet()) {
        intent.putExtra(key, data.get(key).toString());
    }
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
            PendingIntent.FLAG_ONE_SHOT);

    Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
            .setSmallIcon(getApplicationInfo().icon)
            .setContentTitle(title)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent);

    NotificationManager notificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());

}

}

根据一切,我可以发现我已经正确实现了插件,但是我的通知是丑陋的 AF,因为一个充满 JSON 的警报框是人类不可读的。

这是通过 REST API 发送的 JSON 对象:

{  
   "to":"/topics/all",
   "priority":"high",
   "notification":{  
   "title":"App in Foreground Test",
   "body":"Test App in Foreground",
   "sound":"default",
   "click_action":"FCM_PLUGIN_ACTIVITY",
   "icon":"fcm_push_icon"
},
 "data":{  
   "title":"App in Foreground Test",
   "message":"Test with app in Foreground",
   "param1":"value1",
   "param2":"value2"
 }
  }

同时发送通知和数据负载,以便我在应用处于后台和前台时收到通知。

    public static void sendPushPayload(Map<String, Object> payload) {
    Log.d(TAG, "==> FCMPlugin sendPushPayload");
    Log.d(TAG, "\tnotificationCallBackReady: " + notificationCallBackReady);
    Log.d(TAG, "\tgWebView: " + gWebView);
    try {
        JSONObject jo = new JSONObject();
        for (String key : payload.keySet()) {
            jo.put(key, payload.get(key));
            Log.d(TAG, "\tpayload: " + key + " => " + payload.get(key));
        }
        String callBack = "javascript:" + notificationCallBack + "(" + jo.toString() + ")";
        if(notificationCallBackReady && gWebView != null){
            Log.d(TAG, "\tSent PUSH to view: " + callBack);
            gWebView.sendJavascript(callBack);
        }else {
            Log.d(TAG, "\tView not ready. SAVED NOTIFICATION: " + callBack);
            lastPush = payload;
        }
    } catch (Exception e) {
        Log.d(TAG, "\tERROR sendPushToView. SAVED NOTIFICATION: " + e.getMessage());
        lastPush = payload;
    }
}

【问题讨论】:

  • Jon:: 当然这不可能是您正在使用的代码,因为它甚至不应该编译。没有声明变量“消息”或“标题”。您还更改了getDataWithKey(),使其返回与方法返回类型相矛盾的Map
  • 对不起,错误的代码,我已经修改了一些代码以尝试将对象(数据)传递给请求private void sendNotification(String title, String messageBody, Map&lt;String, Object&gt; data) {...的sendNotification方法
  • @Barns 进行澄清,我希望警报具有标题(在前台使用应用程序测试)而不是 ALERT,并且消息当然应该是文本的“正文”部分它目前拥有的 JSON ......(我删除了其他 2 个参数,因为它们是不需要的。
  • @Barns:: 在原始帖子中添加了 sendPushPayload 的代码
  • 我应该早点问的,但是您是在真实设备还是模拟器上进行测试?您的测试设备是什么 API 级别?以及问题顶部的图像。你说的“通知”是“丑陋的json”吗?

标签: android firebase push-notification angular6 cordova-plugin-fcm


【解决方案1】:

您在通知中收到“丑陋”的 JSON,因为您将消息正文直接添加为通知的内容。

.setContentText(messageBody)

messageBody 中提取相关信息并将该信息添加到.setContentText()

要从data 部分获取数据,您可以在onMessageReceived() 方法中添加类似的内容:

if (remoteMessage.getData().size() > 0) {
    message = getDataWithKey(remoteMessage.getData(), "message");
    title = getDataWithKey(remoteMessage.getData(), "title");
    param1 = getDataWithKey(remoteMessage.getData(), "param1");
    param2 = getDataWithKey(remoteMessage.getData(), "param2");
}

然后添加这个方法:

private String getDataWithKey(Map<String, String> params, String fieldKey) {
    String data = "";
    try {
        for (Map.Entry<String, String> param : params.entrySet()) {
            String key = param.getKey();
            String value = param.getValue();
            if(key.contentEquals(fieldKey)){
                if(!value.isEmpty()) {
                    data = value;
                }
            }
        }
    }
    catch (Exception ex){
        Log.e(TAG, "  getDataWithKey -- " + ex.getMessage());
    }
    return data;
}



编辑

“丑陋”通知不是来自Notification,而是来自代码中的其他地方,因为它与此代码中添加的数据完全相同:

Map<String, Object> data = new HashMap<String, Object>();
    data.put("wasTapped", false); 
...

我看到您至少在两个地方使用它:

FCMPlugin.sendPushPayload( data );

for (String key : data.keySet()) {
    intent.putExtra(key, data.get(key).toString());
}


还要考虑: 较新的 Android 操作系统版本需要 NotificationChannel 才能正常工作。示例代码(您需要更改其中的某些部分以满足您的需要):

private void sendNotification(String title, String messageBody, Map<String, Object> data) {
    try{
        Intent intent = new Intent(this, BusinessDetailActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        for (String key : data.keySet()) {
            intent.putExtra(key, data.get(key).toString());
        }

        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                                                                0,
                                                                intent,
                                                                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT); // PendingIntent.FLAG_ONE_SHOT);

        String idNotification = createNotificationChannel();
        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, idNotification)
                .setContentTitle(title)
                .setContentText(body)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setCategory(NotificationCompat.CATEGORY_PROMO)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent)
                .setSmallIcon(SMALL_ICON);

        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            //TODO: You will need to define your own ID_NOTIFICATION!!
            notificationBuilder.setChannelId(ID_NOTIFICATION);
        }

        NotificationManager notificationManager = getSystemService(NotificationManager.class);

        //TODO: I use a random number generator, but you do what fits your needs
        int idNot = CodeGenerator.getRandomNumber(10, 10000);
        assert (notificationManager != null);
        notificationManager.notify(idNot, notificationBuilder.build());
    }
    catch (Exception ex){
        Log.e(TAG, "  sendNotification --- " + ex.getMessage());
    }
}



private String createNotificationChannel() {
    //TODO: You will need to define your own ID_NOTIFICATION!!
    String id = ID_NOTIFICATION;
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String name = "Special Notification";
            String desc = "Notification showing special information.";
            int prio = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(id, name, prio);
            channel.setShowBadge(true);
            channel.setDescription(desc);
            channel.setLightColor(Color.RED);
            channel.enableLights(true);
            channel.enableVibration(true);

            NotificationManager manager = getSystemService(NotificationManager.class);
            assert (manager != null);
            manager.createNotificationChannel(channel);
        }
    }
    catch (Exception ex){
        Log.e(TAG, ex.getMessage());
    }
    return id;
}

【讨论】:

  • 现在尝试,如果测试通过,将设置为接受的答案
  • @JonSmith :: 请注意,包含 DataNotification 部分的 Firebase 云消息由应用程序处理,而不是仅包含 Data 部分的消息。不幸的是,iOS 处理消息的方式与 Android 不同。出于这个原因,我发送不同类型的消息,以便每个操作系统。请参阅文档以了解如何使用 :: firebase.google.com/docs/cloud-messaging/android/receive
  • 感谢您的提醒,一旦我的 android 端工作,我将不得不实施 iOS,因为它是一个正在开发的跨平台应用程序。我会记住你的信息。谢谢您的帮助。我有一个限制性的环境,所以构建过程很长,我仍在测试你的修复。我会在确认修复工作正常后立即接受,再次感谢!
  • @JonSmith :: 正如我在回答中所说的那样——以if (remoteMessage.getData().size() &gt; 0) { 开头的代码必须进入您的onMessageReceived() 方法。根据错误,您必须将其放在方法之外。
  • API 是 Android-27
猜你喜欢
  • 1970-01-01
  • 2019-11-14
  • 2018-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-06
  • 2018-05-24
相关资源
最近更新 更多