Fixed error 'java.lang.ClassCastException: cannot be cast to android.view.WindowManagerImpl' on Android when using native alert dialogs, updated README.md with Xcode version required

This commit is contained in:
Lorenzo Pichilli 2019-12-01 12:55:06 +01:00
parent a56b21282f
commit ade4480c6d
19 changed files with 1623 additions and 756 deletions

View File

@ -15,7 +15,25 @@
</component>
<component name="ChangeListManager">
<list default="true" id="9b41f7a2-a71e-4923-91fb-249d7815b3e7" name="Default" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/CHANGELOG.md" beforeDir="false" afterPath="$PROJECT_DIR$/CHANGELOG.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/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$/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/ios/Runner.xcodeproj/project.pbxproj" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Runner.xcodeproj/project.pbxproj" 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_driver/in_app_webview_on_load_error_test.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/test_driver/in_app_webview_on_load_error_test.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/channel_manager.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/channel_manager.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/chrome_safari_browser.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/chrome_safari_browser.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/content_blocker.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/content_blocker.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/cookie_manager.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/cookie_manager.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/http_auth_credentials_database.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/http_auth_credentials_database.dart" 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_localhost_server.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/in_app_localhost_server.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/in_app_webview.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/in_app_webview.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/types.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/types.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/webview_options.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/webview_options.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/pubspec.yaml" afterDir="false" />
</list>
<ignored path="$PROJECT_DIR$/.dart_tool/" />
<ignored path="$PROJECT_DIR$/.idea/" />
@ -35,12 +53,13 @@
<component name="ExecutionTargetManager" SELECTED_TARGET="Pixel_3_XL_API_24" />
<component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file pinned="false" current-in-tab="true">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="330">
<caret line="22" column="92" selection-start-line="22" selection-start-column="92" selection-end-line="22" selection-end-column="92" />
<state relative-caret-position="12735">
<caret line="849" selection-start-line="849" selection-end-line="849" />
<folding>
<element signature="e#0#20#0" expanded="true" />
<element signature="e#0#39#0" expanded="true" />
<element signature="e#0#39#0" expanded="true" />
</folding>
@ -51,33 +70,33 @@
<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="255">
<caret line="17" column="101" lean-forward="true" selection-start-line="17" selection-start-column="101" selection-end-line="17" selection-end-column="101" />
<state relative-caret-position="30">
<caret line="2" column="145" selection-start-line="2" selection-start-column="145" selection-end-line="2" selection-end-column="145" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor">
<state>
<caret column="26" selection-start-column="6" selection-end-column="26" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="235">
<caret line="1170" column="66" selection-start-line="1170" selection-start-column="66" selection-end-line="1170" selection-end-column="66" />
<state relative-caret-position="304">
<caret line="78" column="1" selection-start-line="78" selection-start-column="1" selection-end-line="78" selection-end-column="1" />
<folding>
<element signature="e#0#17#0" expanded="true" />
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$USER_HOME$/Downloads/in_app_webiew_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="345">
<caret line="33" column="57" selection-start-line="33" selection-start-column="2" selection-end-line="33" selection-end-column="57" />
</state>
</provider>
</entry>
</file>
</leaf>
</component>
<component name="FileTemplateManagerImpl">
@ -90,13 +109,6 @@
</component>
<component name="FindInProjectRecents">
<findStrings>
<find>reload</find>
<find>methods</find>
<find>class</find>
<find>HttpAuthCredentialDatabase</find>
<find>###</find>
<find>#####</find>
<find>loadFile</find>
<find>window.</find>
<find>onLoadHttpError</find>
<find>microphone</find>
@ -117,9 +129,16 @@
<find>[InAppBrowser]</find>
<find>Response({</find>
<find>flutter_inappbrowser</find>
<find>flutterInAppBrowserPlatformReady</find>
<find>InAppBrowser</find>
<find>PlatformRead</find>
<find>flutterInAppBrowserPlatformReady</find>
<find>llowContentAccess</find>
<find>ppCache</find>
<find>onReceivedClientCertRequest</find>
<find>a SSL</find>
<find>iltInZoomControls</find>
<find>databaseEnabled</find>
<find>Cookie</find>
</findStrings>
<replaceStrings>
<replace>activity.getPreferences(0)</replace>
@ -142,13 +161,10 @@
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/.github/ISSUE_TEMPLATE/BUG_REPORT.md" />
<option value="$PROJECT_DIR$/example/test_driver/app_test.dart" />
<option value="$PROJECT_DIR$/lib/src/chrome_safari_browser.dart" />
<option value="$PROJECT_DIR$/example/assets/index.html" />
<option value="$PROJECT_DIR$/lib/src/types.dart" />
<option value="$PROJECT_DIR$/example/android/app/src/main/AndroidManifest.xml" />
<option value="$PROJECT_DIR$/pubspec.yaml" />
<option value="$PROJECT_DIR$/lib/flutter_inappwebview.dart" />
<option value="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" />
<option value="$PROJECT_DIR$/example/lib/in_app_webiew_example.screen.dart" />
@ -168,7 +184,6 @@
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_on_download_start_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_on_find_result_received_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_on_js_dialog_test.dart" />
<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_http_error_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_on_load_resource_custom_scheme_test.dart" />
<option value="$PROJECT_DIR$/example/test_driver/in_app_webview_on_load_resource_test.dart" />
@ -180,23 +195,28 @@
<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$/lib/src/in_app_browser.dart" />
<option value="$PROJECT_DIR$/lib/src/webview_options.dart" />
<option value="$PROJECT_DIR$/example/pubspec.yaml" />
<option value="$PROJECT_DIR$/example/lib/main.dart" />
<option value="$PROJECT_DIR$/ios/Classes/InAppBrowserFlutterPlugin.m" />
<option value="$PROJECT_DIR$/ios/Classes/InAppWebViewFlutterPlugin.h" />
<option value="$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift" />
<option value="$PROJECT_DIR$/lib/src/in_app_webview.dart" />
<option value="$PROJECT_DIR$/lib/src/cookie_manager.dart" />
<option value="$PROJECT_DIR$/lib/src/http_auth_credentials_database.dart" />
<option value="$PROJECT_DIR$/example/test_assets/in_app_webview_initial_file_test.html" />
<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/pubspec.yaml" />
<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$/lib/src/webview_options.dart" />
<option value="$PROJECT_DIR$/lib/src/in_app_browser.dart" />
<option value="$PROJECT_DIR$/lib/src/channel_manager.dart" />
<option value="$PROJECT_DIR$/example/lib/main.dart" />
<option value="$PROJECT_DIR$/README.md" />
</list>
</option>
</component>
<component name="ProjectFrameBounds">
<component name="ProjectFrameBounds" extendedState="6">
<option name="x" value="-1" />
<option name="y" value="23" />
<option name="width" value="1920" />
<option name="height" value="1057" />
@ -248,6 +268,42 @@
<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="assets" 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="assets" type="462c0819:PsiDirectoryNode" />
<item name="images" 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="lib" 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="test_driver" 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>
@ -284,6 +340,10 @@
<property name="show.migrate.to.gradle.popup" value="false" />
</component>
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/example/assets/images" />
<recent name="$PROJECT_DIR$/android/src/main/java" />
</key>
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/example/test_driver" />
<recent name="$PROJECT_DIR$/example/test_assets" />
@ -291,10 +351,6 @@
<recent name="$PROJECT_DIR$/example/assets/images" />
<recent name="$PROJECT_DIR$/android/libs" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/example/assets/images" />
<recent name="$PROJECT_DIR$/android/src/main/java" />
</key>
</component>
<component name="RunDashboard">
<option name="ruleStates">
@ -412,8 +468,7 @@
</todo-panel>
</component>
<component name="ToolWindowManager">
<frame x="0" y="23" width="1920" height="1057" extended-state="0" />
<editor active="true" />
<frame x="-1" y="23" width="1920" height="1057" extended-state="6" />
<layout>
<window_info content_ui="combo" id="Project" order="0" sideWeight="0.6177474" visible="true" weight="0.20766774" />
<window_info id="Structure" order="1" sideWeight="0.38225257" side_tool="true" weight="0.2087327" />
@ -434,7 +489,7 @@
<window_info anchor="bottom" id="Android Profiler" order="7" show_stripe_button="false" />
<window_info anchor="bottom" id="Event Log" order="8" sideWeight="0.50532484" side_tool="true" weight="0.35751295" />
<window_info anchor="bottom" id="Version Control" order="9" />
<window_info active="true" anchor="bottom" id="Terminal" order="10" sideWeight="0.4946752" visible="true" weight="0.38860103" />
<window_info active="true" anchor="bottom" id="Terminal" order="10" sideWeight="0.4946752" visible="true" weight="0.5668394" />
<window_info anchor="bottom" id="Logcat" order="11" weight="0.32953367" />
<window_info anchor="bottom" id="Messages" order="12" sideWeight="0.4968051" weight="0.33782384" />
<window_info anchor="bottom" id="Dependency Viewer" order="13" weight="0.32800853" />
@ -464,55 +519,6 @@
</ignored-roots>
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/lib/src/content_blocker.dart">
<provider selected="true" editor-type-id="text-editor">
<state>
<folding>
<element signature="e#0#41#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/test.sh">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/types.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="570">
<caret line="1614" column="101" selection-start-line="1614" selection-start-column="70" selection-end-line="1614" selection-end-column="101" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/flutter_webview_example_android.iml">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/example/flutter_webview_example.iml">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/ios/flutter_inappwebview.podspec">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="60">
<caret line="4" column="44" selection-start-line="4" selection-start-column="44" selection-end-line="4" selection-end-column="44" />
</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="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/lib/chrome_safari_browser_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$/example/test_driver/custom_widget_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="45">
@ -562,13 +568,6 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_initial_file_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_initial_url_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
@ -611,13 +610,6 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_on_load_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_http_error_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
@ -688,32 +680,6 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_ssl_request_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-496">
<folding>
<element signature="e#1#40#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="32">
<caret line="3" column="20" selection-start-line="3" selection-start-column="20" selection-end-line="3" selection-end-column="20" />
<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="90">
<caret line="6" column="8" selection-start-line="6" selection-start-column="8" selection-end-line="6" selection-end-column="8" />
</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">
@ -721,13 +687,6 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="180">
<caret line="12" column="32" selection-start-line="12" selection-start-column="32" selection-end-line="12" selection-end-column="32" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/ios/Classes/InAppWebViewFlutterPlugin.h">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="285">
@ -742,16 +701,6 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="182">
<caret line="14" column="1" lean-forward="true" selection-start-line="14" selection-start-column="1" selection-end-line="14" selection-end-column="1" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="765">
@ -759,16 +708,6 @@
</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="1170" column="66" selection-start-line="1170" selection-start-column="66" selection-end-line="1170" selection-end-column="66" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/cookie_manager.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="180">
@ -804,31 +743,163 @@
<entry file="file://$PROJECT_DIR$/android/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<entry file="file://$PROJECT_DIR$/.git/description">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/.git/config">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="255">
<caret line="17" column="101" lean-forward="true" selection-start-line="17" selection-start-column="101" selection-end-line="17" selection-end-column="101" />
<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$/example/test_driver/in_app_webview_on_load_error_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="357">
<caret line="27" column="33" selection-start-line="27" selection-start-column="33" selection-end-line="27" selection-end-column="33" />
<folding>
<element signature="e#0#39#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/types.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="161">
<caret line="480" column="9" selection-start-line="480" selection-start-column="9" selection-end-line="480" selection-end-column="9" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity-0.4.5+6/lib/connectivity.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="75">
<caret line="11" column="5" selection-start-line="11" selection-start-column="5" selection-end-line="11" selection-end-column="5" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_ssl_request_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="367">
<caret line="52" column="22" selection-start-line="50" selection-start-column="20" selection-end-line="52" selection-end-column="22" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/test_driver/in_app_webview_initial_file_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="96">
<caret line="28" column="85" selection-start-line="28" selection-start-column="20" selection-end-line="28" selection-end-column="85" />
<folding>
<element signature="e#0#39#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="360">
<caret line="24" column="24" selection-start-line="24" selection-start-column="24" selection-end-line="24" selection-end-column="24" />
</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="161">
<caret line="105" column="30" selection-start-line="105" selection-start-column="15" selection-end-line="105" selection-end-column="30" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state>
<caret column="26" selection-start-column="6" selection-end-column="26" />
<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$/lib/src/in_app_browser.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="413">
<caret line="539" column="3" lean-forward="true" selection-start-line="539" selection-start-column="3" selection-end-line="539" selection-end-column="3" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/channel_manager.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="225">
<caret line="15" column="36" selection-start-line="15" selection-start-column="36" selection-end-line="15" selection-end-column="36" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/flutter_inappwebview.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="315">
<caret line="21" column="29" lean-forward="true" selection-start-line="21" selection-start-column="29" selection-end-line="21" selection-end-column="29" />
<folding>
<element signature="e#0#1252#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="10620">
<caret line="708" column="23" lean-forward="true" selection-start-line="708" selection-start-column="23" selection-end-line="708" selection-end-column="23" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/Downloads/in_app_webiew_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="345">
<caret line="33" column="57" selection-start-line="33" selection-start-column="2" selection-end-line="33" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="330">
<caret line="22" column="92" selection-start-line="22" selection-start-column="92" selection-end-line="22" selection-end-column="92" />
<state relative-caret-position="12735">
<caret line="849" selection-start-line="849" selection-end-line="849" />
<folding>
<element signature="e#0#20#0" expanded="true" />
<element signature="e#0#39#0" expanded="true" />
<element signature="e#0#39#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="30">
<caret line="2" column="145" selection-start-line="2" selection-start-column="145" selection-end-line="2" selection-end-column="145" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/README.md">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="304">
<caret line="78" column="1" selection-start-line="78" selection-start-column="1" selection-end-line="78" selection-end-column="1" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</component>
<component name="masterDetails">
<states>

View File

@ -1,3 +1,7 @@
## 2.0.1+1
- Fixed error "java.lang.ClassCastException: $Proxy1 cannot be cast to android.view.WindowManagerImpl" on Android when using native alert dialogs
## 2.0.1
- Added `onPermissionRequest` event. This event is 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).

View File

@ -14,7 +14,7 @@ A Flutter plugin that allows you to add an inline webview or open an in-app brow
- Dart sdk: ">=2.0.0-dev.68.0 <3.0.0"
- Flutter: ">=1.9.1+hotfix.5 <2.0.0"
- Android: `minSdkVersion 17`
- iOS: `--ios-language swift`
- iOS: `--ios-language swift`, Xcode version `>= 11`
### Note for Android
@ -440,7 +440,7 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
* `onSafeBrowsingHit`: Event fired when the webview notifies that a loading URL has been flagged by Safe Browsing (available only on Android).
* `onReceivedHttpAuthRequest`: Event fired when the WebView received an HTTP authentication request. The default behavior is to cancel the request.
* `onReceivedServerTrustAuthRequest`: Event fired when the WebView need to perform server trust authentication (certificate validation).
* `onReceivedClientCertRequest`: Notify the host application to handle a SSL client certificate request.
* `onReceivedClientCertRequest`: Notify the host application to handle an SSL client certificate request.
* `onFindResultReceived`: Event fired as find-on-page operations progress.
* `shouldInterceptAjaxRequest`: Event fired when an `XMLHttpRequest` is sent to a server.
* `onAjaxReadyStateChange`: Event fired whenever the `readyState` attribute of an `XMLHttpRequest` changes.

View File

@ -164,7 +164,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}
};
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(view.getContext(), R.style.Theme_AppCompat_Dialog_Alert);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(registrar.activeContext(), R.style.Theme_AppCompat_Dialog_Alert);
alertDialogBuilder.setMessage(alertMessage);
if (confirmButtonTitle != null && !confirmButtonTitle.isEmpty()) {
alertDialogBuilder.setPositiveButton(confirmButtonTitle, clickListener);
@ -255,7 +255,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}
};
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(view.getContext(), R.style.Theme_AppCompat_Dialog_Alert);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(registrar.activeContext(), R.style.Theme_AppCompat_Dialog_Alert);
alertDialogBuilder.setMessage(alertMessage);
if (confirmButtonTitle != null && !confirmButtonTitle.isEmpty()) {
alertDialogBuilder.setPositiveButton(confirmButtonTitle, confirmClickListener);
@ -372,7 +372,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}
};
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(view.getContext(), R.style.Theme_AppCompat_Dialog_Alert);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(registrar.activeContext(), R.style.Theme_AppCompat_Dialog_Alert);
alertDialogBuilder.setMessage(alertMessage);
if (confirmButtonTitle != null && !confirmButtonTitle.isEmpty()) {
alertDialogBuilder.setPositiveButton(confirmButtonTitle, confirmClickListener);

View File

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

View File

@ -268,6 +268,8 @@
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/Reachability/Reachability.framework",
"${BUILT_PRODUCTS_DIR}/connectivity/connectivity.framework",
"${BUILT_PRODUCTS_DIR}/flutter_downloader/flutter_downloader.framework",
"${BUILT_PRODUCTS_DIR}/flutter_inappwebview/flutter_inappwebview.framework",
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
@ -275,6 +277,8 @@
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_downloader.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_inappwebview.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",

View File

@ -22,6 +22,7 @@ dependencies:
flutter_downloader: ^1.3.2
path_provider: ^1.4.0
permission_handler: ^3.3.0
connectivity: ^0.4.5+6
flutter_inappwebview:
path: ../

View File

@ -27,7 +27,7 @@ class InAppWebViewOnLoadErrorTestState extends WidgetTestState {
Expanded(
child: Container(
child: InAppWebView(
initialUrl: "http://not-existing-domain.org/",
initialUrl: "https://not-existing-domain.org/",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions(

View File

@ -6,7 +6,8 @@ import 'package:flutter/services.dart';
import 'types.dart' show ListenerCallback;
class ChannelManager {
static const MethodChannel channel = const MethodChannel('com.pichillilorenzo/flutter_inappbrowser');
static const MethodChannel channel =
const MethodChannel('com.pichillilorenzo/flutter_inappbrowser');
static bool initialized = false;
static final listeners = HashMap<String, ListenerCallback>();
@ -16,8 +17,7 @@ class ChannelManager {
}
static void addListener(String key, ListenerCallback callback) {
if (!initialized)
init();
if (!initialized) init();
listeners.putIfAbsent(key, () => callback);
}

View File

@ -53,7 +53,11 @@ class ChromeSafariBrowser {
///[headersFallback]: The additional header of the [InAppBrowser] instance fallback to be used in the HTTP request for this URL, specified as a map from name to value.
///
///[optionsFallback]: Options used by the [InAppBrowser] instance fallback.
Future<void> open({@required String url, ChromeSafariBrowserClassOptions options, Map<String, String> headersFallback = const {}, InAppBrowserClassOptions optionsFallback}) async {
Future<void> open(
{@required String url,
ChromeSafariBrowserClassOptions options,
Map<String, String> headersFallback = const {},
InAppBrowserClassOptions optionsFallback}) async {
assert(url != null && url.isNotEmpty);
this.throwIsAlreadyOpened(message: 'Cannot open $url!');
@ -65,21 +69,33 @@ class ChromeSafariBrowser {
Map<String, dynamic> optionsFallbackMap = {};
if (optionsFallback != null) {
optionsFallbackMap.addAll(optionsFallback.inAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
optionsFallbackMap
.addAll(optionsFallback.inAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback
.inAppWebViewWidgetOptions?.inAppWebViewOptions
?.toMap() ??
{});
if (Platform.isAndroid) {
optionsFallbackMap.addAll(optionsFallback.androidInAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback.inAppWebViewWidgetOptions?.androidInAppWebViewOptions?.toMap() ?? {});
}
else if (Platform.isIOS) {
optionsFallbackMap.addAll(optionsFallback.iosInAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ?? {});
optionsFallbackMap
.addAll(optionsFallback.androidInAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback
.inAppWebViewWidgetOptions?.androidInAppWebViewOptions
?.toMap() ??
{});
} else if (Platform.isIOS) {
optionsFallbackMap
.addAll(optionsFallback.iosInAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback
.inAppWebViewWidgetOptions?.iosInAppWebViewOptions
?.toMap() ??
{});
}
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('uuidFallback', () => (browserFallback != null) ? browserFallback.uuid : '');
args.putIfAbsent('uuidFallback',
() => (browserFallback != null) ? browserFallback.uuid : '');
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headersFallback);
args.putIfAbsent('options', () => optionsMap);
@ -91,19 +107,13 @@ class ChromeSafariBrowser {
}
///Event fires when the [ChromeSafariBrowser] is opened.
void onOpened() {
}
void onOpened() {}
///Event fires when the [ChromeSafariBrowser] is loaded.
void onLoaded() {
}
void onLoaded() {}
///Event fires when the [ChromeSafariBrowser] is closed.
void onClosed() {
}
void onClosed() {}
///Returns `true` if the [ChromeSafariBrowser] instance is opened, otherwise `false`.
bool isOpened() {
@ -112,13 +122,17 @@ class ChromeSafariBrowser {
void throwIsAlreadyOpened({String message = ''}) {
if (this.isOpened()) {
throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is already opened.']);
throw Exception([
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is already opened.'
]);
}
}
void throwIsNotOpened({String message = ''}) {
if (!this.isOpened()) {
throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is not opened.']);
throw Exception([
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is not opened.'
]);
}
}
}

View File

@ -11,27 +11,22 @@ import 'types.dart';
class ContentBlocker {
///Trigger of the content blocker. The trigger tells to the WebView when to perform the corresponding action.
ContentBlockerTrigger trigger;
///Action associated to the trigger. The action tells to the WebView what to do when the trigger is matched.
ContentBlockerAction action;
ContentBlocker({@required this.trigger, @required this.action});
Map<String, Map<String, dynamic>> toMap() {
return {
"trigger": trigger.toMap(),
"action": action.toMap()
};
return {"trigger": trigger.toMap(), "action": action.toMap()};
}
static ContentBlocker fromMap(Map<dynamic, Map<dynamic, dynamic>> map) {
return ContentBlocker(
trigger: ContentBlockerTrigger.fromMap(
Map<String, dynamic>.from(map["trigger"])
),
Map<String, dynamic>.from(map["trigger"])),
action: ContentBlockerAction.fromMap(
Map<String, dynamic>.from(map["action"])
)
);
Map<String, dynamic>.from(map["action"])));
}
}
@ -42,29 +37,42 @@ class ContentBlocker {
class ContentBlockerTrigger {
///A regular expression pattern to match the URL against.
String urlFilter;
///Used only by iOS. A Boolean value. The default value is false.
bool urlFilterIsCaseSensitive;
///A list of [ContentBlockerTriggerResourceType] representing the resource types (how the browser intends to use the resource) that the rule should match.
///If not specified, the rule matches all resource types.
List<ContentBlockerTriggerResourceType> resourceType;
///A list of strings matched to a URL's domain; limits action to a list of specific domains.
///Values must be lowercase ASCII, or punycode for non-ASCII. Add * in front to match domain and subdomains. Can't be used with [ContentBlockerTrigger.unlessDomain].
List<String> ifDomain;
///A list of strings matched to a URL's domain; acts on any site except domains in a provided list.
///Values must be lowercase ASCII, or punycode for non-ASCII. Add * in front to match domain and subdomains. Can't be used with [ContentBlockerTrigger.ifDomain].
List<String> unlessDomain;
///A list of [ContentBlockerTriggerLoadType] that can include one of two mutually exclusive values. If not specified, the rule matches all load types.
List<ContentBlockerTriggerLoadType> loadType;
///A list of strings matched to the entire main document URL; limits the action to a specific list of URL patterns.
///Values must be lowercase ASCII, or punycode for non-ASCII. Can't be used with [ContentBlockerTrigger.unlessTopUrl].
List<String> ifTopUrl;
///An array of strings matched to the entire main document URL; acts on any site except URL patterns in provided list.
///Values must be lowercase ASCII, or punycode for non-ASCII. Can't be used with [ContentBlockerTrigger.ifTopUrl].
List<String> unlessTopUrl;
ContentBlockerTrigger({@required String urlFilter, bool urlFilterIsCaseSensitive = false, List<ContentBlockerTriggerResourceType> resourceType = const [],
List<String> ifDomain = const [], List<String> unlessDomain = const [], List<ContentBlockerTriggerLoadType> loadType = const [],
List<String> ifTopUrl = const [], List<String> unlessTopUrl = const []}) {
ContentBlockerTrigger(
{@required String urlFilter,
bool urlFilterIsCaseSensitive = false,
List<ContentBlockerTriggerResourceType> resourceType = const [],
List<String> ifDomain = const [],
List<String> unlessDomain = const [],
List<ContentBlockerTriggerLoadType> loadType = const [],
List<String> ifTopUrl = const [],
List<String> unlessTopUrl = const []}) {
this.urlFilter = urlFilter;
assert(this.urlFilter != null);
this.resourceType = resourceType;
@ -101,7 +109,9 @@ class ContentBlockerTrigger {
};
map.keys
.where((key) => map[key] == null || (map[key] is List && (map[key] as List).length == 0)) // filter keys
.where((key) =>
map[key] == null ||
(map[key] is List && (map[key] as List).length == 0)) // filter keys
.toList() // create a copy to avoid concurrent modifications
.forEach(map.remove);
@ -112,7 +122,8 @@ class ContentBlockerTrigger {
List<ContentBlockerTriggerResourceType> resourceType = [];
List<ContentBlockerTriggerLoadType> loadType = [];
List<String> resourceTypeStringList = List<String>.from(map["resource-type"] ?? []);
List<String> resourceTypeStringList =
List<String>.from(map["resource-type"] ?? []);
resourceTypeStringList.forEach((type) {
resourceType.add(ContentBlockerTriggerResourceType.fromValue(type));
});
@ -130,8 +141,7 @@ class ContentBlockerTrigger {
resourceType: resourceType,
loadType: loadType,
ifTopUrl: List<String>.from(map["if-top-url"] ?? []),
unlessTopUrl: List<String>.from(map["unless-top-url"] ?? [])
);
unlessTopUrl: List<String>.from(map["unless-top-url"] ?? []));
}
}
@ -143,11 +153,13 @@ class ContentBlockerTrigger {
class ContentBlockerAction {
///Type of the action.
ContentBlockerActionType type;
///If the action type is [ContentBlockerActionType.CSS_DISPLAY_NONE], then also the [selector] property is required, otherwise it is ignored.
///It specify a string that defines a selector list. Use CSS identifiers as the individual selector values, separated by commas.
String selector;
ContentBlockerAction({@required ContentBlockerActionType type, String selector}) {
ContentBlockerAction(
{@required ContentBlockerActionType type, String selector}) {
this.type = type;
assert(this.type != null);
if (this.type == ContentBlockerActionType.CSS_DISPLAY_NONE) {
@ -157,13 +169,12 @@ class ContentBlockerAction {
}
Map<String, dynamic> toMap() {
Map<String, dynamic> map = {
"type": type.toValue(),
"selector": selector
};
Map<String, dynamic> map = {"type": type.toValue(), "selector": selector};
map.keys
.where((key) => map[key] == null || (map[key] is List && (map[key] as List).length == 0)) // filter keys
.where((key) =>
map[key] == null ||
(map[key] is List && (map[key] as List).length == 0)) // filter keys
.toList() // create a copy to avoid concurrent modifications
.forEach(map.remove);
@ -173,7 +184,6 @@ class ContentBlockerAction {
static ContentBlockerAction fromMap(Map<String, dynamic> map) {
return ContentBlockerAction(
type: ContentBlockerActionType.fromValue(map["type"]),
selector: map["selector"]
);
selector: map["selector"]);
}
}

View File

@ -10,7 +10,8 @@ import 'types.dart';
///**NOTE for iOS**: available from iOS 11.0+.
class CookieManager {
static CookieManager _instance;
static const MethodChannel _channel = const MethodChannel('com.pichillilorenzo/flutter_inappwebview_cookiemanager');
static const MethodChannel _channel = const MethodChannel(
'com.pichillilorenzo/flutter_inappwebview_cookiemanager');
///Gets the cookie manager shared instance.
static CookieManager instance() {
@ -23,21 +24,22 @@ class CookieManager {
return _instance;
}
static Future<dynamic> _handleMethod(MethodCall call) async {
}
static Future<dynamic> _handleMethod(MethodCall call) async {}
///Sets a cookie for the given [url]. Any existing cookie with the same [host], [path] and [name] will be replaced with the new cookie. The cookie being set will be ignored if it is expired.
///
///The default value of [path] is `"/"`.
///If [domain] is `null`, its default value will be the domain name of [url].
Future<void> setCookie({@required String url, @required String name, @required String value,
Future<void> setCookie(
{@required String url,
@required String name,
@required String value,
String domain,
String path = "/",
int expiresDate,
int maxAge,
bool isSecure}) async {
if (domain == null)
domain = _getDomainName(url);
if (domain == null) domain = _getDomainName(url);
assert(url != null && url.isNotEmpty);
assert(name != null && name.isNotEmpty);
@ -64,17 +66,20 @@ class CookieManager {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('url', () => url);
List<dynamic> cookieListMap = await _channel.invokeMethod('getCookies', args);
List<dynamic> cookieListMap =
await _channel.invokeMethod('getCookies', args);
cookieListMap = cookieListMap.cast<Map<dynamic, dynamic>>();
List<Cookie> cookies = [];
for (var i = 0; i < cookieListMap.length; i++) {
cookies.add(Cookie(name: cookieListMap[i]["name"], value: cookieListMap[i]["value"]));
cookies.add(Cookie(
name: cookieListMap[i]["name"], value: cookieListMap[i]["value"]));
}
return cookies;
}
///Gets a cookie by its [name] for the given [url].
Future<Cookie> getCookie({@required String url, @required String name}) async {
Future<Cookie> getCookie(
{@required String url, @required String name}) async {
assert(url != null && url.isNotEmpty);
assert(name != null && name.isNotEmpty);
@ -94,9 +99,12 @@ class CookieManager {
///
///The default value of [path] is `"/"`.
///If [domain] is `null` or empty, its default value will be the domain name of [url].
Future<void> deleteCookie({@required String url, @required String name, String domain = "", String path = "/"}) async {
if (domain == null || domain.isEmpty)
domain = _getDomainName(url);
Future<void> deleteCookie(
{@required String url,
@required String name,
String domain = "",
String path = "/"}) async {
if (domain == null || domain.isEmpty) domain = _getDomainName(url);
assert(url != null && url.isNotEmpty);
assert(name != null && name.isNotEmpty);
@ -115,9 +123,9 @@ class CookieManager {
///
///The default value of [path] is `"/"`.
///If [domain] is `null` or empty, its default value will be the domain name of [url].
Future<void> deleteCookies({@required String url, String domain = "", String path = "/"}) async {
if (domain == null || domain.isEmpty)
domain = _getDomainName(url);
Future<void> deleteCookies(
{@required String url, String domain = "", String path = "/"}) async {
if (domain == null || domain.isEmpty) domain = _getDomainName(url);
assert(url != null && url.isNotEmpty);
assert(domain != null && url.isNotEmpty);
@ -139,8 +147,7 @@ class CookieManager {
String _getDomainName(String url) {
Uri uri = Uri.parse(url);
String domain = uri.host;
if (domain == null)
return "";
if (domain == null) return "";
return domain.startsWith("www.") ? domain.substring(4) : domain;
}
}

View File

@ -11,7 +11,8 @@ import 'package:flutter/services.dart';
///doesn't offer the same functionalities as iOS `URLCredentialStorage`.
class HttpAuthCredentialDatabase {
static HttpAuthCredentialDatabase _instance;
static const MethodChannel _channel = const MethodChannel('com.pichillilorenzo/flutter_inappwebview_credential_database');
static const MethodChannel _channel = const MethodChannel(
'com.pichillilorenzo/flutter_inappwebview_credential_database');
///Gets the database shared instance.
static HttpAuthCredentialDatabase instance() {
@ -24,44 +25,57 @@ class HttpAuthCredentialDatabase {
return _instance;
}
static Future<dynamic> _handleMethod(MethodCall call) async {
}
static Future<dynamic> _handleMethod(MethodCall call) async {}
///Gets a map list of all HTTP auth credentials saved.
///Each map contains the key `protectionSpace` of type [ProtectionSpace]
///and the key `credentials` of type `List<HttpAuthCredential>` that contains all the HTTP auth credentials saved for that `protectionSpace`.
Future<List<Map<String, dynamic>>> getAllAuthCredentials() async {
Map<String, dynamic> args = <String, dynamic>{};
List<dynamic> allCredentials = await _channel.invokeMethod('getAllAuthCredentials', args);
List<dynamic> allCredentials =
await _channel.invokeMethod('getAllAuthCredentials', args);
List<Map<String, dynamic>> result = [];
for (Map<dynamic, dynamic> map in allCredentials) {
Map<dynamic, dynamic> protectionSpace = map["protectionSpace"];
List<dynamic> credentials = map["credentials"];
result.add({
"protectionSpace": ProtectionSpace(host: protectionSpace["host"], protocol: protectionSpace["protocol"], realm: protectionSpace["realm"], port: protectionSpace["port"]),
"credentials": credentials.map((credential) => HttpAuthCredential(username: credential["username"], password: credential["password"])).toList()
"protectionSpace": ProtectionSpace(
host: protectionSpace["host"],
protocol: protectionSpace["protocol"],
realm: protectionSpace["realm"],
port: protectionSpace["port"]),
"credentials": credentials
.map((credential) => HttpAuthCredential(
username: credential["username"],
password: credential["password"]))
.toList()
});
}
return result;
}
///Gets all the HTTP auth credentials saved for that [protectionSpace].
Future<List<HttpAuthCredential>> getHttpAuthCredentials({@required ProtectionSpace protectionSpace}) async {
Future<List<HttpAuthCredential>> getHttpAuthCredentials(
{@required ProtectionSpace protectionSpace}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("host", () => protectionSpace.host);
args.putIfAbsent("protocol", () => protectionSpace.protocol);
args.putIfAbsent("realm", () => protectionSpace.realm);
args.putIfAbsent("port", () => protectionSpace.port);
List<dynamic> credentialList = await _channel.invokeMethod('getHttpAuthCredentials', args);
List<dynamic> credentialList =
await _channel.invokeMethod('getHttpAuthCredentials', args);
List<HttpAuthCredential> credentials = [];
for (Map<dynamic, dynamic> credential in credentialList) {
credentials.add(HttpAuthCredential(username: credential["username"], password: credential["password"]));
credentials.add(HttpAuthCredential(
username: credential["username"], password: credential["password"]));
}
return credentials;
}
///Saves an HTTP auth [credential] for that [protectionSpace].
Future<void> setHttpAuthCredential({@required ProtectionSpace protectionSpace, @required HttpAuthCredential credential}) async {
Future<void> setHttpAuthCredential(
{@required ProtectionSpace protectionSpace,
@required HttpAuthCredential credential}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("host", () => protectionSpace.host);
args.putIfAbsent("protocol", () => protectionSpace.protocol);
@ -73,7 +87,9 @@ class HttpAuthCredentialDatabase {
}
///Removes an HTTP auth [credential] for that [protectionSpace].
Future<void> removeHttpAuthCredential({@required ProtectionSpace protectionSpace, @required HttpAuthCredential credential}) async {
Future<void> removeHttpAuthCredential(
{@required ProtectionSpace protectionSpace,
@required HttpAuthCredential credential}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("host", () => protectionSpace.host);
args.putIfAbsent("protocol", () => protectionSpace.protocol);
@ -85,7 +101,8 @@ class HttpAuthCredentialDatabase {
}
///Removes all the HTTP auth credentials saved for that [protectionSpace].
Future<void> removeHttpAuthCredentials({@required ProtectionSpace protectionSpace}) async {
Future<void> removeHttpAuthCredentials(
{@required ProtectionSpace protectionSpace}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("host", () => protectionSpace.host);
args.putIfAbsent("protocol", () => protectionSpace.protocol);

View File

@ -14,10 +14,11 @@ import 'in_app_webview.dart' show InAppWebViewController;
///
///This class uses the native WebView of the platform.
class InAppBrowser {
String uuid;
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap = HashMap<String, JavaScriptHandlerCallback>();
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap =
HashMap<String, JavaScriptHandlerCallback>();
bool _isOpened = false;
/// WebView Controller that can be used to access the [InAppWebView] API.
InAppWebViewController webViewController;
@ -26,7 +27,8 @@ class InAppBrowser {
uuid = uuidGenerator.v4();
ChannelManager.addListener(uuid, handleMethod);
_isOpened = false;
webViewController = new InAppWebViewController.fromInAppBrowser(uuid, ChannelManager.channel, this);
webViewController = new InAppWebViewController.fromInAppBrowser(
uuid, ChannelManager.channel, this);
}
Future<dynamic> handleMethod(MethodCall call) async {
@ -51,21 +53,29 @@ class InAppBrowser {
///[headers]: The additional headers to be used in the HTTP request for this URL, specified as a map from name to value.
///
///[options]: Options for the [InAppBrowser].
Future<void> open({String url = "about:blank", Map<String, String> headers = const {}, InAppBrowserClassOptions options}) async {
Future<void> open(
{String url = "about:blank",
Map<String, String> headers = const {},
InAppBrowserClassOptions options}) async {
assert(url != null && url.isNotEmpty);
this.throwIsAlreadyOpened(message: 'Cannot open $url!');
Map<String, dynamic> optionsMap = {};
optionsMap.addAll(options.inAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
if (Platform.isAndroid) {
optionsMap.addAll(options.androidInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.androidInAppWebViewOptions?.toMap() ?? {});
}
else if (Platform.isIOS) {
optionsMap.addAll(options
.inAppWebViewWidgetOptions?.androidInAppWebViewOptions
?.toMap() ??
{});
} else if (Platform.isIOS) {
optionsMap.addAll(options.iosInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ??
{});
}
Map<String, dynamic> args = <String, dynamic>{};
@ -113,21 +123,29 @@ class InAppBrowser {
///[headers]: The additional headers to be used in the HTTP request for this URL, specified as a map from name to value.
///
///[options]: Options for the [InAppBrowser].
Future<void> openFile({@required String assetFilePath, Map<String, String> headers = const {}, InAppBrowserClassOptions options}) async {
Future<void> openFile(
{@required String assetFilePath,
Map<String, String> headers = const {},
InAppBrowserClassOptions options}) async {
assert(assetFilePath != null && assetFilePath.isNotEmpty);
this.throwIsAlreadyOpened(message: 'Cannot open $assetFilePath!');
Map<String, dynamic> optionsMap = {};
optionsMap.addAll(options.inAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
if (Platform.isAndroid) {
optionsMap.addAll(options.androidInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.androidInAppWebViewOptions?.toMap() ?? {});
}
else if (Platform.isIOS) {
optionsMap.addAll(options
.inAppWebViewWidgetOptions?.androidInAppWebViewOptions
?.toMap() ??
{});
} else if (Platform.isIOS) {
optionsMap.addAll(options.iosInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ??
{});
}
Map<String, dynamic> args = <String, dynamic>{};
@ -149,20 +167,30 @@ class InAppBrowser {
///The [encoding] parameter specifies the encoding of the data.
///
///The [options] parameter specifies the options for the [InAppBrowser].
Future<void> openData({@required String data, String mimeType = "text/html", String encoding = "utf8", String baseUrl = "about:blank", InAppBrowserClassOptions options}) async {
Future<void> openData(
{@required String data,
String mimeType = "text/html",
String encoding = "utf8",
String baseUrl = "about:blank",
InAppBrowserClassOptions options}) async {
assert(data != null);
Map<String, dynamic> optionsMap = {};
optionsMap.addAll(options.inAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
if (Platform.isAndroid) {
optionsMap.addAll(options.androidInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.androidInAppWebViewOptions?.toMap() ?? {});
}
else if (Platform.isIOS) {
optionsMap.addAll(options
.inAppWebViewWidgetOptions?.androidInAppWebViewOptions
?.toMap() ??
{});
} else if (Platform.isIOS) {
optionsMap.addAll(options.iosInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ??
{});
}
Map<String, dynamic> args = <String, dynamic>{};
@ -233,14 +261,19 @@ class InAppBrowser {
Map<String, dynamic> optionsMap = {};
optionsMap.addAll(options.inAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
if (Platform.isAndroid) {
optionsMap.addAll(options.androidInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.androidInAppWebViewOptions?.toMap() ?? {});
}
else if (Platform.isIOS) {
optionsMap.addAll(options
.inAppWebViewWidgetOptions?.androidInAppWebViewOptions
?.toMap() ??
{});
} else if (Platform.isIOS) {
optionsMap.addAll(options.iosInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ?? {});
optionsMap.addAll(
options.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ??
{});
}
Map<String, dynamic> args = <String, dynamic>{};
@ -257,19 +290,27 @@ class InAppBrowser {
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('optionsType', () => "InAppBrowserOptions");
InAppBrowserClassOptions inAppBrowserClassOptions = InAppBrowserClassOptions();
Map<dynamic, dynamic> options = await ChannelManager.channel.invokeMethod('getOptions', args);
InAppBrowserClassOptions inAppBrowserClassOptions =
InAppBrowserClassOptions();
Map<dynamic, dynamic> options =
await ChannelManager.channel.invokeMethod('getOptions', args);
if (options != null) {
options = options.cast<String, dynamic>();
inAppBrowserClassOptions.inAppBrowserOptions = InAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions.inAppWebViewWidgetOptions.inAppWebViewOptions = InAppWebViewOptions.fromMap(options);
inAppBrowserClassOptions.inAppBrowserOptions =
InAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions.inAppWebViewWidgetOptions.inAppWebViewOptions =
InAppWebViewOptions.fromMap(options);
if (Platform.isAndroid) {
inAppBrowserClassOptions.androidInAppBrowserOptions = AndroidInAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions.inAppWebViewWidgetOptions.androidInAppWebViewOptions = AndroidInAppWebViewOptions.fromMap(options);
}
else if (Platform.isIOS) {
inAppBrowserClassOptions.iosInAppBrowserOptions = IosInAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions.inAppWebViewWidgetOptions.iosInAppWebViewOptions = IosInAppWebViewOptions.fromMap(options);
inAppBrowserClassOptions.androidInAppBrowserOptions =
AndroidInAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions
.inAppWebViewWidgetOptions.androidInAppWebViewOptions =
AndroidInAppWebViewOptions.fromMap(options);
} else if (Platform.isIOS) {
inAppBrowserClassOptions.iosInAppBrowserOptions =
IosInAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions.inAppWebViewWidgetOptions
.iosInAppWebViewOptions = IosInAppWebViewOptions.fromMap(options);
}
}
@ -282,29 +323,19 @@ class InAppBrowser {
}
///Event fired when the [InAppBrowser] is created.
void onBrowserCreated() {
}
void onBrowserCreated() {}
///Event fired when the [InAppBrowser] window is closed.
void onExit() {
}
void onExit() {}
///Event fired when the [InAppBrowser] starts to load an [url].
void onLoadStart(String url) {
}
void onLoadStart(String url) {}
///Event fired when the [InAppBrowser] finishes loading an [url].
void onLoadStop(String url) {
}
void onLoadStop(String url) {}
///Event fired when the [InAppBrowser] encounters an error loading an [url].
void onLoadError(String url, int code, String message) {
}
void onLoadError(String url, int code, String message) {}
///Event fired when the [InAppBrowser] main page receives an HTTP error.
///
@ -315,51 +346,37 @@ class InAppBrowser {
///[description] represents the description of the HTTP error. On iOS, it is always an empty string.
///
///**NOTE**: available on Android 23+.
void onLoadHttpError(String url, int statusCode, String description) {
}
void onLoadHttpError(String url, int statusCode, String description) {}
///Event fired when the current [progress] (range 0-100) of loading a page is changed.
void onProgressChanged(int progress) {
}
void onProgressChanged(int progress) {}
///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.
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldOverrideUrlLoading] option to `true`.
void shouldOverrideUrlLoading(String url) {
}
void shouldOverrideUrlLoading(String url) {}
///Event fired when the [InAppBrowser] webview loads a resource.
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useOnLoadResource] and [InAppWebViewOptions.javaScriptEnabled] options to `true`.
void onLoadResource(LoadedResource resource) {
}
void onLoadResource(LoadedResource resource) {}
///Event fired when the [InAppBrowser] webview scrolls.
///
///[x] represents the current horizontal scroll origin in pixels.
///
///[y] represents the current vertical scroll origin in pixels.
void onScrollChanged(int x, int y) {
}
void onScrollChanged(int x, int y) {}
///Event fired when [InAppBrowser] recognizes and starts a downloadable file.
///
///[url] represents the url of the file.
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useOnDownloadStart] option to `true`.
void onDownloadStart(String url) {
}
void onDownloadStart(String url) {}
///Event fired when the [InAppBrowser] webview 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`.
///
@ -367,18 +384,15 @@ class InAppBrowser {
///
///[url] represents the url of the request.
// ignore: missing_return
Future<CustomSchemeResponse> onLoadResourceCustomScheme(String scheme, String url) {
}
Future<CustomSchemeResponse> onLoadResourceCustomScheme(
String scheme, String url) {}
///Event fired when the [InAppBrowser] webview tries to open a link with `target="_blank"`.
///
///[url] represents the url of the link.
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useOnTargetBlank] option to `true`.
void onTargetBlank(String url) {
}
void onTargetBlank(String url) {}
///Event that notifies the host application that web content from the specified origin is attempting to use the Geolocation API, but no permission state is currently set for that origin.
///Note that for applications targeting Android N and later SDKs (API level > `Build.VERSION_CODES.M`) this method is only called for requests originating from secure origins such as https.
@ -388,27 +402,22 @@ class InAppBrowser {
///
///**NOTE**: available only on Android.
// ignore: missing_return
Future<GeolocationPermissionShowPromptResponse> onGeolocationPermissionsShowPrompt (String origin) {
}
Future<GeolocationPermissionShowPromptResponse>
onGeolocationPermissionsShowPrompt(String origin) {}
///Event fired when javascript calls the `alert()` method to display an alert dialog.
///If [JsAlertResponse.handledByClient] is `true`, the webview will assume that the client will handle the dialog.
///
///[message] represents the message to be displayed in the alert dialog.
// ignore: missing_return
Future<JsAlertResponse> onJsAlert(String message) {
}
Future<JsAlertResponse> onJsAlert(String message) {}
///Event fired when javascript calls the `confirm()` method to display a confirm dialog.
///If [JsConfirmResponse.handledByClient] is `true`, the webview will assume that the client will handle the dialog.
///
///[message] represents the message to be displayed in the alert dialog.
// ignore: missing_return
Future<JsConfirmResponse> onJsConfirm(String message) {
}
Future<JsConfirmResponse> onJsConfirm(String message) {}
///Event fired when javascript calls the `prompt()` method to display a prompt dialog.
///If [JsPromptResponse.handledByClient] is `true`, the webview will assume that the client will handle the dialog.
@ -416,9 +425,7 @@ class InAppBrowser {
///[message] represents the message to be displayed in the alert dialog.
///[defaultValue] represents the default value displayed in the prompt dialog.
// ignore: missing_return
Future<JsPromptResponse> onJsPrompt(String message, String defaultValue) {
}
Future<JsPromptResponse> onJsPrompt(String message, String defaultValue) {}
///Event fired when the WebView notifies that a loading URL has been flagged by Safe Browsing.
///The default behavior is to show an interstitial to the user, with the reporting checkbox visible.
@ -429,37 +436,33 @@ class InAppBrowser {
///
///**NOTE**: available only on Android.
// ignore: missing_return
Future<SafeBrowsingResponse> onSafeBrowsingHit(String url, SafeBrowsingThreat threatType) {
}
Future<SafeBrowsingResponse> onSafeBrowsingHit(
String url, SafeBrowsingThreat threatType) {}
///Event fired when the WebView received an HTTP authentication request. The default behavior is to cancel the request.
///
///[challenge] contains data about host, port, protocol, realm, etc. as specified in the [HttpAuthChallenge].
// ignore: missing_return
Future<HttpAuthResponse> onReceivedHttpAuthRequest(HttpAuthChallenge challenge) {
}
Future<HttpAuthResponse> onReceivedHttpAuthRequest(
HttpAuthChallenge challenge) {}
///Event fired when the WebView need to perform server trust authentication (certificate validation).
///The host application must return either [ServerTrustAuthResponse] instance with [ServerTrustAuthResponseAction.CANCEL] or [ServerTrustAuthResponseAction.PROCEED].
///
///[challenge] contains data about host, port, protocol, realm, etc. as specified in the [ServerTrustChallenge].
// ignore: missing_return
Future<ServerTrustAuthResponse> onReceivedServerTrustAuthRequest(ServerTrustChallenge challenge) {
Future<ServerTrustAuthResponse> onReceivedServerTrustAuthRequest(
ServerTrustChallenge challenge) {}
}
///Notify the host application to handle a SSL client certificate request.
///Notify the host application to handle an SSL client certificate request.
///Webview stores the response in memory (for the life of the application) if [ClientCertResponseAction.PROCEED] or [ClientCertResponseAction.CANCEL]
///is called and does not call [onReceivedClientCertRequest] again for the same host and port pair.
///Note that, multiple layers in chromium network stack might be caching the responses.
///
///[challenge] contains data about host, port, protocol, realm, etc. as specified in the [ClientCertChallenge].
// ignore: missing_return
Future<ClientCertResponse> onReceivedClientCertRequest(ClientCertChallenge challenge) {
}
Future<ClientCertResponse> onReceivedClientCertRequest(
ClientCertChallenge challenge) {}
///Event fired as find-on-page operations progress.
///The listener may be notified multiple times while the operation is underway, and the numberOfMatches value should not be considered final unless [isDoneCounting] is true.
@ -469,9 +472,8 @@ class InAppBrowser {
///[numberOfMatches] represents how many matches have been found.
///
///[isDoneCounting] whether the find operation has actually completed.
void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, bool isDoneCounting) {
}
void onFindResultReceived(
int activeMatchOrdinal, int numberOfMatches, bool isDoneCounting) {}
///Event fired when an `XMLHttpRequest` is sent to a server.
///It gives the host application a chance to take control over the request before sending it.
@ -480,9 +482,7 @@ class InAppBrowser {
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptAjaxRequest] option to `true`.
// ignore: missing_return
Future<AjaxRequest> shouldInterceptAjaxRequest(AjaxRequest ajaxRequest) {
}
Future<AjaxRequest> shouldInterceptAjaxRequest(AjaxRequest ajaxRequest) {}
///Event fired whenever the `readyState` attribute of an `XMLHttpRequest` changes.
///It gives the host application a chance to abort the request.
@ -491,9 +491,7 @@ class InAppBrowser {
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptAjaxRequest] option to `true`.
// ignore: missing_return
Future<AjaxRequestAction> onAjaxReadyStateChange(AjaxRequest ajaxRequest) {
}
Future<AjaxRequestAction> onAjaxReadyStateChange(AjaxRequest ajaxRequest) {}
///Event fired as an `XMLHttpRequest` progress.
///It gives the host application a chance to abort the request.
@ -502,9 +500,7 @@ class InAppBrowser {
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptAjaxRequest] option to `true`.
// ignore: missing_return
Future<AjaxRequestAction> onAjaxProgress(AjaxRequest ajaxRequest) {
}
Future<AjaxRequestAction> onAjaxProgress(AjaxRequest ajaxRequest) {}
///Event fired when a request is sent to a server through [Fetch API](https://developer.mozilla.org/it/docs/Web/API/Fetch_API).
///It gives the host application a chance to take control over the request before sending it.
@ -513,9 +509,7 @@ class InAppBrowser {
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptFetchRequest] option to `true`.
// ignore: missing_return
Future<FetchRequest> shouldInterceptFetchRequest(FetchRequest fetchRequest) {
}
Future<FetchRequest> shouldInterceptFetchRequest(FetchRequest fetchRequest) {}
///Event fired when the navigation state of the WebView changes throught the usage of
///javascript **[History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API)** functions (`pushState()`, `replaceState()`) and `onpopstate` event.
@ -523,9 +517,7 @@ class InAppBrowser {
///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).
///
///[url] represents the new url.
void onNavigationStateChange(String url) {
}
void onNavigationStateChange(String url) {}
///Event fired when the WebView is requesting permission to access the specified resources and the permission currently isn't granted or denied.
///
@ -534,20 +526,23 @@ class InAppBrowser {
///[resources] represents the array of resources the web content wants to access.
///
///**NOTE**: available only on Android 23+.
Future<PermissionRequestResponse> onPermissionRequest(String origin, List<String> resources) {
}
// ignore: missing_return
Future<PermissionRequestResponse> onPermissionRequest(
String origin, List<String> resources) {}
void throwIsAlreadyOpened({String message = ''}) {
if (this.isOpened()) {
throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is already opened.']);
throw Exception([
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is already opened.'
]);
}
}
void throwIsNotOpened({String message = ''}) {
if (!this.isOpened()) {
throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is not opened.']);
throw Exception([
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is not opened.'
]);
}
}
}

View File

@ -8,7 +8,6 @@ import 'package:mime/mime.dart';
///
///This class allows you to create a simple server on `http://localhost:[port]/` in order to be able to load your assets file on a server. The default [port] value is `8080`.
class InAppLocalhostServer {
HttpServer _server;
int _port = 8080;
@ -28,7 +27,6 @@ class InAppLocalhostServer {
///```
///The `NSAllowsLocalNetworking` key is available since **iOS 10**.
Future<void> start() async {
if (this._server != null) {
throw Exception('Server already started on http://localhost:$_port');
}
@ -48,8 +46,7 @@ class InAppLocalhostServer {
path += (path.endsWith('/')) ? 'index.html' : '';
try {
body = (await rootBundle.load(path))
.buffer.asUint8List();
body = (await rootBundle.load(path)).buffer.asUint8List();
} catch (e) {
print(e.toString());
request.response.close();
@ -57,14 +54,17 @@ class InAppLocalhostServer {
}
var contentType = ['text', 'html'];
if (!request.requestedUri.path.endsWith('/') && request.requestedUri.pathSegments.isNotEmpty) {
var mimeType = lookupMimeType(request.requestedUri.path, headerBytes: body);
if (!request.requestedUri.path.endsWith('/') &&
request.requestedUri.pathSegments.isNotEmpty) {
var mimeType =
lookupMimeType(request.requestedUri.path, headerBytes: body);
if (mimeType != null) {
contentType = mimeType.split('/');
}
}
request.response.headers.contentType = new ContentType(contentType[0], contentType[1], charset: 'utf-8');
request.response.headers.contentType =
new ContentType(contentType[0], contentType[1], charset: 'utf-8');
request.response.add(body);
request.response.close();
});
@ -84,5 +84,4 @@ class InAppLocalhostServer {
this._server = null;
}
}
}

View File

@ -16,24 +16,31 @@ import 'types.dart';
import 'in_app_browser.dart';
import 'webview_options.dart';
const javaScriptHandlerForbiddenNames = ["onLoadResource", "shouldInterceptAjaxRequest", "onAjaxReadyStateChange", "onAjaxProgress", "shouldInterceptFetchRequest"];
const javaScriptHandlerForbiddenNames = [
"onLoadResource",
"shouldInterceptAjaxRequest",
"onAjaxReadyStateChange",
"onAjaxProgress",
"shouldInterceptFetchRequest"
];
///InAppWebView Widget class.
///
///Flutter Widget for adding an **inline native WebView** integrated in the flutter widget tree.
class InAppWebView extends StatefulWidget {
///Event fired when the [InAppWebView] is created.
final void Function(InAppWebViewController controller) onWebViewCreated;
///Event fired when the [InAppWebView] starts to load an [url].
final void Function(InAppWebViewController controller, String url) onLoadStart;
final void Function(InAppWebViewController controller, String url)
onLoadStart;
///Event fired when the [InAppWebView] finishes loading an [url].
final void Function(InAppWebViewController controller, String url) onLoadStop;
///Event fired when the [InAppWebView] encounters an error loading an [url].
final void Function(InAppWebViewController controller, String url, int code, String message) onLoadError;
final void Function(InAppWebViewController controller, String url, int code,
String message) onLoadError;
///Event fired when the [InAppWebView] main page receives an HTTP error.
///
@ -44,51 +51,63 @@ class InAppWebView extends StatefulWidget {
///[description] represents the description of the HTTP error. On iOS, it is always an empty string.
///
///**NOTE**: available on Android 23+.
final void Function(InAppWebViewController controller, String url, int statusCode, String description) onLoadHttpError;
final void Function(InAppWebViewController controller, String url,
int statusCode, String description) onLoadHttpError;
///Event fired when the current [progress] of loading a page is changed.
final void Function(InAppWebViewController controller, int progress) onProgressChanged;
final void Function(InAppWebViewController controller, int progress)
onProgressChanged;
///Event fired when the [InAppWebView] receives a [ConsoleMessage].
final void Function(InAppWebViewController controller, ConsoleMessage consoleMessage) onConsoleMessage;
final void Function(
InAppWebViewController controller, ConsoleMessage consoleMessage)
onConsoleMessage;
///Give the host application a chance to take control when a URL is about to be loaded in the current WebView.
///
///**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) shouldOverrideUrlLoading;
final void Function(InAppWebViewController controller, String url)
shouldOverrideUrlLoading;
///Event fired when the [InAppWebView] loads a resource.
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useOnLoadResource] and [InAppWebViewOptions.javaScriptEnabled] options to `true`.
final void Function(InAppWebViewController controller, LoadedResource resource) onLoadResource;
final void Function(
InAppWebViewController controller, LoadedResource resource)
onLoadResource;
///Event fired when the [InAppWebView] scrolls.
///
///[x] represents the current horizontal scroll origin in pixels.
///
///[y] represents the current vertical scroll origin in pixels.
final void Function(InAppWebViewController controller, int x, int y) onScrollChanged;
final void Function(InAppWebViewController controller, int x, int y)
onScrollChanged;
///Event fired when [InAppWebView] recognizes and starts a downloadable file.
///
///[url] represents the url of the file.
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useOnDownloadStart] option to `true`.
final void Function(InAppWebViewController controller, String url) onDownloadStart;
final void Function(InAppWebViewController controller, String url)
onDownloadStart;
///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`.
///
///[scheme] represents the scheme of the url.
///
///[url] represents the url of the request.
final Future<CustomSchemeResponse> Function(InAppWebViewController controller, String scheme, String url) onLoadResourceCustomScheme;
final Future<CustomSchemeResponse> Function(
InAppWebViewController controller, String scheme, String url)
onLoadResourceCustomScheme;
///Event fired when the [InAppWebView] tries to open a link with `target="_blank"`.
///
///[url] represents the url of the link.
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useOnTargetBlank] option to `true`.
final void Function(InAppWebViewController controller, String url) onTargetBlank;
final void Function(InAppWebViewController controller, String url)
onTargetBlank;
///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.
@ -97,19 +116,23 @@ class InAppWebView extends StatefulWidget {
///[origin] represents the origin of the web content attempting to use the Geolocation API.
///
///**NOTE**: available only on Android.
final Future<GeolocationPermissionShowPromptResponse> Function(InAppWebViewController controller, String origin) onGeolocationPermissionsShowPrompt;
final Future<GeolocationPermissionShowPromptResponse> Function(
InAppWebViewController controller, String origin)
onGeolocationPermissionsShowPrompt;
///Event fired when javascript calls the `alert()` method to display an alert dialog.
///If [JsAlertResponse.handledByClient] is `true`, the webview will assume that the client will handle the dialog.
///
///[message] represents the message to be displayed in the alert dialog.
final Future<JsAlertResponse> Function(InAppWebViewController controller, String message) onJsAlert;
final Future<JsAlertResponse> Function(
InAppWebViewController controller, String message) onJsAlert;
///Event fired when javascript calls the `confirm()` method to display a confirm dialog.
///If [JsConfirmResponse.handledByClient] is `true`, the webview will assume that the client will handle the dialog.
///
///[message] represents the message to be displayed in the alert dialog.
final Future<JsConfirmResponse> Function(InAppWebViewController controller, String message) onJsConfirm;
final Future<JsConfirmResponse> Function(
InAppWebViewController controller, String message) onJsConfirm;
///Event fired when javascript calls the `prompt()` method to display a prompt dialog.
///If [JsPromptResponse.handledByClient] is `true`, the webview will assume that the client will handle the dialog.
@ -117,7 +140,8 @@ class InAppWebView extends StatefulWidget {
///[message] represents the message to be displayed in the alert dialog.
///
///[defaultValue] represents the default value displayed in the prompt dialog.
final Future<JsPromptResponse> Function(InAppWebViewController controller, String message, String defaultValue) onJsPrompt;
final Future<JsPromptResponse> Function(InAppWebViewController controller,
String message, String defaultValue) onJsPrompt;
///Event fired when the webview notifies that a loading URL has been flagged by Safe Browsing.
///The default behavior is to show an interstitial to the user, with the reporting checkbox visible.
@ -127,26 +151,33 @@ class InAppWebView extends StatefulWidget {
///[threatType] represents the reason the resource was caught by Safe Browsing, corresponding to a [SafeBrowsingThreat].
///
///**NOTE**: available only on Android.
final Future<SafeBrowsingResponse> Function(InAppWebViewController controller, String url, SafeBrowsingThreat threatType) onSafeBrowsingHit;
final Future<SafeBrowsingResponse> Function(InAppWebViewController controller,
String url, SafeBrowsingThreat threatType) onSafeBrowsingHit;
///Event fired when the WebView received an HTTP authentication request. The default behavior is to cancel the request.
///
///[challenge] contains data about host, port, protocol, realm, etc. as specified in the [HttpAuthChallenge].
final Future<HttpAuthResponse> Function(InAppWebViewController controller, HttpAuthChallenge challenge) onReceivedHttpAuthRequest;
final Future<HttpAuthResponse> Function(
InAppWebViewController controller, HttpAuthChallenge challenge)
onReceivedHttpAuthRequest;
///Event fired when the WebView need to perform server trust authentication (certificate validation).
///The host application must return either [ServerTrustAuthResponse] instance with [ServerTrustAuthResponseAction.CANCEL] or [ServerTrustAuthResponseAction.PROCEED].
///
///[challenge] contains data about host, port, protocol, realm, etc. as specified in the [ServerTrustChallenge].
final Future<ServerTrustAuthResponse> Function(InAppWebViewController controller, ServerTrustChallenge challenge) onReceivedServerTrustAuthRequest;
final Future<ServerTrustAuthResponse> Function(
InAppWebViewController controller, ServerTrustChallenge challenge)
onReceivedServerTrustAuthRequest;
///Notify the host application to handle a SSL client certificate request.
///Notify the host application to handle an SSL client certificate request.
///Webview stores the response in memory (for the life of the application) if [ClientCertResponseAction.PROCEED] or [ClientCertResponseAction.CANCEL]
///is called and does not call [onReceivedClientCertRequest] again for the same host and port pair.
///Note that, multiple layers in chromium network stack might be caching the responses.
///
///[challenge] contains data about host, port, protocol, realm, etc. as specified in the [ClientCertChallenge].
final Future<ClientCertResponse> Function(InAppWebViewController controller, ClientCertChallenge challenge) onReceivedClientCertRequest;
final Future<ClientCertResponse> Function(
InAppWebViewController controller, ClientCertChallenge challenge)
onReceivedClientCertRequest;
///Event fired as find-on-page operations progress.
///The listener may be notified multiple times while the operation is underway, and the numberOfMatches value should not be considered final unless [isDoneCounting] is true.
@ -156,7 +187,8 @@ class InAppWebView extends StatefulWidget {
///[numberOfMatches] represents how many matches have been found.
///
///[isDoneCounting] whether the find operation has actually completed.
final void Function(InAppWebViewController controller, int activeMatchOrdinal, int numberOfMatches, bool isDoneCounting) onFindResultReceived;
final void Function(InAppWebViewController controller, int activeMatchOrdinal,
int numberOfMatches, bool isDoneCounting) onFindResultReceived;
///Event fired when an `XMLHttpRequest` is sent to a server.
///It gives the host application a chance to take control over the request before sending it.
@ -168,7 +200,9 @@ class InAppWebView extends StatefulWidget {
///can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code
///used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS but just after some milliseconds (< ~100ms).
///Inside the `window.addEventListener("flutterInAppWebViewPlatformReady")` event, the ajax requests will be intercept for sure.
final Future<AjaxRequest> Function(InAppWebViewController controller, AjaxRequest ajaxRequest) shouldInterceptAjaxRequest;
final Future<AjaxRequest> Function(
InAppWebViewController controller, AjaxRequest ajaxRequest)
shouldInterceptAjaxRequest;
///Event fired whenever the `readyState` attribute of an `XMLHttpRequest` changes.
///It gives the host application a chance to abort the request.
@ -180,7 +214,9 @@ class InAppWebView extends StatefulWidget {
///can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code
///used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS but just after some milliseconds (< ~100ms).
///Inside the `window.addEventListener("flutterInAppWebViewPlatformReady")` event, the ajax requests will be intercept for sure.
final Future<AjaxRequestAction> Function(InAppWebViewController controller, AjaxRequest ajaxRequest) onAjaxReadyStateChange;
final Future<AjaxRequestAction> Function(
InAppWebViewController controller, AjaxRequest ajaxRequest)
onAjaxReadyStateChange;
///Event fired as an `XMLHttpRequest` progress.
///It gives the host application a chance to abort the request.
@ -192,7 +228,9 @@ class InAppWebView extends StatefulWidget {
///can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code
///used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS but just after some milliseconds (< ~100ms).
///Inside the `window.addEventListener("flutterInAppWebViewPlatformReady")` event, the ajax requests will be intercept for sure.
final Future<AjaxRequestAction> Function(InAppWebViewController controller, AjaxRequest ajaxRequest) onAjaxProgress;
final Future<AjaxRequestAction> Function(
InAppWebViewController controller, AjaxRequest ajaxRequest)
onAjaxProgress;
///Event fired when a request is sent to a server through [Fetch API](https://developer.mozilla.org/it/docs/Web/API/Fetch_API).
///It gives the host application a chance to take control over the request before sending it.
@ -204,7 +242,9 @@ class InAppWebView extends StatefulWidget {
///can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code
///used to intercept fetch requests is loaded as soon as possible so it won't be instantaneous as iOS but just after some milliseconds (< ~100ms).
///Inside the `window.addEventListener("flutterInAppWebViewPlatformReady")` event, the fetch requests will be intercept for sure.
final Future<FetchRequest> Function(InAppWebViewController controller, FetchRequest fetchRequest) shouldInterceptFetchRequest;
final Future<FetchRequest> Function(
InAppWebViewController controller, FetchRequest fetchRequest)
shouldInterceptFetchRequest;
///Event fired when the navigation state of the [InAppWebView] changes throught the usage of
///javascript **[History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API)** functions (`pushState()`, `replaceState()`) and `onpopstate` event.
@ -212,7 +252,8 @@ class InAppWebView extends StatefulWidget {
///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).
///
///[url] represents the new url.
final void Function(InAppWebViewController controller, String url) onNavigationStateChange;
final void Function(InAppWebViewController controller, String url)
onNavigationStateChange;
///Event fired when the WebView is requesting permission to access the specified resources and the permission currently isn't granted or denied.
///
@ -221,18 +262,26 @@ class InAppWebView extends StatefulWidget {
///[resources] represents the array of resources the web content wants to access.
///
///**NOTE**: available only on Android 23+.
final Future<PermissionRequestResponse> Function(InAppWebViewController controller, String origin, List<String> resources) onPermissionRequest;
final Future<PermissionRequestResponse> Function(
InAppWebViewController controller,
String origin,
List<String> resources) onPermissionRequest;
///Initial url that will be loaded.
final String initialUrl;
///Initial asset file that will be loaded. See [InAppWebView.loadFile()] for explanation.
final String initialFile;
///Initial [InAppWebViewInitialData] that will be loaded.
final InAppWebViewInitialData initialData;
///Initial headers that will be used.
final Map<String, String> initialHeaders;
///Initial options that will be used.
final InAppWebViewWidgetOptions initialOptions;
/// `gestureRecognizers` specifies which gestures should be consumed by the web view.
/// It is possible for other gesture recognizers to be competing with the web view on pointer
/// events, e.g if the web view is inside a [ListView] the [ListView] will want to handle
@ -248,7 +297,7 @@ class InAppWebView extends StatefulWidget {
this.initialFile,
this.initialData,
this.initialHeaders = const {},
this.initialOptions,
@required this.initialOptions,
this.onWebViewCreated,
this.onLoadStart,
this.onLoadStop,
@ -285,17 +334,19 @@ class InAppWebView extends StatefulWidget {
}
class _InAppWebViewState extends State<InAppWebView> {
InAppWebViewController _controller;
@override
Widget build(BuildContext context) {
Map<String, dynamic> initialOptions = {};
initialOptions.addAll(widget.initialOptions.inAppWebViewOptions?.toMap() ?? {});
initialOptions
.addAll(widget.initialOptions.inAppWebViewOptions?.toMap() ?? {});
if (Platform.isAndroid)
initialOptions.addAll(widget.initialOptions.androidInAppWebViewOptions?.toMap() ?? {});
initialOptions.addAll(
widget.initialOptions.androidInAppWebViewOptions?.toMap() ?? {});
else if (Platform.isIOS)
initialOptions.addAll(widget.initialOptions.iosInAppWebViewOptions?.toMap() ?? {});
initialOptions
.addAll(widget.initialOptions.iosInAppWebViewOptions?.toMap() ?? {});
if (defaultTargetPlatform == TargetPlatform.android) {
return AndroidView(
@ -373,10 +424,10 @@ class _InAppWebViewState extends State<InAppWebView> {
/// An [InAppWebViewController] instance can be obtained by setting the [InAppWebView.onWebViewCreated]
/// callback for an [InAppWebView] widget.
class InAppWebViewController {
InAppWebView _widget;
MethodChannel _channel;
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap = HashMap<String, JavaScriptHandlerCallback>();
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap =
HashMap<String, JavaScriptHandlerCallback>();
// ignore: unused_field
bool _isOpened = false;
// ignore: unused_field
@ -384,15 +435,16 @@ class InAppWebViewController {
String _inAppBrowserUuid;
InAppBrowser _inAppBrowser;
InAppWebViewController(int id, InAppWebView widget) {
this._id = id;
this._channel = MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id');
this._channel =
MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id');
this._channel.setMethodCallHandler(handleMethod);
this._widget = widget;
}
InAppWebViewController.fromInAppBrowser(String uuid, MethodChannel channel, InAppBrowser inAppBrowser) {
InAppWebViewController.fromInAppBrowser(
String uuid, MethodChannel channel, InAppBrowser inAppBrowser) {
this._inAppBrowserUuid = uuid;
this._channel = channel;
this._inAppBrowser = inAppBrowser;
@ -404,15 +456,13 @@ class InAppWebViewController {
String url = call.arguments["url"];
if (_widget != null && _widget.onLoadStart != null)
_widget.onLoadStart(this, url);
else if (_inAppBrowser != null)
_inAppBrowser.onLoadStart(url);
else if (_inAppBrowser != null) _inAppBrowser.onLoadStart(url);
break;
case "onLoadStop":
String url = call.arguments["url"];
if (_widget != null && _widget.onLoadStop != null)
_widget.onLoadStop(this, url);
else if (_inAppBrowser != null)
_inAppBrowser.onLoadStop(url);
else if (_inAppBrowser != null) _inAppBrowser.onLoadStop(url);
break;
case "onLoadError":
String url = call.arguments["url"];
@ -448,8 +498,10 @@ class InAppWebViewController {
break;
case "onConsoleMessage":
String message = call.arguments["message"];
ConsoleMessageLevel messageLevel = ConsoleMessageLevel.fromValue(call.arguments["messageLevel"]);
ConsoleMessage consoleMessage = ConsoleMessage(message: message, messageLevel: messageLevel);
ConsoleMessageLevel messageLevel =
ConsoleMessageLevel.fromValue(call.arguments["messageLevel"]);
ConsoleMessage consoleMessage =
ConsoleMessage(message: message, messageLevel: messageLevel);
if (_widget != null && _widget.onConsoleMessage != null)
_widget.onConsoleMessage(this, consoleMessage);
else if (_inAppBrowser != null)
@ -460,22 +512,21 @@ class InAppWebViewController {
int y = call.arguments["y"];
if (_widget != null && _widget.onScrollChanged != null)
_widget.onScrollChanged(this, x, y);
else if (_inAppBrowser != null)
_inAppBrowser.onScrollChanged(x, y);
else if (_inAppBrowser != null) _inAppBrowser.onScrollChanged(x, y);
break;
case "onDownloadStart":
String url = call.arguments["url"];
if (_widget != null && _widget.onDownloadStart != null)
_widget.onDownloadStart(this, url);
else if (_inAppBrowser != null)
_inAppBrowser.onDownloadStart(url);
else if (_inAppBrowser != null) _inAppBrowser.onDownloadStart(url);
break;
case "onLoadResourceCustomScheme":
String scheme = call.arguments["scheme"];
String url = call.arguments["url"];
if (_widget != null && _widget.onLoadResourceCustomScheme != null) {
try {
var response = await _widget.onLoadResourceCustomScheme(this, scheme, url);
var response =
await _widget.onLoadResourceCustomScheme(this, scheme, url);
return (response != null) ? response.toJson() : null;
} catch (error) {
print(error);
@ -483,7 +534,8 @@ class InAppWebViewController {
}
} else if (_inAppBrowser != null) {
try {
var response = await _inAppBrowser.onLoadResourceCustomScheme(scheme, url);
var response =
await _inAppBrowser.onLoadResourceCustomScheme(scheme, url);
return (response != null) ? response.toJson() : null;
} catch (error) {
print(error);
@ -495,15 +547,19 @@ class InAppWebViewController {
String url = call.arguments["url"];
if (_widget != null && _widget.onTargetBlank != null)
_widget.onTargetBlank(this, url);
else if (_inAppBrowser != null)
_inAppBrowser.onTargetBlank(url);
else if (_inAppBrowser != null) _inAppBrowser.onTargetBlank(url);
break;
case "onGeolocationPermissionsShowPrompt":
String origin = call.arguments["origin"];
if (_widget != null && _widget.onGeolocationPermissionsShowPrompt != null)
return (await _widget.onGeolocationPermissionsShowPrompt(this, origin))?.toMap();
if (_widget != null &&
_widget.onGeolocationPermissionsShowPrompt != null)
return (await _widget.onGeolocationPermissionsShowPrompt(
this, origin))
?.toMap();
else if (_inAppBrowser != null)
return (await _inAppBrowser.onGeolocationPermissionsShowPrompt(origin))?.toMap();
return (await _inAppBrowser
.onGeolocationPermissionsShowPrompt(origin))
?.toMap();
break;
case "onJsAlert":
String message = call.arguments["message"];
@ -523,17 +579,22 @@ class InAppWebViewController {
String message = call.arguments["message"];
String defaultValue = call.arguments["defaultValue"];
if (_widget != null && _widget.onJsPrompt != null)
return (await _widget.onJsPrompt(this, message, defaultValue))?.toMap();
return (await _widget.onJsPrompt(this, message, defaultValue))
?.toMap();
else if (_inAppBrowser != null)
return (await _inAppBrowser.onJsPrompt(message, defaultValue))?.toMap();
return (await _inAppBrowser.onJsPrompt(message, defaultValue))
?.toMap();
break;
case "onSafeBrowsingHit":
String url = call.arguments["url"];
SafeBrowsingThreat threatType = SafeBrowsingThreat.fromValue(call.arguments["threatType"]);
SafeBrowsingThreat threatType =
SafeBrowsingThreat.fromValue(call.arguments["threatType"]);
if (_widget != null && _widget.onSafeBrowsingHit != null)
return (await _widget.onSafeBrowsingHit(this, url, threatType))?.toMap();
return (await _widget.onSafeBrowsingHit(this, url, threatType))
?.toMap();
else if (_inAppBrowser != null)
return (await _inAppBrowser.onSafeBrowsingHit(url, threatType))?.toMap();
return (await _inAppBrowser.onSafeBrowsingHit(url, threatType))
?.toMap();
break;
case "onReceivedHttpAuthRequest":
String host = call.arguments["host"];
@ -541,12 +602,17 @@ class InAppWebViewController {
String realm = call.arguments["realm"];
int port = call.arguments["port"];
int previousFailureCount = call.arguments["previousFailureCount"];
var protectionSpace = ProtectionSpace(host: host, protocol: protocol, realm: realm, port: port);
var challenge = HttpAuthChallenge(previousFailureCount: previousFailureCount, protectionSpace: protectionSpace);
var protectionSpace = ProtectionSpace(
host: host, protocol: protocol, realm: realm, port: port);
var challenge = HttpAuthChallenge(
previousFailureCount: previousFailureCount,
protectionSpace: protectionSpace);
if (_widget != null && _widget.onReceivedHttpAuthRequest != null)
return (await _widget.onReceivedHttpAuthRequest(this, challenge))?.toMap();
return (await _widget.onReceivedHttpAuthRequest(this, challenge))
?.toMap();
else if (_inAppBrowser != null)
return (await _inAppBrowser.onReceivedHttpAuthRequest(challenge))?.toMap();
return (await _inAppBrowser.onReceivedHttpAuthRequest(challenge))
?.toMap();
break;
case "onReceivedServerTrustAuthRequest":
String host = call.arguments["host"];
@ -556,33 +622,47 @@ class InAppWebViewController {
int error = call.arguments["error"];
String message = call.arguments["message"];
Uint8List serverCertificate = call.arguments["serverCertificate"];
var protectionSpace = ProtectionSpace(host: host, protocol: protocol, realm: realm, port: port);
var challenge = ServerTrustChallenge(protectionSpace: protectionSpace, error: error, message: message, serverCertificate: serverCertificate);
var protectionSpace = ProtectionSpace(
host: host, protocol: protocol, realm: realm, port: port);
var challenge = ServerTrustChallenge(
protectionSpace: protectionSpace,
error: error,
message: message,
serverCertificate: serverCertificate);
if (_widget != null && _widget.onReceivedServerTrustAuthRequest != null)
return (await _widget.onReceivedServerTrustAuthRequest(this, challenge))?.toMap();
return (await _widget.onReceivedServerTrustAuthRequest(
this, challenge))
?.toMap();
else if (_inAppBrowser != null)
return (await _inAppBrowser.onReceivedServerTrustAuthRequest(challenge))?.toMap();
return (await _inAppBrowser
.onReceivedServerTrustAuthRequest(challenge))
?.toMap();
break;
case "onReceivedClientCertRequest":
String host = call.arguments["host"];
String protocol = call.arguments["protocol"];
String realm = call.arguments["realm"];
int port = call.arguments["port"];
var protectionSpace = ProtectionSpace(host: host, protocol: protocol, realm: realm, port: port);
var protectionSpace = ProtectionSpace(
host: host, protocol: protocol, realm: realm, port: port);
var challenge = ClientCertChallenge(protectionSpace: protectionSpace);
if (_widget != null && _widget.onReceivedClientCertRequest != null)
return (await _widget.onReceivedClientCertRequest(this, challenge))?.toMap();
return (await _widget.onReceivedClientCertRequest(this, challenge))
?.toMap();
else if (_inAppBrowser != null)
return (await _inAppBrowser.onReceivedClientCertRequest(challenge))?.toMap();
return (await _inAppBrowser.onReceivedClientCertRequest(challenge))
?.toMap();
break;
case "onFindResultReceived":
int activeMatchOrdinal = call.arguments["activeMatchOrdinal"];
int numberOfMatches = call.arguments["numberOfMatches"];
bool isDoneCounting = call.arguments["isDoneCounting"];
if (_widget != null && _widget.onFindResultReceived != null)
_widget.onFindResultReceived(this, activeMatchOrdinal, numberOfMatches, isDoneCounting);
_widget.onFindResultReceived(
this, activeMatchOrdinal, numberOfMatches, isDoneCounting);
else if (_inAppBrowser != null)
_inAppBrowser.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting);
_inAppBrowser.onFindResultReceived(
activeMatchOrdinal, numberOfMatches, isDoneCounting);
break;
case "onNavigationStateChange":
String url = call.arguments["url"];
@ -595,9 +675,11 @@ class InAppWebViewController {
String origin = call.arguments["origin"];
List<String> resources = call.arguments["resources"].cast<String>();
if (_widget != null && _widget.onPermissionRequest != null)
return (await _widget.onPermissionRequest(this, origin, resources))?.toMap();
return (await _widget.onPermissionRequest(this, origin, resources))
?.toMap();
else if (_inAppBrowser != null)
return (await _inAppBrowser.onPermissionRequest(origin, resources))?.toMap();
return (await _inAppBrowser.onPermissionRequest(origin, resources))
?.toMap();
break;
case "onCallJsHandler":
String handlerName = call.arguments["handlerName"];
@ -609,10 +691,18 @@ class InAppWebViewController {
Map<dynamic, dynamic> argMap = args[0];
String initiatorType = argMap["initiatorType"];
String url = argMap["name"];
double startTime = argMap["startTime"] is int ? argMap["startTime"].toDouble() : argMap["startTime"];
double duration = argMap["duration"] is int ? argMap["duration"].toDouble() : argMap["duration"];
double startTime = argMap["startTime"] is int
? argMap["startTime"].toDouble()
: argMap["startTime"];
double duration = argMap["duration"] is int
? argMap["duration"].toDouble()
: argMap["duration"];
var response = new LoadedResource(initiatorType: initiatorType, url: url, startTime: startTime, duration: duration);
var response = new LoadedResource(
initiatorType: initiatorType,
url: url,
startTime: startTime,
duration: duration);
if (_widget != null && _widget.onLoadResource != null)
_widget.onLoadResource(this, response);
@ -631,12 +721,23 @@ class InAppWebViewController {
AjaxRequestHeaders headers = AjaxRequestHeaders(argMap["headers"]);
String responseType = argMap["responseType"];
var request = new AjaxRequest(data: data, method: method, url: url, isAsync: isAsync, user: user, password: password, withCredentials: withCredentials, headers: headers, responseType: responseType);
var request = new AjaxRequest(
data: data,
method: method,
url: url,
isAsync: isAsync,
user: user,
password: password,
withCredentials: withCredentials,
headers: headers,
responseType: responseType);
if (_widget != null && _widget.shouldInterceptAjaxRequest != null)
return jsonEncode(await _widget.shouldInterceptAjaxRequest(this, request));
return jsonEncode(
await _widget.shouldInterceptAjaxRequest(this, request));
else if (_inAppBrowser != null)
return jsonEncode(await _inAppBrowser.shouldInterceptAjaxRequest(request));
return jsonEncode(
await _inAppBrowser.shouldInterceptAjaxRequest(request));
return null;
case "onAjaxReadyStateChange":
Map<dynamic, dynamic> argMap = args[0];
@ -658,14 +759,31 @@ class InAppWebViewController {
String statusText = argMap["statusText"];
Map<dynamic, dynamic> responseHeaders = argMap["responseHeaders"];
var request = new AjaxRequest(data: data, method: method, url: url, isAsync: isAsync, user: user, password: password,
withCredentials: withCredentials, headers: headers, readyState: AjaxRequestReadyState.fromValue(readyState), status: status, responseURL: responseURL,
responseType: responseType, response: response, responseText: responseText, responseXML: responseXML, statusText: statusText, responseHeaders: responseHeaders);
var request = new AjaxRequest(
data: data,
method: method,
url: url,
isAsync: isAsync,
user: user,
password: password,
withCredentials: withCredentials,
headers: headers,
readyState: AjaxRequestReadyState.fromValue(readyState),
status: status,
responseURL: responseURL,
responseType: responseType,
response: response,
responseText: responseText,
responseXML: responseXML,
statusText: statusText,
responseHeaders: responseHeaders);
if (_widget != null && _widget.onAjaxReadyStateChange != null)
return jsonEncode(await _widget.onAjaxReadyStateChange(this, request));
return jsonEncode(
await _widget.onAjaxReadyStateChange(this, request));
else if (_inAppBrowser != null)
return jsonEncode(await _inAppBrowser.onAjaxReadyStateChange(request));
return jsonEncode(
await _inAppBrowser.onAjaxReadyStateChange(request));
return null;
case "onAjaxProgress":
Map<dynamic, dynamic> argMap = args[0];
@ -688,11 +806,31 @@ class InAppWebViewController {
Map<dynamic, dynamic> responseHeaders = argMap["responseHeaders"];
Map<dynamic, dynamic> eventMap = argMap["event"];
AjaxRequestEvent event = AjaxRequestEvent(lengthComputable: eventMap["lengthComputable"], loaded: eventMap["loaded"], total: eventMap["total"], type: AjaxRequestEventType.fromValue(eventMap["type"]));
AjaxRequestEvent event = AjaxRequestEvent(
lengthComputable: eventMap["lengthComputable"],
loaded: eventMap["loaded"],
total: eventMap["total"],
type: AjaxRequestEventType.fromValue(eventMap["type"]));
var request = new AjaxRequest(data: data, method: method, url: url, isAsync: isAsync, user: user, password: password,
withCredentials: withCredentials, headers: headers, readyState: AjaxRequestReadyState.fromValue(readyState), status: status, responseURL: responseURL,
responseType: responseType, response: response, responseText: responseText, responseXML: responseXML, statusText: statusText, responseHeaders: responseHeaders, event: event);
var request = new AjaxRequest(
data: data,
method: method,
url: url,
isAsync: isAsync,
user: user,
password: password,
withCredentials: withCredentials,
headers: headers,
readyState: AjaxRequestReadyState.fromValue(readyState),
status: status,
responseURL: responseURL,
responseType: responseType,
response: response,
responseText: responseText,
responseXML: responseXML,
statusText: statusText,
responseHeaders: responseHeaders,
event: event);
if (_widget != null && _widget.onAjaxProgress != null)
return jsonEncode(await _widget.onAjaxProgress(this, request));
@ -706,7 +844,9 @@ class InAppWebViewController {
Map<dynamic, dynamic> headers = argMap["headers"];
Uint8List body = Uint8List.fromList(argMap["body"].cast<int>());
String mode = argMap["mode"];
FetchRequestCredential credentials = FetchRequest.createFetchRequestCredentialFromMap(argMap["credentials"]);
FetchRequestCredential credentials =
FetchRequest.createFetchRequestCredentialFromMap(
argMap["credentials"]);
String cache = argMap["cache"];
String redirect = argMap["redirect"];
String referrer = argMap["referrer"];
@ -714,13 +854,26 @@ class InAppWebViewController {
String integrity = argMap["integrity"];
bool keepalive = argMap["keepalive"];
var request = new FetchRequest(url: url, method: method, headers: headers, body: body, mode: mode, credentials: credentials,
cache: cache, redirect: redirect, referrer: referrer, referrerPolicy: referrerPolicy, integrity: integrity, keepalive: keepalive);
var request = new FetchRequest(
url: url,
method: method,
headers: headers,
body: body,
mode: mode,
credentials: credentials,
cache: cache,
redirect: redirect,
referrer: referrer,
referrerPolicy: referrerPolicy,
integrity: integrity,
keepalive: keepalive);
if (_widget != null && _widget.shouldInterceptFetchRequest != null)
return jsonEncode(await _widget.shouldInterceptFetchRequest(this, request));
return jsonEncode(
await _widget.shouldInterceptFetchRequest(this, request));
else if (_inAppBrowser != null)
return jsonEncode(await _inAppBrowser.shouldInterceptFetchRequest(request));
return jsonEncode(
await _inAppBrowser.shouldInterceptFetchRequest(request));
return null;
}
@ -777,10 +930,11 @@ class InAppWebViewController {
Future<String> getHtml() async {
var html = "";
InAppWebViewWidgetOptions options = await getOptions();
if (options != null && options.inAppWebViewOptions.javaScriptEnabled == true) {
html = await evaluateJavascript(source: "window.document.getElementsByTagName('html')[0].outerHTML;");
if (html != null && html.isNotEmpty)
return html;
if (options != null &&
options.inAppWebViewOptions.javaScriptEnabled == true) {
html = await evaluateJavascript(
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
if (html != null && html.isNotEmpty) return html;
}
var webviewUrl = await getUrl();
@ -789,13 +943,13 @@ class InAppWebViewController {
var assetPath = assetPathSplitted[assetPathSplitted.length - 1];
var bytes = await rootBundle.load(assetPath);
html = utf8.decode(bytes.buffer.asUint8List());
}
else {
} else {
HttpClient client = new HttpClient();
var url = Uri.parse(webviewUrl);
try {
var htmlRequest = await client.getUrl(url);
html = await (await htmlRequest.close()).transform(Utf8Decoder()).join();
html =
await (await htmlRequest.close()).transform(Utf8Decoder()).join();
} catch (e) {
print(e);
}
@ -809,7 +963,9 @@ class InAppWebViewController {
HttpClient client = new HttpClient();
var webviewUrl = await getUrl();
var url = (webviewUrl.startsWith("file:///")) ? Uri.file(webviewUrl) : Uri.parse(webviewUrl);
var url = (webviewUrl.startsWith("file:///"))
? Uri.file(webviewUrl)
: Uri.parse(webviewUrl);
String manifestUrl;
var html = await getHtml();
@ -835,14 +991,18 @@ class InAppWebViewController {
if (manifestUrl.startsWith("/")) {
manifestUrl = manifestUrl.substring(1);
}
manifestUrl = ((assetPathBase == null) ? url.scheme + "://" + url.host + "/" : assetPathBase) + manifestUrl;
manifestUrl = ((assetPathBase == null)
? url.scheme + "://" + url.host + "/"
: assetPathBase) +
manifestUrl;
}
continue;
}
if (!attributes["rel"].contains("icon")) {
continue;
}
favicons.addAll(_createFavicons(url, assetPathBase, attributes["href"], attributes["rel"], attributes["sizes"], false));
favicons.addAll(_createFavicons(url, assetPathBase, attributes["href"],
attributes["rel"], attributes["sizes"], false));
}
// try to get /favicon.ico
@ -864,16 +1024,19 @@ class InAppWebViewController {
try {
manifestRequest = await client.getUrl(Uri.parse(manifestUrl));
manifestResponse = await manifestRequest.close();
manifestFound = manifestResponse.statusCode == 200 && manifestResponse.headers.contentType?.mimeType == "application/json";
manifestFound = manifestResponse.statusCode == 200 &&
manifestResponse.headers.contentType?.mimeType == "application/json";
} catch (e) {
print("Manifest file not found: " + e.toString());
}
if (manifestFound) {
Map<String, dynamic> manifest = json.decode(await manifestResponse.transform(Utf8Decoder()).join());
Map<String, dynamic> manifest =
json.decode(await manifestResponse.transform(Utf8Decoder()).join());
if (manifest.containsKey("icons")) {
for (Map<String, dynamic> icon in manifest["icons"]) {
favicons.addAll(_createFavicons(url, assetPathBase, icon["src"], icon["rel"], icon["sizes"], true));
favicons.addAll(_createFavicons(url, assetPathBase, icon["src"],
icon["rel"], icon["sizes"], true));
}
}
}
@ -885,7 +1048,8 @@ class InAppWebViewController {
return url.startsWith("http://") || url.startsWith("https://");
}
List<Favicon> _createFavicons(Uri url, String assetPathBase, String urlIcon, String rel, String sizes, bool isManifest) {
List<Favicon> _createFavicons(Uri url, String assetPathBase, String urlIcon,
String rel, String sizes, bool isManifest) {
List<Favicon> favicons = [];
List<String> urlSplitted = urlIcon.split("/");
@ -893,17 +1057,26 @@ class InAppWebViewController {
if (urlIcon.startsWith("/")) {
urlIcon = urlIcon.substring(1);
}
urlIcon = ((assetPathBase == null) ? url.scheme + "://" + url.host + "/" : assetPathBase) + urlIcon;
urlIcon = ((assetPathBase == null)
? url.scheme + "://" + url.host + "/"
: assetPathBase) +
urlIcon;
}
if (isManifest) {
rel = (sizes != null) ? urlSplitted[urlSplitted.length - 1].replaceFirst("-" + sizes, "").split(" ")[0].split(".")[0] : null;
rel = (sizes != null)
? urlSplitted[urlSplitted.length - 1]
.replaceFirst("-" + sizes, "")
.split(" ")[0]
.split(".")[0]
: null;
}
if (sizes != null && sizes.isNotEmpty && sizes != "any") {
List<String> sizesSplitted = sizes.split(" ");
for (String size in sizesSplitted) {
int width = int.parse(size.split("x")[0]);
int height = int.parse(size.split("x")[1]);
favicons.add(Favicon(url: urlIcon, rel: rel, width: width, height: height));
favicons
.add(Favicon(url: urlIcon, rel: rel, width: width, height: height));
}
} else {
favicons.add(Favicon(url: urlIcon, rel: rel, width: null, height: null));
@ -913,7 +1086,8 @@ class InAppWebViewController {
}
///Loads the given [url] with optional [headers] specified as a map from name to value.
Future<void> loadUrl({@required String url, Map<String, String> headers = const {}}) async {
Future<void> loadUrl(
{@required String url, Map<String, String> headers = const {}}) async {
assert(url != null && url.isNotEmpty);
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
@ -926,7 +1100,8 @@ class InAppWebViewController {
}
///Loads the given [url] with [postData] using `POST` method into this WebView.
Future<void> postUrl({@required String url, @required Uint8List postData}) async {
Future<void> postUrl(
{@required String url, @required Uint8List postData}) async {
assert(url != null && url.isNotEmpty);
assert(postData != null);
Map<String, dynamic> args = <String, dynamic>{};
@ -942,7 +1117,11 @@ class InAppWebViewController {
///Loads the given [data] into this WebView, using [baseUrl] as the base URL for the content.
///The [mimeType] parameter specifies the format of the data.
///The [encoding] parameter specifies the encoding of the data.
Future<void> loadData({@required String data, String mimeType = "text/html", String encoding = "utf8", String baseUrl = "about:blank"}) async {
Future<void> loadData(
{@required String data,
String mimeType = "text/html",
String encoding = "utf8",
String baseUrl = "about:blank"}) async {
assert(data != null);
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
@ -985,7 +1164,9 @@ class InAppWebViewController {
///inAppBrowser.loadFile("assets/index.html");
///...
///```
Future<void> loadFile({@required String assetFilePath, Map<String, String> headers = const {}}) async {
Future<void> loadFile(
{@required String assetFilePath,
Map<String, String> headers = const {}}) async {
assert(assetFilePath != null && assetFilePath.isNotEmpty);
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
@ -1107,8 +1288,7 @@ class InAppWebViewController {
}
args.putIfAbsent('source', () => source);
var data = await _channel.invokeMethod('evaluateJavascript', args);
if (data != null && Platform.isAndroid)
data = json.decode(data);
if (data != null && Platform.isAndroid) data = json.decode(data);
return data;
}
@ -1124,7 +1304,8 @@ class InAppWebViewController {
}
///Injects a JavaScript file into the WebView from the flutter assets directory.
Future<void> injectJavascriptFileFromAsset({@required String assetFilePath}) async {
Future<void> injectJavascriptFileFromAsset(
{@required String assetFilePath}) async {
String source = await rootBundle.loadString(assetFilePath);
await evaluateJavascript(source: source);
}
@ -1201,7 +1382,9 @@ class InAppWebViewController {
/// });
/// """);
///```
void addJavaScriptHandler({@required String handlerName, @required JavaScriptHandlerCallback callback}) {
void addJavaScriptHandler(
{@required String handlerName,
@required JavaScriptHandlerCallback callback}) {
assert(!javaScriptHandlerForbiddenNames.contains(handlerName));
this.javaScriptHandlersMap[handlerName] = (callback);
}
@ -1209,7 +1392,8 @@ class InAppWebViewController {
///Removes a JavaScript message handler previously added with the [addJavaScriptHandler()] associated to [handlerName] key.
///Returns the value associated with [handlerName] before it was removed.
///Returns `null` if [handlerName] was not found.
JavaScriptHandlerCallback removeJavaScriptHandler({@required String handlerName}) {
JavaScriptHandlerCallback removeJavaScriptHandler(
{@required String handlerName}) {
return this.javaScriptHandlersMap.remove(handlerName);
}
@ -1252,15 +1436,20 @@ class InAppWebViewController {
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
InAppWebViewWidgetOptions inAppWebViewWidgetOptions = InAppWebViewWidgetOptions();
Map<dynamic, dynamic> options = await _channel.invokeMethod('getOptions', args);
InAppWebViewWidgetOptions inAppWebViewWidgetOptions =
InAppWebViewWidgetOptions();
Map<dynamic, dynamic> options =
await _channel.invokeMethod('getOptions', args);
if (options != null) {
options = options.cast<String, dynamic>();
inAppWebViewWidgetOptions.inAppWebViewOptions = InAppWebViewOptions.fromMap(options);
inAppWebViewWidgetOptions.inAppWebViewOptions =
InAppWebViewOptions.fromMap(options);
if (Platform.isAndroid)
inAppWebViewWidgetOptions.androidInAppWebViewOptions = AndroidInAppWebViewOptions.fromMap(options);
inAppWebViewWidgetOptions.androidInAppWebViewOptions =
AndroidInAppWebViewOptions.fromMap(options);
else if (Platform.isIOS)
inAppWebViewWidgetOptions.iosInAppWebViewOptions = IosInAppWebViewOptions.fromMap(options);
inAppWebViewWidgetOptions.iosInAppWebViewOptions =
IosInAppWebViewOptions.fromMap(options);
}
return inAppWebViewWidgetOptions;
@ -1276,7 +1465,8 @@ class InAppWebViewController {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
Map<dynamic, dynamic> result = await _channel.invokeMethod('getCopyBackForwardList', args);
Map<dynamic, dynamic> result =
await _channel.invokeMethod('getCopyBackForwardList', args);
result = result.cast<String, dynamic>();
List<dynamic> historyListMap = result["history"];
@ -1287,7 +1477,12 @@ class InAppWebViewController {
List<WebHistoryItem> historyList = List();
for (var i = 0; i < historyListMap.length; i++) {
LinkedHashMap<dynamic, dynamic> historyItem = historyListMap[i];
historyList.add(WebHistoryItem(originalUrl: historyItem["originalUrl"], title: historyItem["title"], url: historyItem["url"], index: i, offset: i - currentIndex));
historyList.add(WebHistoryItem(
originalUrl: historyItem["originalUrl"],
title: historyItem["title"],
url: historyItem["url"],
index: i,
offset: i - currentIndex));
}
return WebHistory(list: historyList, currentIndex: currentIndex);
}
@ -1434,12 +1629,14 @@ class InAppWebViewController {
///Gets the html (with javascript) of the Chromium's t-rex runner game. Used in combination with [getTRexRunnerCss()].
Future<String> getTRexRunnerHtml() async {
return await rootBundle.loadString("packages/flutter_inappwebview/t_rex_runner/t-rex.html");
return await rootBundle
.loadString("packages/flutter_inappwebview/t_rex_runner/t-rex.html");
}
///Gets the css of the Chromium's t-rex runner game. Used in combination with [getTRexRunnerHtml()].
Future<String> getTRexRunnerCss() async {
return await rootBundle.loadString("packages/flutter_inappwebview/t_rex_runner/t-rex.css");
return await rootBundle
.loadString("packages/flutter_inappwebview/t_rex_runner/t-rex.css");
}
///Scrolls the WebView to the position.

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@ import 'content_blocker.dart';
import 'types.dart';
class AndroidOptions {}
class IosOptions {}
class WebViewOptions {
@ -37,84 +38,129 @@ class ChromeSafariBrowserOptions {
}
///This class represents all the cross-platform WebView options available.
class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOptions, IosOptions {
class InAppWebViewOptions
implements WebViewOptions, BrowserOptions, AndroidOptions, IosOptions {
///Set to `true` to be able to listen at the [shouldOverrideUrlLoading] event. The default value is `false`.
bool useShouldOverrideUrlLoading;
///Set to `true` to be able to listen at the [onLoadResource] event. The default value is `false`.
bool useOnLoadResource;
///Set to `true` to be able to listen at the [onDownloadStart] event. The default value is `false`.
bool useOnDownloadStart;
///Set to `true` to be able to listen at the [onTargetBlank] event. The default value is `false`.
bool useOnTargetBlank;
///Set to `true` to have all the browser's cache cleared before the new window is opened. The default value is `false`.
bool clearCache;
///Sets the user-agent for the WebView.
///
///**NOTE**: available on iOS 9.0+.
String userAgent;
///Append to the existing user-agent. Setting userAgent will override this.
///
///**NOTE**: available on Android 17+ and on iOS 9.0+.
String applicationNameForUserAgent;
///Set to `true` to enable JavaScript. The default value is `true`.
bool javaScriptEnabled;
///Enables debugging of web contents (HTML / CSS / JavaScript) loaded into any WebViews of this application.
///This flag can be enabled in order to facilitate debugging of web layouts and JavaScript code running inside WebViews. The default is `false`.
///
///**NOTE**: on iOS the debugging mode is always enabled.
bool debuggingEnabled;
///Set to `true` to allow JavaScript open windows without user interaction. The default value is `false`.
bool javaScriptCanOpenWindowsAutomatically;
///Set to `true` to prevent HTML5 audio or video from autoplaying. The default value is `true`.
///
///**NOTE**: available on iOS 10.0+.
bool mediaPlaybackRequiresUserGesture;
///Sets the minimum font size. The default value is `8` for Android, `0` for iOS.
int minimumFontSize;
///Define whether the vertical scrollbar should be drawn or not. The default value is `true`.
bool verticalScrollBarEnabled;
///Define whether the horizontal scrollbar should be drawn or not. The default value is `true`.
bool horizontalScrollBarEnabled;
///List of custom schemes that the WebView must handle. Use the [onLoadResourceCustomScheme] event to intercept resource requests with custom scheme.
///
///**NOTE**: available on iOS 11.0+.
List<String> resourceCustomSchemes;
///List of [ContentBlocker] that are a set of rules used to block content in the browser window.
///
///**NOTE**: available on iOS 11.0+.
List<ContentBlocker> contentBlockers;
///Sets the content mode that the WebView needs to use when loading and rendering a webpage. The default value is [InAppWebViewUserPreferredContentMode.RECOMMENDED].
///
///**NOTE**: available on iOS 13.0+.
InAppWebViewUserPreferredContentMode preferredContentMode;
///Set to `true` to be able to listen at the [shouldInterceptAjaxRequest] event. The default value is `false`.
bool useShouldInterceptAjaxRequest;
///Set to `true` to be able to listen at the [shouldInterceptFetchRequest] event. The default value is `false`.
bool useShouldInterceptFetchRequest;
///Set to `true` to open a browser window with incognito mode. The default value is `false`.
///
///**NOTE**: available on iOS 9.0+.
bool incognito;
///Sets whether WebView should use browser caching. The default value is `true`.
///
///**NOTE**: available on iOS 9.0+.
bool cacheEnabled;
///Set to `true` to make the background of the WebView transparent. If your app has a dark theme, this can prevent a white flash on initialization. The default value is `false`.
bool transparentBackground;
///Set to `true` to disable vertical scroll. The default value is `false`.
bool disableVerticalScroll;
///Set to `true` to disable horizontal scroll. The default value is `false`.
bool disableHorizontalScroll;
InAppWebViewOptions({this.useShouldOverrideUrlLoading = false, this.useOnLoadResource = false, this.useOnDownloadStart = false, this.useOnTargetBlank = false,
this.clearCache = false, this.userAgent = "", this.applicationNameForUserAgent = "", this.javaScriptEnabled = true, this.debuggingEnabled = false, this.javaScriptCanOpenWindowsAutomatically = false,
this.mediaPlaybackRequiresUserGesture = true, this.minimumFontSize, this.verticalScrollBarEnabled = true, this.horizontalScrollBarEnabled = true,
this.resourceCustomSchemes = const [], this.contentBlockers = const [], this.preferredContentMode = InAppWebViewUserPreferredContentMode.RECOMMENDED,
this.useShouldInterceptAjaxRequest = false, this.useShouldInterceptFetchRequest = false, this.incognito = false, this.cacheEnabled = true, this.transparentBackground = false,
this.disableVerticalScroll = false, this.disableHorizontalScroll = false}) {
InAppWebViewOptions(
{this.useShouldOverrideUrlLoading = false,
this.useOnLoadResource = false,
this.useOnDownloadStart = false,
this.useOnTargetBlank = false,
this.clearCache = false,
this.userAgent = "",
this.applicationNameForUserAgent = "",
this.javaScriptEnabled = true,
this.debuggingEnabled = false,
this.javaScriptCanOpenWindowsAutomatically = false,
this.mediaPlaybackRequiresUserGesture = true,
this.minimumFontSize,
this.verticalScrollBarEnabled = true,
this.horizontalScrollBarEnabled = true,
this.resourceCustomSchemes = const [],
this.contentBlockers = const [],
this.preferredContentMode =
InAppWebViewUserPreferredContentMode.RECOMMENDED,
this.useShouldInterceptAjaxRequest = false,
this.useShouldInterceptFetchRequest = false,
this.incognito = false,
this.cacheEnabled = true,
this.transparentBackground = false,
this.disableVerticalScroll = false,
this.disableHorizontalScroll = false}) {
if (this.minimumFontSize == null)
this.minimumFontSize = Platform.isAndroid ? 8 : 0;
assert(!this.resourceCustomSchemes.contains("http") && !this.resourceCustomSchemes.contains("https"));
assert(!this.resourceCustomSchemes.contains("http") &&
!this.resourceCustomSchemes.contains("https"));
}
@override
@ -134,7 +180,8 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOpti
"applicationNameForUserAgent": applicationNameForUserAgent,
"javaScriptEnabled": javaScriptEnabled,
"debuggingEnabled": debuggingEnabled,
"javaScriptCanOpenWindowsAutomatically": javaScriptCanOpenWindowsAutomatically,
"javaScriptCanOpenWindowsAutomatically":
javaScriptCanOpenWindowsAutomatically,
"mediaPlaybackRequiresUserGesture": mediaPlaybackRequiresUserGesture,
"verticalScrollBarEnabled": verticalScrollBarEnabled,
"horizontalScrollBarEnabled": horizontalScrollBarEnabled,
@ -151,15 +198,14 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOpti
};
}
@override
static InAppWebViewOptions fromMap(Map<String, dynamic> map) {
List<ContentBlocker> contentBlockers = [];
List<dynamic> contentBlockersMapList = map["contentBlockers"];
if (contentBlockersMapList != null) {
contentBlockersMapList.forEach((contentBlocker) {
contentBlockers.add(ContentBlocker.fromMap(
Map<dynamic, Map<dynamic, dynamic>>.from(Map<dynamic, dynamic>.from(contentBlocker))
));
Map<dynamic, Map<dynamic, dynamic>>.from(
Map<dynamic, dynamic>.from(contentBlocker))));
});
}
@ -173,15 +219,22 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOpti
options.applicationNameForUserAgent = map["applicationNameForUserAgent"];
options.javaScriptEnabled = map["javaScriptEnabled"];
options.debuggingEnabled = map["debuggingEnabled"];
options.javaScriptCanOpenWindowsAutomatically = map["javaScriptCanOpenWindowsAutomatically"];
options.mediaPlaybackRequiresUserGesture = map["mediaPlaybackRequiresUserGesture"];
options.javaScriptCanOpenWindowsAutomatically =
map["javaScriptCanOpenWindowsAutomatically"];
options.mediaPlaybackRequiresUserGesture =
map["mediaPlaybackRequiresUserGesture"];
options.verticalScrollBarEnabled = map["verticalScrollBarEnabled"];
options.horizontalScrollBarEnabled = map["horizontalScrollBarEnabled"];
options.resourceCustomSchemes = List<String>.from(map["resourceCustomSchemes"] ?? []);
options.resourceCustomSchemes =
List<String>.from(map["resourceCustomSchemes"] ?? []);
options.contentBlockers = contentBlockers;
options.preferredContentMode = InAppWebViewUserPreferredContentMode.fromValue(map["preferredContentMode"]);
options.useShouldInterceptAjaxRequest = map["useShouldInterceptAjaxRequest"];
options.useShouldInterceptFetchRequest = map["useShouldInterceptFetchRequest"];
options.preferredContentMode =
InAppWebViewUserPreferredContentMode.fromValue(
map["preferredContentMode"]);
options.useShouldInterceptAjaxRequest =
map["useShouldInterceptAjaxRequest"];
options.useShouldInterceptFetchRequest =
map["useShouldInterceptFetchRequest"];
options.incognito = map["incognito"];
options.cacheEnabled = map["cacheEnabled"];
options.transparentBackground = map["transparentBackground"];
@ -192,92 +245,124 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOpti
}
///This class represents all the Android-only WebView options available.
class AndroidInAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOptions {
class AndroidInAppWebViewOptions
implements WebViewOptions, BrowserOptions, AndroidOptions {
///Sets the text zoom of the page in percent. The default value is `100`.
int textZoom;
///Set to `true` to have the session cookie cache cleared before the new window is opened.
bool clearSessionCache;
///Set to `true` if the WebView should use its built-in zoom mechanisms. The default value is `false`.
bool builtInZoomControls;
///Set to `true` if the WebView should display on-screen zoom controls when using the built-in zoom mechanisms. The default value is `false`.
bool displayZoomControls;
///Set to `false` if the WebView should not support zooming using its on-screen zoom controls and gestures. The default value is `true`.
bool supportZoom;
///Set to `true` if you want the database storage API is enabled. The default value is `false`.
bool databaseEnabled;
///Set to `true` if you want the DOM storage API is enabled. The default value is `false`.
bool domStorageEnabled;
///Set to `true` if the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport.
///When the value of the setting is false, the layout width is always set to the width of the WebView control in device-independent (CSS) pixels.
///When the value is true and the page contains the viewport meta tag, the value of the width specified in the tag is used.
///If the page does not contain the tag or does not provide a width, then a wide viewport will be used. The default value is `true`.
bool useWideViewPort;
///Sets whether Safe Browsing is enabled. Safe Browsing allows WebView to protect against malware and phishing attacks by verifying the links.
///Safe Browsing is enabled by default for devices which support it.
///
///**NOTE**: available on Android 26+.
bool safeBrowsingEnabled;
///Configures the WebView's behavior when a secure origin attempts to load a resource from an insecure origin.
///
///**NOTE**: available on Android 21+.
AndroidInAppWebViewMixedContentMode mixedContentMode;
///Enables or disables content URL access within WebView. Content URL access allows WebView to load content from a content provider installed in the system. The default value is `true`.
bool allowContentAccess;
///Enables or disables file access within WebView. Note that this enables or disables file system access only.
///Assets and resources are still accessible using \file:///android_asset` and `file:///android_res`. The default value is `true`.
bool allowFileAccess;
///Sets whether JavaScript running in the context of a file scheme URL should be allowed to access content from other file scheme URLs.
///Note that the value of this setting is ignored if the value of [allowFileAccessFromFileURLs] is `true`.
///Note too, that this setting affects only JavaScript access to file scheme resources. The default value is `false`.
bool allowFileAccessFromFileURLs;
///Sets whether JavaScript running in the context of a file scheme URL should be allowed to access content from any origin.
///Note that this setting affects only JavaScript access to file scheme resources.
///This includes access to content from other file scheme URLs. The default value is `false`.
bool allowUniversalAccessFromFileURLs;
///Sets the path to the Application Caches files. In order for the Application Caches API to be enabled, this option must be set a path to which the application can write.
///This option is used one time: repeated calls are ignored.
String appCachePath;
///Sets whether the WebView should not load image resources from the network (resources accessed via http and https URI schemes). The default value is `false`.
bool blockNetworkImage;
///Sets whether the WebView should not load resources from the network. The default value is `false`.
bool blockNetworkLoads;
///Overrides the way the cache is used. The way the cache is used is based on the navigation type. For a normal page load, the cache is checked and content is re-validated as needed.
///When navigating back, content is not revalidated, instead the content is just retrieved from the cache. The default value is [AndroidInAppWebViewCacheMode.LOAD_DEFAULT].
AndroidInAppWebViewCacheMode cacheMode;
///Sets the cursive font family name. The default value is `"cursive"`.
String cursiveFontFamily;
///Sets the default fixed font size. The default value is `16`.
int defaultFixedFontSize;
///Sets the default font size. The default value is `16`.
int defaultFontSize;
///Sets the default text encoding name to use when decoding html pages. The default value is `"UTF-8"`.
String defaultTextEncodingName;
///Disables the action mode menu items according to menuItems flag.
///
///**NOTE**: available on Android 24+.
AndroidInAppWebViewModeMenuItem disabledActionModeMenuItems;
///Sets the fantasy font family name. The default value is `"fantasy"`.
String fantasyFontFamily;
///Sets the fixed font family name. The default value is `"monospace"`.
String fixedFontFamily;
///Set the force dark mode for this WebView. The default value is [AndroidInAppWebViewForceDark.FORCE_DARK_OFF].
///
///**NOTE**: available on Android 29+.
AndroidInAppWebViewForceDark forceDark;
///Sets whether Geolocation API is enabled. The default value is `true`.
bool geolocationEnabled;
///Sets the underlying layout algorithm. This will cause a re-layout of the WebView.
AndroidInAppWebViewLayoutAlgorithm layoutAlgorithm;
///Sets whether the WebView loads pages in overview mode, that is, zooms out the content to fit on screen by width.
///This setting is taken into account when the content width is greater than the width of the WebView control, for example, when [useWideViewPort] is enabled.
///The default value is `false`.
bool loadWithOverviewMode;
///Sets whether the WebView should load image resources. Note that this method controls loading of all images, including those embedded using the data URI scheme.
///Note that if the value of this setting is changed from false to true, all images resources referenced by content currently displayed by the WebView are loaded automatically.
///The default value is `true`.
bool loadsImagesAutomatically;
///Sets the minimum logical font size. The default is `8`.
int minimumLogicalFontSize;
///Sets the initial scale for this WebView. 0 means default. The behavior for the default scale depends on the state of [useWideViewPort] and [loadWithOverviewMode].
///If the content fits into the WebView control by width, then the zoom is set to 100%. For wide content, the behavior depends on the state of [loadWithOverviewMode].
///If its value is true, the content will be zoomed out to be fit by width into the WebView control, otherwise not.
@ -285,43 +370,82 @@ class AndroidInAppWebViewOptions implements WebViewOptions, BrowserOptions, Andr
///Please note that unlike the scale properties in the viewport meta tag, this method doesn't take the screen density into account.
///The default is `0`.
int initialScale;
///Tells the WebView whether it needs to set a node. The default value is `true`.
bool needInitialFocus;
///Sets whether this WebView should raster tiles when it is offscreen but attached to a window.
///Turning this on can avoid rendering artifacts when animating an offscreen WebView on-screen.
///Offscreen WebViews in this mode use more memory. The default value is `false`.
///
///**NOTE**: available on Android 23+.
bool offscreenPreRaster;
///Sets the sans-serif font family name. The default value is `"sans-serif"`.
String sansSerifFontFamily;
///Sets the serif font family name. The default value is `"sans-serif"`.
String serifFontFamily;
///Sets the standard font family name. The default value is `"sans-serif"`.
String standardFontFamily;
///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.
bool saveFormData;
///Boolean value to enable third party cookies in the WebView.
///Used on Android Lollipop and above only as third party cookies are enabled by default on Android Kitkat and below and on iOS.
///The default value is `true`.
///
///**NOTE**: available on Android 21+.
bool thirdPartyCookiesEnabled;
///Boolean value to enable Hardware Acceleration in the WebView.
///The default value is `true`.
bool hardwareAcceleration;
AndroidInAppWebViewOptions({this.textZoom = 100, this.clearSessionCache = false, this.builtInZoomControls = false, this.displayZoomControls = false, this.supportZoom = true, this.databaseEnabled = false,
this.domStorageEnabled = false, this.useWideViewPort = true, this.safeBrowsingEnabled = true, this.mixedContentMode,
this.allowContentAccess = true, this.allowFileAccess = true, this.allowFileAccessFromFileURLs = false, this.allowUniversalAccessFromFileURLs = false,
this.appCachePath, this.blockNetworkImage = false, this.blockNetworkLoads = false, this.cacheMode = AndroidInAppWebViewCacheMode.LOAD_DEFAULT,
this.cursiveFontFamily = "cursive", this.defaultFixedFontSize = 16, this.defaultFontSize = 16, this.defaultTextEncodingName = "UTF-8",
this.disabledActionModeMenuItems, this.fantasyFontFamily = "fantasy", this.fixedFontFamily = "monospace", this.forceDark = AndroidInAppWebViewForceDark.FORCE_DARK_OFF,
this.geolocationEnabled = true, this.layoutAlgorithm, this.loadWithOverviewMode = true, this.loadsImagesAutomatically = true,
this.minimumLogicalFontSize = 8, this.needInitialFocus = true, this.offscreenPreRaster = false, this.sansSerifFontFamily = "sans-serif", this.serifFontFamily = "sans-serif",
this.standardFontFamily = "sans-serif", this.saveFormData = true, this.thirdPartyCookiesEnabled = true, this.hardwareAcceleration = true, this.initialScale = 0
});
AndroidInAppWebViewOptions(
{this.textZoom = 100,
this.clearSessionCache = false,
this.builtInZoomControls = false,
this.displayZoomControls = false,
this.supportZoom = true,
this.databaseEnabled = false,
this.domStorageEnabled = false,
this.useWideViewPort = true,
this.safeBrowsingEnabled = true,
this.mixedContentMode,
this.allowContentAccess = true,
this.allowFileAccess = true,
this.allowFileAccessFromFileURLs = false,
this.allowUniversalAccessFromFileURLs = false,
this.appCachePath,
this.blockNetworkImage = false,
this.blockNetworkLoads = false,
this.cacheMode = AndroidInAppWebViewCacheMode.LOAD_DEFAULT,
this.cursiveFontFamily = "cursive",
this.defaultFixedFontSize = 16,
this.defaultFontSize = 16,
this.defaultTextEncodingName = "UTF-8",
this.disabledActionModeMenuItems,
this.fantasyFontFamily = "fantasy",
this.fixedFontFamily = "monospace",
this.forceDark = AndroidInAppWebViewForceDark.FORCE_DARK_OFF,
this.geolocationEnabled = true,
this.layoutAlgorithm,
this.loadWithOverviewMode = true,
this.loadsImagesAutomatically = true,
this.minimumLogicalFontSize = 8,
this.needInitialFocus = true,
this.offscreenPreRaster = false,
this.sansSerifFontFamily = "sans-serif",
this.serifFontFamily = "sans-serif",
this.standardFontFamily = "sans-serif",
this.saveFormData = true,
this.thirdPartyCookiesEnabled = true,
this.hardwareAcceleration = true,
this.initialScale = 0});
@override
Map<String, dynamic> toMap() {
@ -369,7 +493,6 @@ class AndroidInAppWebViewOptions implements WebViewOptions, BrowserOptions, Andr
};
}
@override
static AndroidInAppWebViewOptions fromMap(Map<String, dynamic> map) {
AndroidInAppWebViewOptions options = new AndroidInAppWebViewOptions();
options.textZoom = map["textZoom"];
@ -381,25 +504,32 @@ class AndroidInAppWebViewOptions implements WebViewOptions, BrowserOptions, Andr
options.domStorageEnabled = map["domStorageEnabled"];
options.useWideViewPort = map["useWideViewPort"];
options.safeBrowsingEnabled = map["safeBrowsingEnabled"];
options.mixedContentMode = AndroidInAppWebViewMixedContentMode.fromValue(map["mixedContentMode"]);
options.mixedContentMode =
AndroidInAppWebViewMixedContentMode.fromValue(map["mixedContentMode"]);
options.allowContentAccess = map["allowContentAccess"];
options.allowFileAccess = map["allowFileAccess"];
options.allowFileAccessFromFileURLs = map["allowFileAccessFromFileURLs"];
options.allowUniversalAccessFromFileURLs = map["allowUniversalAccessFromFileURLs"];
options.allowUniversalAccessFromFileURLs =
map["allowUniversalAccessFromFileURLs"];
options.appCachePath = map["appCachePath"];
options.blockNetworkImage = map["blockNetworkImage"];
options.blockNetworkLoads = map["blockNetworkLoads"];
options.cacheMode = AndroidInAppWebViewCacheMode.fromValue(map["cacheMode"]);
options.cacheMode =
AndroidInAppWebViewCacheMode.fromValue(map["cacheMode"]);
options.cursiveFontFamily = map["cursiveFontFamily"];
options.defaultFixedFontSize = map["defaultFixedFontSize"];
options.defaultFontSize = map["defaultFontSize"];
options.defaultTextEncodingName = map["defaultTextEncodingName"];
options.disabledActionModeMenuItems = AndroidInAppWebViewModeMenuItem.fromValue(map["disabledActionModeMenuItems"]);
options.disabledActionModeMenuItems =
AndroidInAppWebViewModeMenuItem.fromValue(
map["disabledActionModeMenuItems"]);
options.fantasyFontFamily = map["fantasyFontFamily"];
options.fixedFontFamily = map["fixedFontFamily"];
options.forceDark = AndroidInAppWebViewForceDark.fromValue(map["forceDark"]);
options.forceDark =
AndroidInAppWebViewForceDark.fromValue(map["forceDark"]);
options.geolocationEnabled = map["geolocationEnabled"];
options.layoutAlgorithm = AndroidInAppWebViewLayoutAlgorithm.fromValue(map["layoutAlgorithm"]);
options.layoutAlgorithm =
AndroidInAppWebViewLayoutAlgorithm.fromValue(map["layoutAlgorithm"]);
options.loadWithOverviewMode = map["loadWithOverviewMode"];
options.loadsImagesAutomatically = map["loadsImagesAutomatically"];
options.minimumLogicalFontSize = map["minimumLogicalFontSize"];
@ -417,57 +547,79 @@ class AndroidInAppWebViewOptions implements WebViewOptions, BrowserOptions, Andr
}
///This class represents all the iOS-only WebView options available.
class IosInAppWebViewOptions implements WebViewOptions, BrowserOptions, IosOptions {
class IosInAppWebViewOptions
implements WebViewOptions, BrowserOptions, IosOptions {
///Set to `true` to disable the bouncing of the WebView when the scrolling has reached an edge of the content. The default value is `false`.
bool disallowOverScroll;
///Set to `true` to allow a viewport meta tag to either disable or restrict the range of user scaling. The default value is `false`.
bool enableViewportScale;
///Set to `true` if you want the WebView suppresses content rendering until it is fully loaded into memory. The default value is `false`.
bool suppressesIncrementalRendering;
///Set to `true` to allow AirPlay. The default value is `true`.
bool allowsAirPlayForMediaPlayback;
///Set to `true` to allow the horizontal swipe gestures trigger back-forward list navigations. The default value is `true`.
bool allowsBackForwardNavigationGestures;
///Set to `true` to allow that pressing on a link displays a preview of the destination for the link. The default value is `true`.
///
///**NOTE**: available on iOS 9.0+.
bool allowsLinkPreview;
///Set to `true` if you want that the WebView should always allow scaling of the webpage, regardless of the author's intent.
///The ignoresViewportScaleLimits property overrides the `user-scalable` HTML property in a webpage. The default value is `false`.
bool ignoresViewportScaleLimits;
///Set to `true` to allow HTML5 media playback to appear inline within the screen layout, using browser-supplied controls rather than native controls.
///For this to work, add the `webkit-playsinline` attribute to any `<video>` elements. The default value is `false`.
bool allowsInlineMediaPlayback;
///Set to `true` to allow HTML5 videos play picture-in-picture. The default value is `true`.
///
///**NOTE**: available on iOS 9.0+.
bool allowsPictureInPictureMediaPlayback;
///A Boolean value indicating whether warnings should be shown for suspected fraudulent content such as phishing or malware.
///According to the official documentation, this feature is currently available in the following region: China.
///The default value is `true`.
///
///**NOTE**: available on iOS 13.0+.
bool isFraudulentWebsiteWarningEnabled;
///The level of granularity with which the user can interactively select content in the web view.
///The default value is [IosInAppWebViewSelectionGranularity.DYNAMIC]
IosInAppWebViewSelectionGranularity selectionGranularity;
///Specifying a dataDetectoryTypes value adds interactivity to web content that matches the value.
///For example, Safari adds a link to apple.com in the text Visit apple.com if the dataDetectorTypes property is set to [IosInAppWebViewDataDetectorTypes.LINK].
///The default value is [IosInAppWebViewDataDetectorTypes.NONE].
///
///**NOTE**: available on iOS 10.0+.
List<IosInAppWebViewDataDetectorTypes> dataDetectorTypes;
///Set `true` if shared cookies from `HTTPCookieStorage.shared` should used for every load request in the WebView.
///The default value is `false`.
///
///**NOTE**: available on iOS 11.0+.
bool sharedCookiesEnabled;
IosInAppWebViewOptions({this.disallowOverScroll = false, this.enableViewportScale = false, this.suppressesIncrementalRendering = false, this.allowsAirPlayForMediaPlayback = true,
this.allowsBackForwardNavigationGestures = true, this.allowsLinkPreview = true, this.ignoresViewportScaleLimits = false, this.allowsInlineMediaPlayback = false,
this.allowsPictureInPictureMediaPlayback = true, this.isFraudulentWebsiteWarningEnabled = true,
this.selectionGranularity = IosInAppWebViewSelectionGranularity.DYNAMIC, this.dataDetectorTypes = const [IosInAppWebViewDataDetectorTypes.NONE], this.sharedCookiesEnabled = false
});
IosInAppWebViewOptions(
{this.disallowOverScroll = false,
this.enableViewportScale = false,
this.suppressesIncrementalRendering = false,
this.allowsAirPlayForMediaPlayback = true,
this.allowsBackForwardNavigationGestures = true,
this.allowsLinkPreview = true,
this.ignoresViewportScaleLimits = false,
this.allowsInlineMediaPlayback = false,
this.allowsPictureInPictureMediaPlayback = true,
this.isFraudulentWebsiteWarningEnabled = true,
this.selectionGranularity = IosInAppWebViewSelectionGranularity.DYNAMIC,
this.dataDetectorTypes = const [IosInAppWebViewDataDetectorTypes.NONE],
this.sharedCookiesEnabled = false});
@override
Map<String, dynamic> toMap() {
@ -481,11 +633,13 @@ class IosInAppWebViewOptions implements WebViewOptions, BrowserOptions, IosOptio
"enableViewportScale": enableViewportScale,
"suppressesIncrementalRendering": suppressesIncrementalRendering,
"allowsAirPlayForMediaPlayback": allowsAirPlayForMediaPlayback,
"allowsBackForwardNavigationGestures": allowsBackForwardNavigationGestures,
"allowsBackForwardNavigationGestures":
allowsBackForwardNavigationGestures,
"allowsLinkPreview": allowsLinkPreview,
"ignoresViewportScaleLimits": ignoresViewportScaleLimits,
"allowsInlineMediaPlayback": allowsInlineMediaPlayback,
"allowsPictureInPictureMediaPlayback": allowsPictureInPictureMediaPlayback,
"allowsPictureInPictureMediaPlayback":
allowsPictureInPictureMediaPlayback,
"isFraudulentWebsiteWarningEnabled": isFraudulentWebsiteWarningEnabled,
"selectionGranularity": selectionGranularity.toValue(),
"dataDetectorTypes": dataDetectorTypesList,
@ -493,26 +647,34 @@ class IosInAppWebViewOptions implements WebViewOptions, BrowserOptions, IosOptio
};
}
@override
static IosInAppWebViewOptions fromMap(Map<String, dynamic> map) {
List<IosInAppWebViewDataDetectorTypes> dataDetectorTypes = [];
List<String> dataDetectorTypesList = List<String>.from(map["dataDetectorTypes"] ?? []);
List<String> dataDetectorTypesList =
List<String>.from(map["dataDetectorTypes"] ?? []);
dataDetectorTypesList.forEach((dataDetectorType) {
dataDetectorTypes.add(IosInAppWebViewDataDetectorTypes.fromValue(dataDetectorType));
dataDetectorTypes
.add(IosInAppWebViewDataDetectorTypes.fromValue(dataDetectorType));
});
IosInAppWebViewOptions options = new IosInAppWebViewOptions();
options.disallowOverScroll = map["disallowOverScroll"];
options.enableViewportScale = map["enableViewportScale"];
options.suppressesIncrementalRendering = map["suppressesIncrementalRendering"];
options.allowsAirPlayForMediaPlayback = map["allowsAirPlayForMediaPlayback"];
options.allowsBackForwardNavigationGestures = map["allowsBackForwardNavigationGestures"];
options.suppressesIncrementalRendering =
map["suppressesIncrementalRendering"];
options.allowsAirPlayForMediaPlayback =
map["allowsAirPlayForMediaPlayback"];
options.allowsBackForwardNavigationGestures =
map["allowsBackForwardNavigationGestures"];
options.allowsLinkPreview = map["allowsLinkPreview"];
options.ignoresViewportScaleLimits = map["ignoresViewportScaleLimits"];
options.allowsInlineMediaPlayback = map["allowsInlineMediaPlayback"];
options.allowsPictureInPictureMediaPlayback = map["allowsPictureInPictureMediaPlayback"];
options.isFraudulentWebsiteWarningEnabled = map["isFraudulentWebsiteWarningEnabled"];
options.selectionGranularity = IosInAppWebViewSelectionGranularity.fromValue(map["selectionGranularity"]);
options.allowsPictureInPictureMediaPlayback =
map["allowsPictureInPictureMediaPlayback"];
options.isFraudulentWebsiteWarningEnabled =
map["isFraudulentWebsiteWarningEnabled"];
options.selectionGranularity =
IosInAppWebViewSelectionGranularity.fromValue(
map["selectionGranularity"]);
options.dataDetectorTypes = dataDetectorTypes;
options.sharedCookiesEnabled = map["sharedCookiesEnabled"];
return options;
@ -520,18 +682,26 @@ class IosInAppWebViewOptions implements WebViewOptions, BrowserOptions, IosOptio
}
///This class represents all the cross-platform [InAppBrowser] options available.
class InAppBrowserOptions implements BrowserOptions, AndroidOptions, IosOptions {
class InAppBrowserOptions
implements BrowserOptions, AndroidOptions, IosOptions {
///Set to `true` to create the browser and load the page, but not show it. Omit or set to `false` to have the browser open and load normally.
///The default value is `false`.
bool hidden;
///Set to `false` to hide the toolbar at the top of the WebView. The default value is `true`.
bool toolbarTop;
///Set the custom background color of the toolbar at the top.
String toolbarTopBackgroundColor;
///Set to `true` to hide the url bar on the toolbar at the top. The default value is `false`.
bool hideUrlBar;
InAppBrowserOptions({this.hidden = false, this.toolbarTop = true, this.toolbarTopBackgroundColor = "", this.hideUrlBar = false});
InAppBrowserOptions(
{this.hidden = false,
this.toolbarTop = true,
this.toolbarTopBackgroundColor = "",
this.hideUrlBar = false});
@override
Map<String, dynamic> toMap() {
@ -543,7 +713,6 @@ class InAppBrowserOptions implements BrowserOptions, AndroidOptions, IosOptions
};
}
@override
static InAppBrowserOptions fromMap(Map<String, dynamic> map) {
InAppBrowserOptions options = new InAppBrowserOptions();
options.hidden = map["hidden"];
@ -558,14 +727,21 @@ class InAppBrowserOptions implements BrowserOptions, AndroidOptions, IosOptions
class AndroidInAppBrowserOptions implements BrowserOptions, AndroidOptions {
///Set to `true` if you want the title should be displayed. The default value is `false`.
bool hideTitleBar;
///Set the action bar's title.
String toolbarTopFixedTitle;
///Set to `false` to not close the InAppBrowser when the user click on the back button and the WebView cannot go back to the history. The default value is `true`.
bool closeOnCannotGoBack;
///Set to `false` to hide the progress bar at the bottom of the toolbar at the top. The default value is `true`.
bool progressBar;
AndroidInAppBrowserOptions({this.hideTitleBar = true, this.toolbarTopFixedTitle = "", this.closeOnCannotGoBack = true, this.progressBar = true});
AndroidInAppBrowserOptions(
{this.hideTitleBar = true,
this.toolbarTopFixedTitle = "",
this.closeOnCannotGoBack = true,
this.progressBar = true});
@override
Map<String, dynamic> toMap() {
@ -577,7 +753,6 @@ class AndroidInAppBrowserOptions implements BrowserOptions, AndroidOptions {
};
}
@override
static AndroidInAppBrowserOptions fromMap(Map<String, dynamic> map) {
AndroidInAppBrowserOptions options = new AndroidInAppBrowserOptions();
options.hideTitleBar = map["hideTitleBar"];
@ -592,24 +767,37 @@ class AndroidInAppBrowserOptions implements BrowserOptions, AndroidOptions {
class IosInAppBrowserOptions implements BrowserOptions, IosOptions {
///Set to `false` to hide the toolbar at the bottom of the WebView. The default value is `true`.
bool toolbarBottom;
///Set the custom background color of the toolbar at the bottom.
String toolbarBottomBackgroundColor;
///Set to `true` to set the toolbar at the bottom translucent. The default value is `true`.
bool toolbarBottomTranslucent;
///Set the custom text for the close button.
String closeButtonCaption;
///Set the custom color for the close button.
String closeButtonColor;
///Set the custom modal presentation style when presenting the WebView. The default value is [IosWebViewOptionsPresentationStyle.FULL_SCREEN].
IosWebViewOptionsPresentationStyle presentationStyle;
///Set to the custom transition style when presenting the WebView. The default value is [IosWebViewOptionsTransitionStyle.COVER_VERTICAL].
IosWebViewOptionsTransitionStyle transitionStyle;
///Set to `false` to hide the spinner when the WebView is loading a page. The default value is `true`.
bool spinner;
IosInAppBrowserOptions({this.toolbarBottom = true, this.toolbarBottomBackgroundColor = "", this.toolbarBottomTranslucent = true, this.closeButtonCaption = "",
this.closeButtonColor = "", this.presentationStyle = IosWebViewOptionsPresentationStyle.FULL_SCREEN,
this.transitionStyle = IosWebViewOptionsTransitionStyle.COVER_VERTICAL, this.spinner = true});
IosInAppBrowserOptions(
{this.toolbarBottom = true,
this.toolbarBottomBackgroundColor = "",
this.toolbarBottomTranslucent = true,
this.closeButtonCaption = "",
this.closeButtonColor = "",
this.presentationStyle = IosWebViewOptionsPresentationStyle.FULL_SCREEN,
this.transitionStyle = IosWebViewOptionsTransitionStyle.COVER_VERTICAL,
this.spinner = true});
@override
Map<String, dynamic> toMap() {
@ -625,7 +813,6 @@ class IosInAppBrowserOptions implements BrowserOptions, IosOptions {
};
}
@override
static IosInAppBrowserOptions fromMap(Map<String, dynamic> map) {
IosInAppBrowserOptions options = new IosInAppBrowserOptions();
options.toolbarBottom = map["toolbarBottom"];
@ -633,27 +820,39 @@ class IosInAppBrowserOptions implements BrowserOptions, IosOptions {
options.toolbarBottomTranslucent = map["toolbarBottomTranslucent"];
options.closeButtonCaption = map["closeButtonCaption"];
options.closeButtonColor = map["closeButtonColor"];
options.presentationStyle = IosWebViewOptionsPresentationStyle.fromValue(map["presentationStyle"]);
options.transitionStyle = IosWebViewOptionsTransitionStyle.fromValue(map["transitionStyle"]);
options.presentationStyle =
IosWebViewOptionsPresentationStyle.fromValue(map["presentationStyle"]);
options.transitionStyle =
IosWebViewOptionsTransitionStyle.fromValue(map["transitionStyle"]);
options.spinner = map["spinner"];
return options;
}
}
///This class represents all the Android-only [ChromeSafariBrowser] options available.
class AndroidChromeCustomTabsOptions implements ChromeSafariBrowserOptions, AndroidOptions {
class AndroidChromeCustomTabsOptions
implements ChromeSafariBrowserOptions, AndroidOptions {
///Set to `false` if you don't want the default share button. The default value is `true`.
bool addShareButton;
///Set to `false` if the title shouldn't be shown in the custom tab. The default value is `true`.
bool showTitle;
///Set the custom background color of the toolbar.
String toolbarBackgroundColor;
///Set to `true` to enable the url bar to hide as the user scrolls down on the page. The default value is `false`.
bool enableUrlBarHiding;
///Set to `true` to enable Instant Apps. The default value is `false`.
bool instantAppsEnabled;
AndroidChromeCustomTabsOptions({this.addShareButton = true, this.showTitle = true, this.toolbarBackgroundColor = "", this.enableUrlBarHiding = false, this.instantAppsEnabled = false});
AndroidChromeCustomTabsOptions(
{this.addShareButton = true,
this.showTitle = true,
this.toolbarBackgroundColor = "",
this.enableUrlBarHiding = false,
this.instantAppsEnabled = false});
@override
Map<String, dynamic> toMap() {
@ -666,9 +865,9 @@ class AndroidChromeCustomTabsOptions implements ChromeSafariBrowserOptions, Andr
};
}
@override
static AndroidChromeCustomTabsOptions fromMap(Map<String, dynamic> map) {
AndroidChromeCustomTabsOptions options = new AndroidChromeCustomTabsOptions();
AndroidChromeCustomTabsOptions options =
new AndroidChromeCustomTabsOptions();
options.addShareButton = map["addShareButton"];
options.showTitle = map["showTitle"];
options.toolbarBackgroundColor = map["toolbarBackgroundColor"];
@ -682,27 +881,38 @@ class AndroidChromeCustomTabsOptions implements ChromeSafariBrowserOptions, Andr
class IosSafariOptions implements ChromeSafariBrowserOptions, IosOptions {
///Set to `true` if Reader mode should be entered automatically when it is available for the webpage. The default value is `false`.
bool entersReaderIfAvailable;
///Set to `true` to enable bar collapsing. The default value is `false`.
bool barCollapsingEnabled;
///Set the custom style for the dismiss button. The default value is [IosSafariOptionsDismissButtonStyle.DONE].
///
///**NOTE**: available on iOS 11.0+.
IosSafariOptionsDismissButtonStyle dismissButtonStyle;
///Set the custom background color of the navigation bar and the toolbar.
///
///**NOTE**: available on iOS 10.0+.
String preferredBarTintColor;
///Set the custom color of the control buttons on the navigation bar and the toolbar.
///
///**NOTE**: available on iOS 10.0+.
String preferredControlTintColor;
///Set the custom modal presentation style when presenting the WebView. The default value is [IosWebViewOptionsPresentationStyle.FULL_SCREEN].
IosWebViewOptionsPresentationStyle presentationStyle;
///Set to the custom transition style when presenting the WebView. The default value is [IosWebViewOptionsTransitionStyle.COVER_VERTICAL].
IosWebViewOptionsTransitionStyle transitionStyle;
IosSafariOptions({this.entersReaderIfAvailable = false, this.barCollapsingEnabled = false, this.dismissButtonStyle = IosSafariOptionsDismissButtonStyle.DONE,
this.preferredBarTintColor = "", this.preferredControlTintColor = "", this.presentationStyle = IosWebViewOptionsPresentationStyle.FULL_SCREEN,
IosSafariOptions(
{this.entersReaderIfAvailable = false,
this.barCollapsingEnabled = false,
this.dismissButtonStyle = IosSafariOptionsDismissButtonStyle.DONE,
this.preferredBarTintColor = "",
this.preferredControlTintColor = "",
this.presentationStyle = IosWebViewOptionsPresentationStyle.FULL_SCREEN,
this.transitionStyle = IosWebViewOptionsTransitionStyle.COVER_VERTICAL});
@override
@ -718,16 +928,18 @@ class IosSafariOptions implements ChromeSafariBrowserOptions, IosOptions {
};
}
@override
static IosSafariOptions fromMap(Map<String, dynamic> map) {
IosSafariOptions options = new IosSafariOptions();
options.entersReaderIfAvailable = map["entersReaderIfAvailable"];
options.barCollapsingEnabled = map["barCollapsingEnabled"];
options.dismissButtonStyle = IosSafariOptionsDismissButtonStyle.fromValue(map["dismissButtonStyle"]);
options.dismissButtonStyle =
IosSafariOptionsDismissButtonStyle.fromValue(map["dismissButtonStyle"]);
options.preferredBarTintColor = map["preferredBarTintColor"];
options.preferredControlTintColor = map["preferredControlTintColor"];
options.presentationStyle = IosWebViewOptionsPresentationStyle.fromValue(map["presentationStyle"]);
options.transitionStyle = IosWebViewOptionsTransitionStyle.fromValue(map["transitionStyle"]);
options.presentationStyle =
IosWebViewOptionsPresentationStyle.fromValue(map["presentationStyle"]);
options.transitionStyle =
IosWebViewOptionsTransitionStyle.fromValue(map["transitionStyle"]);
return options;
}
}

View File

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