Flutter插件开发流程3(Use a Platform In
1.分析上一节中Web插件的不足
- methodchannel是通过字节数组传递的在web中是比必要的,因为web最后都是js代码
For one, there is unnecessary overhead of sending plugin method calls over a MethodChannel. On the web, your entire app is compiled into one JavaScript bundle, so the plugin code is needlessly serializing the method call into a byte array, which is then instantly deserialized by the web plugin.
- methodchannel 使用字符串和插件匹配,在其他平台,这个web插件是不必要的,上一讲的写法不利于屏蔽web插件代码
Another disadvantage of using a MethodChannel is that it makes it difficult for the compiler to remove (by tree-shaking) unused plugin code. The web plugin calls the appropriate method based on the name of the method call passed by the MethodChannel, so the compiler has to assume that all of the methods in the plugin are live, and none of them can be tree-shaken out
2.interface模块引入,依赖关系如下
image.png3.关键代码分析
image.png平台接口的launch和closeWebView对应原来methodChannel方法
import 'dart:async';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:url_launcher_platform_interface/link.dart';
import 'method_channel_url_launcher.dart';
abstract class UrlLauncherPlatform extends PlatformInterface {
/// Constructs a UrlLauncherPlatform.
UrlLauncherPlatform() : super(token: _token);
static final Object _token = Object();
static UrlLauncherPlatform _instance = MethodChannelUrlLauncher();
/// The default instance of [UrlLauncherPlatform] to use.
///
/// Defaults to [MethodChannelUrlLauncher].
static UrlLauncherPlatform get instance => _instance;
themselves.
// TODO(amirh): Extract common platform interface logic.
// https://github.com/flutter/flutter/issues/43368
static set instance(UrlLauncherPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
/// The delegate used by the Link widget to build itself.
LinkDelegate? get linkDelegate;
/// Returns `true` if this platform is able to launch [url].
Future<bool> canLaunch(String url) {
throw UnimplementedError('canLaunch() has not been implemented.');
}
/// Returns `true` if the given [url] was successfully launched.
///
/// For documentation on the other arguments, see the `launch` documentation
/// in `package:url_launcher/url_launcher.dart`.
Future<bool> launch(
String url, {
required bool useSafariVC,
required bool useWebView,
required bool enableJavaScript,
required bool enableDomStorage,
required bool universalLinksOnly,
required Map<String, String> headers,
String? webOnlyWindowName,
}) {
throw UnimplementedError('launch() has not been implemented.');
}
/// Closes the WebView, if one was opened earlier by [launch].
Future<void> closeWebView() {
throw UnimplementedError('closeWebView() has not been implemented.');
}
}
url_lancher_web给出实现
注意registerWith不再是创建个methodChannel接收调用,而是更加平台接口的实现为当前web插件
UrlLauncherPlatform.instance = UrlLauncherPlugin();
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:html' as html;
import 'src/shims/dart_ui.dart' as ui;
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
import 'package:meta/meta.dart';
import 'package:url_launcher_platform_interface/link.dart';
import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
import 'src/link.dart';
import 'src/third_party/platform_detect/browser.dart';
const _safariTargetTopSchemes = {
'mailto',
'tel',
'sms',
};
String? _getUrlScheme(String url) => Uri.tryParse(url)?.scheme;
bool _isSafariTargetTopScheme(String url) =>
_safariTargetTopSchemes.contains(_getUrlScheme(url));
/// The web implementation of [UrlLauncherPlatform].
///
/// This class implements the `package:url_launcher` functionality for the web.
class UrlLauncherPlugin extends UrlLauncherPlatform {
html.Window _window;
bool _isSafari = false;
// The set of schemes that can be handled by the plugin
static final _supportedSchemes = {
'http',
'https',
}.union(_safariTargetTopSchemes);
/// A constructor that allows tests to override the window object used by the plugin.
UrlLauncherPlugin({@visibleForTesting html.Window? debugWindow})
: _window = debugWindow ?? html.window {
_isSafari = navigatorIsSafari(_window.navigator);
}
/// Registers this class as the default instance of [UrlLauncherPlatform].
static void registerWith(Registrar registrar) {
UrlLauncherPlatform.instance = UrlLauncherPlugin();
ui.platformViewRegistry.registerViewFactory(linkViewType, linkViewFactory);
}
@override
LinkDelegate get linkDelegate {
return (LinkInfo linkInfo) => WebLinkDelegate(linkInfo);
}
/// Opens the given [url] in the specified [webOnlyWindowName].
///
/// Returns the newly created window.
@visibleForTesting
html.WindowBase openNewWindow(String url, {String? webOnlyWindowName}) {
// We need to open mailto, tel and sms urls on the _top window context on safari browsers.
// See https://github.com/flutter/flutter/issues/51461 for reference.
final target = webOnlyWindowName ??
((_isSafari && _isSafariTargetTopScheme(url)) ? '_top' : '');
return _window.open('https://baidu.com', target);
}
@override
Future<bool> canLaunch(String url) {
return Future<bool>.value(_supportedSchemes.contains(_getUrlScheme(url)));
}
@override
Future<bool> launch(
String url, {
bool useSafariVC = false,
bool useWebView = false,
bool enableJavaScript = false,
bool enableDomStorage = false,
bool universalLinksOnly = false,
Map<String, String> headers = const <String, String>{},
String? webOnlyWindowName,
}) {
return Future<bool>.value(
openNewWindow('https://baidu.com', webOnlyWindowName: webOnlyWindowName) != null);
}
}
url_lancher插件接口修改
以前是主插件那里,发送个methodchannel调用,现在则是改成平台接口调用,而平台接口的实现可以是通过methodchannel方式,而对应web插件的实现,则是直接调用了,不再是methodchannel
插件url_launcher.dart
Future<bool> canLaunch(String urlString) async {
return await UrlLauncherPlatform.instance.canLaunch(urlString);
}
版本依赖和发布
image.png目前认为,先把被依赖的发布上去,和maven库发布流程类似吧,具体没有实际操作过!