updated shouldOverrideUrlLoading event for #146, added print method and event #128, fix #123 javascript handler for Android API <= 22, renamed onTargetBlank to onCreateWindow event, deleted useOnTargetBlank option, added supportMultipleWindows android option, added getDefaultUserAgent static method, Updated default value for domStorageEnabled option to true

This commit is contained in:
Lorenzo Pichilli 2019-12-10 00:29:09 +01:00
parent 3fd1f9552b
commit aa20beafb1
33 changed files with 1935 additions and 534 deletions

View File

@ -15,14 +15,72 @@
</component>
<component name="ChangeListManager">
<list default="true" id="9b41f7a2-a71e-4923-91fb-249d7815b3e7" name="Default" comment="">
<change beforePath="$PROJECT_DIR$/.github/ISSUE_TEMPLATE/BUG_REPORT.md" beforeDir="false" afterPath="$PROJECT_DIR$/.github/ISSUE_TEMPLATE/BUG_REPORT.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md" beforeDir="false" afterPath="$PROJECT_DIR$/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md" afterDir="false" />
<change afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/ios/Classes/InAppWebViewStatic.swift" afterDir="false" />
<change afterPath="$PROJECT_DIR$/ios/Classes/InAppWebViewStatic.swift" 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$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/FlutterWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/FlutterWebView.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppBrowser.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppBrowser.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppBrowserActivity.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppBrowserActivity.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebView.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewClient.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewOptions.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewOptions.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/JavaScriptBridgeInterface.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/JavaScriptBridgeInterface.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/CHANGELOG.md" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/CHANGELOG.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/README.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/FlutterWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/FlutterWebView.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppBrowser.java" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppBrowser.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppBrowserActivity.java" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppBrowserActivity.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebView.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewClient.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewOptions.java" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewOptions.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/JavaScriptBridgeInterface.java" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/JavaScriptBridgeInterface.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/ios/Flutter/flutter_export_environment.sh" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/ios/Flutter/flutter_export_environment.sh" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/lib/in_app_browser_example.screen.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/lib/in_app_browser_example.screen.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/lib/in_app_webiew_example.screen.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/lib/in_app_webiew_example.screen.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/lib/main.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/lib/main.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/pubspec.yaml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/test_assets/in_app_webview_on_target_blank_test.html" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/test_assets/in_app_webview_on_create_window_test.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/test_driver/in_app_webview_on_target_blank_test.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/test_driver/in_app_webview_on_create_window_test.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/test_driver/in_app_webview_should_override_url_loading_test.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/test_driver/in_app_webview_should_override_url_loading_test.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/test_driver/main_test.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/test_driver/main_test.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/flutter_inappwebview.iml" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/flutter_inappwebview.iml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/ios/Classes/FlutterWebViewController.swift" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/ios/Classes/FlutterWebViewController.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/ios/Classes/InAppWebView.swift" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/ios/Classes/InAppWebView.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/ios/Classes/InAppWebViewOptions.swift" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/ios/Classes/InAppWebViewOptions.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/ios/Classes/SwiftFlutterPlugin.swift" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/ios/Classes/SwiftFlutterPlugin.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/lib/src/in_app_browser.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/lib/src/in_app_browser.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/lib/src/in_app_webview.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/lib/src/in_app_webview.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/lib/src/types.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/lib/src/types.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/lib/src/webview_options.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/lib/src/webview_options.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/pubspec.yaml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/Flutter/flutter_export_environment.sh" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Flutter/flutter_export_environment.sh" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/lib/in_app_browser_example.screen.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/in_app_browser_example.screen.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/lib/in_app_webiew_example.screen.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/in_app_webiew_example.screen.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/lib/main.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/main.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/example/pubspec.yaml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/test_assets/in_app_webview_on_target_blank_test.html" beforeDir="false" afterPath="$PROJECT_DIR$/example/test_assets/in_app_webview_on_create_window_test.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/test_driver/in_app_webview_on_target_blank_test.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/test_driver/in_app_webview_on_create_window_test.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/test_driver/in_app_webview_should_override_url_loading_test.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/test_driver/in_app_webview_should_override_url_loading_test.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/test_driver/main_test.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/test_driver/main_test.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/flutter_inappwebview.iml" beforeDir="false" afterPath="$PROJECT_DIR$/flutter_inappwebview.iml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/Classes/FlutterWebViewController.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/FlutterWebViewController.swift" 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$/ios/Classes/SwiftFlutterPlugin.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.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" />
<change beforePath="$PROJECT_DIR$/lib/src/webview_options.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/webview_options.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/pubspec.yaml" afterDir="false" />
</list>
<ignored path="$PROJECT_DIR$/.dart_tool/" />
<ignored path="$PROJECT_DIR$/.idea/" />
@ -45,20 +103,20 @@
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="480">
<caret line="94" column="30" selection-start-line="94" selection-start-column="20" selection-end-line="94" selection-end-column="36" />
<state relative-caret-position="194">
<caret line="229" column="55" selection-start-line="229" selection-start-column="26" selection-end-line="229" selection-end-column="55" />
<folding>
<element signature="e#0#20#0" expanded="true" />
<element signature="e#1907#1927#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart">
<entry file="file://$PROJECT_DIR$/lib/src/webview_options.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="185">
<caret line="415" column="31" selection-start-line="415" selection-start-column="15" selection-end-line="415" selection-end-column="31" />
<state relative-caret-position="328">
<caret line="409" column="28" selection-start-line="409" selection-start-column="2" selection-end-line="409" selection-end-column="28" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
@ -67,32 +125,25 @@
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/android/build.gradle">
<provider selected="true" editor-type-id="text-editor" />
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/example/android/build.gradle">
<provider selected="true" editor-type-id="text-editor" />
</entry>
</file>
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/README.md">
<entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="142">
<caret line="18" column="14" selection-start-line="18" selection-start-column="14" selection-end-line="18" selection-end-column="14" />
<state relative-caret-position="235">
<caret line="78" column="45" selection-start-line="78" selection-start-column="15" selection-end-line="78" selection-end-column="45" />
<folding>
<element signature="e#0#39#0" expanded="true" />
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/AndroidManifest.xml">
<entry file="file://$PROJECT_DIR$/lib/src/types.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="105">
<caret line="7" column="4" selection-start-line="7" selection-start-column="4" selection-end-line="7" selection-end-column="65" />
<state relative-caret-position="100">
<caret line="2026" column="38" selection-start-line="2026" selection-start-column="38" selection-end-line="2026" selection-end-column="38" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
@ -100,8 +151,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="2490">
<caret line="176" column="39" selection-start-line="176" selection-start-column="6" selection-end-line="176" selection-end-column="39" />
<state relative-caret-position="209">
<caret line="359" column="113" selection-start-line="359" selection-start-column="113" selection-end-line="359" selection-end-column="113" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
@ -109,6 +160,28 @@
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="294">
<caret line="78" selection-start-line="78" selection-end-line="80" selection-end-column="134" />
<folding>
<element signature="e#0#39#0" expanded="true" />
<element signature="e#0#39#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="120">
<caret line="8" column="160" selection-start-line="8" selection-start-column="160" selection-end-line="8" selection-end-column="160" />
</state>
</provider>
</entry>
</file>
</leaf>
</component>
<component name="FileTemplateManagerImpl">
@ -121,36 +194,36 @@
</component>
<component name="FindInProjectRecents">
<findStrings>
<find>[InAppBrowser] web</find>
<find>WebView</find>
<find>[InAppBrowser]</find>
<find>Response({</find>
<find>flutter_inappbrowser</find>
<find>InAppBrowser</find>
<find>PlatformRead</find>
<find>flutterInAppBrowserPlatformReady</find>
<find>llowContentAccess</find>
<find>ppCache</find>
<find>onReceivedClientCertRequest</find>
<find>a SSL</find>
<find>iltInZoomControls</find>
<find>databaseEnabled</find>
<find>Cookie</find>
<find>\</find>
<find>`shouldOverrideUrlLoading</find>
<find>useshouldOverrideUrlLoading</find>
<find>initiald</find>
<find>long</find>
<find>should</find>
<find>allowunivers</find>
<find>onNavigationStateChange</find>
<find>_channel</find>
<find>default</find>
<find>_staticChannel</find>
<find>defa</find>
<find>InAppWebViewStatic</find>
<find>removeFromSuperview</find>
<find>onCall</find>
<find>onLoad</find>
<find>printCu</find>
<find>onLoadRe</find>
<find>onPrint</find>
<find>ontARGET</find>
<find>onCreateWindow</find>
<find>javaScriptHandlerForbiddenNames</find>
<find>supportMultipleWindows</find>
<find>ajaxRequest</find>
<find>onTarget</find>
<find>AjaxR</find>
<find>print</find>
<find>shouldOver</find>
<find>ShouldOverrideUrlLoadingAction</find>
<find>headers</find>
<find>domStorageEnabled</find>
<find>fromValue</find>
<find>shouldOv</find>
<find>shouldOverrideUrlLoading</find>
<find>BAAAAACK</find>
<find>loadData</find>
<find>iNitialData</find>
<find>data</find>
<find>pauseTimers</find>
<find>openData</find>
<find>historyUrl</find>
<find>baseUrl</find>
<find>onWebViewCreated</find>
<find>Note for an</find>
</findStrings>
<replaceStrings>
<replace>activity.getPreferences(0)</replace>
@ -173,13 +246,6 @@
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/example/test_driver/custom_widget_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_ajax_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_content_blocker_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_cookie_manager_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_fetch_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_http_auth_credential_database_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_initial_data_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_initial_file_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_initial_url_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_javascript_handler_test.dart" />
@ -196,7 +262,6 @@
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_on_safe_browsing_hit_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_on_scroll_changed_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_on_target_blank_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_should_override_url_loading_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_ssl_request_test.dart" />
<option value="$PROJECT_DIR$/ios/Classes/InAppBrowserFlutterPlugin.m" />
<option value="$PROJECT_DIR$/ios/Classes/InAppWebViewFlutterPlugin.h" />
@ -207,22 +272,30 @@
<option value="$PROJECT_DIR$/.git/config" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_on_load_error_test.dart" />
<option value="$PROJECT_DIR$/lib/src/channel_manager.dart" />
<option value="$PROJECT_DIR$/example/pubspec.yaml" />
<option value="$PROJECT_DIR$/example/assets/index.html" />
<option value="$PROJECT_DIR$/lib/src/types.dart" />
<option value="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/css/style.css" />
<option value="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.html" />
<option value="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/js/main.js" />
<option value="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js" />
<option value="$PROJECT_DIR$/lib/src/in_app_browser.dart" />
<option value="$PROJECT_DIR$/lib/src/webview_options.dart" />
<option value="$PROJECT_DIR$/example/assets/js/main.js" />
<option value="$PROJECT_DIR$/lib/src/in_app_webview.dart" />
<option value="$PROJECT_DIR$/pubspec.yaml" />
<option value="$PROJECT_DIR$/CHANGELOG.md" />
<option value="$PROJECT_DIR$/example/lib/main.dart" />
<option value="$PROJECT_DIR$/.github/ISSUE_TEMPLATE/BUG_REPORT.md" />
<option value="$PROJECT_DIR$/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md" />
<option value="$PROJECT_DIR$/example/assets/index.html" />
<option value="$PROJECT_DIR$/example/lib/in_app_browser_example.screen.dart" />
<option value="$PROJECT_DIR$/android/src/main/res/values/styles.xml" />
<option value="$PROJECT_DIR$/pubspec.yaml" />
<option value="$PROJECT_DIR$/example/lib/in_app_webiew_example.screen.dart" />
<option value="$PROJECT_DIR$/example/assets/css/style.css" />
<option value="$PROJECT_DIR$/example/test_assets/in_app_webview_on_create_window_test.html" />
<option value="$PROJECT_DIR$/example/test_driver/main_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_on_create_window_test.dart" />
<option value="$PROJECT_DIR$/example/assets/js/main.js" />
<option value="$PROJECT_DIR$/example/pubspec.yaml" />
<option value="$PROJECT_DIR$/lib/src/types.dart" />
<option value="$PROJECT_DIR$/lib/src/webview_options.dart" />
<option value="$PROJECT_DIR$/example/lib/main.dart" />
<option value="$PROJECT_DIR$/CHANGELOG.md" />
<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/test_driver/in_app_webview_should_override_url_loading_test.dart" />
<option value="$PROJECT_DIR$/README.md" />
</list>
</option>
@ -250,55 +323,6 @@
<select />
</subPane>
</pane>
<pane id="PackagesPane" />
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="flutter_inappwebview" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappwebview" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappwebview" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappwebview" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappwebview" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappwebview" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" />
<item name="android" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappwebview" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappwebview" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" />
<item name="android" type="462c0819:PsiDirectoryNode" />
<item name="app" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappwebview" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappwebview" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" />
<item name="android" type="462c0819:PsiDirectoryNode" />
<item name="app" type="462c0819:PsiDirectoryNode" />
<item name="main" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappwebview" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappwebview" type="462c0819:PsiDirectoryNode" />
<item name="lib" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappwebview" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappwebview" type="462c0819:PsiDirectoryNode" />
<item name="lib" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
<pane id="AndroidView">
<subPane>
<expand>
@ -328,6 +352,29 @@
<select />
</subPane>
</pane>
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="flutter_inappwebview" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappwebview" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappwebview" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappwebview" type="462c0819:PsiDirectoryNode" />
<item name="lib" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappwebview" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappwebview" type="462c0819:PsiDirectoryNode" />
<item name="lib" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
<pane id="PackagesPane" />
</panes>
</component>
<component name="PropertiesComponent">
@ -477,7 +524,7 @@
</todo-panel>
</component>
<component name="ToolWindowManager">
<frame x="-1" y="23" width="1920" height="1057" extended-state="6" />
<frame x="-1" y="23" width="1920" height="1057" extended-state="0" />
<editor active="true" />
<layout>
<window_info active="true" content_ui="combo" id="Project" order="0" sideWeight="0.6177474" visible="true" weight="0.20766774" />
@ -491,7 +538,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.32745314" />
<window_info anchor="bottom" id="Run" order="2" sideWeight="0.49478307" weight="0.59378237" />
<window_info anchor="bottom" id="Run" order="2" sideWeight="0.49478307" visible="true" weight="0.4787565" />
<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" />
@ -499,7 +546,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.50532484" side_tool="true" weight="0.35751295" />
<window_info anchor="bottom" id="Version Control" order="9" />
<window_info anchor="bottom" id="Terminal" order="10" sideWeight="0.4946752" visible="true" weight="0.35336787" />
<window_info anchor="bottom" id="Terminal" order="10" sideWeight="0.4946752" weight="0.35336787" />
<window_info anchor="bottom" id="Logcat" order="11" weight="0.32953367" />
<window_info anchor="bottom" id="Messages" order="12" sideWeight="0.4968051" weight="0.33782384" />
<window_info anchor="bottom" id="Dependency Viewer" order="13" weight="0.32800853" />
@ -516,6 +563,7 @@
<window_info anchor="right" id="Theme Preview" order="7" />
<window_info anchor="right" id="Assistant" order="8" weight="0.3290735" />
<window_info anchor="right" id="Palette&#9;" order="9" />
<window_info anchor="right" id="Preview" order="10" weight="0.32960597" />
</layout>
</component>
<component name="UnknownFeatures">
@ -529,90 +577,6 @@
</ignored-roots>
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_on_js_dialog_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="57" selection-start-line="2" selection-start-column="57" selection-end-line="2" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_on_load_http_error_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="57" selection-start-line="2" selection-start-column="57" selection-end-line="2" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_on_load_resource_custom_scheme_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="45">
<caret line="3" column="57" selection-start-line="3" selection-start-column="57" selection-end-line="3" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_on_load_resource_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="57" selection-start-line="2" selection-start-column="57" selection-end-line="2" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_on_navigation_state_change_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="57" selection-start-line="2" selection-start-column="57" selection-end-line="2" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_on_progress_changed_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="57" selection-start-line="2" selection-start-column="57" selection-end-line="2" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_on_received_http_auth_request_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="57" selection-start-line="2" selection-start-column="57" selection-end-line="2" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_on_safe_browsing_hit_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="60">
<caret line="4" column="57" selection-start-line="4" selection-start-column="57" selection-end-line="4" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_on_scroll_changed_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="57" selection-start-line="2" selection-start-column="57" selection-end-line="2" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_on_target_blank_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="57" selection-start-line="2" selection-start-column="57" selection-end-line="2" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_should_override_url_loading_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="57" selection-start-line="2" selection-start-column="57" selection-end-line="2" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/in_app_webiew_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="15">
<caret line="1" column="57" selection-start-line="1" selection-start-column="57" selection-end-line="1" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/ios/Classes/InAppWebViewFlutterPlugin.h">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="285">
@ -634,16 +598,6 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/cookie_manager.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="180">
<caret line="12" column="101" selection-start-line="12" selection-start-column="101" selection-end-line="12" selection-end-column="101" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/http_auth_credentials_database.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="195">
@ -776,81 +730,6 @@
</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="73">
<caret line="606" column="28" lean-forward="true" selection-start-line="606" selection-start-column="28" selection-end-line="606" selection-end-column="28" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/assets/js/main.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="45">
<caret line="3" column="25" selection-start-line="3" selection-start-column="25" selection-end-line="3" selection-end-column="25" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/assets/index.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="459">
<caret line="39" column="38" selection-start-line="39" selection-start-column="38" selection-end-line="39" selection-end-column="38" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="540">
<caret line="36" column="27" lean-forward="true" selection-start-line="36" selection-start-column="27" selection-end-line="36" selection-end-column="27" />
</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="16" selection-start-line="2" selection-start-column="16" selection-end-line="2" selection-end-column="16" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="195">
<caret line="13" lean-forward="true" selection-start-line="13" selection-end-line="13" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/types.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="405">
<caret line="98" column="19" selection-start-line="98" selection-start-column="9" selection-end-line="98" selection-end-column="19" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/in_app_browser.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="2490">
<caret line="176" column="39" selection-start-line="176" selection-start-column="6" selection-end-line="176" selection-end-column="39" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="480">
<caret line="94" column="30" selection-start-line="94" selection-start-column="20" selection-end-line="94" selection-end-column="36" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="120">
@ -865,26 +744,6 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/build.gradle">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="105">
<caret line="7" column="4" selection-start-line="7" selection-start-column="4" selection-end-line="7" selection-end-column="65" />
</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="185">
<caret line="415" column="31" selection-start-line="415" selection-start-column="15" selection-end-line="415" selection-end-column="31" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/app/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-230" />
@ -893,12 +752,214 @@
<entry file="file://$PROJECT_DIR$/example/android/build.gradle">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/android/build.gradle">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_ajax_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="151">
<caret line="32" selection-start-line="32" selection-end-line="55" selection-end-column="7" />
<folding>
<element signature="e#0#39#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/chrome_safari_browser_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state>
<folding>
<element signature="e#0#39#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/src/main/res/layout/chrome_custom_tabs_layout.xml">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/android/src/main/res/layout/activity_web_view.xml">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/android/src/main/res/values/styles.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="44" selection-start-line="2" selection-start-column="44" selection-end-line="2" selection-end-column="44" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="52">
<caret line="36" column="39" lean-forward="true" selection-start-line="36" selection-start-column="39" selection-end-line="36" selection-end-column="39" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/assets/index.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="77">
<caret line="14" column="24" selection-start-line="14" selection-start-column="24" selection-end-line="14" selection-end-column="24" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/cookie_manager.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="203">
<caret line="38" column="10" selection-start-line="38" selection-start-column="10" selection-end-line="38" selection-end-column="10" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/assets/css/style.css">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="215">
<caret line="31" selection-start-line="31" selection-end-line="31" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_assets/in_app_webview_on_create_window_test.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="135">
<caret line="9" column="42" selection-start-line="9" selection-start-column="42" selection-end-line="9" selection-end-column="42" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_on_create_window_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="345">
<caret line="23" column="24" lean-forward="true" selection-start-line="23" selection-start-column="24" selection-end-line="23" selection-end-column="24" />
<folding>
<element signature="e#0#39#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/main_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="690">
<caret line="46" column="56" lean-forward="true" selection-start-line="46" selection-start-column="56" selection-end-line="46" selection-end-column="56" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/in_app_webiew_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="487">
<caret line="73" column="39" selection-start-line="73" selection-start-column="39" selection-end-line="73" selection-end-column="39" />
<folding>
<element signature="e#0#39#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/in_app_browser_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="178">
<caret line="39" column="71" selection-start-line="39" selection-start-column="42" selection-end-line="39" selection-end-column="71" />
<folding>
<element signature="e#0#20#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="165">
<caret line="11" column="10" selection-start-line="11" selection-start-column="10" selection-end-line="11" selection-end-column="10" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="454">
<caret line="58" column="49" selection-start-line="58" selection-start-column="49" selection-end-line="58" selection-end-column="49" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/assets/js/main.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="45">
<caret line="3" column="25" selection-start-line="3" selection-start-column="25" selection-end-line="3" selection-end-column="25" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/types.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="100">
<caret line="2026" column="38" selection-start-line="2026" selection-start-column="38" selection-end-line="2026" selection-end-column="38" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="194">
<caret line="229" column="55" selection-start-line="229" selection-start-column="26" selection-end-line="229" selection-end-column="55" />
<folding>
<element signature="e#1907#1927#0" expanded="true" />
</folding>
</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="328">
<caret line="409" column="28" selection-start-line="409" selection-start-column="2" selection-end-line="409" selection-end-column="28" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/in_app_browser.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="209">
<caret line="359" column="113" selection-start-line="359" selection-start-column="113" selection-end-line="359" selection-end-column="113" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_should_override_url_loading_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="329">
<caret line="49" column="68" lean-forward="true" selection-start-line="49" selection-start-column="68" selection-end-line="49" selection-end-column="68" />
<folding>
<element signature="e#0#39#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="235">
<caret line="78" column="45" selection-start-line="78" selection-start-column="15" selection-end-line="78" selection-end-column="45" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="120">
<caret line="8" column="160" selection-start-line="8" selection-start-column="160" selection-end-line="8" selection-end-column="160" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="142">
<caret line="18" column="14" selection-start-line="18" selection-start-column="14" selection-end-line="18" selection-end-column="14" />
<state relative-caret-position="294">
<caret line="78" selection-start-line="78" selection-end-line="80" selection-end-column="134" />
<folding>
<element signature="e#0#39#0" expanded="true" />
<element signature="e#0#39#0" expanded="true" />
</folding>
</state>
</provider>

View File

@ -1,3 +1,23 @@
## 2.2.0
- Updated `clearCache` for Android
- Added `Promise` javascript [polyfill](https://github.com/taylorhakes/promise-polyfill/blob/master/src/index.js) for webviews that doesn't support it for `window.flutter_inappwebview.callHandler`
- Added `getDefaultUserAgent` static method to `InAppWebViewController`
- Added `printCurrentPage` method to `InAppWebViewController`
- Added `onPrint` event
- Added `supportMultipleWindows` webview option for Android
- Added `regexToCancelSubFramesLoading` webview option for Android to cancel subframe requests on `shouldOverrideUrlLoading` event based on a Regular Expression
- Updated default value for `domStorageEnabled` option to `true` for Android
- Fix for Android `InAppBrowser` for some controller methods not exposed.
### BREAKING CHANGES
- Updated `shouldOverrideUrlLoading` event:
- the `url` parameter has been moved inside an instance of `ShouldOverrideUrlLoadingRequest` class
- it has a return type `ShouldOverrideUrlLoadingAction` to allow or cancel navigation instead of cancel every time the request
- Renamed `onTargetBlank` to `onCreateWindow`
- Deleted `useOnTargetBlank` webview option
## 2.1.0+1
- Fix docs

View File

@ -76,6 +76,10 @@ Classes:
See the online [API Reference](https://pub.dartlang.org/documentation/flutter_inappwebview/latest/) to get the full documentation.
The API showed in this `README.md` file shows only a part of the documentation that conforms to the master branch only.
So, here you could have methods, options, and events that aren't published yet.
If you need a specific version, change the **GitHub branch** to your version or use the **online API Reference** (recommended).
### Load a file inside `assets` folder
To be able to load your local files (assets, js, css, etc.), you need to add them in the `assets` section of the `pubspec.yaml` file, otherwise they cannot be found!
@ -286,6 +290,8 @@ Screenshots:
* `getTRexRunnerCss`: Gets the css of the Chromium's t-rex runner game. Used in combination with `getTRexRunnerHtml()`.
* `scrollTo({@required int x, @required int y})`: Scrolls the WebView to the position.
* `scrollBy({@required int x, @required int y})`: Moves the scrolled position of the WebView.
* `printCurrentPage`: Prints the current page.
* `static getDefaultUserAgent`: Gets the default user agent.
##### About the JavaScript handler
@ -339,7 +345,6 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
* `useShouldOverrideUrlLoading`: Set to `true` to be able to listen at the `shouldOverrideUrlLoading` event. The default value is `false`.
* `useOnLoadResource`: Set to `true` to be able to listen at the `onLoadResource` event. The default value is `false`.
* `useOnDownloadStart`: Set to `true` to be able to listen at the `onDownloadStart` event. The default value is `false`.
* `useOnTargetBlank`: Set to `true` to be able to listen at the `onTargetBlank` event. The default value is `false`.
* `clearCache`: Set to `true` to have all the browser's cache cleared before the new window is opened. The default value is `false`.
* `userAgent`: Sets the user-agent for the WebView.
* `applicationNameForUserAgent`: Append to the existing user-agent. Setting userAgent will override this.
@ -369,7 +374,7 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
* `displayZoomControls`: Set to `true` if the WebView should display on-screen zoom controls when using the built-in zoom mechanisms. The default value is `false`.
* `supportZoom`: Set to `false` if the WebView should not support zooming using its on-screen zoom controls and gestures. The default value is `true`.
* `databaseEnabled`: Set to `true` if you want the database storage API is enabled. The default value is `false`.
* `domStorageEnabled`: Set to `true` if you want the DOM storage API is enabled. The default value is `false`.
* `domStorageEnabled`: Set to `true` if you want the DOM storage API is enabled. The default value is `true`.
* `useWideViewPort`: Set to `true` if the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport.
* `safeBrowsingEnabled`: Sets whether Safe Browsing is enabled. Safe Browsing allows WebView to protect against malware and phishing attacks by verifying the links.
* `mixedContentMode`: Configures the WebView's behavior when a secure origin attempts to load a resource from an insecure origin.
@ -403,6 +408,7 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
* `saveFormData`: Sets whether the WebView should save form data. In Android O, the platform has implemented a fully functional Autofill feature to store form data.
* `thirdPartyCookiesEnabled`: Boolean value to enable third party cookies in the WebView.
* `hardwareAcceleration`: Boolean value to enable Hardware Acceleration in the WebView.
* `supportMultipleWindows`: Sets whether the WebView whether supports multiple windows.
##### `InAppWebView` iOS-specific options
@ -429,12 +435,13 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
* `onLoadHttpError`: Event fired when the InAppWebView main page receives an HTTP error.
* `onProgressChanged`: Event fired when the current progress of loading a page is changed.
* `onConsoleMessage`: Event fired when the InAppWebView receives a ConsoleMessage.
* `shouldOverrideUrlLoading`: Give the host application a chance to take control when a URL is about to be loaded in the current WebView (to use this event, the `useShouldOverrideUrlLoading` option must be `true`).
* `shouldOverrideUrlLoading`: Give the host application a chance to take control when a URL is about to be loaded in the current WebView (to use this event, the `useShouldOverrideUrlLoading` option must be `true`). This event is not called on the initial load of the WebView.
* `onNavigationStateChange`: Event fired when the navigation state of the InAppWebView changes, for example through the usage of the javascript **[History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API)** functions.
* `onLoadResource`: Event fired when the InAppWebView loads a resource (to use this event, the `useOnLoadResource` option must be `true`).
* `onScrollChanged`: Event fired when the InAppWebView scrolls.
* `onDownloadStart`: Event fired when InAppWebView recognizes and starts a downloadable file (to use this event, the `useOnDownloadStart` option must be `true`).
* `onLoadResourceCustomScheme`: Event fired when the InAppWebView finds the `custom-scheme` while loading a resource. Here you can handle the url request and return a CustomSchemeResponse to load a specific resource encoded to `base64`.
* `onTargetBlank`: Event fired when the InAppWebView tries to open a link with `target="_blank"` (to use this event, the `useOnTargetBlank` option must be `true`).
* `onCreateWindow`: Event fired when the InAppWebView requests the host application to create a new window, for example when trying to open a link with `target="_blank"` or when `window.open()` is called by JavaScript side.
* `onGeolocationPermissionsShowPrompt`: Event that notifies the host application that web content from the specified origin is attempting to use the Geolocation API, but no permission state is currently set for that origin (available only on Android).
* `onJsAlert`: Event fired when javascript calls the `alert()` method to display an alert dialog.
* `onJsConfirm`: Event fired when javascript calls the `confirm()` method to display a confirm dialog.
@ -448,8 +455,8 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
* `onAjaxReadyStateChange`: Event fired whenever the `readyState` attribute of an `XMLHttpRequest` changes (to use this event, the `useShouldInterceptAjaxRequest` option must be `true`).
* `onAjaxProgress`: Event fired as an `XMLHttpRequest` progress (to use this event, the `useShouldInterceptAjaxRequest` option must be `true`).
* `shouldInterceptFetchRequest`: Event fired when a request is sent to a server through [Fetch API](https://developer.mozilla.org/it/docs/Web/API/Fetch_API) (to use this event, the `useShouldInterceptFetchRequest` option must be `true`).
* `onNavigationStateChange`: Event fired when the navigation state of the InAppWebView changes.
* `onPermissionRequest`: Event fired when the webview is requesting permission to access the specified resources and the permission currently isn't granted or denied (available only on Android).
* `onPrint`: Event fired when `window.print()` is called from JavaScript side.
### `InAppBrowser` class
@ -495,9 +502,9 @@ class MyInAppBrowser extends InAppBrowser {
}
@override
void shouldOverrideUrlLoading(String url) {
print("\n\n override $url\n\n");
this.webViewController.loadUrl(url: url);
void shouldOverrideUrlLoading(ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) {
print("\n\n override ${shouldOverrideUrlLoadingRequest.url}\n\n");
this.webViewController.loadUrl(url: shouldOverrideUrlLoadingRequest.url);
}
@override

View File

@ -334,6 +334,14 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
result.success(false);
}
break;
case "printCurrentPage":
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webView.printCurrentPage();
result.success(true);
} else {
result.success(false);
}
break;
default:
result.notImplemented();
}

View File

@ -25,6 +25,7 @@ import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Parcelable;
import android.provider.Browser;
import android.net.Uri;
@ -34,6 +35,8 @@ import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.util.Log;
import androidx.annotation.RequiresApi;
import com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ChromeCustomTabsActivity;
import com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.CustomTabActivityHelper;
@ -307,13 +310,51 @@ public class InAppBrowser implements MethodChannel.MethodCallHandler {
case "clearMatches":
clearMatches(uuid, result);
break;
case "scrollTo":
{
Integer x = (Integer) call.argument("x");
Integer y = (Integer) call.argument("y");
scrollTo(uuid, x, y);
}
result.success(true);
break;
case "scrollBy":
{
Integer x = (Integer) call.argument("x");
Integer y = (Integer) call.argument("y");
scrollBy(uuid, x, y);
}
result.success(true);
break;
case "pause":
onPause(uuid);
result.success(true);
break;
case "resume":
onResume(uuid);
result.success(true);
break;
case "pauseTimers":
pauseTimers(uuid);
result.success(true);
break;
case "resumeTimers":
resumeTimers(uuid);
result.success(true);
break;
case "printCurrentPage":
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
printCurrentPage(uuid);
}
result.success(true);
break;
default:
result.notImplemented();
}
}
private void evaluateJavascript(String uuid, String source, final Result result) {
public void evaluateJavascript(String uuid, String source, final Result result) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.evaluateJavascript(source, result);
@ -322,21 +363,21 @@ public class InAppBrowser implements MethodChannel.MethodCallHandler {
}
}
private void injectJavascriptFileFromUrl(String uuid, String urlFile) {
public void injectJavascriptFileFromUrl(String uuid, String urlFile) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectJavascriptFileFromUrl(urlFile);
}
}
private void injectCSSCode(String uuid, String source) {
public void injectCSSCode(String uuid, String source) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectCSSCode(source);
}
}
private void injectCSSFileFromUrl(String uuid, String urlFile) {
public void injectCSSFileFromUrl(String uuid, String urlFile) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectCSSFileFromUrl(urlFile);
@ -386,7 +427,7 @@ public class InAppBrowser implements MethodChannel.MethodCallHandler {
* Opens the intent, providing a chooser that excludes the current app to avoid
* circular loops.
*/
private void openExternalExcludeCurrentApp(Activity activity, Intent intent) {
public void openExternalExcludeCurrentApp(Activity activity, Intent intent) {
String currentPackage = activity.getPackageName();
boolean hasCurrentPackage = false;
PackageManager pm = activity.getPackageManager();
@ -479,21 +520,21 @@ public class InAppBrowser implements MethodChannel.MethodCallHandler {
activity.startActivity(intent);
}
private String getUrl(String uuid) {
public String getUrl(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getUrl();
return null;
}
private String getTitle(String uuid) {
public String getTitle(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getWebViewTitle();
return null;
}
private Integer getProgress(String uuid) {
public Integer getProgress(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getProgress();
@ -730,6 +771,49 @@ public class InAppBrowser implements MethodChannel.MethodCallHandler {
result.success(false);
}
public void scrollTo(String uuid, Integer x, Integer y) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.scrollTo(x, y);
}
public void scrollBy(String uuid, Integer x, Integer y) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.scrollBy(x, y);
}
public void onPause(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.onPauseWebView();
}
public void onResume(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.onResumeWebView();
}
public void pauseTimers(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.pauseTimers();
}
public void resumeTimers(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.resumeTimers();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void printCurrentPage(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.printCurrentPage();
}
public void dispose() {
channel.setMethodCallHandler(null);
for ( InAppBrowserActivity activity : webViewActivities.values()) {

View File

@ -6,6 +6,8 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Picture;
import android.graphics.drawable.ColorDrawable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
@ -537,4 +539,41 @@ public class InAppBrowserActivity extends AppCompatActivity {
webView.loadUrl("about:blank");
}
}
public void scrollTo(Integer x, Integer y) {
if (webView != null)
webView.scrollTo(x, y);
}
public void scrollBy(Integer x, Integer y) {
if (webView != null)
webView.scrollBy(x, y);
}
public void onPauseWebView() {
if (webView != null)
webView.onPause();
}
public void onResumeWebView() {
if (webView != null)
webView.onResume();
}
public void pauseTimers() {
if (webView != null)
webView.pauseTimers();
}
public void resumeTimers() {
if (webView != null)
webView.resumeTimers();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void printCurrentPage() {
if (webView != null)
webView.printCurrentPage();
}
}

View File

@ -6,6 +6,9 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Build;
import android.print.PrintAttributes;
import android.print.PrintDocumentAdapter;
import android.print.PrintManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
@ -18,6 +21,8 @@ import android.webkit.WebHistoryItem;
import android.webkit.WebSettings;
import android.webkit.WebStorage;
import androidx.annotation.RequiresApi;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlocker;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerAction;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerHandler;
@ -34,12 +39,13 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import okhttp3.OkHttpClient;
import static com.pichillilorenzo.flutter_inappwebview.InAppWebView.PreferredContentModeOptionType.*;
import static com.pichillilorenzo.flutter_inappwebview.InAppWebView.PreferredContentModeOptionType.fromValue;
final public class InAppWebView extends InputAwareWebView {
@ -57,6 +63,7 @@ final public class InAppWebView extends InputAwareWebView {
public float scale = getResources().getDisplayMetrics().density;
int okHttpClientCacheSize = 10 * 1024 * 1024; // 10MB
public ContentBlockerHandler contentBlockerHandler = new ContentBlockerHandler();
public Pattern regexToCancelSubFramesLoadingCompiled;
static final String consoleLogJS = "(function(console) {" +
" var oldLogs = {" +
@ -84,6 +91,10 @@ final public class InAppWebView extends InputAwareWebView {
" }" +
"})(window.console);";
static final String printJS = "window.print = function() {" +
" window." + JavaScriptBridgeInterface.name + ".callHandler('onPrint', window.location.href);" +
"}";
static final String platformReadyJS = "window.dispatchEvent(new Event('flutterInAppWebViewPlatformReady'));";
static final String variableForOnLoadResourceJS = "window._flutter_inappwebview_useOnLoadResource";
@ -554,7 +565,7 @@ final public class InAppWebView extends InputAwareWebView {
settings.setJavaScriptCanOpenWindowsAutomatically(options.javaScriptCanOpenWindowsAutomatically);
settings.setBuiltInZoomControls(options.builtInZoomControls);
settings.setDisplayZoomControls(options.displayZoomControls);
settings.setSupportMultipleWindows(options.useOnTargetBlank);
settings.setSupportMultipleWindows(options.supportMultipleWindows);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
settings.setSafeBrowsingEnabled(options.safeBrowsingEnabled);
@ -571,7 +582,7 @@ final public class InAppWebView extends InputAwareWebView {
if (options.applicationNameForUserAgent != null && !options.applicationNameForUserAgent.isEmpty()) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
String userAgent = (options.userAgent != null && !options.userAgent.isEmpty()) ? options.userAgent :WebSettings.getDefaultUserAgent(getContext());
String userAgent = (options.userAgent != null && !options.userAgent.isEmpty()) ? options.userAgent : WebSettings.getDefaultUserAgent(getContext());
String userAgentWithApplicationName = userAgent + " " + options.applicationNameForUserAgent;
settings.setUserAgentString(userAgentWithApplicationName);
}
@ -655,6 +666,9 @@ final public class InAppWebView extends InputAwareWebView {
setLayerType(View.LAYER_TYPE_HARDWARE, null);
else
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
if (options.regexToCancelSubFramesLoading != null) {
regexToCancelSubFramesLoadingCompiled = Pattern.compile(options.regexToCancelSubFramesLoading);
}
contentBlockerHandler.getRuleList().clear();
for (Map<String, Map<String, Object>> contentBlocker : options.contentBlockers) {
@ -996,8 +1010,8 @@ final public class InAppWebView extends InputAwareWebView {
if (newOptionsMap.get("mixedContentMode") != null && !options.mixedContentMode.equals(newOptions.mixedContentMode))
settings.setMixedContentMode(newOptions.mixedContentMode);
if (newOptionsMap.get("useOnTargetBlank") != null && options.useOnTargetBlank != newOptions.useOnTargetBlank)
settings.setSupportMultipleWindows(newOptions.useOnTargetBlank);
if (newOptionsMap.get("supportMultipleWindows") != null && options.supportMultipleWindows != newOptions.supportMultipleWindows)
settings.setSupportMultipleWindows(newOptions.supportMultipleWindows);
if (newOptionsMap.get("useOnDownloadStart") != null && options.useOnDownloadStart != newOptions.useOnDownloadStart) {
if (newOptions.useOnDownloadStart) {
@ -1127,6 +1141,13 @@ final public class InAppWebView extends InputAwareWebView {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
if (newOptionsMap.get("regexToCancelSubFramesLoading") != null && options.regexToCancelSubFramesLoading != newOptions.regexToCancelSubFramesLoading) {
if (newOptions.regexToCancelSubFramesLoading == null)
regexToCancelSubFramesLoadingCompiled = null;
else
regexToCancelSubFramesLoadingCompiled = Pattern.compile(options.regexToCancelSubFramesLoading);
}
if (newOptions.contentBlockers != null) {
contentBlockerHandler.getRuleList().clear();
for (Map<String, Map<String, Object>> contentBlocker : newOptions.contentBlockers) {
@ -1304,6 +1325,22 @@ final public class InAppWebView extends InputAwareWebView {
webSettings.setBuiltInZoomControls(enabled);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void printCurrentPage() {
// Get a PrintManager instance
PrintManager printManager = (PrintManager) registrar.activity()
.getSystemService(Context.PRINT_SERVICE);
String jobName = getTitle() + " Document";
// Get a printCurrentPage adapter instance
PrintDocumentAdapter printAdapter = createPrintDocumentAdapter(jobName);
// Create a printCurrentPage job with name and adapter instance
printManager.print(jobName, printAdapter,
new PrintAttributes.Builder().build());
}
@Override
public void dispose() {
super.dispose();

View File

@ -418,16 +418,16 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
if (data == null) {
// to get the URL, create a temp weview
final WebView newWebView = new WebView(view.getContext());
final WebView tempWebView = new WebView(view.getContext());
// disable javascript
newWebView.getSettings().setJavaScriptEnabled(false);
newWebView.setWebViewClient(new WebViewClient(){
tempWebView.getSettings().setJavaScriptEnabled(false);
tempWebView.setWebViewClient(new WebViewClient(){
@Override
public void onPageStarted(WebView v, String url, Bitmap favicon) {
super.onPageStarted(v, url, favicon);
obj.put("url", url);
getChannel().invokeMethod("onTargetBlank", obj);
getChannel().invokeMethod("onCreateWindow", obj);
// stop webview loading
v.stopLoading();
@ -437,13 +437,13 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
v.destroy();
}
});
((WebView.WebViewTransport)resultMsg.obj).setWebView(newWebView);
((WebView.WebViewTransport) resultMsg.obj).setWebView(tempWebView);
resultMsg.sendToTarget();
return true;
}
obj.put("url", data);
getChannel().invokeMethod("onTargetBlank", obj);
getChannel().invokeMethod("onCreateWindow", obj);
return false;
}

View File

@ -1,13 +1,14 @@
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
import android.content.Intent;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.graphics.Bitmap;
import android.net.Uri;
import android.net.http.SslCertificate;
import android.net.http.SslError;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.webkit.ClientCertRequest;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
@ -43,6 +44,7 @@ import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import io.flutter.plugin.common.MethodChannel;
@ -51,7 +53,6 @@ public class InAppWebViewClient extends WebViewClient {
protected static final String LOG_TAG = "IABWebViewClient";
private FlutterWebView flutterWebView;
private InAppBrowserActivity inAppBrowserActivity;
Map<Integer, String> statusCodeMapping = new HashMap<Integer, String>();
private static int previousAuthRequestFailureCount = 0;
private static List<Credential> credentialsProposed = null;
private String onPageStartedURL = "";
@ -63,72 +64,105 @@ public class InAppWebViewClient extends WebViewClient {
else if (obj instanceof FlutterWebView)
this.flutterWebView = (FlutterWebView) obj;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
InAppWebView webView = (InAppWebView) view;
if (webView.options.useShouldOverrideUrlLoading) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
onShouldOverrideUrlLoading(
request.getUrl().toString(),
request.getMethod(),
request.getRequestHeaders(),
request.isForMainFrame(),
request.hasGesture(),
request.isRedirect());
} else {
onShouldOverrideUrlLoading(
request.getUrl().toString(),
request.getMethod(),
request.getRequestHeaders(),
request.isForMainFrame(),
request.hasGesture(),
false);
}
if (webView.regexToCancelSubFramesLoadingCompiled != null) {
if (request.isForMainFrame())
return true;
else {
Matcher m = webView.regexToCancelSubFramesLoadingCompiled.matcher(request.getUrl().toString());
if (m.matches())
return true;
else
return false;
}
} else {
// There isn't any way to load an URL for a frame that is not the main frame,
// so if the request is not for the main frame, the navigation is allowed.
return request.isForMainFrame();
}
}
return false;
}
@Override
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
if (((inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView).options.useShouldOverrideUrlLoading) {
Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url);
getChannel().invokeMethod("shouldOverrideUrlLoading", obj);
onShouldOverrideUrlLoading(url, "GET", null,true, false, false);
return true;
}
return false;
}
if (url != null) {
if (url.startsWith(WebView.SCHEME_TEL)) {
try {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url));
((inAppBrowserActivity != null) ? inAppBrowserActivity : flutterWebView.activity).startActivity(intent);
return true;
} catch (android.content.ActivityNotFoundException e) {
Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
}
} else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:") || url.startsWith("intent:")) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
((inAppBrowserActivity != null) ? inAppBrowserActivity : flutterWebView.activity).startActivity(intent);
return true;
} catch (android.content.ActivityNotFoundException e) {
Log.e(LOG_TAG, "Error with " + url + ": " + e.toString());
}
}
// If sms:5551212?body=This is the message
else if (url.startsWith("sms:")) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
// Get address
String address;
int parmIndex = url.indexOf('?');
if (parmIndex == -1) {
address = url.substring(4);
} else {
address = url.substring(4, parmIndex);
// If body, then set sms body
Uri uri = Uri.parse(url);
String query = uri.getQuery();
if (query != null) {
if (query.startsWith("body=")) {
intent.putExtra("sms_body", query.substring(5));
}
public void onShouldOverrideUrlLoading(final String url, final String method, final Map<String, String> headers, final boolean isForMainFrame, boolean hasGesture, boolean isRedirect) {
Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url);
obj.put("method", method);
obj.put("headers", headers);
obj.put("isForMainFrame", isForMainFrame);
obj.put("androidHasGesture", hasGesture);
obj.put("androidIsRedirect", isRedirect);
obj.put("iosWKNavigationType", null);
getChannel().invokeMethod("shouldOverrideUrlLoading", 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");
if (action != null) {
switch (action) {
case 1:
if (isForMainFrame) {
// There isn't any way to load an URL for a frame that is not the main frame,
// so call this only on main frame.
InAppWebView webView = ((inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
webView.loadUrl(url, headers);
else
webView.loadUrl(url);
}
return;
case 0:
default:
return;
}
}
intent.setData(Uri.parse("sms:" + address));
intent.putExtra("address", address);
intent.setType("vnd.android-dir/mms-sms");
((inAppBrowserActivity != null) ? inAppBrowserActivity : flutterWebView.activity).startActivity(intent);
return true;
} catch (android.content.ActivityNotFoundException e) {
Log.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
}
}
}
return super.shouldOverrideUrlLoading(webView, url);
@Override
public void error(String s, String s1, Object o) {
Log.d(LOG_TAG, "ERROR: " + s + " " + s1);
}
@Override
public void notImplemented() {
}
});
}
@Override
@ -138,7 +172,6 @@ public class InAppWebViewClient extends WebViewClient {
String js = InAppWebView.consoleLogJS.replaceAll("[\r\n]+", "");
js += JavaScriptBridgeInterface.flutterInAppBroserJSClass.replaceAll("[\r\n]+", "");
if (webView.options.useShouldInterceptAjaxRequest) {
js += InAppWebView.interceptAjaxRequestsJS.replaceAll("[\r\n]+", "");
}
@ -148,6 +181,7 @@ public class InAppWebViewClient extends WebViewClient {
if (webView.options.useOnLoadResource) {
js += InAppWebView.resourceObserverJS.replaceAll("[\r\n]+", "");
}
js += InAppWebView.printJS.replaceAll("[\r\n]+", "");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript(js, (ValueCallback<String>) null);
@ -667,6 +701,11 @@ public class InAppWebViewClient extends WebViewClient {
return shouldInterceptRequest(view, url);
}
@Override
public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
}
private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppWebViewFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
}

View File

@ -20,7 +20,6 @@ public class InAppWebViewOptions extends Options {
public Boolean useShouldOverrideUrlLoading = false;
public Boolean useOnLoadResource = false;
public Boolean useOnDownloadStart = false;
public Boolean useOnTargetBlank = false;
public Boolean clearCache = false;
public String userAgent = "";
public String applicationNameForUserAgent = "";
@ -48,7 +47,7 @@ public class InAppWebViewOptions extends Options {
public Boolean displayZoomControls = false;
public Boolean supportZoom = true;
public Boolean databaseEnabled = false;
public Boolean domStorageEnabled = false;
public Boolean domStorageEnabled = true;
public Boolean useWideViewPort = true;
public Boolean safeBrowsingEnabled = true;
public Integer mixedContentMode;
@ -82,6 +81,8 @@ public class InAppWebViewOptions extends Options {
public Boolean saveFormData = true;
public Boolean thirdPartyCookiesEnabled = true;
public Boolean hardwareAcceleration = true;
public Boolean supportMultipleWindows = false;
public String regexToCancelSubFramesLoading;
@Override
public Object onParse(Map.Entry<String, Object> pair) {

View File

@ -15,6 +15,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin {
protected static final String LOG_TAG = "InAppWebViewFlutterPlugin";
public static InAppBrowser inAppBrowser;
public static InAppWebViewStatic inAppWebViewStatic;
public static MyCookieManager myCookieManager;
public static CredentialDatabaseHandler credentialDatabaseHandler;
public static ValueCallback<Uri[]> uploadMessageArray;
@ -28,6 +29,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin {
.platformViewRegistry()
.registerViewFactory(
"com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(registrar, registrar.view()));
new InAppWebViewStatic(registrar);
new MyCookieManager(registrar);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
new CredentialDatabaseHandler(registrar);
@ -44,6 +46,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin {
.getRegistry()
.registerViewFactory(
"com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(registrar,null));
inAppWebViewStatic = new InAppWebViewStatic(registrar);
myCookieManager = new MyCookieManager(registrar);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
credentialDatabaseHandler = new CredentialDatabaseHandler(registrar);
@ -64,6 +67,10 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin {
credentialDatabaseHandler.dispose();
credentialDatabaseHandler = null;
}
if (inAppWebViewStatic != null) {
inAppWebViewStatic.dispose();
inAppWebViewStatic = null;
}
uploadMessageArray = null;
}
}

View File

@ -0,0 +1,37 @@
package com.pichillilorenzo.flutter_inappwebview;
import android.util.Log;
import android.webkit.WebSettings;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
public class InAppWebViewStatic implements MethodChannel.MethodCallHandler {
public PluginRegistry.Registrar registrar;
public MethodChannel channel;
protected static final String LOG_TAG = "InAppWebViewStatic";
public InAppWebViewStatic(PluginRegistry.Registrar r) {
registrar = r;
channel = new MethodChannel(registrar.messenger(), "com.pichillilorenzo/flutter_inappwebview_static");
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
Log.d(LOG_TAG, call.method);
switch (call.method) {
case "getDefaultUserAgent":
result.success(WebSettings.getDefaultUserAgent(registrar.activeContext()));
break;
default:
result.notImplemented();
}
}
public void dispose() {
channel.setMethodCallHandler(null);
}
}

View File

@ -20,7 +20,222 @@ public class JavaScriptBridgeInterface {
private FlutterWebView flutterWebView;
private InAppBrowserActivity inAppBrowserActivity;
public static final String flutterInAppBroserJSClass = "window." + name + ".callHandler = function() {" +
// https://github.com/taylorhakes/promise-polyfill/blob/master/src/index.js
public static final String promisePolyfillJS = "if (window.Promise == null) {" +
" var setTimeoutFunc = setTimeout;" +
" function isArray(x) {" +
" return Boolean(x && typeof x.length !== \"undefined\");" +
" };" +
" function noop() {}" +
" function bind(fn, thisArg) {" +
" return function() {" +
" fn.apply(thisArg, arguments);" +
" };" +
" };" +
" function Promise(fn) {" +
" if (!(this instanceof Promise))" +
" throw new TypeError(\"Promises must be constructed via new\");" +
" if (typeof fn !== \"function\") throw new TypeError(\"not a function\");" +
" this._state = 0;" +
" this._handled = false;" +
" this._value = undefined;" +
" this._deferreds = [];" +
" doResolve(fn, this);" +
" };" +
" function handle(self, deferred) {" +
" while (self._state === 3) {" +
" self = self._value;" +
" }" +
" if (self._state === 0) {" +
" self._deferreds.push(deferred);" +
" return;" +
" }" +
" self._handled = true;" +
" Promise._immediateFn(function() {" +
" var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;" +
" if (cb === null) {" +
" (self._state === 1 ? resolve : reject)(deferred.promise, self._value);" +
" return;" +
" }" +
" var ret;" +
" try {" +
" ret = cb(self._value);" +
" } catch (e) {" +
" reject(deferred.promise, e);" +
" return;" +
" }" +
" resolve(deferred.promise, ret);" +
" });" +
" };" +
" function resolve(self, newValue) {" +
" try {" +
" if (newValue === self)" +
" throw new TypeError(\"A promise cannot be resolved with itself.\");" +
" if (" +
" newValue &&" +
" (typeof newValue === \"object\" || typeof newValue === \"function\")" +
" ) {" +
" var then = newValue.then;" +
" if (newValue instanceof Promise) {" +
" self._state = 3;" +
" self._value = newValue;" +
" finale(self);" +
" return;" +
" } else if (typeof then === \"function\") {" +
" doResolve(bind(then, newValue), self);" +
" return;" +
" }" +
" }" +
" self._state = 1;" +
" self._value = newValue;" +
" finale(self);" +
" } catch (e) {" +
" reject(self, e);" +
" }" +
" };" +
" function reject(self, newValue) {" +
" self._state = 2;" +
" self._value = newValue;" +
" finale(self);" +
" };" +
" function finale(self) {" +
" if (self._state === 2 && self._deferreds.length === 0) {" +
" Promise._immediateFn(function() {" +
" if (!self._handled) {" +
" Promise._unhandledRejectionFn(self._value);" +
" }" +
" });" +
" }" +
" for (var i = 0, len = self._deferreds.length; i < len; i++) {" +
" handle(self, self._deferreds[i]);" +
" }" +
" self._deferreds = null;" +
" };" +
" function Handler(onFulfilled, onRejected, promise) {" +
" this.onFulfilled = typeof onFulfilled === \"function\" ? onFulfilled : null;" +
" this.onRejected = typeof onRejected === \"function\" ? onRejected : null;" +
" this.promise = promise;" +
" };" +
" function doResolve(fn, self) {" +
" var done = false;" +
" try {" +
" fn(" +
" function(value) {" +
" if (done) return;" +
" done = true;" +
" resolve(self, value);" +
" }," +
" function(reason) {" +
" if (done) return;" +
" done = true;" +
" reject(self, reason);" +
" }" +
" );" +
" } catch (ex) {" +
" if (done) return;" +
" done = true;" +
" reject(self, ex);" +
" }" +
" };" +
" Promise.prototype[\"catch\"] = function(onRejected) {" +
" return this.then(null, onRejected);" +
" };" +
" Promise.prototype.then = function(onFulfilled, onRejected) {" +
" var prom = new this.constructor(noop);" +
" handle(this, new Handler(onFulfilled, onRejected, prom));" +
" return prom;" +
" };" +
" Promise.prototype[\"finally\"] = function finallyConstructor(callback) {" +
" var constructor = this.constructor;" +
" return this.then(" +
" function(value) {" +
" return constructor.resolve(callback()).then(function() {" +
" return value;" +
" });" +
" }," +
" function(reason) {" +
" return constructor.resolve(callback()).then(function() {" +
" return constructor.reject(reason);" +
" });" +
" }" +
" );" +
" };" +
" Promise.all = function(arr) {" +
" return new Promise(function(resolve, reject) {" +
" if (!isArray(arr)) {" +
" return reject(new TypeError(\"Promise.all accepts an array\"));" +
" }" +
" var args = Array.prototype.slice.call(arr);" +
" if (args.length === 0) return resolve([]);" +
" var remaining = args.length;" +
" function res(i, val) {" +
" try {" +
" if (val && (typeof val === \"object\" || typeof val === \"function\")) {" +
" var then = val.then;" +
" if (typeof then === \"function\") {" +
" then.call(" +
" val," +
" function(val) {" +
" res(i, val);" +
" }," +
" reject" +
" );" +
" return;" +
" }" +
" }" +
" args[i] = val;" +
" if (--remaining === 0) {" +
" resolve(args);" +
" }" +
" } catch (ex) {" +
" reject(ex);" +
" }" +
" }" +
" for (var i = 0; i < args.length; i++) {" +
" res(i, args[i]);" +
" }" +
" });" +
" };" +
" Promise.resolve = function(value) {" +
" if (value && typeof value === \"object\" && value.constructor === Promise) {" +
" return value;" +
" }" +
"" +
" return new Promise(function(resolve) {" +
" resolve(value);" +
" });" +
" };" +
" Promise.reject = function(value) {" +
" return new Promise(function(resolve, reject) {" +
" reject(value);" +
" });" +
" };" +
" Promise.race = function(arr) {" +
" return new Promise(function(resolve, reject) {" +
" if (!isArray(arr)) {" +
" return reject(new TypeError(\"Promise.race accepts an array\"));" +
" }" +
" for (var i = 0, len = arr.length; i < len; i++) {" +
" Promise.resolve(arr[i]).then(resolve, reject);" +
" }" +
" });" +
" };" +
" Promise._immediateFn =" +
" (typeof setImmediate === \"function\" &&" +
" function(fn) {" +
" setImmediate(fn);" +
" }) ||" +
" function(fn) {" +
" setTimeoutFunc(fn, 0);" +
" };" +
" Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {" +
" if (typeof console !== \"undefined\" && console) {" +
" console.warn(\"Possible Unhandled Promise Rejection:\", err);" +
" }" +
" };" +
"}";
public static final String flutterInAppBroserJSClass = promisePolyfillJS + " " + "window." + name + ".callHandler = function() {" +
"var _callHandlerID = setTimeout(function(){});" +
"window." + name + "._callHandler(arguments[0], _callHandlerID, JSON.stringify(Array.prototype.slice.call(arguments, 1)));" +
"return new Promise(function(resolve, reject) {" +
@ -37,6 +252,8 @@ public class JavaScriptBridgeInterface {
@JavascriptInterface
public void _callHandler(final String handlerName, final String _callHandlerID, String args) {
final InAppWebView webView = (inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView;
final Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
@ -49,11 +266,13 @@ public class JavaScriptBridgeInterface {
handler.post(new Runnable() {
@Override
public void run() {
if (handlerName.equals("onPrint") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webView.printCurrentPage();
}
getChannel().invokeMethod("onCallJsHandler", obj, new MethodChannel.Result() {
@Override
public void success(Object json) {
InAppWebView webView = (inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView;
if (webView == null) {
// The webview has already been disposed, ignore.
return;

View File

@ -2,10 +2,9 @@
# 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_FRAMEWORK_DIR=/Users/lorenzopichilli/flutter/bin/cache/artifacts/engine/ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "TRACK_WIDGET_CREATION=true"

View File

@ -37,7 +37,7 @@ class MyInAppBrowser extends InAppBrowser {
}
@override
void shouldOverrideUrlLoading(String url) {
void shouldOverrideUrlLoading(String url, Map<String, String> headers, bool isForMainFrame) {
print("\n\n override $url\n\n");
this.webViewController.loadUrl(url: url);
}

View File

@ -31,7 +31,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
title: Text("InAppWebView")
),
drawer: myDrawer(context: context),
body: Container(
body: SafeArea(
child: Column(children: <Widget>[
Container(
padding: EdgeInsets.all(20.0),
@ -69,6 +69,11 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
this.url = url;
});
},
onNavigationStateChange: (InAppWebViewController controller, String url) async {
setState(() {
this.url = url;
});
},
onProgressChanged: (InAppWebViewController controller, int progress) {
setState(() {
this.progress = progress / 100;

View File

@ -1,11 +1,11 @@
import 'dart:async';
/*import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_inappwebview_example/chrome_safari_browser_example.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 'chrome_safari_browser_example.screen.dart';
import 'in_app_webiew_example.screen.dart';
import 'in_app_browser_example.screen.dart';
// InAppLocalhostServer localhostServer = new InAppLocalhostServer();
@ -76,4 +76,279 @@ class _MyAppState extends State<MyApp> {
}
);
}
}*/
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
Future main() async {
runApp(new MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: InAppWebViewPage()
);
}
}
class InAppWebViewPage extends StatefulWidget {
@override
_InAppWebViewPageState createState() => new _InAppWebViewPageState();
}
class _InAppWebViewPageState extends State<InAppWebViewPage> with WidgetsBindingObserver {
InAppWebViewController webView;
String defaultUserAgent;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
print(state);
if (webView != null) {
if (Platform.isAndroid) {
if (state == AppLifecycleState.paused) {
webView.pause();
} else if (state == AppLifecycleState.resumed) {
webView.resume();
}
}
if (state == AppLifecycleState.paused) {
webView.pauseTimers();
} else if (state == AppLifecycleState.resumed) {
webView.resumeTimers();
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("InAppWebView")
),
body: SafeArea(
child: Column(children: <Widget>[
Expanded(
child: Container(
child: InAppWebView(
//initialUrl: "https:/flutter.dev",
//initialFile: "assets/index.html",
initialData: InAppWebViewInitialData(
data: """
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Flutter InAppWebView</title>
<link rel="stylesheet" href="https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<link rel="shortcut icon" href="favicon.ico">
</head>
<body class="text-center">
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
<header class="masthead mb-auto">
<div class="inner">
<h3 class="masthead-brand">Flutter InAppWebView</h3>
<nav class="nav nav-masthead justify-content-center">
<a class="nav-link active" href="index.html">Home</a>
<a class="nav-link" href="page-1.html">Page 1</a>
<a class="nav-link" href="page-2.html">Page 2</a>
</nav>
</div>
</header>
<form action="https://example.org/" method="POST">
<input type="submit" />
</form>
<main role="main" class="inner cover">
<h1 class="cover-heading">Inline WebView</h1>
<img src="images/flutter-logo.svg" alt="flutter logo">
<p class="lead">Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.</p>
</main>
<footer class="mastfoot mt-auto">
<div class="inner">
<p>Cover template for <a target="_blank" href="https://getbootstrap.com/">Bootstrap</a>, by <a href="https://twitter.com/mdo">@mdo</a>.</p>
<p>Phone link example <a href="tel:1-408-555-5555">1-408-555-5555</a></p>
<p>Email link example <a href="mailto:example@gmail.com">example@gmail.com</a></p>
</div>
</footer>
</div>
</body>
</html>
"""
),
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions(
debuggingEnabled: true,
useShouldOverrideUrlLoading: true
),
androidInAppWebViewOptions: AndroidInAppWebViewOptions(
domStorageEnabled: true,
regexToCancelSubFramesLoading: ""
)
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart: (InAppWebViewController controller, String url) {
print("start $url");
},
onLoadStop: (InAppWebViewController controller, String url) async {
print("stop $url");
},
onPrint: (InAppWebViewController controller, String url) async {
print("print $url");
},
onCreateWindow: (InAppWebViewController controller, String url) async {
print("target blank $url");
},
shouldOverrideUrlLoading: (InAppWebViewController controller, ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async {
print("overidde url ${shouldOverrideUrlLoadingRequest.url}, method: ${shouldOverrideUrlLoadingRequest.method}, headers: ${shouldOverrideUrlLoadingRequest.headers}, isForMainFrame: ${shouldOverrideUrlLoadingRequest.isForMainFrame}");
return ShouldOverrideUrlLoadingAction.ALLOW;
},
),
)
/*Container(
child: InAppWebView(
initialUrl: "about:blank",
//initialUrl: "https://www.youtube.com/embed/fq4N0hgOWzU",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions(
debuggingEnabled: true,
)
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart: (InAppWebViewController controller, String url) {
},
onLoadStop: (InAppWebViewController controller, String url) async {
if (url == "about:blank" && defaultUserAgent == null) {
defaultUserAgent = await controller.evaluateJavascript(
source: "navigator.userAgent");
webView.setOptions(options: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions(
userAgent: defaultUserAgent + " my-custom-value",
)
));
webView.loadUrl(url: "https://flutter.dev");
}
print(await controller.evaluateJavascript(
source: "navigator.userAgent"));
},
),
)*/
/*child: FutureBuilder(
future: InAppWebViewController.getDefaultUserAgent(),
builder: (context, projectSnap) {
if (!projectSnap.hasData) {
return Center(child: CircularProgressIndicator());
} else {
return Container(
child: InAppWebView(
initialUrl: "https://flutter.dev",
//initialUrl: "https://www.youtube.com/embed/fq4N0hgOWzU",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions(
debuggingEnabled: true,
userAgent: projectSnap.data.toString() + "; my-value"
)
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart: (InAppWebViewController controller, String url) {
},
onLoadStop: (InAppWebViewController controller, String url) async {
print(await controller.evaluateJavascript(source: "navigator.userAgent"));
},
),
);
}
}
),*/
),
ButtonBar(
alignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Icon(Icons.arrow_back),
onPressed: () {
if (webView != null) {
webView.goBack();
}
},
),
RaisedButton(
child: Icon(Icons.arrow_forward),
onPressed: () {
if (webView != null) {
webView.goForward();
}
},
),
RaisedButton(
child: Icon(Icons.refresh),
onPressed: () {
if (webView != null) {
webView.reload();
}
},
),
],
),
]))
);
}
}

View File

@ -56,7 +56,7 @@ flutter:
- test_assets/in_app_webview_javascript_handler_test.html
- test_assets/in_app_webview_on_load_resource_custom_scheme_test.html
- test_assets/in_app_webview_on_console_message_test.html
- test_assets/in_app_webview_on_target_blank_test.html
- test_assets/in_app_webview_on_create_window_test.html
- test_assets/in_app_webview_on_js_dialog_test.html
- test_assets/css/
- test_assets/images/

View File

@ -4,10 +4,10 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>InAppWebViewOnTargetBlankTest</title>
<title>InAppWebViewOnCreateWindowTest</title>
</head>
<body>
<h1>InAppWebViewOnTargetBlankTest</h1>
<h1>InAppWebViewOnCreateWindowTest</h1>
<a id="target-blank" href="https://flutter.dev/" target="_blank">target blank</a>
<script>
document.querySelector('#target-blank').click();

View File

@ -5,15 +5,15 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'main_test.dart';
import 'custom_widget_test.dart';
class InAppWebViewOnTargetBlankTest extends WidgetTest {
final InAppWebViewOnTargetBlankTestState state = InAppWebViewOnTargetBlankTestState();
class InAppWebViewOnCreateWindowTest extends WidgetTest {
final InAppWebViewOnCreateWindowTestState state = InAppWebViewOnCreateWindowTestState();
@override
InAppWebViewOnTargetBlankTestState createState() => state;
InAppWebViewOnCreateWindowTestState createState() => state;
}
class InAppWebViewOnTargetBlankTestState extends WidgetTestState {
String appBarTitle = "InAppWebViewOnTargetBlankTest";
class InAppWebViewOnCreateWindowTestState extends WidgetTestState {
String appBarTitle = "InAppWebViewOnCreateWindowTest";
@override
Widget build(BuildContext context) {
@ -26,13 +26,12 @@ class InAppWebViewOnTargetBlankTestState extends WidgetTestState {
Expanded(
child: Container(
child: InAppWebView(
initialFile: "test_assets/in_app_webview_on_target_blank_test.html",
initialFile: "test_assets/in_app_webview_on_create_window_test.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions(
clearCache: true,
debuggingEnabled: true,
useOnTargetBlank: true,
javaScriptCanOpenWindowsAutomatically: true,
)
),
@ -49,7 +48,7 @@ class InAppWebViewOnTargetBlankTestState extends WidgetTestState {
});
}
},
onTargetBlank: (InAppWebViewController controller, String url) {
onCreateWindow: (InAppWebViewController controller, String url) {
controller.loadUrl(url: url);
},
),

View File

@ -50,8 +50,9 @@ class InAppWebViewShouldOverrideUrlLoadingTestState extends WidgetTestState {
controller.evaluateJavascript(source: "document.querySelector('#link').click();");
}
},
shouldOverrideUrlLoading: (InAppWebViewController controller, String url) {
shouldOverrideUrlLoading: (InAppWebViewController controller, ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async {
controller.loadUrl(url: "https://flutter.dev/");
return ShouldOverrideUrlLoadingAction.CANCEL;
},
),
),

View File

@ -25,7 +25,7 @@ import 'in_app_webview_on_progress_changed_test.dart';
import 'in_app_webview_on_received_http_auth_request_test.dart';
import 'in_app_webview_on_safe_browsing_hit_test.dart';
import 'in_app_webview_on_scroll_changed_test.dart';
import 'in_app_webview_on_target_blank_test.dart';
import 'in_app_webview_on_create_window_test.dart';
import 'in_app_webview_should_override_url_loading_test.dart';
import 'in_app_webview_ssl_request_test.dart';
@ -44,7 +44,7 @@ Map<String, WidgetBuilder> getTestRoutes({@required BuildContext context}) {
'/InAppWebViewShouldOverrideUrlLoadingTest': (context) => InAppWebViewShouldOverrideUrlLoadingTest(),
'/InAppWebViewOnConsoleMessageTest': (context) => InAppWebViewOnConsoleMessageTest(),
'/InAppWebViewOnDownloadStartTest': (context) => InAppWebViewOnDownloadStartTest(),
'/InAppWebViewOnTargetBlankTest': (context) => InAppWebViewOnTargetBlankTest(),
'/InAppWebViewOnCreateWindowTest': (context) => InAppWebViewOnCreateWindowTest(),
'/InAppWebViewOnJsDialogTest': (context) => InAppWebViewOnJsDialogTest(),
'/InAppWebViewOnSafeBrowsingHitTest': (context) => InAppWebViewOnSafeBrowsingHitTest(),
'/InAppWebViewOnReceivedHttpAuthRequestTest': (context) => InAppWebViewOnReceivedHttpAuthRequestTest(),

View File

@ -20,7 +20,13 @@
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/build" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/ios/Flutter/App.framework/flutter_assets/packages" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/build" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/build" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/ios/Flutter/App.framework/flutter_assets/packages" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/App.framework/flutter_assets/packages" />
<excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/.pub" />

View File

@ -330,6 +330,20 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
}
result(true)
break
case "printCurrentPage":
if webView != nil {
webView!.printCurrentPage(printCompletionHandler: {(completed, error) in
if !completed, let e = error {
result(false)
return
}
result(true)
})
} else {
result(false)
}
break
case "removeFromSuperview":
webView!.removeFromSuperview()
result(true)

View File

@ -41,6 +41,234 @@ func JSONStringify(value: Any, prettyPrinted: Bool = false) -> String {
let JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview"
// https://github.com/taylorhakes/promise-polyfill/blob/master/src/index.js
let promisePolyfillJS = """
if (window.Promise == null) {
var setTimeoutFunc = setTimeout;
function isArray(x) {
return Boolean(x && typeof x.length !== "undefined");
};
function noop() {}
function bind(fn, thisArg) {
return function() {
fn.apply(thisArg, arguments);
};
};
function Promise(fn) {
if (!(this instanceof Promise))
throw new TypeError("Promises must be constructed via new");
if (typeof fn !== "function") throw new TypeError("not a function");
this._state = 0;
this._handled = false;
this._value = undefined;
this._deferreds = [];
doResolve(fn, this);
};
function handle(self, deferred) {
while (self._state === 3) {
self = self._value;
}
if (self._state === 0) {
self._deferreds.push(deferred);
return;
}
self._handled = true;
Promise._immediateFn(function() {
var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
if (cb === null) {
(self._state === 1 ? resolve : reject)(deferred.promise, self._value);
return;
}
var ret;
try {
ret = cb(self._value);
} catch (e) {
reject(deferred.promise, e);
return;
}
resolve(deferred.promise, ret);
});
};
function resolve(self, newValue) {
try {
if (newValue === self)
throw new TypeError("A promise cannot be resolved with itself.");
if (
newValue &&
(typeof newValue === "object" || typeof newValue === "function")
) {
var then = newValue.then;
if (newValue instanceof Promise) {
self._state = 3;
self._value = newValue;
finale(self);
return;
} else if (typeof then === "function") {
doResolve(bind(then, newValue), self);
return;
}
}
self._state = 1;
self._value = newValue;
finale(self);
} catch (e) {
reject(self, e);
}
};
function reject(self, newValue) {
self._state = 2;
self._value = newValue;
finale(self);
};
function finale(self) {
if (self._state === 2 && self._deferreds.length === 0) {
Promise._immediateFn(function() {
if (!self._handled) {
Promise._unhandledRejectionFn(self._value);
}
});
}
for (var i = 0, len = self._deferreds.length; i < len; i++) {
handle(self, self._deferreds[i]);
}
self._deferreds = null;
};
function Handler(onFulfilled, onRejected, promise) {
this.onFulfilled = typeof onFulfilled === "function" ? onFulfilled : null;
this.onRejected = typeof onRejected === "function" ? onRejected : null;
this.promise = promise;
};
function doResolve(fn, self) {
var done = false;
try {
fn(
function(value) {
if (done) return;
done = true;
resolve(self, value);
},
function(reason) {
if (done) return;
done = true;
reject(self, reason);
}
);
} catch (ex) {
if (done) return;
done = true;
reject(self, ex);
}
};
Promise.prototype["catch"] = function(onRejected) {
return this.then(null, onRejected);
};
Promise.prototype.then = function(onFulfilled, onRejected) {
var prom = new this.constructor(noop);
handle(this, new Handler(onFulfilled, onRejected, prom));
return prom;
};
Promise.prototype["finally"] = function finallyConstructor(callback) {
var constructor = this.constructor;
return this.then(
function(value) {
return constructor.resolve(callback()).then(function() {
return value;
});
},
function(reason) {
return constructor.resolve(callback()).then(function() {
return constructor.reject(reason);
});
}
);
};
Promise.all = function(arr) {
return new Promise(function(resolve, reject) {
if (!isArray(arr)) {
return reject(new TypeError("Promise.all accepts an array"));
}
var args = Array.prototype.slice.call(arr);
if (args.length === 0) return resolve([]);
var remaining = args.length;
function res(i, val) {
try {
if (val && (typeof val === "object" || typeof val === "function")) {
var then = val.then;
if (typeof then === "function") {
then.call(
val,
function(val) {
res(i, val);
},
reject
);
return;
}
}
args[i] = val;
if (--remaining === 0) {
resolve(args);
}
} catch (ex) {
reject(ex);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
};
Promise.resolve = function(value) {
if (value && typeof value === "object" && value.constructor === Promise) {
return value;
}
return new Promise(function(resolve) {
resolve(value);
});
};
Promise.reject = function(value) {
return new Promise(function(resolve, reject) {
reject(value);
});
};
Promise.race = function(arr) {
return new Promise(function(resolve, reject) {
if (!isArray(arr)) {
return reject(new TypeError("Promise.race accepts an array"));
}
for (var i = 0, len = arr.length; i < len; i++) {
Promise.resolve(arr[i]).then(resolve, reject);
}
});
};
Promise._immediateFn =
(typeof setImmediate === "function" &&
function(fn) {
setImmediate(fn);
}) ||
function(fn) {
setTimeoutFunc(fn, 0);
};
Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {
if (typeof console !== "undefined" && console) {
console.warn("Possible Unhandled Promise Rejection:", err);
}
};
}
"""
let javaScriptBridgeJS = """
window.\(JAVASCRIPT_BRIDGE_NAME) = {};
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler = function() {
var _callHandlerID = setTimeout(function(){});
window.webkit.messageHandlers['callHandler'].postMessage( {'handlerName': arguments[0], '_callHandlerID': _callHandlerID, 'args': JSON.stringify(Array.prototype.slice.call(arguments, 1))} );
return new Promise(function(resolve, reject) {
window.\(JAVASCRIPT_BRIDGE_NAME)[_callHandlerID] = resolve;
});
}
"""
// the message needs to be concatenated with '' in order to have the same behavior like on Android
let consoleLogJS = """
(function(console) {
@ -71,14 +299,9 @@ let consoleLogJS = """
})(window.console);
"""
let javaScriptBridgeJS = """
window.\(JAVASCRIPT_BRIDGE_NAME) = {};
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler = function() {
var _callHandlerID = setTimeout(function(){});
window.webkit.messageHandlers['callHandler'].postMessage( {'handlerName': arguments[0], '_callHandlerID': _callHandlerID, 'args': JSON.stringify(Array.prototype.slice.call(arguments, 1))} );
return new Promise(function(resolve, reject) {
window.\(JAVASCRIPT_BRIDGE_NAME)[_callHandlerID] = resolve;
});
let printJS = """
window.print = function() {
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler("onPrint", window.location.href);
}
"""
@ -691,6 +914,11 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
var lastScrollY: CGFloat = 0
var isPausedTimers = false
var isPausedTimersCompletionHandler: (() -> Void)?
var webViewForUserAgent: WKWebView?
var defaultUserAgent: String?
// This flag is used to block the "shouldOverrideUrlLoading" event when the WKWebView is loading the first time,
// in order to have the same behavior as Android
var activateShouldOverrideUrlLoading = false
init(frame: CGRect, configuration: WKWebViewConfiguration, IABController: InAppBrowserWebViewController?, IAWController: FlutterWebViewController?) {
@ -700,6 +928,23 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
uiDelegate = self
navigationDelegate = self
scrollView.delegate = self
webViewForUserAgent = WKWebView()
webViewForUserAgent?.evaluateJavaScript("navigator.userAgent") { (result, error) in
if error != nil {
print("Error occured to get userAgent")
self.webViewForUserAgent = nil
return
}
if let unwrappedUserAgent = result as? String {
self.defaultUserAgent = unwrappedUserAgent
} else {
print("Failed to get userAgent")
}
self.webViewForUserAgent = nil
}
}
required public init(coder aDecoder: NSCoder) {
@ -746,6 +991,13 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
let jscriptWebkitTouchCallout = WKUserScript(source: "document.body.style.webkitTouchCallout='none';", injectionTime: .atDocumentEnd, forMainFrameOnly: true)
configuration.userContentController.addUserScript(jscriptWebkitTouchCallout)
let promisePolyfillJSScript = WKUserScript(source: promisePolyfillJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(promisePolyfillJSScript)
let javaScriptBridgeJSScript = WKUserScript(source: javaScriptBridgeJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(javaScriptBridgeJSScript)
configuration.userContentController.add(self, name: "callHandler")
let consoleLogJSScript = WKUserScript(source: consoleLogJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(consoleLogJSScript)
configuration.userContentController.add(self, name: "consoleLog")
@ -754,9 +1006,8 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
configuration.userContentController.add(self, name: "consoleInfo")
configuration.userContentController.add(self, name: "consoleWarn")
let javaScriptBridgeJSScript = WKUserScript(source: javaScriptBridgeJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(javaScriptBridgeJSScript)
configuration.userContentController.add(self, name: "callHandler")
let printJSScript = WKUserScript(source: printJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(printJSScript)
if (options?.useOnLoadResource)! {
let resourceObserverJSScript = WKUserScript(source: resourceObserverJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
@ -1300,46 +1551,63 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
let app = UIApplication.shared
if let url = navigationAction.request.url {
// Handle target="_blank"
if navigationAction.targetFrame == nil && (options?.useOnTargetBlank)! {
onTargetBlank(url: url)
decisionHandler(.cancel)
return
}
if navigationAction.navigationType == .linkActivated && (options?.useShouldOverrideUrlLoading)! {
shouldOverrideUrlLoading(url: url)
decisionHandler(.cancel)
return
}
// Handle phone and email links
if url.scheme == "tel" || url.scheme == "mailto" {
if app.canOpenURL(url) {
if #available(iOS 10.0, *) {
app.open(url)
} else {
app.openURL(url)
if activateShouldOverrideUrlLoading && (options?.useShouldOverrideUrlLoading)! {
let isForMainFrame = navigationAction.targetFrame?.isMainFrame ?? false
shouldOverrideUrlLoading(url: url, method: navigationAction.request.httpMethod, headers: navigationAction.request.allHTTPHeaderFields, isForMainFrame: isForMainFrame, navigationType: navigationAction.navigationType, result: { (result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
}
}
decisionHandler(.cancel)
else if (result as? NSObject) == FlutterMethodNotImplemented {
self.updateUrlTextFieldForIABController(navigationAction: navigationAction)
decisionHandler(.allow)
}
else {
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 1:
self.updateUrlTextFieldForIABController(navigationAction: navigationAction)
decisionHandler(.allow)
break
default:
decisionHandler(.cancel)
}
return;
}
self.updateUrlTextFieldForIABController(navigationAction: navigationAction)
decisionHandler(.allow)
}
})
return
}
if navigationAction.navigationType == .linkActivated || navigationAction.navigationType == .backForward {
currentURL = url
if IABController != nil {
IABController!.updateUrlTextField(url: (currentURL?.absoluteString)!)
}
}
updateUrlTextFieldForIABController(navigationAction: navigationAction)
}
if !activateShouldOverrideUrlLoading {
activateShouldOverrideUrlLoading = true
}
decisionHandler(.allow)
}
public func updateUrlTextFieldForIABController(navigationAction: WKNavigationAction) {
if navigationAction.navigationType == .linkActivated || navigationAction.navigationType == .backForward {
currentURL = url
if IABController != nil {
IABController!.updateUrlTextField(url: (currentURL?.absoluteString)!)
}
}
}
public func webView(_ webView: WKWebView,
decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
@ -1839,6 +2107,14 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
lastScrollY = scrollView.contentOffset.y
}
public func webView(_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures) -> WKWebView? {
onCreateWindow(url: navigationAction.request.url!)
return nil
}
public func onLoadStart(url: String) {
var arguments: [String: Any] = ["url": url]
if IABController != nil {
@ -1945,23 +2221,31 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
}
}
public func shouldOverrideUrlLoading(url: URL) {
var arguments: [String: Any] = ["url": url.absoluteString]
public func shouldOverrideUrlLoading(url: URL, method: String?, headers: [String: String]?, isForMainFrame: Bool, navigationType: WKNavigationType, result: FlutterResult?) {
var arguments: [String: Any?] = [
"url": url.absoluteString,
"method": method,
"headers": headers,
"isForMainFrame": isForMainFrame,
"androidHasGesture": nil,
"androidIsRedirect": nil,
"iosWKNavigationType": navigationType.rawValue
]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("shouldOverrideUrlLoading", arguments: arguments)
channel.invokeMethod("shouldOverrideUrlLoading", arguments: arguments, result: result)
}
}
public func onTargetBlank(url: URL) {
public func onCreateWindow(url: URL) {
var arguments: [String: Any] = ["url": url.absoluteString]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onTargetBlank", arguments: arguments)
channel.invokeMethod("onCreateWindow", arguments: arguments)
}
}
@ -2091,32 +2375,34 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
if message.name.starts(with: "console") {
var messageLevel = 1
switch (message.name) {
case "consoleLog":
messageLevel = 1
break;
case "consoleDebug":
// on Android, console.debug is TIP
messageLevel = 0
break;
case "consoleError":
messageLevel = 3
break;
case "consoleInfo":
// on Android, console.info is LOG
messageLevel = 1
break;
case "consoleWarn":
messageLevel = 2
break;
default:
messageLevel = 1
break;
case "consoleLog":
messageLevel = 1
break;
case "consoleDebug":
// on Android, console.debug is TIP
messageLevel = 0
break;
case "consoleError":
messageLevel = 3
break;
case "consoleInfo":
// on Android, console.info is LOG
messageLevel = 1
break;
case "consoleWarn":
messageLevel = 2
break;
default:
messageLevel = 1
break;
}
onConsoleMessage(message: message.body as! String, messageLevel: messageLevel)
}
else if message.name == "callHandler" {
} else if message.name == "callHandler" {
let body = message.body as! [String: Any]
let handlerName = body["handlerName"] as! String
if handlerName == "onPrint" {
printCurrentPage(printCompletionHandler: nil)
}
let _callHandlerID = body["_callHandlerID"] as! Int64
let args = body["args"] as! String
onCallJsHandler(handlerName: handlerName, _callHandlerID: _callHandlerID, args: args)
@ -2180,6 +2466,27 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
isPausedTimers = false
}
public func printCurrentPage(printCompletionHandler: ((_ completed: Bool, _ error: Error?) -> Void)?) {
let printController = UIPrintInteractionController.shared
let printFormatter = self.viewPrintFormatter()
printController.printFormatter = printFormatter
let completionHandler: UIPrintInteractionController.CompletionHandler = { (printController, completed, error) in
if !completed {
if let e = error {
print("[PRINT] Failed: \(e.localizedDescription)")
} else {
print("[PRINT] Canceled")
}
}
if let callback = printCompletionHandler {
callback(completed, error)
}
}
printController.present(animated: true, completionHandler: completionHandler)
}
public override func removeFromSuperview() {
configuration.userContentController.removeScriptMessageHandler(forName: "consoleLog")
configuration.userContentController.removeScriptMessageHandler(forName: "consoleDebug")

View File

@ -14,7 +14,6 @@ public class InAppWebViewOptions: Options {
var useShouldOverrideUrlLoading = false
var useOnLoadResource = false
var useOnDownloadStart = false
var useOnTargetBlank = false
var clearCache = false
var userAgent = ""
var applicationNameForUserAgent = ""

View File

@ -0,0 +1,66 @@
//
// InAppWebViewStatic.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 08/12/2019.
//
import Foundation
import WebKit
class InAppWebViewStatic: NSObject, FlutterPlugin {
static var registrar: FlutterPluginRegistrar?
static var channel: FlutterMethodChannel?
static var webViewForUserAgent: WKWebView?
static var defaultUserAgent: String?
static func register(with registrar: FlutterPluginRegistrar) {
}
init(registrar: FlutterPluginRegistrar) {
super.init()
InAppWebViewStatic.registrar = registrar
InAppWebViewStatic.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_static", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(self, channel: InAppWebViewStatic.channel!)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
//let arguments = call.arguments as? NSDictionary
switch call.method {
case "getDefaultUserAgent":
InAppWebViewStatic.getDefaultUserAgent(completionHandler: { (value) in
result(value)
})
break
default:
result(FlutterMethodNotImplemented)
break
}
}
static public func getDefaultUserAgent(completionHandler: @escaping (_ value: String?) -> Void) {
if defaultUserAgent == nil {
InAppWebViewStatic.webViewForUserAgent = WKWebView()
InAppWebViewStatic.webViewForUserAgent?.evaluateJavaScript("navigator.userAgent") { (value, error) in
if error != nil {
print("Error occured to get userAgent")
self.webViewForUserAgent = nil
completionHandler(nil)
return
}
if let unwrappedUserAgent = value as? String {
InAppWebViewStatic.defaultUserAgent = unwrappedUserAgent
completionHandler(defaultUserAgent)
} else {
print("Failed to get userAgent")
}
self.webViewForUserAgent = nil
}
} else {
completionHandler(defaultUserAgent)
}
}
}

View File

@ -57,12 +57,10 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
SwiftFlutterPlugin.instance = SwiftFlutterPlugin(with: registrar)
registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: "com.pichillilorenzo/flutter_inappwebview")
InAppWebViewStatic(registrar: registrar)
if #available(iOS 11.0, *) {
MyCookieManager(registrar: registrar)
} else {
// Fallback on earlier versions
}
CredentialDatabase(registrar: registrar)
}

View File

@ -357,10 +357,19 @@ class InAppBrowser {
///Event fired when the [InAppBrowser] webview receives a [ConsoleMessage].
void onConsoleMessage(ConsoleMessage consoleMessage) {}
///Give the host application a chance to take control when a URL is about to be loaded in the current WebView.
///Give the host application a chance to take control when a URL is about to be loaded in the current WebView. This event is not called on the initial load of the WebView.
///
///Note that on Android there isn't any way to load an URL for a frame that is not the main frame, so if the request is not for the main frame, the navigation is allowed by default.
///However, if you want to cancel requests for subframes, you can use the [AndroidInAppWebViewOptions.regexToCancelSubFramesLoading] option
///to write a Regular Expression that, if the url request of a subframe matches, then the request of that subframe is canceled.
///
///Also, on Android, this method is not called for POST requests.
///
///[shouldOverrideUrlLoadingRequest] represents the navigation request.
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldOverrideUrlLoading] option to `true`.
void shouldOverrideUrlLoading(String url) {}
// ignore: missing_return
Future<ShouldOverrideUrlLoadingAction> shouldOverrideUrlLoading(ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) {}
///Event fired when the [InAppBrowser] webview loads a resource.
///
@ -390,12 +399,13 @@ class InAppBrowser {
Future<CustomSchemeResponse> onLoadResourceCustomScheme(
String scheme, String url) {}
///Event fired when the [InAppBrowser] webview tries to open a link with `target="_blank"`.
///Event fired when the [InAppBrowser] webview requests the host application to create a new window,
///for example when trying to open a link with `target="_blank"` or when `window.open()` is called by JavaScript side.
///
///[url] represents the url of the link.
///[url] represents the url of the request.
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useOnTargetBlank] option to `true`.
void onTargetBlank(String url) {}
///**NOTE**: on Android you need to set [AndroidInAppWebViewOptions.supportMultipleWindows] option to `true`.
void onCreateWindow(String url) {}
///Event that notifies the host application that web content from the specified origin is attempting to use the Geolocation API, but no permission state is currently set for that origin.
///Note that for applications targeting Android N and later SDKs (API level > `Build.VERSION_CODES.M`) this method is only called for requests originating from secure origins such as https.
@ -533,6 +543,13 @@ class InAppBrowser {
Future<PermissionRequestResponse> onPermissionRequest(
String origin, List<String> resources) {}
///Event fired when `window.print()` is called from JavaScript side.
///
///[url] represents the url on which is called.
///
///**NOTE**: available on Android 21+.
void onPrint(String url) {}
void throwIsAlreadyOpened({String message = ''}) {
if (this.isOpened()) {
throw Exception([

View File

@ -16,12 +16,14 @@ import 'types.dart';
import 'in_app_browser.dart';
import 'webview_options.dart';
///List of forbidden names for JavaScript handlers.
const javaScriptHandlerForbiddenNames = [
"onLoadResource",
"shouldInterceptAjaxRequest",
"onAjaxReadyStateChange",
"onAjaxProgress",
"shouldInterceptFetchRequest"
"shouldInterceptFetchRequest",
"onPrint",
];
///InAppWebView Widget class.
@ -63,10 +65,18 @@ class InAppWebView extends StatefulWidget {
InAppWebViewController controller, ConsoleMessage consoleMessage)
onConsoleMessage;
///Give the host application a chance to take control when a URL is about to be loaded in the current WebView.
///Give the host application a chance to take control when a URL is about to be loaded in the current WebView. This event is not called on the initial load of the WebView.
///
///Note that on Android there isn't any way to load an URL for a frame that is not the main frame, so if the request is not for the main frame, the navigation is allowed by default.
///However, if you want to cancel requests for subframes, you can use the [AndroidInAppWebViewOptions.regexToCancelSubFramesLoading] option
///to write a Regular Expression that, if the url request of a subframe matches, then the request of that subframe is canceled.
///
///Also, on Android, this method is not called for POST requests.
///
///[shouldOverrideUrlLoadingRequest] represents the navigation request.
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldOverrideUrlLoading] option to `true`.
final void Function(InAppWebViewController controller, String url)
final Future<ShouldOverrideUrlLoadingAction> Function(InAppWebViewController controller, ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest)
shouldOverrideUrlLoading;
///Event fired when the [InAppWebView] loads a resource.
@ -101,13 +111,14 @@ class InAppWebView extends StatefulWidget {
InAppWebViewController controller, String scheme, String url)
onLoadResourceCustomScheme;
///Event fired when the [InAppWebView] tries to open a link with `target="_blank"`.
///Event fired when the [InAppWebView] requests the host application to create a new window,
///for example when trying to open a link with `target="_blank"` or when `window.open()` is called by JavaScript side.
///
///[url] represents the url of the link.
///[url] represents the url of the request.
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useOnTargetBlank] option to `true`.
///**NOTE**: on Android you need to set [AndroidInAppWebViewOptions.supportMultipleWindows] option to `true`.
final void Function(InAppWebViewController controller, String url)
onTargetBlank;
onCreateWindow;
///Event that notifies the host application that web content from the specified origin is attempting to use the Geolocation API, but no permission state is currently set for that origin.
///Note that for applications targeting Android N and later SDKs (API level > `Build.VERSION_CODES.M`) this method is only called for requests originating from secure origins such as https.
@ -246,7 +257,7 @@ class InAppWebView extends StatefulWidget {
InAppWebViewController controller, FetchRequest fetchRequest)
shouldInterceptFetchRequest;
///Event fired when the navigation state of the [InAppWebView] changes throught the usage of
///Event fired when the navigation state of the [InAppWebView] changes through the usage of
///javascript **[History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API)** functions (`pushState()`, `replaceState()`) and `onpopstate` event.
///
///Also, the event is fired when the javascript `window.location` changes without reloading the webview (for example appending or modifying an hash to the url).
@ -267,6 +278,13 @@ class InAppWebView extends StatefulWidget {
String origin,
List<String> resources) onPermissionRequest;
///Event fired when `window.print()` is called from JavaScript side.
///
///[url] represents the url on which is called.
///
///**NOTE**: available on Android 21+.
final void Function(InAppWebViewController controller, String url) onPrint;
///Initial url that will be loaded.
final String initialUrl;
@ -310,7 +328,7 @@ class InAppWebView extends StatefulWidget {
this.onScrollChanged,
this.onDownloadStart,
this.onLoadResourceCustomScheme,
this.onTargetBlank,
this.onCreateWindow,
this.onGeolocationPermissionsShowPrompt,
this.onJsAlert,
this.onJsConfirm,
@ -326,6 +344,7 @@ class InAppWebView extends StatefulWidget {
this.shouldInterceptFetchRequest,
this.onNavigationStateChange,
this.onPermissionRequest,
this.onPrint,
this.gestureRecognizers,
}) : super(key: key);
@ -426,6 +445,7 @@ class _InAppWebViewState extends State<InAppWebView> {
class InAppWebViewController {
InAppWebView _widget;
MethodChannel _channel;
static MethodChannel _staticChannel = MethodChannel('com.pichillilorenzo/flutter_inappwebview_static');
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap =
HashMap<String, JavaScriptHandlerCallback>();
// ignore: unused_field
@ -491,10 +511,20 @@ class InAppWebViewController {
break;
case "shouldOverrideUrlLoading":
String url = call.arguments["url"];
String method = call.arguments["method"];
Map<String, String> headers = call.arguments["headers"]?.cast<String, String>();
bool isForMainFrame = call.arguments["isForMainFrame"];
bool androidHasGesture = call.arguments["androidHasGesture"];
bool androidIsRedirect = call.arguments["androidIsRedirect"];
int iosWKNavigationType = call.arguments["iosWKNavigationType"];
ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest = ShouldOverrideUrlLoadingRequest(url: url, method: method, headers: headers, isForMainFrame: isForMainFrame,
androidHasGesture: androidHasGesture, androidIsRedirect: androidIsRedirect, iosWKNavigationType: IosWKNavigationType.fromValue(iosWKNavigationType));
if (_widget != null && _widget.shouldOverrideUrlLoading != null)
_widget.shouldOverrideUrlLoading(this, url);
return (await _widget.shouldOverrideUrlLoading(this, shouldOverrideUrlLoadingRequest))?.toMap();
else if (_inAppBrowser != null)
_inAppBrowser.shouldOverrideUrlLoading(url);
return (await _inAppBrowser.shouldOverrideUrlLoading(shouldOverrideUrlLoadingRequest))?.toMap();
break;
case "onConsoleMessage":
String message = call.arguments["message"];
@ -543,11 +573,11 @@ class InAppWebViewController {
}
}
break;
case "onTargetBlank":
case "onCreateWindow":
String url = call.arguments["url"];
if (_widget != null && _widget.onTargetBlank != null)
_widget.onTargetBlank(this, url);
else if (_inAppBrowser != null) _inAppBrowser.onTargetBlank(url);
if (_widget != null && _widget.onCreateWindow != null)
_widget.onCreateWindow(this, url);
else if (_inAppBrowser != null) _inAppBrowser.onCreateWindow(url);
break;
case "onGeolocationPermissionsShowPrompt":
String origin = call.arguments["origin"];
@ -875,6 +905,13 @@ class InAppWebViewController {
return jsonEncode(
await _inAppBrowser.shouldInterceptFetchRequest(request));
return null;
case "onPrint":
String url = args[0];
if (_widget != null && _widget.onPrint != null)
_widget.onPrint(this, url);
else if (_inAppBrowser != null)
_inAppBrowser.onPrint(url);
return null;
}
if (javaScriptHandlersMap.containsKey(handlerName)) {
@ -1388,6 +1425,8 @@ class InAppWebViewController {
/// });
/// """);
///```
///
///Forbidden names for JavaScript handlers are defined in [javaScriptHandlerForbiddenNames].
void addJavaScriptHandler(
{@required String handlerName,
@required JavaScriptHandlerCallback callback}) {
@ -1729,6 +1768,24 @@ class InAppWebViewController {
await _channel.invokeMethod('resumeTimers', args);
}
///Prints the current page.
///
///**NOTE**: available on Android 21+.
Future<void> printCurrentPage() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
await _channel.invokeMethod('printCurrentPage', args);
}
///Gets the default user agent.
static Future<String> getDefaultUserAgent() async {
Map<String, dynamic> args = <String, dynamic>{};
return await _staticChannel.invokeMethod('getDefaultUserAgent', args);
}
/*Future<void> dispose() async {
Map<String, dynamic> args = <String, dynamic>{};
if (Platform.isIOS)

View File

@ -1966,3 +1966,94 @@ class PermissionRequestResponse {
return {"resources": resources, "action": action?.toValue()};
}
}
///ShouldOverrideUrlLoadingAction class is used by [shouldOverrideUrlLoading] event.
///It represents the policy to pass back to the decision handler.
class ShouldOverrideUrlLoadingAction {
final int _value;
const ShouldOverrideUrlLoadingAction._internal(this._value);
int toValue() => _value;
///Cancel the navigation.
static const CANCEL = const ShouldOverrideUrlLoadingAction._internal(0);
///Allow the navigation to continue.
static const ALLOW = const ShouldOverrideUrlLoadingAction._internal(1);
bool operator ==(value) => value == _value;
@override
int get hashCode => _value.hashCode;
Map<String, dynamic> toMap() {
return {
"action": _value,
};
}
}
///IosWKNavigationType class represents the type of action triggering a navigation on iOS for the [shouldOverrideUrlLoading] event.
class IosWKNavigationType {
final int _value;
const IosWKNavigationType._internal(this._value);
int toValue() => _value;
static IosWKNavigationType fromValue(int value) {
if (value != null && ((value >= 0 && value <= 4) || value == -1))
return IosWKNavigationType._internal(value);
return null;
}
///A link with an href attribute was activated by the user.
static const LINK_ACTIVATED = const IosWKNavigationType._internal(0);
///A form was submitted.
static const FORM_SUBMITTED = const IosWKNavigationType._internal(1);
///An item from the back-forward list was requested.
static const BACK_FORWARD = const IosWKNavigationType._internal(2);
///The webpage was reloaded.
static const RELOAD = const IosWKNavigationType._internal(3);
///A form was resubmitted (for example by going back, going forward, or reloading).
static const FORM_RESUBMITTED = const IosWKNavigationType._internal(4);
///Navigation is taking place for some other reason.
static const OTHER = const IosWKNavigationType._internal(-1);
bool operator ==(value) => value == _value;
@override
int get hashCode => _value.hashCode;
}
///ShouldOverrideUrlLoadingAction class represents the navigation request used by the [shouldOverrideUrlLoading] event.
class ShouldOverrideUrlLoadingRequest {
///Represents the url of the navigation request.
String url;
///Represents the method of the navigation request. On Android < 21, this value is always `GET`.
String method;
///Represents the headers of the navigation request. On Android < 21, this is always `null`.
Map<String, String> headers;
///Indicates whether the request was made for the main frame. On Android < 21, this is always `true`.
bool isForMainFrame;
///Gets whether the request was a result of a server-side redirect. Available only on Android. On Android < 21, this is always `false`.
bool androidHasGesture;
///Gets whether a gesture (such as a click) was associated with the request.
///For security reasons in certain situations this method may return `false` even though
///the sequence of events which caused the request to be created was initiated by a user
///gesture.
///
///Available only on Android. On Android < 24, this is always `false`.
bool androidIsRedirect;
///The type of action triggering the navigation. Available only on iOS.
IosWKNavigationType iosWKNavigationType;
ShouldOverrideUrlLoadingRequest({this.url, this.method, this.headers, this.isForMainFrame, this.androidHasGesture, this.androidIsRedirect, this.iosWKNavigationType});
}

View File

@ -49,9 +49,6 @@ class InAppWebViewOptions
///Set to `true` to be able to listen at the [onDownloadStart] event. The default value is `false`.
bool useOnDownloadStart;
///Set to `true` to be able to listen at the [onTargetBlank] event. The default value is `false`.
bool useOnTargetBlank;
///Set to `true` to have all the browser's cache cleared before the new window is opened. The default value is `false`.
bool clearCache;
@ -135,7 +132,6 @@ class InAppWebViewOptions
{this.useShouldOverrideUrlLoading = false,
this.useOnLoadResource = false,
this.useOnDownloadStart = false,
this.useOnTargetBlank = false,
this.clearCache = false,
this.userAgent = "",
this.applicationNameForUserAgent = "",
@ -174,7 +170,6 @@ class InAppWebViewOptions
"useShouldOverrideUrlLoading": useShouldOverrideUrlLoading,
"useOnLoadResource": useOnLoadResource,
"useOnDownloadStart": useOnDownloadStart,
"useOnTargetBlank": useOnTargetBlank,
"clearCache": clearCache,
"userAgent": userAgent,
"applicationNameForUserAgent": applicationNameForUserAgent,
@ -213,7 +208,6 @@ class InAppWebViewOptions
options.useShouldOverrideUrlLoading = map["useShouldOverrideUrlLoading"];
options.useOnLoadResource = map["useOnLoadResource"];
options.useOnDownloadStart = map["useOnDownloadStart"];
options.useOnTargetBlank = map["useOnTargetBlank"];
options.clearCache = map["clearCache"];
options.userAgent = map["userAgent"];
options.applicationNameForUserAgent = map["applicationNameForUserAgent"];
@ -265,7 +259,7 @@ class AndroidInAppWebViewOptions
///Set to `true` if you want the database storage API is enabled. The default value is `false`.
bool databaseEnabled;
///Set to `true` if you want the DOM storage API is enabled. The default value is `false`.
///Set to `true` if you want the DOM storage API is enabled. The default value is `true`.
bool domStorageEnabled;
///Set to `true` if the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport.
@ -392,6 +386,7 @@ class AndroidInAppWebViewOptions
///Sets whether the WebView should save form data. In Android O, the platform has implemented a fully functional Autofill feature to store form data.
///Therefore, the Webview form data save feature is disabled. Note that the feature will continue to be supported on older versions of Android as before.
///The default value is `true`.
bool saveFormData;
///Boolean value to enable third party cookies in the WebView.
@ -405,6 +400,13 @@ class AndroidInAppWebViewOptions
///The default value is `true`.
bool hardwareAcceleration;
///Sets whether the WebView whether supports multiple windows.
///If set to `true`, [onCreateWindow] event must be implemented by the host application. The default value is `false`.
bool supportMultipleWindows;
///Regular expression used by [shouldOverrideUrlLoading] event to cancel navigation for frames that are not the main frame.
String regexToCancelSubFramesLoading;
AndroidInAppWebViewOptions(
{this.textZoom = 100,
this.clearSessionCache = false,
@ -412,7 +414,7 @@ class AndroidInAppWebViewOptions
this.displayZoomControls = false,
this.supportZoom = true,
this.databaseEnabled = false,
this.domStorageEnabled = false,
this.domStorageEnabled = true,
this.useWideViewPort = true,
this.safeBrowsingEnabled = true,
this.mixedContentMode,
@ -445,7 +447,9 @@ class AndroidInAppWebViewOptions
this.saveFormData = true,
this.thirdPartyCookiesEnabled = true,
this.hardwareAcceleration = true,
this.initialScale = 0});
this.initialScale = 0,
this.supportMultipleWindows = false,
this.regexToCancelSubFramesLoading});
@override
Map<String, dynamic> toMap() {
@ -489,7 +493,9 @@ class AndroidInAppWebViewOptions
"standardFontFamily": standardFontFamily,
"saveFormData": saveFormData,
"thirdPartyCookiesEnabled": thirdPartyCookiesEnabled,
"hardwareAcceleration": hardwareAcceleration
"hardwareAcceleration": hardwareAcceleration,
"supportMultipleWindows": supportMultipleWindows,
"regexToCancelSubFramesLoading": regexToCancelSubFramesLoading
};
}
@ -542,6 +548,8 @@ class AndroidInAppWebViewOptions
options.saveFormData = map["saveFormData"];
options.thirdPartyCookiesEnabled = map["thirdPartyCookiesEnabled"];
options.hardwareAcceleration = map["hardwareAcceleration"];
options.supportMultipleWindows = map["supportMultipleWindows"];
options.regexToCancelSubFramesLoading = map["regexToCancelSubFramesLoading"];
return options;
}
}

View File

@ -1,6 +1,6 @@
name: flutter_inappwebview
description: A Flutter plugin that allows you to add an inline webview or open an in-app browser window.
version: 2.1.0+1
version: 2.2.0
author: Lorenzo Pichilli <pichillilorenzo@gmail.com>
homepage: https://github.com/pichillilorenzo/flutter_inappwebview