как открыть конкретный экран при нажатии на push-уведомление для флаттера
Я пытаюсь открыть открытое окно при нажатии push-уведомления, и моя полезная нагрузка выглядит следующим образом:
var payload = {
notification: {
title: notificationTitle,
body: notificationMessage,
click_action:"/screena",sound:"default",
}
};
Я получаю уведомление, но я не могу отловить событие щелчка уведомления во флаттере, как его поймать. Я использую флаттер
https://github.com/flutter/plugins/tree/master/packages/firebase_messaging
и мой код службы push-сообщений 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 сказал в сообщении, когда мое приложение находится на переднем плане, но мой вопрос заключается в том, как отловить событие клика из push-уведомления, отображаемого в системном трее, и перейти на нужный экран.
Ответы
Ответ 1
Несколько вещей здесь:
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>"
}'
Это должно позволить вам получать сообщение в обработчике onMessage
в вашем onMessage
приложении.
Оттуда вы можете вызвать Navigator.of(context).pushNamed(message['screen'])
.
Если в этот момент у вас нет BuildContext
, вы можете зарегистрировать GlobalKey
как свойство navigatorKey
вашего MaterialApp
и использовать его для доступа к вашему Navigator
глобально через GlobalKey.currentState
Ответ 2
Поскольку метод @xqwzts хорошо работает для получения сообщений в открытом состоянии приложения,
следующий пример переместится на определенную страницу,
[Код взят из примера с пламенным сообщением ТОЛЬКО И НАВИГАЦИЯ НА ИМЯ СТРАНИЦУ, НА КОТОРОЙ ДАННЫЕ, КОТОРЫЕ МЫ ОТПРАВЛИ ПОЖАРНАЯ КОНСОЛЬ]
//eg:if you give /Nexpage3 in status field then it will navigate to Nextpage3 of your App
ПОНИМАНИЕ 2 ВЕЩЕЙ, УВЕДОМЛЕНИЯ FCM ИМЕЕТ 2 РАЗДЕЛА
1-й заголовок сообщения Раздел на странице облачных сообщений Firebase называется Данные уведомления[когда приложение свернуто или закрыто, оно будет отображаться в виде уведомления]
Второй заголовок сообщения, находящийся в нижней части веб-страницы, называется "Данные сообщения", [он будет отображаться внутри приложения в виде уведомления или диалогового окна с предупреждением по вашему желанию]
ЭТАПЫ
Создайте фиктивный проект, затем используйте плагин Firebase Message, и в этом поле укажите BMW Cars как
тему и нажмите подписаться
Теперь перейдите на консоль, затем отправьте сообщение с СЛЕДУЮЩИМ ФОРМАТОМ, он должен содержать ключи Id
и Status
, потому что мы разбираем порядок Id и Status Keys, чтобы показать NextPage с Vlaue ключа состояния, но если вы предпочитаете поле, такое как title или body, то вы тоже можете это сделать, но обязательно проанализируйте значение карты в коде вашего флаттера.
//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(),
),
);
}
}
Ответ 3
Я перехожу к определенному экрану onResume и onLaunch при нажатии на уведомление. Но у меня все еще есть проблема, когда мое приложение закрывается, и я нажимаю на уведомление, мой экран открыт и через несколько секунд Мой экран приложения по умолчанию - open.pleasue guid.
Ответ 4
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()
)
);
},
попробуй это