2

PluginUtilities is documented as "Functionality for Flutter plugin authors.". It's quite hard to understand what it does. When/ how should I use it?

Ben Butterworth
  • 22,056
  • 10
  • 114
  • 167

1 Answers1

4

PluginUtilities does two things:

You can pass these references between completely different isolates running different code. For example, you could implement a method in Isolate A, get a handle for it, pass the handle to Isolate B, get the method from that handle using PluginUtilities.getCallbackHandle, and call that method in Isolate B.

final handle = PluginUtilities.getCallbackHandle(myLovelyFunctionTearOff); // What is a tear off?: https://stackoverflow.com/questions/69065771/what-is-an-instance-method-tear-off
if (handle == null) {
  // function has to be a static method or a top level function. It is null otherwise.
  // TODO Show an error to the user to help them fix it.
}

Once you receive the handle in a separate isolate, you can get the function once again:

final function = PluginUtilities.getCallbackFromHandle(handle);
final result = function();

Examples of usage

Firebase messaging uses it twice, specifically for background messages. They use it for 2 functions:

  • They get a handle to the users callback function, that the user set.
    • final CallbackHandle userHandle = PluginUtilities.getCallbackHandle(handler)!;
  • They get a handle to their additional app entrypoint (main function, which they call _firebaseMessagingCallbackDispatcher ):
    • final CallbackHandle bgHandle = PluginUtilities.getCallbackHandle(_firebaseMessagingCallbackDispatcher)!;

They save these handles into SharedPreferences, and use them when the app is launched by a push notification. This is because the Flutter application doesn't automatically get launched in this case, on Android. The service or broadcast receiver is launched without an Activity, which launches the FlutterEngine and your app.

When this happens, Firebase_messaging will use these handles to get the callback function and app entrypoint, and launch them. So your callback still gets called when the your app is not running, because it runs a new application/ entrypoint (_firebaseMessagingCallbackDispatcher):

void _firebaseMessagingCallbackDispatcher() {
  // Initialize state necessary for MethodChannels.
  WidgetsFlutterBinding.ensureInitialized();

  const MethodChannel _channel = MethodChannel(
    'plugins.flutter.io/firebase_messaging_background',
  );

  // This is where we handle background events from the native portion of the plugin.
  _channel.setMethodCallHandler((MethodCall call) async {
     /** implementation of method call handling **/
  });

  // Once we've finished initializing, let the native portion of the plugin
  // know that it can start scheduling alarms.
  _channel.invokeMethod<void>('MessagingBackground#initialized');
Ben Butterworth
  • 22,056
  • 10
  • 114
  • 167