blob: f28c460cce4f5b854c9b85a209732f23c30cda79 [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 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
/// Parses the specified URL string and delegates handling of it to the
/// underlying platform.
///
/// The returned future completes with a [PlatformException] on invalid URLs and
/// schemes which cannot be handled, that is when [canLaunch] would complete
/// with false.
///
/// By default when [forceSafariVC] is 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.
///
/// [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].
///
/// [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.
/// [enableJavaScript] is an Android only setting. If true, WebView enable
/// javascript.
/// [enableDomStorage] is an Android only setting. If true, WebView enable
/// DOM storage.
/// [headers] is an Android only setting that adds headers to the WebView.
/// When not using a WebView, the header information is passed to the browser,
/// some Android browsers do not support the [Browser.EXTRA_HEADERS](https://developer.android.com/reference/android/provider/Browser#EXTRA_HEADERS)
/// intent extra and the header information will be lost.
/// [webOnlyWindowName] is an Web only setting . _blank opens the new url in new tab ,
/// _self opens the new url in current tab.
/// Default behaviour is to open the url in new tab.
///
/// Note that if any of the above are set to true but the URL is not a web URL,
/// this will throw a [PlatformException].
///
/// [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.
///
/// Returns true if launch url is successful; false is only returned when [universalLinksOnly]
/// is set to true and the universal link failed to launch.
Future<bool> launch(
String urlString, {
bool? forceSafariVC,
bool forceWebView = false,
bool enableJavaScript = false,
bool enableDomStorage = false,
bool universalLinksOnly = false,
Map<String, String> headers = const <String, String>{},
Brightness? statusBarBrightness,
String? webOnlyWindowName,
}) async {
final Uri? url = Uri.tryParse(urlString.trimLeft());
final bool isWebURL =
url != null && (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.');
}
/// [true] so that ui is automatically computed if [statusBarBrightness] is set.
bool previousAutomaticSystemUiAdjustment = true;
if (statusBarBrightness != null &&
defaultTargetPlatform == TargetPlatform.iOS &&
_ambiguate(WidgetsBinding.instance) != null) {
previousAutomaticSystemUiAdjustment = _ambiguate(WidgetsBinding.instance)!
.renderView
.automaticSystemUiAdjustment;
_ambiguate(WidgetsBinding.instance)!
.renderView
.automaticSystemUiAdjustment = false;
SystemChrome.setSystemUIOverlayStyle(statusBarBrightness == Brightness.light
? SystemUiOverlayStyle.dark
: SystemUiOverlayStyle.light);
}
final bool result = await UrlLauncherPlatform.instance.launch(
urlString,
useSafariVC: forceSafariVC ?? isWebURL,
useWebView: forceWebView,
enableJavaScript: enableJavaScript,
enableDomStorage: enableDomStorage,
universalLinksOnly: universalLinksOnly,
headers: headers,
webOnlyWindowName: webOnlyWindowName,
);
if (statusBarBrightness != null &&
_ambiguate(WidgetsBinding.instance) != null) {
_ambiguate(WidgetsBinding.instance)!
.renderView
.automaticSystemUiAdjustment = previousAutomaticSystemUiAdjustment;
}
return result;
}
/// Checks whether the specified URL can be handled by some app installed on the
/// device.
///
/// On some systems, such as recent versions of Android and iOS, this will
/// always return false unless the application has been configuration to allow
/// querying the system for launch support. See
/// [the README](https://pub.dev/packages/url_launcher#configuration) for
/// details.
Future<bool> canLaunch(String urlString) async {
return await UrlLauncherPlatform.instance.canLaunch(urlString);
}
/// Closes the current WebView, if one was previously opened via a call to [launch].
///
/// If [launch] was never called, then this call will not have any effect.
///
/// On Android systems, if [launch] was called without `forceWebView` being set to `true`
/// Or on IOS systems, if [launch] was called without `forceSafariVC` being set to `true`,
/// this call will not do anything either, simply because there is no
/// WebView/SafariViewController available to be closed.
Future<void> closeWebView() async {
return await UrlLauncherPlatform.instance.closeWebView();
}
/// This allows a value of type T or T? to be treated as a value of type T?.
///
/// We use this so that APIs that have become non-nullable can still be used
/// with `!` and `?` on the stable branch.
// TODO(ianh): Remove this once we roll stable in late 2021.
T? _ambiguate<T>(T? value) => value;