url_launcher是用于在移动平台中启动URL的Flutter插件,适用于IOS和Android平台。他可以打开网页,发送邮件,还可以拨打电话。
github地址:https://github.com/flutter/plugins/tree/master/packages/url_launcher
最近项目需求就是打开一个连接跳转到安卓或苹果默认的浏览器。虽然开始一个简单的要求,其中的一个细节就是执行打开网页这一操作后,不能看上去像在应用内部打开,看上去要在应用外部打开。pub.dev 提供了加载网页的插件url_launcher;所谓的插件也是用安卓和苹果原生代码实现的,对插件的代码进行解压可以看到。
加载网页的方式:
_launchURL() async { const url = '要加载的网页地址'; if (await canLaunch(url)) { await launch(url); } }
简单查看一下插件的源码:
Future<bool> launch( String urlString, { bool forceSafariVC, bool forceWebView, bool enableJavaScript, bool enableDomStorage, bool universalLinksOnly, Map<String, String> headers, Brightness statusBarBrightness, }) async { assert(urlString != null); ........................................
属性:forceSafariVC
/// [forceSafariVC] is only used in iOS with iOS version >= 9.0. By default (when unset), the launcher /// opens web URLs in the Safari View Controller, anything else is opened /// using the default handler on the platform. If set to true, it opens the /// URL in the Safari View Controller. If false, the URL is opened in the /// default browser of the phone. Note that to work with universal links on iOS, /// this must be set to false to let the platform's system handle the URL. /// Set this to false if you want to use the cookies/context of the main browser /// of the app (such as SSO flows). This setting will nullify [universalLinksOnly] /// and will always launch a web content in the built-in Safari View Controller regardless /// if the url is a universal link or not.
forceSafariVC 仅被用于IOS版本为0.9和0.9以上的系统。默认情况下不设置,如果设置加载网页连接在Safari视图控制器打开,其他操作系统打开使用默认设置。如果设置为true,在Safari视图控制器打开URL。如果设置为false,在手机默认浏览器中打开。注意网页连接在IOS 平台操作系统上打开必须设置为false。如果你想去用cookies在app网页端实现登录需要设置为false。
如果加载在内置Safari视图控制器的网页内容是universal link或不是,设置universalLinksOnly无效。
Universal Link:(点击连接打开应用)参考、参考
属性:forceWebView
/// [forceWebView] is an Android only setting. If null or false, the URL is /// always launched with the default browser on device. If set to true, the URL /// is launched in a WebView. Unlike iOS, browser context is shared across /// WebViews.
该属性只在安卓平台设置。如果设置为false或不设置,网络地址被加载在设备默认浏览器。如果设置为true,网络地址被加载在自定义WebView。ios系统的浏览器可以共享数据。
属性:enableJavaScript
/// [enableJavaScript] is an Android only setting. If true, WebView enable /// javascript.
该属性只在安卓平台设置。如果为true,webview可加载脚步。
属性:enableDomStorage
/// [enableDomStorage] is an Android only setting. If true, WebView enable /// DOM storage.
该属性只在安卓平台设置。如果为true,webView加载本地网页缓存。
属性:universalLinksOnly
/// [universalLinksOnly] is only used in iOS with iOS version >= 10.0. This setting is only validated /// when [forceSafariVC] is set to false. The default value of this setting is false. /// By default (when unset), the launcher will either launch the url in a browser (when the /// url is not a universal link), or launch the respective native app content (when /// the url is a universal link). When set to true, the launcher will only launch /// the content if the url is a universal link and the respective app for the universal /// link is installed on the user's device; otherwise throw a [PlatformException].
该属性只在IOS平台使用并且IOS版本为10.0或10.0以上。当前该属性设置成false生效。默认值是false。默认情况下,通过手机手机浏览器加载网页(当这个链接不是一个universal link)或 加载各自app(当这个链接是一个universal link,点击进行下载应用包)。如果设置属性值为true,如果这个连接是一个universal link并且各自的应用通过这个universal link安装在用户的设备上,那么改网页会被加载。否则抛出PlatformException。
属性:statusBarBrightness
/// [statusBarBrightness] Sets the status bar brightness of the application /// after opening a link on iOS. Does nothing if no value is passed. This does /// not handle resetting the previous status bar style.
设置的状态栏亮度在IOS应用打开一个连接后可以看到。如果没有设置该属性不会有效果的。状态栏样式重复设置以第一次设置为准。
Future<bool> launch( String urlString, { bool forceSafariVC, bool forceWebView, bool enableJavaScript, bool enableDomStorage, bool universalLinksOnly, Map<String, String> headers, Brightness statusBarBrightness, }) async { assert(urlString != null); final Uri url = Uri.parse(urlString.trimLeft()); final bool isWebURL = url.scheme == 'http' || url.scheme == 'https'; if ((forceSafariVC == true || forceWebView == true) && !isWebURL) { throw PlatformException( code: 'NOT_A_WEB_SCHEME', message: 'To use webview or safariVC, you need to pass' 'in a web URL. This $urlString is not a web URL.'); } bool previousAutomaticSystemUiAdjustment; if (statusBarBrightness != null && defaultTargetPlatform == TargetPlatform.iOS) { previousAutomaticSystemUiAdjustment = WidgetsBinding.instance.renderView.automaticSystemUiAdjustment; WidgetsBinding.instance.renderView.automaticSystemUiAdjustment = true; SystemChrome.setSystemUIOverlayStyle(statusBarBrightness == Brightness.light ? SystemUiOverlayStyle.dark : SystemUiOverlayStyle.light); } final bool result = await UrlLauncherPlatform.instance.launch( urlString, useSafariVC: forceSafariVC ?? isWebURL, useWebView: forceWebView ?? false, enableJavaScript: enableJavaScript ?? false, enableDomStorage: enableDomStorage ?? false, universalLinksOnly: universalLinksOnly ?? false, headers: headers ?? <String, String>{}, ); if (statusBarBrightness != null) { WidgetsBinding.instance.renderView.automaticSystemUiAdjustment = previousAutomaticSystemUiAdjustment; } return result; }
安卓或苹果平台加载:
实现让用户看到不少应用内部跳转打开网页加载,是跳转到手机默认浏览器加载。
if (Platform.isIOS) { launch(url, forceSafariVC: false, forceWebView: true); return; } if (Platform.isAndroid) { launch(url); }
解压插件源码可以看到Flutter就是调用安卓或者ios原生代码进行加载网页。
安卓中通过webview加载网页或者跳转默认浏览器加载网页:
LaunchStatus launch( String url, Bundle headersBundle, boolean useWebView, boolean enableJavaScript, boolean enableDomStorage) { if (activity == null) { return LaunchStatus.NO_ACTIVITY; } Intent launchIntent; if (useWebView) { launchIntent = WebViewActivity.createIntent( activity, url, enableJavaScript, enableDomStorage, headersBundle); } else { launchIntent = new Intent(Intent.ACTION_VIEW) .setData(Uri.parse(url)) .putExtra(Browser.EXTRA_HEADERS, headersBundle); } activity.startActivity(launchIntent); return LaunchStatus.OK; }
在ios手机中默认浏览器打开
- (void)launchURLInVC:(NSString *)urlString result:(FlutterResult)result API_AVAILABLE(ios(9.0)) { NSURL *url = [NSURL URLWithString:urlString]; self.currentSession = [[FLTURLLaunchSession alloc] initWithUrl:url withFlutterResult:result]; __weak typeof(self) weakSelf = self; self.currentSession.didFinish = ^(void) { weakSelf.currentSession = nil; }; [self.topViewController presentViewController:self.currentSession.safari animated:YES completion:nil]; }
在ios中用内置浏览器打开:
- (void)launchURL:(NSString *)urlString call:(FlutterMethodCall *)call result:(FlutterResult)result { NSURL *url = [NSURL URLWithString:urlString]; UIApplication *application = [UIApplication sharedApplication]; if (@available(iOS 10.0, *)) { NSNumber *universalLinksOnly = call.arguments[@"universalLinksOnly"] ?: @0; NSDictionary *options = @{UIApplicationOpenURLOptionUniversalLinksOnly : universalLinksOnly}; [application openURL:url options:options completionHandler:^(BOOL success) { result(@(success)); }]; } else { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" BOOL success = [application openURL:url]; #pragma clang diagnostic pop result(@(success)); } }
如果在安卓或者苹果加载http网页出现无法加载:
///安卓:在xml文件夹下创建network_security_config.xml ,然后在AndroidManifest.xml 标签application引用
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true"> <trust-anchors> <certificates src="system" /> </trust-anchors> </base-config> </network-security-config> ///IOS:
参考:
Android WebView:https://developer.android.google.cn/guide/webapps/webview?hl=zh_cn
SafariServices:https://developer.apple.com/documentation/safariservices