added debuggingEnabled option, fixed InputConnection error on Android

This commit is contained in:
Lorenzo Pichilli 2019-10-29 17:51:55 +01:00
parent ab3b5c3935
commit fed99ec0e9
18 changed files with 704 additions and 129 deletions

View File

@ -15,13 +15,20 @@
</component>
<component name="ChangeListManager">
<list default="true" id="9b41f7a2-a71e-4923-91fb-249d7815b3e7" name="Default" comment="">
<change afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/DisplayListenerProxy.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InputAwareWebView.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/ThreadedInputConnectionProxyAdapterView.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/CHANGELOG.md" beforeDir="false" afterPath="$PROJECT_DIR$/CHANGELOG.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerHandler.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebView.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebChromeClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebChromeClient.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebViewFactory.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebViewFactory.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/lib/inline_example.screen.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/inline_example.screen.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/lib/webview_example.screen.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/webview_example.screen.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/Classes/InAppWebView.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/InAppWebView.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/Classes/InAppWebViewOptions.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/InAppWebViewOptions.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/in_app_browser.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/in_app_browser.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/in_app_webview.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/in_app_webview.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/types.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/types.dart" afterDir="false" />
@ -45,11 +52,11 @@
<component name="ExecutionTargetManager" SELECTED_TARGET="Pixel_3_XL_API_24" />
<component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file pinned="false" current-in-tab="false">
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="300">
<caret line="20" column="62" selection-start-line="20" selection-start-column="62" selection-end-line="20" selection-end-column="62" />
<state relative-caret-position="557">
<caret line="39" column="8" lean-forward="true" selection-start-line="39" selection-start-column="8" selection-end-line="39" selection-end-column="8" />
</state>
</provider>
</entry>
@ -57,8 +64,8 @@
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/webview_options.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="499">
<caret line="446" column="12" selection-start-line="446" selection-start-column="12" selection-end-line="446" selection-end-column="12" />
<state relative-caret-position="150">
<caret line="10" column="22" selection-start-line="10" selection-start-column="22" selection-end-line="10" selection-end-column="22" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
@ -78,20 +85,11 @@
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="14" selection-start-line="2" selection-start-column="14" selection-end-line="2" selection-end-column="14" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="380">
<caret line="462" column="29" selection-start-line="462" selection-start-column="12" selection-end-line="462" selection-end-column="29" />
<state relative-caret-position="150">
<caret line="169" column="79" selection-start-line="169" selection-start-column="79" selection-end-line="169" selection-end-column="79" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
@ -102,8 +100,8 @@
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/in_app_browser.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="372">
<caret line="397" column="102" selection-start-line="397" selection-start-column="102" selection-end-line="397" selection-end-column="102" />
<state relative-caret-position="549">
<caret line="409" column="5" selection-start-line="409" selection-start-column="5" selection-end-line="409" selection-end-column="5" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
@ -114,8 +112,8 @@
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/types.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="261">
<caret line="264" column="32" selection-start-line="264" selection-start-column="32" selection-end-line="264" selection-end-column="32" />
<state relative-caret-position="-453">
<caret line="241" selection-start-line="241" selection-end-line="241" />
<folding>
<element signature="e#0#32#0" expanded="true" />
</folding>
@ -132,11 +130,11 @@
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="true">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/example/lib/inline_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-625">
<caret line="100" column="14" selection-start-line="100" selection-start-column="14" selection-end-line="100" selection-end-column="14" />
<state relative-caret-position="1401">
<caret line="222" column="12" selection-start-line="222" selection-start-column="12" selection-end-line="222" selection-end-column="12" />
<folding>
<element signature="e#0#22#0" expanded="true" />
</folding>
@ -156,7 +154,6 @@
</component>
<component name="FindInProjectRecents">
<findStrings>
<find>minimumFontSize</find>
<find>defaultWebpagePreferences</find>
<find>contentBlockers</find>
<find>preferredContentMode</find>
@ -183,9 +180,10 @@
<find>ConsoleMessageLevel</find>
<find>ConsoleMessage</find>
<find>appCa</find>
<find>iOSInAppWebViewUserPreferredContentMode</find>
<find>SafeBrowsingResponse</find>
<find>onSafeBrowsingHit</find>
<find>SafeBrowsingResponse</find>
<find>onReceivedHttpAuthRequest</find>
<find>iOSInAppWebViewUserPreferredContentMode</find>
</findStrings>
<replaceStrings>
<replace>activity.getPreferences(0)</replace>
@ -244,19 +242,19 @@
<option value="$PROJECT_DIR$/lib/flutter_inappbrowser.dart" />
<option value="$PROJECT_DIR$/example/lib/chrome_safari_example.screen.dart" />
<option value="$PROJECT_DIR$/lib/src/chrome_safari_browser.dart" />
<option value="$PROJECT_DIR$/example/pubspec.yaml" />
<option value="$PROJECT_DIR$/example/ios/Runner/Info.plist" />
<option value="$PROJECT_DIR$/pubspec.yaml" />
<option value="$PROJECT_DIR$/example/lib/main.dart" />
<option value="$PROJECT_DIR$/lib/src/content_blocker.dart" />
<option value="$PROJECT_DIR$/example/assets/index.html" />
<option value="$PROJECT_DIR$/lib/src/in_app_browser.dart" />
<option value="$PROJECT_DIR$/lib/src/in_app_webview.dart" />
<option value="$PROJECT_DIR$/example/lib/webview_example.screen.dart" />
<option value="$PROJECT_DIR$/lib/src/types.dart" />
<option value="$PROJECT_DIR$/CHANGELOG.md" />
<option value="$PROJECT_DIR$/lib/src/webview_options.dart" />
<option value="$PROJECT_DIR$/lib/src/in_app_webview.dart" />
<option value="$PROJECT_DIR$/lib/src/in_app_browser.dart" />
<option value="$PROJECT_DIR$/example/pubspec.yaml" />
<option value="$PROJECT_DIR$/example/lib/inline_example.screen.dart" />
<option value="$PROJECT_DIR$/lib/src/webview_options.dart" />
<option value="$PROJECT_DIR$/CHANGELOG.md" />
</list>
</option>
</component>
@ -502,8 +500,8 @@
<frame x="0" y="23" width="1920" height="1057" extended-state="6" />
<editor active="true" />
<layout>
<window_info active="true" content_ui="combo" id="Project" order="0" sideWeight="0.59641874" visible="true" weight="0.15867944" />
<window_info id="Structure" order="1" sideWeight="0.40358126" side_tool="true" visible="true" weight="0.15867944" />
<window_info content_ui="combo" id="Project" order="0" sideWeight="0.5961821" visible="true" weight="0.15867944" />
<window_info id="Structure" order="1" sideWeight="0.40381792" side_tool="true" visible="true" weight="0.15867944" />
<window_info id="Designer" order="2" />
<window_info id="Build Variants" order="3" side_tool="true" />
<window_info id="Captures" order="4" side_tool="true" weight="0.32936507" />
@ -513,7 +511,7 @@
<window_info id="Resources Explorer" order="8" />
<window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Find" order="1" weight="0.32642487" />
<window_info anchor="bottom" id="Run" order="2" sideWeight="0.49307775" visible="true" weight="0.2476684" />
<window_info anchor="bottom" id="Run" order="2" sideWeight="0.49307775" weight="0.4580311" />
<window_info anchor="bottom" id="Debug" order="3" weight="0.34196892" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
@ -521,7 +519,7 @@
<window_info anchor="bottom" id="Android Profiler" order="7" show_stripe_button="false" />
<window_info anchor="bottom" id="Event Log" order="8" sideWeight="0.50692225" side_tool="true" weight="0.38445595" />
<window_info anchor="bottom" id="Version Control" order="9" weight="0.32953367" />
<window_info anchor="bottom" id="Terminal" order="10" sideWeight="0.49533224" weight="0.29430053" />
<window_info active="true" anchor="bottom" id="Terminal" order="10" sideWeight="0.49533224" visible="true" weight="0.29430053" />
<window_info anchor="bottom" id="Logcat" order="11" weight="0.32953367" />
<window_info anchor="bottom" id="Messages" order="12" weight="0.226943" />
<window_info anchor="bottom" id="Dependency Viewer" order="13" weight="0.32800853" />
@ -757,13 +755,6 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="345">
<caret line="23" column="28" selection-start-line="23" selection-start-column="28" selection-end-line="23" selection-end-column="28" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Podfile">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="990">
@ -802,10 +793,37 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<entry file="file://$USER_HOME$/flutter/packages/flutter/lib/src/material/dialog.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="14" selection-start-line="2" selection-start-column="14" selection-end-line="2" selection-end-column="14" />
<state relative-caret-position="307">
<caret line="690" column="10" selection-start-line="690" selection-start-column="10" selection-end-line="690" selection-end-column="10" />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib/io/platform.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="233">
<caret line="67" selection-start-line="67" selection-end-line="67" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/types.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-453">
<caret line="241" selection-start-line="241" selection-end-line="241" />
<folding>
<element signature="e#0#32#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/inline_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="1401">
<caret line="222" column="12" selection-start-line="222" selection-start-column="12" selection-end-line="222" selection-end-column="12" />
<folding>
<element signature="e#0#22#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
@ -816,10 +834,37 @@
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/flutter/packages/flutter/lib/src/material/dialog.dart">
<entry file="file://$PROJECT_DIR$/lib/src/in_app_browser.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="307">
<caret line="690" column="10" selection-start-line="690" selection-start-column="10" selection-end-line="690" selection-end-column="10" />
<state relative-caret-position="549">
<caret line="409" column="5" selection-start-line="409" selection-start-column="5" selection-end-line="409" selection-end-column="5" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="150">
<caret line="169" column="79" selection-start-line="169" selection-start-column="79" selection-end-line="169" selection-end-column="79" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="14" selection-start-line="2" selection-start-column="14" selection-end-line="2" selection-end-column="14" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="345">
<caret line="23" column="28" selection-start-line="23" selection-start-column="28" selection-end-line="23" selection-end-column="28" />
</state>
</provider>
</entry>
@ -833,67 +878,20 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="300">
<caret line="20" column="62" selection-start-line="20" selection-start-column="62" selection-end-line="20" selection-end-column="62" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/webview_options.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="499">
<caret line="446" column="12" selection-start-line="446" selection-start-column="12" selection-end-line="446" selection-end-column="12" />
<state relative-caret-position="150">
<caret line="10" column="22" selection-start-line="10" selection-start-column="22" selection-end-line="10" selection-end-column="22" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/in_app_browser.dart">
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="372">
<caret line="397" column="102" selection-start-line="397" selection-start-column="102" selection-end-line="397" selection-end-column="102" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/types.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="261">
<caret line="264" column="32" selection-start-line="264" selection-start-column="32" selection-end-line="264" selection-end-column="32" />
<folding>
<element signature="e#0#32#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="380">
<caret line="462" column="29" selection-start-line="462" selection-start-column="12" selection-end-line="462" selection-end-column="29" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib/io/platform.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="233">
<caret line="67" selection-start-line="67" selection-end-line="67" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/inline_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-625">
<caret line="100" column="14" selection-start-line="100" selection-start-column="14" selection-end-line="100" selection-end-column="14" />
<folding>
<element signature="e#0#22#0" expanded="true" />
</folding>
<state relative-caret-position="557">
<caret line="39" column="8" lean-forward="true" selection-start-line="39" selection-start-column="8" selection-end-line="39" selection-end-column="8" />
</state>
</provider>
</entry>

View File

@ -13,17 +13,19 @@
- Added `onLoadResourceCustomScheme` event and `resourceCustomSchemes` option to set custom schemes that WebView must handle to load resources
- Added `onTargetBlank` event and `useOnTargetBlank` option to manage links with `target="_blank"`
- Added `ContentBlocker`, `ContentBlockerTrigger` and `ContentBlockerAction` classes and the `contentBlockers` option that allows to define a set of rules to use to block content in the WebView
- Added new WebView option `minimumFontSize`
- Added new WebView options: `minimumFontSize`, `debuggingEnabled`
- Added new Android WebView options: `allowContentAccess`, `allowFileAccess`, `allowFileAccessFromFileURLs`, `allowUniversalAccessFromFileURLs`, `appCacheEnabled`, `appCachePath`, `blockNetworkImage`, `blockNetworkLoads`, `cacheMode`, `cursiveFontFamily`, `defaultFixedFontSize`, `defaultFontSize`, `defaultTextEncodingName`, `disabledActionModeMenuItems`, `fantasyFontFamily`, `fixedFontFamily`, `forceDark`, `geolocationEnabled`, `layoutAlgorithm`, `loadWithOverviewMode`, `loadsImagesAutomatically`, `minimumLogicalFontSize`, `needInitialFocus`, `offscreenPreRaster`, `sansSerifFontFamily`, `serifFontFamily`, `standardFontFamily`
- Added new iOS WebView options: `applicationNameForUserAgent`, `isFraudulentWebsiteWarningEnabled`, `selectionGranularity`, `dataDetectorTypes`, `preferredContentMode`
- Added `onGeolocationPermissionsShowPrompt` event and `GeolocationPermissionShowPromptResponse` class (available only for Android)
- Added `startSafeBrowsing`, `setSafeBrowsingWhitelist` and `getSafeBrowsingPrivacyPolicyUrl` methods (available only for Android)
- Added `onSafeBrowsingHit` event (available only for Android)
- Added `onJsAlert`, `onJsConfirm` and `onJsPrompt` events to manage javascript popup dialogs
- Fixed `InputConnection` error on Android
### BREAKING CHANGES
- Deleted `WebResourceRequest` class
- Updated `WebResourceResponse` class
- Updated `ConsoleMessageLevel` class
- Updated `onLoadResource` event
- WebView options are now available with the new corresponding classes: `InAppWebViewOptions`, `AndroidInAppWebViewOptions`, `iOSInAppWebViewOptions`, `InAppBrowserOptions`, `AndroidInAppBrowserOptions`, `iOSInAppBrowserOptions`, `AndroidChromeCustomTabsOptions` and `iOSChromeCustomTabsOptions`

View File

@ -3,21 +3,26 @@ package com.pichillilorenzo.flutter_inappbrowser;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.DisplayListenerProxy;
import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebView;
import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebViewOptions;
import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InputAwareWebView;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import static io.flutter.plugin.common.MethodChannel.MethodCallHandler;
@ -31,14 +36,19 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
public final Activity activity;
public InAppWebView webView;
public MethodChannel channel;
public final MethodChannel channel;
public final Registrar registrar;
public FlutterWebView(Registrar registrar, int id, HashMap<String, Object> params) {
public FlutterWebView(Registrar registrar, int id, HashMap<String, Object> params, View containerView) {
this.registrar = registrar;
this.activity = registrar.activity();
DisplayListenerProxy displayListenerProxy = new DisplayListenerProxy();
DisplayManager displayManager =
(DisplayManager) this.registrar.context().getSystemService(Context.DISPLAY_SERVICE);
displayListenerProxy.onPreWebViewInitialization(displayManager);
String initialUrl = (String) params.get("initialUrl");
String initialFile = (String) params.get("initialFile");
Map<String, String> initialData = (Map<String, String>) params.get("initialData");
@ -48,7 +58,9 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
InAppWebViewOptions options = new InAppWebViewOptions();
options.parse(initialOptions);
webView = new InAppWebView(registrar, this, id, options);
webView = new InAppWebView(registrar, this, id, options, containerView);
displayListenerProxy.onPostWebViewInitialization(displayManager);
webView.prepare();
channel = new MethodChannel(registrar.messenger(), "com.pichillilorenzo/flutter_inappwebview_" + id);
@ -257,9 +269,15 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
}
@Override
public void onInputConnectionLocked() {}
public void onInputConnectionLocked() {
if (webView.inAppBrowserActivity == null)
webView.lockInputConnection();
}
@Override
public void onInputConnectionUnlocked() {}
public void onInputConnectionUnlocked() {
if (webView.inAppBrowserActivity == null)
webView.unlockInputConnection();
}
}

View File

@ -1,6 +1,7 @@
package com.pichillilorenzo.flutter_inappbrowser;
import android.content.Context;
import android.view.View;
import java.util.HashMap;
@ -11,16 +12,18 @@ import io.flutter.plugin.platform.PlatformViewFactory;
public class FlutterWebViewFactory extends PlatformViewFactory {
private final Registrar registrar;
private final View containerView;
public FlutterWebViewFactory(Registrar registrar) {
public FlutterWebViewFactory(Registrar registrar, View containerView) {
super(StandardMessageCodec.INSTANCE);
this.registrar = registrar;
this.containerView = containerView;
}
@Override
public PlatformView create(Context context, int id, Object args) {
HashMap<String, Object> params = (HashMap<String, Object>) args;
return new FlutterWebView(registrar, id, params);
return new FlutterWebView(registrar, id, params, containerView);
}
}

View File

@ -86,7 +86,7 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
registrar
.platformViewRegistry()
.registerViewFactory(
"com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(registrar));
"com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(registrar, registrar.view()));
}
}

View File

@ -0,0 +1,122 @@
package com.pichillilorenzo.flutter_inappbrowser.InAppWebView;
import static android.hardware.display.DisplayManager.DisplayListener;
import android.annotation.TargetApi;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.util.Log;
import java.lang.reflect.Field;
import java.util.ArrayList;
/**
* Works around an Android WebView bug by filtering some DisplayListener invocations.
* https://github.com/flutter/plugins/blob/master/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
public
class DisplayListenerProxy {
private static final String TAG = "DisplayListenerProxy";
private ArrayList<DisplayListener> listenersBeforeWebView;
/** Should be called prior to the webview's initialization. */
public void onPreWebViewInitialization(DisplayManager displayManager) {
listenersBeforeWebView = yoinkDisplayListeners(displayManager);
}
/** Should be called after the webview's initialization. */
public void onPostWebViewInitialization(final DisplayManager displayManager) {
final ArrayList<DisplayListener> webViewListeners = yoinkDisplayListeners(displayManager);
// We recorded the list of listeners prior to initializing webview, any new listeners we see
// after initializing the webview are listeners added by the webview.
webViewListeners.removeAll(listenersBeforeWebView);
if (webViewListeners.isEmpty()) {
// The Android WebView registers a single display listener per process (even if there
// are multiple WebView instances) so this list is expected to be non-empty only the
// first time a webview is initialized.
// Note that in an add2app scenario if the application had instantiated a non Flutter
// WebView prior to instantiating the Flutter WebView we are not able to get a reference
// to the WebView's display listener and can't work around the bug.
//
// This means that webview resizes in add2app Flutter apps with a non Flutter WebView
// running on a system with a webview prior to 58.0.3029.125 may crash (the Android's
// behavior seems to be racy so it doesn't always happen).
return;
}
for (DisplayListener webViewListener : webViewListeners) {
// Note that while DisplayManager.unregisterDisplayListener throws when given an
// unregistered listener, this isn't an issue as the WebView code never calls
// unregisterDisplayListener.
displayManager.unregisterDisplayListener(webViewListener);
// We never explicitly unregister this listener as the webview's listener is never
// unregistered (it's released when the process is terminated).
displayManager.registerDisplayListener(
new DisplayListener() {
@Override
public void onDisplayAdded(int displayId) {
for (DisplayListener webViewListener : webViewListeners) {
webViewListener.onDisplayAdded(displayId);
}
}
@Override
public void onDisplayRemoved(int displayId) {
for (DisplayListener webViewListener : webViewListeners) {
webViewListener.onDisplayRemoved(displayId);
}
}
@Override
public void onDisplayChanged(int displayId) {
if (displayManager.getDisplay(displayId) == null) {
return;
}
for (DisplayListener webViewListener : webViewListeners) {
webViewListener.onDisplayChanged(displayId);
}
}
},
null);
}
}
@SuppressWarnings({"unchecked", "PrivateApi"})
private static ArrayList<DisplayListener> yoinkDisplayListeners(DisplayManager displayManager) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// We cannot use reflection on Android P, but it shouldn't matter as it shipped
// with WebView 66.0.3359.158 and the WebView version the bug this code is working around was
// fixed in 61.0.3116.0.
return new ArrayList<>();
}
try {
Field displayManagerGlobalField = DisplayManager.class.getDeclaredField("mGlobal");
displayManagerGlobalField.setAccessible(true);
Object displayManagerGlobal = displayManagerGlobalField.get(displayManager);
Field displayListenersField =
displayManagerGlobal.getClass().getDeclaredField("mDisplayListeners");
displayListenersField.setAccessible(true);
ArrayList<Object> delegates =
(ArrayList<Object>) displayListenersField.get(displayManagerGlobal);
Field listenerField = null;
ArrayList<DisplayManager.DisplayListener> listeners = new ArrayList<>();
for (Object delegate : delegates) {
if (listenerField == null) {
listenerField = delegate.getClass().getField("mListener");
listenerField.setAccessible(true);
}
DisplayManager.DisplayListener listener =
(DisplayManager.DisplayListener) listenerField.get(delegate);
listeners.add(listener);
}
return listeners;
} catch (NoSuchFieldException | IllegalAccessException e) {
Log.w(TAG, "Could not extract WebView's display listeners. " + e);
return new ArrayList<>();
}
}
}

View File

@ -10,9 +10,9 @@ import android.util.AttributeSet;
import android.util.JsonReader;
import android.util.JsonToken;
import android.util.Log;
import android.view.View;
import android.webkit.CookieManager;
import android.webkit.DownloadListener;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebBackForwardList;
import android.webkit.WebHistoryItem;
@ -41,7 +41,7 @@ import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import okhttp3.OkHttpClient;
public class InAppWebView extends WebView {
final public class InAppWebView extends InputAwareWebView {
static final String LOG_TAG = "InAppWebView";
@ -107,8 +107,8 @@ public class InAppWebView extends WebView {
super(context, attrs, defaultStyle);
}
public InAppWebView(PluginRegistry.Registrar registrar, Object obj, int id, InAppWebViewOptions options) {
super(registrar.activeContext());
public InAppWebView(PluginRegistry.Registrar registrar, Object obj, int id, InAppWebViewOptions options, View containerView) {
super(registrar.activeContext(), containerView);
this.registrar = registrar;
if (obj instanceof InAppBrowserActivity)
this.inAppBrowserActivity = (InAppBrowserActivity) obj;
@ -146,6 +146,9 @@ public class InAppWebView extends WebView {
WebSettings settings = getSettings();
settings.setJavaScriptEnabled(options.javaScriptEnabled);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
setWebContentsDebuggingEnabled(options.debuggingEnabled);
}
settings.setJavaScriptCanOpenWindowsAutomatically(options.javaScriptCanOpenWindowsAutomatically);
settings.setBuiltInZoomControls(options.builtInZoomControls);
settings.setDisplayZoomControls(options.displayZoomControls);

View File

@ -17,6 +17,7 @@ import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.WebViewDatabase;
import androidx.annotation.RequiresApi;
@ -296,9 +297,56 @@ public class InAppWebViewClient extends WebViewClient {
* On received http auth request.
*/
@Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
// By default handle 401 like we'd normally do!
super.onReceivedHttpAuthRequest(view, handler, host, realm);
public void onReceivedHttpAuthRequest(final WebView view, final HttpAuthHandler handler, final String host, final String realm) {
Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("host", host);
obj.put("realm", realm);
getChannel().invokeMethod("onReceivedHttpAuthRequest", obj, new MethodChannel.Result() {
@Override
public void success(Object response) {
if (response != null) {
Map<String, Object> responseMap = (Map<String, Object>) response;
Integer action = (Integer) responseMap.get("action");
Log.d(LOG_TAG, "\n\naction: " + action);
if (action != null) {
switch (action) {
case 0:
handler.cancel();
return;
case 1:
String username = (String) responseMap.get("username");
String password = (String) responseMap.get("password");
Boolean permanentPersistence = (Boolean) responseMap.get("permanentPersistence");
if (permanentPersistence != null && permanentPersistence && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WebViewDatabase.getInstance(view.getContext()).setHttpAuthUsernamePassword(host, realm, username, password);
}
handler.proceed(username, password);
return;
case 2:
handler.useHttpAuthUsernamePassword();
return;
}
}
}
handler.cancel();
}
@Override
public void error(String s, String s1, Object o) {
Log.e(LOG_TAG, s + ", " + s1);
}
@Override
public void notImplemented() {
handler.cancel();
}
});
}
@Override
@ -324,9 +372,6 @@ public class InAppWebViewClient extends WebViewClient {
Boolean report = (Boolean) responseMap.get("report");
Integer action = (Integer) responseMap.get("action");
Log.d(LOG_TAG, "\n\nreport: " + report);
Log.d(LOG_TAG, "\n\naction: " + action);
report = report != null ? report : true;
if (action != null) {

View File

@ -19,6 +19,7 @@ public class InAppWebViewOptions extends Options {
public boolean clearCache = false;
public String userAgent = "";
public boolean javaScriptEnabled = true;
public boolean debuggingEnabled = false;
public boolean javaScriptCanOpenWindowsAutomatically = false;
public boolean mediaPlaybackRequiresUserGesture = true;
public Integer textZoom = 100;

View File

@ -0,0 +1,169 @@
package com.pichillilorenzo.flutter_inappbrowser.InAppWebView;
import static android.content.Context.INPUT_METHOD_SERVICE;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebView;
/**
* A WebView subclass that mirrors the same implementation hacks that the system WebView does in
* order to correctly create an InputConnection.
*
* https://github.com/flutter/plugins/blob/master/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java
*/
public class InputAwareWebView extends WebView {
public View containerView;
private View threadedInputConnectionProxyView;
private ThreadedInputConnectionProxyAdapterView proxyAdapterView;
public InputAwareWebView(Context context, View containerView) {
super(context);
this.containerView = containerView;
}
public InputAwareWebView(Context context, AttributeSet attrs) {
super(context, attrs);
this.containerView = null;
}
public InputAwareWebView(Context context) {
super(context);
this.containerView = null;
}
public InputAwareWebView(Context context, AttributeSet attrs, int defaultStyle) {
super(context, attrs, defaultStyle);
this.containerView = null;
}
/**
* Set our proxy adapter view to use its cached input connection instead of creating new ones.
*
* <p>This is used to avoid losing our input connection when the virtual display is resized.
*/
public void lockInputConnection() {
if (proxyAdapterView == null) {
return;
}
proxyAdapterView.setLocked(true);
}
/** Sets the proxy adapter view back to its default behavior. */
public void unlockInputConnection() {
if (proxyAdapterView == null) {
return;
}
proxyAdapterView.setLocked(false);
}
/** Restore the original InputConnection, if needed. */
void dispose() {
resetInputConnection();
}
/**
* Creates an InputConnection from the IME thread when needed.
*
* <p>We only need to create a {@link ThreadedInputConnectionProxyAdapterView} and create an
* InputConnectionProxy on the IME thread when WebView is doing the same thing. So we rely on the
* system calling this method for WebView's proxy view in order to know when we need to create our
* own.
*
* <p>This method would normally be called for any View that used the InputMethodManager. We rely
* on flutter/engine filtering the calls we receive down to the ones in our hierarchy and the
* system WebView in order to know whether or not the system WebView expects an InputConnection on
* the IME thread.
*/
@Override
public boolean checkInputConnectionProxy(final View view) {
if (containerView == null)
return super.checkInputConnectionProxy(view);
// Check to see if the view param is WebView's ThreadedInputConnectionProxyView.
View previousProxy = threadedInputConnectionProxyView;
threadedInputConnectionProxyView = view;
if (previousProxy == view) {
// This isn't a new ThreadedInputConnectionProxyView. Ignore it.
return super.checkInputConnectionProxy(view);
}
// We've never seen this before, so we make the assumption that this is WebView's
// ThreadedInputConnectionProxyView. We are making the assumption that the only view that could
// possibly be interacting with the IMM here is WebView's ThreadedInputConnectionProxyView.
proxyAdapterView =
new ThreadedInputConnectionProxyAdapterView(
/*containerView=*/ containerView,
/*targetView=*/ view,
/*imeHandler=*/ view.getHandler());
setInputConnectionTarget(/*targetView=*/ proxyAdapterView);
return super.checkInputConnectionProxy(view);
}
/**
* Ensure that input creation happens back on {@link #containerView}'s thread once this view no
* longer has focus.
*
* <p>The logic in {@link #checkInputConnectionProxy} forces input creation to happen on Webview's
* thread for all connections. We undo it here so users will be able to go back to typing in
* Flutter UIs as expected.
*/
@Override
public void clearFocus() {
super.clearFocus();
if (containerView != null)
resetInputConnection();
}
/**
* Ensure that input creation happens back on {@link #containerView}.
*
* <p>The logic in {@link #checkInputConnectionProxy} forces input creation to happen on Webview's
* thread for all connections. We undo it here so users will be able to go back to typing in
* Flutter UIs as expected.
*/
private void resetInputConnection() {
if (proxyAdapterView == null) {
// No need to reset the InputConnection to the default thread if we've never changed it.
return;
}
setInputConnectionTarget(/*targetView=*/ containerView);
}
/**
* This is the crucial trick that gets the InputConnection creation to happen on the correct
* thread pre Android N.
* https://cs.chromium.org/chromium/src/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java?l=169&rcl=f0698ee3e4483fad5b0c34159276f71cfaf81f3a
*
* <p>{@code targetView} should have a {@link View#getHandler} method with the thread that future
* InputConnections should be created on.
*/
private void setInputConnectionTarget(final View targetView) {
targetView.requestFocus();
containerView.post(
new Runnable() {
@Override
public void run() {
InputMethodManager imm =
(InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
// This is a hack to make InputMethodManager believe that the target view now has focus.
// As a result, InputMethodManager will think that targetView is focused, and will call
// getHandler() of the view when creating input connection.
// Step 1: Set targetView as InputMethodManager#mNextServedView. This does not affect
// the real window focus.
targetView.onWindowFocusChanged(true);
// Step 2: Have InputMethodManager focus in on targetView. As a result, IMM will call
// onCreateInputConnection() on targetView on the same thread as
// targetView.getHandler(). It will also call subsequent InputConnection methods on this
// thread. This is the IME thread in cases where targetView is our proxyAdapterView.
imm.isActive(containerView);
}
});
}
}

View File

@ -0,0 +1,99 @@
package com.pichillilorenzo.flutter_inappbrowser.InAppWebView;
import android.os.Handler;
import android.os.IBinder;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
/**
* A fake View only exposed to InputMethodManager.
*
* https://github.com/flutter/plugins/blob/master/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/ThreadedInputConnectionProxyAdapterView.java
*/
final class ThreadedInputConnectionProxyAdapterView extends View {
final Handler imeHandler;
final IBinder windowToken;
final View containerView;
final View rootView;
final View targetView;
private boolean triggerDelayed = true;
private boolean isLocked = false;
private InputConnection cachedConnection;
ThreadedInputConnectionProxyAdapterView(View containerView, View targetView, Handler imeHandler) {
super(containerView.getContext());
this.imeHandler = imeHandler;
this.containerView = containerView;
this.targetView = targetView;
windowToken = containerView.getWindowToken();
rootView = containerView.getRootView();
setFocusable(true);
setFocusableInTouchMode(true);
setVisibility(VISIBLE);
}
/** Returns whether or not this is currently asynchronously acquiring an input connection. */
boolean isTriggerDelayed() {
return triggerDelayed;
}
/** Sets whether or not this should use its previously cached input connection. */
void setLocked(boolean locked) {
isLocked = locked;
}
/**
* This is expected to be called on the IME thread. See the setup required for this in {@link
* InputAwareWebView#checkInputConnectionProxy(View)}.
*
* <p>Delegates to ThreadedInputConnectionProxyView to get WebView's input connection.
*/
@Override
public InputConnection onCreateInputConnection(final EditorInfo outAttrs) {
triggerDelayed = false;
InputConnection inputConnection =
(isLocked) ? cachedConnection : targetView.onCreateInputConnection(outAttrs);
triggerDelayed = true;
cachedConnection = inputConnection;
return inputConnection;
}
@Override
public boolean checkInputConnectionProxy(View view) {
return true;
}
@Override
public boolean hasWindowFocus() {
// None of our views here correctly report they have window focus because of how we're embedding
// the platform view inside of a virtual display.
return true;
}
@Override
public View getRootView() {
return rootView;
}
@Override
public boolean onCheckIsTextEditor() {
return true;
}
@Override
public boolean isFocused() {
return true;
}
@Override
public IBinder getWindowToken() {
return windowToken;
}
@Override
public Handler getHandler() {
return imeHandler;
}
}

View File

@ -70,6 +70,7 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
initialHeaders: {},
initialOptions: [
InAppWebViewOptions(
clearCache: true,
useShouldOverrideUrlLoading: true,
useOnTargetBlank: true,
//useOnLoadResource: true,

View File

@ -202,7 +202,10 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
scrollView.showsVerticalScrollIndicator = (options?.verticalScrollBarEnabled)!
scrollView.showsHorizontalScrollIndicator = (options?.horizontalScrollBarEnabled)!
// options.debuggingEnabled is always enabled for iOS.
if (options?.clearCache)! {
clearCache()
}
@ -745,6 +748,54 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
}
}
public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let host = challenge.protectionSpace.host
let realm = challenge.protectionSpace.realm
onReceivedHttpAuthRequest(host: host, realm: realm, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
completionHandler(.performDefaultHandling, nil)
}
else {
//WKWebsiteDataStore.default()
//URLCredentialStorage()
var response: [String: Any]
if let r = result {
response = r as! [String: Any]
var action = response["action"] as? Int
action = action != nil ? action : 0;
switch action {
case 0:
completionHandler(.cancelAuthenticationChallenge, nil)
break
case 1:
let username = response["username"] as! String
let password = response["password"] as! String
let permanentPersistence = response["permanentPersistence"] as? Bool ?? false
let persistence = (permanentPersistence) ? URLCredential.Persistence.permanent : URLCredential.Persistence.forSession
let credential = URLCredential(user: username, password: password, persistence: persistence)
completionHandler(.useCredential, credential)
break
case 2:
if let credential = challenge.proposedCredential {
completionHandler(.useCredential, credential)
}
else {
completionHandler(.performDefaultHandling, nil)
}
break
default:
completionHandler(.performDefaultHandling, nil)
}
return;
}
completionHandler(.performDefaultHandling, nil)
}
})
}
fileprivate func createAlertDialog(message: String?, responseMessage: String?, confirmButtonTitle: String?, completionHandler: @escaping () -> Void) {
let title = responseMessage != nil && !responseMessage!.isEmpty ? responseMessage : message
let okButton = confirmButtonTitle != nil && !confirmButtonTitle!.isEmpty ? confirmButtonTitle : NSLocalizedString("Ok", comment: "")
@ -765,7 +816,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
onJsAlert(message: message, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
completionHandler()
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
self.createAlertDialog(message: message, responseMessage: nil, confirmButtonTitle: nil, completionHandler: completionHandler)
@ -824,7 +874,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
onJsConfirm(message: message, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
completionHandler(false)
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
self.createConfirmDialog(message: message, responseMessage: nil, confirmButtonTitle: nil, cancelButtonTitle: nil, completionHandler: completionHandler)
@ -898,7 +947,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
onJsPrompt(message: message, defaultValue: defaultValue, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
completionHandler(nil)
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
self.createPromptDialog(message: message, defaultValue: defaultValue, responseMessage: nil, confirmButtonTitle: nil, cancelButtonTitle: nil, value: nil, completionHandler: completionHandler)
@ -1053,6 +1101,16 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
}
}
public func onReceivedHttpAuthRequest(host: String, realm: String?, result: FlutterResult?) {
var arguments: [String: Any] = ["host": host, "realm": realm as Any]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onReceivedHttpAuthRequest", arguments: arguments, result: result)
}
}
public func onJsAlert(message: String, result: FlutterResult?) {
var arguments: [String: Any] = ["message": message]
if IABController != nil {

View File

@ -18,6 +18,7 @@ public class InAppWebViewOptions: Options {
var clearCache = false
var userAgent = ""
var javaScriptEnabled = true
var debuggingEnabled = true
var javaScriptCanOpenWindowsAutomatically = false
var mediaPlaybackRequiresUserGesture = true
var verticalScrollBarEnabled = true
@ -25,7 +26,7 @@ public class InAppWebViewOptions: Options {
var resourceCustomSchemes: [String] = []
var contentBlockers: [[String: [String : Any]]] = []
var minimumFontSize = 0;
var disallowOverScroll = false
var enableViewportScale = false
//var keyboardDisplayRequiresUserAction = true

View File

@ -406,6 +406,15 @@ class InAppBrowser {
}
///Event fires when a WebView received an HTTP authentication request. The default behavior is to cancel the request.
///
///[host] represents the host requiring authentication.
///
///[realm] represents the realm for which authentication is required
Future<HttpAuthResponse> onReceivedHttpAuthRequest(String url, String realm) {
}
void throwIsAlreadyOpened({String message = ''}) {
if (this.isOpened()) {
throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is already opened.']);

View File

@ -176,6 +176,13 @@ class InAppWebView extends StatefulWidget {
///**NOTE**: available only for Android.
final onSafeBrowsingHitCallback onSafeBrowsingHit;
///Event fires when a WebView received an HTTP authentication request. The default behavior is to cancel the request.
///
///[host] represents the host requiring authentication.
///
///[realm] represents the realm for which authentication is required
final onReceivedHttpAuthRequestCallback onReceivedHttpAuthRequest;
///Initial url that will be loaded.
final String initialUrl;
///Initial asset file that will be loaded. See [InAppWebView.loadFile()] for explanation.
@ -219,6 +226,7 @@ class InAppWebView extends StatefulWidget {
this.onJsConfirm,
this.onJsPrompt,
this.onSafeBrowsingHit,
this.onReceivedHttpAuthRequest,
this.gestureRecognizers,
}) : super(key: key);
@ -468,6 +476,14 @@ class InAppWebViewController {
else if (_inAppBrowser != null)
return (await _inAppBrowser.onSafeBrowsingHit(url, threatType))?.toMap();
break;
case "onReceivedHttpAuthRequest":
String host = call.arguments["host"];
String realm = call.arguments["realm"];
if (_widget != null && _widget.onReceivedHttpAuthRequest != null)
return (await _widget.onReceivedHttpAuthRequest(this, host, realm))?.toMap();
else if (_inAppBrowser != null)
return (await _inAppBrowser.onReceivedHttpAuthRequest(host, realm))?.toMap();
break;
case "onCallJsHandler":
String handlerName = call.arguments["handlerName"];
// decode args to json

View File

@ -270,6 +270,34 @@ class SafeBrowsingResponse {
}
}
class HttpAuthResponseAction {
final int _value;
const HttpAuthResponseAction._internal(this._value);
toValue() => _value;
static const CANCEL = const HttpAuthResponseAction._internal(0);
static const PROCEED = const HttpAuthResponseAction._internal(1);
static const USE_HTTP_AUTH_USERNAME_PASSWORD = const HttpAuthResponseAction._internal(2);
}
class HttpAuthResponse {
String username;
String password;
bool permanentPersistence;
HttpAuthResponseAction action;
HttpAuthResponse({this.username = "", this.password = "", this.permanentPersistence = false, this.action = HttpAuthResponseAction.CANCEL});
Map<String, dynamic> toMap() {
return {
"username": username,
"password": password,
"permanentPersistence": permanentPersistence,
"action": action?.toValue()
};
}
}
typedef onWebViewCreatedCallback = void Function(InAppWebViewController controller);
typedef onWebViewLoadStartCallback = void Function(InAppWebViewController controller, String url);
typedef onWebViewLoadStopCallback = void Function(InAppWebViewController controller, String url);
@ -286,4 +314,5 @@ typedef onGeolocationPermissionsShowPromptCallback = Future<GeolocationPermissio
typedef onJsAlertCallback = Future<JsAlertResponse> Function(InAppWebViewController controller, String message);
typedef onJsConfirmCallback = Future<JsConfirmResponse> Function(InAppWebViewController controller, String message);
typedef onJsPromptCallback = Future<JsPromptResponse> Function(InAppWebViewController controller, String message, String defaultValue);
typedef onSafeBrowsingHitCallback = Future<SafeBrowsingResponse> Function(InAppWebViewController controller, String url, SafeBrowsingThreat threatType);
typedef onSafeBrowsingHitCallback = Future<SafeBrowsingResponse> Function(InAppWebViewController controller, String url, SafeBrowsingThreat threatType);
typedef onReceivedHttpAuthRequestCallback = Future<HttpAuthResponse> Function(InAppWebViewController controller, String url, String realm);

View File

@ -22,6 +22,7 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions {
bool clearCache;
String userAgent;
bool javaScriptEnabled;
bool debuggingEnabled;
bool javaScriptCanOpenWindowsAutomatically;
bool mediaPlaybackRequiresUserGesture;
int textZoom;
@ -32,7 +33,7 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions {
List<ContentBlocker> contentBlockers;
InAppWebViewOptions({this.useShouldOverrideUrlLoading = false, this.useOnLoadResource = false, this.useOnDownloadStart = false, this.useOnTargetBlank = false,
this.clearCache = false, this.userAgent = "", this.javaScriptEnabled = true, this.javaScriptCanOpenWindowsAutomatically = false,
this.clearCache = false, this.userAgent = "", this.javaScriptEnabled = true, this.debuggingEnabled = false, this.javaScriptCanOpenWindowsAutomatically = false,
this.mediaPlaybackRequiresUserGesture = true, this.textZoom = 100, this.minimumFontSize, this.verticalScrollBarEnabled = true, this.horizontalScrollBarEnabled = true,
this.resourceCustomSchemes = const [], this.contentBlockers = const []}) {
if (this.minimumFontSize == null)