这是我的舱单:
<service android:name=".fcm.PshycoFirebaseMessagingServices">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name=".fcm.PshycoFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
当应用程序在后台和通知到达,然后默认通知来,不运行我的onmessagerreceived代码。
这是我的onMessageReceived代码。如果我的应用程序在前台运行,而不是在后台运行,就会调用这个函数。我怎么能运行这段代码时,应用程序是在后台太?
// [START receive_message]
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// TODO(developer): Handle FCM messages here.
// 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.
data = remoteMessage.getData();
String title = remoteMessage.getNotification().getTitle();
String message = remoteMessage.getNotification().getBody();
String imageUrl = (String) data.get("image");
String action = (String) data.get("action");
Log.i(TAG, "onMessageReceived: title : "+title);
Log.i(TAG, "onMessageReceived: message : "+message);
Log.i(TAG, "onMessageReceived: imageUrl : "+imageUrl);
Log.i(TAG, "onMessageReceived: action : "+action);
if (imageUrl == null) {
sendNotification(title,message,action);
} else {
new BigPictureNotification(this,title,message,imageUrl,action);
}
}
// [END receive_message]
我想出了各种方案
当app在前台时,
onMessageReceived()方法从FirebaseService调用。因此,服务类中定义的pendingIntent将被调用。
当app在后台时,第一个activity被调用。
现在,如果你使用了一个splashactivity,那么必须记住splashactivity会被调用,否则如果没有splashactivity,那么无论第一个activity是什么,都会被调用。
然后你需要检查firstActivity的getIntent(),看看它是否有任何bundle。如果一切正常,你会看到bundle在那里,值被填充。如果从服务器发送的数据标签中的值是这样的,
"data": {
"user_name": "arefin sajib",
"value": "user name notification"
}
然后在第一个活动中,你会看到,
有一个有效的意图(getIntent()不是null),有效的捆绑包和在捆绑包内,会有上面提到的以数据为键的整个JSON。
在这种情况下,提取值的代码是这样的,
if(getIntent()!=null){
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
try {
JSONObject object = new JSONObject(bundle.getStringExtra("data"));
String user_name = object.optString("user_name");
} catch (JSONException e) {
e.printStackTrace();
}
}
}
根据firebase文档在发送下游使用firebase,有两种类型的有效载荷:
数据
此参数指定消息有效负载的自定义键-值对。
客户端应用程序负责处理数据消息。数据消息只有自定义键值对。
通知
此参数指定通知有效负载的预定义的、用户可见的键-值对。FCM自动代表客户端应用程序将消息显示给最终用户设备。通知消息具有一组预定义的用户可见键。
当你在前台时,你可以使用onmessagerecreceived()在FCM内部获取数据,你可以从数据有效载荷中获取数据。
data = remoteMessage.getData();
String customData = (String) data.get("customData");
当您在后台时,FCM将根据通知有效载荷的信息在系统托盘中显示通知。系统托盘上用于通知的标题、消息和图标都来自通知有效负载。
{
"notification": {
"title" : "title",
"body" : "body text",
"icon" : "ic_notification",
"click_action" : "OPEN_ACTIVITY_1"
}
}
当你想在应用程序处于后台时自动在系统托盘上显示通知时,使用这个通知有效载荷。
当你的应用程序在后台运行时,为了获得通知数据,你应该在通知有效载荷中添加click_action。
如果你想打开你的应用并执行一个特定的动作(在后台),在通知有效载荷中设置click_action,并将其映射到你想要启动的Activity中的意图过滤器。例如,将click_action设置为OPEN_ACTIVITY_1来触发一个意图过滤器,如下所示:
<intent-filter>
<action android:name="OPEN_ACTIVITY_1" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
把intent-filter放在你的清单上,在你的一个activity标签里面。当你点击通知时,它将打开应用程序并直接进入你在click_action中定义的活动,在本例中为“OPEN_ACTIVTY_1”。
在这个活动中,你可以通过以下方式获取数据:
Bundle b = getIntent().getExtras();
String someData = b.getString("someData");
我使用FCM为我的android应用程序和使用两个有效载荷。
下面是我使用的JSON示例:
{
"to": "FCM registration ID",
"notification": {
"title" : "title",
"body" : "body text",
"icon" : "ic_notification",
"click_action" : "OPEN_ACTIVITY_1"
},
"data": {
"someData" : "This is some data",
"someData2" : "etc"
}
}
感谢你们所有人的回答。但是我通过发送数据消息而不是发送通知来解决这个问题。
服务器代码
<?php
$url = "https://fcm.googleapis.com/fcm/send";
$token = "C-l6T_a7HouUK****";
$serverKey = "AAAAaOcKS00:********";
define( 'API_ACCESS_KEY', $serverKey );
$registrationIds = array($token);
// prep the bundle
$msg = array
(
'message' => 'here is a message. message',
'title' => 'This is a title. title',
'subtitle' => 'This is a subtitle. subtitle',
'tickerText' => 'Ticker text here...Ticker text here...Ticker text
here',
'vibrate' => 1,
'sound' => 1,
'largeIcon' => 'large_icon',
'smallIcon' => 'small_icon'
);
$fields = array
(
'registration_ids' => $registrationIds,
'data' => $msg
);
$headers = array
(
'Authorization: key=' . API_ACCESS_KEY,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt( $ch,CURLOPT_URL, 'https://android.googleapis.com/gcm/send'
);
curl_setopt( $ch,CURLOPT_POST, true );
curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );
curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, false );
curl_setopt( $ch,CURLOPT_POSTFIELDS, json_encode( $fields ) );
$result = curl_exec($ch );
curl_close( $ch );
echo $result;
?>
并在onmessagerreceived中捕获数据
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
sendNotification(remoteMessage.getData().get("message"));
}
// Check if message contains a notification payload.
else if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
sendNotification(remoteMessage.getNotification().getBody());
}
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, Notify.class).putExtra("msg",messageBody);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
String channelId = "idddd";
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(MyFirebaseMessagingService.this)
.setSmallIcon(R.mipmap.ic_launcher)
.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());
}
}
自2019年以来,谷歌Firebase的api有了很大的变化
我的意思是:
“com.google.firebase: firebase-messaging: 18.0.0”
在18.0.0中,他们删除了MyFirebaseInstanceIDService,你需要在MyFirebaseMessagingService中获取令牌,所以你只需要写:
@Override
public void onNewToken(String token) {
Log.d(TAG, "Refreshed token: " + token);
}
在你的AndroidManifest.xml中,你必须删除:
<service android:name=".service.MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
此外,建议您设置默认值以自定义通知的外观。您可以指定自定义默认图标和自定义默认颜色,在通知有效负载中没有设置等效值时应用它们。
在应用程序标记中添加这些行来设置自定义默认图标和自定义颜色:
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_notification" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorAccent" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/push_channel" />
现在要在后台应用程序中处理通知消息,你应该在你的第一个Activity中定义一个Intent,即使它是SplashScreen。当你的应用程序在后台时,Android将通知消息定向到系统托盘。用户点击通知会默认打开应用启动器。
例如,如果你的Json是这样的:
"data": {
"message": "2",
"title": "1",
"pushType" : "banner",
"bannerLink": "http://www.google.com",
"image" : "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"}
你只需要写一个简单的意图来获取这些值:
Bundle extras = intent.getExtras();
String bannerLink = extras.getString("bannerLink");
...
String channelId = extras.getString("channelId");