Firebase FCM 通知 click_action 负载

Firebase FCM notifications click_action payload

当用户在应用程序处于后台时单击通知时,我试图打开一个特定的 activity。从文档中,我了解到必须在有效载荷中添加 click_action 并在应用程序中添加一个意图过滤器来处理它。但是,如何通过 Firebase 控制台在 Firebase 通知中添加 click_action?我也愿意接受任何其他解决方法。提前致谢。

更新:

所以只是为了验证一下,目前无法通过 Firebase 控制台设置 click_action 参数。


所以我一直在尝试在 Firebase 通知控制台中执行此操作,但没有成功。由于我似乎无法在控制台中找到任何地方放置 click_action 值,我主要做的测试是在通知中添加一个自定义 key/value 对(高级选项>自定义数据):

Key: click_action
Value: <your_preferred_value>

然后尝试调用 RemoteMessage.getNotification().getClickAction() in onMessageReceived() to see if it was retrieving the correct value, but it always returns null. So next I tried calling RemoteMessage.getData().get(< specified_key >) 并且能够检索我添加的值。

注意:我不完全确定这是否可以用作解决方法,或者是否违反最佳实践。我建议使用您自己的应用服务器,但您的 post 特定于 Firebase 控制台。

客户端应用程序和通知的行为方式仍然取决于您对其进行编程的方式。话虽如此,我认为您可以使用上面的方法作为解决方法,使用从 getData() 检索到的值,然后让 Notification 调用这个或那个。希望这会有所帮助。干杯! :D

据我所知,此时无法在控制台中设置 click_action。

虽然没有关于如何在控制台中设置 click_action 的严格答案,但您可以使用 curl 作为替代方法:

curl --header "Authorization: key=<YOUR_KEY_GOES_HERE>" --header Content-Type:"application/json" https://fcm.googleapis.com/fcm/send  -d "{\"to\":\"/topics/news\",\"notification\": {\"title\": \"Click Action Message\",\"text\": \"Sample message\",\"click_action\":\"OPEN_ACTIVITY_1\"}}"

这是测试 click_action 映射的简单方法。它需要一个类似于 FCM 文档中指定的意图过滤器:

<intent-filter>
  <action android:name="OPEN_ACTIVITY_1" />
  <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

这也是利用话题来设置受众。为了使其正常工作,您需要订阅一个名为 "news".

的主题
FirebaseMessaging.getInstance().subscribeToTopic("news");

即使需要几个小时才能在控制台中看到新创建的主题,您仍然可以通过 FCM api 向它发送消息。

另外,请记住,这只有在应用程序处于后台时才有效。如果它在前台,您将需要实施 FirebaseMessagingService 的扩展。在 onMessageReceived 方法中,您需要手动导航到您的 click_action 目标:

    @Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    //This will give you the topic string from curl request (/topics/news)
    Log.d(TAG, "From: " + remoteMessage.getFrom());
    //This will give you the Text property in the curl request(Sample Message): 
    Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
    //This is where you get your click_action 
    Log.d(TAG, "Notification Click Action: " + remoteMessage.getNotification().getClickAction());
    //put code here to navigate based on click_action
}

正如我所说,目前我找不到通过控制台访问通知有效负载属性的方法,但我认为此解决方法可能会有所帮助。

如果您的应用程序在后台运行,Firebase 将不会触发 onMessageReceived()。为什么.....?我不知道。在这种情况下,我认为实施 FirebaseMessagingService 没有任何意义。

根据文档,如果你想处理后台消息到达,你必须发送 'click_action' 和你的消息。 但是如果你从 Firebase 控制台发送消息,那是不可能的,只能通过 Firebase API。 这意味着您必须构建自己的 "console" 才能让营销人员使用它。所以,这使得 Firebase 控制台也变得毫无用处!

这个新工具背后的想法确实很好,很有前途,但执行得很糟糕。

我想我们将不得不等待新版本 improvements/fixes!

这属于解决方法类别,也包含一些额外信息:

由于根据应用程序的状态(foreground/background/not 已启动)处理通知的方式不同,所以我看到了实现助手 class 的最佳方法,其中选择 activity根据通知消息中发送的自定义数据启动。

  • 当应用程序在前台时,在 onMessageReceived
  • 中使用助手 class
  • 当应用程序在后台运行时,使用助手 class 处理主要 activity 的 onNewIntent 中的意图(检查特定的自定义数据)
  • 当应用程序不是 运行 时,使用助手 class 处理主要 activity 的 onCreate 中的意图(为意图调用 getIntent)。

这样您就不需要 click_action 或特定于它的意图过滤器。此外,您只需编写一次代码,就可以相当轻松地启动任何 activity.

所以最少的自定义数据应该是这样的:

Key: run_activity
Value: com.mypackage.myactivity

以及处理它的代码:

if (intent.hasExtra("run_activity")) {
    handleFirebaseNotificationIntent(intent);
}


private void handleFirebaseNotificationIntent(Intent intent){
    String className = intent.getStringExtra("run_activity");
    startSelectedActivity(className, intent.getExtras());
}

private void startSelectedActivity(String className, Bundle extras){
    Class cls;
    try {
        cls = Class.forName(className);
    }catch(ClassNotFoundException e){
        ...
    }
    Intent i = new Intent(context, cls);

    if (i != null) {
        i.putExtras(extras);
        this.startActivity(i);
    } 
}

这是最后两种情况的代码,startSelectedActivity 也会从 onMessageReceived 调用(第一种情况)。

限制是 intent extras 中的所有数据都是字符串,因此您可能需要在 activity 本身中以某种方式处理它。此外,这是简化的,您可能不会在不警告用户的情况下更改前台应用程序上的 Activity/View。

现在可以在 Firebase 控制台中设置 click_action。您只需转到通知-发送消息-高级选项,在那里您将有两个键和值字段。在第一个字段中输入 click_action,在第二个字段中输入一些代表该操作价值的文本。然后你在你的清单中添加 intent-filter 并给他与你在控制台中写的相同的值。 那就是模拟真实click_action.

您可以在扩展 FirebaseMessagingService 的服务的 onMessageReceived() 中根据您的消息处理所有操作。 为此,您必须发送一条仅包含数据的消息,例如使用 Advanced REST client in Chrome。 然后你发送一个 POST 到 https://fcm.googleapis.com/fcm/send 在 "Raw headers":

中使用

Content-Type: application/json Authorization: key=YOUR_PERSONAL_FIREBASE_WEB_API_KEY

并且 json 字段中的消息 "Raw payload"。

警告,如果您的 json 中有字段 "notification",即使有数据字段,应用在后台 onMessageReceived() 时也永远不会收到您的消息! 例如,如果应用程序在前台:

{
    "condition": " 'Symulti' in topics || 'SymultiLite' in topics",
    "priority" : "normal",
    "time_to_live" : 0,
    "notification" : {
        "body" : "new Symulti update !",
        "title" : "new Symulti update !",
        "icon" : "ic_notif_symulti"
    },
    "data" : {
        "id" : 1,
        "text" : "new Symulti update !"
    }
}

为了在所有情况下都能在 onMessageReceived() 中收到您的消息,只需从您的 json !

中删除 "notification" 字段

示例:

{
    "condition": " 'Symulti' in topics || 'SymultiLite' in topics",
    "priority" : "normal",
    "time_to_live" : 0,,
    "data" : {
        "id" : 1,
        "text" : "new Symulti update !",
        "link" : "href://www.symulti.com"
    }
}

并在您的 FirebaseMessagingService 中:

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMsgService";

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
      String message = "";
      obj = remoteMessage.getData().get("text");
      if (obj != null) {
        try {
          message = obj.toString();
        } catch (Exception e) {
          message = "";
          e.printStackTrace();
        }
      }

      String link = "";
      obj = remoteMessage.getData().get("link");
      if (obj != null) {
        try {
          link = (String) obj;
        } catch (Exception e) {
          link = "";
          e.printStackTrace();
        }
      }

      Intent intent;
      PendingIntent pendingIntent;
      if (link.equals("")) { // Simply run your activity
        intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
      } else { // open a link
        String url = "";
        if (!link.equals("")) {
          intent = new Intent(Intent.ACTION_VIEW);
          intent.setData(Uri.parse(link));
          intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        }
      }
      pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
          PendingIntent.FLAG_ONE_SHOT);


      NotificationCompat.Builder notificationBuilder = null;

      try {
        notificationBuilder = new NotificationCompat.Builder(this)
            .setSmallIcon(R.drawable.ic_notif_symulti)          // don't need to pass icon with your message if it's already in your app !
            .setContentTitle(URLDecoder.decode(getString(R.string.app_name), "UTF-8"))
            .setContentText(URLDecoder.decode(message, "UTF-8"))
            .setAutoCancel(true)
            .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
            .setContentIntent(pendingIntent);
        } catch (UnsupportedEncodingException e) {
          e.printStackTrace();
        }

        if (notificationBuilder != null) {
          NotificationManager notificationManager =
              (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
          notificationManager.notify(id, notificationBuilder.build());
        } else {
          Log.d(TAG, "error NotificationManager");
        }
      }
    }
}

尽情享受吧!

我在看这个 Firebase 是从 google 云消息推送通知基础 开发的,所以我们可以使用gcm tutorial, function and implementation in firebase , 我使用 gcm 推送通知功能来解决这个 click_action 问题 我使用 gcm 函数 **

'notificationclick'

** 尝试将 url click_action 保存在变量 url 中 这是在 server-worker.js

var url =  "";

messaging.setBackgroundMessageHandler(function(payload) {

  console.log('[firebase-messaging-sw.js] Received background message ', payload);
  // Customize notification here
  url = payload.data.click_action;

  const notificationTitle = payload.data.title;
  const notificationOptions = {
    body: payload.data.body , 
    icon: 'firebase-logo.png'
  };

  return self.registration.showNotification(notificationTitle,
      notificationOptions);

});


   //i got this in google cloud messaging push notification


self.addEventListener('notificationclick', function (event) {
  event.notification.close();

  var clickResponsePromise = Promise.resolve();
    clickResponsePromise = clients.openWindow(url);

  event.waitUntil(Promise.all([clickResponsePromise, self.analytics.trackEvent('notification-click')]));
});

如果您的应用程序在后台运行,Firebase 将不会触发 onMessageReceived()。 onMessageReceived() 在应用程序处于前台时被调用。 当应用程序在后台时,仅当 https://fcm.googleapis.com/fcm/send 的主体仅包含数据 payload.Here 时才会调用 onMessageReceived() 方法,我刚刚创建了一个方法来构建自定义通知,其意图是您需要 activity。并在 onMessageRecevied() 中调用此方法。

在 PostMan 中:

uri: https://fcm.googleapis.com/fcm/send

header:Authorization:key=你的密钥

正文--->>

{  "data" : {
      "Nick" : "Mario",
      "Room" : "PoSDenmark",

    },

  "to" : "xxxxxxxxx"

}

在您的申请中。

class MyFirebaseMessagingService  extends FirebaseMessagingService {

 public void onMessageReceived(RemoteMessage remoteMessage) {
       if (remoteMessage.getData().size() > 0) {
           sendNotification("ur message body") ;
        }
    }
private void sendNotification(String messageBody) {
        Intent intent = new Intent(this, Main2Activity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        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(R.drawable.ic_stat_ic_notification)
                .setContentTitle("FCM Message")
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

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

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

 }

当数据有效载荷到达移动设备时,将调用 onMessageReceived() 方法。在该方法中,我刚刚制作了一个自定义通知。即使您的应用程序是后台或前台,这也能正常工作。

从 firebase 文档可以清楚地看出,当应用程序处于后台时,您的 onMessageReceived 将无法运行。

当您的应用程序在后台并单击您的通知时,您的默认启动器将启动。 要启动所需的 activity,您需要在通知负载中指定 click_action

$noti = array
    (
    'icon' => 'new',
    'title' => 'title',
    'body' => 'new msg',
    'click_action' => 'your activity name comes here'
); 

并且在您的 android.manifest 文件中

在您注册 activity

的地方添加以下代码
     <activity
                android:name="your activity name">
                <intent-filter>
                    <action android:name="your activity name" />
                   <category android:name="android.intent.category.DEFAULT"/>
               </intent-filter>
   </activity>

fcm有对偶方法 fcm消息通知和应用程序通知 首先,您的应用仅接收带有 body 的消息通知,标题,您可以添加颜色,振动不起作用,声音默认。 在第二个中,您可以完全控制收到消息示例时发生的情况 onMessageReciever(RemoteMessage rMessage){ notification.setContentTitle(rMessage.getData().get("yourKey")); } 您将收到数据(您的密钥) 但那不是来自 fcm 消息 来自 fcm 云函数 守卫

在 Web 中,只需添加您要打开的 url:

{  
  "condition": "'test-topic' in topics || 'test-topic-2' in topics",  
  "notification": {
            "title": "FCM Message with condition and link",
            "body": "This is a Firebase Cloud Messaging Topic Message!",            
            "click_action": "https://yoururl.here"
        }
}

一个简单的解决方法是,在 fcm 选项中 - 添加 / 作为 link 值,后台通知点击将被重定向到应用程序。