Flutter Analysis and Practice: Native Capability-Based Plug-In Extension

2.1.1 Flutter Plug-Ins

Figure 2–1

2.1.2 Platform Channels Flutter App Calls Native APIs

Figure 2–2 Platform Channel Architecture

Figure 2–3
  • The Flutter app (client) calls the MethodChannel class to send call messages to the platform.
  • The Android platform (host) calls the MethodChannel class to receive call messages.
  • The iOS platform (host) calls the FlutterMethodChannel class to receive call messages.

2.1.3 Flutter Battery Plug-In

Figure 2–4 Create a Plug-in

Figure 2–5 Plug-In in the Flutter Side

static const MethodChannel _methodChannel = const MethodChannel ('samples. flutter.io/battery');

Future<String> getBatteryLevel() async {
String batteryLevel;
try {
final int result = await _methodChannel.invokeMethod('getBatteryLevel', {'paramName':'paramVale'});
batteryLevel = 'Battery level: $result%.';
} catch(e) {
batteryLevel = 'Failed to get battery level.';
return batteryLevel;
static const EventChannel _eventChannel = const EventChannel('samples. flutter.io/charging');  void listenNativeEvent() {
_eventChannel.receiveBroadcastStream().listen(_onEvent, onError:_onError);
void _onEvent(Object event) {
print("Battery status: ${event == 'charging' ? '' : 'dis'}charging.");
void _onError(Object error) {
print('Battery status: unknown.');
} Plug-In in the Android Side

import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
protected void onCreate(Bundle savedInstanceState) {
public static void registerWith(Registrar registrar) {
* Channel名称:必须与Flutter App的Channel名称一致
private static final String METHOD_CHANNEL = "samples.flutter.io/battery";
private static final String EVENT_CHANNEL = "samples.flutter.io/charging";
// 实例Plugin,并绑定到Channel上
FlutterPluginBatteryLevel plugin = new FlutterPluginBatteryLevel();
final MethodChannel methodChannel = new MethodChannel (registrar. messenger(), METHOD_CHANNEL);
final EventChannel eventChannel = new EventChannel(registrar.messenger(), EVENT_CHANNEL);
  • Set Channel to be the same as the channel name of the Flutter app.
  • Pass the registrar FlutterActivity during the initialization of MethodChannel and EventChannel.
  • Set MethodCallHandler, the handler of MethodChannel.
  • Set EventChannel.StreamHandler, the handler of EventChannel.
public class FlutterPluginBatteryLevel implements MethodCallHandler, EventChannel.StreamHandler {    /**
* MethodCallHandler
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getBatteryLevel")) {
Random random = new Random();
} else {
* EventChannel.StreamHandler
public void onListen(Object obj, EventChannel.EventSink eventSink) {
BroadcastReceiver chargingStateChangeReceiver = createChargingState ChangeReceiver(events);
public void onCancel(Object obj) {
private BroadcastReceiver createChargingStateChangeReceiver(final EventSink events) {
return new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
if (status == BatteryManager.BATTERY_STATUS_UNKNOWN) {
events.error("UNAVAILABLE", "Charging status unavailable", null);
} else {
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
status == BatteryManager.BATTERY_STATUS_FULL;
events.success(isCharging ? "charging" : "discharging");
} Plug-In in the iOS Side

* Channel名称:必须与Flutter App的Channel名称一致
#define METHOD_CHANNEL "samples.flutter.io/battery";
#define EVENT_CHANNEL "samples.flutter.io/charging";
@implementation AppDelegate- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
* 注册Plugin
[GeneratedPluginRegistrant registerWithRegistry:self];

* FlutterViewController
FlutterViewController* controller = (FlutterViewController*)self.window. rootViewController;
* FlutterMethodChannel & Handler
FlutterMethodChannel* batteryChannel = [FlutterMethodChannel methodChannelWithName:METHOD_CHANNEL binaryMessenger:controller];
[batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
if ([@"getBatteryLevel" isEqualToString:call.method]) {
int batteryLevel = [self getBatteryLevel];
} else {

* FlutterEventChannel & Handler
FlutterEventChannel* chargingChannel = [FlutterEventChannel eventChannelWithName:EVENT_CHANNEL binaryMessenger:controller];
[chargingChannel setStreamHandler:self];

return [super application:application didFinishLaunchingWithOptions:launchOptions];
@interface AppDelegate () <FlutterStreamHandler>@property (nonatomic, copy)   FlutterEventSink     eventSink;@end- (FlutterError*)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink {
self.eventSink = eventSink;
// 监听电池状态
[[NSNotificationCenter defaultCenter] addObserver:self
return nil;
- (FlutterError*)onCancelWithArguments:(id)arguments {
[[NSNotificationCenter defaultCenter] removeObserver:self];
self.eventSink = nil;
return nil;
- (void)onBatteryStateDidChange:(NSNotification*)notification {
if (self.eventSink == nil) return;
UIDeviceBatteryState state = [[UIDevice currentDevice] batteryState];
switch (state) {
case UIDeviceBatteryStateFull:
case UIDeviceBatteryStateCharging:
case UIDeviceBatteryStateUnplugged:
self.eventSink([FlutterError errorWithCode:@"UNAVAILABLE"
message:@"Charging status unavailable"

2.1.4 Plug-In Loading Add a Package to the Flutter App

  • Edit the pubspec.yaml file in the app root directory to manage dependencies.
  • Run the flutter packages get command or click Packages Get in IntelliJ IDEA.
  • Reference a package and run the app again. Hosted Packages

$flutter packages pub publish --dry-run
$flutter packages pub publish
url_launcher: ^3.0.0 Git Packages (Remote)

// cd 到 flutter_remote_package  
flutter_remote_package $:git init
flutter_remote_package $:git remote add origin git@gitlab.alibaba-inc. com:churui/flutter_remote_package.git
flutter_remote_package $:git add .
flutter_remote_package $:git commit
flutter_remote_package $:git commit -m"init"
flutter_remote_package $:git push -u origin master
flutter_remote_package $:git tag 0.0.1
url: git@gitlab.alibaba-inc.com:churui/flutter_remote_package.git
ref: 0.0.1 Path Packages (Local)

Figure 2–6
path: plugins/flutter_plugin_batterylevel

2.1.5 Problems Use Xcode to Edit Plug-Ins No Plug-in Is Found at Runtime When iOS Compilation is Correct

@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
// Plugin注册方法
[GeneratedPluginRegistrant registerWithRegistry:self];

// 显示Window
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window setRootViewController:[[FlutterViewController alloc] initWithNibName:nil bundle:nil]]];
[self.window setBackgroundColor:[UIColor whiteColor]];
[self.window makeKeyAndVisible];

return [super application:application didFinishLaunchingWithOptions: launchOptions];
@end A Native Project Fails to Call the Flutter App iOS Plug-in Is Registered with the Specified FlutterViewController

- (NSObject<FlutterBinaryMessenger>*)binaryMessenger;
- (NSObject<FlutterTextureRegistry>*)textures;

2.1.6 More Discussions

Original Source:



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alibaba Cloud

Alibaba Cloud

Follow me to keep abreast with the latest technology news, industry insights, and developer trends. Alibaba Cloud website:https://www.alibabacloud.com