最後来看Native 端(iOS):
补充:iOS 中的 .h 和.m 档
.h 为标头档,做为宣告属性及方法使用
.m 为Objective-C档,做为实际编写属性值及方法内容使用
这边先介绍一下,Flutter 专案的iOS 入口点在AppDelegate
,其继承自Flutter.framework 的FlutterAppDelegate
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
在启动时进入AppDelegate
後会执行GeneratedPluginRegistrant.register(with: self)
,而GeneratedPluginRegistrant
中的(void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry
会实现当执行flutter pub get
时生成的Flutter 所依赖iOS 端的插件
举例来说,我们来看之前建立plugin 时自动产生的example
(使用我们plugin package 的范例专案),此范例专案已经依赖我们的plugin package,我们就可以看到它的GeneratedPluginRegistrant.m
:
#import "GeneratedPluginRegistrant.h"
#if __has_include(<batterylevel/BatterylevelPlugin.h>)
#import <batterylevel/BatterylevelPlugin.h>
#else
@import batterylevel;
#endif
@implementation GeneratedPluginRegistrant
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
[BatterylevelPlugin registerWithRegistrar:[registry registrarForPlugin:@"BatterylevelPlugin"]];
}
@end
使范例专案在启动iOS 时,会注册Flutter 依赖的iOS 端插件(此时会呼叫我们的pluginBatterylevelPlugin
来注册)
回到我们的plugin,我们来看看如何实现Native 端(iOS)的功能:
预设建立的档案主要有:
ios/Classes/BatterylevelPlugin
#import "BatterylevelPlugin.h"
#if __has_include(<batterylevel/batterylevel-Swift.h>)
#import <batterylevel/batterylevel-Swift.h>
#else
// Support project import fallback if the generated compatibility header
// is not copied when this plugin is created as a library.
// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
#import "batterylevel-Swift.h"
#endif
@implementation BatterylevelPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
[SwiftBatterylevelPlugin registerWithRegistrar:registrar];
}
@end
当别人使用我们的plugin 时,在启动iOS 後会注册它们Flutter 所依赖的iOS 端插件,我们的plugin 就透过BatterylevelPlugin
提供一个SwiftBatterylevelPlugin
来注册,其plugin 的功能也会在SwiftBatterylevelPlugin
来实现
ios/Classes/SwiftBatterylevelPlugin.swift
用来实现注册方法以及我们插件的功能,其中FlutterPlugin
为插件协议,所以必须实作注册方法
public class SwiftBatterylevelPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "batterylevel", binaryMessenger: registrar.messenger())
let instance = SwiftBatterylevelPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
result("iOS " + UIDevice.current.systemVersion)
}
}
在注册方法中需要新建用来通信的Channel
(对应Flutter 端的MethodChannel
,iOS 端为FlutterMethodChannel
)并与FlutterPluginRegistrar
的FlutterBinaryMessenger
进行连结绑定,再透过调用addMethodCallDelegate
方法将Channel
注册到FlutterEngine
里,这边我们来看看FlutterEngine 里的原始码:
- (void)addMethodCallDelegate:(NSObject<FlutterPlugin>*)delegate
channel:(FlutterMethodChannel*)channel {
[channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
[delegate handleMethodCall:call result:result];
}];
}
这边将Channel
透过setMessageHandler
向 FlutterBinaryMessenger
注册一个FlutterMethodChannel
用的FlutterMethodCallHandler
来处理接收讯息,当Flutter 端通过invokeMethod
调用Native iOS 端方法时,就会通过传进来的FlutterPlugin 的delegate
将讯息回调给FlutterPlugin
(这边的SwiftBatterylevelPlugin
)的handleMethodCall
方法
回到SwiftBatterylevelPlugin
,最後handle
用来实现FlutterPlugin
的- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result
,这边产生的范例程序直接回传版本资讯给Flutter 端
而范例程序并无针对Flutter 端呼叫FlutterMethodCall
的不同方法名做判断处理,我们来对其做以下修改:
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "getPlatformVersion":
result("iOS " + UIDevice.current.systemVersion)
default:
result(FlutterMethodNotImplemented)
}
}
在看完plugin 范例程序的版本资讯功能後,我们对plugin 对Channel
功能的实现已经有初步的了解,这边就先以一样的步骤,新增取得batterylevel 电池电量资讯的功能吧
<<: @Day29 | C# WixToolset + WPF 帅到不行的安装包 [如何拿已经安装好的资料]
>>: 透过写程序可以更熟悉AWS console上的完整操作
在大型专案中,可能会把专案依功能、架构等等因素,切分为多个子专案,虽然切分为多个子专案,有些逻辑可能...
今天会开始来讲元件的部分~ 通用参数 height : 高度 width : 宽度 fg : 文字颜...
杂谈 今年是个很特别的一年,对威尔猪来说也是,从没写过任何形式的笔记或文章,也没什麽特别规划,居然就...
今天来介绍一些跟「错误处理」有关的 operators。在使用 RxJS 时,资料流是透过 pipe...
上一篇利用路由机制传递参数来实作待办事项的编辑功能,除了透过网址路径来传递所需要的参数,还可以在路由...