Skip to content

Platform Channels

Flutter draws its own pixels, but some things live only in the native OS — the battery level, a specific sensor, a platform SDK, the secure enclave. To reach them, Flutter uses platform channels: a typed, asynchronous message pipe between your Dart code and native (Kotlin/Java on Android, Swift/Objective-C on iOS).

The model is the same async message passing you already know from Dart: you send a message, the native side handles it, and a Future completes with the reply. Nothing blocks the UI thread.

flowchart LR
  dart["Dart
invokeMethod('getBattery')"] -->|message| platform["platform channel"]
  platform --> native["native code
reads battery level"]
  native -->|reply| platform
  platform -->|Future completes| dart
A MethodChannel round-trip

A MethodChannel names a pipe and lets you invokeMethod on it. The call is async and returns a Future with the native result. Arguments and results are standard types (numbers, strings, lists, maps) serialized across the boundary.

const channel = MethodChannel('samples.app/battery');
Future<int> getBatteryLevel() async {
try {
final level = await channel.invokeMethod<int>('getBatteryLevel');
return level ?? -1;
} on PlatformException catch (e) {
// native side reported an error
return -1;
}
}

The native side registers a handler for the same channel name and switches on the method string to run the real platform code.

Where MethodChannel is one call and one reply, an EventChannel delivers a stream of events from native — sensor updates, connectivity changes, location. It maps to a Dart Stream, so you consume it exactly like any other stream.

const events = EventChannel('samples.app/accelerometer');
Stream<AccelData> accelerometer() {
return events.receiveBroadcastStream().map((e) => AccelData.parse(e));
}

You rarely write channel code by hand. A plugin is a package that wraps platform channels plus the native implementation behind a clean Dart API — battery_plus, geolocator, camera. Reach for a well-maintained plugin first; write a raw channel only for something bespoke to your app.

Not native, but part of app structure: images, fonts, and JSON you bundle must be declared in pubspec.yaml so they ship with the app.

flutter:
assets:
- assets/images/logo.png
- assets/data/
fonts:
- family: Inter
fonts:
- asset: assets/fonts/Inter-Regular.ttf
// Then load them by their declared path:
Image.asset('assets/images/logo.png');
What is a platform channel?
What is the difference between MethodChannel and EventChannel?
For a common need like battery level or geolocation, what should you reach for first?
Where must bundled assets (images, fonts) be declared?