第12章:Flutter 与原生插件开发
Flutter 提供了插件机制,允许开发者将平台原生功能(Java/Kotlin、Swift/Objective-C)封装为 Dart 接口,供 Flutter 使用。你可以开发:
- 私有插件:在你的项目中复用
- 公共插件:发布到 pub.dev,供社区使用
一、创建插件项目
使用命令行创建插件:
flutter create --template=plugin --platforms=android,ios flutter_battery_plugin
目录结构说明:
flutter_battery_plugin/
├── lib/flutter_battery_plugin.dart # Dart接口
├── android/src/.../FlutterBatteryPlugin.kt
├── ios/Classes/FlutterBatteryPlugin.swift
二、Dart 端接口定义
// lib/flutter_battery_plugin.dart
import 'package:flutter/services.dart';
class FlutterBatteryPlugin {
static const MethodChannel _channel = MethodChannel('flutter_battery_plugin');
static Future<int?> getBatteryLevel() async {
final level = await _channel.invokeMethod<int>('getBatteryLevel');
return level;
}
}
三、Android 原生实现(Kotlin)
// android/src/main/kotlin/com/example/flutter_battery_plugin/FlutterBatteryPlugin.kt
package com.example.flutter_battery_plugin
import android.content.Context
import android.os.BatteryManager
import android.os.Build
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
class FlutterBatteryPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
private lateinit var channel: MethodChannel
private lateinit var context: Context
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
context = flutterPluginBinding.applicationContext
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_battery_plugin")
channel.setMethodCallHandler(this)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: MethodChannel.Result) {
if (call.method == "getBatteryLevel") {
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val level = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
result.success(level)
} else {
result.notImplemented()
}
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}
四、iOS 原生实现(Swift)
// ios/Classes/FlutterBatteryPlugin.swift
import Flutter
import UIKit
public class FlutterBatteryPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "flutter_battery_plugin", binaryMessenger: registrar.messenger())
let instance = FlutterBatteryPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if call.method == "getBatteryLevel" {
let device = UIDevice.current
device.isBatteryMonitoringEnabled = true
result(Int(device.batteryLevel * 100))
} else {
result(FlutterMethodNotImplemented)
}
}
}
五、在主项目中引用插件(本地依赖)
在你的主 App 项目中:
dependencies:
flutter_battery_plugin:
path: ../flutter_battery_plugin
使用:
import 'package:flutter_battery_plugin/flutter_battery_plugin.dart';
Future<void> _getBattery() async {
final level = await FlutterBatteryPlugin.getBatteryLevel();
print('Battery Level: $level%');
}
六、发布插件到 pub.dev(可选)
- 填写
pubspec.yaml中的name、description、version、homepage - 添加
README.md、CHANGELOG.md、LICENSE - 注册 pub.dev 账号
- 登录并发布:
dart pub publish
七、常见问题解析
❗ 插件无法识别 MethodChannel
- 检查通道名称必须一致(Dart 与原生)
- 原生端是否实现了
onMethodCall
❗ Android 端电池读取失败(0 或 -1)
- 需使用真实设备或模拟器设置支持电池状态
- 请检查是否有正确的上下文和权限
❗ iOS 端未返回电池电量
UIDevice.current.isBatteryMonitoringEnabled是否开启- iOS 模拟器不支持电池状态,需要真机调试