diff --git a/example/lib/main.dart b/example/lib/main.dart index c7763e1..0693654 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,3 +1,4 @@ +// ignore_for_file: avoid_print import 'dart:io'; import 'dart:typed_data'; import 'package:flutter/material.dart'; @@ -10,13 +11,14 @@ import 'package:permission_handler/permission_handler.dart'; Future serviceHandleData(Map? data) async { print('[BG] Received data $data'); GetIt.I.get().send( - TestEvent(), - id: data!['id']! as String, - ); + TestEvent(), + id: data!['id']! as String, + ); } @pragma('vm:entry-point') Future serviceEntrypoint(String initialLocale) async { + // avoid_print print('Initial locale: $initialLocale'); } @@ -34,15 +36,15 @@ class MyApp extends StatefulWidget { class TestCommand extends BackgroundCommand { @override Map toJson() => { - 'request': 'return_name', - }; + 'request': 'return_name', + }; } class TestEvent extends BackgroundEvent { @override Map toJson() => { - 'name': 'Moxxy', - }; + 'name': 'Moxxy', + }; } class MyAppState extends State { @@ -61,7 +63,6 @@ class MyAppState extends State { onPressed: () async { final result = await MoxxyPickerApi() .pickFiles(FilePickerType.image, false); - // ignore: avoid_print print('User picked: $result'); }, child: const Text('Photo picker'), @@ -70,7 +71,6 @@ class MyAppState extends State { onPressed: () async { final result = await MoxxyPickerApi() .pickFiles(FilePickerType.imageAndVideo, true); - // ignore: avoid_print print('User picked: $result'); }, child: const Text('Photo/Video multi-picker'), @@ -79,7 +79,6 @@ class MyAppState extends State { onPressed: () async { final result = await MoxxyPickerApi() .pickFiles(FilePickerType.generic, true); - // ignore: avoid_print print('User picked: $result'); }, child: const Text('Generic multi-picker'), @@ -101,7 +100,6 @@ class MyAppState extends State { 'SHA-256', ); if (encResult == null) { - // ignore: avoid_print print('Failed to encrypt file'); return; } @@ -115,7 +113,6 @@ class MyAppState extends State { 'SHA-256', ); if (decResult == null) { - // ignore: avoid_print print('Failed to decrypt file'); return; } @@ -146,7 +143,7 @@ class MyAppState extends State { await Permission.notification.request(); - final srv = ForegroundService(); + final srv = getForegroundService(); await srv.start( const ServiceConfig( serviceEntrypoint, @@ -159,7 +156,7 @@ class MyAppState extends State { ); await Future.delayed(const Duration(milliseconds: 600)); - await srv.dataSender.sendData( + await getForegroundService().send( TestCommand(), awaitable: false, ); diff --git a/example/pubspec.lock b/example/pubspec.lock index 110eadd..65b07c2 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -108,7 +108,7 @@ packages: source: hosted version: "2.0.1" logging: - dependency: transitive + dependency: "direct main" description: name: logging sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 14fdde1..f19c40f 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -30,6 +30,7 @@ dependencies: cupertino_icons: ^1.0.2 permission_handler: ^10.4.5 get_it: ^7.6.0 + logging: ^1.2.0 dev_dependencies: flutter_test: diff --git a/lib/moxxy_native.dart b/lib/moxxy_native.dart index afd3c9e..8970b6b 100644 --- a/lib/moxxy_native.dart +++ b/lib/moxxy_native.dart @@ -6,4 +6,7 @@ export 'pigeon/notifications.g.dart'; export 'pigeon/picker.g.dart'; export 'pigeon/platform.g.dart'; export 'pigeon/service.g.dart'; -export 'src/service.dart'; +export 'src/service/background/base.dart'; +export 'src/service/config.dart'; +export 'src/service/datasender/types.dart'; +export 'src/service/foreground/base.dart'; diff --git a/lib/pigeon/background_service.g.dart b/lib/pigeon/background_service.g.dart index 37a0868..9aac2ee 100644 --- a/lib/pigeon/background_service.g.dart +++ b/lib/pigeon/background_service.g.dart @@ -20,10 +20,10 @@ class MoxxyBackgroundServiceApi { Future getHandler() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.getHandler', codec, + 'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.getHandler', + codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; + final List? replyList = await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -47,10 +47,10 @@ class MoxxyBackgroundServiceApi { Future getExtraData() async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.getExtraData', codec, + 'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.getExtraData', + codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; + final List? replyList = await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -74,7 +74,8 @@ class MoxxyBackgroundServiceApi { Future setNotificationBody(String arg_body) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.setNotificationBody', codec, + 'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.setNotificationBody', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_body]) as List?; @@ -96,7 +97,8 @@ class MoxxyBackgroundServiceApi { Future sendData(String arg_data) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.sendData', codec, + 'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.sendData', + codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_data]) as List?; @@ -120,8 +122,7 @@ class MoxxyBackgroundServiceApi { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.stop', codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; + final List? replyList = await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', diff --git a/lib/pigeon/service.g.dart b/lib/pigeon/service.g.dart index caaf54a..a7db05a 100644 --- a/lib/pigeon/service.g.dart +++ b/lib/pigeon/service.g.dart @@ -22,8 +22,8 @@ class MoxxyServiceApi { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.moxxy_native.MoxxyServiceApi.configure', codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_handle, arg_extraData]) as List?; + final List? replyList = await channel + .send([arg_handle, arg_extraData]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -44,8 +44,7 @@ class MoxxyServiceApi { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.moxxy_native.MoxxyServiceApi.isRunning', codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; + final List? replyList = await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -71,8 +70,7 @@ class MoxxyServiceApi { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.moxxy_native.MoxxyServiceApi.start', codec, binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; + final List? replyList = await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', diff --git a/lib/src/service.dart b/lib/src/service.dart deleted file mode 100644 index 668fd71..0000000 --- a/lib/src/service.dart +++ /dev/null @@ -1,168 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'dart:ui'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/services.dart'; -import 'package:logging/logging.dart'; -import 'package:moxlib/moxlib.dart'; -import 'package:moxxy_native/moxxy_native.dart'; -import 'package:moxxy_native/src/service_android.dart'; -import 'package:uuid/uuid.dart'; - -typedef EntrypointCallback = Future Function(String initialLocale); -typedef HandleEventCallback = Future Function(Map? data); - -abstract class BackgroundCommand implements JsonImplementation {} - -abstract class BackgroundEvent implements JsonImplementation {} - -class ServiceConfig { - const ServiceConfig( - this.entrypoint, - this.handleData, - this.initialLocale, - ); - - factory ServiceConfig.fromString(String rawData) { - final data = jsonDecode(rawData) as Map; - return ServiceConfig( - PluginUtilities.getCallbackFromHandle( - CallbackHandle.fromRawHandle( - data['entrypoint']! as int, - ), - )! as EntrypointCallback, - PluginUtilities.getCallbackFromHandle( - CallbackHandle.fromRawHandle( - data['handleData']! as int, - ), - )! as HandleEventCallback, - data['initialLocale']! as String, - ); - } - - final String initialLocale; - final EntrypointCallback entrypoint; - final HandleEventCallback handleData; - - @override - String toString() { - return jsonEncode({ - 'entrypoint': PluginUtilities.getCallbackHandle(entrypoint)!.toRawHandle(), - 'handleData': PluginUtilities.getCallbackHandle(handleData)!.toRawHandle(), - 'initialLocale': initialLocale, - }); - } -} - -/// Wrapper API that is only available to the background service. -class BackgroundService { - final MoxxyBackgroundServiceApi _api = MoxxyBackgroundServiceApi(); - - /// A method channel for Foreground -> Service communication - // TODO(Unknown): Move this into a constant for reuse - final MethodChannel _channel = MethodChannel('org.moxxy.moxxy_native/background'); - - /// A logger. - final Logger _log = Logger('BackgroundService'); - - Future send(BackgroundEvent event, {String? id}) async { - final data = DataWrapper( - id ?? const Uuid().v4(), - event, - ); - - await _api.sendData(jsonEncode(data.toJson())); - } - - void init( - ServiceConfig config, - ) { - // Ensure that the Dart executor is ready to use plugins - WidgetsFlutterBinding.ensureInitialized(); - DartPluginRegistrant.ensureInitialized(); - - // Register the channel for Foreground -> Service communication - _channel.setMethodCallHandler((call) async { - // TODO(Unknown): Maybe do something smarter like pigeon and use Lists instead of Maps - final args = call.arguments! as String; - await config.handleData(jsonDecode(args) as Map); - }); - - // Start execution - _log.finest('Setup complete. Calling main entrypoint...'); - config.entrypoint(config.initialLocale); - } - - void setNotificationBody(String body) { - _api.setNotificationBody(body); - } -} - -class ForegroundServiceDataSender extends AwaitableDataSender { - ForegroundServiceDataSender(this._api); - final MoxxyServiceApi _api; - - @override - Future sendDataImpl(DataWrapper data) { - return _api.sendData(jsonEncode(data.toJson())); - } -} - -/// Wrapper API that is only available to the UI isolate. -// TODO(Unknown): Dumb naming. Name it something better -class ForegroundService { - ForegroundService() { - dataSender = ForegroundServiceDataSender(_api); - } - - final MoxxyServiceApi _api = MoxxyServiceApi(); - - /// A method channel for background service -> UI isolate communication. - final MethodChannel _channel = MethodChannel('org.moxxy.moxxy_native/foreground'); - - late final ForegroundServiceDataSender dataSender; - - /// A logger. - final Logger _log = Logger('ForegroundService'); - - Future attach( - HandleEventCallback handleData, - ) async { - _channel.setMethodCallHandler((call) async { - await handleData( - jsonDecode(call.arguments! as String) as Map, - ); - }); - } - - Future start( - ServiceConfig config, HandleEventCallback uiHandleData, - ) async { - int platformEntrypointHandle; - if (Platform.isAndroid) { - platformEntrypointHandle = PluginUtilities.getCallbackHandle( - androidEntrypoint, - )!.toRawHandle(); - } else { - // TODO: Custom exception - throw Exception('Unsupported platform'); - } - - // Configure the service on the native side - await _api.configure(platformEntrypointHandle, config.toString()); - - // Prepare the method channel - await attach(uiHandleData); - - // Start the service - await _api.start(); - _log.finest('Background service started...'); - } - - /// Returns true if the background service is already running. False, if not. - Future isRunning() async { - WidgetsFlutterBinding.ensureInitialized(); - return _api.isRunning(); - } -} diff --git a/lib/src/service/background/base.dart b/lib/src/service/background/base.dart new file mode 100644 index 0000000..c06e37f --- /dev/null +++ b/lib/src/service/background/base.dart @@ -0,0 +1,16 @@ +import 'package:moxxy_native/src/service/config.dart'; +import 'package:moxxy_native/src/service/datasender/types.dart'; + +/// Wrapper API that is only available to the background service. +abstract class BackgroundService { + /// Send [event] with optional id [id] to the foreground. + Future send(BackgroundEvent event, {String? id}); + + /// Platform specific initialization routine that is called after + /// the entrypoint has been called. + Future init(ServiceConfig config); + + /// Update the notification body, if the platform shows a persistent + /// notification. + void setNotificationBody(String body); +} diff --git a/lib/src/service/background/pigeon.dart b/lib/src/service/background/pigeon.dart new file mode 100644 index 0000000..47ec9db --- /dev/null +++ b/lib/src/service/background/pigeon.dart @@ -0,0 +1,58 @@ +import 'dart:convert'; +import 'dart:ui'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:logging/logging.dart'; +import 'package:moxlib/moxlib.dart'; +import 'package:moxxy_native/pigeon/background_service.g.dart'; +import 'package:moxxy_native/src/service/background/base.dart'; +import 'package:moxxy_native/src/service/config.dart'; +import 'package:moxxy_native/src/service/datasender/types.dart'; +import 'package:uuid/uuid.dart'; + +class PigeonBackgroundService extends BackgroundService { + final MoxxyBackgroundServiceApi _api = MoxxyBackgroundServiceApi(); + + /// A method channel for Foreground -> Service communication + // TODO(Unknown): Move this into a constant for reuse + final MethodChannel _channel = + const MethodChannel('org.moxxy.moxxy_native/background'); + + /// A logger. + final Logger _log = Logger('PigeonBackgroundService'); + + @override + Future send(BackgroundEvent event, {String? id}) async { + final data = DataWrapper( + id ?? const Uuid().v4(), + event, + ); + + await _api.sendData(jsonEncode(data.toJson())); + } + + @override + Future init( + ServiceConfig config, + ) async { + // Ensure that the Dart executor is ready to use plugins + WidgetsFlutterBinding.ensureInitialized(); + DartPluginRegistrant.ensureInitialized(); + + // Register the channel for Foreground -> Service communication + _channel.setMethodCallHandler((call) async { + // TODO(Unknown): Maybe do something smarter like pigeon and use Lists instead of Maps + final args = call.arguments! as String; + await config.handleData(jsonDecode(args) as Map); + }); + + // Start execution + _log.finest('Setup complete. Calling main entrypoint...'); + await config.entrypoint(config.initialLocale); + } + + @override + void setNotificationBody(String body) { + _api.setNotificationBody(body); + } +} diff --git a/lib/src/service/config.dart b/lib/src/service/config.dart new file mode 100644 index 0000000..53be299 --- /dev/null +++ b/lib/src/service/config.dart @@ -0,0 +1,55 @@ +import 'dart:convert'; +import 'dart:ui'; + +/// A function that can act as a service entrypoint. +typedef EntrypointCallback = Future Function(String initialLocale); + +/// A function that can be called when data is received. +typedef HandleEventCallback = Future Function(Map? data); + +/// Configuration that will be passed to the service's entrypoint +class ServiceConfig { + const ServiceConfig( + this.entrypoint, + this.handleData, + this.initialLocale, + ); + + /// Reconstruct the configuration from a JSON string. + factory ServiceConfig.fromString(String rawData) { + final data = jsonDecode(rawData) as Map; + return ServiceConfig( + PluginUtilities.getCallbackFromHandle( + CallbackHandle.fromRawHandle( + data['entrypoint']! as int, + ), + )! as EntrypointCallback, + PluginUtilities.getCallbackFromHandle( + CallbackHandle.fromRawHandle( + data['handleData']! as int, + ), + )! as HandleEventCallback, + data['initialLocale']! as String, + ); + } + + /// The initial locale to use. + final String initialLocale; + + /// The entrypoint to call into. + final EntrypointCallback entrypoint; + + /// Entry function to call when the service receives data. + final HandleEventCallback handleData; + + @override + String toString() { + return jsonEncode({ + 'entrypoint': + PluginUtilities.getCallbackHandle(entrypoint)!.toRawHandle(), + 'handleData': + PluginUtilities.getCallbackHandle(handleData)!.toRawHandle(), + 'initialLocale': initialLocale, + }); + } +} diff --git a/lib/src/service/datasender/pigeon.dart b/lib/src/service/datasender/pigeon.dart new file mode 100644 index 0000000..d0d6dc3 --- /dev/null +++ b/lib/src/service/datasender/pigeon.dart @@ -0,0 +1,15 @@ +import 'dart:convert'; +import 'package:moxlib/moxlib.dart'; +import 'package:moxxy_native/pigeon/service.g.dart'; +import 'package:moxxy_native/src/service/datasender/types.dart'; + +class PigeonForegroundServiceDataSender + extends AwaitableDataSender { + PigeonForegroundServiceDataSender(this._api); + final MoxxyServiceApi _api; + + @override + Future sendDataImpl(DataWrapper data) { + return _api.sendData(jsonEncode(data.toJson())); + } +} diff --git a/lib/src/service/datasender/types.dart b/lib/src/service/datasender/types.dart new file mode 100644 index 0000000..4a93cb6 --- /dev/null +++ b/lib/src/service/datasender/types.dart @@ -0,0 +1,20 @@ +import 'dart:io'; +import 'package:moxlib/moxlib.dart'; +import 'package:moxxy_native/pigeon/service.g.dart'; +import 'package:moxxy_native/src/service/datasender/pigeon.dart'; +import 'package:moxxy_native/src/service/exceptions.dart'; + +typedef ForegroundServiceDataSender + = AwaitableDataSender; + +abstract class BackgroundCommand implements JsonImplementation {} + +abstract class BackgroundEvent implements JsonImplementation {} + +ForegroundServiceDataSender getForegroundDataSender(MoxxyServiceApi api) { + if (Platform.isAndroid) { + return PigeonForegroundServiceDataSender(api); + } else { + throw UnsupportedPlatformException(); + } +} diff --git a/lib/src/service_android.dart b/lib/src/service/entrypoints/pigeon.dart similarity index 53% rename from lib/src/service_android.dart rename to lib/src/service/entrypoints/pigeon.dart index 231455a..da27b1b 100644 --- a/lib/src/service_android.dart +++ b/lib/src/service/entrypoints/pigeon.dart @@ -1,10 +1,14 @@ import 'package:flutter/cupertino.dart'; import 'package:get_it/get_it.dart'; import 'package:moxxy_native/pigeon/background_service.g.dart'; -import 'package:moxxy_native/src/service.dart'; +import 'package:moxxy_native/src/service/background/base.dart'; +import 'package:moxxy_native/src/service/background/pigeon.dart'; +import 'package:moxxy_native/src/service/config.dart'; +/// An entrypoint that should be used when the service runs +/// in a new Flutter Engine. @pragma('vm:entry-point') -Future androidEntrypoint() async { +Future pigeonEntrypoint() async { // ignore: avoid_print print('androidEntrypoint: Called on new FlutterEngine'); @@ -15,7 +19,7 @@ Future androidEntrypoint() async { ); // Setup the background service - final srv = BackgroundService(); - GetIt.I.registerSingleton(srv); - srv.init(config); + final srv = PigeonBackgroundService(); + GetIt.I.registerSingleton(srv); + await srv.init(config); } diff --git a/lib/src/service/exceptions.dart b/lib/src/service/exceptions.dart new file mode 100644 index 0000000..11ea639 --- /dev/null +++ b/lib/src/service/exceptions.dart @@ -0,0 +1,8 @@ +import 'dart:io'; + +/// An exception representing that moxxy_native does not support the given platform. +class UnsupportedPlatformException implements Exception { + UnsupportedPlatformException(); + + String get message => 'Unsupported platform "${Platform.operatingSystem}"'; +} diff --git a/lib/src/service/foreground/base.dart b/lib/src/service/foreground/base.dart new file mode 100644 index 0000000..0530800 --- /dev/null +++ b/lib/src/service/foreground/base.dart @@ -0,0 +1,49 @@ +import 'dart:io'; +import 'package:moxlib/moxlib.dart'; +import 'package:moxxy_native/src/service/config.dart'; +import 'package:moxxy_native/src/service/datasender/types.dart'; +import 'package:moxxy_native/src/service/exceptions.dart'; +import 'package:moxxy_native/src/service/foreground/pigeon.dart'; + +/// Wrapper API that is only available to the UI isolate. +// TODO(Unknown): Dumb naming. Name it something better +abstract class ForegroundService { + /// Perform setup such that we [handleData] is called whenever the background service + /// sends data to the foreground. + Future attach(HandleEventCallback handleData); + + /// Start the background service with the config [config]. Additionally, perform + /// setup such that [uiHandleData] is called whenever the background service sends + /// data to the foreground. + Future start(ServiceConfig config, HandleEventCallback uiHandleData); + + /// Return true if the background service is running. False, if not. + Future isRunning(); + + /// Return the [AwaitableDataSender] that is used to send data to the background service. + ForegroundServiceDataSender getDataSender(); + + /// Convenience wrapper around getDataSender().sendData. The arguments are the same + /// as for [AwaitableDataSender]. + Future send( + BackgroundCommand command, { + bool awaitable = true, + }); +} + +/// "Singleton" ForegroundService instance to prevent having to type "GetIt.I.get()" +ForegroundService? _service; + +/// Either returns or creates a [ForegroundService] object of the correct type for the +/// current platform. +ForegroundService getForegroundService() { + if (_service == null) { + if (Platform.isAndroid) { + _service = PigeonForegroundService(); + } else { + throw UnsupportedPlatformException(); + } + } + + return _service!; +} diff --git a/lib/src/service/foreground/pigeon.dart b/lib/src/service/foreground/pigeon.dart new file mode 100644 index 0000000..50755f9 --- /dev/null +++ b/lib/src/service/foreground/pigeon.dart @@ -0,0 +1,82 @@ +import 'dart:convert'; +import 'dart:ui'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:logging/logging.dart'; +import 'package:moxxy_native/pigeon/service.g.dart'; +import 'package:moxxy_native/src/service/config.dart'; +import 'package:moxxy_native/src/service/datasender/pigeon.dart'; +import 'package:moxxy_native/src/service/datasender/types.dart'; +import 'package:moxxy_native/src/service/entrypoints/pigeon.dart'; +import 'package:moxxy_native/src/service/foreground/base.dart'; + +class PigeonForegroundService extends ForegroundService { + PigeonForegroundService() { + _dataSender = PigeonForegroundServiceDataSender(_api); + } + + /// Pigeon channel to the native side. + final MoxxyServiceApi _api = MoxxyServiceApi(); + + /// A method channel for background service -> UI isolate communication. + final MethodChannel _channel = + const MethodChannel('org.moxxy.moxxy_native/foreground'); + + /// The data sender backing this class. + late final PigeonForegroundServiceDataSender _dataSender; + + /// A logger. + final Logger _log = Logger('PigeonForegroundService'); + + @override + Future attach( + HandleEventCallback handleData, + ) async { + _channel.setMethodCallHandler((call) async { + await handleData( + jsonDecode(call.arguments! as String) as Map, + ); + }); + } + + @override + Future start( + ServiceConfig config, + HandleEventCallback uiHandleData, + ) async { + await _api.configure( + PluginUtilities.getCallbackHandle( + pigeonEntrypoint, + )! + .toRawHandle(), + config.toString(), + ); + + // Prepare the method channel + await attach(uiHandleData); + + // Start the service + await _api.start(); + _log.finest('Background service started...'); + } + + @override + Future isRunning() async { + WidgetsFlutterBinding.ensureInitialized(); + return _api.isRunning(); + } + + @override + ForegroundServiceDataSender getDataSender() => _dataSender; + + @override + Future send( + BackgroundCommand command, { + bool awaitable = true, + }) { + return _dataSender.sendData( + command, + awaitable: awaitable, + ); + } +} diff --git a/pigeon/background_service.dart b/pigeon/background_service.dart index b13efaf..244889a 100644 --- a/pigeon/background_service.dart +++ b/pigeon/background_service.dart @@ -10,7 +10,6 @@ import 'package:pigeon/pigeon.dart'; ), ), ) - @HostApi() abstract class MoxxyBackgroundServiceApi { int getHandler(); diff --git a/pigeon/service.dart b/pigeon/service.dart index 1e7b933..1dc83cf 100644 --- a/pigeon/service.dart +++ b/pigeon/service.dart @@ -10,7 +10,6 @@ import 'package:pigeon/pigeon.dart'; ), ), ) - @HostApi() abstract class MoxxyServiceApi { void configure(int handle, String extraData);