Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 4ec6e57

Browse files
[webview_flutter_wkwebview] Add WKWebView method stubs (#4990)
1 parent 431cac9 commit 4ec6e57

File tree

6 files changed

+810
-85
lines changed

6 files changed

+810
-85
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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+
5+
import 'dart:async';
6+
import 'dart:math';
7+
8+
import '../web_kit/web_kit.dart';
9+
10+
/// A view that allows the scrolling and zooming of its contained views.
11+
///
12+
/// Wraps [UIScrollView](https://developer.apple.com/documentation/uikit/uiscrollview?language=objc).
13+
class UIScrollView {
14+
/// Constructs a [UIScrollView] that is owned by [webView].
15+
// TODO(bparrishMines): Remove ignore once constructor is implemented.
16+
// ignore: avoid_unused_constructor_parameters
17+
UIScrollView.fromWebView(WKWebView webView);
18+
19+
/// Point at which the origin of the content view is offset from the origin of the scroll view.
20+
Future<Point<double>> get contentOffset {
21+
throw UnimplementedError();
22+
}
23+
24+
/// Move the scrolled position of this view.
25+
///
26+
/// This method is not a part of UIKit and is only a helper method to make
27+
/// scrollBy atomic.
28+
Future<void> scrollBy(Point<double> offset) {
29+
throw UnimplementedError();
30+
}
31+
32+
/// Set point at which the origin of the content view is offset from the origin of the scroll view.
33+
///
34+
/// The default value is `Point<double>(0.0, 0.0)`.
35+
set contentOffset(FutureOr<Point<double>> offset) {
36+
throw UnimplementedError();
37+
}
38+
}

packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit.dart

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'package:flutter/foundation.dart';
66

77
import '../foundation/foundation.dart';
8+
import '../ui_kit/ui_kit.dart';
89

910
/// Times at which to inject script content into a webpage.
1011
///
@@ -450,6 +451,9 @@ class WKWebView {
450451
late final WKWebViewConfiguration configuration =
451452
WKWebViewConfiguration._fromWebView(this);
452453

454+
/// The scrollable view associated with the web view.
455+
late final UIScrollView scrollView = UIScrollView.fromWebView(this);
456+
453457
/// Used to integrate custom user interface elements into web view interactions.
454458
set uiDelegate(WKUIDelegate? delegate) {
455459
throw UnimplementedError();
@@ -472,4 +476,79 @@ class WKWebView {
472476
Future<void> loadRequest(NSUrlRequest request) {
473477
throw UnimplementedError();
474478
}
479+
480+
/// Loads the contents of the specified HTML string and navigates to it.
481+
Future<void> loadHtmlString(String string, {String? baseUrl}) {
482+
throw UnimplementedError();
483+
}
484+
485+
/// Loads the web content from the specified file and navigates to it.
486+
Future<void> loadFileUrl(String url, {required String readAccessUrl}) {
487+
throw UnimplementedError();
488+
}
489+
490+
/// Loads the Flutter asset specified in the pubspec.yaml file.
491+
///
492+
/// This method is not a part of WebKit and is only a Flutter specific helper
493+
/// method.
494+
Future<void> loadFlutterAsset(String key) {
495+
throw UnimplementedError();
496+
}
497+
498+
/// Indicates whether there is a valid back item in the back-forward list.
499+
Future<bool> get canGoBack {
500+
throw UnimplementedError();
501+
}
502+
503+
/// Indicates whether there is a valid forward item in the back-forward list.
504+
Future<bool> get canGoForward {
505+
throw UnimplementedError();
506+
}
507+
508+
/// Navigates to the back item in the back-forward list.
509+
Future<void> goBack() {
510+
throw UnimplementedError();
511+
}
512+
513+
/// Navigates to the forward item in the back-forward list.
514+
Future<void> goForward() {
515+
throw UnimplementedError();
516+
}
517+
518+
/// Reloads the current webpage.
519+
Future<void> reload() {
520+
throw UnimplementedError();
521+
}
522+
523+
/// The page title.
524+
Future<String?> get title {
525+
throw UnimplementedError();
526+
}
527+
528+
/// An estimate of what fraction of the current navigation has been loaded.
529+
Future<double> get estimatedProgress {
530+
throw UnimplementedError();
531+
}
532+
533+
/// Indicates whether horizontal swipe gestures trigger page navigation.
534+
///
535+
/// The default value is false.
536+
set allowsBackForwardNavigationGestures(bool allow) {
537+
throw UnimplementedError();
538+
}
539+
540+
/// The custom user agent string.
541+
///
542+
/// The default value of this property is null.
543+
set customUserAgent(String? userAgent) {
544+
throw UnimplementedError();
545+
}
546+
547+
/// Evaluates the specified JavaScript string.
548+
///
549+
/// Throws a `PlatformException` if an error occurs or return value is not
550+
/// supported.
551+
Future<Object?> evaluateJavaScript(String javaScriptString) {
552+
throw UnimplementedError();
553+
}
475554
}

packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit_webview_widget.dart

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
// found in the LICENSE file.
44

55
import 'dart:async';
6+
import 'dart:math';
67

78
import 'package:flutter/foundation.dart';
9+
import 'package:flutter/services.dart';
810
import 'package:flutter/widgets.dart';
11+
import 'package:path/path.dart' as path;
912
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
1013

1114
import 'foundation/foundation.dart';
@@ -194,6 +197,19 @@ class WebKitWebViewPlatformController extends WebViewPlatformController {
194197
};
195198
}
196199

200+
@override
201+
Future<void> loadHtmlString(String html, {String? baseUrl}) {
202+
return webView.loadHtmlString(html, baseUrl: baseUrl);
203+
}
204+
205+
@override
206+
Future<void> loadFile(String absoluteFilePath) async {
207+
await webView.loadFileUrl(
208+
absoluteFilePath,
209+
readAccessUrl: path.dirname(absoluteFilePath),
210+
);
211+
}
212+
197213
@override
198214
Future<void> clearCache() {
199215
return webView.configuration.webSiteDataStore.removeDataOfTypes(
@@ -207,6 +223,124 @@ class WebKitWebViewPlatformController extends WebViewPlatformController {
207223
);
208224
}
209225

226+
@override
227+
Future<void> loadFlutterAsset(String key) async {
228+
assert(key.isNotEmpty);
229+
return webView.loadFlutterAsset(key);
230+
}
231+
232+
@override
233+
Future<void> loadUrl(String url, Map<String, String>? headers) async {
234+
final NSUrlRequest request = NSUrlRequest(
235+
url: url,
236+
allHttpHeaderFields: headers ?? <String, String>{},
237+
);
238+
return webView.loadRequest(request);
239+
}
240+
241+
@override
242+
Future<void> loadRequest(WebViewRequest request) async {
243+
if (!request.uri.hasScheme) {
244+
throw ArgumentError('WebViewRequest#uri is required to have a scheme.');
245+
}
246+
247+
final NSUrlRequest urlRequest = NSUrlRequest(
248+
url: request.uri.toString(),
249+
allHttpHeaderFields: request.headers,
250+
httpMethod: describeEnum(request.method),
251+
httpBody: request.body,
252+
);
253+
254+
return webView.loadRequest(urlRequest);
255+
}
256+
257+
@override
258+
Future<bool> canGoBack() => webView.canGoBack;
259+
260+
@override
261+
Future<bool> canGoForward() => webView.canGoForward;
262+
263+
@override
264+
Future<void> goBack() => webView.goBack();
265+
266+
@override
267+
Future<void> goForward() => webView.goForward();
268+
269+
@override
270+
Future<void> reload() => webView.reload();
271+
272+
@override
273+
Future<String> evaluateJavascript(String javascript) async {
274+
final Object? result = await webView.evaluateJavaScript(javascript);
275+
// The legacy implementation of webview_flutter_wkwebview would convert
276+
// objects to strings before returning them to Dart. This method attempts
277+
// to converts Dart objects to Strings the way it is done in Objective-C
278+
// to avoid breaking users expecting the same String format.
279+
return _asObjectiveCString(result);
280+
}
281+
282+
@override
283+
Future<void> runJavascript(String javascript) async {
284+
try {
285+
await webView.evaluateJavaScript(javascript);
286+
} on PlatformException catch (exception) {
287+
// WebKit will throw an error when the type of the evaluated value is
288+
// unsupported. This also goes for `null` and `undefined` on iOS 14+. For
289+
// example, when running a void function. For ease of use, this specific
290+
// error is ignored when no return value is expected.
291+
// TODO(bparrishMines): Ensure the platform code includes the NSError in
292+
// the FlutterError.details.
293+
if (exception.details is! NSError ||
294+
exception.details.code !=
295+
WKErrorCode.javaScriptResultTypeIsUnsupported) {
296+
rethrow;
297+
}
298+
}
299+
}
300+
301+
@override
302+
Future<String> runJavascriptReturningResult(String javascript) async {
303+
final Object? result = await webView.evaluateJavaScript(javascript);
304+
if (result == null) {
305+
throw ArgumentError(
306+
'Result of JavaScript execution returned a `null` value. '
307+
'Use `runJavascript` when expecting a null return value.',
308+
);
309+
}
310+
return result.toString();
311+
}
312+
313+
@override
314+
Future<String?> getTitle() => webView.title;
315+
316+
@override
317+
Future<void> scrollTo(int x, int y) async {
318+
webView.scrollView.contentOffset = Point<double>(
319+
x.toDouble(),
320+
y.toDouble(),
321+
);
322+
}
323+
324+
@override
325+
Future<void> scrollBy(int x, int y) async {
326+
await webView.scrollView.scrollBy(Point<double>(
327+
x.toDouble(),
328+
y.toDouble(),
329+
));
330+
}
331+
332+
@override
333+
Future<int> getScrollX() async {
334+
final Point<double> offset = await webView.scrollView.contentOffset;
335+
return offset.x.toInt();
336+
}
337+
338+
@override
339+
Future<int> getScrollY() async {
340+
final Point<double> offset = await webView.scrollView.contentOffset;
341+
return offset.y.toInt();
342+
}
343+
210344
@override
211345
Future<void> updateSettings(WebSettings setting) async {
212346
if (setting.hasNavigationDelegate != null) {
@@ -324,6 +458,35 @@ class WebKitWebViewPlatformController extends WebViewPlatformController {
324458
errorType: errorType,
325459
);
326460
}
461+
462+
String _asObjectiveCString(Object? value, {bool inContainer = false}) {
463+
if (value == null) {
464+
// An NSNull inside an NSArray or NSDictionary is represented as a String
465+
// differently than a nil.
466+
if (inContainer) {
467+
return '"<null>"';
468+
}
469+
return '(null)';
470+
} else if (value is List) {
471+
final List<String> stringValues = <String>[];
472+
for (final Object? listValue in value) {
473+
stringValues.add(_asObjectiveCString(listValue, inContainer: true));
474+
}
475+
return '(${stringValues.join(',')})';
476+
} else if (value is Map) {
477+
final List<String> stringValues = <String>[];
478+
for (final MapEntry<Object?, Object?> entry in value.entries) {
479+
stringValues.add(
480+
'${_asObjectiveCString(entry.key, inContainer: true)} '
481+
'= '
482+
'${_asObjectiveCString(entry.value, inContainer: true)}',
483+
);
484+
}
485+
return '{${stringValues.join(';')}}';
486+
}
487+
488+
return value.toString();
489+
}
327490
}
328491

329492
/// Handles constructing objects and calling static methods.

packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ flutter:
1818
dependencies:
1919
flutter:
2020
sdk: flutter
21+
path: ^1.8.0
2122
webview_flutter_platform_interface: ^1.8.0
2223

2324
dev_dependencies:

0 commit comments

Comments
 (0)