blob: bf96bf2aa29342d69255a9fd7f1d12a72c2b16f8 [file] [log] [blame]
// 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 'dart:ui_web' as ui_web;
import 'package:flutter/foundation.dart' show kDebugMode, visibleForTesting;
import 'package:flutter_web_plugins/flutter_web_plugins.dart' show Registrar;
import 'package:url_launcher_platform_interface/link.dart';
import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
import 'src/link.dart';
const Set<String> _safariTargetTopSchemes = <String>{
String? _getUrlScheme(String url) => Uri.tryParse(url)?.scheme;
bool _isSafariTargetTopScheme(String? scheme) =>
// The set of schemes that are explicitly disallowed by the plugin.
const Set<String> _disallowedSchemes = <String>{
bool _isDisallowedScheme(String? scheme) => _disallowedSchemes.contains(scheme);
bool _navigatorIsSafari(html.Navigator navigator) =>
navigator.userAgent.contains('Safari') &&
/// The web implementation of [UrlLauncherPlatform].
/// This class implements the `package:url_launcher` functionality for the web.
class UrlLauncherPlugin extends UrlLauncherPlatform {
/// 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);
final html.Window _window;
bool _isSafari = false;
// The set of schemes that can be handled by the plugin.
static final Set<String> _supportedSchemes = <String>{
/// Registers this class as the default instance of [UrlLauncherPlatform].
static void registerWith(Registrar registrar) {
UrlLauncherPlatform.instance = UrlLauncherPlugin();
.registerViewFactory(linkViewType, linkViewFactory, isVisible: false);
LinkDelegate get linkDelegate {
return (LinkInfo linkInfo) => WebLinkDelegate(linkInfo);
/// Opens the given [url] in the specified [webOnlyWindowName].
/// Returns the newly created window.
html.WindowBase? openNewWindow(String url, {String? webOnlyWindowName}) {
final String? scheme = _getUrlScheme(url);
// Actively disallow opening some schemes, like javascript.
// See
if (_isDisallowedScheme(scheme)) {
if (kDebugMode) {
print('Disallowed URL with scheme: $scheme');
return null;
// Some schemes need to be opened on the _top window context on Safari.
// See
final String target = webOnlyWindowName ??
((_isSafari && _isSafariTargetTopScheme(scheme)) ? '_top' : '');
// ignore: unsafe_html
return, target, 'noopener,noreferrer');
Future<bool> canLaunch(String url) {
return Future<bool>.value(_supportedSchemes.contains(_getUrlScheme(url)));
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,
}) async {
return launchUrl(url, LaunchOptions(webOnlyWindowName: webOnlyWindowName));
Future<bool> launchUrl(String url, LaunchOptions options) async {
final String? windowName = options.webOnlyWindowName;
return openNewWindow(url, webOnlyWindowName: windowName) != null;