Flutter Desktop Mac版(二) 插件初探
文章目录
上篇粗略的查看了一下 desktop 的基本使用, 本篇探索一下插件的使用
环境变量的配置请查看上篇,本篇不再赘述
更新
继上一篇文章过去了几天, 这个桌面引擎有了一点点的更改: 现在完全用 swift 了,不用 oc 了,无论是 example 还是 plugin 模板都是如此
所以, 为了省事,我重新 clone 了一个仓库, 然后准备用 swift 来创建插件
$ git clone https://github.com/google/flutter-desktop-embedding.git flutter-desktop-embedding-2
然后分别打开工程和插件 $ code flutter-desktop-embedding-2/example/
and $ code flutter-desktop-embedding-2/plugins/example_plugin
这个 example_plugin 是给的模板, 最好是复制一份出来
复制插件目录
1cd flutter-desktop-embedding-2/plugins
2cp -r example_plugin math_desktop
3code math_desktop
查看一下目录结构
1tree math_desktop
2
3math_desktop
4├── LICENSE
5├── lib
6│ └── example_plugin.dart
7├── linux
8│ ├── Makefile
9│ ├── example_plugin.cc
10│ └── example_plugin.h
11├── macos
12│ ├── Classes
13│ │ └── ExamplePlugin.swift
14│ └── example_plugin.podspec
15├── pubspec.yaml
16└── windows
17 ├── ExamplePlugin.vcxproj
18 ├── ExamplePlugin.vcxproj.filters
19 ├── example_plugin.cpp
20 ├── example_plugin.h
21 └── scripts
22 └── cache_flutter.bat
基本是约定式的,和移动版的很类似
pubspec.yaml 在根目录,lib 放 dart 文件,然后根据 Platform 的不同使用不同的文件
依赖插件并打开插件
修改 example 文件,添加依赖
1dependencies:
2 flutter:
3 sdk: flutter
4
5 cupertino_icons: ^0.1.0
6 math_desktop: # add it
7 path: ../plugins/math_desktop
然后在 example 目录下执行flutter pub get
, 这个是flutter packages get
的另一种写法, 比较简单点
接着进入 macos 目录下,执行$ pod install
等待完成后 执行 $ open Runner.xcworkspace
, 这样正常情况下会用 xcode 打开这个工程
接着出现的就和 iOS 的插件差不多一样了 是这个 SHI 样的:
需要简化目录结构的可以搜索我写的 appcode 索引那个文章, 有简化方式,我这里不管它了
编写插件
dart
插件目录下的 lib 文件夹
添加一个方法
1 static Future<int> add(int a, int b) async {
2 return _channel.invokeMethod('add', [a, b]);
3 }
swift
很显然,中间那段是我自己加的,没什么实际意义, 就为了演示而已
1 public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
2 if (call.method == "getPlatformVersion") {
3 result("macOS " + ProcessInfo.processInfo.operatingSystemVersionString)
4 } else if(call.method == "add"){
5 let args = call.arguments as! [Any]
6 let a = args[0] as! Int
7 let b = args[1] as! Int
8 result(a + b)
9 } else {
10 result(FlutterMethodNotImplemented);
11 }
12 }
调用
在 example 中调用这个方法
1FutureBuilder<int>(
2 future: ExamplePlugin.add(_counter, 5),
3 builder: (context, snapshot) {
4 if (snapshot.hasData) {
5 return Text(snapshot.data.toString());
6 } else {
7 return Text('计算中');
8 }
9 },
10)
目前完整的 example 部分的代码如下:
1// Copyright 2018 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import 'package:flutter/foundation.dart'
16 show debugDefaultTargetPlatformOverride;
17import 'package:flutter/material.dart';
18import 'package:math_desktop/example_plugin.dart';
19
20void main() {
21 // See https://github.com/flutter/flutter/wiki/Desktop-shells#target-platform-override
22 debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
23
24 runApp(new MyApp());
25}
26
27class MyApp extends StatelessWidget {
28 @override
29 Widget build(BuildContext context) {
30 return MaterialApp(
31 title: 'Flutter Demo',
32 theme: ThemeData(
33 primarySwatch: Colors.blue,
34 // See https://github.com/flutter/flutter/wiki/Desktop-shells#fonts
35 fontFamily: 'Roboto',
36 ),
37 home: MyHomePage(title: 'Flutter Demo Home Page'),
38 );
39 }
40}
41
42class MyHomePage extends StatefulWidget {
43 MyHomePage({Key key, this.title}) : super(key: key);
44
45 final String title;
46
47 @override
48 _MyHomePageState createState() => _MyHomePageState();
49}
50
51class _MyHomePageState extends State<MyHomePage> {
52 int _counter = 0;
53
54 void _incrementCounter() {
55 setState(() {
56 _counter++;
57 });
58 }
59
60 @override
61 Widget build(BuildContext context) {
62 return Scaffold(
63 appBar: AppBar(
64 title: Text(widget.title),
65 ),
66 body: Center(
67 child: Column(
68 mainAxisAlignment: MainAxisAlignment.center,
69 children: <Widget>[
70 Text(
71 'You have pushed the button this many times:',
72 ),
73 Text(
74 '$_counter',
75 style: Theme.of(context).textTheme.display1,
76 ),
77 FutureBuilder<int>(
78 future: ExamplePlugin.add(_counter, 5),
79 builder: (context, snapshot) {
80 if (snapshot.hasData) {
81 return Text(snapshot.data.toString());
82 } else {
83 return Text('计算中');
84 }
85 },
86 ),
87 ],
88 ),
89 ),
90 floatingActionButton: FloatingActionButton(
91 onPressed: _incrementCounter,
92 tooltip: 'Increment',
93 child: Icon(Icons.add),
94 ),
95 );
96 }
97}
运行代码
这里会发现这种错误
1[ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: MissingPluginException(No implementation found for method add on channel example_plugin)
首先我在 MathDesktop
类的注册方法中加入了 NSLog 的日志, 发现并没有输出, 所以应该是插件没有注册的原因
1public static func register(with registrar: FlutterPluginRegistrar) {
2 let channel = FlutterMethodChannel(name: "example_plugin", binaryMessenger: registrar.messenger)
3 let instance = MathDesktop()
4 registrar.addMethodCallDelegate(instance, channel: channel)
5 NSLog("初始插件 : example_plugin")
6}
据我观察并测试后, 原因是: 虽然迁移到了 swift, 但是相应的脚本或者说 flutter 的工具链没有迁移, 所以还是用的 oc 文件来注入, 但 oc 文件未被纳入到 flutter 项目中, 所以暂时还没法通过 flutter packages get 来自动引入原生的 plugin
所以需要手动修改example/macos/Flutter/GeneratedPluginRegistrant.swift
文件,来注册插件
1import Foundation
2import FlutterMacOS
3import math_desktop
4
5func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
6 MathDesktop.register(with: registry.registrar(forPlugin: "math_desktop"))
7}
这样再次运行,就不会再报错了
可以得到正确的效果
简单总结
通过插件的编写, 简单总结一下:
- 插件的原生中引入的库不是 iOS 中的 Flutter, 而是 FlutterMacOS
- ViewController 的是 Cocoa 框架, 个人猜测不排除未来会变成 SwiftUI 的可能性
- 注册工具目前不太好用
- dart 端几乎无差,但是不排除会有一些特殊的手势或事件(鼠标滑过,键盘监听)
后记
仓库地址: https://git.kikt.top/kikt/flutter-desktop-mac-example-2 目前私有库,后续修改完成后放在 github 上
插件的简单使用就到这里
以上