updated README.md, Added verticalScrollbarThumbColor, verticalScrollbarTrackColor, horizontalScrollbarThumbColor, horizontalScrollbarTrackColor Android-specific WebView options, Fixed some null types and wrong casting

This commit is contained in:
Lorenzo Pichilli 2021-02-25 00:00:46 +01:00
parent 35cea5b01a
commit 1e63238eb8
21 changed files with 476 additions and 218 deletions

View File

@ -1,3 +1,8 @@
## 5.0.1-nullsafety.1
- Added `verticalScrollbarThumbColor`, `verticalScrollbarTrackColor`, `horizontalScrollbarThumbColor`, `horizontalScrollbarTrackColor` Android-specific WebView options
- Fixed some null types and wrong casting
## 5.0.0-nullsafety.0
- Added support for Dart null-safety feature

170
README.md
View File

@ -217,14 +217,33 @@ First, add `flutter_inappwebview` as a [dependency in your pubspec.yaml file](ht
Classes:
- [InAppWebView](#inappwebview-class): Flutter Widget for adding an **inline native WebView** integrated into the flutter widget tree. Note that on Android it requires **Android API 20+** (see [AndroidView](https://api.flutter.dev/flutter/widgets/AndroidView-class.html)) or **Android API 19+** if you enable the `useHybridComposition` Android-specific option.
- [methods](#inappwebviewcontroller-methods)
- [options](#inappwebview-options)
- [events](#inappwebview-events)
- [ContextMenu](#contextmenu-class): This class represents the WebView context menu.
- [options](#contextmenu-options)
- [events](#contextmenu-events)
- [HeadlessInAppWebView](#headlessinappwebview-class): Class that represents a WebView in headless mode. It can be used to run a WebView in background without attaching an `InAppWebView` to the widget tree.
- [methods](#inappwebviewcontroller-methods)
- [options](#inappwebview-options)
- [events](#inappwebview-events)
- [InAppBrowser](#inappbrowser-class): In-App Browser using native WebView.
- [methods](#inappbrowser-methods)
- [options](#inappbrowser-options)
- [events](#inappbrowser-events)
- [ChromeSafariBrowser](#chromesafaribrowser-class): In-App Browser using [Chrome Custom Tabs](https://developer.android.com/reference/android/support/customtabs/package-summary) on Android / [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS.
- [methods](#chromesafaribrowser-methods)
- [options](#chromesafaribrowser-options)
- [events](#chromesafaribrowser-events)
- [InAppLocalhostServer](#inapplocalhostserver-class): This class allows you to create a simple server on `http://localhost:[port]/`. The default `port` value is `8080`.
- [CookieManager](#cookiemanager-class): This class implements a singleton object (shared instance) which manages the cookies used by WebView instances. **LIMITED SUPPORT for iOS below 11.0**.
- [methods](#cookiemanager-methods)
- [HttpAuthCredentialDatabase](#httpauthcredentialdatabase-class): This class implements a singleton object (shared instance) which manages the shared HTTP auth credentials cache.
- [methods](#httpauthcredentialdatabase-methods)
- [WebStorageManager](#webstoragemanager-class): This class implements a singleton object (shared instance) which manages the web storage used by WebView instances.
- [methods](#webstoragemanager-methods)
- [WebRTC](#webrtc)
- [Service Worker API](#service-worker-api)
### Load a file inside `assets` folder
@ -613,6 +632,8 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
* `forceDark`: Set the force dark mode for this WebView. The default value is `AndroidInAppWebViewForceDark.FORCE_DARK_OFF`.
* `geolocationEnabled`: Sets whether Geolocation API is enabled. The default value is `true`.
* `hardwareAcceleration`: Boolean value to enable Hardware Acceleration in the WebView.
* `horizontalScrollbarThumbColor`: Sets the horizontal scrollbar thumb color.
* `horizontalScrollbarTrackColor`: Sets the horizontal scrollbar track color.
* `initialScale`: Sets the initial scale for this WebView. 0 means default. The behavior for the default scale depends on the state of `useWideViewPort` and `loadWithOverviewMode`.
* `layoutAlgorithm`: Sets the underlying layout algorithm. This will cause a re-layout of the WebView.
* `loadWithOverviewMode`: Sets whether the WebView loads pages in overview mode, that is, zooms out the content to fit on screen by width.
@ -642,6 +663,8 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
* `useShouldInterceptRequest`: Set to `true` to be able to listen at the `androidShouldInterceptRequest` event. The default value is `false`.
* `useWideViewPort`: Set to `true` if the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport.
* `verticalScrollbarPosition`: Set the position of the vertical scroll bar. The default value is `AndroidVerticalScrollbarPosition.SCROLLBAR_POSITION_DEFAULT`.
* `verticalScrollbarThumbColor`: Sets the vertical scrollbar thumb color.
* `verticalScrollbarTrackColor`: Sets the vertical scrollbar track color.
##### `InAppWebView` iOS-specific options
@ -1148,7 +1171,7 @@ class _MyAppState extends State<MyApp> {
Screenshots:
- iOS:
![ios](https://user-images.githubusercontent.com/5956938/45934084-2a935400-bf99-11e8-9d71-9e1758b5b8c6.gif)
![ios](https://user-images.githubusercontent.com/5956938/109074100-92fd3700-76f7-11eb-8e75-34ce7377e35f.gif)
- Android:
@ -1509,3 +1532,148 @@ iOS-specific methods can be called using the `WebStorageManager.instance().ios`
* `fetchDataRecords({required Set<IOSWKWebsiteDataType> dataTypes})`: Fetches data records containing the given website data types.
* `removeDataFor({required Set<IOSWKWebsiteDataType> dataTypes, required List<IOSWKWebsiteDataRecord> dataRecords})`: Removes website data of the given types for the given data records.
* `removeDataModifiedSince({required Set<IOSWKWebsiteDataType> dataTypes, required DateTime date})`: Removes all website data of the given types that has been modified since the given date.
### WebRTC
To work with WebRTC, you need to request `camera` and `microphone` permissions, for example using the `permission_handler` flutter package:
```dart
import 'package:permission_handler/permission_handler.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Permission.camera.request();
await Permission.microphone.request();
runApp(MyApp());
}
```
Also, you need to set the cross-platform option `mediaPlaybackRequiresUserGesture` to `false` in order to autoplay HTML5 audio and video.
After that, follow the instructions below for each platform where you want to use it.
To test WebRTC, you can try to visit https://appr.tc/.
#### WebRTC on Android
On Android, you need to implement the `androidOnPermissionRequest` event, that is an event fired when the WebView is requesting permission to access a specific resource.
This event is used to grant permissions for the WebRTC API, for example:
```dart
androidOnPermissionRequest: (controller, origin, resources) async {
return PermissionRequestResponse(resources: resources, action: PermissionRequestResponseAction.GRANT);
}
```
Also, you need to add these permissions in your `AndroidManifest.xml` file:
```xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.VIDEO_CAPTURE" />
<uses-permission android:name="android.permission.AUDIO_CAPTURE" />
```
#### WebRTC on iOS
On iOS, WebRTC is supported starting from 14.3+.
You need to set the iOS-specific option `allowsInlineMediaPlayback` to `true`, for example:
```dart
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
mediaPlaybackRequiresUserGesture: false,
),
android: AndroidInAppWebViewOptions(
useHybridComposition: true
),
ios: IOSInAppWebViewOptions(
allowsInlineMediaPlayback: true,
)
),
```
Note that on iOS, to be able to play video inline, the `video` HTML element must have the `playsinline` attribute, for example:
```html
<video autoplay playsinline src="..."></video>
```
In your `Info.plist` file, you need to add also the following properties:
```xml
<key>NSMicrophoneUsageDescription</key>
<string>Flutter requires access to microphone.</string>
<key>NSCameraUsageDescription</key>
<string>Flutter requires access to camera.</string>
```
If you open this file In Xcode, the `NSMicrophoneUsageDescription` property is represented by `Privacy - Microphone Usage Description` and
`NSCameraUsageDescription` is represented by `Privacy - Camera Usage Description`.
### Service Worker API
Check https://caniuse.com/serviceworkers for JavaScript Service Worker API availability.
#### Service Worker API on Android
On Android, the `AndroidServiceWorkerController` and `AndroidServiceWorkerClient` classes can be used to intercept requests.
Before using these classes or its methods, you should check if the service worker features you want to use are supported or not, for example:
```dart
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isAndroid) {
await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true);
var swAvailable = await AndroidWebViewFeature.isFeatureSupported(AndroidWebViewFeature.SERVICE_WORKER_BASIC_USAGE);
var swInterceptAvailable = await AndroidWebViewFeature.isFeatureSupported(AndroidWebViewFeature.SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST);
if (swAvailable && swInterceptAvailable) {
AndroidServiceWorkerController serviceWorkerController = AndroidServiceWorkerController.instance();
serviceWorkerController.serviceWorkerClient = AndroidServiceWorkerClient(
shouldInterceptRequest: (request) async {
print(request);
return null;
},
);
}
}
runApp(MyApp());
}
```
#### Service Worker API on iOS
The JavaScript Service Worker API are available starting from iOS 14.0+.
To enable this JavaScript API on iOS there are only 2 ways:
- using `App-Bound Domains`
- your App proposes itself as a possible Default Browser such as iOS Safari or Google Chrome
##### iOS App-Bound Domains
Read the [WebKit - App-Bound Domains](https://webkit.org/blog/10882/app-bound-domains/) article for details.
You can specify up to 10 "app-bound" domains using a new Info.plist key `WKAppBoundDomains`, for example:
```xml
<dict>
<key>WKAppBoundDomains</key>
<array>
<string>flutter.dev</string>
<string>github.com</string>
</array>
</dict>
```
After that, you need to set to `true` the `limitsNavigationsToAppBoundDomains` iOS-specific WebView option, for example:
```dart
InAppWebViewGroupOptions(
ios: IOSInAppWebViewOptions(
limitsNavigationsToAppBoundDomains: true // adds Service Worker API on iOS 14.0+
)
)
```
##### iOS Default Browser
Read the [Preparing Your App to be the Default Browser or Email Client](https://developer.apple.com/documentation/xcode/allowing_apps_and_websites_to_link_to_your_content/preparing_your_app_to_be_the_default_browser_or_email_client) article for details.

View File

@ -8,6 +8,8 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@ -78,6 +80,8 @@ import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@ -184,6 +188,25 @@ final public class InAppWebView extends InputAwareWebView {
WebViewCompat.setWebViewRenderProcessClient(this, inAppWebViewRenderProcessClient);
}
userContentController.addPluginScript(PromisePolyfillJS.PROMISE_POLYFILL_JS_PLUGIN_SCRIPT);
userContentController.addPluginScript(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT);
userContentController.addPluginScript(ConsoleLogJS.CONSOLE_LOG_JS_PLUGIN_SCRIPT);
userContentController.addPluginScript(PrintJS.PRINT_JS_PLUGIN_SCRIPT);
userContentController.addPluginScript(OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT);
userContentController.addPluginScript(OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT);
if (options.useShouldInterceptAjaxRequest) {
userContentController.addPluginScript(InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT);
}
if (options.useShouldInterceptFetchRequest) {
userContentController.addPluginScript(InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT);
}
if (options.useOnLoadResource) {
userContentController.addPluginScript(OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT);
}
if (!options.useHybridComposition) {
userContentController.addPluginScript(PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT);
}
if (options.useOnDownloadStart)
setDownloadListener(new DownloadStartListener());
@ -304,6 +327,18 @@ final public class InAppWebView extends InputAwareWebView {
options.scrollBarFadeDuration = getScrollBarFadeDuration();
}
setVerticalScrollbarPosition(options.verticalScrollbarPosition);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (options.verticalScrollbarThumbColor != null)
setVerticalScrollbarThumbDrawable(new ColorDrawable(Color.parseColor(options.verticalScrollbarThumbColor)));
if (options.verticalScrollbarTrackColor != null)
setVerticalScrollbarTrackDrawable(new ColorDrawable(Color.parseColor(options.verticalScrollbarTrackColor)));
if (options.horizontalScrollbarThumbColor != null)
setHorizontalScrollbarThumbDrawable(new ColorDrawable(Color.parseColor(options.horizontalScrollbarThumbColor)));
if (options.horizontalScrollbarTrackColor != null)
setHorizontalScrollbarTrackDrawable(new ColorDrawable(Color.parseColor(options.horizontalScrollbarTrackColor)));
}
setOverScrollMode(options.overScrollMode);
if (options.networkAvailable != null) {
setNetworkAvailable(options.networkAvailable);
@ -436,25 +471,6 @@ final public class InAppWebView extends InputAwareWebView {
return false;
}
});
userContentController.addPluginScript(PromisePolyfillJS.PROMISE_POLYFILL_JS_PLUGIN_SCRIPT);
userContentController.addPluginScript(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT);
userContentController.addPluginScript(ConsoleLogJS.CONSOLE_LOG_JS_PLUGIN_SCRIPT);
userContentController.addPluginScript(PrintJS.PRINT_JS_PLUGIN_SCRIPT);
userContentController.addPluginScript(OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT);
userContentController.addPluginScript(OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT);
if (options.useShouldInterceptAjaxRequest) {
userContentController.addPluginScript(InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT);
}
if (options.useShouldInterceptFetchRequest) {
userContentController.addPluginScript(InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT);
}
if (options.useOnLoadResource) {
userContentController.addPluginScript(OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT);
}
if (!options.useHybridComposition) {
userContentController.addPluginScript(PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT);
}
}
public void setIncognito(boolean enabled) {

View File

@ -4,6 +4,8 @@ import android.os.Build;
import android.view.View;
import android.webkit.WebSettings;
import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.Options;
import com.pichillilorenzo.flutter_inappwebview.types.PreferredContentModeOptionType;
@ -97,6 +99,14 @@ public class InAppWebViewOptions implements Options<InAppWebView> {
public Boolean useOnRenderProcessGone = false;
public Boolean disableDefaultErrorPage = false;
public Boolean useHybridComposition = false;
@Nullable
public String verticalScrollbarThumbColor;
@Nullable
public String verticalScrollbarTrackColor;
@Nullable
public String horizontalScrollbarThumbColor;
@Nullable
public String horizontalScrollbarTrackColor;
@Override
public InAppWebViewOptions parse(Map<String, Object> options) {
@ -339,6 +349,18 @@ public class InAppWebViewOptions implements Options<InAppWebView> {
case "useHybridComposition":
useHybridComposition = (Boolean) value;
break;
case "verticalScrollbarThumbColor":
verticalScrollbarThumbColor = (String) value;
break;
case "verticalScrollbarTrackColor":
verticalScrollbarTrackColor = (String) value;
break;
case "horizontalScrollbarThumbColor":
horizontalScrollbarThumbColor = (String) value;
break;
case "horizontalScrollbarTrackColor":
horizontalScrollbarTrackColor = (String) value;
break;
}
}
@ -425,6 +447,10 @@ public class InAppWebViewOptions implements Options<InAppWebView> {
options.put("useOnRenderProcessGone", useOnRenderProcessGone);
options.put("disableDefaultErrorPage", disableDefaultErrorPage);
options.put("useHybridComposition", useHybridComposition);
options.put("verticalScrollbarThumbColor", verticalScrollbarThumbColor);
options.put("verticalScrollbarTrackColor", verticalScrollbarTrackColor);
options.put("horizontalScrollbarThumbColor", horizontalScrollbarThumbColor);
options.put("horizontalScrollbarTrackColor", horizontalScrollbarTrackColor);
return options;
}

View File

@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"device_info","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":["device_info"]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-02-22 23:54:51.255907","version":"1.27.0-5.0.pre.90"}
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"device_info","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":["device_info"]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-02-24 23:50:11.899671","version":"1.27.0-4.0.pre"}

View File

@ -44,6 +44,7 @@ android {
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
buildTypes {
@ -63,4 +64,6 @@ dependencies {
testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'com.android.support:multidex:1.0.3'
}

View File

@ -1,8 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Theme applied to the Android Window while the process is starting -->
<style name="LaunchTheme" parent="Theme.MaterialComponents.NoActionBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="Theme.MaterialComponents.NoActionBar">
<item name="android:windowBackground">@android:color/white</item>
</style>
</resources>

View File

@ -459,7 +459,7 @@ void main() {
final ConsoleMessage consoleMessage = await consoleMessageCompleter.future;
expect(consoleMessage.messageLevel, ConsoleMessageLevel.LOG);
expect(consoleMessage.message, 'message');
});
}, skip: !Platform.isIOS);
testWidgets('loadUrl with file:// scheme and iosAllowingReadAccessTo argument', (WidgetTester tester) async {
final Completer<ConsoleMessage?> consoleMessageShouldNotComplete = Completer<ConsoleMessage?>();
@ -503,7 +503,7 @@ void main() {
final ConsoleMessage consoleMessage = await consoleMessageCompleter.future;
expect(consoleMessage.messageLevel, ConsoleMessageLevel.LOG);
expect(consoleMessage.message, 'message');
});
}, skip: !Platform.isIOS);
}, skip: !Platform.isIOS);
testWidgets('JavaScript Handler', (WidgetTester tester) async {
@ -2971,7 +2971,7 @@ setTimeout(function() {
await pageLoaded.future;
final String url = await onNavigationResponseCompleter.future;
expect(url, 'https://flutter.dev/');
});
}, skip: !Platform.isIOS);
testWidgets('cancel navigation', (WidgetTester tester) async {
final Completer controllerCompleter = Completer<InAppWebViewController>();
@ -3008,7 +3008,7 @@ setTimeout(function() {
final String url = await onNavigationResponseCompleter.future;
expect(url, 'https://flutter.dev/');
expect(pageLoaded.future, doesNotComplete);
});
}, skip: !Platform.isIOS);
}, skip: !Platform.isIOS);
testWidgets('initialUserScripts', (WidgetTester tester) async {
@ -4292,7 +4292,7 @@ setTimeout(function() {
final InAppWebViewController controller = await controllerCompleter.future;
await pageLoaded.future;
await expectLater(controller.android.clearSslPreferences(), completes);
});
}, skip: !Platform.isAndroid);
testWidgets('pause/resume', (WidgetTester tester) async {
final Completer controllerCompleter = Completer<InAppWebViewController>();
@ -4321,7 +4321,7 @@ setTimeout(function() {
await expectLater(controller.android.pause(), completes);
await Future.delayed(Duration(seconds: 1));
await expectLater(controller.android.resume(), completes);
});
}, skip: !Platform.isAndroid);
testWidgets('getOriginalUrl', (WidgetTester tester) async {
final Completer controllerCompleter = Completer<InAppWebViewController>();
@ -4349,7 +4349,7 @@ setTimeout(function() {
await pageLoaded.future;
var originUrl = (await controller.android.getOriginalUrl())?.toString();
expect(originUrl, 'https://flutter.dev/');
});
}, skip: !Platform.isAndroid);
testWidgets('pageDown/pageUp', (WidgetTester tester) async {
final Completer controllerCompleter = Completer<InAppWebViewController>();
@ -4378,7 +4378,7 @@ setTimeout(function() {
expect(await controller.android.pageDown(bottom: false), true);
await Future.delayed(Duration(seconds: 1));
expect(await controller.android.pageUp(top: false), true);
});
}, skip: !Platform.isAndroid);
testWidgets('zoomIn/zoomOut', (WidgetTester tester) async {
final Completer controllerCompleter = Completer<InAppWebViewController>();
@ -4407,7 +4407,7 @@ setTimeout(function() {
expect(await controller.android.zoomIn(), true);
await Future.delayed(Duration(seconds: 1));
expect(await controller.android.zoomOut(), true);
});
}, skip: !Platform.isAndroid);
testWidgets('clearHistory', (WidgetTester tester) async {
final Completer controllerCompleter = Completer<InAppWebViewController>();
@ -4443,121 +4443,121 @@ setTimeout(function() {
webHistory = await controller.getCopyBackForwardList();
expect(webHistory!.list!.length, 1);
});
}, skip: !Platform.isAndroid);
test('clearClientCertPreferences', () async {
await expectLater(AndroidInAppWebViewController.clearClientCertPreferences(), completes);
});
}, skip: !Platform.isAndroid);
test('getSafeBrowsingPrivacyPolicyUrl', () async {
expect(await AndroidInAppWebViewController.getSafeBrowsingPrivacyPolicyUrl(), isNotNull);
});
}, skip: !Platform.isAndroid);
test('setSafeBrowsingWhitelist', () async {
expect(await AndroidInAppWebViewController.setSafeBrowsingWhitelist(hosts: ["flutter.dev", "github.com"]), true);
});
}, skip: !Platform.isAndroid);
test('getCurrentWebViewPackage', () async {
expect(await AndroidInAppWebViewController.getCurrentWebViewPackage(), isNotNull);
});
}, skip: !Platform.isAndroid);
}, skip: !Platform.isAndroid);
group('ios methods', () {
testWidgets('reloadFromOrigin', (WidgetTester tester) async {
final Completer controllerCompleter = Completer<InAppWebViewController>();
final Completer<void> pageLoaded = Completer<void>();
group('ios methods', () {
testWidgets('reloadFromOrigin', (WidgetTester tester) async {
final Completer controllerCompleter = Completer<InAppWebViewController>();
final Completer<void> pageLoaded = Completer<void>();
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: InAppWebView(
key: GlobalKey(),
initialUrlRequest: URLRequest(
url: Uri.parse('https://flutter.dev')
),
onWebViewCreated: (controller) {
controllerCompleter.complete(controller);
},
onLoadStop: (controller, url) {
pageLoaded.complete();
},
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: InAppWebView(
key: GlobalKey(),
initialUrlRequest: URLRequest(
url: Uri.parse('https://flutter.dev')
),
onWebViewCreated: (controller) {
controllerCompleter.complete(controller);
},
onLoadStop: (controller, url) {
pageLoaded.complete();
},
),
);
),
);
final InAppWebViewController controller = await controllerCompleter.future;
await pageLoaded.future;
await expectLater(controller.ios.reloadFromOrigin(), completes);
});
testWidgets('createPdf', (WidgetTester tester) async {
final Completer controllerCompleter = Completer<InAppWebViewController>();
final Completer<void> pageLoaded = Completer<void>();
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: InAppWebView(
key: GlobalKey(),
initialUrlRequest: URLRequest(
url: Uri.parse('https://flutter.dev')
),
onWebViewCreated: (controller) {
controllerCompleter.complete(controller);
},
onLoadStop: (controller, url) {
pageLoaded.complete();
},
),
),
);
final InAppWebViewController controller = await controllerCompleter.future;
await pageLoaded.future;
var iosWKPdfConfiguration = IOSWKPDFConfiguration(rect: InAppWebViewRect(
width: 100,
height: 100,
x: 50,
y: 50
));
var pdf = await controller.ios.createPdf(iosWKPdfConfiguration: iosWKPdfConfiguration);
expect(pdf, isNotNull);
});
testWidgets('createWebArchiveData', (WidgetTester tester) async {
final Completer controllerCompleter = Completer<InAppWebViewController>();
final Completer<void> pageLoaded = Completer<void>();
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: InAppWebView(
key: GlobalKey(),
initialUrlRequest: URLRequest(
url: Uri.parse('https://flutter.dev')
),
onWebViewCreated: (controller) {
controllerCompleter.complete(controller);
},
onLoadStop: (controller, url) {
pageLoaded.complete();
},
),
),
);
final InAppWebViewController controller = await controllerCompleter.future;
await pageLoaded.future;
expect(await controller.ios.createWebArchiveData(), isNotNull);
});
test('handlesURLScheme', () async {
expect(await IOSInAppWebViewController.handlesURLScheme("http"), true);
expect(await IOSInAppWebViewController.handlesURLScheme("https"), true);
});
final InAppWebViewController controller = await controllerCompleter.future;
await pageLoaded.future;
await expectLater(controller.ios.reloadFromOrigin(), completes);
}, skip: !Platform.isIOS);
testWidgets('createPdf', (WidgetTester tester) async {
final Completer controllerCompleter = Completer<InAppWebViewController>();
final Completer<void> pageLoaded = Completer<void>();
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: InAppWebView(
key: GlobalKey(),
initialUrlRequest: URLRequest(
url: Uri.parse('https://flutter.dev')
),
onWebViewCreated: (controller) {
controllerCompleter.complete(controller);
},
onLoadStop: (controller, url) {
pageLoaded.complete();
},
),
),
);
final InAppWebViewController controller = await controllerCompleter.future;
await pageLoaded.future;
var iosWKPdfConfiguration = IOSWKPDFConfiguration(rect: InAppWebViewRect(
width: 100,
height: 100,
x: 50,
y: 50
));
var pdf = await controller.ios.createPdf(iosWKPdfConfiguration: iosWKPdfConfiguration);
expect(pdf, isNotNull);
}, skip: !Platform.isIOS);
testWidgets('createWebArchiveData', (WidgetTester tester) async {
final Completer controllerCompleter = Completer<InAppWebViewController>();
final Completer<void> pageLoaded = Completer<void>();
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: InAppWebView(
key: GlobalKey(),
initialUrlRequest: URLRequest(
url: Uri.parse('https://flutter.dev')
),
onWebViewCreated: (controller) {
controllerCompleter.complete(controller);
},
onLoadStop: (controller, url) {
pageLoaded.complete();
},
),
),
);
final InAppWebViewController controller = await controllerCompleter.future;
await pageLoaded.future;
expect(await controller.ios.createWebArchiveData(), isNotNull);
}, skip: !Platform.isIOS);
test('handlesURLScheme', () async {
expect(await IOSInAppWebViewController.handlesURLScheme("http"), true);
expect(await IOSInAppWebViewController.handlesURLScheme("https"), true);
}, skip: !Platform.isIOS);
}, skip: !Platform.isIOS);
});
group('Cookie Manager', () {

View File

@ -1,18 +0,0 @@
#
# NOTE: This podspec is NOT to be published. It is only used as a local source!
# This is a generated file; do not edit or check into version control.
#
Pod::Spec.new do |s|
s.name = 'Flutter'
s.version = '1.0.0'
s.summary = 'High-performance, high-fidelity mobile apps.'
s.homepage = 'https://flutter.io'
s.license = { :type => 'MIT' }
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
s.ios.deployment_target = '8.0'
# Framework linking is handled by Flutter tooling, not CocoaPods.
# Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs.
s.vendored_frameworks = 'path/to/nothing'
end

View File

@ -2,13 +2,12 @@
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/lorenzopichilli/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example"
export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/lib/main.dart"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "DART_DEFINES=Zmx1dHRlci5pbnNwZWN0b3Iuc3RydWN0dXJlZEVycm9ycz10cnVl,RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TRACK_WIDGET_CREATION=false"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/.dart_tool/package_config.json"
export "PACKAGE_CONFIG=.packages"

View File

@ -1,7 +1,7 @@
import 'dart:collection';
import 'dart:convert';
// import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
// import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
@ -23,7 +23,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
late ContextMenu contextMenu;
String url = "";
double progress = 0;
CookieManager _cookieManager = CookieManager.instance();
// CookieManager _cookieManager = CookieManager.instance();
@override
void initState() {
@ -70,7 +70,6 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
),
ios: IOSInAppWebViewOptions(
allowsInlineMediaPlayback: true,
// limitsNavigationsToAppBoundDomains: true // adds Service Worker API on iOS 14.0+
)
);
@ -146,9 +145,6 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
this.url = url.toString();
});
webView = controller;
// RenderObject renderBox = webViewKey.currentContext!.findRenderObject()!;
// print(renderBox.paintBounds.size);
},
onProgressChanged: (controller, progress) {
setState(() {
@ -162,7 +158,6 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
});
},
onConsoleMessage: (controller, consoleMessage) {
print("CONSOLE MESSAGE FROM MAIN WEBVIEW!");
print(consoleMessage);
},
),

View File

@ -8,22 +8,26 @@ import 'package:flutter_inappwebview_example/chrome_safari_browser_example.scree
import 'package:flutter_inappwebview_example/headless_in_app_webview.screen.dart';
import 'package:flutter_inappwebview_example/in_app_webiew_example.screen.dart';
import 'package:flutter_inappwebview_example/in_app_browser_example.screen.dart';
import 'package:path_provider/path_provider.dart';
// import 'package:path_provider/path_provider.dart';
// import 'package:permission_handler/permission_handler.dart';
// InAppLocalhostServer localhostServer = new InAppLocalhostServer();
AndroidServiceWorkerController serviceWorkerController = AndroidServiceWorkerController.instance();
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
// await Permission.camera.request();
// await Permission.microphone.request();
// await Permission.storage.request();
//await Permission.storage.request();
if (Platform.isAndroid) {
await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true);
if (await AndroidWebViewFeature.isFeatureSupported(AndroidWebViewFeature.SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST)) {
var swAvailable = await AndroidWebViewFeature.isFeatureSupported(AndroidWebViewFeature.SERVICE_WORKER_BASIC_USAGE);
var swInterceptAvailable = await AndroidWebViewFeature.isFeatureSupported(AndroidWebViewFeature.SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST);
if (swAvailable && swInterceptAvailable) {
AndroidServiceWorkerController serviceWorkerController = AndroidServiceWorkerController.instance();
serviceWorkerController.serviceWorkerClient = AndroidServiceWorkerClient(
shouldInterceptRequest: (request) async {
print(request);

View File

@ -1012,6 +1012,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
if newOptionsMap["javaScriptEnabled"] != nil && options?.javaScriptEnabled != newOptions.javaScriptEnabled {
configuration.preferences.javaScriptEnabled = newOptions.javaScriptEnabled
}
if #available(iOS 14.0, *) {
if options?.mediaType != newOptions.mediaType {
mediaType = newOptions.mediaType
@ -1479,7 +1480,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
if let useOnDownloadStart = options?.useOnDownloadStart, useOnDownloadStart {
let mimeType = navigationResponse.response.mimeType
if let url = navigationResponse.response.url, navigationResponse.isForMainFrame {
if mimeType != nil && !mimeType!.starts(with: "text/") {
if url.scheme != "file", mimeType != nil, !mimeType!.starts(with: "text/") {
onDownloadStart(url: url.absoluteString)
if useOnNavigationResponse == nil || !useOnNavigationResponse! {
decisionHandler(.cancel)

View File

@ -1,3 +1,4 @@
import 'package:uuid/uuid.dart';
// ignore: non_constant_identifier_names
final UUID_GENERATOR = Uuid();

View File

@ -6,8 +6,6 @@ class AndroidWebViewFeature {
static const MethodChannel _channel = const MethodChannel(
'com.pichillilorenzo/flutter_inappwebview_android_webviewfeature');
static Future<dynamic> _handleMethod(MethodCall call) async {}
final String _value;
const AndroidWebViewFeature._internal(this._value);

View File

@ -1,3 +1,7 @@
import 'dart:ui';
import 'package:flutter_inappwebview/src/util.dart';
import '../../types.dart';
import '../../in_app_browser/in_app_browser_options.dart';
@ -213,7 +217,27 @@ class AndroidInAppWebViewOptions
///Sets whether the default Android error page should be disabled.
///The default value is `false`.
bool? disableDefaultErrorPage;
bool disableDefaultErrorPage;
///Sets the vertical scrollbar thumb color.
///
///**NOTE**: available on Android 29+.
Color? verticalScrollbarThumbColor;
///Sets the vertical scrollbar track color.
///
///**NOTE**: available on Android 29+.
Color? verticalScrollbarTrackColor;
///Sets the horizontal scrollbar thumb color.
///
///**NOTE**: available on Android 29+.
Color? horizontalScrollbarThumbColor;
///Sets the horizontal scrollbar track color.
///
///**NOTE**: available on Android 29+.
Color? horizontalScrollbarTrackColor;
AndroidInAppWebViewOptions({
this.textZoom = 100,
@ -267,7 +291,11 @@ class AndroidInAppWebViewOptions
this.scrollbarFadingEnabled = true,
this.scrollBarFadeDuration,
this.rendererPriorityPolicy,
this.disableDefaultErrorPage,
this.disableDefaultErrorPage = false,
this.verticalScrollbarThumbColor,
this.verticalScrollbarTrackColor,
this.horizontalScrollbarThumbColor,
this.horizontalScrollbarTrackColor,
});
@override
@ -323,7 +351,11 @@ class AndroidInAppWebViewOptions
"scrollbarFadingEnabled": scrollbarFadingEnabled,
"scrollBarFadeDuration": scrollBarFadeDuration,
"rendererPriorityPolicy": rendererPriorityPolicy?.toMap(),
"disableDefaultErrorPage": disableDefaultErrorPage
"disableDefaultErrorPage": disableDefaultErrorPage,
"verticalScrollbarThumbColor": verticalScrollbarThumbColor?.toHex(),
"verticalScrollbarTrackColor": verticalScrollbarTrackColor?.toHex(),
"horizontalScrollbarThumbColor": horizontalScrollbarThumbColor?.toHex(),
"horizontalScrollbarTrackColor": horizontalScrollbarTrackColor?.toHex(),
};
}
@ -390,6 +422,14 @@ class AndroidInAppWebViewOptions
options.rendererPriorityPolicy = RendererPriorityPolicy.fromMap(
map["rendererPriorityPolicy"]?.cast<String, dynamic>());
options.disableDefaultErrorPage = map["disableDefaultErrorPage"];
options.verticalScrollbarThumbColor =
UtilColor.fromHex(map["verticalScrollbarThumbColor"]);
options.verticalScrollbarTrackColor =
UtilColor.fromHex(map["verticalScrollbarTrackColor"]);
options.horizontalScrollbarThumbColor =
UtilColor.fromHex(map["horizontalScrollbarThumbColor"]);
options.horizontalScrollbarTrackColor =
UtilColor.fromHex(map["horizontalScrollbarTrackColor"]);
return options;
}

View File

@ -1871,7 +1871,7 @@ class Favicon {
}
}
///Class that represents an Android-specific class used to override the way the cache is used.
///An Android-specific class used to override the way the cache is used.
class AndroidCacheMode {
final int _value;
@ -1932,7 +1932,7 @@ class AndroidCacheMode {
int get hashCode => _value.hashCode;
}
///Class that represents an Android-specific class used to disable the action mode menu items.
///An Android-specific class used to disable the action mode menu items.
///
///**NOTE**: available on Android 24+.
class AndroidActionModeMenuItem {
@ -1996,7 +1996,7 @@ class AndroidActionModeMenuItem {
int get hashCode => _value.hashCode;
}
///Class that represents an Android-specific class used to indicate the force dark mode.
///An Android-specific class used to indicate the force dark mode.
///
///**NOTE**: available on Android 29+.
class AndroidForceDark {
@ -2053,7 +2053,7 @@ class AndroidForceDark {
int get hashCode => _value.hashCode;
}
///Class that represents an Android-specific class used to set the underlying layout algorithm.
///An Android-specific class used to set the underlying layout algorithm.
class AndroidLayoutAlgorithm {
final String _value;
@ -2102,7 +2102,7 @@ class AndroidLayoutAlgorithm {
int get hashCode => _value.hashCode;
}
///Class that represents an Android-specific class used to configure the WebView's behavior when a secure origin attempts to load a resource from an insecure origin.
///An Android-specific class used to configure the WebView's behavior when a secure origin attempts to load a resource from an insecure origin.
///
///**NOTE**: available on Android 21+.
class AndroidMixedContentMode {
@ -2167,7 +2167,7 @@ class AndroidMixedContentMode {
int get hashCode => _value.hashCode;
}
///Class that represents an iOS-specific class used to set the level of granularity with which the user can interactively select content in the web view.
///An iOS-specific class used to set the level of granularity with which the user can interactively select content in the web view.
class IOSWKSelectionGranularity {
final int _value;
@ -2215,7 +2215,7 @@ class IOSWKSelectionGranularity {
int get hashCode => _value.hashCode;
}
///Class that represents an iOS-specific class used to specify a `dataDetectoryTypes` value that adds interactivity to web content that matches the value.
///An iOS-specific class used to specify a `dataDetectoryTypes` value that adds interactivity to web content that matches the value.
///
///**NOTE**: available on iOS 10.0+.
class IOSWKDataDetectorTypes {
@ -2390,7 +2390,7 @@ class UserPreferredContentMode {
int get hashCode => _value.hashCode;
}
///Class that represents an iOS-specific class used to specify the modal presentation style when presenting a view controller.
///An iOS-specific class used to specify the modal presentation style when presenting a view controller.
class IOSUIModalPresentationStyle {
final int _value;
@ -2490,7 +2490,7 @@ class IOSUIModalPresentationStyle {
int get hashCode => _value.hashCode;
}
///Class that represents an iOS-specific class used to specify the transition style when presenting a view controller.
///An iOS-specific class used to specify the transition style when presenting a view controller.
class IOSUIModalTransitionStyle {
final int _value;
@ -2556,7 +2556,7 @@ class IOSUIModalTransitionStyle {
int get hashCode => _value.hashCode;
}
///Class that represents an iOS-specific class used to set the custom style for the dismiss button.
///An iOS-specific class used to set the custom style for the dismiss button.
///
///**NOTE**: available on iOS 11.0+.
class IOSSafariDismissButtonStyle {
@ -4618,7 +4618,7 @@ class FormResubmissionAction {
}
}
///Class that represents an Android-specific class used to configure the WebView's over-scroll mode.
///An Android-specific class used to configure the WebView's over-scroll mode.
///Setting the over-scroll mode of a WebView will have an effect only if the WebView is capable of scrolling.
class AndroidOverScrollMode {
final int _value;
@ -4674,7 +4674,7 @@ class AndroidOverScrollMode {
int get hashCode => _value.hashCode;
}
///Class that represents an Android-specific class used to configure the style of the scrollbars.
///An Android-specific class used to configure the style of the scrollbars.
///The scrollbars can be overlaid or inset.
///When inset, they add to the padding of the view. And the scrollbars can be drawn inside the padding area or on the edge of the view.
///For example, if a view has a background drawable and you want to draw the scrollbars inside the padding specified by the drawable,
@ -4748,7 +4748,7 @@ class AndroidScrollBarStyle {
int get hashCode => _value.hashCode;
}
///Class that represents an Android-specific class used to configure the position of the vertical scroll bar.
///An Android-specific class used to configure the position of the vertical scroll bar.
class AndroidVerticalScrollbarPosition {
final int _value;
@ -5181,7 +5181,7 @@ class IOSSslError {
int get hashCode => _value.hashCode;
}
///Class that represents an iOS-specific class used to configure how safe area insets are added to the adjusted content inset.
///An iOS-specific class used to configure how safe area insets are added to the adjusted content inset.
///
///**NOTE**: available on iOS 11.0+.
class IOSUIScrollViewContentInsetAdjustmentBehavior {
@ -5576,6 +5576,7 @@ class ContentWorld {
}
///The default world for clients.
// ignore: non_constant_identifier_names
static final ContentWorld DEFAULT_CLIENT =
ContentWorld.world(name: "defaultClient");
@ -5583,6 +5584,7 @@ class ContentWorld {
///This property contains the content world for scripts that the current webpage executes.
///Be careful when manipulating variables in this content world.
///If you modify a variable with the same name as one the webpage uses, you may unintentionally disrupt the normal operation of that page.
// ignore: non_constant_identifier_names
static final ContentWorld PAGE = ContentWorld.world(name: "page");
Map<String, dynamic> toMap() {

View File

@ -98,9 +98,8 @@ class ASN1Object {
}
String? get asString {
var string = value as String?;
if (string != null) {
return string;
if (value is String) {
return value;
}
if (sub != null && sub!.length > 0) {

View File

@ -114,8 +114,8 @@ class X509Certificate {
///Gets the version (version number) value from the certificate.
int? get version {
if (block1 != null) {
var v = firstLeafValue(block: block1!) as List<int>?;
if (v != null) {
var v = firstLeafValue(block: block1!);
if (v is List<int>) {
var index = toIntValue(v);
if (index != null) {
return index.toInt() + 1;
@ -126,8 +126,10 @@ class X509Certificate {
}
///Gets the serialNumber value from the certificate.
List<int> get serialNumber =>
block1?.atIndex(X509BlockPosition.serialNumber)?.value as List<int>;
List<int>? get serialNumber {
var data = block1?.atIndex(X509BlockPosition.serialNumber)?.value;
return data is List<int> ? data : null;
}
///Returns the issuer (issuer distinguished name) value from the certificate as a String.
String? get issuerDistinguishedName {
@ -143,8 +145,8 @@ class X509Certificate {
var issuerBlock = block1?.atIndex(X509BlockPosition.issuer);
if (issuerBlock != null) {
for (var sub in (issuerBlock.sub ?? <ASN1Object>[])) {
var value = firstLeafValue(block: sub) as String?;
if (value != null) {
var value = firstLeafValue(block: sub);
if (value is String) {
result.add(value);
}
}
@ -162,8 +164,8 @@ class X509Certificate {
var oidBlock = issuerBlock.findOid(oidValue: oid);
if (oidBlock != null) {
var sub = oidBlock.parent?.sub;
if (sub != null && sub.length > 0) {
return sub.last.value as String;
if (sub != null && sub.length > 0 && sub.last.value is String) {
return sub.last.value;
} else {
return null;
}
@ -187,8 +189,8 @@ class X509Certificate {
var subjectBlock = block1?.atIndex(X509BlockPosition.subject);
if (subjectBlock != null) {
for (var sub in (subjectBlock.sub ?? <ASN1Object>[])) {
var value = firstLeafValue(block: sub) as String?;
if (value != null) {
var value = firstLeafValue(block: sub);
if (value is String) {
result.add(value);
}
}
@ -206,8 +208,8 @@ class X509Certificate {
var oidBlock = subjectBlock.findOid(oidValue: oid);
if (oidBlock != null) {
var sub = oidBlock.parent?.sub;
if (sub != null && sub.length > 0) {
return sub.last.value as String;
if (sub != null && sub.length > 0 && sub.last.value is String) {
return sub.last.value;
} else {
return null;
}
@ -218,28 +220,33 @@ class X509Certificate {
}
///Gets the notBefore date from the validity period of the certificate.
DateTime? get notBefore =>
block1?.atIndex(X509BlockPosition.dateValidity)?.subAtIndex(0)?.value
as DateTime?;
DateTime? get notBefore {
var data =
block1?.atIndex(X509BlockPosition.dateValidity)?.subAtIndex(0)?.value;
return data is DateTime ? data : null;
}
///Gets the notAfter date from the validity period of the certificate.
DateTime? get notAfter {
var value = block1
?.atIndex(X509BlockPosition.dateValidity)
?.subAtIndex(1)
?.value as DateTime?;
return value;
var data =
block1?.atIndex(X509BlockPosition.dateValidity)?.subAtIndex(1)?.value;
return data is DateTime ? data : null;
}
///Gets the signature value (the raw signature bits) from the certificate.
List<int>? get signature => asn1?[0].subAtIndex(2)?.value as List<int>;
List<int>? get signature {
var data = asn1?[0].subAtIndex(2)?.value;
return data is List<int> ? data : null;
}
///Gets the signature algorithm name for the certificate signature algorithm.
String? get sigAlgName => OID.fromValue(sigAlgOID ?? '')?.name();
///Gets the signature algorithm OID string from the certificate.
String? get sigAlgOID =>
block1?.subAtIndex(2)?.subAtIndex(0)?.value as String?;
String? get sigAlgOID {
var data = block1?.subAtIndex(2)?.subAtIndex(0)?.value;
return data is String ? data : null;
}
///Gets the DER-encoded signature algorithm parameters from this certificate's signature algorithm.
List<int>? get sigAlgParams => null;
@ -264,8 +271,8 @@ class X509Certificate {
if (oidBlock != null) {
var sub = oidBlock.parent?.sub;
if (sub != null && sub.length > 0) {
var data = sub.last.subAtIndex(0)?.value as List<int>?;
int bits = (data != null && data.length > 0) ? data.first : 0;
var data = sub.last.subAtIndex(0)?.value;
int bits = (data is List<int> && data.length > 0) ? data.first : 0;
for (var index = 0; index < 8; index++) {
var value = bits & (1 << index).toUnsigned(8) != 0;
result.insert(0, value);

View File

@ -108,18 +108,18 @@ class X509Extension {
case 1:
case 2:
case 6:
String? name = item.value as String?;
var name = item.value is String ? item.value : null;
return name;
case 4:
return ASN1DistinguishedNames.string(block: item);
case 7:
var ip = item.value as List<int>?;
var ip = item.value is List<int> ? item.value : null;
if (ip != null) {
return ip.map((e) => e.toString()).join(".");
}
break;
case 8:
var value = item.value as String?;
var value = item.value is String ? item.value : null;
if (value != null) {
try {
var data = utf8.encode(value);
@ -139,12 +139,14 @@ class X509Extension {
class BasicConstraintExtension extends X509Extension {
BasicConstraintExtension({required block}) : super(block: block);
bool get isCA =>
valueAsBlock?.subAtIndex(0)?.subAtIndex(0)?.value as bool? ?? false;
bool get isCA {
var data = valueAsBlock?.subAtIndex(0)?.subAtIndex(0)?.value;
return data is bool ? data : false;
}
int? get pathLenConstraint {
var data = valueAsBlock?.subAtIndex(0)?.subAtIndex(0)?.value as List<int>?;
if (data != null) {
var data = valueAsBlock?.subAtIndex(0)?.subAtIndex(0)?.value;
if (data is List<int>) {
return data.length;
}
return null;

View File

@ -1,6 +1,6 @@
name: flutter_inappwebview
description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window.
version: 5.0.0-nullsafety.0
version: 5.0.1-nullsafety.1
homepage: https://github.com/pichillilorenzo/flutter_inappwebview
environment: