Flutter与iOS之间平台通信(platform channel)基本流程

创建插件项目

1
2
3
4
5
6
# 命令解读 
# -i 指的是iOS平台选择什么语言 后接语言类型 objc/swift
# -a 指的是Android平台 后接语言类型 java/kotlin
flutter create --template=plugin -i objc -a java MyPlugin
cd MyPlugin/example
flutter run #试试项目能否跑🏃起来

等待命令执行完即可

目录结构大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
.
├── CHANGELOG.md
├── LICENSE
├── MyPlugin.iml
├── README.md
├── android #安卓平台代码
├── example #demo例子🌰
├── ios #iOS平台代码
├── lib #插件通信代码
├── pubspec.lock
├── pubspec.yaml
└── test

开始编写插件代码

首先打开项目找到MyPlugin.dart文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import 'dart:async';

import 'package:flutter/services.dart';

class MyPlugin {
static const MethodChannel _channel = const MethodChannel('MyPlugin');

static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}

//新增一个方法 用于发送字典即Map参数给iOS平台 返回值是泛型类型用于接收iOS发送过来的消息内容
static Future<dynamic> dartSendMessageToIOS(Map<String, dynamic> args) {
return _channel.invokeMethod("dartSendMessageToIOS", args);
}
}

其次找到example/main.dart用于开发调试插件代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:MyPlugin/MyPlugin.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';

@override
void initState() {
super.initState();
initPlatformState();
initDartSendMessage();
}

Future<void> initDartSendMessage() async {
String platformVersion;
dynamic args; //定义接收对应平台的返回值 (这里指iOS平台,Android端暂未实现)
try {
platformVersion = "";
args = await MyPlugin.dartSendMessageToIOS({
"floatNumber": 0.02,
"number": 666,
"str": "字符串",
"arr": ["item1", "item2", "item3"],
"dict": {"key": "value"}
});
print("iOS获取过来的数据如下:\n $args");
} on PlatformException {
platformVersion = "获取到版本号失败!!!";
}
if (!mounted) {
return;
}
setState(() {
_platformVersion = platformVersion;
});
}

// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
platformVersion = await MyPlugin.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}

// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;

setState(() {
_platformVersion = platformVersion;
});
}

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Text('Running on: $_platformVersion\n'),
),
),
);
}
}

关于通道(channel)的数据类型交互可参考flutter中文网的介绍

最后就是使用Xcode打开example/ios/Runner.xcodeproj编辑本地库里的插件文件MyPlugin.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#import "MyPlugin.h"

@implementation MyPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"MyPlugin"
binaryMessenger:[registrar messenger]];
MyPlugin* instance = [[MyPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"getPlatformVersion" isEqualToString:call.method]) {
result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
}else if ([@"dartSendMessageToIOS" isEqualToString:call.method]){
//dart 发送一些参数给iOS,收到消息之后做一些事情

//dart传的参数字典也就是Map
NSDictionary *args = call.arguments;
NSLog(@"dart发送过来的数据:");
NSLog(@"floatNumber: %@",args[@"floatNumber"]);
NSLog(@"str: %@",args[@"str"]);
NSLog(@"arr: %@",args[@"arr"]);
NSLog(@"dict: %@",args[@"dict"]);
NSLog(@"dict[key]: %@",args[@"dict"][@"key"]);

//给flutter channel发送一些参数过去 dart收到会打印显示的
result(@{
@"float" : @(0.0666),
@"int" : @(1111),
@"strings" : @"哈哈哈哈,我是字符串了",
@"array" : @[@"iOS",@"Swift",@"Flutter"],
@"dict" : @{@"iOS":@"666"}
});

}else {
result(FlutterMethodNotImplemented);
}
}

@end

最后,运行代码查看效果

1
2
cd example
flutter run

附上一张控制台打印的效果图