25-10-5/1
This commit is contained in:
@@ -26,6 +26,7 @@ import '../functions/encrypt_decrypt.dart';
|
||||
import '../functions/face_detect.dart';
|
||||
import 'access_token.dart';
|
||||
import 'local_notification.dart';
|
||||
import 'notification_service.dart';
|
||||
|
||||
class FirebaseMessagesController extends GetxController {
|
||||
final fcmToken = FirebaseMessaging.instance;
|
||||
@@ -154,12 +155,20 @@ class FirebaseMessagesController extends GetxController {
|
||||
'VIP Order'.tr, '', 'order', '');
|
||||
}
|
||||
MyDialog().getDialog('VIP Order'.tr, 'midTitle', () {
|
||||
sendNotificationToPassengerToken(
|
||||
'VIP Order Accepted'.tr,
|
||||
'The driver accepted your trip'.tr,
|
||||
driverList[0],
|
||||
[driverList[1]],
|
||||
'order');
|
||||
// sendNotificationToPassengerToken(
|
||||
// 'VIP Order Accepted'.tr,
|
||||
// 'The driver accepted your trip'.tr,
|
||||
// driverList[0],
|
||||
// [driverList[1]],
|
||||
// 'order');
|
||||
NotificationService.sendNotification(
|
||||
target: driverList[0].toString(),
|
||||
title: 'VIP Order Accepted'.tr,
|
||||
body: 'The driver accepted your trip'.tr,
|
||||
isTopic: false, // Important: this is a token
|
||||
tone: 'order',
|
||||
driverList: [],
|
||||
);
|
||||
});
|
||||
|
||||
// Get.to(const VipOrderPage());
|
||||
@@ -387,360 +396,360 @@ class FirebaseMessagesController extends GetxController {
|
||||
// }));
|
||||
// }
|
||||
|
||||
late String serviceAccountKeyJson;
|
||||
@override
|
||||
Future<void> onInit() async {
|
||||
super.onInit();
|
||||
try {
|
||||
// getToken();
|
||||
var encryptedKey = Env.privateKeyFCM;
|
||||
// Log.print('encryptedKey: ${encryptedKey}');
|
||||
serviceAccountKeyJson =
|
||||
EncryptionHelper.instance.decryptData(encryptedKey);
|
||||
// Log.print('serviceAccountKeyJson: ${serviceAccountKeyJson}');
|
||||
} catch (e) {
|
||||
print('🔴 Error decrypting FCM key: $e');
|
||||
}
|
||||
}
|
||||
// late String serviceAccountKeyJson;
|
||||
// @override
|
||||
// Future<void> onInit() async {
|
||||
// super.onInit();
|
||||
// try {
|
||||
// // getToken();
|
||||
// var encryptedKey = Env.privateKeyFCM;
|
||||
// // Log.print('encryptedKey: ${encryptedKey}');
|
||||
// serviceAccountKeyJson =
|
||||
// EncryptionHelper.instance.decryptData(encryptedKey);
|
||||
// // Log.print('serviceAccountKeyJson: ${serviceAccountKeyJson}');
|
||||
// } catch (e) {
|
||||
// print('🔴 Error decrypting FCM key: $e');
|
||||
// }
|
||||
// }
|
||||
|
||||
void sendNotificationAll(String title, body, tone) async {
|
||||
// توكني الحالي (لا أرسل لنفسي)
|
||||
final String myToken = box.read(BoxName.tokenFCM) ?? '';
|
||||
// اقرأ قائمة كل التوكنات
|
||||
final List<String> all =
|
||||
List<String>.from(box.read(BoxName.tokens) ?? const []);
|
||||
// void sendNotificationAll(String title, body, tone) async {
|
||||
// // توكني الحالي (لا أرسل لنفسي)
|
||||
// final String myToken = box.read(BoxName.tokenFCM) ?? '';
|
||||
// // اقرأ قائمة كل التوكنات
|
||||
// final List<String> all =
|
||||
// List<String>.from(box.read(BoxName.tokens) ?? const []);
|
||||
|
||||
// استبعد توكنك واحذف الفارغ
|
||||
final targets = all.where((t) => t.isNotEmpty && t != myToken).toList();
|
||||
// // استبعد توكنك واحذف الفارغ
|
||||
// final targets = all.where((t) => t.isNotEmpty && t != myToken).toList();
|
||||
|
||||
if (serviceAccountKeyJson.isEmpty) {
|
||||
print("🔴 Error: Service Account Key is empty");
|
||||
return;
|
||||
}
|
||||
final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
||||
final accessToken = await accessTokenManager.getAccessToken();
|
||||
// if (serviceAccountKeyJson.isEmpty) {
|
||||
// print("🔴 Error: Service Account Key is empty");
|
||||
// return;
|
||||
// }
|
||||
// final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
||||
// final accessToken = await accessTokenManager.getAccessToken();
|
||||
|
||||
for (final t in targets) {
|
||||
// ⚠️ المهم: استخدم t (توكن الهدف)، وليس المتغير myToken
|
||||
final response = await http.post(
|
||||
Uri.parse(
|
||||
'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer $accessToken',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'message': {
|
||||
'token': t,
|
||||
'notification': {'title': title, 'body': body},
|
||||
'android': {
|
||||
'priority': 'HIGH', // القيم الصحيحة: HIGH/NORMAL
|
||||
'notification': {'sound': tone},
|
||||
// (اختياري) TTL لتجنّب رسائل قديمة
|
||||
'ttl': '30s',
|
||||
},
|
||||
'apns': {
|
||||
'headers': {
|
||||
'apns-priority': '10',
|
||||
// لو iOS: حدد نوع الدفع
|
||||
'apns-push-type': 'alert',
|
||||
},
|
||||
'payload': {
|
||||
'aps': {'sound': tone}
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
// for (final t in targets) {
|
||||
// // ⚠️ المهم: استخدم t (توكن الهدف)، وليس المتغير myToken
|
||||
// final response = await http.post(
|
||||
// Uri.parse(
|
||||
// 'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'),
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
// 'Authorization': 'Bearer $accessToken',
|
||||
// },
|
||||
// body: jsonEncode({
|
||||
// 'message': {
|
||||
// 'token': t,
|
||||
// 'notification': {'title': title, 'body': body},
|
||||
// 'android': {
|
||||
// 'priority': 'HIGH', // القيم الصحيحة: HIGH/NORMAL
|
||||
// 'notification': {'sound': tone},
|
||||
// // (اختياري) TTL لتجنّب رسائل قديمة
|
||||
// 'ttl': '30s',
|
||||
// },
|
||||
// 'apns': {
|
||||
// 'headers': {
|
||||
// 'apns-priority': '10',
|
||||
// // لو iOS: حدد نوع الدفع
|
||||
// 'apns-push-type': 'alert',
|
||||
// },
|
||||
// 'payload': {
|
||||
// 'aps': {'sound': tone}
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// }),
|
||||
// );
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
// حاول تقرأ الخطأ وتشيل التوكنات التالفة
|
||||
_handleV1Error(response, badToken: t);
|
||||
await Future.delayed(const Duration(milliseconds: 50)); // تخفيف ضغط
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (response.statusCode != 200) {
|
||||
// // حاول تقرأ الخطأ وتشيل التوكنات التالفة
|
||||
// _handleV1Error(response, badToken: t);
|
||||
// await Future.delayed(const Duration(milliseconds: 50)); // تخفيف ضغط
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
void _handleV1Error(http.Response res, {required String badToken}) {
|
||||
try {
|
||||
final body = jsonDecode(res.body);
|
||||
final err = body['error']?['status']?.toString() ?? '';
|
||||
// أمثلة شائعة:
|
||||
if (err.contains('UNREGISTERED') || err.contains('NOT_FOUND')) {
|
||||
removeInvalidToken(badToken);
|
||||
} else if (err.contains('INVALID_ARGUMENT')) {
|
||||
// payload غير صحيح
|
||||
print(
|
||||
'⚠️ INVALID_ARGUMENT for $badToken: ${body['error']?['message']}');
|
||||
} else if (err.contains('RESOURCE_EXHAUSTED') ||
|
||||
err.contains('QUOTA_EXCEEDED')) {
|
||||
// تجاوزت الحصة—خفّف السرعة/قسّم الإرسال (FCM v1 له حصة/دقيقة)
|
||||
// https docs: 600k req/min per project (token bucket)
|
||||
print('⏳ Throttled by FCM: slow down sending rate.');
|
||||
} else {
|
||||
print('FCM v1 error: ${res.statusCode} ${res.body}');
|
||||
}
|
||||
} catch (_) {
|
||||
print('FCM v1 error: ${res.statusCode} ${res.body}');
|
||||
}
|
||||
}
|
||||
// void _handleV1Error(http.Response res, {required String badToken}) {
|
||||
// try {
|
||||
// final body = jsonDecode(res.body);
|
||||
// final err = body['error']?['status']?.toString() ?? '';
|
||||
// // أمثلة شائعة:
|
||||
// if (err.contains('UNREGISTERED') || err.contains('NOT_FOUND')) {
|
||||
// removeInvalidToken(badToken);
|
||||
// } else if (err.contains('INVALID_ARGUMENT')) {
|
||||
// // payload غير صحيح
|
||||
// print(
|
||||
// '⚠️ INVALID_ARGUMENT for $badToken: ${body['error']?['message']}');
|
||||
// } else if (err.contains('RESOURCE_EXHAUSTED') ||
|
||||
// err.contains('QUOTA_EXCEEDED')) {
|
||||
// // تجاوزت الحصة—خفّف السرعة/قسّم الإرسال (FCM v1 له حصة/دقيقة)
|
||||
// // https docs: 600k req/min per project (token bucket)
|
||||
// print('⏳ Throttled by FCM: slow down sending rate.');
|
||||
// } else {
|
||||
// print('FCM v1 error: ${res.statusCode} ${res.body}');
|
||||
// }
|
||||
// } catch (_) {
|
||||
// print('FCM v1 error: ${res.statusCode} ${res.body}');
|
||||
// }
|
||||
// }
|
||||
|
||||
void sendNotificationToPassengerToken(
|
||||
String title, body, token, List<String> map, String tone,
|
||||
{int retryCount = 2}) async {
|
||||
try {
|
||||
if (serviceAccountKeyJson.isEmpty) {
|
||||
print("🔴 Error: Service Account Key is empty");
|
||||
return;
|
||||
}
|
||||
// Initialize AccessTokenManager
|
||||
final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
||||
// void sendNotificationToPassengerToken(
|
||||
// String title, body, token, List<String> map, String tone,
|
||||
// {int retryCount = 2}) async {
|
||||
// try {
|
||||
// if (serviceAccountKeyJson.isEmpty) {
|
||||
// print("🔴 Error: Service Account Key is empty");
|
||||
// return;
|
||||
// }
|
||||
// // Initialize AccessTokenManager
|
||||
// final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
||||
|
||||
// Obtain an OAuth 2.0 access token
|
||||
final accessToken = await accessTokenManager.getAccessToken();
|
||||
// Log.print('accessToken: ${accessToken}');
|
||||
// // Obtain an OAuth 2.0 access token
|
||||
// final accessToken = await accessTokenManager.getAccessToken();
|
||||
// // Log.print('accessToken: ${accessToken}');
|
||||
|
||||
// Send the notification
|
||||
final response = await http.post(
|
||||
Uri.parse(
|
||||
'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'),
|
||||
headers: <String, String>{
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer $accessToken',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'message': {
|
||||
'token': token,
|
||||
'notification': {
|
||||
'title': title,
|
||||
'body': body,
|
||||
},
|
||||
'data': {
|
||||
'passengerList': jsonEncode(map),
|
||||
},
|
||||
'android': {
|
||||
'priority': 'HIGH ', // Set priority to high
|
||||
'notification': {
|
||||
'sound': tone,
|
||||
},
|
||||
},
|
||||
'apns': {
|
||||
'headers': {
|
||||
'apns-priority': '10', // Set APNs priority to 10
|
||||
},
|
||||
'payload': {
|
||||
'aps': {
|
||||
'sound': tone,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
// // Send the notification
|
||||
// final response = await http.post(
|
||||
// Uri.parse(
|
||||
// 'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'),
|
||||
// headers: <String, String>{
|
||||
// 'Content-Type': 'application/json',
|
||||
// 'Authorization': 'Bearer $accessToken',
|
||||
// },
|
||||
// body: jsonEncode({
|
||||
// 'message': {
|
||||
// 'token': token,
|
||||
// 'notification': {
|
||||
// 'title': title,
|
||||
// 'body': body,
|
||||
// },
|
||||
// 'data': {
|
||||
// 'passengerList': jsonEncode(map),
|
||||
// },
|
||||
// 'android': {
|
||||
// 'priority': 'HIGH ', // Set priority to high
|
||||
// 'notification': {
|
||||
// 'sound': tone,
|
||||
// },
|
||||
// },
|
||||
// 'apns': {
|
||||
// 'headers': {
|
||||
// 'apns-priority': '10', // Set APNs priority to 10
|
||||
// },
|
||||
// 'payload': {
|
||||
// 'aps': {
|
||||
// 'sound': tone,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// }),
|
||||
// );
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
print(
|
||||
'Notification sent successfully. Status code: ${response.statusCode}');
|
||||
print('Response body: ${response.body}');
|
||||
} else {
|
||||
print(
|
||||
'Failed to send notification. Status code: ${response.statusCode}');
|
||||
// if (response.statusCode == 200) {
|
||||
// print(
|
||||
// 'Notification sent successfully. Status code: ${response.statusCode}');
|
||||
// print('Response body: ${response.body}');
|
||||
// } else {
|
||||
// print(
|
||||
// 'Failed to send notification. Status code: ${response.statusCode}');
|
||||
|
||||
print('Response body: ${response.body}');
|
||||
if (retryCount > 0) {
|
||||
print('Retrying... Attempts remaining: $retryCount');
|
||||
await Future.delayed(
|
||||
const Duration(seconds: 2)); // Optional delay before retrying
|
||||
return sendNotificationToPassengerToken(title, body, token, map, tone,
|
||||
retryCount: retryCount - 1);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error sending notification: $e');
|
||||
if (retryCount > 0) {
|
||||
print('Retrying... Attempts remaining: $retryCount');
|
||||
await Future.delayed(
|
||||
const Duration(seconds: 2)); // Optional delay before retrying
|
||||
return sendNotificationToPassengerToken(title, body, token, map, tone,
|
||||
retryCount: retryCount - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// print('Response body: ${response.body}');
|
||||
// if (retryCount > 0) {
|
||||
// print('Retrying... Attempts remaining: $retryCount');
|
||||
// await Future.delayed(
|
||||
// const Duration(seconds: 2)); // Optional delay before retrying
|
||||
// return sendNotificationToPassengerToken(title, body, token, map, tone,
|
||||
// retryCount: retryCount - 1);
|
||||
// }
|
||||
// }
|
||||
// } catch (e) {
|
||||
// print('Error sending notification: $e');
|
||||
// if (retryCount > 0) {
|
||||
// print('Retrying... Attempts remaining: $retryCount');
|
||||
// await Future.delayed(
|
||||
// const Duration(seconds: 2)); // Optional delay before retrying
|
||||
// return sendNotificationToPassengerToken(title, body, token, map, tone,
|
||||
// retryCount: retryCount - 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
void sendNotificationToPassengerTokenCALL(
|
||||
String title, body, token, List<String> map, String tone,
|
||||
{int retryCount = 2}) async {
|
||||
try {
|
||||
if (serviceAccountKeyJson.isEmpty) {
|
||||
print("🔴 Error: Service Account Key is empty");
|
||||
return;
|
||||
}
|
||||
// Initialize AccessTokenManager
|
||||
final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
||||
// void sendNotificationToPassengerTokenCALL(
|
||||
// String title, body, token, List<String> map, String tone,
|
||||
// {int retryCount = 2}) async {
|
||||
// try {
|
||||
// if (serviceAccountKeyJson.isEmpty) {
|
||||
// print("🔴 Error: Service Account Key is empty");
|
||||
// return;
|
||||
// }
|
||||
// // Initialize AccessTokenManager
|
||||
// final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
||||
|
||||
// Obtain an OAuth 2.0 access token
|
||||
final accessToken = await accessTokenManager.getAccessToken();
|
||||
// Log.print('accessToken: ${accessToken}');
|
||||
// // Obtain an OAuth 2.0 access token
|
||||
// final accessToken = await accessTokenManager.getAccessToken();
|
||||
// // Log.print('accessToken: ${accessToken}');
|
||||
|
||||
// Send the notification
|
||||
final response = await http.post(
|
||||
Uri.parse(
|
||||
'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'),
|
||||
headers: <String, String>{
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer $accessToken',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'message': {
|
||||
'token': token,
|
||||
'notification': {
|
||||
'title': title,
|
||||
'body': body,
|
||||
},
|
||||
'data': {
|
||||
'passengerList': jsonEncode(map),
|
||||
},
|
||||
'android': {
|
||||
'priority': 'HIGH ', // Set priority to high
|
||||
'notification': {
|
||||
'sound': tone,
|
||||
},
|
||||
},
|
||||
'apns': {
|
||||
'headers': {
|
||||
'apns-priority': '10', // Set APNs priority to 10
|
||||
},
|
||||
'payload': {
|
||||
'aps': {
|
||||
'sound': tone,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
// // Send the notification
|
||||
// final response = await http.post(
|
||||
// Uri.parse(
|
||||
// 'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'),
|
||||
// headers: <String, String>{
|
||||
// 'Content-Type': 'application/json',
|
||||
// 'Authorization': 'Bearer $accessToken',
|
||||
// },
|
||||
// body: jsonEncode({
|
||||
// 'message': {
|
||||
// 'token': token,
|
||||
// 'notification': {
|
||||
// 'title': title,
|
||||
// 'body': body,
|
||||
// },
|
||||
// 'data': {
|
||||
// 'passengerList': jsonEncode(map),
|
||||
// },
|
||||
// 'android': {
|
||||
// 'priority': 'HIGH ', // Set priority to high
|
||||
// 'notification': {
|
||||
// 'sound': tone,
|
||||
// },
|
||||
// },
|
||||
// 'apns': {
|
||||
// 'headers': {
|
||||
// 'apns-priority': '10', // Set APNs priority to 10
|
||||
// },
|
||||
// 'payload': {
|
||||
// 'aps': {
|
||||
// 'sound': tone,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// }),
|
||||
// );
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
print(
|
||||
'Notification sent successfully. Status code: ${response.statusCode}');
|
||||
print('Response body: ${response.body}');
|
||||
} else {
|
||||
print(
|
||||
'Failed to send notification. Status code: ${response.statusCode}');
|
||||
// if (response.statusCode == 200) {
|
||||
// print(
|
||||
// 'Notification sent successfully. Status code: ${response.statusCode}');
|
||||
// print('Response body: ${response.body}');
|
||||
// } else {
|
||||
// print(
|
||||
// 'Failed to send notification. Status code: ${response.statusCode}');
|
||||
|
||||
print('Response body: ${response.body}');
|
||||
if (retryCount > 0) {
|
||||
print('Retrying... Attempts remaining: $retryCount');
|
||||
await Future.delayed(
|
||||
const Duration(seconds: 2)); // Optional delay before retrying
|
||||
return sendNotificationToPassengerTokenCALL(
|
||||
title, body, token, map, tone,
|
||||
retryCount: retryCount - 1);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error sending notification: $e');
|
||||
if (retryCount > 0) {
|
||||
print('Retrying... Attempts remaining: $retryCount');
|
||||
await Future.delayed(
|
||||
const Duration(seconds: 2)); // Optional delay before retrying
|
||||
return sendNotificationToPassengerTokenCALL(
|
||||
title, body, token, map, tone,
|
||||
retryCount: retryCount - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// print('Response body: ${response.body}');
|
||||
// if (retryCount > 0) {
|
||||
// print('Retrying... Attempts remaining: $retryCount');
|
||||
// await Future.delayed(
|
||||
// const Duration(seconds: 2)); // Optional delay before retrying
|
||||
// return sendNotificationToPassengerTokenCALL(
|
||||
// title, body, token, map, tone,
|
||||
// retryCount: retryCount - 1);
|
||||
// }
|
||||
// }
|
||||
// } catch (e) {
|
||||
// print('Error sending notification: $e');
|
||||
// if (retryCount > 0) {
|
||||
// print('Retrying... Attempts remaining: $retryCount');
|
||||
// await Future.delayed(
|
||||
// const Duration(seconds: 2)); // Optional delay before retrying
|
||||
// return sendNotificationToPassengerTokenCALL(
|
||||
// title, body, token, map, tone,
|
||||
// retryCount: retryCount - 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Future<void> sendNotificationToDriverMAP(
|
||||
String title, String body, String token, List<String> data, String tone,
|
||||
{int retryCount = 2}) async {
|
||||
try {
|
||||
if (serviceAccountKeyJson.isEmpty) {
|
||||
print("🔴 Error: Service Account Key is empty");
|
||||
return;
|
||||
}
|
||||
// Future<void> sendNotificationToDriverMAP(
|
||||
// String title, String body, String token, List<String> data, String tone,
|
||||
// {int retryCount = 2}) async {
|
||||
// try {
|
||||
// if (serviceAccountKeyJson.isEmpty) {
|
||||
// print("🔴 Error: Service Account Key is empty");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Initialize AccessTokenManager
|
||||
final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
||||
Log.print(
|
||||
'accessTokenManager: ${accessTokenManager.serviceAccountJsonKey}');
|
||||
// // Initialize AccessTokenManager
|
||||
// final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
||||
// Log.print(
|
||||
// 'accessTokenManager: ${accessTokenManager.serviceAccountJsonKey}');
|
||||
|
||||
// Obtain an OAuth 2.0 access token
|
||||
final accessToken = await accessTokenManager.getAccessToken();
|
||||
// Log.print('accessToken: ${accessToken}');
|
||||
// // Obtain an OAuth 2.0 access token
|
||||
// final accessToken = await accessTokenManager.getAccessToken();
|
||||
// // Log.print('accessToken: ${accessToken}');
|
||||
|
||||
// Send the notification
|
||||
final response = await http.post(
|
||||
Uri.parse(
|
||||
'https://fcm.googleapis.com/v1/projects/intaleq-d48a7/messages:send'),
|
||||
headers: <String, String>{
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer $accessToken',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'message': {
|
||||
'token': token,
|
||||
'notification': {
|
||||
'title': title,
|
||||
'body': body,
|
||||
},
|
||||
'data': {
|
||||
'DriverList': jsonEncode(data),
|
||||
},
|
||||
'android': {
|
||||
'priority': 'HIGH ', // Set priority to high
|
||||
'notification': {
|
||||
'sound': tone,
|
||||
},
|
||||
},
|
||||
'apns': {
|
||||
'headers': {
|
||||
'apns-priority': '10', // Set APNs priority to 10
|
||||
},
|
||||
'payload': {
|
||||
'aps': {
|
||||
'sound': tone,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
// // Send the notification
|
||||
// final response = await http.post(
|
||||
// Uri.parse(
|
||||
// 'https://fcm.googleapis.com/v1/projects/intaleq-d48a7/messages:send'),
|
||||
// headers: <String, String>{
|
||||
// 'Content-Type': 'application/json',
|
||||
// 'Authorization': 'Bearer $accessToken',
|
||||
// },
|
||||
// body: jsonEncode({
|
||||
// 'message': {
|
||||
// 'token': token,
|
||||
// 'notification': {
|
||||
// 'title': title,
|
||||
// 'body': body,
|
||||
// },
|
||||
// 'data': {
|
||||
// 'DriverList': jsonEncode(data),
|
||||
// },
|
||||
// 'android': {
|
||||
// 'priority': 'HIGH ', // Set priority to high
|
||||
// 'notification': {
|
||||
// 'sound': tone,
|
||||
// },
|
||||
// },
|
||||
// 'apns': {
|
||||
// 'headers': {
|
||||
// 'apns-priority': '10', // Set APNs priority to 10
|
||||
// },
|
||||
// 'payload': {
|
||||
// 'aps': {
|
||||
// 'sound': tone,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// }),
|
||||
// );
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
print(
|
||||
'Notification sent successfully. Status code: ${response.statusCode}');
|
||||
// print('Response token: ${token}');
|
||||
} else {
|
||||
print(
|
||||
'Failed to send notification. Status code: ${response.statusCode}');
|
||||
print('Response body: ${response.body}');
|
||||
if (retryCount > 0) {
|
||||
print('Retrying... Attempts remaining: $retryCount');
|
||||
await Future.delayed(
|
||||
Duration(seconds: 2)); // Optional delay before retrying
|
||||
return sendNotificationToDriverMAP(title, body, token, data, tone,
|
||||
retryCount: retryCount - 1);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error sending notification: $e');
|
||||
if (retryCount > 0) {
|
||||
print('Retrying... Attempts remaining: $retryCount');
|
||||
await Future.delayed(
|
||||
Duration(seconds: 2)); // Optional delay before retrying
|
||||
return sendNotificationToDriverMAP(title, body, token, data, tone,
|
||||
retryCount: retryCount - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (response.statusCode == 200) {
|
||||
// print(
|
||||
// 'Notification sent successfully. Status code: ${response.statusCode}');
|
||||
// // print('Response token: ${token}');
|
||||
// } else {
|
||||
// print(
|
||||
// 'Failed to send notification. Status code: ${response.statusCode}');
|
||||
// print('Response body: ${response.body}');
|
||||
// if (retryCount > 0) {
|
||||
// print('Retrying... Attempts remaining: $retryCount');
|
||||
// await Future.delayed(
|
||||
// Duration(seconds: 2)); // Optional delay before retrying
|
||||
// return sendNotificationToDriverMAP(title, body, token, data, tone,
|
||||
// retryCount: retryCount - 1);
|
||||
// }
|
||||
// }
|
||||
// } catch (e) {
|
||||
// print('Error sending notification: $e');
|
||||
// if (retryCount > 0) {
|
||||
// print('Retrying... Attempts remaining: $retryCount');
|
||||
// await Future.delayed(
|
||||
// Duration(seconds: 2)); // Optional delay before retrying
|
||||
// return sendNotificationToDriverMAP(title, body, token, data, tone,
|
||||
// retryCount: retryCount - 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Future<void> removeInvalidToken(String token) async {
|
||||
// Remove token from your database/storage
|
||||
// This prevents future attempts to send to invalid tokens
|
||||
print('Removing invalid token from database: $token');
|
||||
// Your database cleanup logic here
|
||||
}
|
||||
// Future<void> removeInvalidToken(String token) async {
|
||||
// // Remove token from your database/storage
|
||||
// // This prevents future attempts to send to invalid tokens
|
||||
// print('Removing invalid token from database: $token');
|
||||
// // Your database cleanup logic here
|
||||
// }
|
||||
}
|
||||
|
||||
class OverlayContent extends StatelessWidget {
|
||||
|
||||
@@ -6,66 +6,50 @@ class NotificationService {
|
||||
static const String _serverUrl =
|
||||
'https://syria.intaleq.xyz/intaleq/fcm/send_fcm.php';
|
||||
|
||||
/// Sends a notification via your backend server.
|
||||
///
|
||||
/// [target]: The device token or the topic name.
|
||||
/// [title]: The notification title.
|
||||
/// [body]: The notification body.
|
||||
/// [isTopic]: Set to true if the target is a topic, false if it's a device token.
|
||||
static Future<void> sendNotification({
|
||||
required String target,
|
||||
required String title,
|
||||
required String body,
|
||||
String? tone,
|
||||
List<String>? driverList, // <-- [تعديل 1] : إضافة المتغير الجديد
|
||||
bool isTopic = false,
|
||||
}) async {
|
||||
try {
|
||||
final Map<String, dynamic> payload = {
|
||||
'target': target,
|
||||
'title': title,
|
||||
'body': body,
|
||||
'isTopic': isTopic,
|
||||
};
|
||||
|
||||
// نضيف النغمة فقط إذا لم تكن فارغة
|
||||
if (tone != null) {
|
||||
payload['tone'] = tone;
|
||||
}
|
||||
|
||||
// <-- [تعديل 2] : نضيف قائمة البيانات بعد تشفيرها إلى JSON
|
||||
if (driverList != null) {
|
||||
payload['driverList'] = jsonEncode(driverList);
|
||||
}
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse(_serverUrl),
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=UTF-8',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'target': target,
|
||||
'title': title,
|
||||
'body': body,
|
||||
'isTopic': isTopic,
|
||||
}),
|
||||
body: jsonEncode(payload),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
print('Notification sent successfully.');
|
||||
print('✅ Notification sent successfully.');
|
||||
print('Server Response: ${response.body}');
|
||||
} else {
|
||||
print(
|
||||
'Failed to send notification. Status code: ${response.statusCode}');
|
||||
'❌ Failed to send notification. Status code: ${response.statusCode}');
|
||||
print('Server Error: ${response.body}');
|
||||
}
|
||||
} catch (e) {
|
||||
print('An error occurred while sending notification: $e');
|
||||
print('❌ An error occurred while sending notification: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Example of how to use it ---
|
||||
|
||||
// To send to a specific driver (using their token)
|
||||
void sendToSpecificDriver() {
|
||||
String driverToken =
|
||||
'bk3RNwTe3H0:CI2k_HHwgIpoDKCI5oT...'; // The driver's FCM token
|
||||
NotificationService.sendNotification(
|
||||
target: driverToken,
|
||||
title: 'New Trip Request!',
|
||||
body: 'A passenger is waiting for you.',
|
||||
isTopic: false, // Important: this is a token
|
||||
);
|
||||
}
|
||||
|
||||
// To send to all drivers (using a topic)
|
||||
void sendToAllDrivers() {
|
||||
NotificationService.sendNotification(
|
||||
target: 'drivers', // The name of the topic
|
||||
title: 'Important Announcement',
|
||||
body: 'Please update your app to the latest version.',
|
||||
isTopic: true, // Important: this is a topic
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user