i am trying to make an app that reads notifications from firebase cloud messaging
i am sending notifications with a node program and reading it in flutter
import 'package:flutter/material.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_tts/flutter_tts.dart';
void main(){runApp(MyApp());}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: ' Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
FirebaseMessaging _firebaseMessaging = new FirebaseMessaging();
FlutterTts flutterTts = new FlutterTts();
int _counter = 0;
String notificationtext;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
void initState() {
super.initState();
_firebaseMessaging.subscribeToTopic("bavo");
_firebaseMessaging.configure(
onMessage : (Map<String,dynamic> message) {
print('on message $message');
setState((){
_counter = _counter + 100;
notificationtext = message.toString();
});
},
onResume : (Map<String, dynamic> message) {
print('on resume $message');
setState((){
_counter = _counter + 100;
notificationtext = message.toString();
});
},
onLaunch : (Map<String, dynamic> message) {
print('on launch $message');
setState((){
_counter = _counter + 100;
notificationtext = message.toString();
});
},
);
_firebaseMessaging.getToken().then((token){
print(token);
});
}
speak() async {
flutterTts.speak(notificationtext);
}
#override
Widget build(BuildContext context) {
flutterTts.speak(notificationtext);
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'You have pushed the button this many times:',
),
new RaisedButton(
onPressed: speak,
child: new Text('Say Hello'),
),
new Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: new Icon(Icons.add),
),
);
}
}
as you can see in onmessage i set a variable equal to the datapayload of the message and the i let it play with the initstate ( this reloads the widget so it runs the text to speech code, this was to only working way i found)
my problem is how can i make it so if the variable changes it plays it with the text to speech even if the phone is off ,
now it tells it when the app is open and only then
hope you guyss can help me
I'm not sure how firebase messaging works, but why not just run the flutterTts.speak() method inside your listener.
Or you can call the speak method within the listener.
I haven't tested this, but might be worth a shot.
example:
onMessage : (Map<String,dynamic> message) {
print('on message $message');
setState((){
_counter = _counter + 100;
notificationtext = message.toString();
});
flutterTts.speak(message.toString());
},
Related
I just try using firebase push notification and messaging. I got an issue which is when I tried send message via console it showed completed but I do not get the notification. So can you guys explain my coding mistake. What must I do?
Local notification was fine.
local notification
Here the message that I tried send on console but i dont get any notification on the phone.
firebase console
this is my code
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
description: 'This channel is used for important notifications.', // description
importance: Importance.high,
playSound: true);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
print('A bg message just showed up : ${message.messageId}');
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
#override
void initState() {
super.initState();
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification notification = message.notification;
AndroidNotification android = message.notification?.android;
if (notification != null && android != null) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription : channel.description,
color: Colors.blue,
playSound: true,
icon: '#mipmap/ic_launcher',
),
));
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('A new onMessageOpenedApp event was published!');
RemoteNotification notification = message.notification;
AndroidNotification android = message.notification?.android;
if (notification != null && android != null) {
showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: Text(notification.title),
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [Text(notification.body)],
),
),
);
});
}
});
}
void showNotification() {
setState(() {
_counter++;
});
flutterLocalNotificationsPlugin.show(
0,
"Testing $_counter",
"How you doin ?",
NotificationDetails(
android: AndroidNotificationDetails(channel.id, channel.name, channelDescription: channel.description,
importance: Importance.high,
color: Colors.blue,
playSound: true,
icon: '#mipmap/ic_launcher')));
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: showNotification,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Is there any error on firebase connection to device?
SOLVED
Coding work fined.This occur because of I am using emulator instead of real device to tested.Thanks to u guys who answered my question.Those also help me a lot to understand.
Please refer the below code
class name FCM
import 'dart:async';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
Future<void> onBackgroundMessage(RemoteMessage message) async {
await Firebase.initializeApp();
if (message.data.containsKey('data')) {
// Handle data message
final data = message.data['data'];
}
if (message.data.containsKey('notification')) {
// Handle notification message
final notification = message.data['notification'];
}
// Or do other work.
}
class FCM {
final _firebaseMessaging = FirebaseMessaging.instance;
final streamCtlr = StreamController<String>.broadcast();
final titleCtlr = StreamController<String>.broadcast();
final bodyCtlr = StreamController<String>.broadcast();
setNotifications() {
FirebaseMessaging.onBackgroundMessage(onBackgroundMessage);
FirebaseMessaging.onMessage.listen(
(message) async {
if (message.data.containsKey('data')) {
// Handle data message
streamCtlr.sink.add(message.data['data']);
}
if (message.data.containsKey('notification')) {
// Handle notification message
streamCtlr.sink.add(message.data['notification']);
}
// Or do other work.
titleCtlr.sink.add(message.notification!.title!);
bodyCtlr.sink.add(message.notification!.body!);
},
);
// With this token you can test it easily on your phone
final token =
_firebaseMessaging.getToken().then((value) => print('Token: $value'));
}
dispose() {
streamCtlr.close();
bodyCtlr.close();
titleCtlr.close();
}
}
And Main Class
void main() async {
await init();
runApp(const MyApp());
}
Future init() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String notificationTitle = 'No Title';
String notificationBody = 'No Body';
String notificationData = 'No Data';
#override
void initState() {
final firebaseMessaging = FCM();
firebaseMessaging.setNotifications();
firebaseMessaging.streamCtlr.stream.listen(_changeData);
firebaseMessaging.bodyCtlr.stream.listen(_changeBody);
firebaseMessaging.titleCtlr.stream.listen(_changeTitle);
super.initState();
}
_changeData(String msg) => setState(() => notificationData = msg);
_changeBody(String msg) => setState(() => notificationBody = msg);
_changeTitle(String msg) => setState(() => notificationTitle = msg);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
notificationTitle,
style: Theme.of(context).textTheme.headline4,
),
Text(
notificationBody,
style: Theme.of(context).textTheme.headline6,
),
Text(
notificationData,
style: Theme.of(context).textTheme.headline6,
),
],
),
),
);
}
}
Try by calling _firebasebackgroundhanler function as below in code
void main() async {
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
Firebasebackground handler function :
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
print("Handling a background message: ${message.messageId}");
}
i try do example flutter app get notification from firebase. I have done everything suggested in the various guides. but I'm in trouble, in ios the code works perfectly, while on android it doesn't and I can't explain why. It seems that when _firebaseMessaging.getToken () is executed it leads nowhere and waits for a response that never comes. some of you have some tips? I tried all the functions made available by _firebaseMessaging but without success.
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'dart:io' show Platform;
import 'package:flutter/foundation.dart';
class PushMessagingExample extends StatefulWidget {
#override
_PushMessagingExampleState createState() => _PushMessagingExampleState();
}
class _PushMessagingExampleState extends State<PushMessagingExample> {
String _homeScreenText = "Waiting for token...";
String _messageText = "Waiting for message...";
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
#override
void initState() {
debugPrint('test firebase');
super.initState();
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
setState(() {
_messageText = "Push Messaging message: $message";
});
print("onMessage: $message");
},
onLaunch: (Map<String, dynamic> message) async {
setState(() {
_messageText = "Push Messaging message: $message";
});
print("onLaunch: $message");
},
onResume: (Map<String, dynamic> message) async {
setState(() {
_messageText = "Push Messaging message: $message";
});
print("onResume: $message");
},
);
_firebaseMessaging.requestNotificationPermissions(
const IosNotificationSettings(sound: true, badge: true, alert: true));
_firebaseMessaging.onIosSettingsRegistered
.listen((IosNotificationSettings settings) {
print("Settings registered: $settings");
});
_firebaseMessaging.subscribeToTopic('all');
debugPrint('token call');
_firebaseMessaging.getToken().then((String token) {
debugPrint('test firebase token: $token');
print(token);
assert(token != null);
setState(() {
_homeScreenText = "Push Messaging token: $token";
});
print(_homeScreenText);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Push Messaging Demo'),
),
body: Material(
child: Column(
children: <Widget>[
Center(
child: Text(_homeScreenText),
),
Row(children: <Widget>[
Expanded(
child: Text(_messageText),
),
])
],
),
));
}
}
void main() {
runApp(
MaterialApp(
home: PushMessagingExample(),
),
);
}
I think your problem is an asynchronous method, first, divide them into Future methods and into methods to create different FirebaseMessaging instances.
Im trying to create a flutter app with a simple raised button that does the following:
sends an sms in the background using the sms package opens a webpage
2. in the app(only for 5 seconds) using url_launcher opens the phones
3. native app for making a voice call with the onPressed property.
And I wanted it to be in this order so that I can make the phone call at the end. However, the inside the onPressed opens the native phone call app first, which doesnt let my web page open unless I exit out of the phone call app.
Im having a hard time understanding why the phone call native app is opened first, even though I make the call the _makePhoneCall() method only after I make the _launchInApp(toLaunch) call. sendSMS() is being called correctly
How can I set this in a way that the phone call native app is called only after the webpage is opened in the app and follows the order? Any help would be great
Below is the piece of code:
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:sms/sms.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Packages testing',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Packages testing'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _phone = '';
_launchInApp(String url) async {
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: true,
forceWebView: true,
headers: <String, String>{'my_header_key': 'my_header_value'},
);
} else {
throw 'Could not launch $url';
}
}
_makePhoneCall(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
void sendSMS() {
SmsSender sender = new SmsSender();
sender.sendSms(new SmsMessage(_phone, 'Testing Handset'));
}
#override
Widget build(BuildContext context) {
const String toLaunch = 'https://flutter.dev/';
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
onChanged: (String text) => _phone = text,
decoration:
const InputDecoration(hintText: 'Phone Number')),
),
FlatButton(
onPressed: () => setState(() {
sendSMS();
_launchInApp(toLaunch);
_makePhoneCall('tel:$_phone');
}),
child: const Text('Run All'),
),
const Padding(padding: EdgeInsets.all(16.0)),
],
),
],
),
);
}
}
You will have to use the await keyword before the _launchInApp function to make it work properly. Try the following code.
FlatButton(
onPressed: () aync {
sendSMS();
await _launchInApp(toLaunch);
_makePhoneCall('tel:$_phone');
}),
child: const Text('Run All'),
),
You created async functions but when you called them you did not specify that you want to wait for them to complete. Add the await keyword in OnPressed
I'm using FCM to send push notifications to my device right now and it's working perfectly. However when the app is open, I only get the onResume to be executed when I'm in that particular page. I want to display the notification on the top regardless of which page(or class) the user is on. Basically I want the notifications to be displayed globally (Show popup). Any help would be appreciated. Here is the code from the page that displays the notifications.
if (Platform.isIOS) {
iosSubscription = _fcm.onIosSettingsRegistered.listen((data) {
_saveDeviceToken();
});
_fcm.requestNotificationPermissions(IosNotificationSettings());
} else {
_saveDeviceToken();
}
_fcm.configure(
onMessage: (Map<String, dynamic> message) async {
print("onMessage: $message");
var temp = message['notification'];
setState(() {
title.add(temp['title']);
body.add(temp['body']);
});
showDialog(
context: context,
builder: (context) => AlertDialog(
content: ListTile(
title: Text(message['notification']['title']),
subtitle: Text(message['notification']['body']),
),
actions: <Widget>[
FlatButton(
color: const Color(0xFF650572),
child: Text('Ok'),
onPressed: () => Navigator.of(context).pop(),
),
],
),
);
},
onLaunch: (Map<String, dynamic> message) async {
print("onLaunch: $message");
Navigator.push(
context, MaterialPageRoute(builder: (context) => MessageHandler()));
// TODO optional
},
onResume: (Map<String, dynamic> message) async {
print("onResume: $message");
Navigator.push(context,
MaterialPageRoute(builder: (context) => MessageHandler()));
// TODO optional
},
);
}
Wrap your MaterialApp in a wrapper class ... lets call that FCMWrapper.
class FCMWrapper extends StatefulWidget {
final Widget child;
const FCMWrapper({Key key, this.child}) : super(key: key);
#override
_FCMWrapperState createState() => _FCMWrapperState();
}
class _FCMWrapperState extends State<FCMWrapper> {
#override
Widget build(BuildContext context) {
return Consumer<YourObservable>(
builder: (context, yourObservable, _) {
if (yourObservable != null && yourObservable.isNotEmpty) {
Future(
() => navigatorKey.currentState.push(
PushNotificationRoute(
child: YourViewOnNotification(),
)),
),
);
}
return widget.child;
},
);
}
}
I have stored my data in an observable from a separate class. So when I receive a notification I update my observable. Since we are consuming on that observable the PushNotificationRoute would be called.
PushNotificationRoute is simply a class which extends ModalRoute.
class PushNotificationRoute extends ModalRoute {
final Widget child;
PushNotificationRoute({this.child});
... //Override other methods to your requirement
//This is important
#override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return SafeArea(
child: Builder(builder: (BuildContext context) {
return child;
}),
);
}
...
#override
Duration get transitionDuration => Duration(milliseconds: 200);
}
Now in main.dart declare a global key like
var navigatorKey = GlobalKey<NavigatorState>();
and wrap your MaterialApp like
...
FCMWrapper(
child: MaterialApp(
navigatorKey: navigatorKey,
title: 'Your App',
...
So now every time a notification comes in your observable should update and push a modal route which would be shown over anywhere in the app.
I receive this error while running test of my flutter MQTT code on the android emulator
═════ Exception caught by gesture ═════════════════════════════════════
mqtt-client::ConnectionException: The connection must be in the Connected state in order to perform this operation.
══════════════════════════════════════════════════════════════════
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
mqtt_client: ^5.5.3
This is the version of mqtt_client I am using
import 'package:flutter/material.dart';
import 'package:mqtt_client/mqtt_client.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({String title});
#override
_MyHomePageState createState( ) => _MyHomePageState( );
}
class _MyHomePageState extends State<MyHomePage> {
String statusLock = '';
String topic = 'test'; //fill in the topic
int status;
MqttClient client = MqttClient.withPort('tailor.cloudmqtt.com', 'test', 12917); //put the mqtt info
MqttConnectMessage connMess = MqttConnectMessage( )
.withClientIdentifier('')
.withWillTopic('test')
.withWillMessage('test')
.startClean( )
.withWillQos(MqttQos.exactlyOnce);
MqttClientPayloadBuilder builder = MqttClientPayloadBuilder( );
#override
void initState( ){
super.initState( );
client.onSubscribed = onSubscribed;
client.connectionMessage = connMess;
}
void onSubscribed(String topic) {
print('EXAMPLE::Subscription confirmed for topic $topic');
}
void contactMQTT( ) async{
try{
await client.connect('example1','example2'); //put mqtt id and password
}catch (e){
print(e);
client.disconnect();
}
}
void _unlock(int status) {
setState(( ) {
if (status == 0){
statusLock = 'OPEN';
}else {
statusLock = 'CLOSE';
}
});
builder.addInt(status.toInt( ));
client.publishMessage(topic, MqttQos.exactlyOnce, builder.payload);
builder.payload.clear();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Status of Lock $statusLock',
),
SizedBox(height: 20.0,),
RaisedButton(
child: Text('ON'),
onPressed: ( ){
_unlock(0);
},
),
RaisedButton(
child: Text('OFF'),
onPressed: ( ) {
_unlock(1);
},
),
],
),
),
);
}
}
can anyone help me with it?i am new to flutter. I am deploying an app that can control a lock through mqtt using the flutter & mqtt by pressing on & off button in my app.