24.调用原生相册
MethodChannel
Flutter 与原生交互的通道是 MethodChannel。下面我们通过调用 iOS 原生相册选择来体验一下。
示例代码
定义一个Channel
MethodChannel _channel = const MethodChannel('mine_header/channel');
给原生发送指令
_channel.invokeMapMethod('sel_avatar');
原生处理指令
import UIKit
import Flutter
/// 这里将指令用 枚举包装,便于使用
enum MineChannelMethod: String {
case AvatarPick = "sel_avatar"
}
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
if let flutterVC = window?.rootViewController as? FlutterViewController,
let messenger = flutterVC as? FlutterBinaryMessenger
{
// 实例化 channel
let mineChannel = FlutterMethodChannel.init(name: "mine_header/channel", binaryMessenger: messenger)
mineChannel.setMethodCallHandler { call, result in
guard
call.method.isEmpty == false,
let method = MineChannelMethod(rawValue: call.method)
else {
return
}
switch method {
case .AvatarPick:
let picker = UIImagePickerController()
picker.modalPresentationStyle = .overFullScreen
picker.delegate = self
flutterVC.present(picker, animated: true, completion: nil)
}
}
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
extension AppDelegate: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
检验效果
数据传递
通过检查选择完成后的回调我们发现 info 中包含的数据:
[__C.UIImagePickerControllerInfoKey(_rawValue: UIImagePickerControllerMediaType): public.image, __C.UIImagePickerControllerInfoKey(_rawValue: UIImagePickerControllerImageURL): file:///private/var/mobile/Containers/Data/Application/8A9A613F-32F9-4E45-8CB3-BB882CC9F590/tmp/3BC0596E-8B97-4E64-B260-269668F9CA73.png, __C.UIImagePickerControllerInfoKey(_rawValue: UIImagePickerControllerOriginalImage): <UIImage:0x281538f30 anonymous {1125, 2436} renderingMode=automatic>, __C.UIImagePickerControllerInfoKey(_rawValue: UIImagePickerControllerReferenceURL): assets-library://asset/asset.PNG?id=65B7A1B5-597F-4B97-B8E3-9CA019A9A526&ext=PNG]
我们需要将图片路径回传给 Flutter 。
if let imgPath = info[UIImagePickerController.InfoKey.imageURL] as? URL {
print(imgPath.absoluteString)
}
file:///private/var/mobile/Containers/Data/Application/EE26C1FB-3551-4454-8BAA-B62CADD2B311/tmp/C2302E64-C587-4975-9A24-BD43B34FA0F1.png
if let imgPath = (info[UIImagePickerController.InfoKey.imageURL] as? URL)?.absoluteString, imgPath.count > 8 {
let path = String(imgPath.suffix(from: String.Index.init(utf16Offset: 7, in: imgPath)))
print(path)
}
截取有效字段: /private/var/mobile/Containers/Data/Application/C7341168-0BCB-4712-8092-CB2661798888/tmp/828FF919-E315-4401-B76D-C774F5F2EF25.png
数据回传
if let imgPath = (info[UIImagePickerController.InfoKey.imageURL] as? URL)?.absoluteString, imgPath.count > 8 {
let path = String(imgPath.suffix(from: String.Index.init(utf16Offset: 7, in: imgPath)))
channel?.invokeMethod("rec_imagePath", arguments: path)
}
数据接收
final String _selAvatar = 'sel_avatar';
final String _reciveImagePath = 'rec_imagePath';
final MethodChannel _channel = const MethodChannel('mine_header/channel');
@override
void initState() {
super.initState();
_channel.setMethodCallHandler( (call) async {
if (call.method == _reciveImagePath) {
print('${call.arguments}');
setState(() {
_avatarPath = call.arguments.toString();
});
}
});
}
得到: flutter: /private/var/mobile/Containers/Data/Application/336E79D6-B33A-4ABC-A380-4501E1550E1D/tmp/D50D8A94-3625-4CA7-8D2B-2C6AD0CCCC67.png
数据展示
class MeHeaderView extends StatelessWidget {
Function()? avatarTap;
File? avatarFile;
MeHeaderView({this.avatarTap, this.avatarFile});
@override
Widget build(BuildContext context) {
return Container(
...
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fitWidth,
image: (avatarFile == null
? const AssetImage('images/header_avatar.GIF')
: FileImage(avatarFile!)) as ImageProvider,
),
),
),
...
}
}
Last updated