Flutter iOS后台Workmanager+MQTT接收通知失败问题求助
Flutter iOS后台MQTT通信异常问题
问题现象
1. 后台获取(Background Fetch)调试失败
使用Flutter结合mqtt_client和workmanager包,期望实现APP在后台状态、设备熄屏时仍能通过MQTT接收通知,但Xcode调试后台获取时出现以下日志,无法正常监听MQTT:
iOS background fetch 022-09-21 14:41:49.499500+0900 Runner[13669:4008622] [workmanager.BackgroundWorker] performBackgroundRequest(_:) -> performBackgroundRequest.failed (finished in 0.04 seconds)
若将Workmanager().executeTask中的initMQTT替换为localNotification,则任务可正常执行。
2. 首次启动APP时Workmanager抛出异常
首次启动时出现任务调度失败异常:
[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(bgTaskSchedulingFailed(Error Domain=BGTaskSchedulerErrorDomain Code=1 "(null)") error, Scheduling the task using BGTaskScheduler has failed. This may be due to too many tasks being scheduled but not run. See the error for details: Error Domain=BGTaskSchedulerErrorDomain Code=1 "(null)". null, null) #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:653:7) #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:296:18) <asynchronous suspension> #2 Workmanager.registerOneOffTask (package:workmanager/src/workmanager.dart:187:7) <asynchronous suspension>
相关代码
main.dart
final MqttServerClient client = MqttServerClient(Env.WEBSOCKET_URL, ''); @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) { switch (task) { case Workmanager.iOSBackgroundTask: stderr.writeln("iOS background fetch"); initMQTT(client); break; } stderr.writeln("iOS background complete"); bool success = true; return Future.value(success); }); } void initWorkManager(MqttServerClient client) async { Workmanager().initialize(callbackDispatcher, isInDebugMode: true); Workmanager().registerOneOffTask( "task-identifier", "task-identifier", // Ignored on iOS initialDelay: const Duration(seconds: 10), constraints: Constraints( networkType: NetworkType.connected, requiresCharging: false, ), // fully supported ); } void main() async { FlutterNativeSplash.preserve( widgetsBinding: WidgetsFlutterBinding.ensureInitialized(), ); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); await dotenv.load(fileName: Env.fileName); await EasyLocalization.ensureInitialized(); await Hive.initFlutter(); Hive.registerAdapter<NoticeItemModel>(NoticeItemModelAdapter()); await Hive.openBox<int>(HiveBoxConstant.NOTICE_UPDATE_TIME); await Hive.openBox<NoticeItemModel>(HiveBoxConstant.NOTICE_ITEM); await Hive.openBox<DateTime>(HiveBoxConstant.EVENT_BANNER_HIDE_TIME); initMQTT(client); Workmanager().initialize(callbackDispatcher, isInDebugMode: true); Workmanager().registerOneOffTask("task-identifier", "simpleTask"); MobileAds.instance.initialize(); runApp( ProviderScope( child: EasyLocalization( supportedLocales: const [Locale('en'), Locale('ko')], path: 'assets/translations', fallbackLocale: const Locale('en'), child: const AppMain(), ), ), ); }
mqtt_init.dart
Future<void> initMQTT(MqttServerClient client) async { print('mqtt init'); client.useWebSocket = true; client.port = 9001; client.logging(on: kDebugMode ? true : false); client.setProtocolV311(); client.keepAlivePeriod = 60 * 15; client.connectTimeoutPeriod = 5000; client.autoReconnect = true; String id = ''; DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); if (Platform.isAndroid) { final AndroidDeviceInfo androidData = await deviceInfo.androidInfo; id = androidData.androidId ?? ''; } else if (Platform.isIOS) { final IosDeviceInfo iosData = await deviceInfo.iosInfo; id = iosData.identifierForVendor ?? ''; } final connMess = MqttConnectMessage() .withClientIdentifier('${id}_${Platform.localeName}') .authenticateAs(Env.WEBSOCKET_ID, Env.WEBSOCKET_PW) .withWillTopic('conntect') .withWillMessage('connect message') .startClean() .withWillQos(MqttQos.atLeastOnce); print('MQTT connecting....'); client.connectionMessage = connMess; try { await client.connect(); } on NoConnectionException catch (e) { print('MQTT exception - $e'); client.disconnect(); } on SocketException catch (e) { print('Socket exception - $e'); client.disconnect(); } if (client.connectionStatus!.state == MqttConnectionState.connected) { print('[MQTT connected]'); } else { print(''' [ERROR MQTT connection failed] disconnecting, status is ${client.connectionStatus} '''); client.disconnect(); exit(-1); } final String userKey = await SecureStorageViewModel.getUserKey(); client.subscribe(Env.WEBSOCKET_TOPIC_NOTI_ANNOUNCE, MqttQos.exactlyOnce); client.subscribe(Env.WEBSOCKET_TOPIC_NOTI_EVENT, MqttQos.exactlyOnce); client.subscribe(Env.WEBSOCKET_TOPIC_NOTI_NOTICE, MqttQos.exactlyOnce); client.subscribe(Env.WEBSOCKET_TOPIC_NOTI_SEASON, MqttQos.exactlyOnce); client.subscribe(Env.WEBSOCKET_TOPIC_NOTI_UPDATE, MqttQos.exactlyOnce); client.subscribe( '${Env.WEBSOCKET_TOPIC_NOTI_WALLET}$userKey', MqttQos.exactlyOnce); mqttListen(client); } void mqttListen(MqttServerClient client) { client.updates!.listen((List<MqttReceivedMessage<MqttMessage?>>? c) async { print('mqtt listen!'); final recMess = c![0].payload as MqttPublishMessage; final topic = c[0].topic; final message = MqttPublishPayload.bytesToStringAsString(recMess.payload.message); final String userKey = await SecureStorageViewModel.getUserKey(); if (topic == Env.WEBSOCKET_TOPIC_NOTI_ANNOUNCE) {} if (topic == Env.WEBSOCKET_TOPIC_NOTI_EVENT) {} if (topic == Env.WEBSOCKET_TOPIC_NOTI_NOTICE) {} if (topic == Env.WEBSOCKET_TOPIC_NOTI_SEASON) {} if (topic == Env.WEBSOCKET_TOPIC_NOTI_UPDATE) {} if (topic == '${Env.WEBSOCKET_TOPIC_NOTI_WALLET}$userKey') {} LocalNotification.addNotification( type: NotificationConstants.notice, remainingSeconds: 5, ); }); }
环境信息
[✓] Flutter (Channel stable, 3.3.2, on macOS 12.6 21G115 darwin-x64, locale ko-KR) • Flutter version 3.3.2 on channel stable at /Users/leedonghee/Documents/libraries.nosync/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision e3c29ec00c (7일 전), 2022-09-14 08:46:55 -0500 • Engine revision a4ff2c53d8 • Dart version 2.18.1 • DevTools version 2.15.0 [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc3) • Android SDK at /Users/leedonghee/Library/Android/sdk • Platform android-32, build-tools 33.0.0-rc3 • ANDROID_HOME = /Users/leedonghee/Library/Android/sdk • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 14.0) • Xcode at /Applications/Xcode.app/Contents/Developer • Build 14A309 • CocoaPods version 1.11.3 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio (version 2021.3) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866) [✓] VS Code (version 1.71.2) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.48.0 [✓] Connected device (3 available) • iPhone 14 Pro (mobile) • DC0EC2DD-FF96-417C-93A8-2843F8D8BF8E • ios • com.apple.CoreSimulator.SimRuntime.iOS-16-0 (simulator) • macOS (desktop) • macos • darwin-x64 • macOS 12.6 21G115 darwin-x64 • Chrome (web) • chrome • web-javascript • Google Chrome 105.0.5195.125 [✓] HTTP Host Availability • All required HTTP hosts are available • No issues found!
内容的提问来源于stack exchange,提问作者LeeDongHee
相关产品推荐
相关产品推荐

