第9章:Flutter 与原生交互(平台通道)
Flutter 是跨平台框架,但有时我们仍需要访问原生功能,比如:
- 调用 Android 的传感器或服务
- 使用 iOS 的特定 API
- 访问硬件(如蓝牙、相机、定位)
Flutter 提供了 平台通道(Platform Channel) 来实现这些操作。
一、平台通道的工作原理
平台通道是 Flutter 与原生代码(Android/iOS)之间通信的桥梁。
基本流程:
Flutter(Dart) <-- MethodChannel --> 原生平台(Java/Kotlin/Swift)
二、使用 MethodChannel 调用原生代码(示例)
1. Dart 端定义通道
import 'package:flutter/services.dart';
class NativeBridge {
static const _channel = MethodChannel('com.example.platform');
static Future<String> getPlatformVersion() async {
final version = await _channel.invokeMethod<String>('getPlatformVersion');
return version ?? 'Unknown';
}
}
2. Android 端实现(Kotlin)
在 MainActivity.kt 中添加:
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.example.platform"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
.setMethodCallHandler { call, result ->
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else {
result.notImplemented()
}
}
}
}
3. iOS 端实现(Swift)
在 AppDelegate.swift 中添加:
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller = window.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "com.example.platform",
binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler { call, result in
if call.method == "getPlatformVersion" {
result("iOS " + UIDevice.current.systemVersion)
} else {
result(FlutterMethodNotImplemented)
}
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
三、常见原生功能的调用方式(推荐使用插件)
Flutter 提供了大量封装好的插件,你通常无需手写原生代码。
| 功能 | 推荐插件 | 用途简述 |
|---|---|---|
| 相机 | camera | 拍照、录像、预览 |
| 相册选择 | image_picker | 从相册选择图片/拍照 |
| 定位 | geolocator | 获取 GPS、定位权限 |
| 权限管理 | permission_handler | 动态申请相机/麦克风/位置权限等 |
| 蓝牙 | flutter_blue | 蓝牙设备扫描、连接、传输数据 |
| 本地通知 | flutter_local_notifications | 显示通知,定时提醒 |
四、使用示例:使用 image_picker 打开相册
添加依赖
dependencies:
image_picker: ^1.0.0
permission_handler: ^11.0.0
示例代码
import 'package:image_picker/image_picker.dart';
final picker = ImagePicker();
Future<void> pickImage() async {
final pickedFile = await picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
print('选择的文件路径: ${pickedFile.path}');
}
}
五、权限处理(Android/iOS)
Android 添加权限(如相机、定位)
在 AndroidManifest.xml 中添加:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
iOS 添加权限说明
在 Info.plist 中添加:
<key>NSCameraUsageDescription</key>
<string>我们需要访问相机来拍照</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>我们需要访问位置来提供更好的服务</string>
六、常见问题解析
❗ 问题 1:MethodChannel 调用失败,提示未实现
- 检查通道名是否一致(Flutter 和原生)
- 检查
call.method是否拼写正确 - 检查是否注册了通道(
configureFlutterEngine())
❗ 问题 2:原生权限申请失败
- Android 6.0+ 需要动态申请权限(使用
permission_handler) - iOS 需要在
Info.plist中写权限用途说明
❗ 问题 3:插件功能在模拟器无法使用
- 相机、GPS、蓝牙等功能需真机调试
- 可以通过 Flutter 的平台判断避免模拟器执行:
import 'dart:io';
if (Platform.isAndroid || Platform.isIOS) {
// 真机逻辑
}