Call Platform Code
Start with the highest-level boundary that solves the problem.
Choose The Boundary
| Need | Use |
|---|---|
| Common device capability | Existing plugin |
| A few app-owned native calls | MethodChannel |
| Larger typed host API | Pigeon |
| C-compatible native library | FFI |
| Native UI inside Flutter | Platform view |
| Browser API on web | JS interop |
MethodChannel Shape
Keep the Dart side small and typed at your app boundary:
import 'package:flutter/services.dart';
class BatteryService {
static const _channel = MethodChannel('app.example/battery');
Future<int> batteryLevel() async {
final level = await _channel.invokeMethod<int>('batteryLevel');
if (level == null) {
throw StateError('Platform returned no battery level');
}
return level;
}
}
Then hide BatteryService behind a repository or view model dependency so tests can fake it.
Rules
- Document channel names and method names.
- Validate arguments and nulls on both sides.
- Keep platform calls asynchronous.
- Test missing plugin and unsupported platform paths.
- Avoid calling platform code directly from widgets.
Gotcha: Web does not use normal platform channels for browser APIs. Plan a web-specific interop path or mark web unsupported for the feature.