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

[webview_flutter] Added Android implementation of PlatformWebViewWidget #6686

Merged
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';

import '../../android_webview.dart' as android_webview;
import '../../android_webview.dart';
import '../../instance_manager.dart';
import '../../weak_reference_utils.dart';
import 'android_navigation_delegate.dart';
import 'android_proxy.dart';
Expand Down Expand Up @@ -329,3 +333,87 @@ class AndroidJavaScriptChannelParams extends JavaScriptChannelParams {

final android_webview.JavaScriptChannel _javaScriptChannel;
}

/// Object specifying creation parameters for creating a [AndroidWebViewWidget].
///
/// When adding additional fields make sure they can be null or have a default
/// value to avoid breaking changes. See [PlatformWebViewWidgetCreationParams] for
/// more information.
@immutable
class AndroidWebViewWidgetCreationParams
extends PlatformWebViewWidgetCreationParams {
/// Creates [AndroidWebWidgetCreationParams].
AndroidWebViewWidgetCreationParams({
super.key,
required super.controller,
super.layoutDirection,
super.gestureRecognizers,
@visibleForTesting InstanceManager? instanceManager,
}) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager;

/// Constructs a [WebKitWebViewWidgetCreationParams] using a
/// [PlatformWebViewWidgetCreationParams].
AndroidWebViewWidgetCreationParams.fromPlatformWebViewWidgetCreationParams(
PlatformWebViewWidgetCreationParams params, {
InstanceManager? instanceManager,
}) : this(
key: params.key,
controller: params.controller,
layoutDirection: params.layoutDirection,
gestureRecognizers: params.gestureRecognizers,
instanceManager: instanceManager,
);

/// Maintains instances used to communicate with the native objects they
/// represent.
///
/// This field is exposed for testing purposes only and should not be used
/// outside of tests.
@visibleForTesting
final InstanceManager instanceManager;
}

/// An implementation of [PlatformWebViewWidget] with the Android WebView API.
class AndroidWebViewWidget extends PlatformWebViewWidget {
/// Constructs a [WebKitWebViewWidget].
AndroidWebViewWidget(PlatformWebViewWidgetCreationParams params)
: super.implementation(
params is AndroidWebViewWidgetCreationParams
? params
: AndroidWebViewWidgetCreationParams
.fromPlatformWebViewWidgetCreationParams(params),
);

AndroidWebViewWidgetCreationParams get _androidParams =>
params as AndroidWebViewWidgetCreationParams;

@override
Widget build(BuildContext context) {
return PlatformViewLink(
key: _androidParams.key,
viewType: 'plugins.flutter.io/webview',
surfaceFactory: (
BuildContext context,
PlatformViewController controller,
) {
return AndroidViewSurface(
controller: controller as AndroidViewController,
gestureRecognizers: _androidParams.gestureRecognizers,
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
);
},
onCreatePlatformView: (PlatformViewCreationParams params) {
return PlatformViewsService.initSurfaceAndroidView(
id: params.id,
viewType: 'plugins.flutter.io/webview',
layoutDirection: _androidParams.layoutDirection,
creationParams: _androidParams.instanceManager.getIdentifier(
(_androidParams.controller as AndroidWebViewController)
._webView),
creationParamsCodec: const StandardMessageCodec(),
)
..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
..create();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:webview_flutter_android/src/android_webview.dart'
as android_webview;
import 'package:webview_flutter_android/src/instance_manager.dart';
import 'package:webview_flutter_android/src/v4/src/android_navigation_delegate.dart';
import 'package:webview_flutter_android/src/v4/src/android_proxy.dart';
import 'package:webview_flutter_android/src/v4/src/android_webview_controller.dart';
Expand All @@ -18,80 +20,84 @@ import 'android_webview_controller_test.mocks.dart';

@GenerateNiceMocks(<MockSpec<Object>>[
MockSpec<AndroidNavigationDelegate>(),
MockSpec<AndroidWebViewController>(),
MockSpec<AndroidWebViewProxy>(),
MockSpec<AndroidWebViewWidgetCreationParams>(),
MockSpec<android_webview.FlutterAssetManager>(),
MockSpec<android_webview.JavaScriptChannel>(),
MockSpec<android_webview.WebChromeClient>(),
MockSpec<android_webview.WebSettings>(),
MockSpec<android_webview.WebView>(),
MockSpec<android_webview.WebViewClient>(),
MockSpec<android_webview.WebStorage>(),
MockSpec<BuildContext>(),
MockSpec<InstanceManager>(),
])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();

group('AndroidWebViewController', () {
AndroidWebViewController createControllerWithMocks({
android_webview.FlutterAssetManager? mockFlutterAssetManager,
android_webview.JavaScriptChannel? mockJavaScriptChannel,
android_webview.WebChromeClient? mockWebChromeClient,
android_webview.WebView? mockWebView,
android_webview.WebViewClient? mockWebViewClient,
android_webview.WebStorage? mockWebStorage,
}) {
final android_webview.WebView nonNullMockWebView =
mockWebView ?? MockWebView();

final AndroidWebViewControllerCreationParams creationParams =
AndroidWebViewControllerCreationParams(
androidWebStorage: mockWebStorage ?? MockWebStorage(),
androidWebViewProxy: AndroidWebViewProxy(
createAndroidWebChromeClient: (
{void Function(android_webview.WebView, int)?
onProgressChanged}) =>
mockWebChromeClient ?? MockWebChromeClient(),
createAndroidWebView: ({required bool useHybridComposition}) =>
nonNullMockWebView,
createAndroidWebViewClient: ({
void Function(android_webview.WebView webView, String url)?
onPageFinished,
void Function(android_webview.WebView webView, String url)?
onPageStarted,
@Deprecated('Only called on Android version < 23.')
void Function(
android_webview.WebView webView,
int errorCode,
String description,
String failingUrl,
)?
onReceivedError,
void Function(
android_webview.WebView webView,
android_webview.WebResourceRequest request,
android_webview.WebResourceError error,
)?
onReceivedRequestError,
void Function(
android_webview.WebView webView,
android_webview.WebResourceRequest request,
)?
requestLoading,
void Function(android_webview.WebView webView, String url)?
urlLoading,
}) =>
mockWebViewClient ?? MockWebViewClient(),
createFlutterAssetManager: () =>
mockFlutterAssetManager ?? MockFlutterAssetManager(),
createJavaScriptChannel: (
String channelName, {
required void Function(String) postMessage,
}) =>
mockJavaScriptChannel ?? MockJavaScriptChannel(),
));

return AndroidWebViewController(creationParams);
}
AndroidWebViewController createControllerWithMocks({
android_webview.FlutterAssetManager? mockFlutterAssetManager,
android_webview.JavaScriptChannel? mockJavaScriptChannel,
android_webview.WebChromeClient? mockWebChromeClient,
android_webview.WebView? mockWebView,
android_webview.WebViewClient? mockWebViewClient,
android_webview.WebStorage? mockWebStorage,
}) {
final android_webview.WebView nonNullMockWebView =
mockWebView ?? MockWebView();

final AndroidWebViewControllerCreationParams creationParams =
AndroidWebViewControllerCreationParams(
androidWebStorage: mockWebStorage ?? MockWebStorage(),
androidWebViewProxy: AndroidWebViewProxy(
createAndroidWebChromeClient: (
{void Function(android_webview.WebView, int)?
onProgressChanged}) =>
mockWebChromeClient ?? MockWebChromeClient(),
createAndroidWebView: ({required bool useHybridComposition}) =>
nonNullMockWebView,
createAndroidWebViewClient: ({
void Function(android_webview.WebView webView, String url)?
onPageFinished,
void Function(android_webview.WebView webView, String url)?
onPageStarted,
@Deprecated('Only called on Android version < 23.')
void Function(
android_webview.WebView webView,
int errorCode,
String description,
String failingUrl,
)?
onReceivedError,
void Function(
android_webview.WebView webView,
android_webview.WebResourceRequest request,
android_webview.WebResourceError error,
)?
onReceivedRequestError,
void Function(
android_webview.WebView webView,
android_webview.WebResourceRequest request,
)?
requestLoading,
void Function(android_webview.WebView webView, String url)?
urlLoading,
}) =>
mockWebViewClient ?? MockWebViewClient(),
createFlutterAssetManager: () =>
mockFlutterAssetManager ?? MockFlutterAssetManager(),
createJavaScriptChannel: (
String channelName, {
required void Function(String) postMessage,
}) =>
mockJavaScriptChannel ?? MockJavaScriptChannel(),
));

return AndroidWebViewController(creationParams);
}

group('AndroidWebViewController', () {
AndroidJavaScriptChannelParams
createAndroidJavaScriptChannelParamsWithMocks({
String? name,
Expand Down Expand Up @@ -728,4 +734,31 @@ void main() {
verify(mockSettings.setUserAgentString('Test Framework')).called(1);
});
});

group('AndroidWebViewWidget', () {
testWidgets('Builds AndroidView using supplied parameters',
(WidgetTester tester) async {
final MockAndroidWebViewWidgetCreationParams mockParams =
MockAndroidWebViewWidgetCreationParams();
final MockInstanceManager mockInstanceManager = MockInstanceManager();
final MockWebView mockWebView = MockWebView();
final AndroidWebViewController controller =
createControllerWithMocks(mockWebView: mockWebView);

when(mockParams.key).thenReturn(const Key('test_web_view'));
when(mockParams.instanceManager).thenReturn(mockInstanceManager);
when(mockParams.controller).thenReturn(controller);
when(mockInstanceManager.getIdentifier(mockWebView)).thenReturn(42);

final AndroidWebViewWidget webViewWidget =
AndroidWebViewWidget(mockParams);

await tester.pumpWidget(Builder(
builder: (BuildContext context) => webViewWidget.build(context),
));

expect(find.byType(PlatformViewLink), findsOneWidget);
expect(find.byKey(const Key('test_web_view')), findsOneWidget);
});
});
}
Loading