Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/webview_flutter_lwe/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 0.3.6
* Update minimum Flutter and Dart version to 3.24 and 3.5.
* Update the example main app.
* Update webview_flutter to 4.10.0.
* Update webview_flutter_platform_interface to 2.10.0.
* Add removeJavaScriptChannel method call.
* Fix deadlock issue caused by calling setBackgroundColor() after the WebViewController is created.

## 0.3.5

* Fix an issue where platform channel isn't called on the main thread.
Expand Down
4 changes: 2 additions & 2 deletions packages/webview_flutter_lwe/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ This package is not an _endorsed_ implementation of `webview_flutter`. Therefore

```yaml
dependencies:
webview_flutter: ^4.4.2
webview_flutter_lwe: ^0.3.5
webview_flutter: ^4.10.0
webview_flutter_lwe: ^0.3.6
```

## Example
Expand Down
129 changes: 125 additions & 4 deletions packages/webview_flutter_lwe/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:webview_flutter/webview_flutter.dart';
Expand Down Expand Up @@ -108,13 +108,21 @@ class WebViewExample extends StatefulWidget {
}

class _WebViewExampleState extends State<WebViewExample> {
final WebViewController _controller = WebViewController();
late final WebViewController _controller;

@override
void initState() {
super.initState();

_controller
// #docregion platform_features
late final PlatformWebViewControllerCreationParams params;
params = const PlatformWebViewControllerCreationParams();

final WebViewController controller =
WebViewController.fromPlatformCreationParams(params);
// #enddocregion platform_features

controller
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0x00000000))
..setNavigationDelegate(
Expand All @@ -138,14 +146,25 @@ Page resource error:
''');
},
onNavigationRequest: (NavigationRequest request) {
debugPrint('On onNavigationReques');
if (request.url.startsWith('https://www.youtube.com/')) {
debugPrint('blocking navigation to ${request.url}');
return NavigationDecision.prevent;
}
debugPrint('allowing navigation to ${request.url}');
return NavigationDecision.navigate;
},
// Note: onHttpError is not supproted by LweWebview.
// onHttpError: (HttpResponseError error) {
// debugPrint('Error occurred on page: ${error.response?.statusCode}');
// },
// Note: onUrlChange is not supproted by LweWebview.
// onUrlChange: (UrlChange change) {
// debugPrint('url change to ${change.url}');
// },
// Note: onHttpAuthRequest is not supproted by LweWebview.
// onHttpAuthRequest: (HttpAuthRequest request) {
// openDialog(request);
// },
),
)
..addJavaScriptChannel(
Expand All @@ -157,6 +176,13 @@ Page resource error:
},
)
..loadRequest(Uri.parse('https://flutter.dev'));

// setBackgroundColor is not currently supported on macOS.
if (kIsWeb || !Platform.isMacOS) {
controller.setBackgroundColor(const Color(0x80000000));
}

_controller = controller;
}

@override
Expand Down Expand Up @@ -189,6 +215,62 @@ Page resource error:
child: const Icon(Icons.favorite),
);
}

Future<void> openDialog(HttpAuthRequest httpRequest) async {
final TextEditingController usernameTextController =
TextEditingController();
final TextEditingController passwordTextController =
TextEditingController();

return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('${httpRequest.host}: ${httpRequest.realm ?? '-'}'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextField(
decoration: const InputDecoration(labelText: 'Username'),
autofocus: true,
controller: usernameTextController,
),
TextField(
decoration: const InputDecoration(labelText: 'Password'),
controller: passwordTextController,
),
],
),
),
actions: <Widget>[
// Explicitly cancel the request on iOS as the OS does not emit new
// requests when a previous request is pending.
TextButton(
onPressed: () {
httpRequest.onCancel();
Navigator.of(context).pop();
},
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
httpRequest.onProceed(
WebViewCredential(
user: usernameTextController.text,
password: passwordTextController.text,
),
);
Navigator.of(context).pop();
},
child: const Text('Authenticate'),
),
],
);
},
);
}
}

enum MenuOptions {
Expand All @@ -206,6 +288,7 @@ enum MenuOptions {
transparentBackground,
setCookie,
logExample,
basicAuthentication,
}

class SampleMenu extends StatelessWidget {
Expand Down Expand Up @@ -251,6 +334,8 @@ class SampleMenu extends StatelessWidget {
_onSetCookie();
case MenuOptions.logExample:
_onLogExample();
case MenuOptions.basicAuthentication:
_promptForUrl(context);
}
},
itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
Expand Down Expand Up @@ -311,6 +396,10 @@ class SampleMenu extends StatelessWidget {
value: MenuOptions.logExample,
child: Text('Log example'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.basicAuthentication,
child: Text('Basic Authentication Example'),
),
],
);
}
Expand Down Expand Up @@ -465,6 +554,38 @@ class SampleMenu extends StatelessWidget {

return webViewController.loadHtmlString(kLogExamplePage);
}

Future<void> _promptForUrl(BuildContext context) {
final TextEditingController urlTextController = TextEditingController();

return showDialog<String>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Input URL to visit'),
content: TextField(
decoration: const InputDecoration(labelText: 'URL'),
autofocus: true,
controller: urlTextController,
),
actions: <Widget>[
TextButton(
onPressed: () {
if (urlTextController.text.isNotEmpty) {
final Uri? uri = Uri.tryParse(urlTextController.text);
if (uri != null && uri.scheme.isNotEmpty) {
webViewController.loadRequest(uri);
Navigator.pop(context);
}
}
},
child: const Text('Visit'),
),
],
);
},
);
}
}

class NavigationControls extends StatelessWidget {
Expand Down
6 changes: 3 additions & 3 deletions packages/webview_flutter_lwe/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ description: Demonstrates how to use the webview_flutter_lwe plugin.
publish_to: "none"

environment:
sdk: ">=3.1.0 <4.0.0"
flutter: ">=3.13.0"
sdk: ^3.5.0
flutter: ">=3.24.0"

dependencies:
flutter:
sdk: flutter
path_provider: ^2.0.7
path_provider_tizen:
path: ../../path_provider/
webview_flutter: ^4.4.2
webview_flutter: ^4.10.0
webview_flutter_lwe:
path: ../

Expand Down
23 changes: 23 additions & 0 deletions packages/webview_flutter_lwe/lib/src/lwe_webview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,35 @@ class LweWebView {
/// Adds a new JavaScript channel to the set of enabled channels.
Future<void> addJavaScriptChannel(
JavaScriptChannelParams javaScriptChannelParams) {
// When JavaScript channel with the same name exists make sure to remove it
// before registering the new channel.
if (_javaScriptChannelParams.containsKey(javaScriptChannelParams.name)) {
_invokeChannelMethod<void>(
'removeJavaScriptChannel', javaScriptChannelParams.name);
}

_javaScriptChannelParams[javaScriptChannelParams.name] =
javaScriptChannelParams;

return _invokeChannelMethod<void>(
'addJavaScriptChannel', javaScriptChannelParams.name);
}

/// Removes the JavaScript channel with the matching name from the set of
/// enabled channels.
Future<void> removeJavaScriptChannel(String javaScriptChannelName) async {
final JavaScriptChannelParams? params =
_javaScriptChannelParams[javaScriptChannelName];

if (params == null) {
return;
}

_javaScriptChannelParams.remove(javaScriptChannelName);
return _invokeChannelMethod<void>(
'removeJavaScriptChannel', javaScriptChannelName);
}

/// Runs the given JavaScript in the context of the current page.
Future<void> runJavaScript(String javaScript) =>
_invokeChannelMethod<void>('runJavaScript', javaScript);
Expand Down
Loading
Loading