基于用户角色类型在Flutter应用程序中发送Firebase通知,错误是未为类“FirebaseMessaging”定义“sendNotification”

r7knjye2  于 2023-06-07  发布在  Flutter
关注(0)|答案(2)|浏览(147)

我仍在执行上述任务(在Flutter App中发送Firebase通知基于用户角色类型,),通知应在用户按下报告按钮时发送
错误是lib/screens/report。dart:96:33:错误:未为类“FirebaseMessaging”定义方法“sendNotification”。

  • 'FirebaseMessaging'来自'package:firebase_messaging/firebase_messaging.dart'('../../AppData/Local/Pub/Cache/hosted/pub.dev/firebase_messaging-14.6.2/lib/firebase_messaging.dart')。尝试将名称更正为现有方法的名称,或定义名为“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,
      });
    }
  }
}

如何避免错误?

t8e9dugd

t8e9dugd1#

Firebase Cloud Messages只能从受信任的环境发送所谓的下游消息(消息设备),例如您的开发机器、您控制的服务器或类似Cloud Functions/Cloud Run的东西。它不支持将消息从一个设备直接发送到另一个设备。
有关如何使用Cloud Functions通过FCM发送消息的示例,请参阅文档中的用例,即在发生有趣的事情时通知用户。
另见:

disho6za

disho6za2#

我实现了让用户订阅一个主题。

@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

  }

处理的订阅,

FirebaseMessaging.instance.subscribeToTopic('sandfly');

相关问题