我仍在执行上述任务(在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,
});
}
}
}
如何避免错误?
2条答案
按热度按时间t8e9dugd1#
Firebase Cloud Messages只能从受信任的环境发送所谓的下游消息(消息到设备),例如您的开发机器、您控制的服务器或类似Cloud Functions/Cloud Run的东西。它不支持将消息从一个设备直接发送到另一个设备。
有关如何使用Cloud Functions通过FCM发送消息的示例,请参阅文档中的用例,即在发生有趣的事情时通知用户。
另见:
disho6za2#
我实现了让用户订阅一个主题。
处理的订阅,