code refactoring, new features, replaced String url to Uri uri everywhere, added URLRequest
This commit is contained in:
parent
de9d081af2
commit
0b0bce66aa
772
.idea/libraries/Dart_Packages.xml
generated
Normal file
772
.idea/libraries/Dart_Packages.xml
generated
Normal file
@ -0,0 +1,772 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Dart Packages" type="DartPackagesLibraryType">
|
||||
<properties>
|
||||
<option name="packageNameToDirsMap">
|
||||
<entry key="_fe_analyzer_shared">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-12.0.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="analyzer">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-0.40.6/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="archive">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/archive-3.0.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/archive-2.0.13/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="args">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/args-1.6.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="async">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.5.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.5.0-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="boolean_selector">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="characters">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.1.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.1.0-nullsafety.5/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="charcode">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/charcode-1.2.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/charcode-1.2.0-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="cli_util">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/cli_util-0.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="clock">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="collection">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0-nullsafety.5/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="convert">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/convert-2.1.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="coverage">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/coverage-0.14.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="crypto">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-2.1.5/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="cupertino_icons">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="device_info">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="device_info_platform_interface">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_platform_interface-2.0.0-nullsafety.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="fake_async">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="ffi">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/ffi-1.0.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="file">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.0.0-nullsafety.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="flutter">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/packages/flutter/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="flutter_downloader">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="flutter_driver">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/packages/flutter_driver/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="flutter_test">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/packages/flutter_test/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="fuchsia_remote_debug_protocol">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/packages/fuchsia_remote_debug_protocol/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="glob">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/glob-1.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="http_multi_server">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/http_multi_server-2.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="http_parser">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/http_parser-3.1.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="integration_test">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/packages/integration_test/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="intl">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/intl-0.17.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="io">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/io-0.3.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="js">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.3-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="json_rpc_2">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/json_rpc_2-2.2.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="logging">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/logging-0.11.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="matcher">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.10/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.10-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="meta">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.3.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.3.0-nullsafety.6/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="mime">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/mime-1.0.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/mime-0.9.7/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="mockito">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/mockito-4.1.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="node_interop">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/node_interop-1.2.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="node_io">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/node_io-1.1.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="node_preamble">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/node_preamble-1.4.13/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="package_config">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/package_config-1.9.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="path">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path-1.8.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path-1.8.0-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="path_provider">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="path_provider_linux">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="path_provider_macos">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="path_provider_platform_interface">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_platform_interface-2.0.0-nullsafety/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="path_provider_windows">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="pedantic">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/pedantic-1.10.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/pedantic-1.10.0-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="permission_handler">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="permission_handler_platform_interface">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler_platform_interface-2.0.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="platform">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/platform-3.0.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/platform-3.0.0-nullsafety.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="plugin_platform_interface">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-1.1.0-nullsafety.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="pool">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/pool-1.5.0-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="process">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/process-4.1.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/process-4.0.0-nullsafety.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="pub_semver">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/pub_semver-1.4.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="shelf">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-0.7.5/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="shelf_packages_handler">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_packages_handler-2.0.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="shelf_static">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_static-0.2.9+1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="shelf_web_socket">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-0.2.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="sky_engine">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="source_map_stack_trace">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/source_map_stack_trace-2.1.0-nullsafety.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="source_maps">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.10-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="source_span">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.1/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.0-nullsafety.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="stack_trace">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0-nullsafety.6/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="stream_channel">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="string_scanner">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="sync_http">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/sync_http-0.3.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/sync_http-0.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="term_glyph">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="test">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/test-1.16.0-nullsafety.9/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="test_api">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/test_api-0.2.19/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/test_api-0.2.19-nullsafety.6/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="test_core">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/test_core-0.3.12-nullsafety.9/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="typed_data">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0-nullsafety.5/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="url_launcher">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="url_launcher_linux">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="url_launcher_macos">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="url_launcher_platform_interface">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_platform_interface-2.0.0-nullsafety.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="url_launcher_windows">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="uuid">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/uuid-3.0.0-nullsafety.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="vector_math">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.0-nullsafety.5/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="vm_service">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/vm_service-6.0.1-nullsafety.1/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/vm_service-5.5.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="watcher">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/watcher-0.9.7+15/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="web_socket_channel">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-1.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="webdriver">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/webdriver-3.0.0/lib" />
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/webdriver-2.1.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="webkit_inspection_protocol">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/webkit_inspection_protocol-0.7.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="win32">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/win32-2.0.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="xdg_directories">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/xdg_directories-0.2.0-nullsafety.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="yaml">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/yaml-2.2.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
</option>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-12.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-0.40.6/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/archive-2.0.13/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/archive-3.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/args-1.6.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.5.0-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.5.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.1.0-nullsafety.5/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/charcode-1.2.0-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/charcode-1.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/cli_util-0.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0-nullsafety.5/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/convert-2.1.1/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/coverage-0.14.2/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-2.1.5/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-3.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-1.0.2/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/device_info_platform_interface-2.0.0-nullsafety.2/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/ffi-1.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.0.0-nullsafety.4/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/glob-1.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/http_multi_server-2.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/http_parser-3.1.4/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/intl-0.17.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/io-0.3.4/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.3-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/json_rpc_2-2.2.2/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/logging-0.11.4/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.10-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.10/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.3.0-nullsafety.6/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.3.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/mime-0.9.7/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/mime-1.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/mockito-4.1.1/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/node_interop-1.2.1/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/node_io-1.1.1/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/node_preamble-1.4.13/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/package_config-1.9.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path-1.8.0-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path-1.8.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_platform_interface-2.0.0-nullsafety/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/pedantic-1.10.0-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/pedantic-1.10.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler_platform_interface-2.0.2/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/platform-3.0.0-nullsafety.4/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/platform-3.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-1.1.0-nullsafety.1/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/pool-1.5.0-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/process-4.0.0-nullsafety.4/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/process-4.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/pub_semver-1.4.4/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/shelf-0.7.5/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_packages_handler-2.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_static-0.2.9+1/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-0.2.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/source_map_stack_trace-2.1.0-nullsafety.4/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.10-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.0-nullsafety.4/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.1/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0-nullsafety.6/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/sync_http-0.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/sync_http-0.3.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/test-1.16.0-nullsafety.9/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/test_api-0.2.19-nullsafety.6/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/test_api-0.2.19/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/test_core-0.3.12-nullsafety.9/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0-nullsafety.5/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_platform_interface-2.0.0-nullsafety.1/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/uuid-3.0.0-nullsafety.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.0-nullsafety.5/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/vm_service-5.5.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/vm_service-6.0.1-nullsafety.1/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/watcher-0.9.7+15/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-1.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/webdriver-2.1.2/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/webdriver-3.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/webkit_inspection_protocol-0.7.4/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/win32-2.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/xdg_directories-0.2.0-nullsafety.1/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/yaml-2.2.1/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/packages/flutter/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/packages/flutter_driver/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/packages/flutter_test/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/packages/fuchsia_remote_debug_protocol/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/packages/integration_test/lib" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
5
.idea/libraries/Flutter_Plugins.xml
generated
5
.idea/libraries/Flutter_Plugins.xml
generated
@ -1,9 +1,6 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Flutter Plugins">
|
||||
<CLASSES>
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2" />
|
||||
<root url="file://$PROJECT_DIR$" />
|
||||
</CLASSES>
|
||||
<CLASSES />
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
|
43
CHANGELOG.md
43
CHANGELOG.md
@ -5,11 +5,11 @@
|
||||
- Added `allowUniversalAccessFromFileURLs` and `allowFileAccessFromFileURLs` WebView options also for iOS (also thanks to [liranhao](https://github.com/liranhao))
|
||||
- Added limited cookies support on iOS below 11.0 using JavaScript
|
||||
- Added `IOSCookieManager` class and `CookieManager.instance().ios.getAllCookies` iOS-specific method
|
||||
- Added `UserScript`, `UserScriptInjectionTime`, `ContentWorld`, `AndroidWebViewFeature`, `AndroidServiceWorkerController`, `AndroidServiceWorkerClient`, `ScreenshotConfiguration`, `IOSWKPDFConfiguration` classes
|
||||
- Added `UserScript`, `UserScriptInjectionTime`, `ContentWorld`, `AndroidWebViewFeature`, `AndroidServiceWorkerController`, `AndroidServiceWorkerClient`, `ScreenshotConfiguration`, `IOSWKPDFConfiguration`, `URLRequest` classes
|
||||
- Added `initialUserScripts` WebView option
|
||||
- Added `addUserScript`, `addUserScripts`, `removeUserScript`, `removeUserScripts`, `removeAllUserScripts`, `callAsyncJavaScript` WebView methods
|
||||
- Added `addUserScript`, `addUserScripts`, `removeUserScript`, `removeUserScripts`, `removeUserScriptsByGroupName`, `removeAllUserScripts`, `callAsyncJavaScript`, `isSecureContext` WebView methods
|
||||
- Added `contentWorld` argument to `evaluateJavascript` WebView method
|
||||
- Added `isDirectionalLockEnabled`, `mediaType`, `pageZoom`, `limitsNavigationsToAppBoundDomains`, `useOnNavigationResponse`, `applePayAPIEnabled`, `allowingReadAccessTo` iOS-specific WebView options
|
||||
- Added `isDirectionalLockEnabled`, `mediaType`, `pageZoom`, `limitsNavigationsToAppBoundDomains`, `useOnNavigationResponse`, `applePayAPIEnabled`, `allowingReadAccessTo`, `disableLongPressContextMenuOnLinks` iOS-specific WebView options
|
||||
- Added `handlesURLScheme`, `createPdf`, `createWebArchiveData` iOS-specific WebView methods
|
||||
- Added `iosOnNavigationResponse` and `iosShouldAllowDeprecatedTLS` iOS-specific WebView events
|
||||
- Added `iosAnimated` optional argument to `zoomBy` WebView method
|
||||
@ -18,6 +18,7 @@
|
||||
- Added `cssLinkHtmlTagAttributes` optional argument to `injectCSSFileFromUrl` WebView method
|
||||
- Added `iosAllowingReadAccessTo` iOS-specific optional argument to `loadUrl` WebView method
|
||||
- Added new iOS-specific attributes to `ShouldOverrideUrlLoadingRequest` and `CreateWindowRequest` classes
|
||||
- Added `toolbarTopTranslucent`, `toolbarTopTintColor`, `toolbarBottomTintColor`, `toolbarTopBarTintColor` ios-specific InAppBrowser options
|
||||
- Updated integration tests
|
||||
- Merge "Upgraded appcompat to 1.2.0-rc-02" [#465](https://github.com/pichillilorenzo/flutter_inappwebview/pull/465) (thanks to [andreidiaconu](https://github.com/andreidiaconu))
|
||||
- Merge "Added missing field 'headers' which returned by WebResourceResponse.toMap()" [#490](https://github.com/pichillilorenzo/flutter_inappwebview/pull/490) (thanks to [Doflatango](https://github.com/Doflatango))
|
||||
@ -47,14 +48,44 @@
|
||||
|
||||
- Minimum Flutter version required is `1.22.2` and Dart SDK `>=2.12.0-0 <3.0.0`
|
||||
- iOS Xcode version `>= 12`
|
||||
- Removed `debuggingEnabled` WebView option; on Android you should use now the `AndroidInAppWebViewController.setWebContentsDebuggingEnabled(bool debuggingEnabled)` static method; on iOS, debugging is always enabled
|
||||
- `allowUniversalAccessFromFileURLs` and `allowFileAccessFromFileURLs` WebView options moved from Android-specific options to cross-platform options
|
||||
- Added `callAsyncJavaScript` name to the list of javaScriptHandlerForbiddenNames
|
||||
- Changed `zoomBy` WebView method signature
|
||||
- Moved `saveWebArchive` WebView method from Android-specific to cross-platform
|
||||
- Moved `progressBar` InAppBroswer from Android-specific option to cross-platform option and renamed to `hideProgressBar`
|
||||
- Renamed `HttpAuthChallenge` to `URLAuthenticationChallenge`
|
||||
- Deleted `androidOnRequestFocus` event because it is never called
|
||||
- Updated `basicConstraints`, `subjectKeyIdentifier`, `authorityKeyIdentifier`, `certificatePolicies`, `cRLDistributionPoints`, `authorityInfoAccess` attributes type of `X509Certificate`
|
||||
- Updated "WebView.storyboard" for InAppBrowser iOS representation
|
||||
- Renamed `ShouldOverrideUrlLoadingAction` class to `NavigationActionPolicy`
|
||||
- Renamed `ProtectionSpace` class to `URLProtectionSpace`
|
||||
- Renamed `ProtectionSpaceHttpAuthCredentials` to `URLProtectionSpaceHttpAuthCredentials`
|
||||
- Renamed `CreateWindowRequest` class to `CreateWindowAction`
|
||||
- Renamed `initialUrl` to `initialUrlRequest` WebView attribute and made it of type `URLRequest`
|
||||
- Renamed `toolbarTop` InAppBrowser cross-platform option to `hideToolbarTop`
|
||||
- Renamed `toolbarBottom` InAppBrowser ios-specific option to `hideToolbarBottom`
|
||||
- Removed `debuggingEnabled` WebView option; on Android you should use now the `AndroidInAppWebViewController.setWebContentsDebuggingEnabled(bool debuggingEnabled)` static method; on iOS, debugging is always enabled
|
||||
- Removed `androidOnRequestFocus` event because it is never called
|
||||
- Removed `initialHeaders` WebView attribute. Use `URLRequest.headers` attribute
|
||||
- Removed `headers` argument from `loadFile` WebView method
|
||||
- Removed `headers` argument from `openFile` InAppBrowser method
|
||||
- Removed `headers` argument from `loadUrl` WebView method, renamed the `url` argument to `urlRequest` and made it of type `URLRequest`
|
||||
- Removed `headers` argument from `openFile` InAppBrowser method
|
||||
- Removed `headers` argument from `openUrl` InAppBrowser method, renamed the `url` argument to `urlRequest` and made it of type `URLRequest`
|
||||
- Removed `fallback` argument from `ChromeSafariBrowser` constructor. Check for availability of `ChromeSafariBrowser` if you want show one or the other.
|
||||
- Removed `scheme` argument from `onLoadResourceCustomScheme` WebView event. Use the `Uri url` parameter now.
|
||||
- Removed `ShouldOverrideUrlLoadingRequest` class and replaced with `NavigationAction`
|
||||
- Changed `zoomBy` WebView method signature
|
||||
- Changed type of `urlFile` argument of `injectCSSFileFromUrl` WebView method to `Uri`
|
||||
- Changed type of `urlFile` argument of `injectJavascriptFileFromUrl` WebView method to `Uri`
|
||||
- Changed return type of `getOriginalUrl` Android-specific WebView method to `Uri`
|
||||
- Changed return type of `getSafeBrowsingPrivacyPolicyUrl` Android-specific WebView method to `Uri`
|
||||
- Changed type of `url` argument of `onLoadStart`, `onLoadStop`, `onLoadError`, `onLoadHttpError`, `onLoadResourceCustomScheme`, `onUpdateVisitedHistory`, `onPrint`, `onPageCommitVisible`, `androidOnSafeBrowsingHit`, `androidOnRenderProcessUnresponsive`, `androidOnRenderProcessResponsive`, `androidOnFormResubmission`, `androidOnReceivedTouchIconUrl` WebView events to `Uri`
|
||||
- Changed type of `baseUrl` and `androidHistoryUrl` arguments of `loadData` WebView method and `openData` InAppBrowser method
|
||||
- Changed `openUrl` InAppBrowser method to `openUrlRequest`
|
||||
- Changed type of `url` argument of `openWithSystemBrowser` InAppBrowser method to `Uri`
|
||||
- Changed all InAppBrowser color options type from `String` to `Color`
|
||||
- Changed all ChromeSafariBrowser color options type from `String` to `Color`
|
||||
- Updated attributes of `ShouldOverrideUrlLoadingRequest`, `ServerTrustChallenge` and `ClientCertChallenge` classes
|
||||
- Changed type of `url` attribute to `Uri` for `JsAlertRequest`, `JsAlertConfirm`, `JsPromptRequest` classes
|
||||
|
||||
## 4.0.0+4
|
||||
|
||||
|
200
README.md
200
README.md
@ -29,8 +29,8 @@ Also, check the [example/integration_test/webview_flutter_test.dart](https://git
|
||||
|
||||
## Articles/Resources
|
||||
|
||||
- [InAppWebView: The Real Power of WebViews in Flutter](https://medium.com/flutter-community/inappwebview-the-real-power-of-webviews-in-flutter-c6d52374209d?source=friends_link&sk=cb74487219bcd85e610a670ee0b447d0)
|
||||
- [Creating a Full-Featured Browser using WebViews in Flutter](https://medium.com/flutter-community/creating-a-full-featured-browser-using-webviews-in-flutter-9c8f2923c574?source=friends_link&sk=55fc8267f351082aa9e73ced546f6bcb)
|
||||
- [InAppWebView: The Real Power of WebViews in Flutter](https://medium.com/flutter-community/inappwebview-the-real-power-of-webviews-in-flutter-c6d52374209d?source=friends_link&sk=cb74487219bcd85e610a670ee0b447d0) (valid for plugin version 4.0.0)
|
||||
- [Creating a Full-Featured Browser using WebViews in Flutter](https://medium.com/flutter-community/creating-a-full-featured-browser-using-webviews-in-flutter-9c8f2923c574?source=friends_link&sk=55fc8267f351082aa9e73ced546f6bcb) (valid for plugin version 4.0.0)
|
||||
- [Flutter Browser App: A Full-Featured Mobile Browser App (such as the Google Chrome mobile browser) created using Flutter and the features offered by the flutter_inappwebview plugin](https://github.com/pichillilorenzo/flutter_browser_app)
|
||||
|
||||
## Requirements
|
||||
@ -323,24 +323,31 @@ class _MyAppState extends State<MyApp> {
|
||||
decoration:
|
||||
BoxDecoration(border: Border.all(color: Colors.blueAccent)),
|
||||
child: InAppWebView(
|
||||
initialUrl: "https://flutter.dev/",
|
||||
initialHeaders: {},
|
||||
initialUrlRequest: URLRequest(
|
||||
url: Uri.parse("https://flutter.dev/")
|
||||
),
|
||||
initialOptions: InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
|
||||
)
|
||||
),
|
||||
ios: IOSInAppWebViewOptions(
|
||||
|
||||
),
|
||||
android: AndroidInAppWebViewOptions(
|
||||
useHybridComposition: true
|
||||
)
|
||||
),
|
||||
onWebViewCreated: (InAppWebViewController controller) {
|
||||
webView = controller;
|
||||
},
|
||||
onLoadStart: (controller, url) {
|
||||
setState(() {
|
||||
this.url = url ?? '';
|
||||
this.url = url?.toString() ?? '';
|
||||
});
|
||||
},
|
||||
onLoadStop: (controller, url) async {
|
||||
setState(() {
|
||||
this.url = url ?? '';
|
||||
this.url = url?.toString() ?? '';
|
||||
});
|
||||
},
|
||||
onProgressChanged: (controller, progress) {
|
||||
@ -354,19 +361,19 @@ class _MyAppState extends State<MyApp> {
|
||||
ButtonBar(
|
||||
alignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
child: Icon(Icons.arrow_back),
|
||||
onPressed: () {
|
||||
webView?.goBack();
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
child: Icon(Icons.arrow_forward),
|
||||
onPressed: () {
|
||||
webView?.goForward();
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
child: Icon(Icons.refresh),
|
||||
onPressed: () {
|
||||
webView?.reload();
|
||||
@ -395,8 +402,8 @@ Screenshots:
|
||||
##### `InAppWebViewController` Cross-platform methods
|
||||
|
||||
* `addJavaScriptHandler({required String handlerName, required JavaScriptHandlerCallback callback})`: Adds a JavaScript message handler callback that listen to post messages sent from JavaScript by the handler with name `handlerName`.
|
||||
* `addUserScript(UserScript userScript)`: Injects the specified `userScript` into the webpage’s content.
|
||||
* `addUserScripts(List<UserScript> userScripts)`: Injects the `userScripts` into the webpage’s content.
|
||||
* `addUserScript({required UserScript userScript})`: Injects the specified `userScript` into the webpage’s content.
|
||||
* `addUserScripts({required List<UserScript> userScripts})`: Injects the `userScripts` into the webpage’s content.
|
||||
* `callAsyncJavaScript({required String functionBody, Map<String, dynamic> arguments = const <String, dynamic>{}, ContentWorld? contentWorld})`: Executes the specified string as an asynchronous JavaScript function.
|
||||
* `canGoBackOrForward({required int steps})`: Returns a boolean value indicating whether the WebView can go back or forward the given number of steps. Steps is negative if backward and positive if forward.
|
||||
* `canGoBack`: Returns a boolean value indicating whether the WebView can move backward.
|
||||
@ -433,26 +440,28 @@ Screenshots:
|
||||
* `injectCSSFileFromAsset({required String assetFilePath})`: Injects a CSS file into the WebView from the flutter assets directory.
|
||||
* `injectCSSFileFromUrl({required String urlFile, CSSLinkHtmlTagAttributes? cssLinkHtmlTagAttributes})`: Injects an external CSS file into the WebView from a defined url.
|
||||
* `injectJavascriptFileFromAsset({required String assetFilePath})`: Injects a JavaScript file into the WebView from the flutter assets directory.
|
||||
* `injectJavascriptFileFromUrl({required String urlFile, ScriptHtmlTagAttributes? scriptHtmlTagAttributes})`: Injects an external JavaScript file into the WebView from a defined url.
|
||||
* `injectJavascriptFileFromUrl({required Uri urlFile, ScriptHtmlTagAttributes? scriptHtmlTagAttributes})`: Injects an external JavaScript file into the WebView from a defined url.
|
||||
* `isLoading`: Check if the WebView instance is in a loading state.
|
||||
* `loadData({required String data, String mimeType = "text/html", String encoding = "utf8", String baseUrl = "about:blank", String androidHistoryUrl = "about:blank"})`: Loads the given data into this WebView.
|
||||
* `loadFile({required String assetFilePath, Map<String, String> headers = const {}})`: Loads the given `assetFilePath` with optional headers specified as a map from name to value.
|
||||
* `loadUrl({required String url, Map<String, String> headers = const {}, String? iosAllowingReadAccessTo})`: Loads the given url with optional headers specified as a map from name to value.
|
||||
* `isSecureContext`: Indicates whether the webpage context is capable of using features that require secure contexts.
|
||||
* `loadData({required String data, String mimeType = "text/html", String encoding = "utf8", Uri? baseUrl, Uri? androidHistoryUrl})`: Loads the given data into this WebView.
|
||||
* `loadFile({required String assetFilePath})`: Loads the given `assetFilePath` with optional headers specified as a map from name to value.
|
||||
* `loadUrl({required URLRequest urlRequest, Uri? iosAllowingReadAccessTo})`: Loads the given url with optional headers specified as a map from name to value.
|
||||
* `pauseTimers`: On Android, it pauses all layout, parsing, and JavaScript timers for all WebViews. This is a global requests, not restricted to just this WebView. This can be useful if the application has been paused. On iOS, it is restricted to just this WebView.
|
||||
* `postUrl({required String url, required Uint8List postData})`: Loads the given url with postData using `POST` method into this WebView.
|
||||
* `postUrl({required Uri url, required Uint8List postData})`: Loads the given url with postData using `POST` method into this WebView.
|
||||
* `printCurrentPage`: Prints the current page.
|
||||
* `reload`: Reloads the WebView.
|
||||
* `removeAllUserScripts()`: Removes all the user scripts from the webpage’s content.
|
||||
* `removeJavaScriptHandler({required String handlerName})`: Removes a JavaScript message handler previously added with the `addJavaScriptHandler()` associated to `handlerName` key.
|
||||
* `removeUserScript(UserScript userScript)`: Removes the specified `userScript` from the webpage’s content.
|
||||
* `removeUserScripts(List<UserScript> userScripts)`: Removes the `userScripts` from the webpage’s content.
|
||||
* `removeUserScript({required UserScript userScript})`: Removes the specified `userScript` from the webpage’s content.
|
||||
* `removeUserScriptsByGroupName({required String groupName})`: Removes all the `UserScript`s with `groupName` as group name from the webpage’s content.
|
||||
* `removeUserScripts({required List<UserScript> userScripts})`: Removes the `userScripts` from the webpage’s content.
|
||||
* `requestFocusNodeHref`: Requests the anchor or image element URL at the last tapped point.
|
||||
* `requestImageRef`: Requests the URL of the image last touched by the user.
|
||||
* `resumeTimers`: On Android, it resumes all layout, parsing, and JavaScript timers for all WebViews. This will resume dispatching all timers. On iOS, it resumes all layout, parsing, and JavaScript timers to just this WebView.
|
||||
* `saveWebArchive({required String filePath, bool autoname = false})`: Saves the current view as a web archive.
|
||||
* `scrollBy({required int x, required int y, bool animated = false})`: Moves the scrolled position of the WebView.
|
||||
* `scrollTo({required int x, required int y, bool animated = false})`: Scrolls the WebView to the position.
|
||||
* `setContextMenu(ContextMenu contextMenu)`: Sets or updates the WebView context menu to be used next time it will appear.
|
||||
* `setContextMenu(ContextMenu? contextMenu)`: Sets or updates the WebView context menu to be used next time it will appear.
|
||||
* `setOptions({required InAppWebViewGroupOptions options})`: Sets the WebView options with the new options and evaluates them.
|
||||
* `stopLoading`: Stops the WebView from loading.
|
||||
* `takeScreenshot({ScreenshotConfiguration? screenshotConfiguration})`: Takes a screenshot (in PNG format) of the WebView's visible viewport and returns a `Uint8List`. Returns `null` if it wasn't be able to take it.
|
||||
@ -611,6 +620,7 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
|
||||
* `minimumLogicalFontSize`: Sets the minimum logical font size. The default is `8`.
|
||||
* `mixedContentMode`: Configures the WebView's behavior when a secure origin attempts to load a resource from an insecure origin.
|
||||
* `needInitialFocus`: Tells the WebView whether it needs to set a node. The default value is `true`.
|
||||
* `networkAvailable`: Informs WebView of the network state.
|
||||
* `offscreenPreRaster`: Sets whether this WebView should raster tiles when it is offscreen but attached to a window.
|
||||
* `overScrollMode`: Sets the WebView's over-scroll mode. The default value is `AndroidOverScrollMode.OVER_SCROLL_IF_CONTENT_SCROLLS`.
|
||||
* `regexToCancelSubFramesLoading`: Regular expression used by `shouldOverrideUrlLoading` event to cancel navigation for frames that are not the main frame. If the url request of a subframe matches the regular expression, then the request of that subframe is canceled.
|
||||
@ -649,6 +659,7 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
|
||||
* `contentInsetAdjustmentBehavior`: Configures how safe area insets are added to the adjusted content inset. The default value is `IOSUIScrollViewContentInsetAdjustmentBehavior.NEVER`.
|
||||
* `dataDetectorTypes`: Specifying a dataDetectoryTypes value adds interactivity to web content that matches the value.
|
||||
* `decelerationRate`: A `IOSUIScrollViewDecelerationRate` value that determines the rate of deceleration after the user lifts their finger. The default value is `IOSUIScrollViewDecelerationRate.NORMAL`.
|
||||
* `disableLongPressContextMenuOnLinks`: Set to `true` to disable the context menu (copy, select, etc.) that is shown when the user emits a long press event on a HTML link.
|
||||
* `disallowOverScroll`: 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`.
|
||||
* `enableViewportScale`: Set to `true` to allow a viewport meta tag to either disable or restrict the range of user scaling. The default value is `false`.
|
||||
* `ignoresViewportScaleLimits`: Set to `true` if you want that the WebView should always allow scaling of the webpage, regardless of the author's intent.
|
||||
@ -664,7 +675,7 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
|
||||
* `selectionGranularity`: The level of granularity with which the user can interactively select content in the web view.
|
||||
* `sharedCookiesEnabled`: Set `true` if shared cookies from `HTTPCookieStorage.shared` should used for every load request in the WebView.
|
||||
* `suppressesIncrementalRendering`: Set to `true` if you want the WebView suppresses content rendering until it is fully loaded into memory. The default value is `false`.
|
||||
* `useOnNavigationResponse`: Set to `true` to be able to listen at the `iosOnNavigationResponse` event. The default value is `false`.
|
||||
* `useOnNavigationResponse`: Set to `true` to be able to listen to the `iosOnNavigationResponse` event. The default value is `false`.
|
||||
|
||||
#### `InAppWebView` Events
|
||||
|
||||
@ -814,25 +825,32 @@ class _MyAppState extends State<MyApp> {
|
||||
decoration:
|
||||
BoxDecoration(border: Border.all(color: Colors.blueAccent)),
|
||||
child: InAppWebView(
|
||||
initialUrl: "https://flutter.dev/",
|
||||
initialUrlRequest: URLRequest(
|
||||
url: Uri.parse("https://flutter.dev/")
|
||||
),
|
||||
contextMenu: contextMenu,
|
||||
initialHeaders: {},
|
||||
initialOptions: InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
|
||||
)
|
||||
),
|
||||
ios: IOSInAppWebViewOptions(
|
||||
|
||||
),
|
||||
android: AndroidInAppWebViewOptions(
|
||||
useHybridComposition: true
|
||||
)
|
||||
),
|
||||
onWebViewCreated: (InAppWebViewController controller) {
|
||||
webView = controller;
|
||||
},
|
||||
onLoadStart: (controller, url) {
|
||||
setState(() {
|
||||
this.url = url ?? '';
|
||||
this.url = url?.toString() ?? '';
|
||||
});
|
||||
},
|
||||
onLoadStop: (controller, url) async {
|
||||
setState(() {
|
||||
this.url = url ?? '';
|
||||
this.url = url?.toString() ?? '';
|
||||
});
|
||||
},
|
||||
onProgressChanged: (controller, progress) {
|
||||
@ -846,19 +864,19 @@ class _MyAppState extends State<MyApp> {
|
||||
ButtonBar(
|
||||
alignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
child: Icon(Icons.arrow_back),
|
||||
onPressed: () {
|
||||
webView?.goBack();
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
child: Icon(Icons.arrow_forward),
|
||||
onPressed: () {
|
||||
webView?.goForward();
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
child: Icon(Icons.refresh),
|
||||
onPressed: () {
|
||||
webView?.reload();
|
||||
@ -922,7 +940,9 @@ class _MyAppState extends State<MyApp> {
|
||||
super.initState();
|
||||
|
||||
headlessWebView = new HeadlessInAppWebView(
|
||||
initialUrl: "https://flutter.dev/",
|
||||
initialUrlRequest: URLRequest(
|
||||
url: Uri.parse("https://flutter.dev/")
|
||||
),
|
||||
initialOptions: InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
|
||||
@ -937,19 +957,19 @@ class _MyAppState extends State<MyApp> {
|
||||
onLoadStart: (controller, url) async {
|
||||
print("onLoadStart $url");
|
||||
setState(() {
|
||||
this.url = url ?? '';
|
||||
this.url = url?.toString() ?? '';
|
||||
});
|
||||
},
|
||||
onLoadStop: (controller, url) async {
|
||||
print("onLoadStop $url");
|
||||
setState(() {
|
||||
this.url = url ?? '';
|
||||
this.url = url?.toString() ?? '';
|
||||
});
|
||||
},
|
||||
onUpdateVisitedHistory: (controller, url, androidIsReload) {
|
||||
print("onUpdateVisitedHistory $url");
|
||||
setState(() {
|
||||
this.url = url ?? '';
|
||||
this.url = url?.toString() ?? '';
|
||||
});
|
||||
},
|
||||
);
|
||||
@ -976,7 +996,7 @@ class _MyAppState extends State<MyApp> {
|
||||
"CURRENT URL\n${(url.length > 50) ? url.substring(0, 50) + "..." : url}"),
|
||||
),
|
||||
Center(
|
||||
child: RaisedButton(
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
await headlessWebView?.dispose();
|
||||
await headlessWebView?.run();
|
||||
@ -984,7 +1004,7 @@ class _MyAppState extends State<MyApp> {
|
||||
child: Text("Run HeadlessInAppWebView")),
|
||||
),
|
||||
Center(
|
||||
child: RaisedButton(
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
await headlessWebView?.webViewController.evaluateJavascript(source: """console.log('Here is the message!');""");
|
||||
@ -995,7 +1015,7 @@ class _MyAppState extends State<MyApp> {
|
||||
child: Text("Send console.log message")),
|
||||
),
|
||||
Center(
|
||||
child: RaisedButton(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
headlessWebView?.dispose();
|
||||
},
|
||||
@ -1054,9 +1074,9 @@ class MyInAppBrowser extends InAppBrowser {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ShouldOverrideUrlLoadingAction> shouldOverrideUrlLoading(ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async {
|
||||
print("\n\n override ${shouldOverrideUrlLoadingRequest.url}\n\n");
|
||||
return ShouldOverrideUrlLoadingAction.ALLOW;
|
||||
Future<NavigationActionPolicy?>? shouldOverrideUrlLoading(NavigationAction navigationAction) async {
|
||||
print("\n\n override ${navigationAction.request.url}\n\n");
|
||||
return NavigationActionPolicy.ALLOW;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -1066,7 +1086,7 @@ class MyInAppBrowser extends InAppBrowser {
|
||||
"ms ---> duration: " +
|
||||
response.duration.toString() +
|
||||
"ms " +
|
||||
(response.url ?? ''));
|
||||
(response.url?.toString() ?? ''));
|
||||
}
|
||||
|
||||
@override
|
||||
@ -1074,7 +1094,7 @@ class MyInAppBrowser extends InAppBrowser {
|
||||
print("""
|
||||
console output:
|
||||
message: ${consoleMessage.message}
|
||||
messageLevel: ${consoleMessage.messageLevel?.toValue()}
|
||||
messageLevel: ${consoleMessage.messageLevel.toValue()}
|
||||
""");
|
||||
}
|
||||
}
|
||||
@ -1106,7 +1126,7 @@ class _MyAppState extends State<MyApp> {
|
||||
title: const Text('InAppBrowser Example'),
|
||||
),
|
||||
body: Center(
|
||||
child: RaisedButton(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
widget.browser.openFile(
|
||||
assetFilePath: "assets/index.html",
|
||||
@ -1136,10 +1156,10 @@ Screenshots:
|
||||
|
||||
#### `InAppBrowser` Methods
|
||||
|
||||
* `open({String url = "about:blank", Map<String, String> headers = const {}, InAppBrowserClassOptions options})`: Opens an `url` in a new `InAppBrowser` instance.
|
||||
* `openFile({required String assetFilePath, Map<String, String> headers = const {}, InAppBrowserClassOptions options})`: Opens the given `assetFilePath` file in a new `InAppBrowser` instance. The other arguments are the same of `InAppBrowser.open`.
|
||||
* `openData({required String data, String mimeType = "text/html", String encoding = "utf8", String baseUrl = "about:blank", String historyUrl = "about:blank", InAppBrowserClassOptions options})`: Opens a new `InAppBrowser` instance with `data` as a content, using `baseUrl` as the base URL for it.
|
||||
* `openWithSystemBrowser({required String url})`: This is a static method that opens an `url` in the system browser. You wont be able to use the `InAppBrowser` methods here!
|
||||
* `openUrlRequest({required URLRequest urlRequest, InAppBrowserClassOptions? options})`: Opens an `url` in a new `InAppBrowser` instance.
|
||||
* `openFile({required String assetFilePath, InAppBrowserClassOptions? options})`: Opens the given `assetFilePath` file in a new `InAppBrowser` instance. The other arguments are the same of `InAppBrowser.open`.
|
||||
* `openData({required String data, String mimeType = "text/html", String encoding = "utf8", Uri? baseUrl, Uri? androidHistoryUrl, InAppBrowserClassOptions? options})`: Opens a new `InAppBrowser` instance with `data` as a content, using `baseUrl` as the base URL for it.
|
||||
* `openWithSystemBrowser({required Uri url})`: This is a static method that opens an `url` in the system browser. You wont be able to use the `InAppBrowser` methods here!
|
||||
* `show`: Displays an `InAppBrowser` window that was opened hidden. Calling this has no effect if the `InAppBrowser` was already visible.
|
||||
* `hide`: Hides the `InAppBrowser` window. Calling this has no effect if the `InAppBrowser` was already hidden.
|
||||
* `close`: Closes the `InAppBrowser` window.
|
||||
@ -1157,25 +1177,28 @@ Specific options of the `InAppBrowser` class are:
|
||||
|
||||
* `hidden`: 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`.
|
||||
* `hideUrlBar`: Set to `true` to hide the url bar on the toolbar at the top. The default value is `false`.
|
||||
* `hideProgressBar`: Set to `true` to hide the progress bar when the WebView is loading a page. The default value is `false`.
|
||||
* `hideToolbarTop`: Set to `true` to hide the toolbar at the top of the WebView. The default value is `false`.
|
||||
* `toolbarTopBackgroundColor`: Set the custom background color of the toolbar at the top.
|
||||
* `toolbarTop`: Set to `false` to hide the toolbar at the top of the WebView. The default value is `true`.
|
||||
|
||||
##### `InAppBrowser` Android-specific options
|
||||
|
||||
* `closeOnCannotGoBack`: 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`.
|
||||
* `hideTitleBar`: Set to `true` if you want the title should be displayed. The default value is `false`.
|
||||
* `progressBar`: Set to `false` to hide the progress bar at the bottom of the toolbar at the top. The default value is `true`.
|
||||
* `toolbarTopFixedTitle`: Set the action bar's title.
|
||||
|
||||
##### `InAppBrowser` iOS-specific options
|
||||
|
||||
* `closeButtonCaption`: Set the custom text for the close button.
|
||||
* `closeButtonColor`: Set the custom color for the close button.
|
||||
* `hideToolbarBottom`: Set to `true` to hide the toolbar at the bottom of the WebView. The default value is `false`.
|
||||
* `presentationStyle`: Set the custom modal presentation style when presenting the WebView. The default value is `IOSUIModalPresentationStyle.FULL_SCREEN`.
|
||||
* `spinner`: Set to `false` to hide the spinner when the WebView is loading a page. The default value is `true`.
|
||||
* `toolbarBottomBackgroundColor`: Set the custom background color of the toolbar at the bottom.
|
||||
* `toolbarBottomTintColor`: Set the tint color to apply to the bar button items.
|
||||
* `toolbarBottomTranslucent`: Set to `true` to set the toolbar at the bottom translucent. The default value is `true`.
|
||||
* `toolbarBottom`: Set to `false` to hide the toolbar at the bottom of the WebView. The default value is `true`.
|
||||
* `toolbarTopTranslucent`: Set to `true` to set the toolbar at the top translucent. The default value is `true`.
|
||||
* `toolbarTopBarTintColor`: Set the tint color to apply to the navigation bar background.
|
||||
* `toolbarTopTintColor`: Set the tint color to apply to the navigation items and bar button items.
|
||||
* `transitionStyle`: Set to the custom transition style when presenting the WebView. The default value is `IOSUIModalTransitionStyle.COVER_VERTICAL`.
|
||||
|
||||
#### `InAppBrowser` Events
|
||||
@ -1192,8 +1215,6 @@ Specific events of the `InAppBrowser` class are:
|
||||
|
||||
If you want to use the `ChromeSafariBrowser` class on Android 11+ you need to specify your app querying for `android.support.customtabs.action.CustomTabsService` in your `AndroidManifest.xml` (you can read more about it here: https://developers.google.com/web/android/custom-tabs/best-practices#applications_targeting_android_11_api_level_30_or_above).
|
||||
|
||||
You can initialize the `ChromeSafariBrowser` instance with an `InAppBrowser` fallback instance.
|
||||
|
||||
Create a Class that extends the `ChromeSafariBrowser` Class in order to override the callbacks to manage the browser events. Example:
|
||||
```dart
|
||||
import 'dart:io';
|
||||
@ -1227,8 +1248,6 @@ class MyInAppBrowser extends InAppBrowser {
|
||||
|
||||
class MyChromeSafariBrowser extends ChromeSafariBrowser {
|
||||
|
||||
MyChromeSafariBrowser(browserFallback) : super(bFallback: browserFallback);
|
||||
|
||||
@override
|
||||
void onOpened() {
|
||||
print("ChromeSafari browser opened");
|
||||
@ -1254,7 +1273,7 @@ Future main() async {
|
||||
}
|
||||
|
||||
class MyApp extends StatefulWidget {
|
||||
final ChromeSafariBrowser browser = new MyChromeSafariBrowser(new MyInAppBrowser());
|
||||
final ChromeSafariBrowser browser = new MyChromeSafariBrowser();
|
||||
|
||||
@override
|
||||
_MyAppState createState() => new _MyAppState();
|
||||
@ -1285,10 +1304,10 @@ class _MyAppState extends State<MyApp> {
|
||||
title: const Text('ChromeSafariBrowser Example'),
|
||||
),
|
||||
body: Center(
|
||||
child: RaisedButton(
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
await widget.browser.open(
|
||||
url: "https://flutter.dev/",
|
||||
url: Uri.parse("https://flutter.dev/"),
|
||||
options: ChromeSafariBrowserClassOptions(
|
||||
android: AndroidChromeCustomTabsOptions(addDefaultShareMenuItem: false),
|
||||
ios: IOSSafariOptions(barCollapsingEnabled: true)));
|
||||
@ -1316,7 +1335,7 @@ Screenshots:
|
||||
* `addMenuItems`: Adds a list of `ChromeSafariBrowserMenuItem` to the menu.
|
||||
* `close`: Closes the `ChromeSafariBrowser` instance.
|
||||
* `isOpened`: Returns `true` if the `ChromeSafariBrowser` instance is opened, otherwise `false`.
|
||||
* `open({required String url, ChromeSafariBrowserClassOptions options, Map<String, String> headersFallback = const {}, InAppBrowserClassOptions optionsFallback})`: Opens an `url` in a new `ChromeSafariBrowser` instance.
|
||||
* `open({required Uri url, ChromeSafariBrowserClassOptions? options})`: Opens an `url` in a new `ChromeSafariBrowser` instance.
|
||||
* `static isAvailable`: On Android, returns `true` if Chrome Custom Tabs is available. On iOS, returns `true` if SFSafariViewController is available. Otherwise returns `false`.
|
||||
|
||||
#### `ChromeSafariBrowser` options
|
||||
@ -1376,30 +1395,31 @@ Future main() async {
|
||||
title: const Text('InAppWebView Example'),
|
||||
),
|
||||
body: Container(
|
||||
child: Column(children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: InAppWebView(
|
||||
initialUrl: "http://localhost:8080/assets/index.html",
|
||||
initialHeaders: {},
|
||||
initialOptions: InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
child: Column(children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: InAppWebView(
|
||||
initialUrlRequest: URLRequest(
|
||||
url: Uri.parse("http://localhost:8080/assets/index.html")
|
||||
),
|
||||
initialOptions: InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
|
||||
)
|
||||
)
|
||||
),
|
||||
onWebViewCreated: (controller) {
|
||||
|
||||
},
|
||||
onLoadStart: (controller, url) {
|
||||
|
||||
},
|
||||
onLoadStop: (controller, url) {
|
||||
|
||||
},
|
||||
),
|
||||
onWebViewCreated: (controller) {
|
||||
|
||||
},
|
||||
onLoadStart: (controller, url) {
|
||||
|
||||
},
|
||||
onLoadStop: (controller, url) {
|
||||
|
||||
},
|
||||
),
|
||||
),
|
||||
)]
|
||||
)
|
||||
)]
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -1426,11 +1446,11 @@ On iOS, it is implemented using [WKHTTPCookieStore](https://developer.apple.com/
|
||||
#### `CookieManager` methods
|
||||
|
||||
* `instance`: Gets the cookie manager shared instance.
|
||||
* `setCookie({required String url, required String name, required String value, String? domain, String path = "/", int? expiresDate, int? maxAge, bool? isSecure, bool? isHttpOnly, HTTPCookieSameSitePolicy? sameSite, InAppWebViewController? iosBelow11WebViewController})`: 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.
|
||||
* `getCookies({required String url, InAppWebViewController? iosBelow11WebViewController})`: Gets all the cookies for the given `url`.
|
||||
* `getCookie({required String url, required String name, InAppWebViewController? iosBelow11WebViewController})`: Gets a cookie by its `name` for the given `url`.
|
||||
* `deleteCookie({required String url, required String name, String domain = "", String path = "/", InAppWebViewController? iosBelow11WebViewController})`: Removes a cookie by its `name` for the given `url`, `domain` and `path`.
|
||||
* `deleteCookies({required String url, String domain = "", String path = "/", InAppWebViewController? iosBelow11WebViewController})`: Removes all cookies for the given `url`, `domain` and `path`.
|
||||
* `setCookie({required Uri url, required String name, required String value, String? domain, String path = "/", int? expiresDate, int? maxAge, bool? isSecure, bool? isHttpOnly, HTTPCookieSameSitePolicy? sameSite, InAppWebViewController? iosBelow11WebViewController})`: 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.
|
||||
* `getCookies({required Uri url, InAppWebViewController? iosBelow11WebViewController})`: Gets all the cookies for the given `url`.
|
||||
* `getCookie({required Uri url, required String name, InAppWebViewController? iosBelow11WebViewController})`: Gets a cookie by its `name` for the given `url`.
|
||||
* `deleteCookie({required Uri url, required String name, String domain = "", String path = "/", InAppWebViewController? iosBelow11WebViewController})`: Removes a cookie by its `name` for the given `url`, `domain` and `path`.
|
||||
* `deleteCookies({required Uri url, String domain = "", String path = "/", InAppWebViewController? iosBelow11WebViewController})`: Removes all cookies for the given `url`, `domain` and `path`.
|
||||
* `deleteAllCookies()`: Removes all cookies.
|
||||
|
||||
#### `CookieManager` iOS-specific methods
|
||||
@ -1449,10 +1469,10 @@ On Android, this class has a custom implementation using `android.database.sqlit
|
||||
|
||||
* `instance`: Gets the database shared instance.
|
||||
* `getAllAuthCredentials`: Gets a map list of all HTTP auth credentials saved.
|
||||
* `getHttpAuthCredentials({required ProtectionSpace protectionSpace})`: Gets all the HTTP auth credentials saved for that `protectionSpace`.
|
||||
* `setHttpAuthCredential({required ProtectionSpace protectionSpace, required HttpAuthCredential credential})`: Saves an HTTP auth `credential` for that `protectionSpace`.
|
||||
* `removeHttpAuthCredential({required ProtectionSpace protectionSpace, required HttpAuthCredential credential})`: Removes an HTTP auth `credential` for that `protectionSpace`.
|
||||
* `removeHttpAuthCredentials({required ProtectionSpace protectionSpace})`: Removes all the HTTP auth credentials saved for that `protectionSpace`.
|
||||
* `getHttpAuthCredentials({required URLProtectionSpace protectionSpace})`: Gets all the HTTP auth credentials saved for that `protectionSpace`.
|
||||
* `setHttpAuthCredential({required URLProtectionSpace protectionSpace, required URLCredential credential})`: Saves an HTTP auth `credential` for that `protectionSpace`.
|
||||
* `removeHttpAuthCredential({required URLProtectionSpace protectionSpace, required URLCredential credential})`: Removes an HTTP auth `credential` for that `protectionSpace`.
|
||||
* `removeHttpAuthCredentials({required URLProtectionSpace protectionSpace})`: Removes all the HTTP auth credentials saved for that `protectionSpace`.
|
||||
* `clearAllAuthCredentials()`: Removes all the HTTP auth credentials saved in the database.
|
||||
|
||||
### `WebStorageManager` class
|
||||
|
@ -2,9 +2,9 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.pichillilorenzo.flutter_inappwebview">
|
||||
<application>
|
||||
<activity android:theme="@style/AppTheme" android:name="com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity" android:configChanges="orientation|screenSize"></activity>
|
||||
<activity android:theme="@style/ThemeTransparent" android:name="com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ChromeCustomTabsActivity" android:configChanges="orientation|screenSize"></activity>
|
||||
<receiver android:name="com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ActionBroadcastReceiver" />
|
||||
<activity android:theme="@style/AppTheme" android:name="com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserActivity" android:configChanges="orientation|screenSize"></activity>
|
||||
<activity android:theme="@style/ThemeTransparent" android:name="com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ChromeCustomTabsActivity" android:configChanges="orientation|screenSize"></activity>
|
||||
<receiver android:name="com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ActionBroadcastReceiver" />
|
||||
<meta-data
|
||||
android:name="io.flutter.embedded_views_preview"
|
||||
android:value="true" />
|
||||
|
@ -1,106 +0,0 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ChromeCustomTabsActivity;
|
||||
import com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.CustomTabActivityHelper;
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserOptions;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.flutter.plugin.common.BinaryMessenger;
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
|
||||
public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandler {
|
||||
|
||||
public MethodChannel channel;
|
||||
|
||||
protected static final String LOG_TAG = "ChromeBrowserManager";
|
||||
|
||||
public ChromeSafariBrowserManager(BinaryMessenger messenger) {
|
||||
channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_chromesafaribrowser");
|
||||
channel.setMethodCallHandler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMethodCall(final MethodCall call, final MethodChannel.Result result) {
|
||||
final Activity activity = Shared.activity;
|
||||
final String uuid = (String) call.argument("uuid");
|
||||
|
||||
switch (call.method) {
|
||||
case "open":
|
||||
{
|
||||
String url = (String) call.argument("url");
|
||||
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
|
||||
List<HashMap<String, Object>> menuItemList = (List<HashMap<String, Object>>) call.argument("menuItemList");
|
||||
String uuidFallback = (String) call.argument("uuidFallback");
|
||||
Map<String, String> headersFallback = (Map<String, String>) call.argument("headersFallback");
|
||||
HashMap<String, Object> optionsFallback = (HashMap<String, Object>) call.argument("optionsFallback");
|
||||
HashMap<String, Object> contextMenuFallback = (HashMap<String, Object>) call.argument("contextMenuFallback");
|
||||
Integer windowIdFallback = (Integer) call.argument("windowIdFallback");
|
||||
open(activity, uuid, url, options, menuItemList, uuidFallback, headersFallback, optionsFallback, contextMenuFallback, windowIdFallback, result);
|
||||
}
|
||||
break;
|
||||
case "isAvailable":
|
||||
result.success(CustomTabActivityHelper.isAvailable(activity));
|
||||
break;
|
||||
default:
|
||||
result.notImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
public void open(Activity activity, String uuid, String url, HashMap<String, Object> options, List<HashMap<String, Object>> menuItemList, String uuidFallback,
|
||||
Map<String, String> headersFallback, HashMap<String, Object> optionsFallback, HashMap<String, Object> contextMenuFallback, Integer windowIdFallback,
|
||||
MethodChannel.Result result) {
|
||||
|
||||
Intent intent = null;
|
||||
Bundle extras = new Bundle();
|
||||
extras.putString("fromActivity", activity.getClass().getName());
|
||||
extras.putString("url", url);
|
||||
extras.putBoolean("isData", false);
|
||||
extras.putString("uuid", uuid);
|
||||
extras.putSerializable("options", options);
|
||||
extras.putSerializable("menuItemList", (Serializable) menuItemList);
|
||||
|
||||
extras.putSerializable("headers", (Serializable) headersFallback);
|
||||
extras.putSerializable("contextMenu", (Serializable) contextMenuFallback);
|
||||
|
||||
extras.putInt("windowId", windowIdFallback != null ? windowIdFallback : -1);
|
||||
|
||||
if (CustomTabActivityHelper.isAvailable(activity)) {
|
||||
intent = new Intent(activity, ChromeCustomTabsActivity.class);
|
||||
}
|
||||
// check for webview fallback
|
||||
else if (uuidFallback != null) {
|
||||
Log.d(LOG_TAG, "WebView fallback declared.");
|
||||
// overwrite with extras fallback parameters
|
||||
extras.putString("uuid", uuidFallback);
|
||||
if (optionsFallback != null)
|
||||
extras.putSerializable("options", optionsFallback);
|
||||
else
|
||||
extras.putSerializable("options", (Serializable) (new InAppBrowserOptions()).toMap());
|
||||
intent = new Intent(activity, InAppBrowserActivity.class);
|
||||
}
|
||||
|
||||
if (intent != null) {
|
||||
intent.putExtras(extras);
|
||||
activity.startActivity(intent);
|
||||
result.success(true);
|
||||
return;
|
||||
}
|
||||
|
||||
result.error(LOG_TAG, "No WebView fallback declared.", null);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
channel.setMethodCallHandler(null);
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ContentBlocker;
|
||||
|
||||
public class ContentBlocker {
|
||||
public ContentBlockerTrigger trigger;
|
||||
public ContentBlockerAction action;
|
||||
|
||||
public ContentBlocker (ContentBlockerTrigger trigger, ContentBlockerAction action) {
|
||||
this.trigger = trigger;
|
||||
this.action = action;
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ContentBlocker;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ContentBlockerAction {
|
||||
ContentBlockerActionType type;
|
||||
String selector;
|
||||
|
||||
ContentBlockerAction(ContentBlockerActionType type, String selector) {
|
||||
this.type = type;
|
||||
if (this.type.equals(ContentBlockerActionType.CSS_DISPLAY_NONE)) {
|
||||
assert(selector != null);
|
||||
}
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public static ContentBlockerAction fromMap(Map<String, Object> map) {
|
||||
ContentBlockerActionType type = ContentBlockerActionType.fromValue((String) map.get("type"));
|
||||
String selector = (String) map.get("selector");
|
||||
return new ContentBlockerAction(type, selector);
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ContentBlocker;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ContentBlockerTrigger {
|
||||
|
||||
public String urlFilter;
|
||||
public Pattern urlFilterPatternCompiled;
|
||||
public Boolean urlFilterIsCaseSensitive;
|
||||
public List<ContentBlockerTriggerResourceType> resourceType = new ArrayList<>();
|
||||
public List<String> ifDomain = new ArrayList<>();
|
||||
public List<String> unlessDomain = new ArrayList<>();
|
||||
public List<String> loadType = new ArrayList<>();
|
||||
public List<String> ifTopUrl = new ArrayList<>();
|
||||
public List<String> unlessTopUrl = new ArrayList<>();
|
||||
|
||||
public ContentBlockerTrigger(String urlFilter, Boolean urlFilterIsCaseSensitive, List<ContentBlockerTriggerResourceType> resourceType, List<String> ifDomain,
|
||||
List<String> unlessDomain, List<String> loadType, List<String> ifTopUrl, List<String> unlessTopUrl) {
|
||||
this.urlFilter = urlFilter;
|
||||
this.urlFilterPatternCompiled = Pattern.compile(this.urlFilter);
|
||||
|
||||
this.resourceType = resourceType != null ? resourceType : this.resourceType;
|
||||
this.urlFilterIsCaseSensitive = urlFilterIsCaseSensitive != null ? urlFilterIsCaseSensitive : false;
|
||||
this.ifDomain = ifDomain != null ? ifDomain : this.ifDomain;
|
||||
this.unlessDomain = unlessDomain != null ? unlessDomain : this.unlessDomain;
|
||||
if ((!(this.ifDomain.isEmpty() || this.unlessDomain.isEmpty()) != false))
|
||||
throw new AssertionError();
|
||||
this.loadType = loadType != null ? loadType : this.loadType;
|
||||
if ((this.loadType.size() > 2)) throw new AssertionError();
|
||||
this.ifTopUrl = ifTopUrl != null ? ifTopUrl : this.ifTopUrl;
|
||||
this.unlessTopUrl = unlessTopUrl != null ? unlessTopUrl : this.unlessTopUrl;
|
||||
if ((!(this.ifTopUrl.isEmpty() || this.unlessTopUrl.isEmpty()) != false))
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static ContentBlockerTrigger fromMap(Map<String, Object> map) {
|
||||
String urlFilter = (String) map.get("url-filter");
|
||||
Boolean urlFilterIsCaseSensitive = (Boolean) map.get("url-filter-is-case-sensitive");
|
||||
List<String> resourceTypeStringList = (List<String>) map.get("resource-type");
|
||||
List<ContentBlockerTriggerResourceType> resourceType = new ArrayList<>();
|
||||
if (resourceTypeStringList != null) {
|
||||
for (String type : resourceTypeStringList) {
|
||||
resourceType.add(ContentBlockerTriggerResourceType.fromValue(type));
|
||||
}
|
||||
} else {
|
||||
resourceType.addAll(Arrays.asList(ContentBlockerTriggerResourceType.values()));
|
||||
}
|
||||
List<String> ifDomain = (List<String>) map.get("if-domain");
|
||||
List<String> unlessDomain = (List<String>) map.get("unless-domain");
|
||||
List<String> loadType = (List<String>) map.get("load-type");
|
||||
List<String> ifTopUrl = (List<String>) map.get("if-top-url");
|
||||
List<String> unlessTopUrl = (List<String>) map.get("unless-top-url");
|
||||
return new ContentBlockerTrigger(urlFilter, urlFilterIsCaseSensitive, resourceType, ifDomain, unlessDomain, loadType, ifTopUrl, unlessTopUrl);
|
||||
}
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.CredentialDatabase;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Credential {
|
||||
public Long id;
|
||||
public String username;
|
||||
public String password;
|
||||
public Long protectionSpaceId;
|
||||
|
||||
public Credential (Long id, String username, String password, Long protectionSpaceId) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.protectionSpaceId = protectionSpaceId;
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> credentialMap = new HashMap<>();
|
||||
credentialMap.put("username", username);
|
||||
credentialMap.put("password", password);
|
||||
return credentialMap;
|
||||
}
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.CredentialDatabase;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CredentialDao {
|
||||
|
||||
CredentialDatabaseHelper credentialDatabaseHelper;
|
||||
String[] projection = {
|
||||
CredentialContract.FeedEntry._ID,
|
||||
CredentialContract.FeedEntry.COLUMN_NAME_USERNAME,
|
||||
CredentialContract.FeedEntry.COLUMN_NAME_PASSWORD,
|
||||
CredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID
|
||||
};
|
||||
|
||||
public CredentialDao(CredentialDatabaseHelper credentialDatabaseHelper) {
|
||||
this.credentialDatabaseHelper = credentialDatabaseHelper;
|
||||
}
|
||||
|
||||
public List<Credential> getAllByProtectionSpaceId(Long protectionSpaceId) {
|
||||
String selection = CredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + " = ?";
|
||||
String[] selectionArgs = {protectionSpaceId.toString()};
|
||||
|
||||
Cursor cursor = credentialDatabaseHelper.getReadableDatabase().query(
|
||||
CredentialContract.FeedEntry.TABLE_NAME,
|
||||
projection,
|
||||
selection,
|
||||
selectionArgs,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
List<Credential> credentials = new ArrayList<>();
|
||||
while (cursor.moveToNext()) {
|
||||
Long id = cursor.getLong(cursor.getColumnIndexOrThrow(CredentialContract.FeedEntry._ID));
|
||||
String username = cursor.getString(cursor.getColumnIndexOrThrow(CredentialContract.FeedEntry.COLUMN_NAME_USERNAME));
|
||||
String password = cursor.getString(cursor.getColumnIndexOrThrow(CredentialContract.FeedEntry.COLUMN_NAME_PASSWORD));
|
||||
credentials.add(new Credential(id, username, password, protectionSpaceId));
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
return credentials;
|
||||
}
|
||||
|
||||
public Credential find(String username, String password, Long protectionSpaceId) {
|
||||
String selection = CredentialContract.FeedEntry.COLUMN_NAME_USERNAME + " = ? AND " +
|
||||
CredentialContract.FeedEntry.COLUMN_NAME_PASSWORD + " = ? AND " +
|
||||
CredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + " = ?";
|
||||
String[] selectionArgs = {username, password, protectionSpaceId.toString()};
|
||||
|
||||
Cursor cursor = credentialDatabaseHelper.getReadableDatabase().query(
|
||||
CredentialContract.FeedEntry.TABLE_NAME,
|
||||
projection,
|
||||
selection,
|
||||
selectionArgs,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
Credential credential = null;
|
||||
if (cursor.moveToNext()) {
|
||||
Long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(CredentialContract.FeedEntry._ID));
|
||||
String rowUsername = cursor.getString(cursor.getColumnIndexOrThrow(CredentialContract.FeedEntry.COLUMN_NAME_USERNAME));
|
||||
String rowPassword = cursor.getString(cursor.getColumnIndexOrThrow(CredentialContract.FeedEntry.COLUMN_NAME_PASSWORD));
|
||||
credential = new Credential(rowId, rowUsername, rowPassword, protectionSpaceId);
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
return credential;
|
||||
}
|
||||
|
||||
public long insert(Credential credential) {
|
||||
ContentValues credentialValues = new ContentValues();
|
||||
credentialValues.put(CredentialContract.FeedEntry.COLUMN_NAME_USERNAME, credential.username);
|
||||
credentialValues.put(CredentialContract.FeedEntry.COLUMN_NAME_PASSWORD, credential.password);
|
||||
credentialValues.put(CredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID, credential.protectionSpaceId);
|
||||
|
||||
return credentialDatabaseHelper.getWritableDatabase().insert(CredentialContract.FeedEntry.TABLE_NAME, null, credentialValues);
|
||||
}
|
||||
|
||||
public long update(Credential credential) {
|
||||
ContentValues credentialValues = new ContentValues();
|
||||
credentialValues.put(CredentialContract.FeedEntry.COLUMN_NAME_USERNAME, credential.username);
|
||||
credentialValues.put(CredentialContract.FeedEntry.COLUMN_NAME_PASSWORD, credential.password);
|
||||
|
||||
String whereClause = CredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + " = ?";
|
||||
String[] whereArgs = {credential.protectionSpaceId.toString()};
|
||||
|
||||
return credentialDatabaseHelper.getWritableDatabase().update(CredentialContract.FeedEntry.TABLE_NAME, credentialValues, whereClause, whereArgs);
|
||||
}
|
||||
|
||||
public long delete(Credential credential) {
|
||||
String whereClause = CredentialContract.FeedEntry._ID + " = ?";
|
||||
String[] whereArgs = {credential.id.toString()};
|
||||
|
||||
return credentialDatabaseHelper.getWritableDatabase().delete(CredentialContract.FeedEntry.TABLE_NAME, whereClause, whereArgs);
|
||||
}
|
||||
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.CredentialDatabase;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CredentialDatabase {
|
||||
|
||||
private static CredentialDatabase instance;
|
||||
static final String LOG_TAG = "CredentialDatabase";
|
||||
|
||||
// If you change the database schema, you must increment the database version.
|
||||
public static final int DATABASE_VERSION = 2;
|
||||
public static final String DATABASE_NAME = "CredentialDatabase.db";
|
||||
|
||||
public ProtectionSpaceDao protectionSpaceDao;
|
||||
public CredentialDao credentialDao;
|
||||
public CredentialDatabaseHelper db;
|
||||
|
||||
private CredentialDatabase() {}
|
||||
|
||||
private CredentialDatabase(CredentialDatabaseHelper db, ProtectionSpaceDao protectionSpaceDao, CredentialDao credentialDao) {
|
||||
this.db = db;
|
||||
this.protectionSpaceDao = protectionSpaceDao;
|
||||
this.credentialDao = credentialDao;
|
||||
}
|
||||
|
||||
public static CredentialDatabase getInstance(Context context) {
|
||||
if (instance != null)
|
||||
return instance;
|
||||
CredentialDatabaseHelper db = new CredentialDatabaseHelper(context);
|
||||
instance = new CredentialDatabase(db, new ProtectionSpaceDao(db), new CredentialDao(db));
|
||||
return instance;
|
||||
}
|
||||
|
||||
public List<Credential> getHttpAuthCredentials(String host, String protocol, String realm, Integer port) {
|
||||
List<Credential> credentialList = new ArrayList<>();
|
||||
ProtectionSpace protectionSpace = protectionSpaceDao.find(host, protocol, realm, port);
|
||||
if (protectionSpace != null) {
|
||||
credentialList = credentialDao.getAllByProtectionSpaceId(protectionSpace.id);
|
||||
}
|
||||
return credentialList;
|
||||
}
|
||||
|
||||
public void clearAllAuthCredentials() {
|
||||
db.clearAllTables(db.getWritableDatabase());
|
||||
}
|
||||
|
||||
public void removeHttpAuthCredentials(String host, String protocol, String realm, Integer port) {
|
||||
ProtectionSpace protectionSpace = protectionSpaceDao.find(host, protocol, realm, port);
|
||||
if (protectionSpace != null) {
|
||||
protectionSpaceDao.delete(protectionSpace);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeHttpAuthCredential(String host, String protocol, String realm, Integer port, String username, String password) {
|
||||
ProtectionSpace protectionSpace = protectionSpaceDao.find(host, protocol, realm, port);
|
||||
if (protectionSpace != null) {
|
||||
Credential credential = credentialDao.find(username, password, protectionSpace.id);
|
||||
credentialDao.delete(credential);
|
||||
}
|
||||
}
|
||||
|
||||
public void setHttpAuthCredential(String host, String protocol, String realm, Integer port, String username, String password) {
|
||||
ProtectionSpace protectionSpace = protectionSpaceDao.find(host, protocol, realm, port);
|
||||
Long protectionSpaceId;
|
||||
if (protectionSpace == null) {
|
||||
protectionSpaceId = protectionSpaceDao.insert(new ProtectionSpace(null, host, protocol, realm, port));
|
||||
} else {
|
||||
protectionSpaceId = protectionSpace.id;
|
||||
}
|
||||
|
||||
Credential credential = credentialDao.find(username, password, protectionSpaceId);
|
||||
if (credential != null) {
|
||||
boolean needUpdate = false;
|
||||
if (!credential.username.equals(username)) {
|
||||
credential.username = username;
|
||||
needUpdate = true;
|
||||
}
|
||||
if (!credential.password.equals(password)) {
|
||||
credential.password = password;
|
||||
needUpdate = true;
|
||||
}
|
||||
if (needUpdate)
|
||||
credentialDao.update(credential);
|
||||
} else {
|
||||
credential = new Credential(null, username, password, protectionSpaceId);
|
||||
credential.id = credentialDao.insert(credential);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.CredentialDatabase;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
public class CredentialDatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final String SQL_CREATE_PROTECTION_SPACE_TABLE =
|
||||
"CREATE TABLE " + ProtectionSpaceContract.FeedEntry.TABLE_NAME + " (" +
|
||||
ProtectionSpaceContract.FeedEntry._ID + " INTEGER PRIMARY KEY," +
|
||||
ProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST + " TEXT NOT NULL," +
|
||||
ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL + " TEXT," +
|
||||
ProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM + " TEXT," +
|
||||
ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT + " INTEGER," +
|
||||
"UNIQUE(" + ProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST + ", " + ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL + ", " +
|
||||
ProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM + ", " + ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT +
|
||||
")" +
|
||||
");";
|
||||
|
||||
private static final String SQL_CREATE_CREDENTIAL_TABLE =
|
||||
"CREATE TABLE " + CredentialContract.FeedEntry.TABLE_NAME + " (" +
|
||||
CredentialContract.FeedEntry._ID + " INTEGER PRIMARY KEY," +
|
||||
CredentialContract.FeedEntry.COLUMN_NAME_USERNAME + " TEXT NOT NULL," +
|
||||
CredentialContract.FeedEntry.COLUMN_NAME_PASSWORD + " TEXT NOT NULL," +
|
||||
CredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + " INTEGER NOT NULL," +
|
||||
"UNIQUE(" + CredentialContract.FeedEntry.COLUMN_NAME_USERNAME + ", " + CredentialContract.FeedEntry.COLUMN_NAME_PASSWORD + ", " +
|
||||
CredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID +
|
||||
")," +
|
||||
"FOREIGN KEY (" + CredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + ") REFERENCES " +
|
||||
ProtectionSpaceContract.FeedEntry.TABLE_NAME + " (" + ProtectionSpaceContract.FeedEntry._ID + ") ON DELETE CASCADE" +
|
||||
");";
|
||||
|
||||
private static final String SQL_DELETE_PROTECTION_SPACE_TABLE =
|
||||
"DROP TABLE IF EXISTS " + ProtectionSpaceContract.FeedEntry.TABLE_NAME;
|
||||
|
||||
private static final String SQL_DELETE_CREDENTIAL_TABLE =
|
||||
"DROP TABLE IF EXISTS " + CredentialContract.FeedEntry.TABLE_NAME;
|
||||
|
||||
public CredentialDatabaseHelper(Context context) {
|
||||
super(context, CredentialDatabase.DATABASE_NAME, null, CredentialDatabase.DATABASE_VERSION);
|
||||
}
|
||||
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL(SQL_CREATE_PROTECTION_SPACE_TABLE);
|
||||
db.execSQL(SQL_CREATE_CREDENTIAL_TABLE);
|
||||
}
|
||||
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
// This database is only a cache for online data, so its upgrade policy is
|
||||
// to simply to discard the data and start over
|
||||
db.execSQL(SQL_DELETE_PROTECTION_SPACE_TABLE);
|
||||
db.execSQL(SQL_DELETE_CREDENTIAL_TABLE);
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
onUpgrade(db, oldVersion, newVersion);
|
||||
}
|
||||
|
||||
public void clearAllTables(SQLiteDatabase db) {
|
||||
db.execSQL(SQL_DELETE_PROTECTION_SPACE_TABLE);
|
||||
db.execSQL(SQL_DELETE_CREDENTIAL_TABLE);
|
||||
onCreate(db);
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.CredentialDatabase;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ProtectionSpace {
|
||||
public Long id;
|
||||
public String host;
|
||||
public String procotol;
|
||||
public String realm;
|
||||
public Integer port;
|
||||
|
||||
public ProtectionSpace (Long id, String host, String protocol, String realm, Integer port) {
|
||||
this.id = id;
|
||||
this.host = host;
|
||||
this.procotol = protocol;
|
||||
this.realm = realm;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> protectionSpaceMap = new HashMap<>();
|
||||
protectionSpaceMap.put("host", host);
|
||||
protectionSpaceMap.put("protocol", procotol);
|
||||
protectionSpaceMap.put("realm", realm);
|
||||
protectionSpaceMap.put("port", port);
|
||||
return protectionSpaceMap;
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.CredentialDatabase;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ProtectionSpaceDao {
|
||||
CredentialDatabaseHelper credentialDatabaseHelper;
|
||||
String[] projection = {
|
||||
ProtectionSpaceContract.FeedEntry._ID,
|
||||
ProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST,
|
||||
ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL,
|
||||
ProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM,
|
||||
ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT
|
||||
};
|
||||
|
||||
public ProtectionSpaceDao(CredentialDatabaseHelper credentialDatabaseHelper) {
|
||||
this.credentialDatabaseHelper = credentialDatabaseHelper;
|
||||
}
|
||||
|
||||
public List<ProtectionSpace> getAll() {
|
||||
SQLiteDatabase readableDatabase = credentialDatabaseHelper.getReadableDatabase();
|
||||
|
||||
Cursor cursor = readableDatabase.query(
|
||||
ProtectionSpaceContract.FeedEntry.TABLE_NAME,
|
||||
projection,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
List<ProtectionSpace> protectionSpaces = new ArrayList<>();
|
||||
while (cursor.moveToNext()) {
|
||||
Long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(ProtectionSpaceContract.FeedEntry._ID));
|
||||
String rowHost = cursor.getString(cursor.getColumnIndexOrThrow(ProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST));
|
||||
String rowProtocol = cursor.getString(cursor.getColumnIndexOrThrow(ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL));
|
||||
String rowRealm = cursor.getString(cursor.getColumnIndexOrThrow(ProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM));
|
||||
Integer rowPort = cursor.getInt(cursor.getColumnIndexOrThrow(ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT));
|
||||
protectionSpaces.add(new ProtectionSpace(rowId, rowHost, rowProtocol, rowRealm, rowPort));
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
return protectionSpaces;
|
||||
}
|
||||
|
||||
public ProtectionSpace find(String host, String protocol, String realm, Integer port) {
|
||||
SQLiteDatabase readableDatabase = credentialDatabaseHelper.getReadableDatabase();
|
||||
|
||||
String selection = ProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST + " = ? AND " + ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL + " = ? AND " +
|
||||
ProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM + " = ? AND " + ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT + " = ?";
|
||||
String[] selectionArgs = {host, protocol, realm, port.toString()};
|
||||
|
||||
Cursor cursor = readableDatabase.query(
|
||||
ProtectionSpaceContract.FeedEntry.TABLE_NAME,
|
||||
projection,
|
||||
selection,
|
||||
selectionArgs,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
ProtectionSpace protectionSpace = null;
|
||||
if (cursor.moveToNext()) {
|
||||
Long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(ProtectionSpaceContract.FeedEntry._ID));
|
||||
String rowHost = cursor.getString(cursor.getColumnIndexOrThrow(ProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST));
|
||||
String rowProtocol = cursor.getString(cursor.getColumnIndexOrThrow(ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL));
|
||||
String rowRealm = cursor.getString(cursor.getColumnIndexOrThrow(ProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM));
|
||||
Integer rowPort = cursor.getInt(cursor.getColumnIndexOrThrow(ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT));
|
||||
protectionSpace = new ProtectionSpace(rowId, rowHost, rowProtocol, rowRealm, rowPort);
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
return protectionSpace;
|
||||
}
|
||||
|
||||
public long insert(ProtectionSpace protectionSpace) {
|
||||
ContentValues protectionSpaceValues = new ContentValues();
|
||||
protectionSpaceValues.put(ProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST, protectionSpace.host);
|
||||
protectionSpaceValues.put(ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL, protectionSpace.procotol);
|
||||
protectionSpaceValues.put(ProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM, protectionSpace.realm);
|
||||
protectionSpaceValues.put(ProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT, protectionSpace.port);
|
||||
|
||||
return credentialDatabaseHelper.getWritableDatabase().insert(ProtectionSpaceContract.FeedEntry.TABLE_NAME, null, protectionSpaceValues);
|
||||
};
|
||||
|
||||
public long delete(ProtectionSpace protectionSpace) {
|
||||
String whereClause = ProtectionSpaceContract.FeedEntry._ID + " = ?";
|
||||
String[] whereArgs = {protectionSpace.id.toString()};
|
||||
|
||||
return credentialDatabaseHelper.getWritableDatabase().delete(ProtectionSpaceContract.FeedEntry.TABLE_NAME, whereClause, whereArgs);
|
||||
}
|
||||
}
|
@ -4,10 +4,13 @@ import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.webkit.ValueCallback;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.FlutterWebViewFactory;
|
||||
import com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ChromeSafariBrowserManager;
|
||||
import com.pichillilorenzo.flutter_inappwebview.credential_database.CredentialDatabaseHandler;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserManager;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.FlutterWebViewFactory;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.HeadlessInAppWebViewManager;
|
||||
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
|
||||
@ -15,7 +18,6 @@ import io.flutter.plugin.common.BinaryMessenger;
|
||||
import io.flutter.plugin.common.PluginRegistry;
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
||||
import io.flutter.plugin.platform.PlatformViewRegistry;
|
||||
import io.flutter.view.FlutterMain;
|
||||
import io.flutter.view.FlutterView;
|
||||
|
||||
public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
|
||||
|
@ -8,10 +8,16 @@ import androidx.annotation.NonNull;
|
||||
import androidx.webkit.WebViewCompat;
|
||||
import androidx.webkit.WebViewFeature;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserOptions;
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView;
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebViewOptions;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserActivity;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserOptions;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebViewOptions;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.ContentWorld;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.SslCertificateExt;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScript;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ -40,42 +46,55 @@ public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandle
|
||||
result.success((webView != null) ? webView.getProgress() : null);
|
||||
break;
|
||||
case "loadUrl":
|
||||
if (webView != null)
|
||||
webView.loadUrl((String) call.argument("url"), (Map<String, String>) call.argument("headers"), result);
|
||||
else
|
||||
result.success(false);
|
||||
if (webView != null) {
|
||||
Map<String, Object> urlRequest = (Map<String, Object>) call.argument("urlRequest");
|
||||
webView.loadUrl(URLRequest.fromMap(urlRequest));
|
||||
}
|
||||
result.success(true);
|
||||
break;
|
||||
case "postUrl":
|
||||
if (webView != null)
|
||||
webView.postUrl((String) call.argument("url"), (byte[]) call.argument("postData"), result);
|
||||
else
|
||||
result.success(false);
|
||||
if (webView != null) {
|
||||
String url = (String) call.argument("url");
|
||||
byte[] postData = (byte[]) call.argument("postData");
|
||||
webView.postUrl(url, postData);
|
||||
}
|
||||
result.success(true);
|
||||
break;
|
||||
case "loadData":
|
||||
{
|
||||
String data = (String) call.argument("data");
|
||||
String mimeType = (String) call.argument("mimeType");
|
||||
String encoding = (String) call.argument("encoding");
|
||||
String baseUrl = (String) call.argument("baseUrl");
|
||||
String historyUrl = (String) call.argument("historyUrl");
|
||||
|
||||
if (webView != null)
|
||||
webView.loadData(data, mimeType, encoding, baseUrl, historyUrl, result);
|
||||
else
|
||||
result.success(false);
|
||||
}
|
||||
if (webView != null) {
|
||||
String data = (String) call.argument("data");
|
||||
String mimeType = (String) call.argument("mimeType");
|
||||
String encoding = (String) call.argument("encoding");
|
||||
String baseUrl = (String) call.argument("baseUrl");
|
||||
String historyUrl = (String) call.argument("historyUrl");
|
||||
webView.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
|
||||
}
|
||||
result.success(true);
|
||||
break;
|
||||
case "loadFile":
|
||||
if (webView != null)
|
||||
webView.loadFile((String) call.argument("url"), (Map<String, String>) call.argument("headers"), result);
|
||||
else
|
||||
result.success(false);
|
||||
if (webView != null) {
|
||||
String assetFilePath = (String) call.argument("url");
|
||||
try {
|
||||
webView.loadFile(assetFilePath);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
result.error(LOG_TAG, e.getMessage(), null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
result.success(true);
|
||||
break;
|
||||
case "evaluateJavascript":
|
||||
if (webView != null) {
|
||||
String source = (String) call.argument("source");
|
||||
String contentWorldName = (String) call.argument("contentWorld");
|
||||
webView.evaluateJavascript(source, contentWorldName, result);
|
||||
Map<String, Object> contentWorldMap = (Map<String, Object>) call.argument("contentWorld");
|
||||
ContentWorld contentWorld = ContentWorld.fromMap(contentWorldMap);
|
||||
webView.evaluateJavascript(source, contentWorld, new ValueCallback<String>() {
|
||||
@Override
|
||||
public void onReceiveValue(String value) {
|
||||
result.success(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
result.success(null);
|
||||
@ -150,11 +169,12 @@ public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandle
|
||||
result.success(null);
|
||||
break;
|
||||
case "setOptions":
|
||||
if (webView != null && webView.inAppBrowserActivity != null) {
|
||||
if (webView != null && webView.inAppBrowserDelegate != null && webView.inAppBrowserDelegate instanceof InAppBrowserActivity) {
|
||||
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.inAppBrowserDelegate;
|
||||
InAppBrowserOptions inAppBrowserOptions = new InAppBrowserOptions();
|
||||
HashMap<String, Object> inAppBrowserOptionsMap = (HashMap<String, Object>) call.argument("options");
|
||||
inAppBrowserOptions.parse(inAppBrowserOptionsMap);
|
||||
webView.inAppBrowserActivity.setOptions(inAppBrowserOptions, inAppBrowserOptionsMap);
|
||||
inAppBrowserActivity.setOptions(inAppBrowserOptions, inAppBrowserOptionsMap);
|
||||
} else if (webView != null) {
|
||||
InAppWebViewOptions inAppWebViewOptions = new InAppWebViewOptions();
|
||||
HashMap<String, Object> inAppWebViewOptionsMap = (HashMap<String, Object>) call.argument("options");
|
||||
@ -164,30 +184,34 @@ public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandle
|
||||
result.success(true);
|
||||
break;
|
||||
case "getOptions":
|
||||
if (webView != null && webView.inAppBrowserActivity != null) {
|
||||
result.success(webView.inAppBrowserActivity.getOptions());
|
||||
if (webView != null && webView.inAppBrowserDelegate != null && webView.inAppBrowserDelegate instanceof InAppBrowserActivity) {
|
||||
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.inAppBrowserDelegate;
|
||||
result.success(inAppBrowserActivity.getOptions());
|
||||
} else {
|
||||
result.success((webView != null) ? webView.getOptions() : null);
|
||||
}
|
||||
break;
|
||||
case "close":
|
||||
if (webView != null && webView.inAppBrowserActivity != null) {
|
||||
webView.inAppBrowserActivity.close(result);
|
||||
if (webView != null && webView.inAppBrowserDelegate != null && webView.inAppBrowserDelegate instanceof InAppBrowserActivity) {
|
||||
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.inAppBrowserDelegate;
|
||||
inAppBrowserActivity.close(result);
|
||||
} else {
|
||||
result.notImplemented();
|
||||
}
|
||||
break;
|
||||
case "show":
|
||||
if (webView != null && webView.inAppBrowserActivity != null) {
|
||||
webView.inAppBrowserActivity.show();
|
||||
if (webView != null && webView.inAppBrowserDelegate != null && webView.inAppBrowserDelegate instanceof InAppBrowserActivity) {
|
||||
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.inAppBrowserDelegate;
|
||||
inAppBrowserActivity.show();
|
||||
result.success(true);
|
||||
} else {
|
||||
result.notImplemented();
|
||||
}
|
||||
break;
|
||||
case "hide":
|
||||
if (webView != null && webView.inAppBrowserActivity != null) {
|
||||
webView.inAppBrowserActivity.hide();
|
||||
if (webView != null && webView.inAppBrowserDelegate != null && webView.inAppBrowserDelegate instanceof InAppBrowserActivity) {
|
||||
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.inAppBrowserDelegate;
|
||||
inAppBrowserActivity.hide();
|
||||
result.success(true);
|
||||
} else {
|
||||
result.notImplemented();
|
||||
@ -409,7 +433,7 @@ public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandle
|
||||
break;
|
||||
case "getCertificate":
|
||||
if (webView != null) {
|
||||
result.success(webView.getCertificateMap());
|
||||
result.success(SslCertificateExt.toMap(webView.getCertificate()));
|
||||
} else {
|
||||
result.success(null);
|
||||
}
|
||||
@ -421,24 +445,34 @@ public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandle
|
||||
result.success(true);
|
||||
break;
|
||||
case "addUserScript":
|
||||
if (webView != null) {
|
||||
Map<String, Object> userScript = (Map<String, Object>) call.argument("userScript");
|
||||
result.success(webView.addUserScript(userScript));
|
||||
if (webView != null && webView.userContentController != null) {
|
||||
Map<String, Object> userScriptMap = (Map<String, Object>) call.argument("userScript");
|
||||
UserScript userScript = UserScript.fromMap(userScriptMap);
|
||||
result.success(webView.userContentController.addUserOnlyScript(userScript));
|
||||
} else {
|
||||
result.success(false);
|
||||
}
|
||||
break;
|
||||
case "removeUserScript":
|
||||
if (webView != null) {
|
||||
if (webView != null && webView.userContentController != null) {
|
||||
Integer index = (Integer) call.argument("index");
|
||||
result.success(webView.removeUserScript(index));
|
||||
Map<String, Object> userScriptMap = (Map<String, Object>) call.argument("userScript");
|
||||
UserScript userScript = UserScript.fromMap(userScriptMap);
|
||||
result.success(webView.userContentController.removePluginScriptAt(index, userScript.getInjectionTime()));
|
||||
} else {
|
||||
result.success(false);
|
||||
}
|
||||
break;
|
||||
case "removeUserScriptsByGroupName":
|
||||
if (webView != null && webView.userContentController != null) {
|
||||
String groupName = (String) call.argument("groupName");
|
||||
webView.userContentController.removeUserOnlyScriptsByGroupName(groupName);
|
||||
}
|
||||
result.success(true);
|
||||
break;
|
||||
case "removeAllUserScripts":
|
||||
if (webView != null) {
|
||||
webView.removeAllUserScripts();
|
||||
if (webView != null && webView.userContentController != null) {
|
||||
webView.userContentController.removeAllUserOnlyScripts();
|
||||
}
|
||||
result.success(true);
|
||||
break;
|
||||
@ -446,13 +480,31 @@ public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandle
|
||||
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
String functionBody = (String) call.argument("functionBody");
|
||||
Map<String, Object> functionArguments = (Map<String, Object>) call.argument("arguments");
|
||||
String contentWorldName = (String) call.argument("contentWorld");
|
||||
webView.callAsyncJavaScript(functionBody, functionArguments, contentWorldName, result);
|
||||
Map<String, Object> contentWorldMap = (Map<String, Object>) call.argument("contentWorld");
|
||||
ContentWorld contentWorld = ContentWorld.fromMap(contentWorldMap);
|
||||
webView.callAsyncJavaScript(functionBody, functionArguments, contentWorld, new ValueCallback<String>() {
|
||||
@Override
|
||||
public void onReceiveValue(String value) {
|
||||
result.success(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
result.success(null);
|
||||
}
|
||||
break;
|
||||
case "isSecureContext":
|
||||
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
webView.isSecureContext(new ValueCallback<Boolean>() {
|
||||
@Override
|
||||
public void onReceiveValue(Boolean value) {
|
||||
result.success(value);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
result.success(false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
result.notImplemented();
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -8,8 +8,10 @@ import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import org.json.JSONArray;
|
||||
@ -27,12 +29,15 @@ import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
@ -244,7 +249,7 @@ public class Util {
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public static String JSONStringify(Object value) {
|
||||
public static String JSONStringify(@Nullable Object value) {
|
||||
if (value == null) {
|
||||
return "null";
|
||||
}
|
||||
@ -258,4 +263,15 @@ public class Util {
|
||||
return JSONObject.wrap(value).toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean objEquals(@Nullable Object a, @Nullable Object b) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
return Objects.equals(a, b);
|
||||
}
|
||||
return (a == b) || (a != null && a.equals(b));
|
||||
}
|
||||
|
||||
public static String replaceAll(String s, String oldString, String newString) {
|
||||
return TextUtils.join(newString, s.split(Pattern.quote(oldString)));
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs;
|
||||
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.Shared;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs;
|
||||
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
@ -6,7 +6,6 @@ import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.browser.customtabs.CustomTabsCallback;
|
||||
import androidx.browser.customtabs.CustomTabsIntent;
|
||||
@ -16,7 +15,6 @@ import androidx.browser.customtabs.CustomTabsSession;
|
||||
import com.pichillilorenzo.flutter_inappwebview.R;
|
||||
import com.pichillilorenzo.flutter_inappwebview.Shared;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -145,7 +143,7 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
|
||||
if (options.addDefaultShareMenuItem)
|
||||
builder.addDefaultShareMenuItem();
|
||||
|
||||
if (!options.toolbarBackgroundColor.isEmpty())
|
||||
if (options.toolbarBackgroundColor != null && !options.toolbarBackgroundColor.isEmpty())
|
||||
builder.setToolbarColor(Color.parseColor(options.toolbarBackgroundColor));
|
||||
|
||||
builder.setShowTitle(options.showTitle);
|
@ -1,7 +1,9 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs;
|
||||
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.Options;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -13,7 +15,8 @@ public class ChromeCustomTabsOptions implements Options<ChromeCustomTabsActivity
|
||||
|
||||
public Boolean addDefaultShareMenuItem = true;
|
||||
public Boolean showTitle = true;
|
||||
public String toolbarBackgroundColor = "";
|
||||
@Nullable
|
||||
public String toolbarBackgroundColor;
|
||||
public Boolean enableUrlBarHiding = false;
|
||||
public Boolean instantAppsEnabled = false;
|
||||
public String packageName;
|
@ -0,0 +1,76 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.Shared;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import io.flutter.plugin.common.BinaryMessenger;
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
|
||||
public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandler {
|
||||
|
||||
public MethodChannel channel;
|
||||
|
||||
protected static final String LOG_TAG = "ChromeBrowserManager";
|
||||
|
||||
public ChromeSafariBrowserManager(BinaryMessenger messenger) {
|
||||
channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_chromesafaribrowser");
|
||||
channel.setMethodCallHandler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMethodCall(final MethodCall call, final MethodChannel.Result result) {
|
||||
final Activity activity = Shared.activity;
|
||||
final String uuid = (String) call.argument("uuid");
|
||||
|
||||
switch (call.method) {
|
||||
case "open":
|
||||
{
|
||||
String url = (String) call.argument("url");
|
||||
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
|
||||
List<HashMap<String, Object>> menuItemList = (List<HashMap<String, Object>>) call.argument("menuItemList");
|
||||
open(activity, uuid, url, options, menuItemList, result);
|
||||
}
|
||||
break;
|
||||
case "isAvailable":
|
||||
result.success(CustomTabActivityHelper.isAvailable(activity));
|
||||
break;
|
||||
default:
|
||||
result.notImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
public void open(Activity activity, String uuid, String url, HashMap<String, Object> options,
|
||||
List<HashMap<String, Object>> menuItemList, MethodChannel.Result result) {
|
||||
|
||||
Intent intent = null;
|
||||
Bundle extras = new Bundle();
|
||||
extras.putString("fromActivity", activity.getClass().getName());
|
||||
extras.putString("url", url);
|
||||
extras.putBoolean("isData", false);
|
||||
extras.putString("uuid", uuid);
|
||||
extras.putSerializable("options", options);
|
||||
extras.putSerializable("menuItemList", (Serializable) menuItemList);
|
||||
|
||||
if (CustomTabActivityHelper.isAvailable(activity)) {
|
||||
intent = new Intent(activity, ChromeCustomTabsActivity.class);
|
||||
intent.putExtras(extras);
|
||||
activity.startActivity(intent);
|
||||
result.success(true);
|
||||
return;
|
||||
}
|
||||
|
||||
result.error(LOG_TAG, "ChromeCustomTabs is not available!", null);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
channel.setMethodCallHandler(null);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs;
|
||||
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.net.Uri;
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs;
|
||||
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs;
|
||||
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs;
|
||||
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import androidx.browser.customtabs.CustomTabsClient;
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs;
|
||||
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
|
||||
|
||||
import androidx.browser.customtabs.CustomTabsClient;
|
||||
|
@ -0,0 +1,59 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.content_blocker;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class ContentBlocker {
|
||||
@NonNull
|
||||
private ContentBlockerTrigger trigger;
|
||||
@NonNull
|
||||
private ContentBlockerAction action;
|
||||
|
||||
public ContentBlocker (@NonNull ContentBlockerTrigger trigger, @NonNull ContentBlockerAction action) {
|
||||
this.trigger = trigger;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ContentBlockerTrigger getTrigger() {
|
||||
return trigger;
|
||||
}
|
||||
|
||||
public void setTrigger(@NonNull ContentBlockerTrigger trigger) {
|
||||
this.trigger = trigger;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ContentBlockerAction getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(@NonNull ContentBlockerAction action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ContentBlocker that = (ContentBlocker) o;
|
||||
|
||||
if (!trigger.equals(that.trigger)) return false;
|
||||
return action.equals(that.action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = trigger.hashCode();
|
||||
result = 31 * result + action.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ContentBlocker{" +
|
||||
"trigger=" + trigger +
|
||||
", action=" + action +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.content_blocker;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ContentBlockerAction {
|
||||
@NonNull
|
||||
private ContentBlockerActionType type;
|
||||
|
||||
@Nullable
|
||||
private String selector;
|
||||
|
||||
ContentBlockerAction(@NonNull ContentBlockerActionType type, @Nullable String selector) {
|
||||
this.type = type;
|
||||
if (this.type.equals(ContentBlockerActionType.CSS_DISPLAY_NONE)) {
|
||||
assert(selector != null);
|
||||
}
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public static ContentBlockerAction fromMap(Map<String, Object> map) {
|
||||
ContentBlockerActionType type = ContentBlockerActionType.fromValue((String) map.get("type"));
|
||||
String selector = (String) map.get("selector");
|
||||
return new ContentBlockerAction(type, selector);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ContentBlockerActionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(@NonNull ContentBlockerActionType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getSelector() {
|
||||
return selector;
|
||||
}
|
||||
|
||||
public void setSelector(String selector) {
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ContentBlockerAction that = (ContentBlockerAction) o;
|
||||
|
||||
if (type != that.type) return false;
|
||||
return selector != null ? selector.equals(that.selector) : that.selector == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = type.hashCode();
|
||||
result = 31 * result + (selector != null ? selector.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ContentBlockerAction{" +
|
||||
"type=" + type +
|
||||
", selector='" + selector + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ContentBlocker;
|
||||
package com.pichillilorenzo.flutter_inappwebview.content_blocker;
|
||||
|
||||
public enum ContentBlockerActionType {
|
||||
BLOCK ("block"),
|
||||
@ -23,6 +23,7 @@ public enum ContentBlockerActionType {
|
||||
throw new IllegalArgumentException("No enum constant: " + value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.value;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ContentBlocker;
|
||||
package com.pichillilorenzo.flutter_inappwebview.content_blocker;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
@ -6,7 +6,7 @@ import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebResourceResponse;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView;
|
||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
@ -21,7 +21,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
@ -64,23 +63,23 @@ public class ContentBlockerHandler {
|
||||
List<ContentBlocker> ruleListCopy = new CopyOnWriteArrayList<ContentBlocker>(ruleList);
|
||||
|
||||
for (ContentBlocker contentBlocker : ruleListCopy) {
|
||||
ContentBlockerTrigger trigger = contentBlocker.trigger;
|
||||
List<ContentBlockerTriggerResourceType> resourceTypes = trigger.resourceType;
|
||||
ContentBlockerTrigger trigger = contentBlocker.getTrigger();
|
||||
List<ContentBlockerTriggerResourceType> resourceTypes = trigger.getResourceType();
|
||||
if (resourceTypes.contains(ContentBlockerTriggerResourceType.IMAGE) && !resourceTypes.contains(ContentBlockerTriggerResourceType.SVG_DOCUMENT)) {
|
||||
resourceTypes.add(ContentBlockerTriggerResourceType.SVG_DOCUMENT);
|
||||
}
|
||||
|
||||
ContentBlockerAction action = contentBlocker.action;
|
||||
ContentBlockerAction action = contentBlocker.getAction();
|
||||
|
||||
Matcher m = trigger.urlFilterPatternCompiled.matcher(url);
|
||||
Matcher m = trigger.getUrlFilterPatternCompiled().matcher(url);
|
||||
if (m.matches()) {
|
||||
|
||||
if (!resourceTypes.isEmpty() && !resourceTypes.contains(responseResourceType)) {
|
||||
return null;
|
||||
}
|
||||
if (!trigger.ifDomain.isEmpty()) {
|
||||
if (!trigger.getIfDomain().isEmpty()) {
|
||||
boolean matchFound = false;
|
||||
for (String domain : trigger.ifDomain) {
|
||||
for (String domain : trigger.getIfDomain()) {
|
||||
if ((domain.startsWith("*") && host.endsWith(domain.replace("*", ""))) || domain.equals(host)) {
|
||||
matchFound = true;
|
||||
break;
|
||||
@ -89,14 +88,14 @@ public class ContentBlockerHandler {
|
||||
if (!matchFound)
|
||||
return null;
|
||||
}
|
||||
if (!trigger.unlessDomain.isEmpty()) {
|
||||
for (String domain : trigger.unlessDomain)
|
||||
if (!trigger.getUnlessDomain().isEmpty()) {
|
||||
for (String domain : trigger.getUnlessDomain())
|
||||
if ((domain.startsWith("*") && host.endsWith(domain.replace("*", ""))) || domain.equals(host))
|
||||
return null;
|
||||
}
|
||||
|
||||
final String[] webViewUrl = new String[1];
|
||||
if (!trigger.loadType.isEmpty() || !trigger.ifTopUrl.isEmpty() || !trigger.unlessTopUrl.isEmpty()) {
|
||||
if (!trigger.getLoadType().isEmpty() || !trigger.getIfTopUrl().isEmpty() || !trigger.getUnlessTopUrl().isEmpty()) {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
handler.post(new Runnable() {
|
||||
@ -110,19 +109,19 @@ public class ContentBlockerHandler {
|
||||
}
|
||||
|
||||
if (webViewUrl[0] != null) {
|
||||
if (!trigger.loadType.isEmpty()) {
|
||||
if (!trigger.getLoadType().isEmpty()) {
|
||||
URI cUrl = new URI(webViewUrl[0]);
|
||||
String cHost = cUrl.getHost();
|
||||
int cPort = cUrl.getPort();
|
||||
String cScheme = cUrl.getScheme();
|
||||
|
||||
if ( (trigger.loadType.contains("first-party") && cHost != null && !(cScheme.equals(scheme) && cHost.equals(host) && cPort == port)) ||
|
||||
(trigger.loadType.contains("third-party") && cHost != null && cHost.equals(host)) )
|
||||
if ( (trigger.getLoadType().contains("first-party") && cHost != null && !(cScheme.equals(scheme) && cHost.equals(host) && cPort == port)) ||
|
||||
(trigger.getLoadType().contains("third-party") && cHost != null && cHost.equals(host)) )
|
||||
return null;
|
||||
}
|
||||
if (!trigger.ifTopUrl.isEmpty()) {
|
||||
if (!trigger.getIfTopUrl().isEmpty()) {
|
||||
boolean matchFound = false;
|
||||
for (String topUrl : trigger.ifTopUrl) {
|
||||
for (String topUrl : trigger.getIfTopUrl()) {
|
||||
if (webViewUrl[0].startsWith(topUrl)) {
|
||||
matchFound = true;
|
||||
break;
|
||||
@ -131,20 +130,20 @@ public class ContentBlockerHandler {
|
||||
if (!matchFound)
|
||||
return null;
|
||||
}
|
||||
if (!trigger.unlessTopUrl.isEmpty()) {
|
||||
for (String topUrl : trigger.unlessTopUrl)
|
||||
if (!trigger.getUnlessTopUrl().isEmpty()) {
|
||||
for (String topUrl : trigger.getUnlessTopUrl())
|
||||
if (webViewUrl[0].startsWith(topUrl))
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
switch (action.type) {
|
||||
switch (action.getType()) {
|
||||
|
||||
case BLOCK:
|
||||
return new WebResourceResponse("", "", null);
|
||||
|
||||
case CSS_DISPLAY_NONE:
|
||||
final String cssSelector = action.selector;
|
||||
final String cssSelector = action.getSelector();
|
||||
final String jsScript = "(function(d) { " +
|
||||
" function hide () { " +
|
||||
" if (!d.getElementById('css-display-none-style')) { " +
|
@ -0,0 +1,184 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.content_blocker;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ContentBlockerTrigger {
|
||||
|
||||
@NonNull
|
||||
private String urlFilter;
|
||||
private Pattern urlFilterPatternCompiled;
|
||||
private Boolean urlFilterIsCaseSensitive;
|
||||
private List<ContentBlockerTriggerResourceType> resourceType = new ArrayList<>();
|
||||
private List<String> ifDomain = new ArrayList<>();
|
||||
private List<String> unlessDomain = new ArrayList<>();
|
||||
private List<String> loadType = new ArrayList<>();
|
||||
private List<String> ifTopUrl = new ArrayList<>();
|
||||
private List<String> unlessTopUrl = new ArrayList<>();
|
||||
|
||||
public ContentBlockerTrigger(@NonNull String urlFilter, @Nullable Boolean urlFilterIsCaseSensitive, @Nullable List<ContentBlockerTriggerResourceType> resourceType,
|
||||
@Nullable List<String> ifDomain, @Nullable List<String> unlessDomain, @Nullable List<String> loadType,
|
||||
@Nullable List<String> ifTopUrl, @Nullable List<String> unlessTopUrl) {
|
||||
this.urlFilter = urlFilter;
|
||||
this.urlFilterPatternCompiled = Pattern.compile(this.urlFilter);
|
||||
|
||||
this.resourceType = resourceType != null ? resourceType : this.resourceType;
|
||||
this.urlFilterIsCaseSensitive = urlFilterIsCaseSensitive != null ? urlFilterIsCaseSensitive : false;
|
||||
this.ifDomain = ifDomain != null ? ifDomain : this.ifDomain;
|
||||
this.unlessDomain = unlessDomain != null ? unlessDomain : this.unlessDomain;
|
||||
if ((!(this.ifDomain.isEmpty() || this.unlessDomain.isEmpty()) != false))
|
||||
throw new AssertionError();
|
||||
this.loadType = loadType != null ? loadType : this.loadType;
|
||||
if ((this.loadType.size() > 2)) throw new AssertionError();
|
||||
this.ifTopUrl = ifTopUrl != null ? ifTopUrl : this.ifTopUrl;
|
||||
this.unlessTopUrl = unlessTopUrl != null ? unlessTopUrl : this.unlessTopUrl;
|
||||
if ((!(this.ifTopUrl.isEmpty() || this.unlessTopUrl.isEmpty()) != false))
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static ContentBlockerTrigger fromMap(Map<String, Object> map) {
|
||||
String urlFilter = (String) map.get("url-filter");
|
||||
Boolean urlFilterIsCaseSensitive = (Boolean) map.get("url-filter-is-case-sensitive");
|
||||
List<String> resourceTypeStringList = (List<String>) map.get("resource-type");
|
||||
List<ContentBlockerTriggerResourceType> resourceType = new ArrayList<>();
|
||||
if (resourceTypeStringList != null) {
|
||||
for (String type : resourceTypeStringList) {
|
||||
resourceType.add(ContentBlockerTriggerResourceType.fromValue(type));
|
||||
}
|
||||
} else {
|
||||
resourceType.addAll(Arrays.asList(ContentBlockerTriggerResourceType.values()));
|
||||
}
|
||||
List<String> ifDomain = (List<String>) map.get("if-domain");
|
||||
List<String> unlessDomain = (List<String>) map.get("unless-domain");
|
||||
List<String> loadType = (List<String>) map.get("load-type");
|
||||
List<String> ifTopUrl = (List<String>) map.get("if-top-url");
|
||||
List<String> unlessTopUrl = (List<String>) map.get("unless-top-url");
|
||||
return new ContentBlockerTrigger(urlFilter, urlFilterIsCaseSensitive, resourceType, ifDomain, unlessDomain, loadType, ifTopUrl, unlessTopUrl);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getUrlFilter() {
|
||||
return urlFilter;
|
||||
}
|
||||
|
||||
public void setUrlFilter(@NonNull String urlFilter) {
|
||||
this.urlFilter = urlFilter;
|
||||
}
|
||||
|
||||
public Pattern getUrlFilterPatternCompiled() {
|
||||
return urlFilterPatternCompiled;
|
||||
}
|
||||
|
||||
public void setUrlFilterPatternCompiled(Pattern urlFilterPatternCompiled) {
|
||||
this.urlFilterPatternCompiled = urlFilterPatternCompiled;
|
||||
}
|
||||
|
||||
public Boolean getUrlFilterIsCaseSensitive() {
|
||||
return urlFilterIsCaseSensitive;
|
||||
}
|
||||
|
||||
public void setUrlFilterIsCaseSensitive(Boolean urlFilterIsCaseSensitive) {
|
||||
this.urlFilterIsCaseSensitive = urlFilterIsCaseSensitive;
|
||||
}
|
||||
|
||||
public List<ContentBlockerTriggerResourceType> getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
public void setResourceType(List<ContentBlockerTriggerResourceType> resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public List<String> getIfDomain() {
|
||||
return ifDomain;
|
||||
}
|
||||
|
||||
public void setIfDomain(List<String> ifDomain) {
|
||||
this.ifDomain = ifDomain;
|
||||
}
|
||||
|
||||
public List<String> getUnlessDomain() {
|
||||
return unlessDomain;
|
||||
}
|
||||
|
||||
public void setUnlessDomain(List<String> unlessDomain) {
|
||||
this.unlessDomain = unlessDomain;
|
||||
}
|
||||
|
||||
public List<String> getLoadType() {
|
||||
return loadType;
|
||||
}
|
||||
|
||||
public void setLoadType(List<String> loadType) {
|
||||
this.loadType = loadType;
|
||||
}
|
||||
|
||||
public List<String> getIfTopUrl() {
|
||||
return ifTopUrl;
|
||||
}
|
||||
|
||||
public void setIfTopUrl(List<String> ifTopUrl) {
|
||||
this.ifTopUrl = ifTopUrl;
|
||||
}
|
||||
|
||||
public List<String> getUnlessTopUrl() {
|
||||
return unlessTopUrl;
|
||||
}
|
||||
|
||||
public void setUnlessTopUrl(List<String> unlessTopUrl) {
|
||||
this.unlessTopUrl = unlessTopUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ContentBlockerTrigger that = (ContentBlockerTrigger) o;
|
||||
|
||||
if (!urlFilter.equals(that.urlFilter)) return false;
|
||||
if (!urlFilterPatternCompiled.equals(that.urlFilterPatternCompiled)) return false;
|
||||
if (!urlFilterIsCaseSensitive.equals(that.urlFilterIsCaseSensitive)) return false;
|
||||
if (!resourceType.equals(that.resourceType)) return false;
|
||||
if (!ifDomain.equals(that.ifDomain)) return false;
|
||||
if (!unlessDomain.equals(that.unlessDomain)) return false;
|
||||
if (!loadType.equals(that.loadType)) return false;
|
||||
if (!ifTopUrl.equals(that.ifTopUrl)) return false;
|
||||
return unlessTopUrl.equals(that.unlessTopUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = urlFilter.hashCode();
|
||||
result = 31 * result + urlFilterPatternCompiled.hashCode();
|
||||
result = 31 * result + urlFilterIsCaseSensitive.hashCode();
|
||||
result = 31 * result + resourceType.hashCode();
|
||||
result = 31 * result + ifDomain.hashCode();
|
||||
result = 31 * result + unlessDomain.hashCode();
|
||||
result = 31 * result + loadType.hashCode();
|
||||
result = 31 * result + ifTopUrl.hashCode();
|
||||
result = 31 * result + unlessTopUrl.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ContentBlockerTrigger{" +
|
||||
"urlFilter='" + urlFilter + '\'' +
|
||||
", urlFilterPatternCompiled=" + urlFilterPatternCompiled +
|
||||
", urlFilterIsCaseSensitive=" + urlFilterIsCaseSensitive +
|
||||
", resourceType=" + resourceType +
|
||||
", ifDomain=" + ifDomain +
|
||||
", unlessDomain=" + unlessDomain +
|
||||
", loadType=" + loadType +
|
||||
", ifTopUrl=" + ifTopUrl +
|
||||
", unlessTopUrl=" + unlessTopUrl +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.ContentBlocker;
|
||||
package com.pichillilorenzo.flutter_inappwebview.content_blocker;
|
||||
|
||||
public enum ContentBlockerTriggerResourceType {
|
||||
DOCUMENT ("document"),
|
||||
@ -29,6 +29,7 @@ public enum ContentBlockerTriggerResourceType {
|
||||
throw new IllegalArgumentException("No enum constant: " + value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.value;
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.credential_database;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.URLCredential;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.URLProtectionSpace;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CredentialDatabase {
|
||||
|
||||
private static CredentialDatabase instance;
|
||||
static final String LOG_TAG = "CredentialDatabase";
|
||||
|
||||
// If you change the database schema, you must increment the database version.
|
||||
public static final int DATABASE_VERSION = 2;
|
||||
public static final String DATABASE_NAME = "CredentialDatabase.db";
|
||||
|
||||
public URLProtectionSpaceDao protectionSpaceDao;
|
||||
public URLCredentialDao credentialDao;
|
||||
public CredentialDatabaseHelper db;
|
||||
|
||||
private CredentialDatabase() {}
|
||||
|
||||
private CredentialDatabase(CredentialDatabaseHelper db, URLProtectionSpaceDao protectionSpaceDao, URLCredentialDao credentialDao) {
|
||||
this.db = db;
|
||||
this.protectionSpaceDao = protectionSpaceDao;
|
||||
this.credentialDao = credentialDao;
|
||||
}
|
||||
|
||||
public static CredentialDatabase getInstance(Context context) {
|
||||
if (instance != null)
|
||||
return instance;
|
||||
CredentialDatabaseHelper db = new CredentialDatabaseHelper(context);
|
||||
instance = new CredentialDatabase(db, new URLProtectionSpaceDao(db), new URLCredentialDao(db));
|
||||
return instance;
|
||||
}
|
||||
|
||||
public List<URLCredential> getHttpAuthCredentials(String host, String protocol, String realm, Integer port) {
|
||||
List<URLCredential> credentials = new ArrayList<>();
|
||||
URLProtectionSpace protectionSpace = protectionSpaceDao.find(host, protocol, realm, port);
|
||||
if (protectionSpace != null) {
|
||||
credentials = credentialDao.getAllByProtectionSpaceId(protectionSpace.getId());
|
||||
}
|
||||
return credentials;
|
||||
}
|
||||
|
||||
public void clearAllAuthCredentials() {
|
||||
db.clearAllTables(db.getWritableDatabase());
|
||||
}
|
||||
|
||||
public void removeHttpAuthCredentials(String host, String protocol, String realm, Integer port) {
|
||||
URLProtectionSpace URLProtectionSpace = protectionSpaceDao.find(host, protocol, realm, port);
|
||||
if (URLProtectionSpace != null) {
|
||||
protectionSpaceDao.delete(URLProtectionSpace);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeHttpAuthCredential(String host, String protocol, String realm, Integer port, String username, String password) {
|
||||
URLProtectionSpace protectionSpace = protectionSpaceDao.find(host, protocol, realm, port);
|
||||
if (protectionSpace != null) {
|
||||
URLCredential credential = credentialDao.find(username, password, protectionSpace.getId());
|
||||
credentialDao.delete(credential);
|
||||
}
|
||||
}
|
||||
|
||||
public void setHttpAuthCredential(String host, String protocol, String realm, Integer port, String username, String password) {
|
||||
URLProtectionSpace protectionSpace = protectionSpaceDao.find(host, protocol, realm, port);
|
||||
Long protectionSpaceId;
|
||||
if (protectionSpace == null) {
|
||||
protectionSpaceId = protectionSpaceDao.insert(new URLProtectionSpace(null, host, protocol, realm, port));
|
||||
} else {
|
||||
protectionSpaceId = protectionSpace.getId();
|
||||
}
|
||||
|
||||
URLCredential credential = credentialDao.find(username, password, protectionSpaceId);
|
||||
if (credential != null) {
|
||||
boolean needUpdate = false;
|
||||
if (!credential.getUsername().equals(username)) {
|
||||
credential.setUsername(username);
|
||||
needUpdate = true;
|
||||
}
|
||||
if (!credential.getPassword().equals(password)) {
|
||||
credential.setPassword(password);
|
||||
needUpdate = true;
|
||||
}
|
||||
if (needUpdate)
|
||||
credentialDao.update(credential);
|
||||
} else {
|
||||
credential = new URLCredential(null, username, password, protectionSpaceId);
|
||||
credential.setId(credentialDao.insert(credential));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +1,14 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview;
|
||||
package com.pichillilorenzo.flutter_inappwebview.credential_database;
|
||||
|
||||
import android.os.Build;
|
||||
import android.webkit.WebViewDatabase;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.Credential;
|
||||
import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.CredentialDatabase;
|
||||
import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.ProtectionSpace;
|
||||
import com.pichillilorenzo.flutter_inappwebview.Shared;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.URLCredential;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.URLProtectionSpace;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -17,7 +18,6 @@ import java.util.Map;
|
||||
import io.flutter.plugin.common.BinaryMessenger;
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
import io.flutter.plugin.common.PluginRegistry;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class CredentialDatabaseHandler implements MethodChannel.MethodCallHandler {
|
||||
@ -34,15 +34,15 @@ public class CredentialDatabaseHandler implements MethodChannel.MethodCallHandle
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
|
||||
public void onMethodCall(MethodCall call, @NonNull MethodChannel.Result result) {
|
||||
switch (call.method) {
|
||||
case "getAllAuthCredentials":
|
||||
{
|
||||
List<Map<String, Object>> allCredentials = new ArrayList<>();
|
||||
List<ProtectionSpace> protectionSpaces = credentialDatabase.protectionSpaceDao.getAll();
|
||||
for (ProtectionSpace protectionSpace : protectionSpaces) {
|
||||
List<URLProtectionSpace> protectionSpaces = credentialDatabase.protectionSpaceDao.getAll();
|
||||
for (URLProtectionSpace protectionSpace : protectionSpaces) {
|
||||
List<Map<String, Object>> credentials = new ArrayList<>();
|
||||
for (Credential credential : credentialDatabase.credentialDao.getAllByProtectionSpaceId(protectionSpace.id)) {
|
||||
for (URLCredential credential : credentialDatabase.credentialDao.getAllByProtectionSpaceId(protectionSpace.getId())) {
|
||||
credentials.add(credential.toMap());
|
||||
}
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
@ -61,7 +61,7 @@ public class CredentialDatabaseHandler implements MethodChannel.MethodCallHandle
|
||||
Integer port = (Integer) call.argument("port");
|
||||
|
||||
List<Map<String, Object>> credentials = new ArrayList<>();
|
||||
for (Credential credential : credentialDatabase.getHttpAuthCredentials(host, protocol, realm, port)) {
|
||||
for (URLCredential credential : credentialDatabase.getHttpAuthCredentials(host, protocol, realm, port)) {
|
||||
credentials.add(credential.toMap());
|
||||
}
|
||||
result.success(credentials);
|
@ -0,0 +1,66 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.credential_database;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
public class CredentialDatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final String SQL_CREATE_PROTECTION_SPACE_TABLE =
|
||||
"CREATE TABLE " + URLProtectionSpaceContract.FeedEntry.TABLE_NAME + " (" +
|
||||
URLProtectionSpaceContract.FeedEntry._ID + " INTEGER PRIMARY KEY," +
|
||||
URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST + " TEXT NOT NULL," +
|
||||
URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL + " TEXT," +
|
||||
URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM + " TEXT," +
|
||||
URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT + " INTEGER," +
|
||||
"UNIQUE(" + URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST + ", " + URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL + ", " +
|
||||
URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM + ", " + URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT +
|
||||
")" +
|
||||
");";
|
||||
|
||||
private static final String SQL_CREATE_CREDENTIAL_TABLE =
|
||||
"CREATE TABLE " + URLCredentialContract.FeedEntry.TABLE_NAME + " (" +
|
||||
URLCredentialContract.FeedEntry._ID + " INTEGER PRIMARY KEY," +
|
||||
URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME + " TEXT NOT NULL," +
|
||||
URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD + " TEXT NOT NULL," +
|
||||
URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + " INTEGER NOT NULL," +
|
||||
"UNIQUE(" + URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME + ", " + URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD + ", " +
|
||||
URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID +
|
||||
")," +
|
||||
"FOREIGN KEY (" + URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + ") REFERENCES " +
|
||||
URLProtectionSpaceContract.FeedEntry.TABLE_NAME + " (" + URLProtectionSpaceContract.FeedEntry._ID + ") ON DELETE CASCADE" +
|
||||
");";
|
||||
|
||||
private static final String SQL_DELETE_PROTECTION_SPACE_TABLE =
|
||||
"DROP TABLE IF EXISTS " + URLProtectionSpaceContract.FeedEntry.TABLE_NAME;
|
||||
|
||||
private static final String SQL_DELETE_CREDENTIAL_TABLE =
|
||||
"DROP TABLE IF EXISTS " + URLCredentialContract.FeedEntry.TABLE_NAME;
|
||||
|
||||
public CredentialDatabaseHelper(Context context) {
|
||||
super(context, CredentialDatabase.DATABASE_NAME, null, CredentialDatabase.DATABASE_VERSION);
|
||||
}
|
||||
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL(SQL_CREATE_PROTECTION_SPACE_TABLE);
|
||||
db.execSQL(SQL_CREATE_CREDENTIAL_TABLE);
|
||||
}
|
||||
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
// This database is only a cache for online data, so its upgrade policy is
|
||||
// to simply to discard the data and start over
|
||||
db.execSQL(SQL_DELETE_PROTECTION_SPACE_TABLE);
|
||||
db.execSQL(SQL_DELETE_CREDENTIAL_TABLE);
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
onUpgrade(db, oldVersion, newVersion);
|
||||
}
|
||||
|
||||
public void clearAllTables(SQLiteDatabase db) {
|
||||
db.execSQL(SQL_DELETE_PROTECTION_SPACE_TABLE);
|
||||
db.execSQL(SQL_DELETE_CREDENTIAL_TABLE);
|
||||
onCreate(db);
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.CredentialDatabase;
|
||||
package com.pichillilorenzo.flutter_inappwebview.credential_database;
|
||||
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
public class CredentialContract {
|
||||
private CredentialContract() {}
|
||||
public class URLCredentialContract {
|
||||
private URLCredentialContract() {}
|
||||
|
||||
/* Inner class that defines the table contents */
|
||||
public static class FeedEntry implements BaseColumns {
|
@ -0,0 +1,106 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.credential_database;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.URLCredential;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class URLCredentialDao {
|
||||
|
||||
CredentialDatabaseHelper credentialDatabaseHelper;
|
||||
String[] projection = {
|
||||
URLCredentialContract.FeedEntry._ID,
|
||||
URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME,
|
||||
URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD,
|
||||
URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID
|
||||
};
|
||||
|
||||
public URLCredentialDao(CredentialDatabaseHelper credentialDatabaseHelper) {
|
||||
this.credentialDatabaseHelper = credentialDatabaseHelper;
|
||||
}
|
||||
|
||||
public List<URLCredential> getAllByProtectionSpaceId(Long protectionSpaceId) {
|
||||
String selection = URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + " = ?";
|
||||
String[] selectionArgs = {protectionSpaceId.toString()};
|
||||
|
||||
Cursor cursor = credentialDatabaseHelper.getReadableDatabase().query(
|
||||
URLCredentialContract.FeedEntry.TABLE_NAME,
|
||||
projection,
|
||||
selection,
|
||||
selectionArgs,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
List<URLCredential> URLCredentials = new ArrayList<>();
|
||||
while (cursor.moveToNext()) {
|
||||
Long id = cursor.getLong(cursor.getColumnIndexOrThrow(URLCredentialContract.FeedEntry._ID));
|
||||
String username = cursor.getString(cursor.getColumnIndexOrThrow(URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME));
|
||||
String password = cursor.getString(cursor.getColumnIndexOrThrow(URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD));
|
||||
URLCredentials.add(new URLCredential(id, username, password, protectionSpaceId));
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
return URLCredentials;
|
||||
}
|
||||
|
||||
public URLCredential find(String username, String password, Long protectionSpaceId) {
|
||||
String selection = URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME + " = ? AND " +
|
||||
URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD + " = ? AND " +
|
||||
URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + " = ?";
|
||||
String[] selectionArgs = {username, password, protectionSpaceId.toString()};
|
||||
|
||||
Cursor cursor = credentialDatabaseHelper.getReadableDatabase().query(
|
||||
URLCredentialContract.FeedEntry.TABLE_NAME,
|
||||
projection,
|
||||
selection,
|
||||
selectionArgs,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
URLCredential URLCredential = null;
|
||||
if (cursor.moveToNext()) {
|
||||
Long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(URLCredentialContract.FeedEntry._ID));
|
||||
String rowUsername = cursor.getString(cursor.getColumnIndexOrThrow(URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME));
|
||||
String rowPassword = cursor.getString(cursor.getColumnIndexOrThrow(URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD));
|
||||
URLCredential = new URLCredential(rowId, rowUsername, rowPassword, protectionSpaceId);
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
return URLCredential;
|
||||
}
|
||||
|
||||
public long insert(URLCredential urlCredential) {
|
||||
ContentValues credentialValues = new ContentValues();
|
||||
credentialValues.put(URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME, urlCredential.getUsername());
|
||||
credentialValues.put(URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD, urlCredential.getPassword());
|
||||
credentialValues.put(URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID, urlCredential.getProtectionSpaceId());
|
||||
|
||||
return credentialDatabaseHelper.getWritableDatabase().insert(URLCredentialContract.FeedEntry.TABLE_NAME, null, credentialValues);
|
||||
}
|
||||
|
||||
public long update(URLCredential urlCredential) {
|
||||
ContentValues credentialValues = new ContentValues();
|
||||
credentialValues.put(URLCredentialContract.FeedEntry.COLUMN_NAME_USERNAME, urlCredential.getUsername());
|
||||
credentialValues.put(URLCredentialContract.FeedEntry.COLUMN_NAME_PASSWORD, urlCredential.getPassword());
|
||||
|
||||
String whereClause = URLCredentialContract.FeedEntry.COLUMN_NAME_PROTECTION_SPACE_ID + " = ?";
|
||||
String[] whereArgs = {urlCredential.getProtectionSpaceId().toString()};
|
||||
|
||||
return credentialDatabaseHelper.getWritableDatabase().update(URLCredentialContract.FeedEntry.TABLE_NAME, credentialValues, whereClause, whereArgs);
|
||||
}
|
||||
|
||||
public long delete(URLCredential urlCredential) {
|
||||
String whereClause = URLCredentialContract.FeedEntry._ID + " = ?";
|
||||
String[] whereArgs = {urlCredential.getId().toString()};
|
||||
|
||||
return credentialDatabaseHelper.getWritableDatabase().delete(URLCredentialContract.FeedEntry.TABLE_NAME, whereClause, whereArgs);
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.CredentialDatabase;
|
||||
package com.pichillilorenzo.flutter_inappwebview.credential_database;
|
||||
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
public class ProtectionSpaceContract {
|
||||
private ProtectionSpaceContract() {}
|
||||
public class URLProtectionSpaceContract {
|
||||
private URLProtectionSpaceContract() {}
|
||||
|
||||
/* Inner class that defines the table contents */
|
||||
public static class FeedEntry implements BaseColumns {
|
@ -0,0 +1,100 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.credential_database;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.URLProtectionSpace;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class URLProtectionSpaceDao {
|
||||
CredentialDatabaseHelper credentialDatabaseHelper;
|
||||
String[] projection = {
|
||||
URLProtectionSpaceContract.FeedEntry._ID,
|
||||
URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST,
|
||||
URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL,
|
||||
URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM,
|
||||
URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT
|
||||
};
|
||||
|
||||
public URLProtectionSpaceDao(CredentialDatabaseHelper credentialDatabaseHelper) {
|
||||
this.credentialDatabaseHelper = credentialDatabaseHelper;
|
||||
}
|
||||
|
||||
public List<URLProtectionSpace> getAll() {
|
||||
SQLiteDatabase readableDatabase = credentialDatabaseHelper.getReadableDatabase();
|
||||
|
||||
Cursor cursor = readableDatabase.query(
|
||||
URLProtectionSpaceContract.FeedEntry.TABLE_NAME,
|
||||
projection,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
List<URLProtectionSpace> URLProtectionSpaces = new ArrayList<>();
|
||||
while (cursor.moveToNext()) {
|
||||
Long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry._ID));
|
||||
String rowHost = cursor.getString(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST));
|
||||
String rowProtocol = cursor.getString(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL));
|
||||
String rowRealm = cursor.getString(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM));
|
||||
Integer rowPort = cursor.getInt(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT));
|
||||
URLProtectionSpaces.add(new URLProtectionSpace(rowId, rowHost, rowProtocol, rowRealm, rowPort));
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
return URLProtectionSpaces;
|
||||
}
|
||||
|
||||
public URLProtectionSpace find(String host, String protocol, String realm, Integer port) {
|
||||
SQLiteDatabase readableDatabase = credentialDatabaseHelper.getReadableDatabase();
|
||||
|
||||
String selection = URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST + " = ? AND " + URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL + " = ? AND " +
|
||||
URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM + " = ? AND " + URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT + " = ?";
|
||||
String[] selectionArgs = {host, protocol, realm, port.toString()};
|
||||
|
||||
Cursor cursor = readableDatabase.query(
|
||||
URLProtectionSpaceContract.FeedEntry.TABLE_NAME,
|
||||
projection,
|
||||
selection,
|
||||
selectionArgs,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
URLProtectionSpace URLProtectionSpace = null;
|
||||
if (cursor.moveToNext()) {
|
||||
Long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry._ID));
|
||||
String rowHost = cursor.getString(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST));
|
||||
String rowProtocol = cursor.getString(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL));
|
||||
String rowRealm = cursor.getString(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM));
|
||||
Integer rowPort = cursor.getInt(cursor.getColumnIndexOrThrow(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT));
|
||||
URLProtectionSpace = new URLProtectionSpace(rowId, rowHost, rowProtocol, rowRealm, rowPort);
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
return URLProtectionSpace;
|
||||
}
|
||||
|
||||
public long insert(URLProtectionSpace URLProtectionSpace) {
|
||||
ContentValues protectionSpaceValues = new ContentValues();
|
||||
protectionSpaceValues.put(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_HOST, URLProtectionSpace.getHost());
|
||||
protectionSpaceValues.put(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PROTOCOL, URLProtectionSpace.getProtocol());
|
||||
protectionSpaceValues.put(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_REALM, URLProtectionSpace.getRealm());
|
||||
protectionSpaceValues.put(URLProtectionSpaceContract.FeedEntry.COLUMN_NAME_PORT, URLProtectionSpace.getPort());
|
||||
|
||||
return credentialDatabaseHelper.getWritableDatabase().insert(URLProtectionSpaceContract.FeedEntry.TABLE_NAME, null, protectionSpaceValues);
|
||||
};
|
||||
|
||||
public long delete(URLProtectionSpace URLProtectionSpace) {
|
||||
String whereClause = URLProtectionSpaceContract.FeedEntry._ID + " = ?";
|
||||
String[] whereArgs = {URLProtectionSpace.getId().toString()};
|
||||
|
||||
return credentialDatabaseHelper.getWritableDatabase().delete(URLProtectionSpaceContract.FeedEntry.TABLE_NAME, whereClause, whereArgs);
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_browser;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
public interface ActivityResultListener {
|
||||
/** @return true if the result has been handled. */
|
||||
boolean onActivityResult(int requestCode, int resultCode, Intent data);
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.InAppBrowser;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_browser;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
@ -21,13 +23,17 @@ import android.widget.SearchView;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView;
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebViewChromeClient;
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebViewOptions;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebViewChromeClient;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebViewOptions;
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewMethodHandler;
|
||||
import com.pichillilorenzo.flutter_inappwebview.R;
|
||||
import com.pichillilorenzo.flutter_inappwebview.Shared;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScript;
|
||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -35,7 +41,7 @@ import java.util.Map;
|
||||
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
|
||||
public class InAppBrowserActivity extends AppCompatActivity {
|
||||
public class InAppBrowserActivity extends AppCompatActivity implements InAppBrowserDelegate {
|
||||
|
||||
static final String LOG_TAG = "InAppBrowserActivity";
|
||||
public MethodChannel channel;
|
||||
@ -46,11 +52,10 @@ public class InAppBrowserActivity extends AppCompatActivity {
|
||||
public Menu menu;
|
||||
public SearchView searchView;
|
||||
public InAppBrowserOptions options;
|
||||
public Map<String, String> headers;
|
||||
public ProgressBar progressBar;
|
||||
public boolean isHidden = false;
|
||||
public String fromActivity;
|
||||
public List<ActivityResultListener> activityResultListeners = new ArrayList<>();
|
||||
private List<ActivityResultListener> activityResultListeners = new ArrayList<>();
|
||||
public InAppWebViewMethodHandler methodCallDelegate;
|
||||
|
||||
@Override
|
||||
@ -71,7 +76,7 @@ public class InAppBrowserActivity extends AppCompatActivity {
|
||||
|
||||
webView = findViewById(R.id.webView);
|
||||
webView.windowId = windowId;
|
||||
webView.inAppBrowserActivity = this;
|
||||
webView.inAppBrowserDelegate = this;
|
||||
webView.channel = channel;
|
||||
|
||||
methodCallDelegate = new InAppWebViewMethodHandler(webView);
|
||||
@ -79,8 +84,8 @@ public class InAppBrowserActivity extends AppCompatActivity {
|
||||
|
||||
fromActivity = b.getString("fromActivity");
|
||||
|
||||
HashMap<String, Object> optionsMap = (HashMap<String, Object>) b.getSerializable("options");
|
||||
HashMap<String, Object> contextMenu = (HashMap<String, Object>) b.getSerializable("contextMenu");
|
||||
Map<String, Object> optionsMap = (Map<String, Object>) b.getSerializable("options");
|
||||
Map<String, Object> contextMenu = (Map<String, Object>) b.getSerializable("contextMenu");
|
||||
List<Map<String, Object>> initialUserScripts = (List<Map<String, Object>>) b.getSerializable("initialUserScripts");
|
||||
|
||||
options = new InAppBrowserOptions();
|
||||
@ -90,7 +95,14 @@ public class InAppBrowserActivity extends AppCompatActivity {
|
||||
webViewOptions.parse(optionsMap);
|
||||
webView.options = webViewOptions;
|
||||
webView.contextMenu = contextMenu;
|
||||
webView.userScripts = initialUserScripts;
|
||||
|
||||
List<UserScript> userScripts = new ArrayList<>();
|
||||
if (initialUserScripts != null) {
|
||||
for (Map<String, Object> initialUserScript : initialUserScripts) {
|
||||
userScripts.add(UserScript.fromMap(initialUserScript));
|
||||
}
|
||||
}
|
||||
webView.userContentController.addUserOnlyScripts(userScripts);
|
||||
|
||||
actionBar = getSupportActionBar();
|
||||
|
||||
@ -103,22 +115,35 @@ public class InAppBrowserActivity extends AppCompatActivity {
|
||||
resultMsg.sendToTarget();
|
||||
}
|
||||
} else {
|
||||
Boolean isData = b.getBoolean("isData");
|
||||
if (!isData) {
|
||||
headers = (HashMap<String, String>) b.getSerializable("headers");
|
||||
String url = b.getString("url");
|
||||
webView.loadUrl(url, headers);
|
||||
String initialFile = b.getString("initialFile");
|
||||
Map<String, Object> initialUrlRequest = (Map<String, Object>) b.getSerializable("initialUrlRequest");
|
||||
String initialData = b.getString("initialData");
|
||||
if (initialFile != null) {
|
||||
try {
|
||||
webView.loadFile(initialFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Log.e(LOG_TAG, initialFile + " asset file cannot be found!", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
String data = b.getString("data");
|
||||
else if (initialData != null) {
|
||||
String mimeType = b.getString("mimeType");
|
||||
String encoding = b.getString("encoding");
|
||||
String baseUrl = b.getString("baseUrl");
|
||||
String historyUrl = b.getString("historyUrl");
|
||||
webView.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
|
||||
webView.loadDataWithBaseURL(baseUrl, initialData, mimeType, encoding, historyUrl);
|
||||
}
|
||||
else if (initialUrlRequest != null) {
|
||||
URLRequest urlRequest = URLRequest.fromMap(initialUrlRequest);
|
||||
webView.loadUrl(urlRequest);
|
||||
}
|
||||
}
|
||||
|
||||
onBrowserCreated();
|
||||
}
|
||||
|
||||
public void onBrowserCreated() {
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
channel.invokeMethod("onBrowserCreated", obj);
|
||||
}
|
||||
@ -134,14 +159,14 @@ public class InAppBrowserActivity extends AppCompatActivity {
|
||||
|
||||
progressBar = findViewById(R.id.progressBar);
|
||||
|
||||
if (!options.progressBar)
|
||||
if (options.hideProgressBar)
|
||||
progressBar.setMax(0);
|
||||
else
|
||||
progressBar.setMax(100);
|
||||
|
||||
actionBar.setDisplayShowTitleEnabled(!options.hideTitleBar);
|
||||
|
||||
if (!options.toolbarTop)
|
||||
if (options.hideToolbarTop)
|
||||
actionBar.hide();
|
||||
|
||||
if (options.toolbarTopBackgroundColor != null && !options.toolbarTopBackgroundColor.isEmpty())
|
||||
@ -168,7 +193,7 @@ public class InAppBrowserActivity extends AppCompatActivity {
|
||||
|
||||
searchView.setQuery(webView.getUrl(), false);
|
||||
|
||||
if (options.toolbarTopFixedTitle.isEmpty())
|
||||
if (options.toolbarTopFixedTitle == null || options.toolbarTopFixedTitle.isEmpty())
|
||||
actionBar.setTitle(webView.getTitle());
|
||||
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@ -316,8 +341,8 @@ public class InAppBrowserActivity extends AppCompatActivity {
|
||||
show();
|
||||
}
|
||||
|
||||
if (newOptionsMap.get("progressBar") != null && options.progressBar != newOptions.progressBar && progressBar != null) {
|
||||
if (newOptions.progressBar)
|
||||
if (newOptionsMap.get("hideProgressBar") != null && options.hideProgressBar != newOptions.hideProgressBar && progressBar != null) {
|
||||
if (newOptions.hideProgressBar)
|
||||
progressBar.setMax(0);
|
||||
else
|
||||
progressBar.setMax(100);
|
||||
@ -326,17 +351,18 @@ public class InAppBrowserActivity extends AppCompatActivity {
|
||||
if (newOptionsMap.get("hideTitleBar") != null && options.hideTitleBar != newOptions.hideTitleBar)
|
||||
actionBar.setDisplayShowTitleEnabled(!newOptions.hideTitleBar);
|
||||
|
||||
if (newOptionsMap.get("toolbarTop") != null && options.toolbarTop != newOptions.toolbarTop) {
|
||||
if (!newOptions.toolbarTop)
|
||||
if (newOptionsMap.get("hideToolbarTop") != null && options.hideToolbarTop != newOptions.hideToolbarTop) {
|
||||
if (newOptions.hideToolbarTop)
|
||||
actionBar.hide();
|
||||
else
|
||||
actionBar.show();
|
||||
}
|
||||
|
||||
if (newOptionsMap.get("toolbarTopBackgroundColor") != null && options.toolbarTopBackgroundColor != newOptions.toolbarTopBackgroundColor && !newOptions.toolbarTopBackgroundColor.isEmpty())
|
||||
if (newOptionsMap.get("toolbarTopBackgroundColor") != null && !Util.objEquals(options.toolbarTopBackgroundColor, newOptions.toolbarTopBackgroundColor) &&
|
||||
!newOptions.toolbarTopBackgroundColor.isEmpty())
|
||||
actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor(newOptions.toolbarTopBackgroundColor)));
|
||||
|
||||
if (newOptionsMap.get("toolbarTopFixedTitle") != null && options.toolbarTopFixedTitle != newOptions.toolbarTopFixedTitle && !newOptions.toolbarTopFixedTitle.isEmpty())
|
||||
if (newOptionsMap.get("toolbarTopFixedTitle") != null && !Util.objEquals(options.toolbarTopFixedTitle, newOptions.toolbarTopFixedTitle) && !newOptions.toolbarTopFixedTitle.isEmpty())
|
||||
actionBar.setTitle(newOptions.toolbarTopFixedTitle);
|
||||
|
||||
if (newOptionsMap.get("hideUrlBar") != null && options.hideUrlBar != newOptions.hideUrlBar) {
|
||||
@ -359,6 +385,69 @@ public class InAppBrowserActivity extends AppCompatActivity {
|
||||
return optionsMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Activity getActivity() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didChangeTitle(String title) {
|
||||
if (options.toolbarTopFixedTitle == null || options.toolbarTopFixedTitle.isEmpty()) {
|
||||
actionBar.setTitle(title);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didStartNavigation(String url) {
|
||||
progressBar.setProgress(0);
|
||||
searchView.setQuery(url, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didUpdateVisitedHistory(String url) {
|
||||
searchView.setQuery(url, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didFinishNavigation(String url) {
|
||||
searchView.setQuery(url, false);
|
||||
progressBar.setProgress(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didFailNavigation(String url, int errorCode, String description) {
|
||||
progressBar.setProgress(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didChangeProgress(int progress) {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
progressBar.setProgress(progress, true);
|
||||
} else {
|
||||
progressBar.setProgress(progress);
|
||||
}
|
||||
if (progress == 100) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public List<ActivityResultListener> getActivityResultListeners() {
|
||||
return activityResultListeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult (int requestCode,
|
||||
int resultCode,
|
||||
Intent data) {
|
||||
for (ActivityResultListener listener : activityResultListeners) {
|
||||
if (listener.onActivityResult(requestCode, resultCode, data)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
channel.setMethodCallHandler(null);
|
||||
activityResultListeners.clear();
|
||||
@ -385,26 +474,9 @@ public class InAppBrowserActivity extends AppCompatActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult (int requestCode,
|
||||
int resultCode,
|
||||
Intent data) {
|
||||
for (ActivityResultListener listener : activityResultListeners) {
|
||||
if (listener.onActivityResult(requestCode, resultCode, data)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
dispose();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
public interface ActivityResultListener {
|
||||
/** @return true if the result has been handled. */
|
||||
boolean onActivityResult(int requestCode, int resultCode, Intent data);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_browser;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface InAppBrowserDelegate {
|
||||
Activity getActivity();
|
||||
List<ActivityResultListener> getActivityResultListeners();
|
||||
void didChangeTitle(String title);
|
||||
void didStartNavigation(String url);
|
||||
void didUpdateVisitedHistory(String url);
|
||||
void didFinishNavigation(String url);
|
||||
void didFailNavigation(String url, int errorCode, String description);
|
||||
void didChangeProgress(int progress);
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package com.pichillilorenzo.flutter_inappwebview;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_browser;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
@ -32,12 +32,10 @@ import android.os.Bundle;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.util.Log;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
|
||||
import com.pichillilorenzo.flutter_inappwebview.Shared;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -62,49 +60,42 @@ public class InAppBrowserManager implements MethodChannel.MethodCallHandler {
|
||||
@Override
|
||||
public void onMethodCall(final MethodCall call, final Result result) {
|
||||
final Activity activity = Shared.activity;
|
||||
final String uuid = (String) call.argument("uuid");
|
||||
|
||||
switch (call.method) {
|
||||
case "openUrl":
|
||||
case "openUrlRequest":
|
||||
{
|
||||
String url = (String) call.argument("url");
|
||||
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
|
||||
Map<String, String> headers = (Map<String, String>) call.argument("headers");
|
||||
HashMap<String, Object> contextMenu = (HashMap<String, Object>) call.argument("contextMenu");
|
||||
String uuid = (String) call.argument("uuid");
|
||||
Map<String, Object> urlRequest = (Map<String, Object>) call.argument("urlRequest");
|
||||
Map<String, Object> options = (Map<String, Object>) call.argument("options");
|
||||
Map<String, Object> contextMenu = (Map<String, Object>) call.argument("contextMenu");
|
||||
Integer windowId = (Integer) call.argument("windowId");
|
||||
List<Map<String, Object>> initialUserScripts = (List<Map<String, Object>>) call.argument("initialUserScripts");
|
||||
openUrl(activity, uuid, url, options, headers, contextMenu, windowId, initialUserScripts);
|
||||
openUrlRequest(activity, uuid, urlRequest, options, contextMenu, windowId, initialUserScripts);
|
||||
}
|
||||
result.success(true);
|
||||
break;
|
||||
case "openFile":
|
||||
{
|
||||
String url = (String) call.argument("url");
|
||||
try {
|
||||
url = Util.getUrlAsset(url);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
result.error(LOG_TAG, url + " asset file cannot be found!", e);
|
||||
return;
|
||||
}
|
||||
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
|
||||
Map<String, String> headers = (Map<String, String>) call.argument("headers");
|
||||
HashMap<String, Object> contextMenu = (HashMap<String, Object>) call.argument("contextMenu");
|
||||
String uuid = (String) call.argument("uuid");
|
||||
String assetFilePath = (String) call.argument("assetFilePath");
|
||||
Map<String, Object> options = (Map<String, Object>) call.argument("options");
|
||||
Map<String, Object> contextMenu = (Map<String, Object>) call.argument("contextMenu");
|
||||
Integer windowId = (Integer) call.argument("windowId");
|
||||
List<Map<String, Object>> initialUserScripts = (List<Map<String, Object>>) call.argument("initialUserScripts");
|
||||
openUrl(activity, uuid, url, options, headers, contextMenu, windowId, initialUserScripts);
|
||||
openFile(activity, uuid, assetFilePath, options, contextMenu, windowId, initialUserScripts);
|
||||
}
|
||||
result.success(true);
|
||||
break;
|
||||
case "openData":
|
||||
{
|
||||
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
|
||||
String uuid = (String) call.argument("uuid");
|
||||
Map<String, Object> options = (Map<String, Object>) call.argument("options");
|
||||
String data = (String) call.argument("data");
|
||||
String mimeType = (String) call.argument("mimeType");
|
||||
String encoding = (String) call.argument("encoding");
|
||||
String baseUrl = (String) call.argument("baseUrl");
|
||||
String historyUrl = (String) call.argument("historyUrl");
|
||||
HashMap<String, Object> contextMenu = (HashMap<String, Object>) call.argument("contextMenu");
|
||||
Map<String, Object> contextMenu = (Map<String, Object>) call.argument("contextMenu");
|
||||
Integer windowId = (Integer) call.argument("windowId");
|
||||
List<Map<String, Object>> initialUserScripts = (List<Map<String, Object>>) call.argument("initialUserScripts");
|
||||
openData(activity, uuid, options, data, mimeType, encoding, baseUrl, historyUrl, contextMenu, windowId, initialUserScripts);
|
||||
@ -198,32 +189,42 @@ public class InAppBrowserManager implements MethodChannel.MethodCallHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public void openUrl(Activity activity, String uuid, String url, HashMap<String, Object> options, Map<String, String> headers,
|
||||
HashMap<String, Object> contextMenu, Integer windowId, List<Map<String, Object>> initialUserScripts) {
|
||||
public void openUrlRequest(Activity activity, String uuid, Map<String, Object> urlRequest, Map<String, Object> options,
|
||||
Map<String, Object> contextMenu, Integer windowId, List<Map<String, Object>> initialUserScripts) {
|
||||
Bundle extras = new Bundle();
|
||||
extras.putString("fromActivity", activity.getClass().getName());
|
||||
extras.putString("url", url);
|
||||
extras.putBoolean("isData", false);
|
||||
extras.putSerializable("initialUrlRequest", (Serializable) urlRequest);
|
||||
extras.putString("uuid", uuid);
|
||||
extras.putSerializable("options", options);
|
||||
extras.putSerializable("headers", (Serializable) headers);
|
||||
extras.putSerializable("options", (Serializable) options);
|
||||
extras.putSerializable("contextMenu", (Serializable) contextMenu);
|
||||
extras.putInt("windowId", windowId != null ? windowId : -1);
|
||||
extras.putSerializable("initialUserScripts", (Serializable) initialUserScripts);
|
||||
startInAppBrowserActivity(activity, extras);
|
||||
}
|
||||
|
||||
public void openData(Activity activity, String uuid, HashMap<String, Object> options, String data, String mimeType, String encoding,
|
||||
String baseUrl, String historyUrl, HashMap<String, Object> contextMenu, Integer windowId, List<Map<String, Object>> initialUserScripts) {
|
||||
public void openFile(Activity activity, String uuid, String assetFilePath, Map<String, Object> options,
|
||||
Map<String, Object> contextMenu, Integer windowId, List<Map<String, Object>> initialUserScripts) {
|
||||
Bundle extras = new Bundle();
|
||||
extras.putBoolean("isData", true);
|
||||
extras.putString("fromActivity", activity.getClass().getName());
|
||||
extras.putString("initialFile", assetFilePath);
|
||||
extras.putString("uuid", uuid);
|
||||
extras.putSerializable("options", options);
|
||||
extras.putString("data", data);
|
||||
extras.putString("mimeType", mimeType);
|
||||
extras.putString("encoding", encoding);
|
||||
extras.putString("baseUrl", baseUrl);
|
||||
extras.putString("historyUrl", historyUrl);
|
||||
extras.putSerializable("options", (Serializable) options);
|
||||
extras.putSerializable("contextMenu", (Serializable) contextMenu);
|
||||
extras.putInt("windowId", windowId != null ? windowId : -1);
|
||||
extras.putSerializable("initialUserScripts", (Serializable) initialUserScripts);
|
||||
startInAppBrowserActivity(activity, extras);
|
||||
}
|
||||
|
||||
public void openData(Activity activity, String uuid, Map<String, Object> options, String data, String mimeType, String encoding,
|
||||
String baseUrl, String historyUrl, Map<String, Object> contextMenu, Integer windowId, List<Map<String, Object>> initialUserScripts) {
|
||||
Bundle extras = new Bundle();
|
||||
extras.putString("uuid", uuid);
|
||||
extras.putSerializable("options", (Serializable) options);
|
||||
extras.putString("initialData", data);
|
||||
extras.putString("initialMimeType", mimeType);
|
||||
extras.putString("initialEncoding", encoding);
|
||||
extras.putString("initialBaseUrl", baseUrl);
|
||||
extras.putString("initialHistoryUrl", historyUrl);
|
||||
extras.putSerializable("contextMenu", (Serializable) contextMenu);
|
||||
extras.putInt("windowId", windowId != null ? windowId : -1);
|
||||
extras.putSerializable("initialUserScripts", (Serializable) initialUserScripts);
|
@ -1,6 +1,9 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.InAppBrowser;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_browser;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.Options;
|
||||
import com.pichillilorenzo.flutter_inappwebview.R;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -10,14 +13,16 @@ public class InAppBrowserOptions implements Options<InAppBrowserActivity> {
|
||||
public static final String LOG_TAG = "InAppBrowserOptions";
|
||||
|
||||
public Boolean hidden = false;
|
||||
public Boolean toolbarTop = true;
|
||||
public String toolbarTopBackgroundColor = "";
|
||||
public String toolbarTopFixedTitle = "";
|
||||
public Boolean hideToolbarTop = false;
|
||||
@Nullable
|
||||
public String toolbarTopBackgroundColor = null;
|
||||
@Nullable
|
||||
public String toolbarTopFixedTitle;
|
||||
public Boolean hideUrlBar = false;
|
||||
public Boolean hideProgressBar = false;
|
||||
|
||||
public Boolean hideTitleBar = false;
|
||||
public Boolean closeOnCannotGoBack = true;
|
||||
public Boolean progressBar = true;
|
||||
|
||||
@Override
|
||||
public InAppBrowserOptions parse(Map<String, Object> options) {
|
||||
@ -32,8 +37,8 @@ public class InAppBrowserOptions implements Options<InAppBrowserActivity> {
|
||||
case "hidden":
|
||||
hidden = (Boolean) value;
|
||||
break;
|
||||
case "toolbarTop":
|
||||
toolbarTop = (Boolean) value;
|
||||
case "hideToolbarTop":
|
||||
hideToolbarTop = (Boolean) value;
|
||||
break;
|
||||
case "toolbarTopBackgroundColor":
|
||||
toolbarTopBackgroundColor = (String) value;
|
||||
@ -50,8 +55,8 @@ public class InAppBrowserOptions implements Options<InAppBrowserActivity> {
|
||||
case "closeOnCannotGoBack":
|
||||
closeOnCannotGoBack = (Boolean) value;
|
||||
break;
|
||||
case "progressBar":
|
||||
progressBar = (Boolean) value;
|
||||
case "hideProgressBar":
|
||||
hideProgressBar = (Boolean) value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -63,19 +68,22 @@ public class InAppBrowserOptions implements Options<InAppBrowserActivity> {
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> options = new HashMap<>();
|
||||
options.put("hidden", hidden);
|
||||
options.put("toolbarTop", toolbarTop);
|
||||
options.put("hideToolbarTop", hideToolbarTop);
|
||||
options.put("toolbarTopBackgroundColor", toolbarTopBackgroundColor);
|
||||
options.put("toolbarTopFixedTitle", toolbarTopFixedTitle);
|
||||
options.put("hideUrlBar", hideUrlBar);
|
||||
options.put("hideTitleBar", hideTitleBar);
|
||||
options.put("closeOnCannotGoBack", closeOnCannotGoBack);
|
||||
options.put("progressBar", progressBar);
|
||||
options.put("hideProgressBar", hideProgressBar);
|
||||
return options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getRealOptions(InAppBrowserActivity inAppBrowserActivity) {
|
||||
Map<String, Object> realOptions = toMap();
|
||||
realOptions.put("hideToolbarTop", inAppBrowserActivity.actionBar.isShowing());
|
||||
realOptions.put("hideUrlBar", inAppBrowserActivity.menu.findItem(R.id.menu_search).isVisible());
|
||||
realOptions.put("hideProgressBar", inAppBrowserActivity.progressBar.getMax() == 0);
|
||||
return realOptions;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_webview;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.Options;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_webview;
|
||||
|
||||
import static android.hardware.display.DisplayManager.DisplayListener;
|
||||
|
@ -1,7 +1,8 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_webview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.os.Build;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
@ -10,11 +11,18 @@ import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
import androidx.webkit.WebViewCompat;
|
||||
import androidx.webkit.WebViewFeature;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewMethodHandler;
|
||||
import com.pichillilorenzo.flutter_inappwebview.Shared;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScript;
|
||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -38,10 +46,9 @@ public class FlutterWebView implements PlatformView {
|
||||
DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
|
||||
displayListenerProxy.onPreWebViewInitialization(displayManager);
|
||||
|
||||
String initialUrl = (String) params.get("initialUrl");
|
||||
Map<String, Object> initialUrlRequest = (Map<String, Object>) params.get("initialUrlRequest");
|
||||
final String initialFile = (String) params.get("initialFile");
|
||||
final Map<String, String> initialData = (Map<String, String>) params.get("initialData");
|
||||
final Map<String, String> initialHeaders = (Map<String, String>) params.get("initialHeaders");
|
||||
Map<String, Object> initialOptions = (Map<String, Object>) params.get("initialOptions");
|
||||
Map<String, Object> contextMenu = (Map<String, Object>) params.get("contextMenu");
|
||||
Integer windowId = (Integer) params.get("windowId");
|
||||
@ -57,7 +64,14 @@ public class FlutterWebView implements PlatformView {
|
||||
"- See the official wiki here: https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects\n\n\n");
|
||||
}
|
||||
|
||||
webView = new InAppWebView(context, this, id, windowId, options, contextMenu, containerView, initialUserScripts);
|
||||
List<UserScript> userScripts = new ArrayList<>();
|
||||
if (initialUserScripts != null) {
|
||||
for (Map<String, Object> initialUserScript : initialUserScripts) {
|
||||
userScripts.add(UserScript.fromMap(initialUserScript));
|
||||
}
|
||||
}
|
||||
|
||||
webView = new InAppWebView(context, channel, id, windowId, options, contextMenu, containerView, userScripts);
|
||||
displayListenerProxy.onPostWebViewInitialization(displayManager);
|
||||
|
||||
methodCallDelegate = new InAppWebViewMethodHandler(webView);
|
||||
@ -74,15 +88,14 @@ public class FlutterWebView implements PlatformView {
|
||||
} else {
|
||||
if (initialFile != null) {
|
||||
try {
|
||||
initialUrl = Util.getUrlAsset(initialFile);
|
||||
webView.loadFile(initialFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Log.e(LOG_TAG, initialFile + " asset file cannot be found!", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (initialData != null) {
|
||||
else if (initialData != null) {
|
||||
String data = initialData.get("data");
|
||||
String mimeType = initialData.get("mimeType");
|
||||
String encoding = initialData.get("encoding");
|
||||
@ -90,8 +103,9 @@ public class FlutterWebView implements PlatformView {
|
||||
String historyUrl = initialData.get("historyUrl");
|
||||
webView.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
|
||||
}
|
||||
else {
|
||||
webView.loadUrl(initialUrl, initialHeaders);
|
||||
else if (initialUrlRequest != null) {
|
||||
URLRequest urlRequest = URLRequest.fromMap(initialUrlRequest);
|
||||
webView.loadUrl(urlRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,13 +128,20 @@ public class FlutterWebView implements PlatformView {
|
||||
methodCallDelegate = null;
|
||||
}
|
||||
if (webView != null) {
|
||||
webView.inAppWebViewChromeClient.dispose();
|
||||
webView.inAppWebViewClient.dispose();
|
||||
webView.javaScriptBridgeInterface.dispose();
|
||||
webView.removeJavascriptInterface(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE)) {
|
||||
WebViewCompat.setWebViewRenderProcessClient(webView, null);
|
||||
}
|
||||
webView.setWebChromeClient(new WebChromeClient());
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
if (webView.inAppWebViewRenderProcessClient != null) {
|
||||
webView.inAppWebViewRenderProcessClient.dispose();
|
||||
}
|
||||
webView.inAppWebViewChromeClient.dispose();
|
||||
webView.inAppWebViewClient.dispose();
|
||||
webView.javaScriptBridgeInterface.dispose();
|
||||
webView.dispose();
|
||||
webView.destroy();
|
||||
webView = null;
|
||||
@ -134,13 +155,13 @@ public class FlutterWebView implements PlatformView {
|
||||
|
||||
@Override
|
||||
public void onInputConnectionLocked() {
|
||||
if (webView != null && webView.inAppBrowserActivity == null)
|
||||
if (webView != null && webView.inAppBrowserDelegate == null)
|
||||
webView.lockInputConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInputConnectionUnlocked() {
|
||||
if (webView != null && webView.inAppBrowserActivity == null)
|
||||
if (webView != null && webView.inAppBrowserDelegate == null)
|
||||
webView.unlockInputConnection();
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_webview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.FlutterWebView;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import io.flutter.plugin.common.BinaryMessenger;
|
@ -19,11 +19,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package com.pichillilorenzo.flutter_inappwebview;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_webview;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.FlutterWebView;
|
||||
import com.pichillilorenzo.flutter_inappwebview.Shared;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,8 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_webview;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
@ -41,14 +40,16 @@ import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.CreateWindowAction;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.ActivityResultListener;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserDelegate;
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
|
||||
import com.pichillilorenzo.flutter_inappwebview.R;
|
||||
import com.pichillilorenzo.flutter_inappwebview.Shared;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -61,12 +62,11 @@ import io.flutter.plugin.common.PluginRegistry;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
public class InAppWebViewChromeClient extends WebChromeClient implements PluginRegistry.ActivityResultListener, InAppBrowserActivity.ActivityResultListener {
|
||||
public class InAppWebViewChromeClient extends WebChromeClient implements PluginRegistry.ActivityResultListener, ActivityResultListener {
|
||||
|
||||
protected static final String LOG_TAG = "IABWebChromeClient";
|
||||
private FlutterWebView flutterWebView;
|
||||
private InAppBrowserActivity inAppBrowserActivity;
|
||||
public MethodChannel channel;
|
||||
private InAppBrowserDelegate inAppBrowserDelegate;
|
||||
private final MethodChannel channel;
|
||||
public static Map<Integer, Message> windowWebViewMessages = new HashMap<>();
|
||||
private static int windowAutoincrementId = 0;
|
||||
|
||||
@ -101,15 +101,14 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
private int mOriginalOrientation;
|
||||
private int mOriginalSystemUiVisibility;
|
||||
|
||||
public InAppWebViewChromeClient(Object obj) {
|
||||
if (obj instanceof InAppBrowserActivity) {
|
||||
this.inAppBrowserActivity = (InAppBrowserActivity) obj;
|
||||
this.inAppBrowserActivity.activityResultListeners.add(this);
|
||||
public InAppWebViewChromeClient(MethodChannel channel, InAppBrowserDelegate inAppBrowserDelegate) {
|
||||
super();
|
||||
|
||||
this.channel = channel;
|
||||
this.inAppBrowserDelegate = inAppBrowserDelegate;
|
||||
if (this.inAppBrowserDelegate != null) {
|
||||
this.inAppBrowserDelegate.getActivityResultListeners().add(this);
|
||||
}
|
||||
else if (obj instanceof FlutterWebView) {
|
||||
this.flutterWebView = (FlutterWebView) obj;
|
||||
}
|
||||
this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel;
|
||||
|
||||
if (Shared.registrar != null)
|
||||
Shared.registrar.addActivityResultListener(this);
|
||||
@ -122,13 +121,13 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
if (mCustomView == null) {
|
||||
return null;
|
||||
}
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
return BitmapFactory.decodeResource(activity.getApplicationContext().getResources(), 2130837573);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHideCustomView() {
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
|
||||
View decorView = getRootView();
|
||||
((FrameLayout) decorView).removeView(this.mCustomView);
|
||||
@ -149,7 +148,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
return;
|
||||
}
|
||||
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
|
||||
View decorView = getRootView();
|
||||
this.mCustomView = paramView;
|
||||
@ -233,7 +232,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
}
|
||||
};
|
||||
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_Dialog_Alert);
|
||||
alertDialogBuilder.setMessage(alertMessage);
|
||||
@ -326,7 +325,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
}
|
||||
};
|
||||
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_Dialog_Alert);
|
||||
alertDialogBuilder.setMessage(alertMessage);
|
||||
@ -445,7 +444,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
}
|
||||
};
|
||||
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_Dialog_Alert);
|
||||
alertDialogBuilder.setMessage(alertMessage);
|
||||
@ -479,7 +478,6 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("url", url);
|
||||
obj.put("message", message);
|
||||
obj.put("iosIsMainFrame", null);
|
||||
|
||||
channel.invokeMethod("onJsBeforeUnload", obj, new MethodChannel.Result() {
|
||||
@Override
|
||||
@ -544,7 +542,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
}
|
||||
};
|
||||
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_Dialog_Alert);
|
||||
alertDialogBuilder.setMessage(alertMessage);
|
||||
@ -579,25 +577,19 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
WebView.HitTestResult result = view.getHitTestResult();
|
||||
String url = result.getExtra();
|
||||
|
||||
final Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("url", url);
|
||||
obj.put("windowId", windowId);
|
||||
obj.put("androidIsDialog", isDialog);
|
||||
obj.put("androidIsUserGesture", isUserGesture);
|
||||
obj.put("iosWKNavigationType", null);
|
||||
obj.put("iosIsForMainFrame", null);
|
||||
obj.put("iosAllowsCellularAccess", null);
|
||||
obj.put("iosAllowsConstrainedNetworkAccess", null);
|
||||
obj.put("iosAllowsExpensiveNetworkAccess", null);
|
||||
obj.put("iosCachePolicy", null);
|
||||
obj.put("iosHttpShouldHandleCookies", null);
|
||||
obj.put("iosHttpShouldUsePipelining", null);
|
||||
obj.put("iosNetworkServiceType", null);
|
||||
obj.put("iosTimeoutInterval", null);
|
||||
URLRequest request = new URLRequest(url, "GET", null, null);
|
||||
CreateWindowAction createWindowAction = new CreateWindowAction(
|
||||
request,
|
||||
true,
|
||||
isUserGesture,
|
||||
false,
|
||||
windowId,
|
||||
isDialog
|
||||
);
|
||||
|
||||
windowWebViewMessages.put(windowId, resultMsg);
|
||||
|
||||
channel.invokeMethod("onCreateWindow", obj, new MethodChannel.Result() {
|
||||
channel.invokeMethod("onCreateWindow", createWindowAction.toMap(), new MethodChannel.Result() {
|
||||
@Override
|
||||
public void success(@Nullable Object result) {
|
||||
boolean handledByClient = false;
|
||||
@ -678,30 +670,23 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(WebView view, int progress) {
|
||||
if (inAppBrowserActivity != null && inAppBrowserActivity.progressBar != null) {
|
||||
inAppBrowserActivity.progressBar.setVisibility(View.VISIBLE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
inAppBrowserActivity.progressBar.setProgress(progress, true);
|
||||
} else {
|
||||
inAppBrowserActivity.progressBar.setProgress(progress);
|
||||
}
|
||||
if (progress == 100) {
|
||||
inAppBrowserActivity.progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
super.onProgressChanged(view, progress);
|
||||
|
||||
if (inAppBrowserDelegate != null) {
|
||||
inAppBrowserDelegate.didChangeProgress(progress);
|
||||
}
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("progress", progress);
|
||||
channel.invokeMethod("onProgressChanged", obj);
|
||||
|
||||
super.onProgressChanged(view, progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedTitle(WebView view, String title) {
|
||||
super.onReceivedTitle(view, title);
|
||||
if (inAppBrowserActivity != null && inAppBrowserActivity.actionBar != null && inAppBrowserActivity.options.toolbarTopFixedTitle.isEmpty()) {
|
||||
inAppBrowserActivity.actionBar.setTitle(title);
|
||||
|
||||
if (inAppBrowserDelegate != null) {
|
||||
inAppBrowserDelegate.didChangeTitle(title);
|
||||
}
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
@ -744,7 +729,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
}
|
||||
|
||||
protected ViewGroup getRootView() {
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
return (ViewGroup) activity.findViewById(android.R.id.content);
|
||||
}
|
||||
|
||||
@ -838,7 +823,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
}
|
||||
|
||||
private boolean isFileNotEmpty(Uri uri) {
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
|
||||
long length;
|
||||
try {
|
||||
@ -879,7 +864,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
}
|
||||
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{}));
|
||||
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
if (chooserIntent.resolveActivity(activity.getPackageManager()) != null) {
|
||||
activity.startActivityForResult(chooserIntent, PICKER_LEGACY);
|
||||
} else {
|
||||
@ -907,7 +892,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
chooserIntent.putExtra(Intent.EXTRA_INTENT, fileSelectionIntent);
|
||||
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{}));
|
||||
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
if (chooserIntent.resolveActivity(activity.getPackageManager()) != null) {
|
||||
activity.startActivityForResult(chooserIntent, PICKER);
|
||||
} else {
|
||||
@ -920,7 +905,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
protected boolean needsCameraPermission() {
|
||||
boolean needed = false;
|
||||
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
PackageManager packageManager = activity.getPackageManager();
|
||||
try {
|
||||
String[] requestedPermissions = packageManager.getPackageInfo(activity.getApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS).requestedPermissions;
|
||||
@ -1062,7 +1047,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
return Uri.fromFile(capturedFile);
|
||||
}
|
||||
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
// for versions 6.0+ (23) we use the FileProvider to avoid runtime permissions
|
||||
String packageName = activity.getApplicationContext().getPackageName();
|
||||
return FileProvider.getUriForFile(activity.getApplicationContext(), packageName + "." + fileProviderAuthorityExtension, capturedFile);
|
||||
@ -1092,7 +1077,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
return new File(storageDir, filename);
|
||||
}
|
||||
|
||||
Activity activity = inAppBrowserActivity != null ? inAppBrowserActivity : Shared.activity;
|
||||
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : Shared.activity;
|
||||
File storageDir = activity.getApplicationContext().getExternalFilesDir(null);
|
||||
return File.createTempFile(prefix, suffix, storageDir);
|
||||
}
|
||||
@ -1150,15 +1135,12 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
channel.setMethodCallHandler(null);
|
||||
if (Shared.activityPluginBinding != null) {
|
||||
Shared.activityPluginBinding.removeActivityResultListener(this);
|
||||
}
|
||||
if (inAppBrowserActivity != null) {
|
||||
inAppBrowserActivity = null;
|
||||
}
|
||||
if (flutterWebView != null) {
|
||||
flutterWebView = null;
|
||||
if (inAppBrowserDelegate != null) {
|
||||
inAppBrowserDelegate.getActivityResultListeners().clear();
|
||||
inAppBrowserDelegate = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_webview;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.graphics.Bitmap;
|
||||
@ -23,10 +23,18 @@ import android.webkit.WebViewClient;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.Credential;
|
||||
import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.CredentialDatabase;
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
|
||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||
import com.pichillilorenzo.flutter_inappwebview.credential_database.CredentialDatabase;
|
||||
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserDelegate;
|
||||
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.ClientCertChallenge;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.HttpAuthenticationChallenge;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.NavigationAction;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.NavigationActionPolicy;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.ServerTrustChallenge;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.URLCredential;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.URLProtectionSpace;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.net.URI;
|
||||
@ -42,19 +50,16 @@ import io.flutter.plugin.common.MethodChannel;
|
||||
public class InAppWebViewClient extends WebViewClient {
|
||||
|
||||
protected static final String LOG_TAG = "IAWebViewClient";
|
||||
private FlutterWebView flutterWebView;
|
||||
private InAppBrowserActivity inAppBrowserActivity;
|
||||
public MethodChannel channel;
|
||||
private InAppBrowserDelegate inAppBrowserDelegate;
|
||||
private final MethodChannel channel;
|
||||
private static int previousAuthRequestFailureCount = 0;
|
||||
private static List<Credential> credentialsProposed = null;
|
||||
private static List<URLCredential> credentialsProposed = null;
|
||||
|
||||
public InAppWebViewClient(Object obj) {
|
||||
public InAppWebViewClient(MethodChannel channel, InAppBrowserDelegate inAppBrowserDelegate) {
|
||||
super();
|
||||
if (obj instanceof InAppBrowserActivity)
|
||||
this.inAppBrowserActivity = (InAppBrowserActivity) obj;
|
||||
else if (obj instanceof FlutterWebView)
|
||||
this.flutterWebView = (FlutterWebView) obj;
|
||||
this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel;
|
||||
|
||||
this.channel = channel;
|
||||
this.inAppBrowserDelegate = inAppBrowserDelegate;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@ -62,34 +67,24 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
||||
InAppWebView webView = (InAppWebView) view;
|
||||
if (webView.options.useShouldOverrideUrlLoading) {
|
||||
boolean isRedirect = false;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
onShouldOverrideUrlLoading(
|
||||
webView,
|
||||
request.getUrl().toString(),
|
||||
request.getMethod(),
|
||||
request.getRequestHeaders(),
|
||||
request.isForMainFrame(),
|
||||
request.hasGesture(),
|
||||
request.isRedirect());
|
||||
} else {
|
||||
onShouldOverrideUrlLoading(
|
||||
webView,
|
||||
request.getUrl().toString(),
|
||||
request.getMethod(),
|
||||
request.getRequestHeaders(),
|
||||
request.isForMainFrame(),
|
||||
request.hasGesture(),
|
||||
false);
|
||||
isRedirect = request.isRedirect();
|
||||
}
|
||||
onShouldOverrideUrlLoading(
|
||||
webView,
|
||||
request.getUrl().toString(),
|
||||
request.getMethod(),
|
||||
request.getRequestHeaders(),
|
||||
request.isForMainFrame(),
|
||||
request.hasGesture(),
|
||||
isRedirect);
|
||||
if (webView.regexToCancelSubFramesLoadingCompiled != null) {
|
||||
if (request.isForMainFrame())
|
||||
return true;
|
||||
else {
|
||||
Matcher m = webView.regexToCancelSubFramesLoadingCompiled.matcher(request.getUrl().toString());
|
||||
if (m.matches())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
return m.matches();
|
||||
}
|
||||
} else {
|
||||
// There isn't any way to load an URL for a frame that is not the main frame,
|
||||
@ -110,154 +105,99 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void allowShouldOverrideUrlLoading(WebView webView, String url, Map<String, String> headers, boolean isForMainFrame) {
|
||||
if (isForMainFrame) {
|
||||
// There isn't any way to load an URL for a frame that is not the main frame,
|
||||
// so call this only on main frame.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
webView.loadUrl(url, headers);
|
||||
else
|
||||
webView.loadUrl(url);
|
||||
}
|
||||
}
|
||||
public void onShouldOverrideUrlLoading(final InAppWebView webView, final String url, final String method, final Map<String, String> headers,
|
||||
final boolean isForMainFrame, boolean hasGesture, boolean isRedirect) {
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("url", url);
|
||||
obj.put("method", method);
|
||||
obj.put("headers", headers);
|
||||
obj.put("isForMainFrame", isForMainFrame);
|
||||
obj.put("androidHasGesture", hasGesture);
|
||||
obj.put("androidIsRedirect", isRedirect);
|
||||
obj.put("iosWKNavigationType", null);
|
||||
obj.put("iosAllowsCellularAccess", null);
|
||||
obj.put("iosAllowsConstrainedNetworkAccess", null);
|
||||
obj.put("iosAllowsExpensiveNetworkAccess", null);
|
||||
obj.put("iosCachePolicy", null);
|
||||
obj.put("iosHttpShouldHandleCookies", null);
|
||||
obj.put("iosHttpShouldUsePipelining", null);
|
||||
obj.put("iosNetworkServiceType", null);
|
||||
obj.put("iosTimeoutInterval", null);
|
||||
URLRequest request = new URLRequest(url, method, null, headers);
|
||||
NavigationAction navigationAction = new NavigationAction(
|
||||
request,
|
||||
isForMainFrame,
|
||||
hasGesture,
|
||||
isRedirect
|
||||
);
|
||||
|
||||
channel.invokeMethod("shouldOverrideUrlLoading", obj, new MethodChannel.Result() {
|
||||
channel.invokeMethod("shouldOverrideUrlLoading", navigationAction.toMap(), new MethodChannel.Result() {
|
||||
@Override
|
||||
public void success(Object response) {
|
||||
if (response != null) {
|
||||
if (response != null) {
|
||||
Map<String, Object> responseMap = (Map<String, Object>) response;
|
||||
Integer action = (Integer) responseMap.get("action");
|
||||
if (action != null) {
|
||||
switch (action) {
|
||||
case 1:
|
||||
if (isForMainFrame) {
|
||||
// There isn't any way to load an URL for a frame that is not the main frame,
|
||||
// so call this only on main frame.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
webView.loadUrl(url, headers);
|
||||
else
|
||||
webView.loadUrl(url);
|
||||
}
|
||||
action = action != null ? action : NavigationActionPolicy.CANCEL.rawValue();
|
||||
|
||||
NavigationActionPolicy navigationActionPolicy = NavigationActionPolicy.fromValue(action);
|
||||
if (navigationActionPolicy != null) {
|
||||
switch (navigationActionPolicy) {
|
||||
case ALLOW:
|
||||
allowShouldOverrideUrlLoading(webView, url, headers, isForMainFrame);
|
||||
return;
|
||||
case 0:
|
||||
case CANCEL:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
allowShouldOverrideUrlLoading(webView, url, headers, isForMainFrame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String s, String s1, Object o) {
|
||||
Log.d(LOG_TAG, "ERROR: " + s + " " + s1);
|
||||
Log.e(LOG_TAG, "ERROR: " + s + " " + s1);
|
||||
allowShouldOverrideUrlLoading(webView, url, headers, isForMainFrame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notImplemented() {
|
||||
|
||||
allowShouldOverrideUrlLoading(webView, url, headers, isForMainFrame);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadCustomJavaScriptOnPageStarted(WebView view) {
|
||||
public void loadCustomJavaScriptOnPageStarted(WebView view) {
|
||||
InAppWebView webView = (InAppWebView) view;
|
||||
|
||||
String jsPluginScriptsWrapped = webView.prepareAndWrapPluginUserScripts();
|
||||
String jsUserScriptsAtDocumentStart = prepareUserScriptsAtDocumentStart(webView);
|
||||
|
||||
String js = wrapPluginAndUserScripts(jsPluginScriptsWrapped, jsUserScriptsAtDocumentStart, null);
|
||||
String source = webView.userContentController.generateWrappedCodeForDocumentStart();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webView.evaluateJavascript(js, (ValueCallback<String>) null);
|
||||
webView.evaluateJavascript(source, (ValueCallback<String>) null);
|
||||
} else {
|
||||
webView.loadUrl("javascript:" + js.replaceAll("[\r\n]+", ""));
|
||||
webView.loadUrl("javascript:" + source.replaceAll("[\r\n]+", ""));
|
||||
}
|
||||
}
|
||||
|
||||
private void loadCustomJavaScriptOnPageFinished(WebView view) {
|
||||
public void loadCustomJavaScriptOnPageFinished(WebView view) {
|
||||
InAppWebView webView = (InAppWebView) view;
|
||||
|
||||
// try to reload also custom scripts if they were not loaded during the onPageStarted event
|
||||
String jsPluginScriptsWrapped = webView.prepareAndWrapPluginUserScripts();
|
||||
String jsUserScriptsAtDocumentStart = prepareUserScriptsAtDocumentStart(webView);
|
||||
String jsUserScriptsAtDocumentEnd = prepareUserScriptsAtDocumentEnd(webView);
|
||||
|
||||
String js = wrapPluginAndUserScripts(jsPluginScriptsWrapped, jsUserScriptsAtDocumentStart, jsUserScriptsAtDocumentEnd);
|
||||
String source = webView.userContentController.generateWrappedCodeForDocumentEnd();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webView.evaluateJavascript(js, (ValueCallback<String>) null);
|
||||
webView.evaluateJavascript(source, (ValueCallback<String>) null);
|
||||
} else {
|
||||
webView.loadUrl("javascript:" + js.replaceAll("[\r\n]+", ""));
|
||||
webView.loadUrl("javascript:" + source.replaceAll("[\r\n]+", ""));
|
||||
}
|
||||
}
|
||||
|
||||
private String prepareUserScripts(InAppWebView webView, int atDocumentInjectionTime) {
|
||||
StringBuilder js = new StringBuilder();
|
||||
|
||||
for (Map<String, Object> userScript : webView.userScripts) {
|
||||
Integer injectionTime = (Integer) userScript.get("injectionTime");
|
||||
if ((injectionTime == null && atDocumentInjectionTime == 0) || (injectionTime != null && injectionTime == atDocumentInjectionTime)) {
|
||||
String source = (String) userScript.get("source");
|
||||
String contentWorldName = (String) userScript.get("contentWorld");
|
||||
if (source != null) {
|
||||
if (contentWorldName != null && !contentWorldName.equals("page")) {
|
||||
String jsPluginScripts = webView.prepareAndWrapPluginUserScripts();
|
||||
source = jsPluginScripts + "\n" + source;
|
||||
}
|
||||
if (contentWorldName != null && !webView.userScriptsContentWorlds.contains(contentWorldName)) {
|
||||
webView.userScriptsContentWorlds.add(contentWorldName);
|
||||
}
|
||||
String sourceWrapped = webView.wrapSourceCodeInContentWorld(contentWorldName, source);
|
||||
if (atDocumentInjectionTime == 0 && contentWorldName != null && !contentWorldName.equals("page")) {
|
||||
// adds another wrapper because sometimes document.body is not ready and it is undefined, causing an error and not adding the iframe element.
|
||||
sourceWrapped = InAppWebView.documentReadyWrapperJS.replace("$PLACEHOLDER_VALUE", sourceWrapped)
|
||||
.replace("$PLACEHOLDER_VALUE", sourceWrapped);
|
||||
}
|
||||
|
||||
js.append(sourceWrapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return js.toString();
|
||||
}
|
||||
|
||||
private String prepareUserScriptsAtDocumentStart(InAppWebView webView) {
|
||||
return prepareUserScripts(webView, 0);
|
||||
}
|
||||
|
||||
private String prepareUserScriptsAtDocumentEnd(InAppWebView webView) {
|
||||
return prepareUserScripts(webView, 1);
|
||||
}
|
||||
|
||||
private String wrapPluginAndUserScripts(String jsPluginScriptsWrapped, @Nullable String jsUserScriptsAtDocumentStart, @Nullable String jsUserScriptsAtDocumentEnd) {
|
||||
String jsUserScriptsAtDocumentStartWrapped = jsUserScriptsAtDocumentStart == null || jsUserScriptsAtDocumentStart.isEmpty() ? "" :
|
||||
InAppWebView.userScriptsAtDocumentStartWrapperJS.replace("$PLACEHOLDER_VALUE", jsUserScriptsAtDocumentStart);
|
||||
String jsUserScriptsAtDocumentEndWrapped = jsUserScriptsAtDocumentEnd == null || jsUserScriptsAtDocumentEnd.isEmpty() ? "" :
|
||||
InAppWebView.userScriptsAtDocumentEndWrapperJS.replace("$PLACEHOLDER_VALUE", jsUserScriptsAtDocumentEnd);
|
||||
return jsPluginScriptsWrapped + "\n" + jsUserScriptsAtDocumentStartWrapped + "\n" + jsUserScriptsAtDocumentEndWrapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
final InAppWebView webView = (InAppWebView) view;
|
||||
webView.resetUserScriptsContentWorlds();
|
||||
webView.isLoading = true;
|
||||
|
||||
webView.userContentController.resetContentWorlds();
|
||||
loadCustomJavaScriptOnPageStarted(webView);
|
||||
|
||||
super.onPageStarted(view, url, favicon);
|
||||
|
||||
webView.isLoading = true;
|
||||
if (inAppBrowserActivity != null && inAppBrowserActivity.searchView != null && !url.equals(inAppBrowserActivity.searchView.getQuery().toString())) {
|
||||
inAppBrowserActivity.searchView.setQuery(url, false);
|
||||
if (inAppBrowserDelegate != null) {
|
||||
inAppBrowserDelegate.didStartNavigation(url);
|
||||
}
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
@ -268,14 +208,16 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
final InAppWebView webView = (InAppWebView) view;
|
||||
|
||||
webView.isLoading = false;
|
||||
loadCustomJavaScriptOnPageFinished(webView);
|
||||
previousAuthRequestFailureCount = 0;
|
||||
credentialsProposed = null;
|
||||
|
||||
super.onPageFinished(view, url);
|
||||
|
||||
webView.isLoading = false;
|
||||
previousAuthRequestFailureCount = 0;
|
||||
credentialsProposed = null;
|
||||
if (inAppBrowserDelegate != null) {
|
||||
inAppBrowserDelegate.didFinishNavigation(url);
|
||||
}
|
||||
|
||||
// WebView not storing cookies reliable to local device storage
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
@ -284,7 +226,7 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
CookieSyncManager.getInstance().sync();
|
||||
}
|
||||
|
||||
String js = InAppWebView.platformReadyJS;
|
||||
String js = JavaScriptBridgeJS.PLATFORM_READY_JS_SOURCE;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webView.evaluateJavascript(js, (ValueCallback<String>) null);
|
||||
@ -299,17 +241,23 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
|
||||
@Override
|
||||
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
|
||||
super.doUpdateVisitedHistory(view, url, isReload);
|
||||
|
||||
url = view.getUrl();
|
||||
|
||||
if (inAppBrowserDelegate != null) {
|
||||
inAppBrowserDelegate.didUpdateVisitedHistory(url);
|
||||
}
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
// url argument sometimes doesn't contain the new changed URL, so we get it again from the webview.
|
||||
obj.put("url", url);
|
||||
obj.put("androidIsReload", isReload);
|
||||
channel.invokeMethod("onUpdateVisitedHistory", obj);
|
||||
|
||||
super.doUpdateVisitedHistory(view, url, isReload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
|
||||
|
||||
final InAppWebView webView = (InAppWebView) view;
|
||||
|
||||
if (webView.options.disableDefaultErrorPage) {
|
||||
@ -321,6 +269,10 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
previousAuthRequestFailureCount = 0;
|
||||
credentialsProposed = null;
|
||||
|
||||
if (inAppBrowserDelegate != null) {
|
||||
inAppBrowserDelegate.didFailNavigation(failingUrl, errorCode, description);
|
||||
}
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("url", failingUrl);
|
||||
obj.put("code", errorCode);
|
||||
@ -343,9 +295,6 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On received http auth request.
|
||||
*/
|
||||
@Override
|
||||
public void onReceivedHttpAuthRequest(final WebView view, final HttpAuthHandler handler, final String host, final String realm) {
|
||||
|
||||
@ -374,7 +323,18 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
obj.put("port", port);
|
||||
obj.put("previousFailureCount", previousAuthRequestFailureCount);
|
||||
|
||||
channel.invokeMethod("onReceivedHttpAuthRequest", obj, new MethodChannel.Result() {
|
||||
if (credentialsProposed == null)
|
||||
credentialsProposed = CredentialDatabase.getInstance(view.getContext()).getHttpAuthCredentials(host, protocol, realm, port);
|
||||
|
||||
URLCredential credentialProposed = null;
|
||||
if (credentialsProposed != null && credentialsProposed.size() > 0) {
|
||||
credentialProposed = credentialsProposed.get(0);
|
||||
}
|
||||
|
||||
URLProtectionSpace protectionSpace = new URLProtectionSpace(host, protocol, realm, port, view.getCertificate(), null);
|
||||
HttpAuthenticationChallenge challenge = new HttpAuthenticationChallenge(protectionSpace, previousAuthRequestFailureCount, credentialProposed);
|
||||
|
||||
channel.invokeMethod("onReceivedHttpAuthRequest", challenge.toMap(), new MethodChannel.Result() {
|
||||
@Override
|
||||
public void success(Object response) {
|
||||
if (response != null) {
|
||||
@ -386,17 +346,15 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
String username = (String) responseMap.get("username");
|
||||
String password = (String) responseMap.get("password");
|
||||
Boolean permanentPersistence = (Boolean) responseMap.get("permanentPersistence");
|
||||
if (permanentPersistence != null && permanentPersistence && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
if (permanentPersistence != null && permanentPersistence) {
|
||||
CredentialDatabase.getInstance(view.getContext()).setHttpAuthCredential(host, protocol, realm, port, username, password);
|
||||
}
|
||||
handler.proceed(username, password);
|
||||
return;
|
||||
case 2:
|
||||
if (credentialsProposed == null)
|
||||
credentialsProposed = CredentialDatabase.getInstance(view.getContext()).getHttpAuthCredentials(host, protocol, realm, port);
|
||||
if (credentialsProposed.size() > 0) {
|
||||
Credential credential = credentialsProposed.remove(0);
|
||||
handler.proceed(credential.username, credential.password);
|
||||
URLCredential credential = credentialsProposed.remove(0);
|
||||
handler.proceed(credential.getUsername(), credential.getPassword());
|
||||
} else {
|
||||
handler.cancel();
|
||||
}
|
||||
@ -429,10 +387,10 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedSslError(final WebView view, final SslErrorHandler handler, final SslError error) {
|
||||
public void onReceivedSslError(final WebView view, final SslErrorHandler handler, final SslError sslError) {
|
||||
URI uri;
|
||||
try {
|
||||
uri = new URI(view.getUrl());
|
||||
uri = new URI(sslError.getUrl());
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
handler.cancel();
|
||||
@ -444,40 +402,10 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
final String realm = null;
|
||||
final int port = uri.getPort();
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("host", host);
|
||||
obj.put("protocol", protocol);
|
||||
obj.put("realm", realm);
|
||||
obj.put("port", port);
|
||||
obj.put("androidError", error.getPrimaryError());
|
||||
obj.put("iosError", null);
|
||||
obj.put("sslCertificate", InAppWebView.getCertificateMap(error.getCertificate()));
|
||||
URLProtectionSpace protectionSpace = new URLProtectionSpace(host, protocol, realm, port, sslError.getCertificate(), sslError);
|
||||
ServerTrustChallenge challenge = new ServerTrustChallenge(protectionSpace);
|
||||
|
||||
String message;
|
||||
switch (error.getPrimaryError()) {
|
||||
case SslError.SSL_DATE_INVALID:
|
||||
message = "The date of the certificate is invalid";
|
||||
break;
|
||||
case SslError.SSL_EXPIRED:
|
||||
message = "The certificate has expired";
|
||||
break;
|
||||
case SslError.SSL_IDMISMATCH:
|
||||
message = "Hostname mismatch";
|
||||
break;
|
||||
default:
|
||||
case SslError.SSL_INVALID:
|
||||
message = "A generic error occurred";
|
||||
break;
|
||||
case SslError.SSL_NOTYETVALID:
|
||||
message = "The certificate is not yet valid";
|
||||
break;
|
||||
case SslError.SSL_UNTRUSTED:
|
||||
message = "The certificate authority is not trusted";
|
||||
break;
|
||||
}
|
||||
obj.put("message", message);
|
||||
|
||||
channel.invokeMethod("onReceivedServerTrustAuthRequest", obj, new MethodChannel.Result() {
|
||||
channel.invokeMethod("onReceivedServerTrustAuthRequest", challenge.toMap(), new MethodChannel.Result() {
|
||||
@Override
|
||||
public void success(Object response) {
|
||||
if (response != null) {
|
||||
@ -496,7 +424,7 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
}
|
||||
}
|
||||
|
||||
InAppWebViewClient.super.onReceivedSslError(view, handler, error);
|
||||
InAppWebViewClient.super.onReceivedSslError(view, handler, sslError);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -506,7 +434,7 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
|
||||
@Override
|
||||
public void notImplemented() {
|
||||
InAppWebViewClient.super.onReceivedSslError(view, handler, error);
|
||||
InAppWebViewClient.super.onReceivedSslError(view, handler, sslError);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -524,16 +452,15 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
return;
|
||||
}
|
||||
|
||||
final String host = request.getHost();
|
||||
final String protocol = uri.getScheme();
|
||||
final String realm = null;
|
||||
final int port = request.getPort();
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("host", request.getHost());
|
||||
obj.put("protocol", protocol);
|
||||
obj.put("realm", realm);
|
||||
obj.put("port", request.getPort());
|
||||
URLProtectionSpace protectionSpace = new URLProtectionSpace(host, protocol, realm, port, view.getCertificate(), null);
|
||||
ClientCertChallenge challenge = new ClientCertChallenge(protectionSpace, request.getPrincipals(), request.getKeyTypes());
|
||||
|
||||
channel.invokeMethod("onReceivedClientCertRequest", obj, new MethodChannel.Result() {
|
||||
channel.invokeMethod("onReceivedClientCertRequest", challenge.toMap(), new MethodChannel.Result() {
|
||||
@Override
|
||||
public void success(Object response) {
|
||||
if (response != null) {
|
||||
@ -644,9 +571,7 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
|
||||
if (webView.options.useShouldInterceptRequest) {
|
||||
WebResourceResponse onShouldInterceptResponse = onShouldInterceptRequest(url);
|
||||
if (onShouldInterceptResponse != null) {
|
||||
return onShouldInterceptResponse;
|
||||
}
|
||||
return onShouldInterceptResponse;
|
||||
}
|
||||
|
||||
URI uri;
|
||||
@ -669,7 +594,6 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
if (webView.options.resourceCustomSchemes != null && webView.options.resourceCustomSchemes.contains(scheme)) {
|
||||
final Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("url", url);
|
||||
obj.put("scheme", scheme);
|
||||
|
||||
Util.WaitFlutterResult flutterResult;
|
||||
try {
|
||||
@ -686,14 +610,14 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
Map<String, Object> res = (Map<String, Object>) flutterResult.result;
|
||||
WebResourceResponse response = null;
|
||||
try {
|
||||
response = webView.contentBlockerHandler.checkUrl(webView, url, res.get("content-type").toString());
|
||||
response = webView.contentBlockerHandler.checkUrl(webView, url, res.get("contentType").toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (response != null)
|
||||
return response;
|
||||
byte[] data = (byte[]) res.get("data");
|
||||
return new WebResourceResponse(res.get("content-type").toString(), res.get("content-encoding").toString(), new ByteArrayInputStream(data));
|
||||
return new WebResourceResponse(res.get("contentType").toString(), res.get("contentEncoding").toString(), new ByteArrayInputStream(data));
|
||||
}
|
||||
}
|
||||
|
||||
@ -717,9 +641,7 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
|
||||
if (webView.options.useShouldInterceptRequest) {
|
||||
WebResourceResponse onShouldInterceptResponse = onShouldInterceptRequest(request);
|
||||
if (onShouldInterceptResponse != null) {
|
||||
return onShouldInterceptResponse;
|
||||
}
|
||||
return onShouldInterceptResponse;
|
||||
}
|
||||
|
||||
return shouldInterceptRequest(view, url);
|
||||
@ -729,9 +651,9 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
String url = request instanceof String ? (String) request : null;
|
||||
String method = "GET";
|
||||
Map<String, String> headers = null;
|
||||
Boolean hasGesture = false;
|
||||
Boolean isForMainFrame = true;
|
||||
Boolean isRedirect = false;
|
||||
boolean hasGesture = false;
|
||||
boolean isForMainFrame = true;
|
||||
boolean isRedirect = false;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && request instanceof WebResourceRequest) {
|
||||
WebResourceRequest webResourceRequest = (WebResourceRequest) request;
|
||||
@ -869,12 +791,8 @@ public class InAppWebViewClient extends WebViewClient {
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
channel.setMethodCallHandler(null);
|
||||
if (inAppBrowserActivity != null) {
|
||||
inAppBrowserActivity = null;
|
||||
}
|
||||
if (flutterWebView != null) {
|
||||
flutterWebView = null;
|
||||
if (inAppBrowserDelegate != null) {
|
||||
inAppBrowserDelegate = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_webview;
|
||||
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.webkit.WebSettings;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.Options;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.PreferredContentModeOptionType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_webview;
|
||||
|
||||
import android.util.Log;
|
||||
import android.webkit.WebView;
|
||||
@ -9,8 +9,6 @@ import androidx.webkit.WebViewFeature;
|
||||
import androidx.webkit.WebViewRenderProcess;
|
||||
import androidx.webkit.WebViewRenderProcessClient;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ -19,17 +17,12 @@ import io.flutter.plugin.common.MethodChannel;
|
||||
public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient {
|
||||
|
||||
protected static final String LOG_TAG = "IAWRenderProcessClient";
|
||||
private FlutterWebView flutterWebView;
|
||||
private InAppBrowserActivity inAppBrowserActivity;
|
||||
public MethodChannel channel;
|
||||
private final MethodChannel channel;
|
||||
|
||||
public InAppWebViewRenderProcessClient(Object obj) {
|
||||
public InAppWebViewRenderProcessClient(MethodChannel channel) {
|
||||
super();
|
||||
if (obj instanceof InAppBrowserActivity)
|
||||
this.inAppBrowserActivity = (InAppBrowserActivity) obj;
|
||||
else if (obj instanceof FlutterWebView)
|
||||
this.flutterWebView = (FlutterWebView) obj;
|
||||
this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel;
|
||||
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -95,4 +88,8 @@ public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_webview;
|
||||
|
||||
import static android.content.Context.INPUT_METHOD_SERVICE;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
|
||||
package com.pichillilorenzo.flutter_inappwebview.in_app_webview;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
@ -0,0 +1,41 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScriptInjectionTime;
|
||||
|
||||
public class ConsoleLogJS {
|
||||
public static final String CONSOLE_LOG_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_CONSOLE_LOG_JS_PLUGIN_SCRIPT";
|
||||
public static final PluginScript CONSOLE_LOG_JS_PLUGIN_SCRIPT = new PluginScript(
|
||||
ConsoleLogJS.CONSOLE_LOG_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
||||
ConsoleLogJS.CONSOLE_LOG_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
public static final String CONSOLE_LOG_JS_SOURCE = "(function(console) {" +
|
||||
" var oldLogs = {" +
|
||||
" 'log': console.log," +
|
||||
" 'debug': console.debug," +
|
||||
" 'error': console.error," +
|
||||
" 'info': console.info," +
|
||||
" 'warn': console.warn" +
|
||||
" };" +
|
||||
" for (var k in oldLogs) {" +
|
||||
" (function(oldLog) {" +
|
||||
" console[oldLog] = function() {" +
|
||||
" var message = '';" +
|
||||
" for (var i in arguments) {" +
|
||||
" if (message == '') {" +
|
||||
" message += arguments[i];" +
|
||||
" }" +
|
||||
" else {" +
|
||||
" message += ' ' + arguments[i];" +
|
||||
" }" +
|
||||
" }" +
|
||||
" oldLogs[oldLog].call(console, message);" +
|
||||
" }" +
|
||||
" })(k);" +
|
||||
" }" +
|
||||
"})(window.console);";
|
||||
}
|
@ -0,0 +1,232 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScriptInjectionTime;
|
||||
|
||||
public class InterceptAjaxRequestJS {
|
||||
|
||||
public static final String INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT";
|
||||
public static final String FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE = JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._useShouldInterceptAjaxRequest";
|
||||
public static final PluginScript INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT = new PluginScript(
|
||||
InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
||||
InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
public static final String INTERCEPT_AJAX_REQUEST_JS_SOURCE = "(function(ajax) {" +
|
||||
" var w = (window.top == null || window.top === window) ? window : window.top;" +
|
||||
" w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " = true;" +
|
||||
" var send = ajax.prototype.send;" +
|
||||
" var open = ajax.prototype.open;" +
|
||||
" var setRequestHeader = ajax.prototype.setRequestHeader;" +
|
||||
" ajax.prototype._flutter_inappwebview_url = null;" +
|
||||
" ajax.prototype._flutter_inappwebview_method = null;" +
|
||||
" ajax.prototype._flutter_inappwebview_isAsync = null;" +
|
||||
" ajax.prototype._flutter_inappwebview_user = null;" +
|
||||
" ajax.prototype._flutter_inappwebview_password = null;" +
|
||||
" ajax.prototype._flutter_inappwebview_password = null;" +
|
||||
" ajax.prototype._flutter_inappwebview_already_onreadystatechange_wrapped = false;" +
|
||||
" ajax.prototype._flutter_inappwebview_request_headers = {};" +
|
||||
" function convertRequestResponse(request, callback) {" +
|
||||
" if (request.response != null && request.responseType != null) {" +
|
||||
" switch (request.responseType) {" +
|
||||
" case 'arraybuffer':" +
|
||||
" callback(new Uint8Array(request.response));" +
|
||||
" return;" +
|
||||
" case 'blob':" +
|
||||
" const reader = new FileReader();" +
|
||||
" reader.addEventListener('loadend', function() { " +
|
||||
" callback(new Uint8Array(reader.result));" +
|
||||
" });" +
|
||||
" reader.readAsArrayBuffer(blob);" +
|
||||
" return;" +
|
||||
" case 'document':" +
|
||||
" callback(request.response.documentElement.outerHTML);" +
|
||||
" return;" +
|
||||
" case 'json':" +
|
||||
" callback(request.response);" +
|
||||
" return;" +
|
||||
" };" +
|
||||
" }" +
|
||||
" callback(null);" +
|
||||
" };" +
|
||||
" ajax.prototype.open = function(method, url, isAsync, user, password) {" +
|
||||
" isAsync = (isAsync != null) ? isAsync : true;" +
|
||||
" this._flutter_inappwebview_url = url;" +
|
||||
" this._flutter_inappwebview_method = method;" +
|
||||
" this._flutter_inappwebview_isAsync = isAsync;" +
|
||||
" this._flutter_inappwebview_user = user;" +
|
||||
" this._flutter_inappwebview_password = password;" +
|
||||
" this._flutter_inappwebview_request_headers = {};" +
|
||||
" open.call(this, method, url, isAsync, user, password);" +
|
||||
" };" +
|
||||
" ajax.prototype.setRequestHeader = function(header, value) {" +
|
||||
" this._flutter_inappwebview_request_headers[header] = value;" +
|
||||
" setRequestHeader.call(this, header, value);" +
|
||||
" };" +
|
||||
" function handleEvent(e) {" +
|
||||
" var self = this;" +
|
||||
" var w = (window.top == null || window.top === window) ? window : window.top;" +
|
||||
" if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " == true) {" +
|
||||
" var headers = this.getAllResponseHeaders();" +
|
||||
" var responseHeaders = {};" +
|
||||
" if (headers != null) {" +
|
||||
" var arr = headers.trim().split(/[\\r\\n]+/);" +
|
||||
" arr.forEach(function (line) {" +
|
||||
" var parts = line.split(': ');" +
|
||||
" var header = parts.shift();" +
|
||||
" var value = parts.join(': ');" +
|
||||
" responseHeaders[header] = value;" +
|
||||
" });" +
|
||||
" }" +
|
||||
" convertRequestResponse(this, function(response) {" +
|
||||
" var ajaxRequest = {" +
|
||||
" method: self._flutter_inappwebview_method," +
|
||||
" url: self._flutter_inappwebview_url," +
|
||||
" isAsync: self._flutter_inappwebview_isAsync," +
|
||||
" user: self._flutter_inappwebview_user," +
|
||||
" password: self._flutter_inappwebview_password," +
|
||||
" withCredentials: self.withCredentials," +
|
||||
" headers: self._flutter_inappwebview_request_headers," +
|
||||
" readyState: self.readyState," +
|
||||
" status: self.status," +
|
||||
" responseURL: self.responseURL," +
|
||||
" responseType: self.responseType," +
|
||||
" response: response," +
|
||||
" responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null," +
|
||||
" responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null," +
|
||||
" statusText: self.statusText," +
|
||||
" responseHeaders, responseHeaders," +
|
||||
" event: {" +
|
||||
" type: e.type," +
|
||||
" loaded: e.loaded," +
|
||||
" lengthComputable: e.lengthComputable," +
|
||||
" total: e.total" +
|
||||
" }" +
|
||||
" };" +
|
||||
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onAjaxProgress', ajaxRequest).then(function(result) {" +
|
||||
" if (result != null) {" +
|
||||
" switch (result) {" +
|
||||
" case 0:" +
|
||||
" self.abort();" +
|
||||
" return;" +
|
||||
" };" +
|
||||
" }" +
|
||||
" });" +
|
||||
" });" +
|
||||
" }" +
|
||||
" };" +
|
||||
" ajax.prototype.send = function(data) {" +
|
||||
" var self = this;" +
|
||||
" var w = (window.top == null || window.top === window) ? window : window.top;" +
|
||||
" if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " == true) {" +
|
||||
" if (!this._flutter_inappwebview_already_onreadystatechange_wrapped) {" +
|
||||
" this._flutter_inappwebview_already_onreadystatechange_wrapped = true;" +
|
||||
" var onreadystatechange = this.onreadystatechange;" +
|
||||
" this.onreadystatechange = function() {" +
|
||||
" var w = (window.top == null || window.top === window) ? window : window.top;" +
|
||||
" if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " == true) {" +
|
||||
" var headers = this.getAllResponseHeaders();" +
|
||||
" var responseHeaders = {};" +
|
||||
" if (headers != null) {" +
|
||||
" var arr = headers.trim().split(/[\\r\\n]+/);" +
|
||||
" arr.forEach(function (line) {" +
|
||||
" var parts = line.split(': ');" +
|
||||
" var header = parts.shift();" +
|
||||
" var value = parts.join(': ');" +
|
||||
" responseHeaders[header] = value;" +
|
||||
" });" +
|
||||
" }" +
|
||||
" convertRequestResponse(this, function(response) {" +
|
||||
" var ajaxRequest = {" +
|
||||
" method: self._flutter_inappwebview_method," +
|
||||
" url: self._flutter_inappwebview_url," +
|
||||
" isAsync: self._flutter_inappwebview_isAsync," +
|
||||
" user: self._flutter_inappwebview_user," +
|
||||
" password: self._flutter_inappwebview_password," +
|
||||
" withCredentials: self.withCredentials," +
|
||||
" headers: self._flutter_inappwebview_request_headers," +
|
||||
" readyState: self.readyState," +
|
||||
" status: self.status," +
|
||||
" responseURL: self.responseURL," +
|
||||
" responseType: self.responseType," +
|
||||
" response: response," +
|
||||
" responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null," +
|
||||
" responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null," +
|
||||
" statusText: self.statusText," +
|
||||
" responseHeaders: responseHeaders" +
|
||||
" };" +
|
||||
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onAjaxReadyStateChange', ajaxRequest).then(function(result) {" +
|
||||
" if (result != null) {" +
|
||||
" switch (result) {" +
|
||||
" case 0:" +
|
||||
" self.abort();" +
|
||||
" return;" +
|
||||
" };" +
|
||||
" }" +
|
||||
" if (onreadystatechange != null) {" +
|
||||
" onreadystatechange();" +
|
||||
" }" +
|
||||
" });" +
|
||||
" });" +
|
||||
" } else if (onreadystatechange != null) {" +
|
||||
" onreadystatechange();" +
|
||||
" }" +
|
||||
" };" +
|
||||
" }" +
|
||||
" this.addEventListener('loadstart', handleEvent);" +
|
||||
" this.addEventListener('load', handleEvent);" +
|
||||
" this.addEventListener('loadend', handleEvent);" +
|
||||
" this.addEventListener('progress', handleEvent);" +
|
||||
" this.addEventListener('error', handleEvent);" +
|
||||
" this.addEventListener('abort', handleEvent);" +
|
||||
" this.addEventListener('timeout', handleEvent);" +
|
||||
" var ajaxRequest = {" +
|
||||
" data: data," +
|
||||
" method: this._flutter_inappwebview_method," +
|
||||
" url: this._flutter_inappwebview_url," +
|
||||
" isAsync: this._flutter_inappwebview_isAsync," +
|
||||
" user: this._flutter_inappwebview_user," +
|
||||
" password: this._flutter_inappwebview_password," +
|
||||
" withCredentials: this.withCredentials," +
|
||||
" headers: this._flutter_inappwebview_request_headers," +
|
||||
" responseType: this.responseType" +
|
||||
" };" +
|
||||
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('shouldInterceptAjaxRequest', ajaxRequest).then(function(result) {" +
|
||||
" if (result != null) {" +
|
||||
" switch (result.action) {" +
|
||||
" case 0:" +
|
||||
" self.abort();" +
|
||||
" return;" +
|
||||
" };" +
|
||||
" data = result.data;" +
|
||||
" self.withCredentials = result.withCredentials;" +
|
||||
" if (result.responseType != null) {" +
|
||||
" self.responseType = result.responseType;" +
|
||||
" };" +
|
||||
" for (var header in result.headers) {" +
|
||||
" var value = result.headers[header];" +
|
||||
" var flutter_inappwebview_value = self._flutter_inappwebview_request_headers[header];" +
|
||||
" if (flutter_inappwebview_value == null) {" +
|
||||
" self._flutter_inappwebview_request_headers[header] = value;" +
|
||||
" } else {" +
|
||||
" self._flutter_inappwebview_request_headers[header] += ', ' + value;" +
|
||||
" }" +
|
||||
" setRequestHeader.call(self, header, value);" +
|
||||
" };" +
|
||||
" if ((self._flutter_inappwebview_method != result.method && result.method != null) || (self._flutter_inappwebview_url != result.url && result.url != null)) {" +
|
||||
" self.abort();" +
|
||||
" self.open(result.method, result.url, result.isAsync, result.user, result.password);" +
|
||||
" return;" +
|
||||
" }" +
|
||||
" }" +
|
||||
" send.call(self, data);" +
|
||||
" });" +
|
||||
" } else {" +
|
||||
" send.call(this, data);" +
|
||||
" }" +
|
||||
" };" +
|
||||
"})(window.XMLHttpRequest);";
|
||||
}
|
@ -0,0 +1,200 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScriptInjectionTime;
|
||||
|
||||
public class InterceptFetchRequestJS {
|
||||
|
||||
public static final String INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT";
|
||||
public static final String FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE = JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._useShouldInterceptFetchRequest";
|
||||
public static final PluginScript INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT = new PluginScript(
|
||||
InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
||||
InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
public static final String INTERCEPT_FETCH_REQUEST_JS_SOURCE = "(function(fetch) {" +
|
||||
" var w = (window.top == null || window.top === window) ? window : window.top;" +
|
||||
" w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE + " = true;" +
|
||||
" if (fetch == null) {" +
|
||||
" return;" +
|
||||
" }" +
|
||||
" function convertHeadersToJson(headers) {" +
|
||||
" var headersObj = {};" +
|
||||
" for (var header of headers.keys()) {" +
|
||||
" var value = headers.get(header);" +
|
||||
" headersObj[header] = value;" +
|
||||
" }" +
|
||||
" return headersObj;" +
|
||||
" }" +
|
||||
" function convertJsonToHeaders(headersJson) {" +
|
||||
" return new Headers(headersJson);" +
|
||||
" }" +
|
||||
" function convertBodyToArray(body) {" +
|
||||
" return new Response(body).arrayBuffer().then(function(arrayBuffer) {" +
|
||||
" var arr = Array.from(new Uint8Array(arrayBuffer));" +
|
||||
" return arr;" +
|
||||
" })" +
|
||||
" }" +
|
||||
" function convertArrayIntBodyToUint8Array(arrayIntBody) {" +
|
||||
" return new Uint8Array(arrayIntBody);" +
|
||||
" }" +
|
||||
" function convertCredentialsToJson(credentials) {" +
|
||||
" var credentialsObj = {};" +
|
||||
" if (window.FederatedCredential != null && credentials instanceof FederatedCredential) {" +
|
||||
" credentialsObj.type = credentials.type;" +
|
||||
" credentialsObj.id = credentials.id;" +
|
||||
" credentialsObj.name = credentials.name;" +
|
||||
" credentialsObj.protocol = credentials.protocol;" +
|
||||
" credentialsObj.provider = credentials.provider;" +
|
||||
" credentialsObj.iconURL = credentials.iconURL;" +
|
||||
" } else if (window.PasswordCredential != null && credentials instanceof PasswordCredential) {" +
|
||||
" credentialsObj.type = credentials.type;" +
|
||||
" credentialsObj.id = credentials.id;" +
|
||||
" credentialsObj.name = credentials.name;" +
|
||||
" credentialsObj.password = credentials.password;" +
|
||||
" credentialsObj.iconURL = credentials.iconURL;" +
|
||||
" } else {" +
|
||||
" credentialsObj.type = 'default';" +
|
||||
" credentialsObj.value = credentials;" +
|
||||
" }" +
|
||||
" }" +
|
||||
" function convertJsonToCredential(credentialsJson) {" +
|
||||
" var credentials;" +
|
||||
" if (window.FederatedCredential != null && credentialsJson.type === 'federated') {" +
|
||||
" credentials = new FederatedCredential({" +
|
||||
" id: credentialsJson.id," +
|
||||
" name: credentialsJson.name," +
|
||||
" protocol: credentialsJson.protocol," +
|
||||
" provider: credentialsJson.provider," +
|
||||
" iconURL: credentialsJson.iconURL" +
|
||||
" });" +
|
||||
" } else if (window.PasswordCredential != null && credentialsJson.type === 'password') {" +
|
||||
" credentials = new PasswordCredential({" +
|
||||
" id: credentialsJson.id," +
|
||||
" name: credentialsJson.name," +
|
||||
" password: credentialsJson.password," +
|
||||
" iconURL: credentialsJson.iconURL" +
|
||||
" });" +
|
||||
" } else {" +
|
||||
" credentials = credentialsJson;" +
|
||||
" }" +
|
||||
" return credentials;" +
|
||||
" }" +
|
||||
" window.fetch = async function(resource, init) {" +
|
||||
" var w = (window.top == null || window.top === window) ? window : window.top;" +
|
||||
" if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE + " == true) {" +
|
||||
" var fetchRequest = {" +
|
||||
" url: null," +
|
||||
" method: null," +
|
||||
" headers: null," +
|
||||
" body: null," +
|
||||
" mode: null," +
|
||||
" credentials: null," +
|
||||
" cache: null," +
|
||||
" redirect: null," +
|
||||
" referrer: null," +
|
||||
" referrerPolicy: null," +
|
||||
" integrity: null," +
|
||||
" keepalive: null" +
|
||||
" };" +
|
||||
" if (resource instanceof Request) {" +
|
||||
" fetchRequest.url = resource.url;" +
|
||||
" fetchRequest.method = resource.method;" +
|
||||
" fetchRequest.headers = resource.headers;" +
|
||||
" fetchRequest.body = resource.body;" +
|
||||
" fetchRequest.mode = resource.mode;" +
|
||||
" fetchRequest.credentials = resource.credentials;" +
|
||||
" fetchRequest.cache = resource.cache;" +
|
||||
" fetchRequest.redirect = resource.redirect;" +
|
||||
" fetchRequest.referrer = resource.referrer;" +
|
||||
" fetchRequest.referrerPolicy = resource.referrerPolicy;" +
|
||||
" fetchRequest.integrity = resource.integrity;" +
|
||||
" fetchRequest.keepalive = resource.keepalive;" +
|
||||
" } else {" +
|
||||
" fetchRequest.url = resource;" +
|
||||
" if (init != null) {" +
|
||||
" fetchRequest.method = init.method;" +
|
||||
" fetchRequest.headers = init.headers;" +
|
||||
" fetchRequest.body = init.body;" +
|
||||
" fetchRequest.mode = init.mode;" +
|
||||
" fetchRequest.credentials = init.credentials;" +
|
||||
" fetchRequest.cache = init.cache;" +
|
||||
" fetchRequest.redirect = init.redirect;" +
|
||||
" fetchRequest.referrer = init.referrer;" +
|
||||
" fetchRequest.referrerPolicy = init.referrerPolicy;" +
|
||||
" fetchRequest.integrity = init.integrity;" +
|
||||
" fetchRequest.keepalive = init.keepalive;" +
|
||||
" }" +
|
||||
" }" +
|
||||
" if (fetchRequest.headers instanceof Headers) {" +
|
||||
" fetchRequest.headers = convertHeadersToJson(fetchRequest.headers);" +
|
||||
" }" +
|
||||
" fetchRequest.credentials = convertCredentialsToJson(fetchRequest.credentials);" +
|
||||
" return convertBodyToArray(fetchRequest.body).then(function(body) {" +
|
||||
" fetchRequest.body = body;" +
|
||||
" return window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('shouldInterceptFetchRequest', fetchRequest).then(function(result) {" +
|
||||
" if (result != null) {" +
|
||||
" switch (result.action) {" +
|
||||
" case 0:" +
|
||||
" var controller = new AbortController();" +
|
||||
" if (init != null) {" +
|
||||
" init.signal = controller.signal;" +
|
||||
" } else {" +
|
||||
" init = {" +
|
||||
" signal: controller.signal" +
|
||||
" };" +
|
||||
" }" +
|
||||
" controller.abort();" +
|
||||
" break;" +
|
||||
" }" +
|
||||
" resource = (result.url != null) ? result.url : resource;" +
|
||||
" if (init == null) {" +
|
||||
" init = {};" +
|
||||
" }" +
|
||||
" if (result.method != null && result.method.length > 0) {" +
|
||||
" init.method = result.method;" +
|
||||
" }" +
|
||||
" if (result.headers != null && Object.keys(result.headers).length > 0) {" +
|
||||
" init.headers = convertJsonToHeaders(result.headers);" +
|
||||
" }" +
|
||||
" if (result.body != null && result.body.length > 0) {" +
|
||||
" init.body = convertArrayIntBodyToUint8Array(result.body);" +
|
||||
" }" +
|
||||
" if (result.mode != null && result.mode.length > 0) {" +
|
||||
" init.mode = result.mode;" +
|
||||
" }" +
|
||||
" if (result.credentials != null) {" +
|
||||
" init.credentials = convertJsonToCredential(result.credentials);" +
|
||||
" }" +
|
||||
" if (result.cache != null && result.cache.length > 0) {" +
|
||||
" init.cache = result.cache;" +
|
||||
" }" +
|
||||
" if (result.redirect != null && result.redirect.length > 0) {" +
|
||||
" init.redirect = result.redirect;" +
|
||||
" }" +
|
||||
" if (result.referrer != null && result.referrer.length > 0) {" +
|
||||
" init.referrer = result.referrer;" +
|
||||
" }" +
|
||||
" if (result.referrerPolicy != null && result.referrerPolicy.length > 0) {" +
|
||||
" init.referrerPolicy = result.referrerPolicy;" +
|
||||
" }" +
|
||||
" if (result.integrity != null && result.integrity.length > 0) {" +
|
||||
" init.integrity = result.integrity;" +
|
||||
" }" +
|
||||
" if (result.keepalive != null) {" +
|
||||
" init.keepalive = result.keepalive;" +
|
||||
" }" +
|
||||
" return fetch(resource, init);" +
|
||||
" }" +
|
||||
" return fetch(resource, init);" +
|
||||
" });" +
|
||||
" });" +
|
||||
" } else {" +
|
||||
" return fetch(resource, init);" +
|
||||
" }" +
|
||||
" };" +
|
||||
"})(window.fetch);";
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScriptInjectionTime;
|
||||
|
||||
public class JavaScriptBridgeJS {
|
||||
public static final String JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview";
|
||||
public static final String JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT";
|
||||
public static final PluginScript JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT = new PluginScript(
|
||||
JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
||||
JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
public static final String JAVASCRIPT_BRIDGE_JS_SOURCE = "if (window.top == null || window.top === window) {" +
|
||||
" window." + JAVASCRIPT_BRIDGE_NAME + ".callHandler = function() {" +
|
||||
" var _callHandlerID = setTimeout(function(){});" +
|
||||
" window." + JAVASCRIPT_BRIDGE_NAME + "._callHandler(arguments[0], _callHandlerID, JSON.stringify(Array.prototype.slice.call(arguments, 1)));" +
|
||||
" return new Promise(function(resolve, reject) {" +
|
||||
" window." + JAVASCRIPT_BRIDGE_NAME + "[_callHandlerID] = resolve;" +
|
||||
" });" +
|
||||
" };"+
|
||||
"} else {" +
|
||||
" window." + JAVASCRIPT_BRIDGE_NAME + " = {};" +
|
||||
" window." + JAVASCRIPT_BRIDGE_NAME + ".callHandler = function() {" +
|
||||
" var _callHandlerID = setTimeout(function(){});" +
|
||||
" window.top." + JAVASCRIPT_BRIDGE_NAME + "._callHandler(arguments[0], _callHandlerID, JSON.stringify(Array.prototype.slice.call(arguments, 1)));" +
|
||||
" return new Promise(function(resolve, reject) {" +
|
||||
" window.top." + JAVASCRIPT_BRIDGE_NAME + "[_callHandlerID] = resolve;" +
|
||||
" });" +
|
||||
" };"+
|
||||
"}";
|
||||
|
||||
public static final String PLATFORM_READY_JS_SOURCE = "(function() {" +
|
||||
" if ((window.top == null || window.top === window) && window." + JAVASCRIPT_BRIDGE_NAME + "._platformReady == null) {" +
|
||||
" window.dispatchEvent(new Event('flutterInAppWebViewPlatformReady'));" +
|
||||
" window." + JAVASCRIPT_BRIDGE_NAME + "._platformReady = true;" +
|
||||
" }" +
|
||||
"})();";
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScriptInjectionTime;
|
||||
|
||||
public class OnLoadResourceJS {
|
||||
public static final String ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT";
|
||||
public static final String FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE = JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._useOnLoadResource";
|
||||
public static final PluginScript ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT = new PluginScript(
|
||||
OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
||||
OnLoadResourceJS.ON_LOAD_RESOURCE_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
public static final String ON_LOAD_RESOURCE_JS_SOURCE = "window." + FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE + " = true;" +
|
||||
"(function() {" +
|
||||
" var observer = new PerformanceObserver(function(list) {" +
|
||||
" list.getEntries().forEach(function(entry) {" +
|
||||
" if (" + FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE + " == null || " + FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE + " == true) {" +
|
||||
" var resource = {" +
|
||||
" 'url': entry.name," +
|
||||
" 'initiatorType': entry.initiatorType," +
|
||||
" 'startTime': entry.startTime," +
|
||||
" 'duration': entry.duration" +
|
||||
" };" +
|
||||
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onLoadResource', resource);" +
|
||||
" }" +
|
||||
" });" +
|
||||
" });" +
|
||||
" observer.observe({entryTypes: ['resource']});" +
|
||||
"})();";
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScriptInjectionTime;
|
||||
|
||||
public class OnWindowBlurEventJS {
|
||||
public static final String ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT";
|
||||
public static final PluginScript ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT = new PluginScript(
|
||||
OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
||||
OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
public static final String ON_WINDOW_BLUR_EVENT_JS_SOURCE = "(function(){" +
|
||||
" window.addEventListener('blur', function(e) {" +
|
||||
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onWindowBlur');" +
|
||||
" });" +
|
||||
"})();";
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScriptInjectionTime;
|
||||
|
||||
public class OnWindowFocusEventJS {
|
||||
public static final String ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT";
|
||||
public static final PluginScript ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT = new PluginScript(
|
||||
OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
||||
OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
public static final String ON_WINDOW_FOCUS_EVENT_JS_SOURCE = "(function(){" +
|
||||
" window.addEventListener('focus', function(e) {" +
|
||||
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onWindowFocus');" +
|
||||
" });" +
|
||||
"})();";
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.UserContentController;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScriptInjectionTime;
|
||||
|
||||
public class PluginScriptsUtil {
|
||||
|
||||
public static final String VAR_PLACEHOLDER_VALUE = "$IN_APP_WEBVIEW_PLACEHOLDER_VALUE";
|
||||
public static final String VAR_CONTENT_WORLD_NAME_ARRAY = "$IN_APP_WEBVIEW_CONTENT_WORLD_NAME_ARRAY";
|
||||
public static final String VAR_CONTENT_WORLD_NAME = "$IN_APP_WEBVIEW_CONTENT_WORLD_NAME";
|
||||
public static final String VAR_JSON_SOURCE_ENCODED = "$IN_APP_WEBVIEW_JSON_SOURCE_ENCODED";
|
||||
public static final String VAR_FUNCTION_ARGUMENT_NAMES = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENT_NAMES";
|
||||
public static final String VAR_FUNCTION_ARGUMENT_VALUES = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENT_VALUES";
|
||||
public static final String VAR_FUNCTION_ARGUMENTS_OBJ = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENTS_OBJ";
|
||||
public static final String VAR_FUNCTION_BODY = "$IN_APP_WEBVIEW_FUNCTION_BODY";
|
||||
public static final String VAR_RESULT_UUID = "$IN_APP_WEBVIEW_RESULT_UUID";
|
||||
|
||||
public static final String CALL_ASYNC_JAVA_SCRIPT_WRAPPER_JS_SOURCE = "(function(obj) {" +
|
||||
" (async function(" + VAR_FUNCTION_ARGUMENT_NAMES + ") {" +
|
||||
" " + VAR_FUNCTION_BODY +
|
||||
" })(" + VAR_FUNCTION_ARGUMENT_VALUES + ").then(function(value) {" +
|
||||
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('callAsyncJavaScript', {'value': value, 'error': null, 'resultUuid': '" + VAR_RESULT_UUID + "'});" +
|
||||
" }).catch(function(error) {" +
|
||||
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('callAsyncJavaScript', {'value': null, 'error': error + '', 'resultUuid': '" + VAR_RESULT_UUID + "'});" +
|
||||
" });" +
|
||||
" return null;" +
|
||||
"})(" + VAR_FUNCTION_ARGUMENTS_OBJ + ");";
|
||||
|
||||
public static final String EVALUATE_JAVASCRIPT_WITH_CONTENT_WORLD_WRAPPER_JS_SOURCE = "window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('evaluateJavaScriptWithContentWorld', {'value': eval(" + VAR_PLACEHOLDER_VALUE + "), 'resultUuid': '" + VAR_RESULT_UUID + "'});";
|
||||
|
||||
public static final String IS_ACTIVE_ELEMENT_INPUT_EDITABLE_JS_SOURCE =
|
||||
"var activeEl = document.activeElement;" +
|
||||
"var nodeName = (activeEl != null) ? activeEl.nodeName.toLowerCase() : '';" +
|
||||
"var isActiveElementInputEditable = activeEl != null && " +
|
||||
"(activeEl.nodeType == 1 && (nodeName == 'textarea' || (nodeName == 'input' && /^(?:text|email|number|search|tel|url|password)$/i.test(activeEl.type != null ? activeEl.type : 'text')))) && " +
|
||||
"!activeEl.disabled && !activeEl.readOnly;" +
|
||||
"var isActiveElementEditable = isActiveElementInputEditable || (activeEl != null && activeEl.isContentEditable) || document.designMode === 'on';";
|
||||
|
||||
// android Workaround to hide context menu when selected text is empty
|
||||
// and the document active element is not an input element.
|
||||
public static final String CHECK_CONTEXT_MENU_SHOULD_BE_HIDDEN_JS_SOURCE = "(function(){" +
|
||||
" var txt;" +
|
||||
" if (window.getSelection) {" +
|
||||
" txt = window.getSelection().toString();" +
|
||||
" } else if (window.document.getSelection) {" +
|
||||
" txt = window.document.getSelection().toString();" +
|
||||
" } else if (window.document.selection) {" +
|
||||
" txt = window.document.selection.createRange().text;" +
|
||||
" }" +
|
||||
IS_ACTIVE_ELEMENT_INPUT_EDITABLE_JS_SOURCE +
|
||||
" return txt === '' && !isActiveElementEditable;" +
|
||||
"})();";
|
||||
|
||||
public static final String GET_SELECTED_TEXT_JS_SOURCE = "(function(){" +
|
||||
" var txt;" +
|
||||
" if (window.getSelection) {" +
|
||||
" txt = window.getSelection().toString();" +
|
||||
" } else if (window.document.getSelection) {" +
|
||||
" txt = window.document.getSelection().toString();" +
|
||||
" } else if (window.document.selection) {" +
|
||||
" txt = window.document.selection.createRange().text;" +
|
||||
" }" +
|
||||
" return txt;" +
|
||||
"})();";
|
||||
|
||||
public static final String CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT_GROUP_NAME = "CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT";
|
||||
public static final PluginScript CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT = new PluginScript(
|
||||
PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
||||
PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
// android Workaround to hide context menu when user emit a keydown event
|
||||
public static final String CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_SOURCE = "(function(){" +
|
||||
" document.addEventListener('keydown', function(e) {" +
|
||||
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._hideContextMenu();" +
|
||||
" });" +
|
||||
"})();";
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScriptInjectionTime;
|
||||
|
||||
public class PrintJS {
|
||||
public static final String PRINT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_PRINT_JS_PLUGIN_SCRIPT";
|
||||
public static final PluginScript PRINT_JS_PLUGIN_SCRIPT = new PluginScript(
|
||||
PrintJS.PRINT_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
||||
PrintJS.PRINT_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
public static final String PRINT_JS_SOURCE = "window.print = function() {" +
|
||||
" if (window.top == null || window.top === window) {" +
|
||||
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onPrint', window.location.href);" +
|
||||
" } else {" +
|
||||
" window.top.print();" +
|
||||
" }" +
|
||||
"};";
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,86 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ClientCertChallenge extends URLAuthenticationChallenge {
|
||||
@Nullable
|
||||
private Principal[] principals;
|
||||
@Nullable
|
||||
private String[] keyTypes;
|
||||
|
||||
public ClientCertChallenge(URLProtectionSpace protectionSpace, @Nullable Principal[] principals, @Nullable String[] keyTypes) {
|
||||
super(protectionSpace);
|
||||
this.principals = principals;
|
||||
this.keyTypes = keyTypes;
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
List<String> principalList = null;
|
||||
if (principals != null) {
|
||||
principalList = new ArrayList<>();
|
||||
for (Principal principal : principals) {
|
||||
principalList.add(principal.getName());
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> challengeMap = super.toMap();
|
||||
challengeMap.put("androidPrincipals", principalList);
|
||||
challengeMap.put("androidKeyTypes", keyTypes != null ? Arrays.asList(keyTypes) : null);
|
||||
return challengeMap;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Principal[] getPrincipals() {
|
||||
return principals;
|
||||
}
|
||||
|
||||
public void setPrincipals(@Nullable Principal[] principals) {
|
||||
this.principals = principals;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String[] getKeyTypes() {
|
||||
return keyTypes;
|
||||
}
|
||||
|
||||
public void setKeyTypes(@Nullable String[] keyTypes) {
|
||||
this.keyTypes = keyTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
|
||||
ClientCertChallenge that = (ClientCertChallenge) o;
|
||||
|
||||
// Probably incorrect - comparing Object[] arrays with Arrays.equals
|
||||
if (!Arrays.equals(principals, that.principals)) return false;
|
||||
// Probably incorrect - comparing Object[] arrays with Arrays.equals
|
||||
return Arrays.equals(keyTypes, that.keyTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + Arrays.hashCode(principals);
|
||||
result = 31 * result + Arrays.hashCode(keyTypes);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClientCertChallenge{" +
|
||||
"principals=" + Arrays.toString(principals) +
|
||||
", keyTypes=" + Arrays.toString(keyTypes) +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ContentWorld {
|
||||
@NonNull
|
||||
private String name;
|
||||
|
||||
public static final ContentWorld PAGE = new ContentWorld("page");
|
||||
public static final ContentWorld DEFAULT_CLIENT = new ContentWorld("defaultClient");
|
||||
|
||||
private ContentWorld(@NonNull String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static ContentWorld world(@NonNull String name) {
|
||||
return new ContentWorld(name);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ContentWorld fromMap(@Nullable Map<String, Object> map) {
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
String name = (String) map.get("name");
|
||||
assert name != null;
|
||||
return new ContentWorld(name);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(@NonNull String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ContentWorld that = (ContentWorld) o;
|
||||
|
||||
return name.equals(that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ContentWorld{" +
|
||||
"name='" + name + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class CreateWindowAction extends NavigationAction {
|
||||
int windowId;
|
||||
boolean isDialog;
|
||||
|
||||
public CreateWindowAction(URLRequest request, boolean isForMainFrame, boolean hasGesture, boolean isRedirect, int windowId, boolean isDialog) {
|
||||
super(request, isForMainFrame, hasGesture, isRedirect);
|
||||
this.windowId = windowId;
|
||||
this.isDialog = isDialog;
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> createWindowActionMap = super.toMap();
|
||||
createWindowActionMap.put("windowId", windowId);
|
||||
createWindowActionMap.put("androidIsDialog", isDialog);
|
||||
return createWindowActionMap;
|
||||
}
|
||||
|
||||
public int getWindowId() {
|
||||
return windowId;
|
||||
}
|
||||
|
||||
public void setWindowId(int windowId) {
|
||||
this.windowId = windowId;
|
||||
}
|
||||
|
||||
public boolean isDialog() {
|
||||
return isDialog;
|
||||
}
|
||||
|
||||
public void setDialog(boolean dialog) {
|
||||
isDialog = dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
|
||||
CreateWindowAction that = (CreateWindowAction) o;
|
||||
|
||||
if (windowId != that.windowId) return false;
|
||||
return isDialog == that.isDialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + windowId;
|
||||
result = 31 * result + (isDialog ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CreateWindowAction{" +
|
||||
"windowId=" + windowId +
|
||||
", isDialog=" + isDialog +
|
||||
", request=" + request +
|
||||
", isForMainFrame=" + isForMainFrame +
|
||||
", hasGesture=" + hasGesture +
|
||||
", isRedirect=" + isRedirect +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpAuthenticationChallenge extends URLAuthenticationChallenge {
|
||||
private int previousFailureCount;
|
||||
@Nullable
|
||||
URLCredential proposedCredential;
|
||||
|
||||
public HttpAuthenticationChallenge(URLProtectionSpace protectionSpace, int previousFailureCount, @Nullable URLCredential proposedCredential) {
|
||||
super(protectionSpace);
|
||||
this.previousFailureCount = previousFailureCount;
|
||||
this.proposedCredential = proposedCredential;
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> challengeMap = super.toMap();
|
||||
challengeMap.put("previousFailureCount", previousFailureCount);
|
||||
challengeMap.put("proposedCredential", (proposedCredential != null) ? proposedCredential.toMap() : null);
|
||||
return challengeMap;
|
||||
}
|
||||
|
||||
public int getPreviousFailureCount() {
|
||||
return previousFailureCount;
|
||||
}
|
||||
|
||||
public void setPreviousFailureCount(int previousFailureCount) {
|
||||
this.previousFailureCount = previousFailureCount;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public URLCredential getProposedCredential() {
|
||||
return proposedCredential;
|
||||
}
|
||||
|
||||
public void setProposedCredential(@Nullable URLCredential proposedCredential) {
|
||||
this.proposedCredential = proposedCredential;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
|
||||
HttpAuthenticationChallenge that = (HttpAuthenticationChallenge) o;
|
||||
|
||||
if (previousFailureCount != that.previousFailureCount) return false;
|
||||
return proposedCredential != null ? proposedCredential.equals(that.proposedCredential) : that.proposedCredential == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + previousFailureCount;
|
||||
result = 31 * result + (proposedCredential != null ? proposedCredential.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HttpAuthenticationChallenge{" +
|
||||
"previousFailureCount=" + previousFailureCount +
|
||||
", proposedCredential=" + proposedCredential +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class NavigationAction {
|
||||
URLRequest request;
|
||||
boolean isForMainFrame;
|
||||
boolean hasGesture;
|
||||
boolean isRedirect;
|
||||
|
||||
public NavigationAction(URLRequest request, boolean isForMainFrame, boolean hasGesture, boolean isRedirect) {
|
||||
this.request = request;
|
||||
this.isForMainFrame = isForMainFrame;
|
||||
this.hasGesture = hasGesture;
|
||||
this.isRedirect = isRedirect;
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> navigationActionMap = new HashMap<>();
|
||||
navigationActionMap.put("request", request.toMap());
|
||||
navigationActionMap.put("isForMainFrame", isForMainFrame);
|
||||
navigationActionMap.put("hasGesture", hasGesture);
|
||||
navigationActionMap.put("isRedirect", isRedirect);
|
||||
return navigationActionMap;
|
||||
}
|
||||
|
||||
public URLRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public void setRequest(URLRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public boolean isForMainFrame() {
|
||||
return isForMainFrame;
|
||||
}
|
||||
|
||||
public void setForMainFrame(boolean forMainFrame) {
|
||||
isForMainFrame = forMainFrame;
|
||||
}
|
||||
|
||||
public boolean isHasGesture() {
|
||||
return hasGesture;
|
||||
}
|
||||
|
||||
public void setHasGesture(boolean hasGesture) {
|
||||
this.hasGesture = hasGesture;
|
||||
}
|
||||
|
||||
public boolean isRedirect() {
|
||||
return isRedirect;
|
||||
}
|
||||
|
||||
public void setRedirect(boolean redirect) {
|
||||
isRedirect = redirect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NavigationAction that = (NavigationAction) o;
|
||||
|
||||
if (isForMainFrame != that.isForMainFrame) return false;
|
||||
if (hasGesture != that.hasGesture) return false;
|
||||
if (isRedirect != that.isRedirect) return false;
|
||||
return request.equals(that.request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = request.hashCode();
|
||||
result = 31 * result + (isForMainFrame ? 1 : 0);
|
||||
result = 31 * result + (hasGesture ? 1 : 0);
|
||||
result = 31 * result + (isRedirect ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NavigationAction{" +
|
||||
"request=" + request +
|
||||
", isForMainFrame=" + isForMainFrame +
|
||||
", hasGesture=" + hasGesture +
|
||||
", isRedirect=" + isRedirect +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
public enum NavigationActionPolicy {
|
||||
CANCEL(0),
|
||||
ALLOW(1);
|
||||
|
||||
private final int value;
|
||||
|
||||
private NavigationActionPolicy(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean equalsValue(int otherValue) {
|
||||
return value == otherValue;
|
||||
}
|
||||
|
||||
public static NavigationActionPolicy fromValue(int value) {
|
||||
for( NavigationActionPolicy type : NavigationActionPolicy.values()) {
|
||||
if(value == type.value)
|
||||
return type;
|
||||
}
|
||||
throw new IllegalArgumentException("No enum constant: " + value);
|
||||
}
|
||||
|
||||
public int rawValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.valueOf(this.value);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class PluginScript extends UserScript {
|
||||
private boolean requiredInAllContentWorlds;
|
||||
|
||||
public PluginScript(@Nullable String groupName, @NonNull String source, @NonNull UserScriptInjectionTime injectionTime, @Nullable ContentWorld contentWorld, boolean requiredInAllContentWorlds) {
|
||||
super(groupName, source, injectionTime, contentWorld);
|
||||
this.requiredInAllContentWorlds = requiredInAllContentWorlds;
|
||||
}
|
||||
|
||||
public boolean isRequiredInAllContentWorlds() {
|
||||
return requiredInAllContentWorlds;
|
||||
}
|
||||
|
||||
public void setRequiredInAllContentWorlds(boolean requiredInAllContentWorlds) {
|
||||
this.requiredInAllContentWorlds = requiredInAllContentWorlds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
|
||||
PluginScript that = (PluginScript) o;
|
||||
|
||||
return requiredInAllContentWorlds == that.requiredInAllContentWorlds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + (requiredInAllContentWorlds ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PluginScript{" +
|
||||
"requiredInContentWorld=" + requiredInAllContentWorlds +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
public enum PreferredContentModeOptionType {
|
||||
RECOMMENDED (0),
|
@ -0,0 +1,12 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
public class ServerTrustChallenge extends URLAuthenticationChallenge {
|
||||
public ServerTrustChallenge(URLProtectionSpace protectionSpace) {
|
||||
super(protectionSpace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerTrustChallenge{} " + super.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import android.net.http.SslCertificate;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SslCertificateExt extends SslCertificate {
|
||||
|
||||
private SslCertificateExt(X509Certificate certificate) {
|
||||
super(certificate);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static public Map<String, Object> toMap(@Nullable SslCertificate sslCertificate) {
|
||||
if (sslCertificate == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DName issuedByName = sslCertificate.getIssuedBy();
|
||||
Map<String, Object> issuedBy = null;
|
||||
if (issuedByName != null) {
|
||||
issuedBy = new HashMap<>();
|
||||
issuedBy.put("CName", issuedByName.getCName());
|
||||
issuedBy.put("DName", issuedByName.getDName());
|
||||
issuedBy.put("OName", issuedByName.getOName());
|
||||
issuedBy.put("UName", issuedByName.getUName());
|
||||
}
|
||||
|
||||
DName issuedToName = sslCertificate.getIssuedTo();
|
||||
Map<String, Object> issuedTo = null;
|
||||
if (issuedToName != null) {
|
||||
issuedTo = new HashMap<>();
|
||||
issuedTo.put("CName", issuedToName.getCName());
|
||||
issuedTo.put("DName", issuedToName.getDName());
|
||||
issuedTo.put("OName", issuedToName.getOName());
|
||||
issuedTo.put("UName", issuedToName.getUName());
|
||||
}
|
||||
|
||||
byte[] x509CertificateData = null;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
try {
|
||||
X509Certificate certificate = sslCertificate.getX509Certificate();
|
||||
if (certificate != null) {
|
||||
x509CertificateData = certificate.getEncoded();
|
||||
}
|
||||
} catch (CertificateEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
x509CertificateData = Util.getX509CertFromSslCertHack(sslCertificate).getEncoded();
|
||||
} catch (CertificateEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
long validNotAfterDate = sslCertificate.getValidNotAfterDate().getTime();
|
||||
long validNotBeforeDate = sslCertificate.getValidNotBeforeDate().getTime();
|
||||
|
||||
Map<String, Object> sslCertificateMap = new HashMap<>();
|
||||
sslCertificateMap.put("issuedBy", issuedBy);
|
||||
sslCertificateMap.put("issuedTo", issuedTo);
|
||||
sslCertificateMap.put("validNotAfterDate", validNotAfterDate);
|
||||
sslCertificateMap.put("validNotBeforeDate", validNotBeforeDate);
|
||||
sslCertificateMap.put("x509Certificate", x509CertificateData);
|
||||
return sslCertificateMap;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import android.net.http.SslCertificate;
|
||||
import android.net.http.SslError;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SslErrorExt extends SslError {
|
||||
|
||||
private SslErrorExt(int error, SslCertificate certificate, String url) {
|
||||
super(error, certificate, url);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static public Map<String, Object> toMap(SslError sslError) {
|
||||
if (sslError == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int primaryError = sslError.getPrimaryError();
|
||||
|
||||
String message;
|
||||
switch (primaryError) {
|
||||
case SslError.SSL_DATE_INVALID:
|
||||
message = "The date of the certificate is invalid";
|
||||
break;
|
||||
case SslError.SSL_EXPIRED:
|
||||
message = "The certificate has expired";
|
||||
break;
|
||||
case SslError.SSL_IDMISMATCH:
|
||||
message = "Hostname mismatch";
|
||||
break;
|
||||
case SslError.SSL_INVALID:
|
||||
message = "A generic error occurred";
|
||||
break;
|
||||
case SslError.SSL_NOTYETVALID:
|
||||
message = "The certificate is not yet valid";
|
||||
break;
|
||||
case SslError.SSL_UNTRUSTED:
|
||||
message = "The certificate authority is not trusted";
|
||||
break;
|
||||
default:
|
||||
message = null;
|
||||
break;
|
||||
}
|
||||
|
||||
Map<String, Object> urlProtectionSpaceMap = new HashMap<>();
|
||||
urlProtectionSpaceMap.put("androidError", primaryError);
|
||||
urlProtectionSpaceMap.put("message", message);
|
||||
return urlProtectionSpaceMap;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class URLAuthenticationChallenge {
|
||||
private URLProtectionSpace protectionSpace;
|
||||
|
||||
public URLAuthenticationChallenge(URLProtectionSpace protectionSpace) {
|
||||
this.protectionSpace = protectionSpace;
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> challengeMap = new HashMap<>();
|
||||
challengeMap.put("protectionSpace", protectionSpace.toMap());
|
||||
return challengeMap;
|
||||
}
|
||||
|
||||
public URLProtectionSpace getProtectionSpace() {
|
||||
return protectionSpace;
|
||||
}
|
||||
|
||||
public void setProtectionSpace(URLProtectionSpace protectionSpace) {
|
||||
this.protectionSpace = protectionSpace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
URLAuthenticationChallenge challenge = (URLAuthenticationChallenge) o;
|
||||
|
||||
return protectionSpace.equals(challenge.protectionSpace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return protectionSpace.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "URLAuthenticationChallenge{" +
|
||||
"protectionSpace=" + protectionSpace +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class URLCredential {
|
||||
@Nullable
|
||||
private Long id;
|
||||
@Nullable
|
||||
private String username;
|
||||
@Nullable
|
||||
private String password;
|
||||
@Nullable
|
||||
private Long protectionSpaceId;
|
||||
|
||||
public URLCredential(@Nullable String username, @Nullable String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public URLCredential (@Nullable Long id, @NonNull String username, @NonNull String password, @Nullable Long protectionSpaceId) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.protectionSpaceId = protectionSpaceId;
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> urlCredentialMap = new HashMap<>();
|
||||
urlCredentialMap.put("username", username);
|
||||
urlCredentialMap.put("password", password);
|
||||
return urlCredentialMap;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(@Nullable Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(@Nullable String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(@Nullable String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Long getProtectionSpaceId() {
|
||||
return protectionSpaceId;
|
||||
}
|
||||
|
||||
public void setProtectionSpaceId(@Nullable Long protectionSpaceId) {
|
||||
this.protectionSpaceId = protectionSpaceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
URLCredential that = (URLCredential) o;
|
||||
|
||||
if (username != null ? !username.equals(that.username) : that.username != null) return false;
|
||||
return password != null ? password.equals(that.password) : that.password == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = username != null ? username.hashCode() : 0;
|
||||
result = 31 * result + (password != null ? password.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "URLCredential{" +
|
||||
"username='" + username + '\'' +
|
||||
", password='" + password + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import android.net.http.SslCertificate;
|
||||
import android.net.http.SslError;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class URLProtectionSpace {
|
||||
@Nullable
|
||||
private Long id;
|
||||
private String host;
|
||||
private String protocol;
|
||||
@Nullable
|
||||
private String realm;
|
||||
private int port;
|
||||
@Nullable
|
||||
private SslCertificate sslCertificate;
|
||||
@Nullable
|
||||
private SslError sslError;
|
||||
|
||||
public URLProtectionSpace(String host, String protocol, @Nullable String realm, int port, @Nullable SslCertificate sslCertificate, @Nullable SslError sslError) {
|
||||
this.host = host;
|
||||
this.protocol = protocol;
|
||||
this.realm = realm;
|
||||
this.port = port;
|
||||
this.sslCertificate = sslCertificate;
|
||||
this.sslError = sslError;
|
||||
}
|
||||
|
||||
public URLProtectionSpace(@Nullable Long id, String host, String protocol, @Nullable String realm, int port) {
|
||||
this.id = id;
|
||||
this.host = host;
|
||||
this.protocol = protocol;
|
||||
this.realm = realm;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> urlProtectionSpaceMap = new HashMap<>();
|
||||
urlProtectionSpaceMap.put("host", host);
|
||||
urlProtectionSpaceMap.put("protocol", protocol);
|
||||
urlProtectionSpaceMap.put("realm", realm);
|
||||
urlProtectionSpaceMap.put("port", port);
|
||||
urlProtectionSpaceMap.put("sslCertificate", SslCertificateExt.toMap(sslCertificate));
|
||||
urlProtectionSpaceMap.put("sslError", SslErrorExt.toMap(sslError));
|
||||
return urlProtectionSpaceMap;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(@Nullable Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
public void setRealm(@Nullable String realm) {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SslCertificate getSslCertificate() {
|
||||
return sslCertificate;
|
||||
}
|
||||
|
||||
public void setSslCertificate(@Nullable SslCertificate sslCertificateExt) {
|
||||
this.sslCertificate = sslCertificateExt;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SslError getSslError() {
|
||||
return sslError;
|
||||
}
|
||||
|
||||
public void setSslError(@Nullable SslError sslError) {
|
||||
this.sslError = sslError;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
URLProtectionSpace that = (URLProtectionSpace) o;
|
||||
|
||||
if (port != that.port) return false;
|
||||
if (!host.equals(that.host)) return false;
|
||||
if (!protocol.equals(that.protocol)) return false;
|
||||
if (realm != null ? !realm.equals(that.realm) : that.realm != null) return false;
|
||||
if (sslCertificate != null ? !sslCertificate.equals(that.sslCertificate) : that.sslCertificate != null)
|
||||
return false;
|
||||
return sslError != null ? sslError.equals(that.sslError) : that.sslError == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = host.hashCode();
|
||||
result = 31 * result + protocol.hashCode();
|
||||
result = 31 * result + (realm != null ? realm.hashCode() : 0);
|
||||
result = 31 * result + port;
|
||||
result = 31 * result + (sslCertificate != null ? sslCertificate.hashCode() : 0);
|
||||
result = 31 * result + (sslError != null ? sslError.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "URLProtectionSpace{" +
|
||||
"host='" + host + '\'' +
|
||||
", protocol='" + protocol + '\'' +
|
||||
", realm='" + realm + '\'' +
|
||||
", port=" + port +
|
||||
", sslCertificate=" + sslCertificate +
|
||||
", sslError=" + sslError +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class URLRequest {
|
||||
@NonNull
|
||||
private String url;
|
||||
@Nullable
|
||||
private String method;
|
||||
@Nullable
|
||||
private byte[] body;
|
||||
@Nullable
|
||||
private Map<String, String> headers;
|
||||
|
||||
public URLRequest(@NonNull String url, @Nullable String method, @Nullable byte[] body, @Nullable Map<String, String> headers) {
|
||||
this.url = url;
|
||||
this.method = method;
|
||||
this.body = body;
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static URLRequest fromMap(@Nullable Map<String, Object> map) {
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
String url = (String) map.get("url");
|
||||
String method = (String) map.get("method");
|
||||
byte[] body = (byte[]) map.get("body");
|
||||
Map<String, String> headers = (Map<String, String>) map.get("headers");
|
||||
assert url != null;
|
||||
return new URLRequest(url, method, body, headers);
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> urlRequestMap = new HashMap<>();
|
||||
urlRequestMap.put("url", url);
|
||||
urlRequestMap.put("method", method);
|
||||
urlRequestMap.put("body", body);
|
||||
return urlRequestMap;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(@NonNull String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(@Nullable String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public byte[] getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(@Nullable byte[] body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Map<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(@Nullable Map<String, String> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
URLRequest that = (URLRequest) o;
|
||||
|
||||
if (!url.equals(that.url)) return false;
|
||||
if (method != null ? !method.equals(that.method) : that.method != null) return false;
|
||||
if (!Arrays.equals(body, that.body)) return false;
|
||||
return headers != null ? headers.equals(that.headers) : that.headers == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = url.hashCode();
|
||||
result = 31 * result + (method != null ? method.hashCode() : 0);
|
||||
result = 31 * result + Arrays.hashCode(body);
|
||||
result = 31 * result + (headers != null ? headers.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "URLRequest{" +
|
||||
"url='" + url + '\'' +
|
||||
", method='" + method + '\'' +
|
||||
", body=" + Arrays.toString(body) +
|
||||
", headers=" + headers +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,364 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
|
||||
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.PluginScriptsUtil;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class UserContentController {
|
||||
protected static final String LOG_TAG = "UserContentController";
|
||||
|
||||
@NonNull
|
||||
private final Set<ContentWorld> contentWorlds = new HashSet<ContentWorld>() {{
|
||||
add(ContentWorld.PAGE);
|
||||
}};
|
||||
|
||||
@NonNull
|
||||
private final Map<UserScriptInjectionTime, LinkedHashSet<UserScript>> userOnlyScripts = new HashMap<UserScriptInjectionTime, LinkedHashSet<UserScript>>() {{
|
||||
put(UserScriptInjectionTime.AT_DOCUMENT_START, new LinkedHashSet<UserScript>());
|
||||
put(UserScriptInjectionTime.AT_DOCUMENT_END, new LinkedHashSet<UserScript>());
|
||||
}};
|
||||
@NonNull
|
||||
private final Map<UserScriptInjectionTime, LinkedHashSet<PluginScript>> pluginScripts = new HashMap<UserScriptInjectionTime, LinkedHashSet<PluginScript>>() {{
|
||||
put(UserScriptInjectionTime.AT_DOCUMENT_START, new LinkedHashSet<PluginScript>());
|
||||
put(UserScriptInjectionTime.AT_DOCUMENT_END, new LinkedHashSet<PluginScript>());
|
||||
}};
|
||||
|
||||
public UserContentController() {
|
||||
}
|
||||
|
||||
public String generateWrappedCodeForDocumentStart() {
|
||||
return Util.replaceAll(
|
||||
DOCUMENT_READY_WRAPPER_JS_SOURCE,
|
||||
PluginScriptsUtil.VAR_PLACEHOLDER_VALUE,
|
||||
generateCodeForDocumentStart());
|
||||
}
|
||||
|
||||
public String generateWrappedCodeForDocumentEnd() {
|
||||
UserScriptInjectionTime injectionTime = UserScriptInjectionTime.AT_DOCUMENT_END;
|
||||
// try to reload scripts if they were not loaded during the AT_DOCUMENT_START event
|
||||
String js = generateCodeForDocumentStart();
|
||||
js += generatePluginScriptsCodeAt(injectionTime);
|
||||
js += generateUserOnlyScriptsCodeAt(injectionTime);
|
||||
js = USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE.replace(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, js);
|
||||
return js;
|
||||
}
|
||||
|
||||
private String generateCodeForDocumentStart() {
|
||||
UserScriptInjectionTime injectionTime = UserScriptInjectionTime.AT_DOCUMENT_START;
|
||||
String js = "";
|
||||
js += generatePluginScriptsCodeAt(injectionTime);
|
||||
js += generateContentWorldsCreatorCode();
|
||||
js += generateUserOnlyScriptsCodeAt(injectionTime);
|
||||
js = USER_SCRIPTS_AT_DOCUMENT_START_WRAPPER_JS_SOURCE.replace(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, js);
|
||||
return js;
|
||||
}
|
||||
|
||||
private String generateContentWorldsCreatorCode() {
|
||||
if (this.contentWorlds.size() == 1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder source = new StringBuilder();
|
||||
LinkedHashSet<PluginScript> pluginScriptsRequired = this.getPluginScriptsRequiredInAllContentWorlds();
|
||||
for (PluginScript script : pluginScriptsRequired) {
|
||||
source.append(script.getSource());
|
||||
}
|
||||
List<String> contentWorldsNames = new ArrayList<>();
|
||||
for (ContentWorld contentWorld : this.contentWorlds) {
|
||||
if (contentWorld.equals(ContentWorld.PAGE)) {
|
||||
continue;
|
||||
}
|
||||
contentWorldsNames.add("'" + escapeContentWorldName(contentWorld.getName()) + "'");
|
||||
}
|
||||
|
||||
return CONTENT_WORLDS_GENERATOR_JS_SOURCE
|
||||
.replace(PluginScriptsUtil.VAR_CONTENT_WORLD_NAME_ARRAY, TextUtils.join(", ", contentWorldsNames))
|
||||
.replace(PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED, escapeCode(source.toString()));
|
||||
|
||||
}
|
||||
|
||||
private String generatePluginScriptsCodeAt(UserScriptInjectionTime injectionTime) {
|
||||
StringBuilder js = new StringBuilder();
|
||||
LinkedHashSet<PluginScript> scripts = this.getPluginScriptsAt(injectionTime);
|
||||
for (PluginScript script : scripts) {
|
||||
String source = ";" + script.getSource();
|
||||
source = wrapSourceCodeInContentWorld(script.getContentWorld(), source);
|
||||
js.append(source);
|
||||
}
|
||||
return js.toString();
|
||||
}
|
||||
|
||||
private String generateUserOnlyScriptsCodeAt(UserScriptInjectionTime injectionTime) {
|
||||
StringBuilder js = new StringBuilder();
|
||||
LinkedHashSet<UserScript> scripts = this.getUserOnlyScriptsAt(injectionTime);
|
||||
for (UserScript script : scripts) {
|
||||
String source = ";" + script.getSource();
|
||||
source = wrapSourceCodeInContentWorld(script.getContentWorld(), source);
|
||||
js.append(source);
|
||||
}
|
||||
return js.toString();
|
||||
}
|
||||
|
||||
public String generateCodeForScriptEvaluation(String source, @Nullable ContentWorld contentWorld) {
|
||||
if (contentWorld != null && !contentWorld.equals(ContentWorld.PAGE)) {
|
||||
StringBuilder sourceWrapped = new StringBuilder();
|
||||
if (!contentWorlds.contains(contentWorld)) {
|
||||
contentWorlds.add(contentWorld);
|
||||
|
||||
LinkedHashSet<PluginScript> pluginScriptsRequired = this.getPluginScriptsRequiredInAllContentWorlds();
|
||||
for (PluginScript script : pluginScriptsRequired) {
|
||||
sourceWrapped.append(";").append(script.getSource());
|
||||
}
|
||||
}
|
||||
sourceWrapped.append(source);
|
||||
return wrapSourceCodeInContentWorld(contentWorld, sourceWrapped.toString());
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
public String wrapSourceCodeInContentWorld(@Nullable ContentWorld contentWorld, String source) {
|
||||
String sourceWrapped = contentWorld == null || contentWorld.equals(ContentWorld.PAGE) ? source :
|
||||
CONTENT_WORLD_WRAPPER_JS_SOURCE
|
||||
.replace(PluginScriptsUtil.VAR_CONTENT_WORLD_NAME, escapeContentWorldName(contentWorld.getName()))
|
||||
.replace(PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED, escapeCode(source));
|
||||
|
||||
return sourceWrapped;
|
||||
}
|
||||
|
||||
public static String escapeCode(String code) {
|
||||
String escapedCode = JSONObject.quote(code);
|
||||
// escapedCode = escapedCode.substring(1, escapedCode.length() - 1);
|
||||
return escapedCode;
|
||||
}
|
||||
|
||||
public static String escapeContentWorldName(String name) {
|
||||
return name.replaceAll("'", "\\\\'");
|
||||
}
|
||||
|
||||
public LinkedHashSet<UserScript> getUserOnlyScriptsAt(UserScriptInjectionTime injectionTime) {
|
||||
return new LinkedHashSet<>(this.userOnlyScripts.get(injectionTime));
|
||||
}
|
||||
|
||||
public boolean addUserOnlyScript(UserScript userOnlyScript) {
|
||||
ContentWorld contentWorld = userOnlyScript.getContentWorld();
|
||||
if (contentWorld != null) {
|
||||
contentWorlds.add(contentWorld);
|
||||
}
|
||||
return this.userOnlyScripts.get(userOnlyScript.getInjectionTime()).add(userOnlyScript);
|
||||
}
|
||||
|
||||
public void addUserOnlyScripts(List<UserScript> userOnlyScripts) {
|
||||
for (UserScript userOnlyScript : userOnlyScripts) {
|
||||
this.addUserOnlyScript(userOnlyScript);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeUserOnlyScript(UserScript userOnlyScript) {
|
||||
return this.userOnlyScripts.get(userOnlyScript.getInjectionTime()).remove(userOnlyScript);
|
||||
}
|
||||
|
||||
public boolean removeUserOnlyScriptAt(int index, UserScriptInjectionTime injectionTime) {
|
||||
UserScript userOnlyScript = new ArrayList<>(this.userOnlyScripts.get(injectionTime)).get(index);
|
||||
return this.removeUserOnlyScript(userOnlyScript);
|
||||
}
|
||||
|
||||
public void removeAllUserOnlyScripts() {
|
||||
this.userOnlyScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START).clear();
|
||||
this.userOnlyScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END).clear();
|
||||
}
|
||||
|
||||
public LinkedHashSet<PluginScript> getPluginScriptsAt(UserScriptInjectionTime injectionTime) {
|
||||
return new LinkedHashSet<>(this.pluginScripts.get(injectionTime));
|
||||
}
|
||||
|
||||
public LinkedHashSet<PluginScript> getPluginScriptsRequiredInAllContentWorlds() {
|
||||
LinkedHashSet<PluginScript> pluginScriptsRequired = new LinkedHashSet<>();
|
||||
LinkedHashSet<PluginScript> scripts = this.getPluginScriptsAt(UserScriptInjectionTime.AT_DOCUMENT_START);
|
||||
for (PluginScript script : scripts) {
|
||||
if (script.isRequiredInAllContentWorlds()) {
|
||||
pluginScriptsRequired.add(script);
|
||||
}
|
||||
}
|
||||
return pluginScriptsRequired;
|
||||
}
|
||||
|
||||
public boolean addPluginScript(PluginScript pluginScript) {
|
||||
ContentWorld contentWorld = pluginScript.getContentWorld();
|
||||
if (contentWorld != null) {
|
||||
contentWorlds.add(contentWorld);
|
||||
}
|
||||
return this.pluginScripts.get(pluginScript.getInjectionTime()).add(pluginScript);
|
||||
}
|
||||
|
||||
public void addPluginScripts(List<PluginScript> pluginScripts) {
|
||||
for (PluginScript pluginScript : pluginScripts) {
|
||||
this.addPluginScript(pluginScript);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removePluginScript(PluginScript pluginScript) {
|
||||
return this.pluginScripts.get(pluginScript.getInjectionTime()).remove(pluginScript);
|
||||
}
|
||||
|
||||
public boolean removePluginScriptAt(int index, UserScriptInjectionTime injectionTime) {
|
||||
PluginScript pluginScript = new ArrayList<>(this.pluginScripts.get(injectionTime)).get(index);
|
||||
return this.removePluginScript(pluginScript);
|
||||
}
|
||||
|
||||
public void removeAllPluginScripts() {
|
||||
this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START).clear();
|
||||
this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END).clear();
|
||||
}
|
||||
|
||||
public LinkedHashSet<UserScript> getUserOnlyScriptAsList() {
|
||||
LinkedHashSet<UserScript> userOnlyScripts = new LinkedHashSet<>();
|
||||
Collection<LinkedHashSet<UserScript>> collection = this.userOnlyScripts.values();
|
||||
for (LinkedHashSet<UserScript> list : collection) {
|
||||
userOnlyScripts.addAll(list);
|
||||
}
|
||||
return userOnlyScripts;
|
||||
}
|
||||
|
||||
public LinkedHashSet<PluginScript> getPluginScriptAsList() {
|
||||
LinkedHashSet<PluginScript> pluginScripts = new LinkedHashSet<>();
|
||||
Collection<LinkedHashSet<PluginScript>> collection = this.pluginScripts.values();
|
||||
for (LinkedHashSet<PluginScript> list : collection) {
|
||||
pluginScripts.addAll(list);
|
||||
}
|
||||
return pluginScripts;
|
||||
}
|
||||
|
||||
public void resetContentWorlds() {
|
||||
this.contentWorlds.clear();
|
||||
this.contentWorlds.add(ContentWorld.PAGE);
|
||||
|
||||
LinkedHashSet<PluginScript> pluginScripts = this.getPluginScriptAsList();
|
||||
for (PluginScript pluginScript : pluginScripts) {
|
||||
ContentWorld contentWorld = pluginScript.getContentWorld();
|
||||
this.contentWorlds.add(contentWorld);
|
||||
}
|
||||
|
||||
LinkedHashSet<UserScript> userOnlyScripts = this.getUserOnlyScriptAsList();
|
||||
for (UserScript userOnlyScript : userOnlyScripts) {
|
||||
ContentWorld contentWorld = userOnlyScript.getContentWorld();
|
||||
this.contentWorlds.add(contentWorld);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsPluginScript(PluginScript pluginScript) {
|
||||
return this.getPluginScriptAsList().contains(pluginScript);
|
||||
}
|
||||
|
||||
public boolean containsPluginScriptByGroupName(String groupName) {
|
||||
LinkedHashSet<PluginScript> pluginScripts = this.getPluginScriptAsList();
|
||||
for (PluginScript pluginScript : pluginScripts) {
|
||||
if (Util.objEquals(groupName, pluginScript.getGroupName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsUserOnlyScript(UserScript userOnlyScript) {
|
||||
return this.getUserOnlyScriptAsList().contains(userOnlyScript);
|
||||
}
|
||||
|
||||
public boolean containsUserOnlyScriptByGroupName(String groupName) {
|
||||
LinkedHashSet<UserScript> userOnlyScripts = this.getUserOnlyScriptAsList();
|
||||
for (UserScript userOnlyScript : userOnlyScripts) {
|
||||
if (Util.objEquals(groupName, userOnlyScript.getGroupName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void removePluginScriptsByGroupName(String groupName) {
|
||||
LinkedHashSet<PluginScript> pluginScripts = this.getPluginScriptAsList();
|
||||
for (PluginScript pluginScript : pluginScripts) {
|
||||
if (Util.objEquals(groupName, pluginScript.getGroupName())) {
|
||||
this.removePluginScript(pluginScript);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeUserOnlyScriptsByGroupName(String groupName) {
|
||||
LinkedHashSet<UserScript> userOnlyScripts = this.getUserOnlyScriptAsList();
|
||||
for (UserScript userOnlyScript : userOnlyScripts) {
|
||||
if (Util.objEquals(groupName, userOnlyScript.getGroupName())) {
|
||||
this.removeUserOnlyScript(userOnlyScript);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public LinkedHashSet<ContentWorld> getContentWorlds() {
|
||||
return new LinkedHashSet<>(this.contentWorlds);
|
||||
}
|
||||
|
||||
private static final String USER_SCRIPTS_AT_DOCUMENT_START_WRAPPER_JS_SOURCE = "if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentStartLoaded == null || !window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentStartLoaded) {" +
|
||||
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentStartLoaded = true;" +
|
||||
" " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE +
|
||||
"}";
|
||||
|
||||
private static final String USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE = "if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentEndLoaded == null || !window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentEndLoaded) {" +
|
||||
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentEndLoaded = true;" +
|
||||
" " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE +
|
||||
"}";
|
||||
|
||||
private static final String CONTENT_WORLDS_GENERATOR_JS_SOURCE = "(function() {" +
|
||||
" var contentWorldNames = [" + PluginScriptsUtil.VAR_CONTENT_WORLD_NAME_ARRAY + "];" +
|
||||
" for (var contentWorldName of contentWorldNames) {" +
|
||||
" var iframeId = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_' + contentWorldName;" +
|
||||
" var iframe = document.getElementById(iframeId);" +
|
||||
" if (iframe == null) {" +
|
||||
" iframe = document.createElement('iframe');" +
|
||||
" iframe.id = iframeId;" +
|
||||
" iframe.style = 'display: none; z-index: 0; position: absolute; width: 0px; height: 0px';" +
|
||||
" document.body.append(iframe);" +
|
||||
" }" +
|
||||
" var script = iframe.contentWindow.document.createElement('script');" +
|
||||
" script.innerHTML = "+ PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED + ";" +
|
||||
" iframe.contentWindow.document.body.append(script);" +
|
||||
" }" +
|
||||
"})();";
|
||||
|
||||
private static final String CONTENT_WORLD_WRAPPER_JS_SOURCE = "(function() {" +
|
||||
" var iframeId = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_" + PluginScriptsUtil.VAR_CONTENT_WORLD_NAME + "';" +
|
||||
" var iframe = document.getElementById(iframeId);" +
|
||||
" if (iframe == null) {" +
|
||||
" iframe = document.createElement('iframe');" +
|
||||
" iframe.id = iframeId;" +
|
||||
" iframe.style = 'display: none; z-index: 0; position: absolute; width: 0px; height: 0px';" +
|
||||
" document.body.append(iframe);" +
|
||||
" }" +
|
||||
" var script = iframe.contentWindow.document.createElement('script');" +
|
||||
" script.innerHTML = "+ PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED + ";" +
|
||||
" iframe.contentWindow.document.body.append(script);" +
|
||||
"})();";
|
||||
|
||||
private static final String DOCUMENT_READY_WRAPPER_JS_SOURCE = "if (document.readyState === 'interactive' || document.readyState === 'complete') { " +
|
||||
" " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE +
|
||||
"} else {" +
|
||||
" document.addEventListener('DOMContentLoaded', function() {" +
|
||||
" " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE +
|
||||
" });" +
|
||||
"}";
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class UserScript {
|
||||
@Nullable
|
||||
private String groupName;
|
||||
@NonNull
|
||||
private String source;
|
||||
@NonNull
|
||||
private UserScriptInjectionTime injectionTime;
|
||||
@NonNull
|
||||
private ContentWorld contentWorld;
|
||||
|
||||
public UserScript(@Nullable String groupName, @NonNull String source, @NonNull UserScriptInjectionTime injectionTime, @Nullable ContentWorld contentWorld) {
|
||||
this.groupName = groupName;
|
||||
this.source = source;
|
||||
this.injectionTime = injectionTime;
|
||||
this.contentWorld = contentWorld == null ? ContentWorld.PAGE : contentWorld;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static UserScript fromMap(@Nullable Map<String, Object> map) {
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
String groupName = (String) map.get("groupName");
|
||||
String source = (String) map.get("source");
|
||||
UserScriptInjectionTime injectionTime = UserScriptInjectionTime.fromValue((int) map.get("injectionTime"));
|
||||
ContentWorld contentWorld = ContentWorld.fromMap((Map<String, Object>) map.get("contentWorld"));
|
||||
assert source != null;
|
||||
return new UserScript(groupName, source, injectionTime, contentWorld);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getGroupName() {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
public void setGroupName(@Nullable String groupName) {
|
||||
this.groupName = groupName;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(@NonNull String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public UserScriptInjectionTime getInjectionTime() {
|
||||
return injectionTime;
|
||||
}
|
||||
|
||||
public void setInjectionTime(@NonNull UserScriptInjectionTime injectionTime) {
|
||||
this.injectionTime = injectionTime;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ContentWorld getContentWorld() {
|
||||
return contentWorld;
|
||||
}
|
||||
|
||||
public void setContentWorld(@Nullable ContentWorld contentWorld) {
|
||||
this.contentWorld = contentWorld == null ? ContentWorld.PAGE : contentWorld;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
UserScript that = (UserScript) o;
|
||||
|
||||
if (groupName != null ? !groupName.equals(that.groupName) : that.groupName != null) return false;
|
||||
if (!source.equals(that.source)) return false;
|
||||
if (injectionTime != that.injectionTime) return false;
|
||||
return contentWorld.equals(that.contentWorld);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = groupName != null ? groupName.hashCode() : 0;
|
||||
result = 31 * result + source.hashCode();
|
||||
result = 31 * result + injectionTime.hashCode();
|
||||
result = 31 * result + contentWorld.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UserScript{" +
|
||||
"groupName='" + groupName + '\'' +
|
||||
", source='" + source + '\'' +
|
||||
", injectionTime=" + injectionTime +
|
||||
", contentWorld=" + contentWorld +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
public enum UserScriptInjectionTime {
|
||||
AT_DOCUMENT_START (0),
|
||||
AT_DOCUMENT_END (1);
|
||||
|
||||
private final int value;
|
||||
|
||||
private UserScriptInjectionTime(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean equalsValue(int otherValue) {
|
||||
return value == otherValue;
|
||||
}
|
||||
|
||||
public static UserScriptInjectionTime fromValue(int value) {
|
||||
for( UserScriptInjectionTime type : UserScriptInjectionTime.values()) {
|
||||
if(value == type.toValue())
|
||||
return type;
|
||||
}
|
||||
throw new IllegalArgumentException("No enum constant: " + value);
|
||||
}
|
||||
|
||||
public int toValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
@ -7,10 +7,10 @@
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
tools:context=".InAppBrowser.InAppBrowserActivity"
|
||||
tools:context=".in_app_browser.InAppBrowserActivity"
|
||||
android:focusable="true">
|
||||
|
||||
<com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView
|
||||
<com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView
|
||||
android:id="@+id/webView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
@ -3,7 +3,7 @@
|
||||
xmlns:appcompat="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".InAppBrowser.InAppBrowserActivity">
|
||||
tools:context=".in_app_browser.InAppBrowserActivity">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_go_back"
|
||||
|
@ -1 +1 @@
|
||||
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"device_info","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":["device_info"]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-02-12 16:50:12.665299","version":"1.27.0-2.0.pre.43"}
|
||||
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"device_info","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":["device_info"]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-02-22 12:12:06.265826","version":"1.27.0-5.0.pre.90"}
|
File diff suppressed because it is too large
Load Diff
@ -2,12 +2,12 @@
|
||||
# This is a generated file; do not edit or check into version control.
|
||||
export "FLUTTER_ROOT=/Users/lorenzopichilli/flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example"
|
||||
export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/lib/main.dart"
|
||||
export "FLUTTER_TARGET=integration_test/webview_flutter_test.dart"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
|
||||
export "FLUTTER_BUILD_NAME=1.0.0"
|
||||
export "FLUTTER_BUILD_NUMBER=1"
|
||||
export "DART_DEFINES=Zmx1dHRlci5pbnNwZWN0b3Iuc3RydWN0dXJlZEVycm9ycz10cnVl,RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
|
||||
export "DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
|
||||
export "DART_OBFUSCATION=false"
|
||||
export "TRACK_WIDGET_CREATION=true"
|
||||
export "TREE_SHAKE_ICONS=false"
|
||||
|
@ -257,6 +257,7 @@
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/OrderedSet/OrderedSet.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/device_info/device_info.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/flutter_downloader/flutter_downloader.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/flutter_inappwebview/flutter_inappwebview.framework",
|
||||
@ -266,6 +267,7 @@
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OrderedSet.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_downloader.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_inappwebview.framework",
|
||||
|
@ -3,6 +3,7 @@ import Flutter
|
||||
//import flutter_downloader
|
||||
|
||||
@UIApplicationMain
|
||||
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
|
||||
override func application(
|
||||
|
@ -4,7 +4,6 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'main.dart';
|
||||
|
||||
class MyChromeSafariBrowser extends ChromeSafariBrowser {
|
||||
MyChromeSafariBrowser({browserFallback}) : super(bFallback: browserFallback);
|
||||
|
||||
@override
|
||||
void onOpened() {
|
||||
@ -24,7 +23,7 @@ class MyChromeSafariBrowser extends ChromeSafariBrowser {
|
||||
|
||||
class ChromeSafariBrowserExampleScreen extends StatefulWidget {
|
||||
final ChromeSafariBrowser browser =
|
||||
MyChromeSafariBrowser(browserFallback: InAppBrowser());
|
||||
MyChromeSafariBrowser();
|
||||
|
||||
@override
|
||||
_ChromeSafariBrowserExampleScreenState createState() =>
|
||||
@ -57,10 +56,10 @@ class _ChromeSafariBrowserExampleScreenState
|
||||
)),
|
||||
drawer: myDrawer(context: context),
|
||||
body: Center(
|
||||
child: RaisedButton(
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
await widget.browser.open(
|
||||
url: "https://flutter.dev/",
|
||||
url: Uri.parse("https://flutter.dev/"),
|
||||
options: ChromeSafariBrowserClassOptions(
|
||||
android: AndroidChromeCustomTabsOptions(addDefaultShareMenuItem: false, keepAliveEnabled: true),
|
||||
ios: IOSSafariOptions(
|
||||
|
@ -19,7 +19,9 @@ class _HeadlessInAppWebViewExampleScreenState extends State<HeadlessInAppWebView
|
||||
super.initState();
|
||||
|
||||
headlessWebView = new HeadlessInAppWebView(
|
||||
initialUrl: "https://flutter.dev/",
|
||||
initialUrlRequest: URLRequest(
|
||||
url: Uri.parse("https://flutter.dev")
|
||||
),
|
||||
initialOptions: InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
|
||||
@ -34,19 +36,19 @@ class _HeadlessInAppWebViewExampleScreenState extends State<HeadlessInAppWebView
|
||||
onLoadStart: (controller, url) async {
|
||||
print("onLoadStart $url");
|
||||
setState(() {
|
||||
this.url = url ?? '';
|
||||
this.url = url.toString();
|
||||
});
|
||||
},
|
||||
onLoadStop: (controller, url) async {
|
||||
print("onLoadStop $url");
|
||||
setState(() {
|
||||
this.url = url ?? '';
|
||||
this.url = url.toString();
|
||||
});
|
||||
},
|
||||
onUpdateVisitedHistory: (controller, url, androidIsReload) {
|
||||
print("onUpdateVisitedHistory $url");
|
||||
setState(() {
|
||||
this.url = url ?? '';
|
||||
this.url = url.toString();
|
||||
});
|
||||
},
|
||||
);
|
||||
@ -74,7 +76,7 @@ class _HeadlessInAppWebViewExampleScreenState extends State<HeadlessInAppWebView
|
||||
"CURRENT URL\n${(url.length > 50) ? url.substring(0, 50) + "..." : url}"),
|
||||
),
|
||||
Center(
|
||||
child: RaisedButton(
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
await headlessWebView?.dispose();
|
||||
await headlessWebView?.run();
|
||||
@ -82,7 +84,7 @@ class _HeadlessInAppWebViewExampleScreenState extends State<HeadlessInAppWebView
|
||||
child: Text("Run HeadlessInAppWebView")),
|
||||
),
|
||||
Center(
|
||||
child: RaisedButton(
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
await headlessWebView?.webViewController.evaluateJavascript(source: """console.log('Here is the message!');""");
|
||||
@ -93,7 +95,7 @@ class _HeadlessInAppWebViewExampleScreenState extends State<HeadlessInAppWebView
|
||||
child: Text("Send console.log message")),
|
||||
),
|
||||
Center(
|
||||
child: RaisedButton(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
headlessWebView?.dispose();
|
||||
},
|
||||
|
@ -41,10 +41,10 @@ class MyInAppBrowser extends InAppBrowser {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ShouldOverrideUrlLoadingAction> shouldOverrideUrlLoading(
|
||||
shouldOverrideUrlLoadingRequest) async {
|
||||
print("\n\nOverride ${shouldOverrideUrlLoadingRequest.url}\n\n");
|
||||
return ShouldOverrideUrlLoadingAction.ALLOW;
|
||||
Future<NavigationActionPolicy> shouldOverrideUrlLoading(
|
||||
navigationAction) async {
|
||||
print("\n\nOverride ${navigationAction.request.url}\n\n");
|
||||
return NavigationActionPolicy.ALLOW;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -54,7 +54,7 @@ class MyInAppBrowser extends InAppBrowser {
|
||||
"ms ---> duration: " +
|
||||
response.duration.toString() +
|
||||
"ms " +
|
||||
response.url!);
|
||||
(response.url ?? '').toString());
|
||||
}
|
||||
|
||||
@override
|
||||
@ -62,7 +62,7 @@ class MyInAppBrowser extends InAppBrowser {
|
||||
print("""
|
||||
console output:
|
||||
message: ${consoleMessage.message}
|
||||
messageLevel: ${consoleMessage.messageLevel!.toValue()}
|
||||
messageLevel: ${consoleMessage.messageLevel.toValue()}
|
||||
""");
|
||||
}
|
||||
}
|
||||
@ -93,23 +93,24 @@ class _InAppBrowserExampleScreenState extends State<InAppBrowserExampleScreen> {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
await widget.browser.openFile(
|
||||
assetFilePath: "assets/index.html",
|
||||
await widget.browser.openUrlRequest(
|
||||
urlRequest: URLRequest(url: Uri.parse("https://flutter.dev")),
|
||||
options: InAppBrowserClassOptions(
|
||||
inAppWebViewGroupOptions: InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
useShouldOverrideUrlLoading: true,
|
||||
useOnLoadResource: true,
|
||||
))));
|
||||
inAppWebViewGroupOptions: InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
useShouldOverrideUrlLoading: true,
|
||||
useOnLoadResource: true,
|
||||
)
|
||||
)));
|
||||
},
|
||||
child: Text("Open In-App Browser")),
|
||||
Container(height: 40),
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
await InAppBrowser.openWithSystemBrowser(
|
||||
url: "https://flutter.dev/");
|
||||
url: Uri.parse("https://flutter.dev/"));
|
||||
},
|
||||
child: Text("Open System Browser")),
|
||||
])));
|
||||
|
@ -5,7 +5,6 @@ import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
// import 'package:path_provider/path_provider.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
@ -61,6 +60,20 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
var options = InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
useShouldOverrideUrlLoading: false,
|
||||
mediaPlaybackRequiresUserGesture: false,
|
||||
),
|
||||
android: AndroidInAppWebViewOptions(
|
||||
useHybridComposition: true,
|
||||
),
|
||||
ios: IOSInAppWebViewOptions(
|
||||
allowsInlineMediaPlayback: true,
|
||||
// limitsNavigationsToAppBoundDomains: true // adds Service Worker API on iOS 14.0+
|
||||
)
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -88,26 +101,14 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||
child: InAppWebView(
|
||||
key: webViewKey,
|
||||
// contextMenu: contextMenu,
|
||||
initialUrl: "https://flutter.dev",
|
||||
initialUrlRequest: URLRequest(
|
||||
url: Uri.parse("https://github.com")
|
||||
),
|
||||
// initialFile: "assets/index.html",
|
||||
initialHeaders: {},
|
||||
initialUserScripts: UnmodifiableListView<UserScript>([
|
||||
|
||||
]),
|
||||
initialOptions: InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
useShouldOverrideUrlLoading: false,
|
||||
mediaPlaybackRequiresUserGesture: false,
|
||||
clearCache: true,
|
||||
),
|
||||
android: AndroidInAppWebViewOptions(
|
||||
useHybridComposition: false,
|
||||
),
|
||||
ios: IOSInAppWebViewOptions(
|
||||
allowsInlineMediaPlayback: true,
|
||||
// limitsNavigationsToAppBoundDomains: true // adds Service Worker API on iOS 14.0+
|
||||
)
|
||||
),
|
||||
initialOptions: options,
|
||||
onWebViewCreated: (controller) {
|
||||
webView = controller;
|
||||
print("onWebViewCreated");
|
||||
@ -115,15 +116,14 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||
onLoadStart: (controller, url) {
|
||||
print("onLoadStart $url");
|
||||
setState(() {
|
||||
this.url = url ?? '';
|
||||
this.url = url.toString();
|
||||
});
|
||||
},
|
||||
androidOnPermissionRequest: (InAppWebViewController controller, String origin, List<String> resources) async {
|
||||
return PermissionRequestResponse(resources: resources, action: PermissionRequestResponseAction.GRANT);
|
||||
},
|
||||
shouldOverrideUrlLoading: (controller, shouldOverrideUrlLoadingRequest) async {
|
||||
var url = shouldOverrideUrlLoadingRequest.url;
|
||||
var uri = Uri.parse(url);
|
||||
shouldOverrideUrlLoading: (controller, navigationAction) async {
|
||||
var uri = navigationAction.request.url!;
|
||||
|
||||
if (!["http", "https", "file",
|
||||
"chrome", "data", "javascript",
|
||||
@ -134,17 +134,21 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||
url,
|
||||
);
|
||||
// and cancel the request
|
||||
return ShouldOverrideUrlLoadingAction.CANCEL;
|
||||
return NavigationActionPolicy.CANCEL;
|
||||
}
|
||||
}
|
||||
|
||||
return ShouldOverrideUrlLoadingAction.ALLOW;
|
||||
return NavigationActionPolicy.ALLOW;
|
||||
},
|
||||
onLoadResource: (controller, resource) {
|
||||
// print(resource);
|
||||
},
|
||||
onLoadStop: (controller, url) async {
|
||||
print("onLoadStop $url");
|
||||
setState(() {
|
||||
this.url = url ?? '';
|
||||
this.url = url.toString();
|
||||
});
|
||||
webView = controller;
|
||||
|
||||
// RenderObject renderBox = webViewKey.currentContext!.findRenderObject()!;
|
||||
// print(renderBox.paintBounds.size);
|
||||
@ -157,10 +161,11 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||
onUpdateVisitedHistory: (controller, url, androidIsReload) {
|
||||
print("onUpdateVisitedHistory $url");
|
||||
setState(() {
|
||||
this.url = url ?? '';
|
||||
this.url = url.toString();
|
||||
});
|
||||
},
|
||||
onConsoleMessage: (controller, consoleMessage) {
|
||||
print("CONSOLE MESSAGE FROM MAIN WEBVIEW!");
|
||||
print(consoleMessage);
|
||||
},
|
||||
),
|
||||
@ -169,19 +174,19 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||
ButtonBar(
|
||||
alignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
child: Icon(Icons.arrow_back),
|
||||
onPressed: () {
|
||||
webView?.goBack();
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
child: Icon(Icons.arrow_forward),
|
||||
onPressed: () {
|
||||
webView?.goForward();
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
child: Icon(Icons.refresh),
|
||||
onPressed: () {
|
||||
webView?.reload();
|
||||
|
@ -5,9 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>InAppWebViewOnLoadResourceTest</title>
|
||||
<link rel="stylesheet" href="https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
</head>
|
||||
<body class="text-center">
|
||||
@ -20,5 +18,17 @@
|
||||
</p>
|
||||
</main>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var script = document.createElement('script');
|
||||
script.src = "https://code.jquery.com/jquery-3.3.1.min.js"
|
||||
document.body.append(script);
|
||||
|
||||
var link = document.createElement('link');
|
||||
link.rel = "stylesheet";
|
||||
link.href = "https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css"
|
||||
document.body.append(link);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -80,5 +80,6 @@
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Flutter Plugins" level="project" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
</component>
|
||||
</module>
|
@ -32,29 +32,16 @@ class CredentialDatabase: NSObject, FlutterPlugin {
|
||||
case "getAllAuthCredentials":
|
||||
var allCredentials: [[String: Any?]] = []
|
||||
for (protectionSpace, credentials) in CredentialDatabase.credentialStore!.allCredentials {
|
||||
let protectionSpaceDict = [
|
||||
"host": protectionSpace.host,
|
||||
"protocol": protectionSpace.protocol,
|
||||
"realm": protectionSpace.realm,
|
||||
"port": protectionSpace.port
|
||||
] as [String : Any?]
|
||||
|
||||
var crendentials: [[String: String?]] = []
|
||||
var crendentials: [[String: Any?]] = []
|
||||
for c in credentials {
|
||||
if let username = c.value.user, let password = c.value.password {
|
||||
let credential: [String: String] = [
|
||||
"username": username,
|
||||
"password": password,
|
||||
]
|
||||
crendentials.append(credential)
|
||||
}
|
||||
let credential: [String: Any?] = c.value.toMap()
|
||||
crendentials.append(credential)
|
||||
}
|
||||
|
||||
if crendentials.count > 0 {
|
||||
let dict = [
|
||||
"protectionSpace": protectionSpaceDict,
|
||||
let dict: [String : Any] = [
|
||||
"protectionSpace": protectionSpace.toMap(),
|
||||
"credentials": crendentials
|
||||
] as [String : Any]
|
||||
]
|
||||
allCredentials.append(dict)
|
||||
} }
|
||||
result(allCredentials)
|
||||
@ -67,19 +54,13 @@ class CredentialDatabase: NSObject, FlutterPlugin {
|
||||
if let r = realm, r.isEmpty {
|
||||
realm = nil
|
||||
}
|
||||
var crendentials: [[String: String?]] = []
|
||||
var crendentials: [[String: Any?]] = []
|
||||
|
||||
for (protectionSpace, credentials) in CredentialDatabase.credentialStore!.allCredentials {
|
||||
if protectionSpace.host == host && protectionSpace.realm == realm &&
|
||||
protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort {
|
||||
for c in credentials {
|
||||
if let username = c.value.user, let password = c.value.password {
|
||||
let credential: [String: String] = [
|
||||
"username": username,
|
||||
"password": password,
|
||||
]
|
||||
crendentials.append(credential)
|
||||
}
|
||||
crendentials.append(c.value.toMap())
|
||||
}
|
||||
break
|
||||
}
|
||||
@ -97,7 +78,8 @@ class CredentialDatabase: NSObject, FlutterPlugin {
|
||||
let username = arguments!["username"] as! String
|
||||
let password = arguments!["password"] as! String
|
||||
let credential = URLCredential(user: username, password: password, persistence: .permanent)
|
||||
CredentialDatabase.credentialStore!.set(credential, for: URLProtectionSpace(host: host, port: urlPort, protocol: urlProtocol, realm: realm, authenticationMethod: NSURLAuthenticationMethodHTTPBasic))
|
||||
CredentialDatabase.credentialStore!.set(credential,
|
||||
for: URLProtectionSpace(host: host, port: urlPort, protocol: urlProtocol, realm: realm, authenticationMethod: NSURLAuthenticationMethodHTTPBasic))
|
||||
result(true)
|
||||
break
|
||||
case "removeHttpAuthCredential":
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user