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>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="9b41f7a2-a71e-4923-91fb-249d7815b3e7" name="Default" comment=""> <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 afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java" 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$/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$/.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$/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/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/.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/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/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> </list>
<ignored path="$PROJECT_DIR$/.dart_tool/" /> <ignored path="$PROJECT_DIR$/.dart_tool/" />
<ignored path="$PROJECT_DIR$/.idea/" /> <ignored path="$PROJECT_DIR$/.idea/" />
@ -45,20 +103,20 @@
<file pinned="false" current-in-tab="false"> <file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/example/lib/main.dart"> <entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="480"> <state relative-caret-position="194">
<caret line="94" column="30" selection-start-line="94" selection-start-column="20" selection-end-line="94" selection-end-column="36" /> <caret line="229" column="55" selection-start-line="229" selection-start-column="26" selection-end-line="229" selection-end-column="55" />
<folding> <folding>
<element signature="e#0#20#0" expanded="true" /> <element signature="e#1907#1927#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
</file> </file>
<file pinned="false" current-in-tab="false"> <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"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="185"> <state relative-caret-position="328">
<caret line="415" column="31" selection-start-line="415" selection-start-column="15" selection-end-line="415" selection-end-column="31" /> <caret line="409" column="28" selection-start-line="409" selection-start-column="2" selection-end-line="409" selection-end-column="28" />
<folding> <folding>
<element signature="e#0#17#0" expanded="true" /> <element signature="e#0#17#0" expanded="true" />
</folding> </folding>
@ -67,32 +125,25 @@
</entry> </entry>
</file> </file>
<file pinned="false" current-in-tab="false"> <file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/android/build.gradle"> <entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart">
<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">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="142"> <state relative-caret-position="235">
<caret line="18" column="14" selection-start-line="18" selection-start-column="14" selection-end-line="18" selection-end-column="14" /> <caret line="78" column="45" selection-start-line="78" selection-start-column="15" selection-end-line="78" selection-end-column="45" />
<folding> <folding>
<element signature="e#0#39#0" expanded="true" /> <element signature="e#0#17#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
</file> </file>
<file pinned="false" current-in-tab="false"> <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"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="105"> <state relative-caret-position="100">
<caret line="7" column="4" selection-start-line="7" selection-start-column="4" selection-end-line="7" selection-end-column="65" /> <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> </state>
</provider> </provider>
</entry> </entry>
@ -100,8 +151,8 @@
<file pinned="false" current-in-tab="false"> <file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/in_app_browser.dart"> <entry file="file://$PROJECT_DIR$/lib/src/in_app_browser.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="2490"> <state relative-caret-position="209">
<caret line="176" column="39" selection-start-line="176" selection-start-column="6" selection-end-line="176" selection-end-column="39" /> <caret line="359" column="113" selection-start-line="359" selection-start-column="113" selection-end-line="359" selection-end-column="113" />
<folding> <folding>
<element signature="e#0#20#0" expanded="true" /> <element signature="e#0#20#0" expanded="true" />
</folding> </folding>
@ -109,6 +160,28 @@
</provider> </provider>
</entry> </entry>
</file> </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> </leaf>
</component> </component>
<component name="FileTemplateManagerImpl"> <component name="FileTemplateManagerImpl">
@ -121,36 +194,36 @@
</component> </component>
<component name="FindInProjectRecents"> <component name="FindInProjectRecents">
<findStrings> <findStrings>
<find>[InAppBrowser] web</find> <find>long</find>
<find>WebView</find> <find>should</find>
<find>[InAppBrowser]</find> <find>allowunivers</find>
<find>Response({</find> <find>onNavigationStateChange</find>
<find>flutter_inappbrowser</find> <find>_channel</find>
<find>InAppBrowser</find> <find>default</find>
<find>PlatformRead</find> <find>_staticChannel</find>
<find>flutterInAppBrowserPlatformReady</find> <find>defa</find>
<find>llowContentAccess</find> <find>InAppWebViewStatic</find>
<find>ppCache</find> <find>removeFromSuperview</find>
<find>onReceivedClientCertRequest</find> <find>onCall</find>
<find>a SSL</find> <find>onLoad</find>
<find>iltInZoomControls</find> <find>printCu</find>
<find>databaseEnabled</find> <find>onLoadRe</find>
<find>Cookie</find> <find>onPrint</find>
<find>\</find> <find>ontARGET</find>
<find>`shouldOverrideUrlLoading</find> <find>onCreateWindow</find>
<find>useshouldOverrideUrlLoading</find> <find>javaScriptHandlerForbiddenNames</find>
<find>initiald</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>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> </findStrings>
<replaceStrings> <replaceStrings>
<replace>activity.getPreferences(0)</replace> <replace>activity.getPreferences(0)</replace>
@ -173,13 +246,6 @@
<component name="IdeDocumentHistory"> <component name="IdeDocumentHistory">
<option name="CHANGED_PATHS"> <option name="CHANGED_PATHS">
<list> <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_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_initial_url_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_javascript_handler_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_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_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_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$/example/test_driver/in_app_webview_ssl_request_test.dart" />
<option value="$PROJECT_DIR$/ios/Classes/InAppBrowserFlutterPlugin.m" /> <option value="$PROJECT_DIR$/ios/Classes/InAppBrowserFlutterPlugin.m" />
<option value="$PROJECT_DIR$/ios/Classes/InAppWebViewFlutterPlugin.h" /> <option value="$PROJECT_DIR$/ios/Classes/InAppWebViewFlutterPlugin.h" />
@ -207,22 +272,30 @@
<option value="$PROJECT_DIR$/.git/config" /> <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$/example/test_driver/in_app_webview_on_load_error_test.dart" />
<option value="$PROJECT_DIR$/lib/src/channel_manager.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/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/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/js/main.js" />
<option value="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.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/BUG_REPORT.md" />
<option value="$PROJECT_DIR$/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.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" /> <option value="$PROJECT_DIR$/README.md" />
</list> </list>
</option> </option>
@ -250,55 +323,6 @@
<select /> <select />
</subPane> </subPane>
</pane> </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"> <pane id="AndroidView">
<subPane> <subPane>
<expand> <expand>
@ -328,6 +352,29 @@
<select /> <select />
</subPane> </subPane>
</pane> </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> </panes>
</component> </component>
<component name="PropertiesComponent"> <component name="PropertiesComponent">
@ -477,7 +524,7 @@
</todo-panel> </todo-panel>
</component> </component>
<component name="ToolWindowManager"> <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" /> <editor active="true" />
<layout> <layout>
<window_info active="true" content_ui="combo" id="Project" order="0" sideWeight="0.6177474" visible="true" weight="0.20766774" /> <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 id="Resources Explorer" order="8" />
<window_info anchor="bottom" id="Message" order="0" /> <window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Find" order="1" weight="0.32745314" /> <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="Debug" order="3" weight="0.34196892" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" /> <window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" /> <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="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="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="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="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="Messages" order="12" sideWeight="0.4968051" weight="0.33782384" />
<window_info anchor="bottom" id="Dependency Viewer" order="13" weight="0.32800853" /> <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="Theme Preview" order="7" />
<window_info anchor="right" id="Assistant" order="8" weight="0.3290735" /> <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="Palette&#9;" order="9" />
<window_info anchor="right" id="Preview" order="10" weight="0.32960597" />
</layout> </layout>
</component> </component>
<component name="UnknownFeatures"> <component name="UnknownFeatures">
@ -529,90 +577,6 @@
</ignored-roots> </ignored-roots>
</component> </component>
<component name="editorHistoryManager"> <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"> <entry file="file://$PROJECT_DIR$/ios/Classes/InAppWebViewFlutterPlugin.h">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="285"> <state relative-caret-position="285">
@ -634,16 +598,6 @@
</state> </state>
</provider> </provider>
</entry> </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"> <entry file="file://$PROJECT_DIR$/lib/src/http_auth_credentials_database.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="195"> <state relative-caret-position="195">
@ -776,81 +730,6 @@
</state> </state>
</provider> </provider>
</entry> </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"> <entry file="file://$PROJECT_DIR$/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="120"> <state relative-caret-position="120">
@ -865,26 +744,6 @@
</state> </state>
</provider> </provider>
</entry> </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"> <entry file="file://$PROJECT_DIR$/example/android/app/build.gradle">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-230" /> <state relative-caret-position="-230" />
@ -893,12 +752,214 @@
<entry file="file://$PROJECT_DIR$/example/android/build.gradle"> <entry file="file://$PROJECT_DIR$/example/android/build.gradle">
<provider selected="true" editor-type-id="text-editor" /> <provider selected="true" editor-type-id="text-editor" />
</entry> </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"> <entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="142"> <state relative-caret-position="294">
<caret line="18" column="14" selection-start-line="18" selection-start-column="14" selection-end-line="18" selection-end-column="14" /> <caret line="78" selection-start-line="78" selection-end-line="80" selection-end-column="134" />
<folding> <folding>
<element signature="e#0#39#0" expanded="true" /> <element signature="e#0#39#0" expanded="true" />
<element signature="e#0#39#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </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 ## 2.1.0+1
- Fix docs - 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. 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 ### 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! 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()`. * `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. * `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. * `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 ##### 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`. * `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`. * `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`. * `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`. * `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. * `userAgent`: Sets the user-agent for the WebView.
* `applicationNameForUserAgent`: Append to the existing user-agent. Setting userAgent will override this. * `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`. * `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`. * `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`. * `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. * `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. * `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. * `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. * `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. * `thirdPartyCookiesEnabled`: Boolean value to enable third party cookies in the WebView.
* `hardwareAcceleration`: Boolean value to enable Hardware Acceleration 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 ##### `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. * `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. * `onProgressChanged`: Event fired when the current progress of loading a page is changed.
* `onConsoleMessage`: Event fired when the InAppWebView receives a ConsoleMessage. * `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`). * `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. * `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`). * `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`. * `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). * `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. * `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. * `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`). * `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`). * `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`). * `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). * `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 ### `InAppBrowser` class
@ -495,9 +502,9 @@ class MyInAppBrowser extends InAppBrowser {
} }
@override @override
void shouldOverrideUrlLoading(String url) { void shouldOverrideUrlLoading(ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) {
print("\n\n override $url\n\n"); print("\n\n override ${shouldOverrideUrlLoadingRequest.url}\n\n");
this.webViewController.loadUrl(url: url); this.webViewController.loadUrl(url: shouldOverrideUrlLoadingRequest.url);
} }
@override @override

View File

@ -334,6 +334,14 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
result.success(false); result.success(false);
} }
break; 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: default:
result.notImplemented(); result.notImplemented();
} }

View File

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

View File

@ -6,6 +6,8 @@ import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Picture; import android.graphics.Picture;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
@ -537,4 +539,41 @@ public class InAppBrowserActivity extends AppCompatActivity {
webView.loadUrl("about:blank"); 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.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.os.Build; import android.os.Build;
import android.print.PrintAttributes;
import android.print.PrintDocumentAdapter;
import android.print.PrintManager;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -18,6 +21,8 @@ import android.webkit.WebHistoryItem;
import android.webkit.WebSettings; import android.webkit.WebSettings;
import android.webkit.WebStorage; import android.webkit.WebStorage;
import androidx.annotation.RequiresApi;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlocker; import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlocker;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerAction; import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerAction;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerHandler; import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerHandler;
@ -34,12 +39,13 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry; import io.flutter.plugin.common.PluginRegistry;
import okhttp3.OkHttpClient; 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 { final public class InAppWebView extends InputAwareWebView {
@ -57,6 +63,7 @@ final public class InAppWebView extends InputAwareWebView {
public float scale = getResources().getDisplayMetrics().density; public float scale = getResources().getDisplayMetrics().density;
int okHttpClientCacheSize = 10 * 1024 * 1024; // 10MB int okHttpClientCacheSize = 10 * 1024 * 1024; // 10MB
public ContentBlockerHandler contentBlockerHandler = new ContentBlockerHandler(); public ContentBlockerHandler contentBlockerHandler = new ContentBlockerHandler();
public Pattern regexToCancelSubFramesLoadingCompiled;
static final String consoleLogJS = "(function(console) {" + static final String consoleLogJS = "(function(console) {" +
" var oldLogs = {" + " var oldLogs = {" +
@ -84,6 +91,10 @@ final public class InAppWebView extends InputAwareWebView {
" }" + " }" +
"})(window.console);"; "})(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 platformReadyJS = "window.dispatchEvent(new Event('flutterInAppWebViewPlatformReady'));";
static final String variableForOnLoadResourceJS = "window._flutter_inappwebview_useOnLoadResource"; static final String variableForOnLoadResourceJS = "window._flutter_inappwebview_useOnLoadResource";
@ -554,7 +565,7 @@ final public class InAppWebView extends InputAwareWebView {
settings.setJavaScriptCanOpenWindowsAutomatically(options.javaScriptCanOpenWindowsAutomatically); settings.setJavaScriptCanOpenWindowsAutomatically(options.javaScriptCanOpenWindowsAutomatically);
settings.setBuiltInZoomControls(options.builtInZoomControls); settings.setBuiltInZoomControls(options.builtInZoomControls);
settings.setDisplayZoomControls(options.displayZoomControls); settings.setDisplayZoomControls(options.displayZoomControls);
settings.setSupportMultipleWindows(options.useOnTargetBlank); settings.setSupportMultipleWindows(options.supportMultipleWindows);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
settings.setSafeBrowsingEnabled(options.safeBrowsingEnabled); settings.setSafeBrowsingEnabled(options.safeBrowsingEnabled);
@ -571,7 +582,7 @@ final public class InAppWebView extends InputAwareWebView {
if (options.applicationNameForUserAgent != null && !options.applicationNameForUserAgent.isEmpty()) { if (options.applicationNameForUserAgent != null && !options.applicationNameForUserAgent.isEmpty()) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 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; String userAgentWithApplicationName = userAgent + " " + options.applicationNameForUserAgent;
settings.setUserAgentString(userAgentWithApplicationName); settings.setUserAgentString(userAgentWithApplicationName);
} }
@ -655,6 +666,9 @@ final public class InAppWebView extends InputAwareWebView {
setLayerType(View.LAYER_TYPE_HARDWARE, null); setLayerType(View.LAYER_TYPE_HARDWARE, null);
else else
setLayerType(View.LAYER_TYPE_SOFTWARE, null); setLayerType(View.LAYER_TYPE_SOFTWARE, null);
if (options.regexToCancelSubFramesLoading != null) {
regexToCancelSubFramesLoadingCompiled = Pattern.compile(options.regexToCancelSubFramesLoading);
}
contentBlockerHandler.getRuleList().clear(); contentBlockerHandler.getRuleList().clear();
for (Map<String, Map<String, Object>> contentBlocker : options.contentBlockers) { 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)) if (newOptionsMap.get("mixedContentMode") != null && !options.mixedContentMode.equals(newOptions.mixedContentMode))
settings.setMixedContentMode(newOptions.mixedContentMode); settings.setMixedContentMode(newOptions.mixedContentMode);
if (newOptionsMap.get("useOnTargetBlank") != null && options.useOnTargetBlank != newOptions.useOnTargetBlank) if (newOptionsMap.get("supportMultipleWindows") != null && options.supportMultipleWindows != newOptions.supportMultipleWindows)
settings.setSupportMultipleWindows(newOptions.useOnTargetBlank); settings.setSupportMultipleWindows(newOptions.supportMultipleWindows);
if (newOptionsMap.get("useOnDownloadStart") != null && options.useOnDownloadStart != newOptions.useOnDownloadStart) { if (newOptionsMap.get("useOnDownloadStart") != null && options.useOnDownloadStart != newOptions.useOnDownloadStart) {
if (newOptions.useOnDownloadStart) { if (newOptions.useOnDownloadStart) {
@ -1127,6 +1141,13 @@ final public class InAppWebView extends InputAwareWebView {
setLayerType(View.LAYER_TYPE_SOFTWARE, null); 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) { if (newOptions.contentBlockers != null) {
contentBlockerHandler.getRuleList().clear(); contentBlockerHandler.getRuleList().clear();
for (Map<String, Map<String, Object>> contentBlocker : newOptions.contentBlockers) { for (Map<String, Map<String, Object>> contentBlocker : newOptions.contentBlockers) {
@ -1304,6 +1325,22 @@ final public class InAppWebView extends InputAwareWebView {
webSettings.setBuiltInZoomControls(enabled); 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 @Override
public void dispose() { public void dispose() {
super.dispose(); super.dispose();

View File

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

View File

@ -1,13 +1,14 @@
package com.pichillilorenzo.flutter_inappwebview.InAppWebView; package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
import android.content.Intent; import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.net.Uri;
import android.net.http.SslCertificate; import android.net.http.SslCertificate;
import android.net.http.SslError; import android.net.http.SslError;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent;
import android.webkit.ClientCertRequest; import android.webkit.ClientCertRequest;
import android.webkit.CookieManager; import android.webkit.CookieManager;
import android.webkit.CookieSyncManager; import android.webkit.CookieSyncManager;
@ -43,6 +44,7 @@ import java.security.cert.X509Certificate;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Matcher;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
@ -51,7 +53,6 @@ public class InAppWebViewClient extends WebViewClient {
protected static final String LOG_TAG = "IABWebViewClient"; protected static final String LOG_TAG = "IABWebViewClient";
private FlutterWebView flutterWebView; private FlutterWebView flutterWebView;
private InAppBrowserActivity inAppBrowserActivity; private InAppBrowserActivity inAppBrowserActivity;
Map<Integer, String> statusCodeMapping = new HashMap<Integer, String>();
private static int previousAuthRequestFailureCount = 0; private static int previousAuthRequestFailureCount = 0;
private static List<Credential> credentialsProposed = null; private static List<Credential> credentialsProposed = null;
private String onPageStartedURL = ""; private String onPageStartedURL = "";
@ -63,72 +64,105 @@ public class InAppWebViewClient extends WebViewClient {
else if (obj instanceof FlutterWebView) else if (obj instanceof FlutterWebView)
this.flutterWebView = (FlutterWebView) obj; 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 @Override
public boolean shouldOverrideUrlLoading(WebView webView, String url) { public boolean shouldOverrideUrlLoading(WebView webView, String url) {
if (((inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView).options.useShouldOverrideUrlLoading) { if (((inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView).options.useShouldOverrideUrlLoading) {
Map<String, Object> obj = new HashMap<>(); onShouldOverrideUrlLoading(url, "GET", null,true, false, false);
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url);
getChannel().invokeMethod("shouldOverrideUrlLoading", obj);
return true; return true;
} }
return false;
}
if (url != null) { public void onShouldOverrideUrlLoading(final String url, final String method, final Map<String, String> headers, final boolean isForMainFrame, boolean hasGesture, boolean isRedirect) {
if (url.startsWith(WebView.SCHEME_TEL)) { Map<String, Object> obj = new HashMap<>();
try { if (inAppBrowserActivity != null)
Intent intent = new Intent(Intent.ACTION_DIAL); obj.put("uuid", inAppBrowserActivity.uuid);
intent.setData(Uri.parse(url)); obj.put("url", url);
((inAppBrowserActivity != null) ? inAppBrowserActivity : flutterWebView.activity).startActivity(intent); obj.put("method", method);
return true; obj.put("headers", headers);
} catch (android.content.ActivityNotFoundException e) { obj.put("isForMainFrame", isForMainFrame);
Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString()); obj.put("androidHasGesture", hasGesture);
} obj.put("androidIsRedirect", isRedirect);
} else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:") || url.startsWith("intent:")) { obj.put("iosWKNavigationType", null);
try { getChannel().invokeMethod("shouldOverrideUrlLoading", obj, new MethodChannel.Result() {
Intent intent = new Intent(Intent.ACTION_VIEW); @Override
intent.setData(Uri.parse(url)); public void success(Object response) {
((inAppBrowserActivity != null) ? inAppBrowserActivity : flutterWebView.activity).startActivity(intent); if (response != null) {
return true; Map<String, Object> responseMap = (Map<String, Object>) response;
} catch (android.content.ActivityNotFoundException e) { Integer action = (Integer) responseMap.get("action");
Log.e(LOG_TAG, "Error with " + url + ": " + e.toString()); if (action != null) {
} switch (action) {
} case 1:
// If sms:5551212?body=This is the message if (isForMainFrame) {
else if (url.startsWith("sms:")) { // There isn't any way to load an URL for a frame that is not the main frame,
try { // so call this only on main frame.
Intent intent = new Intent(Intent.ACTION_VIEW); InAppWebView webView = ((inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
// Get address webView.loadUrl(url, headers);
String address; else
int parmIndex = url.indexOf('?'); webView.loadUrl(url);
if (parmIndex == -1) { }
address = url.substring(4); return;
} else { case 0:
address = url.substring(4, parmIndex); default:
return;
// 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));
}
} }
} }
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 @Override
@ -138,7 +172,6 @@ public class InAppWebViewClient extends WebViewClient {
String js = InAppWebView.consoleLogJS.replaceAll("[\r\n]+", ""); String js = InAppWebView.consoleLogJS.replaceAll("[\r\n]+", "");
js += JavaScriptBridgeInterface.flutterInAppBroserJSClass.replaceAll("[\r\n]+", ""); js += JavaScriptBridgeInterface.flutterInAppBroserJSClass.replaceAll("[\r\n]+", "");
if (webView.options.useShouldInterceptAjaxRequest) { if (webView.options.useShouldInterceptAjaxRequest) {
js += InAppWebView.interceptAjaxRequestsJS.replaceAll("[\r\n]+", ""); js += InAppWebView.interceptAjaxRequestsJS.replaceAll("[\r\n]+", "");
} }
@ -148,6 +181,7 @@ public class InAppWebViewClient extends WebViewClient {
if (webView.options.useOnLoadResource) { if (webView.options.useOnLoadResource) {
js += InAppWebView.resourceObserverJS.replaceAll("[\r\n]+", ""); js += InAppWebView.resourceObserverJS.replaceAll("[\r\n]+", "");
} }
js += InAppWebView.printJS.replaceAll("[\r\n]+", "");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript(js, (ValueCallback<String>) null); webView.evaluateJavascript(js, (ValueCallback<String>) null);
@ -667,6 +701,11 @@ public class InAppWebViewClient extends WebViewClient {
return shouldInterceptRequest(view, url); return shouldInterceptRequest(view, url);
} }
@Override
public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
}
private MethodChannel getChannel() { private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppWebViewFlutterPlugin.inAppBrowser.channel : flutterWebView.channel; 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 useShouldOverrideUrlLoading = false;
public Boolean useOnLoadResource = false; public Boolean useOnLoadResource = false;
public Boolean useOnDownloadStart = false; public Boolean useOnDownloadStart = false;
public Boolean useOnTargetBlank = false;
public Boolean clearCache = false; public Boolean clearCache = false;
public String userAgent = ""; public String userAgent = "";
public String applicationNameForUserAgent = ""; public String applicationNameForUserAgent = "";
@ -48,7 +47,7 @@ public class InAppWebViewOptions extends Options {
public Boolean displayZoomControls = false; public Boolean displayZoomControls = false;
public Boolean supportZoom = true; public Boolean supportZoom = true;
public Boolean databaseEnabled = false; public Boolean databaseEnabled = false;
public Boolean domStorageEnabled = false; public Boolean domStorageEnabled = true;
public Boolean useWideViewPort = true; public Boolean useWideViewPort = true;
public Boolean safeBrowsingEnabled = true; public Boolean safeBrowsingEnabled = true;
public Integer mixedContentMode; public Integer mixedContentMode;
@ -82,6 +81,8 @@ public class InAppWebViewOptions extends Options {
public Boolean saveFormData = true; public Boolean saveFormData = true;
public Boolean thirdPartyCookiesEnabled = true; public Boolean thirdPartyCookiesEnabled = true;
public Boolean hardwareAcceleration = true; public Boolean hardwareAcceleration = true;
public Boolean supportMultipleWindows = false;
public String regexToCancelSubFramesLoading;
@Override @Override
public Object onParse(Map.Entry<String, Object> pair) { 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"; protected static final String LOG_TAG = "InAppWebViewFlutterPlugin";
public static InAppBrowser inAppBrowser; public static InAppBrowser inAppBrowser;
public static InAppWebViewStatic inAppWebViewStatic;
public static MyCookieManager myCookieManager; public static MyCookieManager myCookieManager;
public static CredentialDatabaseHandler credentialDatabaseHandler; public static CredentialDatabaseHandler credentialDatabaseHandler;
public static ValueCallback<Uri[]> uploadMessageArray; public static ValueCallback<Uri[]> uploadMessageArray;
@ -28,6 +29,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin {
.platformViewRegistry() .platformViewRegistry()
.registerViewFactory( .registerViewFactory(
"com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(registrar, registrar.view())); "com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(registrar, registrar.view()));
new InAppWebViewStatic(registrar);
new MyCookieManager(registrar); new MyCookieManager(registrar);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
new CredentialDatabaseHandler(registrar); new CredentialDatabaseHandler(registrar);
@ -44,6 +46,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin {
.getRegistry() .getRegistry()
.registerViewFactory( .registerViewFactory(
"com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(registrar,null)); "com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(registrar,null));
inAppWebViewStatic = new InAppWebViewStatic(registrar);
myCookieManager = new MyCookieManager(registrar); myCookieManager = new MyCookieManager(registrar);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
credentialDatabaseHandler = new CredentialDatabaseHandler(registrar); credentialDatabaseHandler = new CredentialDatabaseHandler(registrar);
@ -64,6 +67,10 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin {
credentialDatabaseHandler.dispose(); credentialDatabaseHandler.dispose();
credentialDatabaseHandler = null; credentialDatabaseHandler = null;
} }
if (inAppWebViewStatic != null) {
inAppWebViewStatic.dispose();
inAppWebViewStatic = null;
}
uploadMessageArray = 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 FlutterWebView flutterWebView;
private InAppBrowserActivity inAppBrowserActivity; 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(){});" + "var _callHandlerID = setTimeout(function(){});" +
"window." + name + "._callHandler(arguments[0], _callHandlerID, JSON.stringify(Array.prototype.slice.call(arguments, 1)));" + "window." + name + "._callHandler(arguments[0], _callHandlerID, JSON.stringify(Array.prototype.slice.call(arguments, 1)));" +
"return new Promise(function(resolve, reject) {" + "return new Promise(function(resolve, reject) {" +
@ -37,6 +252,8 @@ public class JavaScriptBridgeInterface {
@JavascriptInterface @JavascriptInterface
public void _callHandler(final String handlerName, final String _callHandlerID, String args) { 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<>(); final Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null) if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
@ -49,11 +266,13 @@ public class JavaScriptBridgeInterface {
handler.post(new Runnable() { handler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
if (handlerName.equals("onPrint") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webView.printCurrentPage();
}
getChannel().invokeMethod("onCallJsHandler", obj, new MethodChannel.Result() { getChannel().invokeMethod("onCallJsHandler", obj, new MethodChannel.Result() {
@Override @Override
public void success(Object json) { public void success(Object json) {
InAppWebView webView = (inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView;
if (webView == null) { if (webView == null) {
// The webview has already been disposed, ignore. // The webview has already been disposed, ignore.
return; return;

View File

@ -2,10 +2,9 @@
# This is a generated file; do not edit or check into version control. # This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/lorenzopichilli/flutter" export "FLUTTER_ROOT=/Users/lorenzopichilli/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example" 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 "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build/ios" export "SYMROOT=${SOURCE_ROOT}/../build/ios"
export "FLUTTER_FRAMEWORK_DIR=/Users/lorenzopichilli/flutter/bin/cache/artifacts/engine/ios" export "FLUTTER_FRAMEWORK_DIR=/Users/lorenzopichilli/flutter/bin/cache/artifacts/engine/ios"
export "FLUTTER_BUILD_NAME=1.0.0" export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1" export "FLUTTER_BUILD_NUMBER=1"
export "TRACK_WIDGET_CREATION=true"

View File

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

View File

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

View File

@ -1,11 +1,11 @@
import 'dart:async'; /*import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_inappwebview_example/chrome_safari_browser_example.screen.dart'; import 'chrome_safari_browser_example.screen.dart';
import 'package:flutter_inappwebview_example/in_app_webiew_example.screen.dart'; import 'in_app_webiew_example.screen.dart';
import 'package:flutter_inappwebview_example/in_app_browser_example.screen.dart'; import 'in_app_browser_example.screen.dart';
// InAppLocalhostServer localhostServer = new InAppLocalhostServer(); // 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_javascript_handler_test.html
- test_assets/in_app_webview_on_load_resource_custom_scheme_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_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/in_app_webview_on_js_dialog_test.html
- test_assets/css/ - test_assets/css/
- test_assets/images/ - test_assets/images/

View File

@ -4,10 +4,10 @@
<meta charset="UTF-8"> <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 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"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>InAppWebViewOnTargetBlankTest</title> <title>InAppWebViewOnCreateWindowTest</title>
</head> </head>
<body> <body>
<h1>InAppWebViewOnTargetBlankTest</h1> <h1>InAppWebViewOnCreateWindowTest</h1>
<a id="target-blank" href="https://flutter.dev/" target="_blank">target blank</a> <a id="target-blank" href="https://flutter.dev/" target="_blank">target blank</a>
<script> <script>
document.querySelector('#target-blank').click(); document.querySelector('#target-blank').click();

View File

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

View File

@ -50,8 +50,9 @@ class InAppWebViewShouldOverrideUrlLoadingTestState extends WidgetTestState {
controller.evaluateJavascript(source: "document.querySelector('#link').click();"); controller.evaluateJavascript(source: "document.querySelector('#link').click();");
} }
}, },
shouldOverrideUrlLoading: (InAppWebViewController controller, String url) { shouldOverrideUrlLoading: (InAppWebViewController controller, ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async {
controller.loadUrl(url: "https://flutter.dev/"); 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_received_http_auth_request_test.dart';
import 'in_app_webview_on_safe_browsing_hit_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_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_should_override_url_loading_test.dart';
import 'in_app_webview_ssl_request_test.dart'; import 'in_app_webview_ssl_request_test.dart';
@ -44,7 +44,7 @@ Map<String, WidgetBuilder> getTestRoutes({@required BuildContext context}) {
'/InAppWebViewShouldOverrideUrlLoadingTest': (context) => InAppWebViewShouldOverrideUrlLoadingTest(), '/InAppWebViewShouldOverrideUrlLoadingTest': (context) => InAppWebViewShouldOverrideUrlLoadingTest(),
'/InAppWebViewOnConsoleMessageTest': (context) => InAppWebViewOnConsoleMessageTest(), '/InAppWebViewOnConsoleMessageTest': (context) => InAppWebViewOnConsoleMessageTest(),
'/InAppWebViewOnDownloadStartTest': (context) => InAppWebViewOnDownloadStartTest(), '/InAppWebViewOnDownloadStartTest': (context) => InAppWebViewOnDownloadStartTest(),
'/InAppWebViewOnTargetBlankTest': (context) => InAppWebViewOnTargetBlankTest(), '/InAppWebViewOnCreateWindowTest': (context) => InAppWebViewOnCreateWindowTest(),
'/InAppWebViewOnJsDialogTest': (context) => InAppWebViewOnJsDialogTest(), '/InAppWebViewOnJsDialogTest': (context) => InAppWebViewOnJsDialogTest(),
'/InAppWebViewOnSafeBrowsingHitTest': (context) => InAppWebViewOnSafeBrowsingHitTest(), '/InAppWebViewOnSafeBrowsingHitTest': (context) => InAppWebViewOnSafeBrowsingHitTest(),
'/InAppWebViewOnReceivedHttpAuthRequestTest': (context) => InAppWebViewOnReceivedHttpAuthRequestTest(), '/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/.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/.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/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$/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/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/.pub" /> <excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/.pub" />

View File

@ -330,6 +330,20 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
} }
result(true) result(true)
break 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": case "removeFromSuperview":
webView!.removeFromSuperview() webView!.removeFromSuperview()
result(true) result(true)

View File

@ -41,6 +41,234 @@ func JSONStringify(value: Any, prettyPrinted: Bool = false) -> String {
let JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview" 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 // the message needs to be concatenated with '' in order to have the same behavior like on Android
let consoleLogJS = """ let consoleLogJS = """
(function(console) { (function(console) {
@ -71,14 +299,9 @@ let consoleLogJS = """
})(window.console); })(window.console);
""" """
let javaScriptBridgeJS = """ let printJS = """
window.\(JAVASCRIPT_BRIDGE_NAME) = {}; window.print = function() {
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler = function() { window.\(JAVASCRIPT_BRIDGE_NAME).callHandler("onPrint", window.location.href);
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;
});
} }
""" """
@ -691,6 +914,11 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
var lastScrollY: CGFloat = 0 var lastScrollY: CGFloat = 0
var isPausedTimers = false var isPausedTimers = false
var isPausedTimersCompletionHandler: (() -> Void)? 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?) { init(frame: CGRect, configuration: WKWebViewConfiguration, IABController: InAppBrowserWebViewController?, IAWController: FlutterWebViewController?) {
@ -700,6 +928,23 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
uiDelegate = self uiDelegate = self
navigationDelegate = self navigationDelegate = self
scrollView.delegate = 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) { 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) let jscriptWebkitTouchCallout = WKUserScript(source: "document.body.style.webkitTouchCallout='none';", injectionTime: .atDocumentEnd, forMainFrameOnly: true)
configuration.userContentController.addUserScript(jscriptWebkitTouchCallout) 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) let consoleLogJSScript = WKUserScript(source: consoleLogJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(consoleLogJSScript) configuration.userContentController.addUserScript(consoleLogJSScript)
configuration.userContentController.add(self, name: "consoleLog") 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: "consoleInfo")
configuration.userContentController.add(self, name: "consoleWarn") configuration.userContentController.add(self, name: "consoleWarn")
let javaScriptBridgeJSScript = WKUserScript(source: javaScriptBridgeJS, injectionTime: .atDocumentStart, forMainFrameOnly: false) let printJSScript = WKUserScript(source: printJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(javaScriptBridgeJSScript) configuration.userContentController.addUserScript(printJSScript)
configuration.userContentController.add(self, name: "callHandler")
if (options?.useOnLoadResource)! { if (options?.useOnLoadResource)! {
let resourceObserverJSScript = WKUserScript(source: resourceObserverJS, injectionTime: .atDocumentStart, forMainFrameOnly: false) let resourceObserverJSScript = WKUserScript(source: resourceObserverJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
@ -1300,46 +1551,63 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
decidePolicyFor navigationAction: WKNavigationAction, decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
let app = UIApplication.shared
if let url = navigationAction.request.url { 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)! { if activateShouldOverrideUrlLoading && (options?.useShouldOverrideUrlLoading)! {
shouldOverrideUrlLoading(url: url)
decisionHandler(.cancel) let isForMainFrame = navigationAction.targetFrame?.isMainFrame ?? false
return
} shouldOverrideUrlLoading(url: url, method: navigationAction.request.httpMethod, headers: navigationAction.request.allHTTPHeaderFields, isForMainFrame: isForMainFrame, navigationType: navigationAction.navigationType, result: { (result) -> Void in
if result is FlutterError {
// Handle phone and email links print((result as! FlutterError).message)
if url.scheme == "tel" || url.scheme == "mailto" {
if app.canOpenURL(url) {
if #available(iOS 10.0, *) {
app.open(url)
} else {
app.openURL(url)
} }
} else if (result as? NSObject) == FlutterMethodNotImplemented {
decisionHandler(.cancel) 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 return
} }
if navigationAction.navigationType == .linkActivated || navigationAction.navigationType == .backForward { updateUrlTextFieldForIABController(navigationAction: navigationAction)
currentURL = url }
if IABController != nil {
IABController!.updateUrlTextField(url: (currentURL?.absoluteString)!) if !activateShouldOverrideUrlLoading {
} activateShouldOverrideUrlLoading = true
}
} }
decisionHandler(.allow) 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, public func webView(_ webView: WKWebView,
decidePolicyFor navigationResponse: WKNavigationResponse, decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) { decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
@ -1839,6 +2107,14 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
lastScrollY = scrollView.contentOffset.y 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) { public func onLoadStart(url: String) {
var arguments: [String: Any] = ["url": url] var arguments: [String: Any] = ["url": url]
if IABController != nil { if IABController != nil {
@ -1945,23 +2221,31 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
} }
} }
public func shouldOverrideUrlLoading(url: URL) { public func shouldOverrideUrlLoading(url: URL, method: String?, headers: [String: String]?, isForMainFrame: Bool, navigationType: WKNavigationType, result: FlutterResult?) {
var arguments: [String: Any] = ["url": url.absoluteString] var arguments: [String: Any?] = [
"url": url.absoluteString,
"method": method,
"headers": headers,
"isForMainFrame": isForMainFrame,
"androidHasGesture": nil,
"androidIsRedirect": nil,
"iosWKNavigationType": navigationType.rawValue
]
if IABController != nil { if IABController != nil {
arguments["uuid"] = IABController!.uuid arguments["uuid"] = IABController!.uuid
} }
if let channel = getChannel() { 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] var arguments: [String: Any] = ["url": url.absoluteString]
if IABController != nil { if IABController != nil {
arguments["uuid"] = IABController!.uuid arguments["uuid"] = IABController!.uuid
} }
if let channel = getChannel() { 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") { if message.name.starts(with: "console") {
var messageLevel = 1 var messageLevel = 1
switch (message.name) { switch (message.name) {
case "consoleLog": case "consoleLog":
messageLevel = 1 messageLevel = 1
break; break;
case "consoleDebug": case "consoleDebug":
// on Android, console.debug is TIP // on Android, console.debug is TIP
messageLevel = 0 messageLevel = 0
break; break;
case "consoleError": case "consoleError":
messageLevel = 3 messageLevel = 3
break; break;
case "consoleInfo": case "consoleInfo":
// on Android, console.info is LOG // on Android, console.info is LOG
messageLevel = 1 messageLevel = 1
break; break;
case "consoleWarn": case "consoleWarn":
messageLevel = 2 messageLevel = 2
break; break;
default: default:
messageLevel = 1 messageLevel = 1
break; break;
} }
onConsoleMessage(message: message.body as! String, messageLevel: messageLevel) 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 body = message.body as! [String: Any]
let handlerName = body["handlerName"] as! String let handlerName = body["handlerName"] as! String
if handlerName == "onPrint" {
printCurrentPage(printCompletionHandler: nil)
}
let _callHandlerID = body["_callHandlerID"] as! Int64 let _callHandlerID = body["_callHandlerID"] as! Int64
let args = body["args"] as! String let args = body["args"] as! String
onCallJsHandler(handlerName: handlerName, _callHandlerID: _callHandlerID, args: args) onCallJsHandler(handlerName: handlerName, _callHandlerID: _callHandlerID, args: args)
@ -2180,6 +2466,27 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
isPausedTimers = false 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() { public override func removeFromSuperview() {
configuration.userContentController.removeScriptMessageHandler(forName: "consoleLog") configuration.userContentController.removeScriptMessageHandler(forName: "consoleLog")
configuration.userContentController.removeScriptMessageHandler(forName: "consoleDebug") configuration.userContentController.removeScriptMessageHandler(forName: "consoleDebug")

View File

@ -14,7 +14,6 @@ public class InAppWebViewOptions: Options {
var useShouldOverrideUrlLoading = false var useShouldOverrideUrlLoading = false
var useOnLoadResource = false var useOnLoadResource = false
var useOnDownloadStart = false var useOnDownloadStart = false
var useOnTargetBlank = false
var clearCache = false var clearCache = false
var userAgent = "" var userAgent = ""
var applicationNameForUserAgent = "" 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) SwiftFlutterPlugin.instance = SwiftFlutterPlugin(with: registrar)
registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: "com.pichillilorenzo/flutter_inappwebview") registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: "com.pichillilorenzo/flutter_inappwebview")
InAppWebViewStatic(registrar: registrar)
if #available(iOS 11.0, *) { if #available(iOS 11.0, *) {
MyCookieManager(registrar: registrar) MyCookieManager(registrar: registrar)
} else {
// Fallback on earlier versions
} }
CredentialDatabase(registrar: registrar) CredentialDatabase(registrar: registrar)
} }

View File

@ -357,10 +357,19 @@ class InAppBrowser {
///Event fired when the [InAppBrowser] webview receives a [ConsoleMessage]. ///Event fired when the [InAppBrowser] webview receives a [ConsoleMessage].
void onConsoleMessage(ConsoleMessage 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`. ///**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. ///Event fired when the [InAppBrowser] webview loads a resource.
/// ///
@ -390,12 +399,13 @@ class InAppBrowser {
Future<CustomSchemeResponse> onLoadResourceCustomScheme( Future<CustomSchemeResponse> onLoadResourceCustomScheme(
String scheme, String url) {} 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`. ///**NOTE**: on Android you need to set [AndroidInAppWebViewOptions.supportMultipleWindows] option to `true`.
void onTargetBlank(String url) {} 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. ///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. ///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( Future<PermissionRequestResponse> onPermissionRequest(
String origin, List<String> resources) {} 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 = ''}) { void throwIsAlreadyOpened({String message = ''}) {
if (this.isOpened()) { if (this.isOpened()) {
throw Exception([ throw Exception([

View File

@ -16,12 +16,14 @@ import 'types.dart';
import 'in_app_browser.dart'; import 'in_app_browser.dart';
import 'webview_options.dart'; import 'webview_options.dart';
///List of forbidden names for JavaScript handlers.
const javaScriptHandlerForbiddenNames = [ const javaScriptHandlerForbiddenNames = [
"onLoadResource", "onLoadResource",
"shouldInterceptAjaxRequest", "shouldInterceptAjaxRequest",
"onAjaxReadyStateChange", "onAjaxReadyStateChange",
"onAjaxProgress", "onAjaxProgress",
"shouldInterceptFetchRequest" "shouldInterceptFetchRequest",
"onPrint",
]; ];
///InAppWebView Widget class. ///InAppWebView Widget class.
@ -63,10 +65,18 @@ class InAppWebView extends StatefulWidget {
InAppWebViewController controller, ConsoleMessage consoleMessage) InAppWebViewController controller, ConsoleMessage consoleMessage)
onConsoleMessage; 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`. ///**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; shouldOverrideUrlLoading;
///Event fired when the [InAppWebView] loads a resource. ///Event fired when the [InAppWebView] loads a resource.
@ -101,13 +111,14 @@ class InAppWebView extends StatefulWidget {
InAppWebViewController controller, String scheme, String url) InAppWebViewController controller, String scheme, String url)
onLoadResourceCustomScheme; 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) 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. ///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. ///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) InAppWebViewController controller, FetchRequest fetchRequest)
shouldInterceptFetchRequest; 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. ///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). ///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, String origin,
List<String> resources) onPermissionRequest; 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. ///Initial url that will be loaded.
final String initialUrl; final String initialUrl;
@ -310,7 +328,7 @@ class InAppWebView extends StatefulWidget {
this.onScrollChanged, this.onScrollChanged,
this.onDownloadStart, this.onDownloadStart,
this.onLoadResourceCustomScheme, this.onLoadResourceCustomScheme,
this.onTargetBlank, this.onCreateWindow,
this.onGeolocationPermissionsShowPrompt, this.onGeolocationPermissionsShowPrompt,
this.onJsAlert, this.onJsAlert,
this.onJsConfirm, this.onJsConfirm,
@ -326,6 +344,7 @@ class InAppWebView extends StatefulWidget {
this.shouldInterceptFetchRequest, this.shouldInterceptFetchRequest,
this.onNavigationStateChange, this.onNavigationStateChange,
this.onPermissionRequest, this.onPermissionRequest,
this.onPrint,
this.gestureRecognizers, this.gestureRecognizers,
}) : super(key: key); }) : super(key: key);
@ -426,6 +445,7 @@ class _InAppWebViewState extends State<InAppWebView> {
class InAppWebViewController { class InAppWebViewController {
InAppWebView _widget; InAppWebView _widget;
MethodChannel _channel; MethodChannel _channel;
static MethodChannel _staticChannel = MethodChannel('com.pichillilorenzo/flutter_inappwebview_static');
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap = Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap =
HashMap<String, JavaScriptHandlerCallback>(); HashMap<String, JavaScriptHandlerCallback>();
// ignore: unused_field // ignore: unused_field
@ -491,10 +511,20 @@ class InAppWebViewController {
break; break;
case "shouldOverrideUrlLoading": case "shouldOverrideUrlLoading":
String url = call.arguments["url"]; 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) if (_widget != null && _widget.shouldOverrideUrlLoading != null)
_widget.shouldOverrideUrlLoading(this, url); return (await _widget.shouldOverrideUrlLoading(this, shouldOverrideUrlLoadingRequest))?.toMap();
else if (_inAppBrowser != null) else if (_inAppBrowser != null)
_inAppBrowser.shouldOverrideUrlLoading(url); return (await _inAppBrowser.shouldOverrideUrlLoading(shouldOverrideUrlLoadingRequest))?.toMap();
break; break;
case "onConsoleMessage": case "onConsoleMessage":
String message = call.arguments["message"]; String message = call.arguments["message"];
@ -543,11 +573,11 @@ class InAppWebViewController {
} }
} }
break; break;
case "onTargetBlank": case "onCreateWindow":
String url = call.arguments["url"]; String url = call.arguments["url"];
if (_widget != null && _widget.onTargetBlank != null) if (_widget != null && _widget.onCreateWindow != null)
_widget.onTargetBlank(this, url); _widget.onCreateWindow(this, url);
else if (_inAppBrowser != null) _inAppBrowser.onTargetBlank(url); else if (_inAppBrowser != null) _inAppBrowser.onCreateWindow(url);
break; break;
case "onGeolocationPermissionsShowPrompt": case "onGeolocationPermissionsShowPrompt":
String origin = call.arguments["origin"]; String origin = call.arguments["origin"];
@ -875,6 +905,13 @@ class InAppWebViewController {
return jsonEncode( return jsonEncode(
await _inAppBrowser.shouldInterceptFetchRequest(request)); await _inAppBrowser.shouldInterceptFetchRequest(request));
return null; 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)) { if (javaScriptHandlersMap.containsKey(handlerName)) {
@ -1388,6 +1425,8 @@ class InAppWebViewController {
/// }); /// });
/// """); /// """);
///``` ///```
///
///Forbidden names for JavaScript handlers are defined in [javaScriptHandlerForbiddenNames].
void addJavaScriptHandler( void addJavaScriptHandler(
{@required String handlerName, {@required String handlerName,
@required JavaScriptHandlerCallback callback}) { @required JavaScriptHandlerCallback callback}) {
@ -1729,6 +1768,24 @@ class InAppWebViewController {
await _channel.invokeMethod('resumeTimers', args); 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 { /*Future<void> dispose() async {
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
if (Platform.isIOS) if (Platform.isIOS)

View File

@ -1966,3 +1966,94 @@ class PermissionRequestResponse {
return {"resources": resources, "action": action?.toValue()}; 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`. ///Set to `true` to be able to listen at the [onDownloadStart] event. The default value is `false`.
bool useOnDownloadStart; 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`. ///Set to `true` to have all the browser's cache cleared before the new window is opened. The default value is `false`.
bool clearCache; bool clearCache;
@ -135,7 +132,6 @@ class InAppWebViewOptions
{this.useShouldOverrideUrlLoading = false, {this.useShouldOverrideUrlLoading = false,
this.useOnLoadResource = false, this.useOnLoadResource = false,
this.useOnDownloadStart = false, this.useOnDownloadStart = false,
this.useOnTargetBlank = false,
this.clearCache = false, this.clearCache = false,
this.userAgent = "", this.userAgent = "",
this.applicationNameForUserAgent = "", this.applicationNameForUserAgent = "",
@ -174,7 +170,6 @@ class InAppWebViewOptions
"useShouldOverrideUrlLoading": useShouldOverrideUrlLoading, "useShouldOverrideUrlLoading": useShouldOverrideUrlLoading,
"useOnLoadResource": useOnLoadResource, "useOnLoadResource": useOnLoadResource,
"useOnDownloadStart": useOnDownloadStart, "useOnDownloadStart": useOnDownloadStart,
"useOnTargetBlank": useOnTargetBlank,
"clearCache": clearCache, "clearCache": clearCache,
"userAgent": userAgent, "userAgent": userAgent,
"applicationNameForUserAgent": applicationNameForUserAgent, "applicationNameForUserAgent": applicationNameForUserAgent,
@ -213,7 +208,6 @@ class InAppWebViewOptions
options.useShouldOverrideUrlLoading = map["useShouldOverrideUrlLoading"]; options.useShouldOverrideUrlLoading = map["useShouldOverrideUrlLoading"];
options.useOnLoadResource = map["useOnLoadResource"]; options.useOnLoadResource = map["useOnLoadResource"];
options.useOnDownloadStart = map["useOnDownloadStart"]; options.useOnDownloadStart = map["useOnDownloadStart"];
options.useOnTargetBlank = map["useOnTargetBlank"];
options.clearCache = map["clearCache"]; options.clearCache = map["clearCache"];
options.userAgent = map["userAgent"]; options.userAgent = map["userAgent"];
options.applicationNameForUserAgent = map["applicationNameForUserAgent"]; 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`. ///Set to `true` if you want the database storage API is enabled. The default value is `false`.
bool databaseEnabled; 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; bool domStorageEnabled;
///Set to `true` if the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport. ///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. ///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. ///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; bool saveFormData;
///Boolean value to enable third party cookies in the WebView. ///Boolean value to enable third party cookies in the WebView.
@ -405,6 +400,13 @@ class AndroidInAppWebViewOptions
///The default value is `true`. ///The default value is `true`.
bool hardwareAcceleration; 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( AndroidInAppWebViewOptions(
{this.textZoom = 100, {this.textZoom = 100,
this.clearSessionCache = false, this.clearSessionCache = false,
@ -412,7 +414,7 @@ class AndroidInAppWebViewOptions
this.displayZoomControls = false, this.displayZoomControls = false,
this.supportZoom = true, this.supportZoom = true,
this.databaseEnabled = false, this.databaseEnabled = false,
this.domStorageEnabled = false, this.domStorageEnabled = true,
this.useWideViewPort = true, this.useWideViewPort = true,
this.safeBrowsingEnabled = true, this.safeBrowsingEnabled = true,
this.mixedContentMode, this.mixedContentMode,
@ -445,7 +447,9 @@ class AndroidInAppWebViewOptions
this.saveFormData = true, this.saveFormData = true,
this.thirdPartyCookiesEnabled = true, this.thirdPartyCookiesEnabled = true,
this.hardwareAcceleration = true, this.hardwareAcceleration = true,
this.initialScale = 0}); this.initialScale = 0,
this.supportMultipleWindows = false,
this.regexToCancelSubFramesLoading});
@override @override
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
@ -489,7 +493,9 @@ class AndroidInAppWebViewOptions
"standardFontFamily": standardFontFamily, "standardFontFamily": standardFontFamily,
"saveFormData": saveFormData, "saveFormData": saveFormData,
"thirdPartyCookiesEnabled": thirdPartyCookiesEnabled, "thirdPartyCookiesEnabled": thirdPartyCookiesEnabled,
"hardwareAcceleration": hardwareAcceleration "hardwareAcceleration": hardwareAcceleration,
"supportMultipleWindows": supportMultipleWindows,
"regexToCancelSubFramesLoading": regexToCancelSubFramesLoading
}; };
} }
@ -542,6 +548,8 @@ class AndroidInAppWebViewOptions
options.saveFormData = map["saveFormData"]; options.saveFormData = map["saveFormData"];
options.thirdPartyCookiesEnabled = map["thirdPartyCookiesEnabled"]; options.thirdPartyCookiesEnabled = map["thirdPartyCookiesEnabled"];
options.hardwareAcceleration = map["hardwareAcceleration"]; options.hardwareAcceleration = map["hardwareAcceleration"];
options.supportMultipleWindows = map["supportMultipleWindows"];
options.regexToCancelSubFramesLoading = map["regexToCancelSubFramesLoading"];
return options; return options;
} }
} }

View File

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