skip to content

Native Interop

Crossing from Dart into the host platform: channels, Pigeon codegen, dart:ffi, federated plugins, platform views and add-to-app. Interviewers ask because every app meets an API Flutter does not wrap.

part ofFlutteroverview, primer and where to startread it →
on this pageshow

explore

questions

page 1 of 2

In Flutter, what is a MethodChannel for, and how does a Dart call such as reading the battery-saver state reach host code and come back?

level: juniorimportance: must knowfreq 68%

answer

  1. named pipe, same string both sides
  2. invokeMethod returns a Future
  3. StandardMethodCodec by default
  4. host handler replies success, error or notImplemented
  5. FIFO order, asynchronous only

basics

~20 s

A MethodChannel is a named, asynchronous pipe from Dart to host code: invokeMethod encodes a method name and arguments, the Kotlin or Swift handler registered under the same channel name replies, and Dart awaits the result as a Future.

solid answer

~40 s

A `MethodChannel` lets Dart call platform APIs Flutter does not wrap, such as the OS battery-saver flag. Dart creates `const MethodChannel('app/power')` and calls `invokeMethod<bool>('isPowerSaveMode')`; the call is encoded by `StandardMethodCodec` into bytes and sent through the engine's `BinaryMessenger`. On the host, a handler registered under the same channel name reads `call.method`, does the work and answers with `result.success(value)`, `result.error(code, message, details)` or `result.notImplemented()`. Dart receives a `Future<T?>` that completes with the value or throws `PlatformException` / `MissingPluginException`. Everything is asynchronous, calls on a built-in channel arrive in FIFO order, and the channel is not type safe: both sides must agree on names and argument shapes by convention.

code

dart · 13 lines
dart
import 'package:flutter/services.dart';

const _power = MethodChannel('com.example.app/power');

Future<bool> isBatterySaverOn() async {
  try {
    final bool? on = await _power.invokeMethod<bool>('isPowerSaveMode');
    return on ?? false;
  } on PlatformException catch (e) {
    debugPrint('power query failed: ${e.code} ${e.message}');
    return false;
  }
}

go deeper

for a junior

Recall the pieces: a channel name shared by both sides, invokeMethod returning a Future, and a host handler that replies with success, error or notImplemented.

for a middle

Explain the codec step and why the result is nullable and only cast at runtime, and show how a Dart handler set with setMethodCallHandler answers host-initiated calls.

for a senior

Discuss the lack of type safety, FIFO ordering, the unanswered-reply hang and when to replace hand-written channels with generated bindings or an existing plugin.

for a principal

Frame channel design as an API boundary: naming, versioning of method names and argument maps across app releases, and the cost of keeping two hand-synchronised implementations.

## What problem a MethodChannel solves Flutter draws its own UI, but many device facts live only in the host OS: whether **battery saver** (Android's power-save mode, iOS Low Power Mode) is on, sensor readings, vendor SDKs. A **platform channel** is the message pipe between the Dart code in the Flutter engine and the **host** code of the embedding app (Kotlin/Java on Android, Swift/Objective-C on iOS, C++ or C on desktop). `MethodChannel` is the channel shaped like a remote procedure call: Dart names a method, passes arguments and awaits one reply. ## The round trip, step by step 1. Dart creates the channel with a **name**, conventionally reverse-domain: `const MethodChannel('com.example.app/power')`. The name is the whole identity; a channel with the same name elsewhere interferes with it. 2. Dart calls `invokeMethod<bool>('isPowerSaveMode', args)`. The framework wraps this in a `MethodCall`, and the channel's codec (by default `StandardMethodCodec`, built on `StandardMessageCodec`) encodes it to bytes. 3. The bytes go through the `BinaryMessenger` (by default `ServicesBinding.defaultBinaryMessenger`) into the engine and on to the host. 4. On the host, a handler registered on a channel with the **same name and a compatible codec** decodes the call, switches on the method name and replies with one of three outcomes: **success** with a value, **error** with a code, message and details, or **not implemented**. 5. The reply travels back and completes the Dart `Future<T?>`: a value, a thrown `PlatformException`, or a thrown `MissingPluginException`. ```dart import 'package:flutter/services.dart'; const _power = MethodChannel('com.example.app/power'); Future<bool> isBatterySaverOn() async { final bool? on = await _power.invokeMethod<bool>('isPowerSaveMode'); return on ?? false; } ``` ## Properties worth stating in an interview - **Asynchronous only.** `invokeMethod` returns a `Future`; there is no synchronous channel call, so the Dart UI isolate never blocks waiting for the host. - **FIFO.** The framework documents that calls sent on a built-in `MethodChannel` are received by the platform in the order they were sent. - **Not type safe.** The Dart type argument `T` is only a cast at runtime; if the host returns a different type, a `TypeError` is thrown. Typed, generated wrappers are what Pigeon adds on top. - **Nullable result.** The return type is `Future<T?>`: the host may reply `null` as a legitimate value. - **Bidirectional.** Dart can also *receive* calls: `setMethodCallHandler` registers a Dart handler that the host invokes on the same channel. - **Initialisation.** Setting a Dart handler before `WidgetsFlutterBinding.ensureInitialized()` trips an assert, because the default messenger does not exist yet. ## The three channel classes | Class | Shape | Typical use | |---|---|---| | `MethodChannel` | request, one reply | read the battery-saver flag, start a scan | | `EventChannel` | host-to-Dart stream via `receiveBroadcastStream` | step counts, sensor or connectivity updates | | `BasicMessageChannel<T>` | raw messages with a chosen `MessageCodec<T>` (`send` / `setMessageHandler`) | custom protocols, `StringCodec` or `BinaryCodec` payloads | All three are thin layers over the same `BinaryMessenger`, and all use a codec to turn Dart values into bytes. ## When not to hand-write one - If a maintained plugin already wraps the API, depend on it instead of writing a channel. - If there are many methods with structured arguments, generated code gives compile-time checking on both sides. - If the native side is a C library, `dart:ffi` calls it directly without a message hop. A MethodChannel remains the baseline every Flutter developer should be able to read and write: it is how most plugins are built underneath.

  • Can the host call into Dart over the same MethodChannel?
    Yes. Dart registers `setMethodCallHandler` on the channel, and the host calls `invokeMethod` on its own channel object with the same name. The Dart handler returns a `Future`; a returned value becomes a success reply, a thrown `PlatformException` becomes an error reply, and a thrown `MissingPluginException` becomes the empty 'not implemented' reply.
  • What happens if the host handler never calls result?
    The Dart `Future` from `invokeMethod` simply never completes, because the framework completes it only when a reply arrives. Every branch of the host handler, including the fallback for unknown method names, must answer with `success`, `error` or `notImplemented`.
  • Why does invokeMethod<Map<String, int>> fail at runtime?
    The codec always decodes maps as `Map<Object?, Object?>`, and Dart generics are reified, so casting that object to `Map<String, int>` throws a `TypeError`. Use `invokeMapMethod<String, int>`, which calls `Map.cast`, or cast the entries yourself.

A MethodChannel works like a hotel's room-service phone line: you dial a named extension, say what you want, and hang on for one answer (food, an apology, or 'we do not serve that') while the lobby keeps running.

saying these in an interview costs you the question

  • Says invokeMethod blocks the UI until the host replies
  • Thinks the channel name only needs to match on the Dart side
  • Believes the type argument on invokeMethod is checked at compile time against the host
  • Assumes Flutter wraps native views for every platform feature
  • Forgets the host must reply in every branch, including unknown methods
open as a page

With Flutter's permission_handler package, how do you request microphone permission and handle each status the request can return?

level: juniorimportance: must knowfreq 52%

basics

~10 s

Declare RECORD_AUDIO in AndroidManifest.xml and NSMicrophoneUsageDescription in Info.plist, call Permission.microphone.request(), then branch: granted proceeds, denied can be asked again later, permanentlyDenied needs openAppSettings(), restricted cannot be changed.

open as a page

In Flutter, what is the difference between a plain Dart package and a plugin package, and how does pubspec.yaml mark a package as a plugin?

level: juniorimportance: must knowfreq 58%

basics

~20 s

A plain Dart package ships only Dart code. A plugin package also ships host-platform code (Kotlin or Java, Swift or Objective-C, C++, or web Dart) and declares it per platform under flutter: plugin: platforms: in pubspec.yaml, so the Flutter tool registers it at build time.

open as a page

In Flutter, how do PlatformException and MissingPluginException from MethodChannel.invokeMethod differ, and what usually causes each one?

level: middleimportance: must knowfreq 52%

basics

~10 s

PlatformException means a host handler ran and replied with an error (code, message, details). MissingPluginException means the reply was empty: no handler on that channel name, or the handler answered notImplemented.

open as a page

In Flutter, what are the five AppLifecycleState values, and what does each one mean on Android and iOS?

level: middleimportance: must knowfreq 58%

basics

~10 s

AppLifecycleState has resumed (visible, focused), inactive (visible, unfocused), hidden (no view visible), paused (not visible, no frames, mobile only) and detached (engine without a view, also the initial state).

open as a page

In Flutter add-to-app, why pre-warm a FlutterEngine and store it in FlutterEngineCache, and what does that engine keep doing once pre-warmed?

level: seniorimportance: must knowfreq 36%

basics

~20 s

Pre-warming creates a FlutterEngine and runs its Dart entrypoint ahead of time, so the Flutter screen appears almost immediately. The cached engine keeps running Dart and holding memory after its screen closes, until you destroy it.

open as a page

In Dart FFI, who frees native memory when Flutter code allocates with calloc or an Arena and a C library returns its own buffers?

level: seniorimportance: must knowfreq 32%

basics

~20 s

Nobody frees it automatically: memory from calloc or malloc must be freed with the same allocator, an Arena frees everything when using() ends, and buffers the C library allocates must be released with the library's own free function.

open as a page

In Flutter's add-to-app, what is a Flutter module, and how does an existing Android or iOS app show one Flutter screen from it?

level: juniorimportance: should knowfreq 32%

basics

~20 s

A Flutter module is a Flutter project built to be embedded in an existing native app. Android launches it through FlutterActivity (or FlutterFragment), iOS through a FlutterViewController; each runs the module's Dart entrypoint in a FlutterEngine.

open as a page

In Flutter, what does dart:ffi let you do, and when would you call a C library through it instead of a MethodChannel?

level: juniorimportance: should knowfreq 35%

basics

~20 s

dart:ffi calls C-ABI functions and reads or writes native memory directly from Dart, synchronously and without a codec. Use it for a C library such as an image compressor; use a MethodChannel for Kotlin or Swift platform APIs.

open as a page

In Flutter, what problem does the pigeon package solve compared with a hand-written MethodChannel that matches method names as strings?

level: juniorimportance: should knowfreq 30%

basics

~20 s

Pigeon generates both ends of a platform channel from one Dart definition file, so channel names, argument order and types are produced by a tool instead of matched by hand, and a mismatch becomes a compile error instead of a runtime failure.

open as a page

In Flutter, what are platform views such as AndroidView and UiKitView for, and why avoid them when a Flutter widget could do the job?

level: juniorimportance: should knowfreq 42%

basics

~20 s

Platform views embed a real native view, such as a map or a web view, inside the Flutter widget tree. They cost extra composition work every frame and add platform-specific limits, so a pure Flutter widget is preferred whenever one exists.

open as a page

In Flutter add-to-app on Android, when do you embed a FlutterFragment instead of a FlutterActivity, and what must the host activity do for it?

level: middleimportance: should knowfreq 22%

basics

~20 s

Use FlutterFragment when Flutter is only part of a native screen, such as a card or a tab. The host activity must forward OS calls like onPostResume, onNewIntent, back presses, permission results, onUserLeaveHint and onTrimMemory to the fragment.

open as a page

In Flutter, how does an EventChannel stream step counts from host code, and when does the host start and stop producing events?

level: middleimportance: should knowfreq 38%

basics

~20 s

Dart calls receiveBroadcastStream on an EventChannel; the first listener sends a 'listen' call that runs the host StreamHandler's onListen with an EventSink, and cancelling the last listener sends 'cancel', which runs onCancel to unregister the sensor.

open as a page

In Flutter's StandardMessageCodec, which Dart values can cross a platform channel, and how do ints, maps and typed lists arrive on Android and iOS?

level: middleimportance: should knowfreq 45%

basics

~20 s

StandardMessageCodec carries null, bool, int, double, String, Uint8List, Int32List, Int64List, Float32List, Float64List, and Lists and Maps of those; anything else throws. Ints become 32- or 64-bit host numbers by size, and maps come back untyped.

open as a page

In Dart FFI, how does an @Native external function differ from binding a symbol with DynamicLibrary.open and lookupFunction, and which should new Flutter code use?

level: middleimportance: should knowfreq 24%

basics

~20 s

An @Native external function is resolved by the VM from its annotation, by default against a code asset named after the Dart library, so no loading code is needed; lookupFunction resolves a symbol at runtime in a DynamicLibrary you opened by path. New packages built with hooks use @Native.

open as a page

In Dart FFI, how do you map a C struct and pass a Flutter image's pixel buffer to a C function taking pointers?

level: middleimportance: should knowfreq 22%

basics

~20 s

Declare a final class extending Struct whose external fields carry native-type annotations such as @Int32(), allocate it and reach it through pointer.ref, and copy pixels into native memory via asTypedList, or pass Uint8List.address directly to a leaf @Native call.

open as a page

In a Flutter app targeting Android 15 or later, what does the default SystemUiMode.edgeToEdge change, and what stops working?

level: middleimportance: should knowfreq 26%

basics

~20 s

Edge-to-edge makes the app draw behind transparent status and navigation bars. On Android 15+ targets statusBarColor and systemNavigationBarColor stop working, other SystemUiModes need an opt-out, and Android 16 targets, the Flutter 3.47 default, cannot opt out.

open as a page

In Flutter, how does AppLifecycleListener differ from mixing WidgetsBindingObserver into a State to react to app lifecycle changes?

level: middleimportance: should knowfreq 38%

basics

~10 s

AppLifecycleListener, added in Flutter 3.13, is a disposable object that registers itself on WidgetsBinding and turns state changes into transition callbacks such as onHide, onShow and onExitRequested; WidgetsBindingObserver only hands you the new state.

open as a page

In Flutter's pigeon package, how do you write a definition file with @ConfigurePigeon, and what does each generated output give the Dart and host sides?

level: middleimportance: should knowfreq 26%

basics

~20 s

The definition file declares data classes, enums and @HostApi/@FlutterApi abstract classes, and @ConfigurePigeon(PigeonOptions(...)) names output paths such as dartOut, kotlinOut and swiftOut; dart run pigeon --input writes a Dart API class and host interfaces registered with setUp.

open as a page

In Pigeon for Flutter, how do @HostApi and @FlutterApi differ, and what do @async and @asyncCallback change in the generated Kotlin and Swift signatures?

level: middleimportance: should knowfreq 22%

basics

~20 s

@HostApi methods are implemented on the host and called from Dart; @FlutterApi methods are implemented in Dart and called from the host. Since pigeon 28, @async gives Kotlin suspend functions and Swift async methods, while @asyncCallback keeps completion-callback signatures.

open as a page

In Flutter, a native map embedded in a scrolling property page will not pan because the page scrolls instead; how do gestureRecognizers fix it?

level: middleimportance: should knowfreq 38%

basics

~20 s

A platform view only receives touches that no Flutter recognizer claims unless you list recognizers in gestureRecognizers. Adding an EagerGestureRecognizer gives the map every gesture starting on it; a narrower set, such as horizontal drags, lets the page keep vertical scrolling.

open as a page

With webview_flutter 4 in Flutter, how do you show a web page, and when would you switch its Android widget to hybrid composition?

level: middleimportance: should knowfreq 44%

basics

~20 s

Create a WebViewController, configure it (for example setJavaScriptMode and loadRequest), and pass it to a WebViewWidget. On Android the widget uses texture layer composition by default; switch to hybrid composition through AndroidWebViewWidgetCreationParams when texture mode misbehaves.

open as a page

In a Flutter federated plugin, how does endorsing a platform package with default_package work, and how does an app use a non-endorsed implementation instead?

level: middleimportance: should knowfreq 34%

basics

~20 s

The app-facing package endorses a platform package by depending on it and naming it as default_package for that platform, so apps get it automatically. An app picks a non-endorsed implementation by adding it as a direct dependency, which the Flutter tool prefers.

open as a page

In a Flutter federated plugin, what do the app-facing, platform-interface and platform packages each contain, and why split a plugin that way?

level: middleimportance: should knowfreq 40%

basics

~20 s

The app-facing package holds the public API apps call; the platform-interface package holds an abstract class every implementation extends; each platform package implements it for one platform and registers itself. The split lets platforms ship and version independently.

open as a page

In Flutter, which host thread runs platform channel handlers, and how can a background Dart isolate call a plugin's MethodChannel?

level: seniorimportance: should knowfreq 28%

basics

~20 s

Host channel handlers run on the platform's main thread unless registered with a background TaskQueue. A spawned Dart isolate can call channels after BackgroundIsolateBinaryMessenger.ensureInitialized(token), using a RootIsolateToken taken on the root isolate, but it cannot receive host messages.

open as a page

A Flutter app's permission_handler call Permission.camera.request() returns denied instantly with no dialog on a fresh install; how do you diagnose it?

level: seniorimportance: should knowfreq 30%

basics

~20 s

An instant denied on a fresh install almost always means the permission is not declared: the Android manifest lacks the uses-permission entry, or on iOS the PERMISSION_CAMERA macro is off because NSCameraUsageDescription is missing or the Podfile does not enable it.

open as a page

In a Flutter video-call screen, at which AppLifecycleState should you release the camera, and what goes wrong if you also request permissions there?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Release the camera when the state becomes inactive and re-create it on resumed, as the camera plugin recommends. Never request permissions from that handler: the permission dialog itself makes the app inactive, so it loops.

open as a page

A Flutter plugin bridges a barcode-scanning SDK with Pigeon; which Pigeon-specific failures appear in production, and how do you prevent them?

level: seniorimportance: should knowfreq 18%

basics

~20 s

The usual failures are Dart and host files generated by different Pigeon versions, a missing setUp call surfacing as PlatformException 'channel-error', a host returning null for a non-null type ('null-error'), and generated types leaking into a plugin's public API.

open as a page

In Flutter on Android, how do texture layer, hybrid composition and HCPP platform views differ, and what does each cost in frame rate?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Texture layer renders the native view into a texture Flutter composites, keeping Flutter fast but janking on fast scrolls. Hybrid composition puts it in the Android view hierarchy with full fidelity but merges raster work onto the platform thread. HCPP is an experimental, faster hybrid mode.

open as a page

In a Flutter federated plugin, why must platform implementations extend the PlatformInterface subclass rather than implement it, and how do tests still mock it?

level: seniorimportance: should knowfreq 24%

basics

~20 s

Extending lets the interface package add new methods with default bodies without breaking any implementation; implementing would force every platform package to update. The instance setter enforces this with a token check, and tests opt out with MockPlatformInterfaceMixin.

open as a page

showing 1–30 of 36