skip to Main Content

I am still in the process of doing the above task(Send Firebase Notifications in Flutter App based on User role type,), Notification should send when user press the Report Button.

Error is
lib/screens/report.dart:96:33: Error: The method ‘sendNotification’ isn’t defined for the class ‘FirebaseMessaging’.

  • ‘FirebaseMessaging’ is from ‘package:firebase_messaging/firebase_messaging.dart’ (‘../../AppData/Local/Pub/Cache/hosted/pub.dev/firebase_messaging-14.6.2/lib/firebase_messaging.dart’).
    Try correcting the name to the name of an existing method, or defining a method named ‘sendNotification’.
    return _firebaseMessaging.sendNotification(
    ^^^^^^^^^^^^^^^^

report.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:intl/intl.dart';
import 'package:leishsys/models/case.dart';
import '../collection.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';
import 'package:geocoding/geocoding.dart' as geocoding;
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'dart:io';
import 'package:image_picker/image_picker.dart';
import 'package:firebase_storage/firebase_storage.dart' as storage;
import 'body_parts_screen.dart';
import 'diagnsotic_screen.dart';
import 'package:firebase_messaging/firebase_messaging.dart';

class ReportScreen extends StatefulWidget {
  const ReportScreen({Key? key}) : super(key: key);

  static const routeName = "/report";

  @override
  State<ReportScreen> createState() => _ReportScreenState();
}

class _ReportScreenState extends State<ReportScreen> {
  int _sum = 0;
  late Case _case;
  final _usernameRpt = TextEditingController();
  String _reporterDesignation = "";
  final _otherRpt = TextEditingController();
  DateTime _reportDate = DateTime.now();
  final _ptName = TextEditingController();
  final _ptAge = TextEditingController();
  final _ptNic = TextEditingController();
  String _ptSex = "";
  bool _presumptiveCase = false;
  final _ptAddress = TextEditingController();
  final _ptResidentialArea = TextEditingController();
  LatLng? _selectedLocation;
  final _ptMoh = TextEditingController();
  final _ptPhi = TextEditingController();
  final _ptGn = TextEditingController();
  final _ptOccupation = TextEditingController();
  final _ptOccupationalArea = TextEditingController();
  final _ptTravelHistory = TextEditingController();
  final _ptPhone = TextEditingController();
  bool _confirmedCase = false;
  String _confirmedMethod = "";
  late File _lesionImage;
  bool _uploadingImage = false;
  late List<String> _lesionAreas;

  final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;


  @override
  void initState() {
    super.initState();
    _setInitialUsername();
    _configureFirebaseMessaging();
  }

  void _configureFirebaseMessaging() {
    // Request permission for receiving notifications
    FirebaseMessaging.instance.requestPermission();

    // Configure notification behavior when the app is in the foreground
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      // Handle the received notification message
      print('Foreground Notification: ${message.notification?.body}');
    });

    // Configure notification behavior when the app is in the background
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      // Handle the tapped notification message
      print('Background Notification: ${message.notification?.body}');
    });
  }

  Future<void> _sendNotificationToReviewersAndAdmins() async {
    // Retrieve all users with role "reviewer" or "admin"
    final snapshot = await FirebaseFirestore.instance
        .collection('users')
        .where('role', whereIn: ['reviewer', 'admin'])
        .get();

    // Extract the FCM tokens of the users
    final fcmTokens = snapshot.docs.map((doc) => doc['fcmToken']).toList();

    // Send the notification
    await Future.wait(fcmTokens.map((token) {
      return _firebaseMessaging.sendNotification(
        RemoteMessage(
          data: {
            'click_action': 'FLUTTER_NOTIFICATION_CLICK',
            'id': '1',
            'status': 'done',
          },
          notification: RemoteNotification(
            title: 'New Report Submitted',
            body: 'A new report has been submitted.',
          ),
          token: token,
        ),
      );
    }));

    print('Notification sent to reviewers and admins.');
  }

  Future<void> _setInitialUsername() async {
    final user = auth.FirebaseAuth.instance.currentUser;
    if (user != null) {
      setState(() {
        _usernameRpt.text = user.email ?? '';
      });
    }
  }

  //there's some code

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.green,
        title: const Text("Report a Case"),
      ),
      body: SingleChildScrollView(
        child: ConstrainedBox(
          constraints: BoxConstraints(),
          child: Padding(
              padding: const EdgeInsets.all(15.0),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: TextField(
                      decoration: const InputDecoration(
                          border: OutlineInputBorder(),
                          labelText: "Reporter's Username *"),
                      controller: _usernameRpt,
                      keyboardType: TextInputType.text,
                      enabled: false,
                    ),
                  ),
                  // there's code here
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: IgnorePointer(
                      ignoring: _disabled,
                      child: Opacity(
                        opacity: _disabled ? 0.5 : 1.0,
                        child: ElevatedButton(
                          style: ElevatedButton.styleFrom(
                            backgroundColor: Colors.green,
                          ),
                          onPressed: () {
                            _sendNotificationToReviewersAndAdmins();
                            showDialog(
                              context: context,
                              builder: (BuildContext context) {
                                return FutureBuilder(
                                  future: _reportCase(_case),
                                  builder: (context, snapshot) {
                                    if (snapshot.connectionState ==
                                        ConnectionState.waiting) {
                                      return const AlertDialog(
                                        title: Text('Submitting Report'),
                                        content: LinearProgressIndicator(
                                          backgroundColor: Colors.green,
                                        ),
                                      );
                                    } else {
                                      if (snapshot.hasData &&
                                          snapshot.data == true) {
                                        return AlertDialog(
                                          title: const Text('Report Submitted'),
                                          content: const Text(
                                              'Your report has been submitted successfully.'),
                                          actions: [
                                            ElevatedButton(
                                              onPressed: () {
                                                Navigator.of(context).pop();
                                                Navigator.of(context).pop();
                                              },
                                              child: const Text('OK'),
                                            ),
                                          ],
                                        );
                                      } else {
                                        return AlertDialog(
                                          title: const Text(
                                              'Report Not Submitted'),
                                          content: const Text(
                                              'There was an error submitting your report.'),
                                          actions: [
                                            ElevatedButton(
                                              onPressed: () {
                                                Navigator.of(context).pop();
                                              },style: ButtonStyle(
                                              backgroundColor: MaterialStateProperty.all<Color>(Colors.green),
                                            ),
                                              child: const Text('OK'),
                                            ),
                                          ],
                                        );
                                      }
                                    }
                                  },
                                );
                              },
                            );

                            setState(() {
                              _case = Case.report(
                                usernameRpt: _usernameRpt.text,
                                reporterDesignation:
                                    _reporterDesignation.toString(),
                                otherRpt: _otherRpt.text,
                                reportDate: _reportDate,
                                ptName: _ptName.text,
                                ptNic: _ptNic.text,
                                ptAge: int.parse(_ptAge.text),
                                ptSex: _ptSex.toString(),
                                lesionAreas:_lesionAreas,
                                presumptiveCase: _presumptiveCase,
                                ptAddress: _ptAddress.text,
                                ptResidentialArea: _ptResidentialArea.text,
                                ptMoh: _ptMoh.text,
                                ptPhi: _ptPhi.text,
                                ptGn: _ptGn.text,
                                ptOccupation: _ptOccupation.text,
                                ptOccupationalArea: _ptOccupationalArea.text,
                                ptTravelHistory: _ptTravelHistory.text,
                                ptPhone: int.parse(_ptPhone.text),
                                confirmedCase: _confirmedCase,
                                confirmedMethod: _confirmedMethod.toString(),
                              );
                              _pressedReport = true;
                            });
                          },
                          child: const Text("Report"),
                        ),
                      ),
                    ),
                  )
                ],
              )),
        ),
      ),
    );
  }

  Future<bool> _reportCase(Case kase) async {
    //case cannot be used. So I used kase

    final db = FirebaseFirestore.instance;

    try {
      final latitude = _selectedLocation?.latitude;
      final longitude = _selectedLocation?.longitude;

      kase.latitude = latitude;
      kase.longitude = longitude;

      final downloadURL = await _uploadImage();



      kase.lesionImageUrl = downloadURL;

      if (downloadURL != null) {
        kase.lesionImageUrl = downloadURL;
      } else {
        // Handle error when image upload fails
        return false;
      }




      await db
          .collection(Collection.cases)
          .withConverter(
            fromFirestore: Case.fromFirestore,
            toFirestore: (value, options) {
              return kase.toFirestore();
            },
          )
          .doc(kase.id)
          .set(kase);
    } catch (e) {
      print(e.toString());
      return false;
    } finally {
      await Future.delayed(const Duration(milliseconds: 1000));
    }
    return true;
  }
}

//some code here

main.dart

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:leishsys/screens/login_screen.dart';
import 'package:leishsys/screens/report.dart';
import 'package:leishsys/screens/reported_cases.dart';
import 'package:leishsys/screens/reviewer_home.dart';
import 'package:leishsys/screens/superadmin.dart';
import 'auth/auth_functions.dart';
import 'screens/home/home.dart';
import 'package:firebase_messaging/firebase_messaging.dart';

Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  runApp(Main());
}
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  print('Handling a background message: ${message.messageId}');
}

class Main extends StatelessWidget {

  Main({Key? key}) : super(key: key);



  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primaryColor: CupertinoColors.activeGreen),
      title: "LeishSys",
      home: MainScreen(),
    routes: {
      Home.routeName: (context) => Home(),
      ReportScreen.routeName: (context) => ReportScreen(),
      CasesScreen.routeName: (context) => CasesScreen(),
    }
    );
  }
}


class MainScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
        stream: FirebaseAuth.instance.authStateChanges(),
        builder: (context, snapshot) {
          if (snapshot.hasData && snapshot.data != null) {
            UserHelper.saveUser(snapshot.data!,'','','');
            return StreamBuilder<DocumentSnapshot>(
              stream: FirebaseFirestore.instance
                  .collection("users")
                  .doc(snapshot.data?.uid)
                  .snapshots(),
              builder: (BuildContext context,
                  AsyncSnapshot<DocumentSnapshot> snapshot) {
                if (snapshot.hasData && snapshot.data != null) {
                  final userDoc = snapshot.data!;
                  final user = userDoc.data();
                  if (user != null && user is Map<String, dynamic>) {
                    if (user['role'] == 'reviewer') {
                      return AdminHomePage();
                    } else if(user['role'] == 'admin'){
                      return SuperAdminHomePage();

                    }
                    else {
                      return Home();
                    }
                  } else {
                    return const Material(
                      child: Center(
                        child: Text('Error retrieving user data'),
                      ),
                    );
                  }
                } else {
                  return const Material(
                    child: Center(
                      child: CircularProgressIndicator(),
                    ),
                  );
                }
              },
            );
          }
          return LoginPage();
        });
  }
}

auth_functions.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:package_info_plus/package_info_plus.dart';

class AuthHelper {
  static final FirebaseAuth _auth = FirebaseAuth.instance;

  static Future<User?> signInWithEmail({
    required String email,
    required String password,
  }) async {
    try {
      final res = await _auth.signInWithEmailAndPassword(
        email: email,
        password: password,
      );
      final User? user = res.user;
      return user;
    } catch (e) {
      throw e;
    }
  }

  static Future<User?> signupWithEmail({
    required String email,
    required String password,
    required String name,
    required String designation,
    required String telephone,
  }) async {
    try {
      final res = await _auth.createUserWithEmailAndPassword(
        email: email,
        password: password,
      );
      final User? user = res.user;
      if (user != null) {
        await UserHelper.saveUser(user, name, designation, telephone);
      }
      return user;
    } catch (e) {
      throw e;
    }
  }

  static Future<void> logOut() async {
    await _auth.signOut();
  }
}

class UserHelper {
  static final FirebaseFirestore _db = FirebaseFirestore.instance;

  static Future<void> saveUser(
      User user,
      String name,
      String designation,
      String telephone,
      ) async {
    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    int buildNumber = int.parse(packageInfo.buildNumber);

    Map<String, dynamic> userData = {
      "name": name,
      "designation": designation,
      "telephone": telephone,
      "email": user.email,
      "last_login": user.metadata.lastSignInTime?.millisecondsSinceEpoch,
      "created_at": user.metadata.creationTime?.millisecondsSinceEpoch,
      "role": "user",
      "build_number": buildNumber,
    };

    final userRef = _db.collection("users").doc(user.uid);
    final userDoc = await userRef.get();

    if (userDoc.exists) {
      final userData = userDoc.data();
      if (userData != null && userData.containsKey('role')) {
        userData['role'] = userData['role'];
      } else {
        userData?['role'] = 'user';
      }
      await userRef.update(userData as Map<Object, Object?>); // Explicit cast
    } else {
      await userRef.set(userData);
    }

    await _saveDevice(user);
  }

  static Future<void> _saveDevice(User user) async {
    DeviceInfoPlugin devicePlugin = DeviceInfoPlugin();
    String? deviceId;
    late Map<String, dynamic> deviceData;
    if (Platform.isAndroid) {
      final deviceInfo = await devicePlugin.androidInfo;

      deviceData = {
        "os_version": deviceInfo.version.sdkInt.toString(),
        "platform": 'android',
        "model": deviceInfo.model,
        "device": deviceInfo.device,
      };
    }
    if (Platform.isIOS) {
      final deviceInfo = await devicePlugin.iosInfo;
      deviceId = deviceInfo.identifierForVendor;
      deviceData = {
        "os_version": deviceInfo.systemVersion,
        "device": deviceInfo.name,
        "model": deviceInfo.utsname.machine,
        "platform": 'ios',
      };
    }

    final nowMS = DateTime.now().toUtc().millisecondsSinceEpoch;
    final deviceRef = _db
        .collection("users")
        .doc(user.uid)
        .collection("devices")
        .doc(deviceId);

    if ((await deviceRef.get()).exists) {
      await deviceRef.update({
        "updated_at": nowMS,
        "uninstalled": false,
      });
    } else {
      await deviceRef.set({
        "updated_at": nowMS,
        "uninstalled": false,
        "id": deviceId,
        "created_at": nowMS,
        "device_info": deviceData,
      });
    }
  }
}

How to do this avoiding errors?

2

Answers


  1. Chosen as BEST ANSWER

    I implemented by this letting the users subscribing to a topic.

    @override
    void initState() {
        super.initState();
        FirebaseMessaging.instance.getInitialMessage();
        _setInitialUsername();
        FirebaseMessaging.onMessage.listen((event) {
          LocalNotificationService.display(event);
        });
        storeNotificationToken();
    
      }
    
      storeNotificationToken()async{
        String? token = await FirebaseMessaging.instance.getToken();
        FirebaseFirestore.instance.collection('users').doc(FirebaseAuth.instance.currentUser!.uid).set(
            {
              'token': token
            },SetOptions(merge: true));
      }
    
    
      sendNotificationToTopic(String title)async{
    
        final data = {
          'click_action': 'FLUTTER_NOTIFICATION_CLICK',
          'id': '1',
          'status': 'done',
          'message': title,
        };
    
        try{
          http.Response response = await http.post(Uri.parse('https://fcm.googleapis.com/fcm/send'),headers: <String,String>{
            'Content-Type': 'application/json',
            'Authorization': 'key=MY_KEY'
          },
              body: jsonEncode(<String,dynamic>{
                'notification': <String,dynamic> {'title': title,'body': 'New Case Was Reported'},
                'priority': 'high',
                'data': data,
                'to': '/topics/sandfly'
              })
          );
    
    
          if(response.statusCode == 200){
            print("notificatin is sended");
          }else{
            print("Error");
          }
    
        }catch(e){
    
        }
        enter code here
    
      }
    

    Subscription handled by this,

    FirebaseMessaging.instance.subscribeToTopic('sandfly');
    

  2. Firebase Cloud Messages can only send so-called downstream messages (messages to a device) from a trusted environment, such as your development machine, a server that you control, or something like Cloud Functions/Cloud Run. It does not support sending messages from one device directly to another device.

    For an example of how to send messages through FCM with Cloud Functions, see the use-case in the documentation of notifying the user when something interesting happens.

    Also see:

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search