NativeCallable<T extends Function>.listener constructor

NativeCallable<T extends Function>.listener(
  1. @DartRepresentationOf("T") Function callback
)

Constructs a NativeCallable that can be invoked from any thread.

When the native code invokes the function nativeFunction, the arguments will be sent over a SendPort to the Isolate that created the NativeCallable, and the callback will be invoked.

The native code does not wait for a response from the callback, so only functions returning void are supported.

The callback will be invoked at some time in the future. The native caller cannot assume the callback will be run immediately. Resources passed to the callback (such as pointers to malloc'd memory, or output parameters) must be valid until the call completes.

This callback must be closed when it is no longer needed. The Isolate that created the callback will be kept alive until close is called. After NativeCallable.close is called, invoking the nativeFunction from native code will cause undefined behavior.

For example:

import 'dart:async';
import 'dart:ffi';
import 'package:ffi/ffi.dart';

// Processes a simple HTTP GET request using a native HTTP library that
// processes the request on a background thread.
Future<String> httpGet(String uri) async {
  final uriPointer = uri.toNativeUtf8();

  // Create the NativeCallable.listener.
  final completer = Completer<String>();
  late final NativeCallable<NativeHttpCallback> callback;
  void onResponse(Pointer<Utf8> responsePointer) {
    completer.complete(responsePointer.toDartString());
    calloc.free(responsePointer);
    calloc.free(uriPointer);

    // Remember to close the NativeCallable once the native API is
    // finished with it, otherwise this isolate will stay alive
    // indefinitely.
    callback.close();
  }
  callback = NativeCallable<NativeHttpCallback>.listener(onResponse);

  // Invoke the native HTTP API. Our example HTTP library processes our
  // request on a background thread, and calls the callback on that same
  // thread when it receives the response.
  nativeHttpGet(uriPointer, callback.nativeFunction);

  return completer.future;
}

// Load the native functions from a DynamicLibrary.
final DynamicLibrary dylib = DynamicLibrary.process();
typedef NativeHttpCallback = Void Function(Pointer<Utf8>);

typedef HttpGetFunction = void Function(
    Pointer<Utf8>, Pointer<NativeFunction<NativeHttpCallback>>);
typedef HttpGetNativeFunction = Void Function(
    Pointer<Utf8>, Pointer<NativeFunction<NativeHttpCallback>>);
final nativeHttpGet =
    dylib.lookupFunction<HttpGetNativeFunction, HttpGetFunction>(
        'http_get');

Implementation

factory NativeCallable.listener(
    @DartRepresentationOf("T") Function callback) {
  throw UnsupportedError("NativeCallable cannot be constructed dynamically.");
}