You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

173 rivejä
5.7 KiB

  1. // Copyright 2013 The Flutter Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. import 'package:flutter/foundation.dart' show visibleForTesting;
  5. import 'package:flutter/services.dart';
  6. import 'package:url_launcher_platform_interface/link.dart';
  7. import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
  8. import 'src/messages.g.dart';
  9. /// An implementation of [UrlLauncherPlatform] for iOS.
  10. class UrlLauncherIOS extends UrlLauncherPlatform {
  11. /// Creates a new plugin implementation instance.
  12. UrlLauncherIOS({
  13. @visibleForTesting UrlLauncherApi? api,
  14. }) : _hostApi = api ?? UrlLauncherApi();
  15. final UrlLauncherApi _hostApi;
  16. /// Registers this class as the default instance of [UrlLauncherPlatform].
  17. static void registerWith() {
  18. UrlLauncherPlatform.instance = UrlLauncherIOS();
  19. }
  20. @override
  21. final LinkDelegate? linkDelegate = null;
  22. @override
  23. Future<bool> canLaunch(String url) async {
  24. final LaunchResult result = await _hostApi.canLaunchUrl(url);
  25. return _mapLaunchResult(result);
  26. }
  27. @override
  28. Future<void> closeWebView() {
  29. return _hostApi.closeSafariViewController();
  30. }
  31. @override
  32. Future<bool> launch(
  33. String url, {
  34. required bool useSafariVC,
  35. required bool useWebView,
  36. required bool enableJavaScript,
  37. required bool enableDomStorage,
  38. required bool universalLinksOnly,
  39. required Map<String, String> headers,
  40. String? webOnlyWindowName,
  41. }) async {
  42. final PreferredLaunchMode mode;
  43. if (useSafariVC) {
  44. mode = PreferredLaunchMode.inAppBrowserView;
  45. } else if (universalLinksOnly) {
  46. mode = PreferredLaunchMode.externalNonBrowserApplication;
  47. } else {
  48. mode = PreferredLaunchMode.externalApplication;
  49. }
  50. return launchUrl(
  51. url,
  52. LaunchOptions(
  53. mode: mode,
  54. webViewConfiguration: InAppWebViewConfiguration(
  55. enableDomStorage: enableDomStorage,
  56. enableJavaScript: enableJavaScript,
  57. headers: headers)));
  58. }
  59. @override
  60. Future<bool> launchUrl(String url, LaunchOptions options) async {
  61. final bool inApp;
  62. switch (options.mode) {
  63. case PreferredLaunchMode.inAppWebView:
  64. case PreferredLaunchMode.inAppBrowserView:
  65. // The iOS implementation doesn't distinguish between these two modes;
  66. // both are treated as inAppBrowserView.
  67. inApp = true;
  68. case PreferredLaunchMode.externalApplication:
  69. case PreferredLaunchMode.externalNonBrowserApplication:
  70. inApp = false;
  71. case PreferredLaunchMode.platformDefault:
  72. // Intentionally treat any new values as platformDefault; support for any
  73. // new mode requires intentional opt-in, otherwise falling back is the
  74. // documented behavior.
  75. // ignore: no_default_cases, unreachable_switch_default
  76. default:
  77. // By default, open web URLs in the application.
  78. inApp = url.startsWith('http:') || url.startsWith('https:');
  79. }
  80. if (inApp) {
  81. return _mapInAppLoadResult(
  82. await _hostApi.openUrlInSafariViewController(url),
  83. url: url);
  84. } else {
  85. return _mapLaunchResult(await _hostApi.launchUrl(url,
  86. options.mode == PreferredLaunchMode.externalNonBrowserApplication));
  87. }
  88. }
  89. @override
  90. Future<bool> supportsMode(PreferredLaunchMode mode) async {
  91. switch (mode) {
  92. case PreferredLaunchMode.platformDefault:
  93. case PreferredLaunchMode.inAppWebView:
  94. case PreferredLaunchMode.inAppBrowserView:
  95. case PreferredLaunchMode.externalApplication:
  96. case PreferredLaunchMode.externalNonBrowserApplication:
  97. return true;
  98. // Default is a desired behavior here since support for new modes is
  99. // always opt-in, and the enum lives in a different package, so silently
  100. // adding "false" for new values is the correct behavior.
  101. // ignore: no_default_cases, unreachable_switch_default
  102. default:
  103. return false;
  104. }
  105. }
  106. @override
  107. Future<bool> supportsCloseForMode(PreferredLaunchMode mode) async {
  108. return mode == PreferredLaunchMode.inAppWebView ||
  109. mode == PreferredLaunchMode.inAppBrowserView;
  110. }
  111. bool _mapLaunchResult(LaunchResult result) {
  112. switch (result) {
  113. case LaunchResult.success:
  114. return true;
  115. case LaunchResult.failure:
  116. return false;
  117. case LaunchResult.invalidUrl:
  118. throw _invalidUrlException();
  119. }
  120. }
  121. bool _mapInAppLoadResult(InAppLoadResult result, {required String url}) {
  122. switch (result) {
  123. case InAppLoadResult.success:
  124. return true;
  125. case InAppLoadResult.failedToLoad:
  126. throw _failedSafariViewControllerLoadException(url);
  127. case InAppLoadResult.invalidUrl:
  128. throw _invalidUrlException();
  129. }
  130. }
  131. // TODO(stuartmorgan): Remove this as part of standardizing error handling.
  132. // See https://github.com/flutter/flutter/issues/127665
  133. //
  134. // This PlatformException (including the exact string details, since those
  135. // are a defacto part of the API) is for compatibility with the previous
  136. // native implementation.
  137. PlatformException _invalidUrlException() {
  138. throw PlatformException(
  139. code: 'argument_error',
  140. message: 'Unable to parse URL',
  141. );
  142. }
  143. // TODO(stuartmorgan): Remove this as part of standardizing error handling.
  144. // See https://github.com/flutter/flutter/issues/127665
  145. //
  146. // This PlatformException (including the exact string details, since those
  147. // are a defacto part of the API) is for compatibility with the previous
  148. // native implementation.
  149. PlatformException _failedSafariViewControllerLoadException(String url) {
  150. throw PlatformException(
  151. code: 'Error',
  152. message: 'Error while launching $url',
  153. );
  154. }
  155. }