fluttercommunity / flutter_workmanager

A Flutter plugin which allows you to execute code in the background on Android and iOS.
826 stars 247 forks source link

🐞Unable to use custom native plugin inside work manager callback. #493

Closed BobFactory closed 11 months ago

BobFactory commented 11 months ago

Describe the error

I have a native logic that handles notifications in the Android platform and I wish to use this implementation with Workmanager, but whenever the execution runs I only get this error: Error: MissingPluginException MissingPluginException(No implementation found for method sendNotification on channel flutter_notification_channel)

I am unaware of how I can register my native plugin with Workmanager. I see that it starts a new Flutter Engine, but that does not register my Native implementation. My native implementation is correct as I have tested that out independently. I am unaware as to how this can work in the new Android v2 bindings.

Code sample

NotficiationPlugin.kt

class NotificationPlugin: FlutterPlugin, MethodChannel.MethodCallHandler {
    private val CHANNEL_NAME = "flutter_notification_channel"

    private var channel: MethodChannel? = null
    private var notificationService: NotificationService? = null

    override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
        setupChannel(binding.binaryMessenger, binding.applicationContext)
    }

    override fun onDetachedFromEngine(p0: FlutterPlugin.FlutterPluginBinding) {
        teardownChannel();
    }

    private fun setupChannel(messenger: BinaryMessenger, context: Context) {
        channel = MethodChannel(messenger, CHANNEL_NAME)
        channel?.setMethodCallHandler(this)
        notificationService = NotificationService(context)
    }

    private fun teardownChannel() {
        channel?.setMethodCallHandler(null)
        channel = null
        notificationService = null
    }

    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
        val hashMap = call.arguments as HashMap<*, *>

        when (call.method) {

            "registerChannel" -> {
                val channelId = hashMap["channelId"] as String
                val channelName = hashMap["channelName"] as String
                val channelDescription = hashMap["channelDescription"] as? String ?: ""

                notificationService?.registerChannel(
                    channelId,
                    channelName,
                    channelDescription
                )

                result.success(null)
            }

            "areNotificationsEnabled" -> {
                result.success(notificationService?.isNotificationEnabled)
            }

            "sendNotification" -> {
                val channelId = hashMap["channelId"] as String
                val title = hashMap["title"] as String
                val message = hashMap["message"] as String

                val id = notificationService?.notify(title, message, channelId)
                result.success(id)
            }

            else -> result.notImplemented()

        }
    }

}

MainActivity.kt

class MainActivity : FlutterActivity() {

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        flutterEngine.plugins.add(NotificationPlugin())

    }
}

WorkManager.dart


@pragma('vm:entry-point')
void callbackDispatcher() {
  Workmanager().executeTask((task, inputData) async {
    try {
      var channel = MethodChannel('flutter_notification_channel');

      final args = {
            "channelId": "habit_board_daily_reminder_channel",
            "title": "Helloo",
            "message": "I am a test",
          };

      await channel.invokeMethod("sendNotification", args);
    } catch (e) {
      e.printError();
    }

    return Future.value(true);
  });
}

class WorkManagerService {
  WorkManagerService();

  final _manager = Workmanager();

  Future scheduleReminderChecker() async {
    await _manager.initialize(callbackDispatcher, isInDebugMode: true);

    _manager.registerPeriodicTask(
      "reminder-task",
      "reminder-task",
      existingWorkPolicy: ExistingWorkPolicy.keep,
      frequency: Duration(minutes: 15),
    );
  }

  cancelAll() {
    _manager.cancelAll();
  }
}

main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  DartPluginRegistrant.ensureInitialized();
  ///...Also includes some logic to register the notification channel here. 
  await WorkManagerService().scheduleReminderChecker();

  SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
    statusBarIconBrightness: Brightness.light,
    statusBarBrightness: Brightness.dark,
  ));

runApp(
    Container(
      child: MaterialApp(
        theme: appTheme,
        debugShowCheckedModeBanner: false,
         initialRoute: Routes.HOME,
        defaultTransition: Transition.fade,
      ),
    ),
  );

Version