我目前正在努力在
Flutter
中实现带有通知处理程序的隔离。
它已经在工作了,我有一个
MQTT
侦听器,它使用 AwesomeNotification
显示通知,并有 2 个用于接受或拒绝通知的操作。
当接受通知时,我想进行 API 调用来更新与该通知相关的记录。
为了让我变得更简单,我在
MQTT
有效负载中包含了一些详细信息,我需要使用这些详细信息来进行 API 调用,我将该详细信息设置为一个变量,以便稍后使用它。
问题是,当应用程序到达
AwesomeNotification's onActionReceivedMethod
时,变量的值已经消失了。
我认为这样做的原因是因为,执行代码已经超出了
service/isolate
的范围,因此无法访问该变量。
然后我尝试使用
SharedPreferences
,但密钥的更新速度没有我想要/预期的那么快。现在,我不知道如何保留一点价值,以便我可以继续这个过程。
这是我当前的代码:
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:isolate';
import 'dart:ui';
import 'package:baraco_frontend/helpers/api/request_vehicle_change_api_helper.dart';
import 'package:baraco_frontend/helpers/sharedPref/shared_pref_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:intl/intl.dart';
import 'package:mqtt_client/mqtt_client.dart';
import 'package:vibration/vibration.dart';
import 'package:awesome_notifications/awesome_notifications.dart';
import '../globals.dart';
import '../models/user.dart';
import 'mqtt_helper.dart';
final _service = FlutterBackgroundService();
String notifTxt = 'Waiting for notification';
const String approveKey = 'approve';
const String rejectKey = 'reject';
const String approveLabel = 'Approve';
const String rejectLabel = 'Reject';
String _requestVehicleChangeId = '';
ReceivePort processRequestVehicleChangeRecvPort = ReceivePort('processRequestVehicleChangeRecv');
Future<void> initializeService() async{
log('initializeService');
await _service.configure(
androidConfiguration: AndroidConfiguration(
autoStart: true,
onStart: _onServiceStart,
isForegroundMode: true,
),
iosConfiguration: IosConfiguration(
autoStart: true,
onForeground: _onServiceStart,
onBackground: _onServiceIosBackground,
),
);
await initializeLocalNotifications();
await initializeIsolateReceivePort();
startListeningNotificationEvents();
}
@pragma('vm:entry-point')
Future<void> _onServiceStart(ServiceInstance service) async {
DartPluginRegistrant.ensureInitialized();
log('service started');
if (service is AndroidServiceInstance) {
service.on('setAsForeground').listen((ev) {
service.setAsForegroundService();
});
service.on('setAsBackground').listen((ev) {
service.setAsBackgroundService();
});
}
service.on('stopService').listen((ev) {
service.stopSelf();
});
MqttHelper().connect().then((val) async {
var user = User.fromJson( jsonDecode(await SharedPrefHelper().getPrefWithKey( Globals.USER_PREF_KEY )) );
MqttHelper().send('hi from the app', user.mqttClientId);
MqttHelper().subscribe(user.mqttClientId);
});
Timer(const Duration(milliseconds: 1000), () {
MqttHelper().getClient().updates!.listen((List<MqttReceivedMessage<MqttMessage?>>? c) async {
final recMessage = c![0].payload as MqttPublishMessage;
final payload = MqttPublishPayload.bytesToStringAsString(recMessage.payload.message);
var payloadArr = payload.split(':');
log('payloadArr: $payloadArr');
notifTxt = payloadArr[0];
_requestVehicleChangeId = payloadArr[1];
// _requestVehicleChangeId surely has value here
showNotification('BARACO Notification', notifTxt);
Vibration.vibrate(pattern: [0,
550, 100,
550, 100,
550, 100,
550, 100,
200, 50,
200, 50,
200, 50,
200, 190, 700]);
});
});
}
@pragma('vm:entry-point')
Future<bool> _onServiceIosBackground(ServiceInstance service) async{
WidgetsFlutterBinding.ensureInitialized();
DartPluginRegistrant.ensureInitialized();
log('onServiceIosBackground started');
return false;
}
Future<void> initializeLocalNotifications() async {
await AwesomeNotifications().initialize(
null,
[
NotificationChannel(
channelKey: 'alerts',
channelName: 'Alerts',
channelDescription: 'Notification tests as alerts',
playSound: true,
onlyAlertOnce: true,
importance: NotificationImportance.High,
defaultPrivacy: NotificationPrivacy.Private,
defaultColor: Colors.deepPurple,
ledColor: Colors.deepPurple
)
],
debug: true
);
}
ReceivePort? receivePort;
Future<void> initializeIsolateReceivePort() async {
receivePort = ReceivePort('Notification action port in main isolate')
..listen(
(silentData) {
onActionReceived(silentData);
}
);
IsolateNameServer.registerPortWithName(
receivePort!.sendPort, 'notification_action_port');
log('initializeIsolateReceivePort');
}
Future<void> startListeningNotificationEvents() async {
AwesomeNotifications()
.setListeners(onActionReceivedMethod: onActionReceived);
}
@pragma('vm:entry-point')
Future<void> onActionReceived(ReceivedAction receivedAction) async {
// _requestVehicleChangeId has no value now here
// this is where I wanted to do the api calls
}
@pragma('vm:entry-point')
Future<void> showNotification(String title, String body) async {
// _requestVehicleChangeId still has value here
bool isAllowed = await AwesomeNotifications().isNotificationAllowed();
await AwesomeNotifications().createNotification(
content: NotificationContent(
id: -1,
channelKey: 'alerts',
title: title,
body: body,
bigPicture: '',
largeIcon: '',
notificationLayout: NotificationLayout.BigPicture,
payload: {'notificationId': '1234567890'}),
actionButtons: [
NotificationActionButton(
key: rejectKey,
label: rejectLabel,
actionType: ActionType.SilentAction,
isDangerousOption: true),
NotificationActionButton(
key: approveKey,
label: approveLabel,
actionType: ActionType.SilentAction)
]
);
}
更新:
我刚刚意识到
AwesomeNotification
有一个名为 content
的有效负载字段,其中有一个名为 payload
的字段,它似乎接受 Map
但即使在他们自己的回调中,你似乎也无法访问它。这些例子用一些东西填充了payload
,但没有被使用。多么奇怪啊。
经过一番探索,我发现传递给
ReceivedAction
的 onActionReceivedMethod
实际上包含 NotificationContent
作为 Map
,解决了我的问题。