platform_interface.dart 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. // Copyright 2019 The Chromium 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 'dart:async';
  5. import 'package:flutter/foundation.dart';
  6. import 'package:flutter/gestures.dart';
  7. import 'package:flutter/widgets.dart';
  8. import 'webview_flutter.dart';
  9. /// Interface for callbacks made by [WebViewPlatformController].
  10. ///
  11. /// The webview plugin implements this class, and passes an instance to the [WebViewPlatformController].
  12. /// [WebViewPlatformController] is notifying this handler on events that happened on the platform's webview.
  13. abstract class WebViewPlatformCallbacksHandler {
  14. /// Invoked by [WebViewPlatformController] when a JavaScript channel message is received.
  15. void onJavaScriptChannelMessage(String channel, String message);
  16. /// Invoked by [WebViewPlatformController] when a navigation request is pending.
  17. ///
  18. /// If true is returned the navigation is allowed, otherwise it is blocked.
  19. FutureOr<bool> onNavigationRequest({String url, bool isForMainFrame});
  20. /// Invoked by [WebViewPlatformController] when a page has started loading.
  21. void onPageStarted(String url);
  22. /// Invoked by [WebViewPlatformController] when a page has finished loading.
  23. void onPageFinished(String url);
  24. }
  25. /// Interface for talking to the webview's platform implementation.
  26. ///
  27. /// An instance implementing this interface is passed to the `onWebViewPlatformCreated` callback that is
  28. /// passed to [WebViewPlatformBuilder#onWebViewPlatformCreated].
  29. ///
  30. /// Platform implementations that live in a separate package should extend this class rather than
  31. /// implement it as webview_flutter does not consider newly added methods to be breaking changes.
  32. /// Extending this class (using `extends`) ensures that the subclass will get the default
  33. /// implementation, while platform implementations that `implements` this interface will be broken
  34. /// by newly added [WebViewPlatformController] methods.
  35. abstract class WebViewPlatformController {
  36. /// Creates a new WebViewPlatform.
  37. ///
  38. /// Callbacks made by the WebView will be delegated to `handler`.
  39. ///
  40. /// The `handler` parameter must not be null.
  41. WebViewPlatformController(WebViewPlatformCallbacksHandler handler);
  42. /// Loads the specified URL.
  43. ///
  44. /// If `headers` is not null and the URL is an HTTP URL, the key value paris in `headers` will
  45. /// be added as key value pairs of HTTP headers for the request.
  46. ///
  47. /// `url` must not be null.
  48. ///
  49. /// Throws an ArgumentError if `url` is not a valid URL string.
  50. Future<void> loadUrl(
  51. String url,
  52. Map<String, String> headers,
  53. ) {
  54. throw UnimplementedError(
  55. "WebView loadUrl is not implemented on the current platform");
  56. }
  57. /// Updates the webview settings.
  58. ///
  59. /// Any non null field in `settings` will be set as the new setting value.
  60. /// All null fields in `settings` are ignored.
  61. Future<void> updateSettings(WebSettings setting) {
  62. throw UnimplementedError(
  63. "WebView updateSettings is not implemented on the current platform");
  64. }
  65. /// Accessor to the current URL that the WebView is displaying.
  66. ///
  67. /// If no URL was ever loaded, returns `null`.
  68. Future<String> currentUrl() {
  69. throw UnimplementedError(
  70. "WebView currentUrl is not implemented on the current platform");
  71. }
  72. /// Checks whether there's a back history item.
  73. Future<bool> canGoBack() {
  74. throw UnimplementedError(
  75. "WebView canGoBack is not implemented on the current platform");
  76. }
  77. /// Checks whether there's a forward history item.
  78. Future<bool> canGoForward() {
  79. throw UnimplementedError(
  80. "WebView canGoForward is not implemented on the current platform");
  81. }
  82. /// Goes back in the history of this WebView.
  83. ///
  84. /// If there is no back history item this is a no-op.
  85. Future<void> goBack() {
  86. throw UnimplementedError(
  87. "WebView goBack is not implemented on the current platform");
  88. }
  89. /// Goes forward in the history of this WebView.
  90. ///
  91. /// If there is no forward history item this is a no-op.
  92. Future<void> goForward() {
  93. throw UnimplementedError(
  94. "WebView goForward is not implemented on the current platform");
  95. }
  96. /// Reloads the current URL.
  97. Future<void> reload() {
  98. throw UnimplementedError(
  99. "WebView reload is not implemented on the current platform");
  100. }
  101. /// Clears all caches used by the [WebView].
  102. ///
  103. /// The following caches are cleared:
  104. /// 1. Browser HTTP Cache.
  105. /// 2. [Cache API](https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/cache-api) caches.
  106. /// These are not yet supported in iOS WkWebView. Service workers tend to use this cache.
  107. /// 3. Application cache.
  108. /// 4. Local Storage.
  109. Future<void> clearCache() {
  110. throw UnimplementedError(
  111. "WebView clearCache is not implemented on the current platform");
  112. }
  113. /// Evaluates a JavaScript expression in the context of the current page.
  114. ///
  115. /// The Future completes with an error if a JavaScript error occurred, or if the type of the
  116. /// evaluated expression is not supported(e.g on iOS not all non primitive type can be evaluated).
  117. Future<String> evaluateJavascript(String javascriptString) {
  118. throw UnimplementedError(
  119. "WebView evaluateJavascript is not implemented on the current platform");
  120. }
  121. /// Adds new JavaScript channels to the set of enabled channels.
  122. ///
  123. /// For each value in this list the platform's webview should make sure that a corresponding
  124. /// property with a postMessage method is set on `window`. For example for a JavaScript channel
  125. /// named `Foo` it should be possible for JavaScript code executing in the webview to do
  126. ///
  127. /// ```javascript
  128. /// Foo.postMessage('hello');
  129. /// ```
  130. ///
  131. /// See also: [CreationParams.javascriptChannelNames].
  132. Future<void> addJavascriptChannels(Set<String> javascriptChannelNames) {
  133. throw UnimplementedError(
  134. "WebView addJavascriptChannels is not implemented on the current platform");
  135. }
  136. /// Removes JavaScript channel names from the set of enabled channels.
  137. ///
  138. /// This disables channels that were previously enabled by [addJavaScriptChannels] or through
  139. /// [CreationParams.javascriptChannelNames].
  140. Future<void> removeJavascriptChannels(Set<String> javascriptChannelNames) {
  141. throw UnimplementedError(
  142. "WebView removeJavascriptChannels is not implemented on the current platform");
  143. }
  144. /// Returns the title of the currently loaded page.
  145. Future<String> getTitle() {
  146. throw UnimplementedError(
  147. "WebView getTitle is not implemented on the current platform");
  148. }
  149. }
  150. /// A single setting for configuring a WebViewPlatform which may be absent.
  151. class WebSetting<T> {
  152. /// Constructs an absent setting instance.
  153. ///
  154. /// The [isPresent] field for the instance will be false.
  155. ///
  156. /// Accessing [value] for an absent instance will throw.
  157. WebSetting.absent()
  158. : _value = null,
  159. isPresent = false;
  160. /// Constructs a setting of the given `value`.
  161. ///
  162. /// The [isPresent] field for the instance will be true.
  163. WebSetting.of(T value)
  164. : _value = value,
  165. isPresent = true;
  166. final T _value;
  167. /// The setting's value.
  168. ///
  169. /// Throws if [WebSetting.isPresent] is false.
  170. T get value {
  171. if (!isPresent) {
  172. throw StateError('Cannot access a value of an absent WebSetting');
  173. }
  174. assert(isPresent);
  175. return _value;
  176. }
  177. /// True when this web setting instance contains a value.
  178. ///
  179. /// When false the [WebSetting.value] getter throws.
  180. final bool isPresent;
  181. @override
  182. bool operator ==(Object other) {
  183. if (other.runtimeType != runtimeType) return false;
  184. final WebSetting<T> typedOther = other;
  185. return typedOther.isPresent == isPresent && typedOther._value == _value;
  186. }
  187. @override
  188. int get hashCode => hashValues(_value, isPresent);
  189. }
  190. /// Settings for configuring a WebViewPlatform.
  191. ///
  192. /// Initial settings are passed as part of [CreationParams], settings updates are sent with
  193. /// [WebViewPlatform#updateSettings].
  194. ///
  195. /// The `userAgent` parameter must not be null.
  196. class WebSettings {
  197. /// Construct an instance with initial settings. Future setting changes can be
  198. /// sent with [WebviewPlatform#updateSettings].
  199. ///
  200. /// The `userAgent` parameter must not be null.
  201. WebSettings({
  202. this.javascriptMode,
  203. this.hasNavigationDelegate,
  204. this.debuggingEnabled,
  205. this.gestureNavigationEnabled,
  206. @required this.userAgent,
  207. }) : assert(userAgent != null);
  208. /// The JavaScript execution mode to be used by the webview.
  209. final JavascriptMode javascriptMode;
  210. /// Whether the [WebView] has a [NavigationDelegate] set.
  211. final bool hasNavigationDelegate;
  212. /// Whether to enable the platform's webview content debugging tools.
  213. ///
  214. /// See also: [WebView.debuggingEnabled].
  215. final bool debuggingEnabled;
  216. /// The value used for the HTTP `User-Agent:` request header.
  217. ///
  218. /// If [userAgent.value] is null the platform's default user agent should be used.
  219. ///
  220. /// An absent value ([userAgent.isPresent] is false) represents no change to this setting from the
  221. /// last time it was set.
  222. ///
  223. /// See also [WebView.userAgent].
  224. final WebSetting<String> userAgent;
  225. /// Whether to allow swipe based navigation in iOS.
  226. ///
  227. /// See also: [WebView.gestureNavigationEnabled]
  228. final bool gestureNavigationEnabled;
  229. @override
  230. String toString() {
  231. return 'WebSettings(javascriptMode: $javascriptMode, hasNavigationDelegate: $hasNavigationDelegate, debuggingEnabled: $debuggingEnabled, gestureNavigationEnabled: $gestureNavigationEnabled, userAgent: $userAgent)';
  232. }
  233. }
  234. /// Configuration to use when creating a new [WebViewPlatformController].
  235. ///
  236. /// The `autoMediaPlaybackPolicy` parameter must not be null.
  237. class CreationParams {
  238. /// Constructs an instance to use when creating a new
  239. /// [WebViewPlatformController].
  240. ///
  241. /// The `autoMediaPlaybackPolicy` parameter must not be null.
  242. CreationParams({
  243. this.initialUrl,
  244. this.webSettings,
  245. this.javascriptChannelNames,
  246. this.userAgent,
  247. this.autoMediaPlaybackPolicy =
  248. AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
  249. }) : assert(autoMediaPlaybackPolicy != null);
  250. /// The initialUrl to load in the webview.
  251. ///
  252. /// When null the webview will be created without loading any page.
  253. final String initialUrl;
  254. /// The initial [WebSettings] for the new webview.
  255. ///
  256. /// This can later be updated with [WebViewPlatformController.updateSettings].
  257. final WebSettings webSettings;
  258. /// The initial set of JavaScript channels that are configured for this webview.
  259. ///
  260. /// For each value in this set the platform's webview should make sure that a corresponding
  261. /// property with a postMessage method is set on `window`. For example for a JavaScript channel
  262. /// named `Foo` it should be possible for JavaScript code executing in the webview to do
  263. ///
  264. /// ```javascript
  265. /// Foo.postMessage('hello');
  266. /// ```
  267. // TODO(amirh): describe what should happen when postMessage is called once that code is migrated
  268. // to PlatformWebView.
  269. final Set<String> javascriptChannelNames;
  270. /// The value used for the HTTP User-Agent: request header.
  271. ///
  272. /// When null the platform's webview default is used for the User-Agent header.
  273. final String userAgent;
  274. /// Which restrictions apply on automatic media playback.
  275. final AutoMediaPlaybackPolicy autoMediaPlaybackPolicy;
  276. @override
  277. String toString() {
  278. return '$runtimeType(initialUrl: $initialUrl, settings: $webSettings, javascriptChannelNames: $javascriptChannelNames, UserAgent: $userAgent)';
  279. }
  280. }
  281. typedef WebViewPlatformCreatedCallback = void Function(
  282. WebViewPlatformController webViewPlatformController);
  283. /// Interface for a platform implementation of a WebView.
  284. ///
  285. /// [WebView.platform] controls the builder that is used by [WebView].
  286. /// [AndroidWebViewPlatform] and [CupertinoWebViewPlatform] are the default implementations
  287. /// for Android and iOS respectively.
  288. abstract class WebViewPlatform {
  289. /// Builds a new WebView.
  290. ///
  291. /// Returns a Widget tree that embeds the created webview.
  292. ///
  293. /// `creationParams` are the initial parameters used to setup the webview.
  294. ///
  295. /// `webViewPlatformHandler` will be used for handling callbacks that are made by the created
  296. /// [WebViewPlatformController].
  297. ///
  298. /// `onWebViewPlatformCreated` will be invoked after the platform specific [WebViewPlatformController]
  299. /// implementation is created with the [WebViewPlatformController] instance as a parameter.
  300. ///
  301. /// `gestureRecognizers` specifies which gestures should be consumed by the web view.
  302. /// It is possible for other gesture recognizers to be competing with the web view on pointer
  303. /// events, e.g if the web view is inside a [ListView] the [ListView] will want to handle
  304. /// vertical drags. The web view will claim gestures that are recognized by any of the
  305. /// recognizers on this list.
  306. /// When `gestureRecognizers` is empty or null, the web view will only handle pointer events for gestures that
  307. /// were not claimed by any other gesture recognizer.
  308. ///
  309. /// `webViewPlatformHandler` must not be null.
  310. Widget build({
  311. BuildContext context,
  312. // TODO(amirh): convert this to be the actual parameters.
  313. // I'm starting without it as the PR is starting to become pretty big.
  314. // I'll followup with the conversion PR.
  315. CreationParams creationParams,
  316. @required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler,
  317. WebViewPlatformCreatedCallback onWebViewPlatformCreated,
  318. Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers,
  319. });
  320. /// Clears all cookies for all [WebView] instances.
  321. ///
  322. /// Returns true if cookies were present before clearing, else false.
  323. Future<bool> clearCookies() {
  324. throw UnimplementedError(
  325. "WebView clearCookies is not implemented on the current platform");
  326. }
  327. }