我试图在点击推送通知时实现打开特定屏幕,我的有效负载如下所示:
var payload = {
notification: {
title: notificationTitle,
body: notificationMessage,
click_action:"/screena",sound:"default",
}
};
我收到通知但我无法捕捉到flutter中的通知点击事件如何捕获它。我正在使用扑动消息
https://github.com/flutter/plugins/tree/master/packages/firebase_messaging
和我的firebase推送消息服务代码看起来像这样
pushMessagingService() async{
messagingreference.configure(
onMessage: (Map<String, dynamic> message) {
print("I am here in on message");
print(message);
},
onLaunch: (Map<String, dynamic> message) {
print("I am here onLaunch");
print(message);
},
onResume: (Map<String, dynamic> message) {
print("I am hereonResume");
print(message);
},
);
messagingreference.requestNotificationPermissions(
const IosNotificationSettings(sound: true, badge: true, alert: true));
messagingreference.onIosSettingsRegistered
.listen((IosNotificationSettings settings) {
print("Settings registered: $settings");
});
messagingreference.getToken().then((String token) async {
print(token);
});
}
这里我可以得到消息,因为@xqwzts在我的应用程序处于前台时在消息中说,但我的问题是如何从系统托盘中引发的推送通知中捕获点击事件并导航到所需的屏幕。
这里有几件事:
1- click_action
必须设置为"FLUTTER_NOTIFICATION_CLICK"
2- click_action
必须设置在有效载荷的data
部分
DATA='{
"notification": {
"body": "this is a body",
"title": "this is a title"
},
"data": {
"click_action": "FLUTTER_NOTIFICATION_CLICK",
"sound": "default",
"status": "done",
"screen": "screenA",
},
"to": "<FCM TOKEN>"
}'
这应该允许您在flutter应用程序中的onMessage
处理程序中接收消息。
从那里你可以打电话给Navigator.of(context).pushNamed(message['screen'])
。
如果你当时没有BuildContext
,你可以注册一个GlobalKey
作为navigatorKey
的MaterialApp
属性,并通过Navigator
用它来访问你的GlobalKey.currentState
全球
由于@xqwzts方法适用于在App上接收消息处于打开状态,
以下示例将导航到特定页面,
[该守则仅来自消防局信息插件示例代码,并导航到一个名为页面,我们通过火灾控制台发送的数据]
//eg:if you give /Nexpage3 in status field then it will navigate to Nextpage3 of your App
了解2件事,FCM通知有2个部分
firebase云消息传递页面中的第一个消息标题部分称为通知数据[当应用程序被缩小或关闭时,它将显示为通知]
位于网页底部的第二个消息标题部分称为消息数据,[它将在内部应用程序中显示为通知或警报对话,符合您的愿望]
步骤创建一个虚拟项目然后使用firebase消息插件,并在该框中将BMW Cars作为主题并单击订阅
现在转到你的控制台,然后发送一条消息,其中包含以下格式,它必须包含Id
和Status
键,因为我们正在解析Id和Status键以便显示带有状态键的Vlaue的NextPage但是如果你更喜欢像标题或正文这样的字段那么你可以这样做但确保在你的flutter代码中解析地图值。
//THIS IS A LITTLE BIT MODIFIED VERSION OF Example Code given in Firebase
//Messagaing Plugin
//WHEN U PASTE THE CODE IN UR VSCODE OR ANDROID STUDIO PLEASE Format the
//Document because it is aligned in single lines
import 'dart:async';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
void main() {
runApp(
new MaterialApp(
home: new PushMessagingExample(),
routes: <String,WidgetBuilder>{
"/Nexpage1":(BuildContext context)=> new Nexpage1(),
"/Nexpage2":(BuildContext context)=> new Nexpage2(),
"/Nexpage3":(BuildContext context)=> new Nexpage3(),
} ),);}
//INITIAL PARAMETERS
String _homeScreenText = "Waiting for token...";
bool _topicButtonsDisabled = false;
final FirebaseMessaging _firebaseMessaging = new FirebaseMessaging();
final TextEditingController _topicController = new TextEditingController(text: 'topic');
final Map<String, Item> _items = <String, Item>{};
Item _itemForMessage(Map<String, dynamic> message) {
final String itemId = message['id'];
final Item item = _items.putIfAbsent(itemId, () => new Item(itemId: itemId))..status = message['status'];
return item;
}
//MAIN CLASS WHICH IS THE HOMEPAGE
class PushMessagingExample extends StatefulWidget {
@override
_PushMessagingExampleState createState() => new _PushMessagingExampleState();
}
class _PushMessagingExampleState extends State<PushMessagingExample> {
void _navigateToItemDetail(Map<String, dynamic> message) {
final String pagechooser= message['status'];
Navigator.pushNamed(context, pagechooser);
}
//CLEAR TOPIC
void _clearTopicText() {setState(() {_topicController.text = "";_topicButtonsDisabled = true;});}
//DIALOGUE
void _showItemDialog(Map<String, dynamic> message) {showDialog<bool>(context: context,builder: (_) => _buildDialog(context, _itemForMessage(message)),).then((bool shouldNavigate) {if (shouldNavigate == true) {_navigateToItemDetail(message);}});}
//WIDGET WHICH IS GOING TO BE CALLED IN THE ABOVE DIALOGUE
Widget _buildDialog(BuildContext context, Item item) {return new AlertDialog(content: new Text("Item ${item.itemId} has been updated"),actions: <Widget>[new FlatButton(child: const Text('CLOSE'),onPressed: () {Navigator.pop(context, false);},),new FlatButton(child: const Text('SHOW'),onPressed: () {Navigator.pop(context, true);},),]);}
@override
void initState() {
super.initState();
_firebaseMessaging.configure(
onLaunch: (Map<String, dynamic> message) async { _navigateToItemDetail(message);},
onResume: (Map<String, dynamic> message) async { _navigateToItemDetail(message);},
onMessage: (Map<String, dynamic> message) async {_showItemDialog(message);},);
//GETTING TOKEN FOR TESTING MANUALY
_firebaseMessaging.getToken().then((String token) {assert(token != null);setState(() {_homeScreenText = "Push Messaging token: $token";});print(_homeScreenText);});}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar( title: const Text('Push Messaging Demo'),),
body: new Material(
child: new Column(
children: <Widget>[
new Center(
child: new Text(_homeScreenText),
),
new Row(children: <Widget>[
new Expanded(
child: new TextField(
controller: _topicController,
onChanged: (String v) {
setState(() {
_topicButtonsDisabled = v.isEmpty;
});
}),
),
new FlatButton(
child: const Text("subscribe"),
onPressed: _topicButtonsDisabled
? null
: () {
_firebaseMessaging
.subscribeToTopic(_topicController.text);
_clearTopicText();
},
),
new FlatButton(child: const Text("unsubscribe"),
onPressed: _topicButtonsDisabled? null: () { _firebaseMessaging.unsubscribeFromTopic(_topicController.text);
_clearTopicText();},),
])],),));}}
//THREE DUMMY CLASSES FOR TESTING PURPOSE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//PAGE1
class Nexpage1 extends StatefulWidget { @override _Nexpage1State createState() => _Nexpage1State();}
class _Nexpage1State extends State<Nexpage1> { @override Widget build(BuildContext context) { return Scaffold(body: new Center(child: new Text(" Page1"),));}}
//PAGE2
class Nexpage2 extends StatefulWidget { @override _Nexpage2State createState() => _Nexpage2State();}
class _Nexpage2State extends State<Nexpage2> { @override Widget build(BuildContext context) { return Scaffold( body: Center(child: new Text("2pending"),) ); }}
//PAGE3
class Nexpage3 extends StatefulWidget { @override _Nexpage3State createState() => _Nexpage3State();}
class _Nexpage3State extends State<Nexpage3> { @override Widget build(BuildContext context) { return Scaffold( body: Center(child: new Text("3connected"),) ); }}
//THIS IS THE CLASS WHICH IS USED TO PARSE THE INFORMATION
class Item {
Item({this.itemId});
final String itemId;
StreamController<Item> _controller = new StreamController<Item>.broadcast();
Stream<Item> get onChanged => _controller.stream;
String _status;
String get status => _status;
set status(String value) {
_status = value;
_controller.add(this);
}
static final Map<String, Route<Null>> routes = <String, Route<Null>>{};
Route<Null> get route {
final String routeName = '/detail/$itemId';
return routes.putIfAbsent(
routeName,
() => new MaterialPageRoute<Null>(
settings: new RouteSettings(name: routeName),
builder: (BuildContext context) => new Nexpage3(),
),
);
}
}
onLaunch: (Map<String, dynamic> message) {
print("I am here onLaunch");
print(message);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ScreenA()
)
);
},
onResume: (Map<String, dynamic> message) {
print("I am here onResume");
print(message);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ScreenA()
)
);
},
试试这个