fix #679, updated X509Certificate classes, removed androidOnRequestFocus event
because it is never called
This commit is contained in:
parent
e9f5cabd2b
commit
de9d081af2
772
.idea/libraries/Dart_Packages.xml
generated
772
.idea/libraries/Dart_Packages.xml
generated
@ -1,772 +0,0 @@
|
||||
<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-0.1.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="file">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/file-6.0.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-1.6.27/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.0.1+2/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.4+8/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-1.0.4/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.0.4+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.0.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.0/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-1.7.4+1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="xdg_directories">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/xdg_directories-0.1.2/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-0.1.3/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.0.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-1.6.27/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.0.1+2/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.4+8/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_platform_interface-1.0.4/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.0.4+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.0.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.0/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-1.7.4+1/lib" />
|
||||
<root url="file://$USER_HOME$/flutter/.pub-cache/hosted/pub.dartlang.org/xdg_directories-0.1.2/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,6 +1,9 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Flutter Plugins">
|
||||
<CLASSES />
|
||||
<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>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
|
@ -9,13 +9,14 @@
|
||||
- Added `initialUserScripts` WebView option
|
||||
- Added `addUserScript`, `addUserScripts`, `removeUserScript`, `removeUserScripts`, `removeAllUserScripts`, `callAsyncJavaScript` WebView methods
|
||||
- Added `contentWorld` argument to `evaluateJavascript` WebView method
|
||||
- Added `isDirectionalLockEnabled`, `mediaType`, `pageZoom`, `limitsNavigationsToAppBoundDomains`, `useOnNavigationResponse`, `applePayAPIEnabled` iOS-specific WebView options
|
||||
- Added `isDirectionalLockEnabled`, `mediaType`, `pageZoom`, `limitsNavigationsToAppBoundDomains`, `useOnNavigationResponse`, `applePayAPIEnabled`, `allowingReadAccessTo` 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
|
||||
- Added `screenshotConfiguration` optional argument to `takeScreenshot` WebView method
|
||||
- Added `scriptHtmlTagAttributes` optional argument to `injectJavascriptFileFromUrl` WebView method
|
||||
- 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
|
||||
- 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))
|
||||
@ -52,6 +53,8 @@
|
||||
- Changed `zoomBy` WebView method signature
|
||||
- Moved `saveWebArchive` WebView method from Android-specific to cross-platform
|
||||
- Renamed `HttpAuthChallenge` to `URLAuthenticationChallenge`
|
||||
- Deleted `androidOnRequestFocus` event because it is never called
|
||||
- Updated `basicConstraints`, `subjectKeyIdentifier`, `authorityKeyIdentifier`, `certificatePolicies`, `cRLDistributionPoints`, `authorityInfoAccess` attributes type of `X509Certificate`
|
||||
|
||||
## 4.0.0+4
|
||||
|
||||
|
@ -437,7 +437,7 @@ Screenshots:
|
||||
* `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 {}})`: Loads the given url 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.
|
||||
* `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.
|
||||
* `printCurrentPage`: Prints the current page.
|
||||
@ -636,6 +636,7 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
|
||||
##### `InAppWebView` iOS-specific options
|
||||
|
||||
* `accessibilityIgnoresInvertColors`: A Boolean value indicating whether the view ignores an accessibility request to invert its colors. The default value is `false`.
|
||||
* `allowingReadAccessTo`: Used in combination with `WebView.initialUrl` (with `file://` scheme), it represents the URL from which to read the web content. This URL must be a file-based URL (with `file://` scheme).
|
||||
* `allowsAirPlayForMediaPlayback`: Set to `true` to allow AirPlay. The default value is `true`.
|
||||
* `allowsBackForwardNavigationGestures`: Set to `true` to allow the horizontal swipe gestures trigger back-forward list navigations. The default value is `true`.
|
||||
* `allowsInlineMediaPlayback`: Set to `true` to allow HTML5 media playback to appear inline within the screen layout, using browser-supplied controls rather than native controls.
|
||||
@ -713,7 +714,6 @@ Event names that starts with `android` or `ios` are events platform-specific.
|
||||
* `androidOnRenderProcessUnresponsive`: Event called when the renderer currently associated with the WebView becomes unresponsive as a result of a long running blocking task such as the execution of JavaScript (available only on Android).
|
||||
* `androidOnFormResubmission`: As the host application if the browser should resend data as the requested page was a result of a POST. The default is to not resend the data (available only on Android).
|
||||
* `androidOnScaleChanged`: Event fired when the scale applied to the WebView has changed (available only on Android).
|
||||
* `androidOnRequestFocus`: Event fired when there is a request to display and focus for this WebView (available only on Android).
|
||||
* `androidOnReceivedIcon`: Event fired when there is new favicon for the current page (available only on Android).
|
||||
* `androidOnReceivedTouchIconUrl`: Event fired when there is an url for an apple-touch-icon (available only on Android).
|
||||
* `androidOnJsBeforeUnload`: Event fired when the client should display a dialog to confirm navigation away from the current page. This is the result of the `onbeforeunload` javascript event (available only on Android).
|
||||
|
@ -666,21 +666,21 @@ final public class InAppWebView extends InputAwareWebView {
|
||||
"})();";
|
||||
|
||||
static final String onWindowBlurEventJS = "(function(){" +
|
||||
" window.addEventListener('blur', function(e) {" +
|
||||
" window." + JavaScriptBridgeInterface.name + ".callHandler('onWindowBlur');" +
|
||||
" });" +
|
||||
"})();";
|
||||
" window.addEventListener('blur', function(e) {" +
|
||||
" window." + JavaScriptBridgeInterface.name + ".callHandler('onWindowBlur');" +
|
||||
" });" +
|
||||
"})();";
|
||||
|
||||
static final String callAsyncJavaScriptWrapperJS = "(function(obj) {" +
|
||||
" (async function($FUNCTION_ARGUMENT_NAMES) {" +
|
||||
" $FUNCTION_BODY" +
|
||||
" })($FUNCTION_ARGUMENT_VALUES).then(function(value) {" +
|
||||
" window." + JavaScriptBridgeInterface.name + ".callHandler('callAsyncJavaScript', {'value': value, 'error': null, 'resultUuid': '$RESULT_UUID'});" +
|
||||
" }).catch(function(error) {" +
|
||||
" window." + JavaScriptBridgeInterface.name + ".callHandler('callAsyncJavaScript', {'value': null, 'error': error, 'resultUuid': '$RESULT_UUID'});" +
|
||||
" });" +
|
||||
" return null;" +
|
||||
"})($FUNCTION_ARGUMENTS_OBJ);";
|
||||
" (async function($FUNCTION_ARGUMENT_NAMES) {" +
|
||||
" $FUNCTION_BODY" +
|
||||
" })($FUNCTION_ARGUMENT_VALUES).then(function(value) {" +
|
||||
" window." + JavaScriptBridgeInterface.name + ".callHandler('callAsyncJavaScript', {'value': value, 'error': null, 'resultUuid': '$RESULT_UUID'});" +
|
||||
" }).catch(function(error) {" +
|
||||
" window." + JavaScriptBridgeInterface.name + ".callHandler('callAsyncJavaScript', {'value': null, 'error': error, 'resultUuid': '$RESULT_UUID'});" +
|
||||
" });" +
|
||||
" return null;" +
|
||||
"})($FUNCTION_ARGUMENTS_OBJ);";
|
||||
|
||||
public InAppWebView(Context context) {
|
||||
super(context);
|
||||
@ -1864,8 +1864,8 @@ final public class InAppWebView extends InputAwareWebView {
|
||||
final ActionMode.Callback callback
|
||||
) {
|
||||
// fix Android 10 clipboard not working properly https://github.com/pichillilorenzo/flutter_inappwebview/issues/678
|
||||
if (!options.useHybridComposition) {
|
||||
onWindowFocusChanged(isFocused());
|
||||
if (!options.useHybridComposition && containerView != null) {
|
||||
onWindowFocusChanged(containerView.isFocused());
|
||||
}
|
||||
|
||||
boolean hasBeenRemovedAndRebuilt = false;
|
||||
|
@ -569,7 +569,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
|
||||
AlertDialog alertDialog = alertDialogBuilder.create();
|
||||
alertDialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, final Message resultMsg) {
|
||||
@ -635,14 +635,6 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
||||
super.onCloseWindow(window);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestFocus(WebView view) {
|
||||
final Map<String, Object> obj = new HashMap<>();
|
||||
channel.invokeMethod("onRequestFocus", obj);
|
||||
|
||||
super.onCloseWindow(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback callback) {
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
|
@ -23,6 +23,7 @@ public class WebViewFeatureManager implements MethodChannel.MethodCallHandler {
|
||||
case "isFeatureSupported":
|
||||
String feature = (String) call.argument("feature");
|
||||
result.success(WebViewFeature.isFeatureSupported(feature));
|
||||
break;
|
||||
default:
|
||||
result.notImplemented();
|
||||
}
|
||||
|
@ -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-1.6.27/","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-1.6.27/","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.4+8/","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.0.1+2/","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.0.4+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-11 17:35:59.644389","version":"1.26.0-18.0.pre.257"}
|
||||
{"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"}
|
@ -10,6 +10,7 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import '.env.dart';
|
||||
|
||||
@ -119,6 +120,127 @@ void main() {
|
||||
expect(content.contains('flutter_test_header'), isTrue);
|
||||
});
|
||||
|
||||
group("iOS loadFileURL", () {
|
||||
late Directory appSupportDir;
|
||||
late File fileHtml;
|
||||
late File fileJs;
|
||||
|
||||
setUpAll(() async {
|
||||
appSupportDir = (await getApplicationSupportDirectory())!;
|
||||
|
||||
final Directory htmlFolder = Directory('${appSupportDir.path}/html/');
|
||||
if(!await htmlFolder.exists()){
|
||||
await htmlFolder.create(recursive: true);
|
||||
}
|
||||
|
||||
final Directory jsFolder = Directory('${appSupportDir.path}/js/');
|
||||
if(!await jsFolder.exists()){
|
||||
await jsFolder.create(recursive: true);
|
||||
}
|
||||
|
||||
var html = """
|
||||
<!DOCTYPE html><html>
|
||||
<head>
|
||||
<title>file scheme</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
fileHtml = File(htmlFolder.path + "index.html");
|
||||
fileHtml.writeAsStringSync(html);
|
||||
|
||||
var js = """
|
||||
console.log('message');
|
||||
""";
|
||||
fileJs = File(jsFolder.path + "main.js");
|
||||
fileJs.writeAsStringSync(js);
|
||||
});
|
||||
|
||||
testWidgets('initialUrl with file:// scheme and allowingReadAccessTo', (WidgetTester tester) async {
|
||||
final Completer<ConsoleMessage?> consoleMessageShouldNotComplete = Completer<ConsoleMessage?>();
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: InAppWebView(
|
||||
key: GlobalKey(),
|
||||
initialUrl: Uri.encodeFull('file://${fileHtml.path}'),
|
||||
onConsoleMessage: (controller, consoleMessage) {
|
||||
consoleMessageShouldNotComplete.complete(consoleMessage);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
var result = await consoleMessageShouldNotComplete.future
|
||||
.timeout(const Duration(seconds: 2), onTimeout: () => null);
|
||||
expect(result, null);
|
||||
|
||||
final Completer<ConsoleMessage> consoleMessageCompleter = Completer<ConsoleMessage>();
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: InAppWebView(
|
||||
key: GlobalKey(),
|
||||
initialUrl: Uri.encodeFull('file://${fileHtml.path}'),
|
||||
initialOptions: InAppWebViewGroupOptions(
|
||||
ios: IOSInAppWebViewOptions(
|
||||
allowingReadAccessTo: Uri.encodeFull('file://${appSupportDir.path}/')
|
||||
)
|
||||
),
|
||||
onConsoleMessage: (controller, consoleMessage) {
|
||||
consoleMessageCompleter.complete(consoleMessage);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
final ConsoleMessage consoleMessage = await consoleMessageCompleter.future;
|
||||
expect(consoleMessage.messageLevel, ConsoleMessageLevel.LOG);
|
||||
expect(consoleMessage.message, 'message');
|
||||
});
|
||||
|
||||
testWidgets('loadUrl with file:// scheme and iosAllowingReadAccessTo argument', (WidgetTester tester) async {
|
||||
final Completer<ConsoleMessage?> consoleMessageShouldNotComplete = Completer<ConsoleMessage?>();
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: InAppWebView(
|
||||
key: GlobalKey(),
|
||||
onWebViewCreated: (controller) {
|
||||
controller.loadUrl(url: Uri.encodeFull('file://${fileHtml.path}'));
|
||||
},
|
||||
onConsoleMessage: (controller, consoleMessage) {
|
||||
consoleMessageShouldNotComplete.complete(consoleMessage);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
var result = await consoleMessageShouldNotComplete.future
|
||||
.timeout(const Duration(seconds: 2), onTimeout: () => null);
|
||||
expect(result, null);
|
||||
|
||||
final Completer<ConsoleMessage> consoleMessageCompleter = Completer<ConsoleMessage>();
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: InAppWebView(
|
||||
key: GlobalKey(),
|
||||
onWebViewCreated: (controller) {
|
||||
controller.loadUrl(url: Uri.encodeFull('file://${fileHtml.path}'),
|
||||
iosAllowingReadAccessTo: Uri.encodeFull('file://${appSupportDir.path}/'));
|
||||
},
|
||||
onConsoleMessage: (controller, consoleMessage) {
|
||||
consoleMessageCompleter.complete(consoleMessage);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
final ConsoleMessage consoleMessage = await consoleMessageCompleter.future;
|
||||
expect(consoleMessage.messageLevel, ConsoleMessageLevel.LOG);
|
||||
expect(consoleMessage.message, 'message');
|
||||
});
|
||||
}, skip: !Platform.isIOS);
|
||||
|
||||
testWidgets('JavaScript Handler', (WidgetTester tester) async {
|
||||
|
||||
final Completer controllerCompleter =
|
||||
@ -1080,7 +1202,7 @@ void main() {
|
||||
await pageLoads.stream.first;
|
||||
final InAppWebViewController controller = await controllerCompleter.future;
|
||||
|
||||
await controller.evaluateJavascript(source: 'window.open("about:blank", "_blank")');
|
||||
await controller.evaluateJavascript(source: 'window.open("about:blank", "_blank");');
|
||||
await pageLoads.stream.first;
|
||||
final String? currentUrl = await controller.getUrl();
|
||||
expect(currentUrl, 'about:blank');
|
||||
|
@ -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=integration_test/webview_flutter_test.dart"
|
||||
export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/lib/main.dart"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
|
||||
export "FLUTTER_BUILD_NAME=1.0.0"
|
||||
export "FLUTTER_BUILD_NUMBER=1"
|
||||
export "DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
|
||||
export "DART_DEFINES=Zmx1dHRlci5pbnNwZWN0b3Iuc3RydWN0dXJlZEVycm9ycz10cnVl,RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
|
||||
export "DART_OBFUSCATION=false"
|
||||
export "TRACK_WIDGET_CREATION=true"
|
||||
export "TREE_SHAKE_ICONS=false"
|
||||
|
@ -10,9 +10,13 @@ import Flutter
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
/*FlutterDownloaderPlugin.setPluginRegistrantCallback({(registry: FlutterPluginRegistry) in
|
||||
|
||||
})*/
|
||||
//FlutterDownloaderPlugin.setPluginRegistrantCallback(registerPlugins)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
}
|
||||
|
||||
//private func registerPlugins(registry: FlutterPluginRegistry) {
|
||||
// if (!registry.hasPlugin("FlutterDownloaderPlugin")) {
|
||||
// FlutterDownloaderPlugin.register(with: registry.registrar(forPlugin: "FlutterDownloaderPlugin")!)
|
||||
// }
|
||||
//}
|
||||
|
@ -1,8 +1,11 @@
|
||||
import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
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';
|
||||
|
||||
@ -95,9 +98,10 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||
crossPlatform: InAppWebViewOptions(
|
||||
useShouldOverrideUrlLoading: false,
|
||||
mediaPlaybackRequiresUserGesture: false,
|
||||
clearCache: true,
|
||||
),
|
||||
android: AndroidInAppWebViewOptions(
|
||||
useHybridComposition: true,
|
||||
useHybridComposition: false,
|
||||
),
|
||||
ios: IOSInAppWebViewOptions(
|
||||
allowsInlineMediaPlayback: true,
|
||||
|
@ -8,6 +8,7 @@ import 'package:flutter_inappwebview_example/chrome_safari_browser_example.scree
|
||||
import 'package:flutter_inappwebview_example/headless_in_app_webview.screen.dart';
|
||||
import 'package:flutter_inappwebview_example/in_app_webiew_example.screen.dart';
|
||||
import 'package:flutter_inappwebview_example/in_app_browser_example.screen.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
// import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
// InAppLocalhostServer localhostServer = new InAppLocalhostServer();
|
||||
|
@ -21,7 +21,7 @@ dependencies:
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.2
|
||||
flutter_downloader: ^1.5.2
|
||||
path_provider: ^1.6.27
|
||||
path_provider: ^2.0.0-nullsafety
|
||||
permission_handler: ^5.0.1+1
|
||||
url_launcher: ^6.0.0-nullsafety.4
|
||||
# connectivity: ^0.4.5+6
|
||||
|
@ -80,6 +80,5 @@
|
||||
<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>
|
@ -166,7 +166,7 @@ public class InAppBrowserManager: NSObject, FlutterPlugin {
|
||||
if webViewController.isHidden {
|
||||
webViewController.view.isHidden = true
|
||||
webViewController.tmpWindow!.rootViewController!.present(webViewController, animated: false, completion: {() -> Void in
|
||||
webViewController.webView.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
|
||||
|
||||
})
|
||||
webViewController.presentingViewController?.dismiss(animated: false, completion: {() -> Void in
|
||||
webViewController.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
|
||||
@ -175,7 +175,7 @@ public class InAppBrowserManager: NSObject, FlutterPlugin {
|
||||
}
|
||||
else {
|
||||
webViewController.tmpWindow!.rootViewController!.present(webViewController, animated: true, completion: {() -> Void in
|
||||
webViewController.webView.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -71,12 +71,12 @@ public class InAppBrowserWebViewController: UIViewController, UIScrollViewDelega
|
||||
|
||||
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(options: webViewOptions)
|
||||
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
self.webView = webViewTransport.webView
|
||||
self.webView.IABController = self
|
||||
self.webView.contextMenu = contextMenu
|
||||
self.webView.channel = channel!
|
||||
webView = webViewTransport.webView
|
||||
webView.IABController = self
|
||||
webView.contextMenu = contextMenu
|
||||
webView.channel = channel!
|
||||
} else {
|
||||
self.webView = InAppWebView(frame: .zero,
|
||||
webView = InAppWebView(frame: .zero,
|
||||
configuration: preWebviewConfiguration,
|
||||
IABController: self,
|
||||
contextMenu: contextMenu,
|
||||
@ -86,8 +86,8 @@ public class InAppBrowserWebViewController: UIViewController, UIScrollViewDelega
|
||||
methodCallDelegate = InAppWebViewMethodHandler(webView: webView!)
|
||||
channel!.setMethodCallHandler(LeakAvoider(delegate: methodCallDelegate!).handle)
|
||||
|
||||
self.webView.appendUserScripts(userScripts: initUserScripts)
|
||||
self.containerWebView.addSubview(self.webView)
|
||||
webView.appendUserScripts(userScripts: initUserScripts)
|
||||
containerWebView.addSubview(webView)
|
||||
prepareConstraints()
|
||||
prepareWebView()
|
||||
|
||||
@ -111,7 +111,7 @@ public class InAppBrowserWebViewController: UIViewController, UIScrollViewDelega
|
||||
let configuration = self.webView!.configuration
|
||||
configuration.userContentController.add(contentRuleList!)
|
||||
|
||||
self.initLoad(initURL: self.initURL, initData: self.initData, initMimeType: self.initMimeType, initEncoding: self.initEncoding, initBaseUrl: self.initBaseUrl, initHeaders: self.initHeaders)
|
||||
self.initLoad()
|
||||
|
||||
self.onBrowserCreated()
|
||||
}
|
||||
@ -122,7 +122,7 @@ public class InAppBrowserWebViewController: UIViewController, UIScrollViewDelega
|
||||
}
|
||||
}
|
||||
|
||||
initLoad(initURL: initURL, initData: initData, initMimeType: initMimeType, initEncoding: initEncoding, initBaseUrl: initBaseUrl, initHeaders: initHeaders)
|
||||
initLoad()
|
||||
}
|
||||
|
||||
onBrowserCreated()
|
||||
@ -131,9 +131,16 @@ public class InAppBrowserWebViewController: UIViewController, UIScrollViewDelega
|
||||
super.viewWillAppear(animated)
|
||||
}
|
||||
|
||||
public func initLoad(initURL: URL?, initData: String?, initMimeType: String?, initEncoding: String?, initBaseUrl: String?, initHeaders: [String: String]?) {
|
||||
if self.initData == nil {
|
||||
loadUrl(url: self.initURL!, headers: self.initHeaders)
|
||||
public func initLoad() {
|
||||
if initData == nil, let initURL = initURL {
|
||||
var allowingReadAccessToURL: URL? = nil
|
||||
if let allowingReadAccessTo = webView.options?.allowingReadAccessTo, initURL.scheme == "file" {
|
||||
allowingReadAccessToURL = URL(string: allowingReadAccessTo)
|
||||
if allowingReadAccessToURL?.scheme != "file" {
|
||||
allowingReadAccessToURL = nil
|
||||
}
|
||||
}
|
||||
loadUrl(url: initURL, headers: initHeaders, allowingReadAccessTo: allowingReadAccessToURL)
|
||||
}
|
||||
else {
|
||||
webView.loadData(data: initData!, mimeType: initMimeType!, encoding: initEncoding!, baseUrl: initBaseUrl!)
|
||||
@ -144,29 +151,29 @@ public class InAppBrowserWebViewController: UIViewController, UIScrollViewDelega
|
||||
super.viewDidLoad()
|
||||
|
||||
urlField.delegate = self
|
||||
urlField.text = self.initURL?.absoluteString
|
||||
urlField.text = initURL?.absoluteString
|
||||
urlField.backgroundColor = .white
|
||||
urlField.textColor = .black
|
||||
urlField.layer.borderWidth = 1.0
|
||||
urlField.layer.borderColor = UIColor.lightGray.cgColor
|
||||
urlField.layer.cornerRadius = 4
|
||||
|
||||
closeButton.addTarget(self, action: #selector(self.close), for: .touchUpInside)
|
||||
closeButton.addTarget(self, action: #selector(close), for: .touchUpInside)
|
||||
|
||||
forwardButton.target = self
|
||||
forwardButton.action = #selector(self.goForward)
|
||||
forwardButton.action = #selector(goForward)
|
||||
|
||||
forwardButton.target = self
|
||||
forwardButton.action = #selector(self.goForward)
|
||||
forwardButton.action = #selector(goForward)
|
||||
|
||||
backButton.target = self
|
||||
backButton.action = #selector(self.goBack)
|
||||
backButton.action = #selector(goBack)
|
||||
|
||||
reloadButton.target = self
|
||||
reloadButton.action = #selector(self.reload)
|
||||
reloadButton.action = #selector(reload)
|
||||
|
||||
shareButton.target = self
|
||||
shareButton.action = #selector(self.share)
|
||||
shareButton.action = #selector(share)
|
||||
|
||||
spinner.hidesWhenStopped = true
|
||||
spinner.isHidden = false
|
||||
@ -184,53 +191,53 @@ public class InAppBrowserWebViewController: UIViewController, UIScrollViewDelega
|
||||
}
|
||||
|
||||
public func prepareConstraints () {
|
||||
containerWebView_BottomFullScreenConstraint = NSLayoutConstraint(item: self.containerWebView!, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: 0)
|
||||
containerWebView_TopFullScreenConstraint = NSLayoutConstraint(item: self.containerWebView!, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: 0)
|
||||
containerWebView_BottomFullScreenConstraint = NSLayoutConstraint(item: containerWebView!, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: 0)
|
||||
containerWebView_TopFullScreenConstraint = NSLayoutConstraint(item: containerWebView!, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: 0)
|
||||
|
||||
webView.translatesAutoresizingMaskIntoConstraints = false
|
||||
let height = NSLayoutConstraint(item: self.webView!, attribute: .height, relatedBy: .equal, toItem: containerWebView, attribute: .height, multiplier: 1, constant: 0)
|
||||
let width = NSLayoutConstraint(item: self.webView!, attribute: .width, relatedBy: .equal, toItem: containerWebView, attribute: .width, multiplier: 1, constant: 0)
|
||||
let leftConstraint = NSLayoutConstraint(item: self.webView!, attribute: .leftMargin, relatedBy: .equal, toItem: containerWebView, attribute: .leftMargin, multiplier: 1, constant: 0)
|
||||
let rightConstraint = NSLayoutConstraint(item: self.webView!, attribute: .rightMargin, relatedBy: .equal, toItem: containerWebView, attribute: .rightMargin, multiplier: 1, constant: 0)
|
||||
let bottomContraint = NSLayoutConstraint(item: self.webView!, attribute: .bottomMargin, relatedBy: .equal, toItem: containerWebView, attribute: .bottomMargin, multiplier: 1, constant: 0)
|
||||
let height = NSLayoutConstraint(item: webView!, attribute: .height, relatedBy: .equal, toItem: containerWebView, attribute: .height, multiplier: 1, constant: 0)
|
||||
let width = NSLayoutConstraint(item: webView!, attribute: .width, relatedBy: .equal, toItem: containerWebView, attribute: .width, multiplier: 1, constant: 0)
|
||||
let leftConstraint = NSLayoutConstraint(item: webView!, attribute: .leftMargin, relatedBy: .equal, toItem: containerWebView, attribute: .leftMargin, multiplier: 1, constant: 0)
|
||||
let rightConstraint = NSLayoutConstraint(item: webView!, attribute: .rightMargin, relatedBy: .equal, toItem: containerWebView, attribute: .rightMargin, multiplier: 1, constant: 0)
|
||||
let bottomContraint = NSLayoutConstraint(item: webView!, attribute: .bottomMargin, relatedBy: .equal, toItem: containerWebView, attribute: .bottomMargin, multiplier: 1, constant: 0)
|
||||
containerWebView.addConstraints([height, width, leftConstraint, rightConstraint, bottomContraint])
|
||||
|
||||
webView_BottomFullScreenConstraint = NSLayoutConstraint(item: webView!, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.containerWebView, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: 0)
|
||||
webView_TopFullScreenConstraint = NSLayoutConstraint(item: webView!, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.containerWebView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: 0)
|
||||
webView_BottomFullScreenConstraint = NSLayoutConstraint(item: webView!, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: containerWebView, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: 0)
|
||||
webView_TopFullScreenConstraint = NSLayoutConstraint(item: webView!, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: containerWebView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: 0)
|
||||
}
|
||||
|
||||
public func prepareWebView() {
|
||||
self.webView.options = webViewOptions
|
||||
self.webView.prepare()
|
||||
webView.options = webViewOptions
|
||||
webView.prepare()
|
||||
|
||||
if (browserOptions?.hideUrlBar)! {
|
||||
self.urlField.isHidden = true
|
||||
self.urlField.isEnabled = false
|
||||
urlField.isHidden = true
|
||||
urlField.isEnabled = false
|
||||
}
|
||||
|
||||
if (browserOptions?.toolbarTop)! {
|
||||
if browserOptions?.toolbarTopBackgroundColor != "" {
|
||||
self.toolbarTop.backgroundColor = color(fromHexString: (browserOptions?.toolbarTopBackgroundColor)!)
|
||||
toolbarTop.backgroundColor = color(fromHexString: (browserOptions?.toolbarTopBackgroundColor)!)
|
||||
}
|
||||
}
|
||||
else {
|
||||
self.toolbarTop.isHidden = true
|
||||
self.toolbarTop_BottomToWebViewTopConstraint.isActive = false
|
||||
self.containerWebView_TopFullScreenConstraint.isActive = true
|
||||
self.webView_TopFullScreenConstraint.isActive = true
|
||||
toolbarTop.isHidden = true
|
||||
toolbarTop_BottomToWebViewTopConstraint.isActive = false
|
||||
containerWebView_TopFullScreenConstraint.isActive = true
|
||||
webView_TopFullScreenConstraint.isActive = true
|
||||
}
|
||||
|
||||
if (browserOptions?.toolbarBottom)! {
|
||||
if browserOptions?.toolbarBottomBackgroundColor != "" {
|
||||
self.toolbarBottom.backgroundColor = color(fromHexString: (browserOptions?.toolbarBottomBackgroundColor)!)
|
||||
toolbarBottom.backgroundColor = color(fromHexString: (browserOptions?.toolbarBottomBackgroundColor)!)
|
||||
}
|
||||
self.toolbarBottom.isTranslucent = (browserOptions?.toolbarBottomTranslucent)!
|
||||
toolbarBottom.isTranslucent = (browserOptions?.toolbarBottomTranslucent)!
|
||||
}
|
||||
else {
|
||||
self.toolbarBottom.isHidden = true
|
||||
self.toolbarBottom_TopToWebViewBottomConstraint.isActive = false
|
||||
self.containerWebView_BottomFullScreenConstraint.isActive = true
|
||||
self.webView_BottomFullScreenConstraint.isActive = true
|
||||
toolbarBottom.isHidden = true
|
||||
toolbarBottom_TopToWebViewBottomConstraint.isActive = false
|
||||
containerWebView_BottomFullScreenConstraint.isActive = true
|
||||
webView_BottomFullScreenConstraint.isActive = true
|
||||
}
|
||||
|
||||
if browserOptions?.closeButtonCaption != "" {
|
||||
@ -242,12 +249,12 @@ public class InAppBrowserWebViewController: UIViewController, UIScrollViewDelega
|
||||
}
|
||||
|
||||
public func prepareBeforeViewWillAppear() {
|
||||
self.modalPresentationStyle = UIModalPresentationStyle(rawValue: (browserOptions?.presentationStyle)!)!
|
||||
self.modalTransitionStyle = UIModalTransitionStyle(rawValue: (browserOptions?.transitionStyle)!)!
|
||||
modalPresentationStyle = UIModalPresentationStyle(rawValue: (browserOptions?.presentationStyle)!)!
|
||||
modalTransitionStyle = UIModalTransitionStyle(rawValue: (browserOptions?.transitionStyle)!)!
|
||||
}
|
||||
|
||||
public func loadUrl(url: URL, headers: [String: String]?) {
|
||||
webView.loadUrl(url: url, headers: headers)
|
||||
public func loadUrl(url: URL, headers: [String: String]?, allowingReadAccessTo: URL?) {
|
||||
webView.loadUrl(url: url, headers: headers, allowingReadAccessTo: allowingReadAccessTo)
|
||||
updateUrlTextField(url: (webView.currentURL?.absoluteString)!)
|
||||
}
|
||||
|
||||
|
@ -134,9 +134,9 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
|
||||
}
|
||||
|
||||
public func load(initialUrl: String?, initialFile: String?, initialData: [String: String]?, initialHeaders: [String: String]?) {
|
||||
if initialFile != nil {
|
||||
if let initialFile = initialFile {
|
||||
do {
|
||||
try webView!.loadFile(url: initialFile!, headers: initialHeaders)
|
||||
try webView?.loadFile(url: initialFile, headers: initialHeaders)
|
||||
}
|
||||
catch let error as NSError {
|
||||
dump(error)
|
||||
@ -144,15 +144,22 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
|
||||
return
|
||||
}
|
||||
|
||||
if initialData != nil {
|
||||
let data = initialData!["data"]!
|
||||
let mimeType = initialData!["mimeType"]!
|
||||
let encoding = initialData!["encoding"]!
|
||||
let baseUrl = initialData!["baseUrl"]!
|
||||
webView!.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
|
||||
if let initialData = initialData {
|
||||
let data = initialData["data"]!
|
||||
let mimeType = initialData["mimeType"]!
|
||||
let encoding = initialData["encoding"]!
|
||||
let baseUrl = initialData["baseUrl"]!
|
||||
webView?.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
|
||||
}
|
||||
else if let url = URL(string: initialUrl!) {
|
||||
webView!.loadUrl(url: url, headers: initialHeaders)
|
||||
else if let initialUrl = initialUrl, let url = URL(string: initialUrl) {
|
||||
var allowingReadAccessToURL: URL? = nil
|
||||
if let allowingReadAccessTo = webView?.options?.allowingReadAccessTo, url.scheme == "file" {
|
||||
allowingReadAccessToURL = URL(string: allowingReadAccessTo)
|
||||
if allowingReadAccessToURL?.scheme != "file" {
|
||||
allowingReadAccessToURL = nil
|
||||
}
|
||||
}
|
||||
webView?.loadUrl(url: url, headers: initialHeaders, allowingReadAccessTo: allowingReadAccessToURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1838,18 +1838,22 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
||||
})
|
||||
}
|
||||
|
||||
public func loadUrl(url: URL, headers: [String: String]?) {
|
||||
var request = URLRequest(url: url)
|
||||
currentURL = url
|
||||
if headers != nil {
|
||||
if let mutableRequest = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest {
|
||||
for (key, value) in headers! {
|
||||
mutableRequest.setValue(value, forHTTPHeaderField: key)
|
||||
public func loadUrl(url: URL, headers: [String: String]?, allowingReadAccessTo: URL?) {
|
||||
if #available(iOS 9.0, *), let allowingReadAccessTo = allowingReadAccessTo, url.scheme == "file", allowingReadAccessTo.scheme == "file" {
|
||||
loadFileURL(url, allowingReadAccessTo: allowingReadAccessTo)
|
||||
} else {
|
||||
var request = URLRequest(url: url)
|
||||
currentURL = url
|
||||
if headers != nil {
|
||||
if let mutableRequest = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest {
|
||||
for (key, value) in headers! {
|
||||
mutableRequest.setValue(value, forHTTPHeaderField: key)
|
||||
}
|
||||
request = mutableRequest as URLRequest
|
||||
}
|
||||
request = mutableRequest as URLRequest
|
||||
}
|
||||
load(request)
|
||||
}
|
||||
load(request)
|
||||
}
|
||||
|
||||
public func postUrl(url: URL, postData: Data, completionHandler: @escaping () -> Void) {
|
||||
@ -1887,7 +1891,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
||||
if assetURL == nil {
|
||||
throw NSError(domain: url + " asset file cannot be found!", code: 0)
|
||||
}
|
||||
loadUrl(url: assetURL!, headers: headers)
|
||||
loadUrl(url: assetURL!, headers: headers, allowingReadAccessTo: nil)
|
||||
}
|
||||
|
||||
func setOptions(newOptions: InAppWebViewOptions, newOptionsMap: [String: Any]) {
|
||||
@ -3167,7 +3171,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
||||
if !handledByClient, InAppWebView.windowWebViews[windowId] != nil {
|
||||
InAppWebView.windowWebViews.removeValue(forKey: windowId)
|
||||
if let url = navigationAction.request.url {
|
||||
self.loadUrl(url: url, headers: nil)
|
||||
self.loadUrl(url: url, headers: nil, allowingReadAccessTo: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3435,9 +3439,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
||||
let serverTrust = challenge.protectionSpace.serverTrust!
|
||||
|
||||
var secResult = SecTrustResultType.invalid
|
||||
SecTrustEvaluate(serverTrust, &secResult);
|
||||
let secTrustEvaluateStatus = SecTrustEvaluate(serverTrust, &secResult);
|
||||
|
||||
if let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) {
|
||||
if secTrustEvaluateStatus == errSecSuccess, let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) {
|
||||
let serverCertificateCFData = SecCertificateCopyData(serverCertificate)
|
||||
let data = CFDataGetBytePtr(serverCertificateCFData)
|
||||
let size = CFDataGetLength(serverCertificateCFData)
|
||||
|
@ -67,6 +67,7 @@ public class InAppWebViewOptions: Options<InAppWebView> {
|
||||
var limitsNavigationsToAppBoundDomains = false
|
||||
var useOnNavigationResponse = false
|
||||
var applePayAPIEnabled = false
|
||||
var allowingReadAccessTo: String? = nil
|
||||
|
||||
override init(){
|
||||
super.init()
|
||||
|
@ -32,7 +32,12 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
|
||||
case "loadUrl":
|
||||
let url = arguments!["url"] as! String
|
||||
let headers = arguments!["headers"] as! [String: String]
|
||||
webView?.loadUrl(url: URL(string: url)!, headers: headers)
|
||||
let allowingReadAccessTo = arguments!["iosAllowingReadAccessTo"] as? String
|
||||
var allowingReadAccessToURL: URL? = nil
|
||||
if let allowingReadAccessTo = allowingReadAccessTo {
|
||||
allowingReadAccessToURL = URL(string: allowingReadAccessTo)
|
||||
}
|
||||
webView?.loadUrl(url: URL(string: url)!, headers: headers, allowingReadAccessTo: allowingReadAccessToURL)
|
||||
result(true)
|
||||
break
|
||||
case "postUrl":
|
||||
|
@ -193,9 +193,9 @@ class ASN1DERDecoder {
|
||||
}
|
||||
|
||||
/// Decode DER OID bytes to String with dot notation
|
||||
static String decodeOid({required List<int> contentData}) {
|
||||
static String? decodeOid({required List<int> contentData}) {
|
||||
if (contentData.isEmpty) {
|
||||
return "";
|
||||
return null;
|
||||
}
|
||||
|
||||
var oid = "";
|
||||
@ -393,6 +393,16 @@ class ASN1DERDecoder {
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
static List<int> sequenceContent({required List<int> data}) {
|
||||
var iterator = data.iterator;
|
||||
iterator.moveNext();
|
||||
try {
|
||||
return loadSubContent(iterator: iterator);
|
||||
} catch (e) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BigInt? toIntValue(List<int> data) {
|
||||
|
27
lib/src/X509Certificate/asn1_der_encoder.dart
Normal file
27
lib/src/X509Certificate/asn1_der_encoder.dart
Normal file
@ -0,0 +1,27 @@
|
||||
import 'dart:typed_data';
|
||||
import 'asn1_identifier.dart';
|
||||
|
||||
class ASN1DEREncoder {
|
||||
|
||||
static Uint8List encodeSequence({required Uint8List content}) {
|
||||
var encoded = Uint8List.fromList([]);
|
||||
encoded.add(ASN1Identifier.constructedTag | ASN1IdentifierTagNumber.SEQUENCE.toValue());
|
||||
encoded.addAll(contentLength(size: content.length));
|
||||
encoded.addAll(content);
|
||||
return Uint8List.fromList(encoded);
|
||||
}
|
||||
|
||||
static Uint8List contentLength({required int size}) {
|
||||
if (size >= 128) {
|
||||
var lenBytes = Uint8List(size);
|
||||
while (lenBytes.first == 0) {
|
||||
lenBytes.removeAt(0);
|
||||
}
|
||||
int len = 0x80 | lenBytes.length;
|
||||
return Uint8List(len)..addAll(lenBytes);
|
||||
} else {
|
||||
return Uint8List(size);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
|
||||
class ASN1DistinguishedNames {
|
||||
final String _oid;
|
||||
final String _representation;
|
||||
@ -67,4 +69,40 @@ class ASN1DistinguishedNames {
|
||||
|
||||
@override
|
||||
int get hashCode => _oid.hashCode;
|
||||
|
||||
/// Format subject/issuer information in RFC1779
|
||||
static String string({required ASN1Object block}) {
|
||||
var result = "";
|
||||
var oidNames = ASN1DistinguishedNames.values;
|
||||
for (var oidName in oidNames) {
|
||||
var oidBlock = block.findOid(oidValue: oidName.oid());
|
||||
if (oidBlock == null) {
|
||||
continue;
|
||||
}
|
||||
if (result.isNotEmpty) {
|
||||
result += ", ";
|
||||
}
|
||||
result += oidName.representation();
|
||||
result += "=";
|
||||
|
||||
String? value;
|
||||
try {
|
||||
value = oidBlock.parent?.sub?.last.value as String?;
|
||||
} catch (e) {}
|
||||
if (value != null) {
|
||||
result += quote(value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static String quote(String string) {
|
||||
var specialChars = [",", "+", "=", "\n", "<", ">", "#", ";", "\\"];
|
||||
for (var specialChar in specialChars) {
|
||||
if (string.contains(specialChar)) {
|
||||
return "\"" + string + "\"";
|
||||
}
|
||||
}
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
@ -206,15 +206,16 @@ class ASN1IdentifierTagNumber {
|
||||
|
||||
class ASN1Identifier {
|
||||
int rawValue;
|
||||
static int constructedTag = 0x20;
|
||||
|
||||
ASN1Identifier(this.rawValue);
|
||||
|
||||
bool isPrimitive() {
|
||||
return (rawValue & 0x20) == 0;
|
||||
return (rawValue & ASN1Identifier.constructedTag) == 0;
|
||||
}
|
||||
|
||||
bool isConstructed() {
|
||||
return (rawValue & 0x20) != 0;
|
||||
return (rawValue & ASN1Identifier.constructedTag) != 0;
|
||||
}
|
||||
|
||||
ASN1IdentifierTagNumber tagNumber() {
|
||||
|
@ -9,7 +9,7 @@ class ASN1Object {
|
||||
/// This property contains the DER encoded object
|
||||
Uint8List? encoded;
|
||||
|
||||
/// This property contains the decoded Swift object whenever is possible
|
||||
/// This property contains the decoded object whenever is possible
|
||||
dynamic value;
|
||||
|
||||
ASN1Identifier? identifier;
|
||||
@ -96,4 +96,22 @@ class ASN1Object {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String? get asString {
|
||||
var string = value as String?;
|
||||
if (string != null) {
|
||||
return string;
|
||||
}
|
||||
|
||||
if (sub != null && sub!.length > 0) {
|
||||
for (var item in sub!) {
|
||||
var itemAsString = item.asString;
|
||||
if (itemAsString != null) {
|
||||
return itemAsString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
// from https://github.com/filom/ASN1Decoder
|
||||
|
||||
export 'asn1_decoder.dart';
|
||||
export 'asn1_distinguished_names.dart';
|
||||
export 'asn1_identifier.dart';
|
||||
@ -7,3 +9,4 @@ export 'key_usage.dart';
|
||||
export 'x509_certificate.dart';
|
||||
export 'x509_extension.dart';
|
||||
export 'x509_public_key.dart';
|
||||
export 'asn1_der_encoder.dart';
|
@ -100,6 +100,11 @@ class OID {
|
||||
OID.codeSigning,
|
||||
OID.emailProtection,
|
||||
OID.timeStamping,
|
||||
OID.pkcsSha256,
|
||||
OID.sha2Family,
|
||||
OID.sha3_244,
|
||||
OID.sha3_256,
|
||||
OID.sha3_384,
|
||||
].toSet();
|
||||
|
||||
static OID? fromValue(String? value) {
|
||||
@ -174,10 +179,15 @@ class OID {
|
||||
static const dateOfBirth = const OID._internal("1.3.6.1.5.5.7.9.1");
|
||||
static const desCBC = const OID._internal("1.3.14.3.2.7");
|
||||
static const sha1 = const OID._internal("1.3.14.3.2.26");
|
||||
static const pkcsSha256 = const OID._internal("1.3.6.1.4.1.22554.1.2.1");
|
||||
static const sha2Family = const OID._internal("1.3.6.1.4.1.22554.1.2");
|
||||
static const sha3_244 = const OID._internal("2.16.840.1.101.3.4.2.7");
|
||||
static const sha3_256 = const OID._internal("2.16.840.1.101.3.4.2.8");
|
||||
static const sha3_384 = const OID._internal("2.16.840.1.101.3.4.2.9");
|
||||
static const md5 = const OID._internal("0.2.262.1.10.1.3.2");
|
||||
static const sha256 = const OID._internal("2.16.840.1.101.3.4.2.1");
|
||||
static const sha384 = const OID._internal("2.16.840.1.101.3.4.2.2");
|
||||
static const sha512 = const OID._internal("2.16.840.1.101.3.4.2.3");
|
||||
static const md5 = const OID._internal("1.2.840.113549.2.5");
|
||||
static const VeriSignEVpolicy =
|
||||
const OID._internal("2.16.840.1.113733.1.7.23.6");
|
||||
static const extendedValidation = const OID._internal("2.23.140.1.1");
|
||||
@ -278,10 +288,15 @@ class OID {
|
||||
"1.3.6.1.5.5.7.9.1": "dateOfBirth",
|
||||
"1.3.14.3.2.7": "desCBC",
|
||||
"1.3.14.3.2.26": "sha1",
|
||||
"1.3.6.1.4.1.22554.1.2.1": "pkcsSha256",
|
||||
"1.3.6.1.4.1.22554.1.2": "sha2Family",
|
||||
"2.16.840.1.101.3.4.2.7": "sha3_244",
|
||||
"2.16.840.1.101.3.4.2.8": "sha3_256",
|
||||
"2.16.840.1.101.3.4.2.9": "sha3_384",
|
||||
"2.16.840.1.101.3.4.2.1": "sha256",
|
||||
"2.16.840.1.101.3.4.2.2": "sha384",
|
||||
"2.16.840.1.101.3.4.2.3": "sha512",
|
||||
"1.2.840.113549.2.5": "md5",
|
||||
"0.2.262.1.10.1.3.2": "md5",
|
||||
"2.16.840.1.113733.1.7.23.6": "VeriSign EV policy",
|
||||
"2.23.140.1.1": "extendedValidation",
|
||||
"2.23.140.1.2.2": "organizationValidated",
|
||||
|
@ -131,7 +131,7 @@ class X509Certificate {
|
||||
String? get issuerDistinguishedName {
|
||||
var issuerBlock = block1?.atIndex(X509BlockPosition.issuer);
|
||||
if (issuerBlock != null) {
|
||||
return blockDistinguishedName(block: issuerBlock);
|
||||
return ASN1DistinguishedNames.string(block: issuerBlock);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -175,7 +175,7 @@ class X509Certificate {
|
||||
String? get subjectDistinguishedName {
|
||||
var subjectBlock = block1?.atIndex(X509BlockPosition.subject);
|
||||
if (subjectBlock != null) {
|
||||
return blockDistinguishedName(block: subjectBlock);
|
||||
return ASN1DistinguishedNames.string(block: subjectBlock);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -278,11 +278,11 @@ class X509Certificate {
|
||||
|
||||
///Gets a collection of subject alternative names from the SubjectAltName extension, (OID = 2.5.29.17).
|
||||
List<String> get subjectAlternativeNames =>
|
||||
extensionObject(oid: OID.subjectAltName)?.valueAsStrings ?? <String>[];
|
||||
extensionObject(oid: OID.subjectAltName)?.alternativeNameAsStrings ?? <String>[];
|
||||
|
||||
///Gets a collection of issuer alternative names from the IssuerAltName extension, (OID = 2.5.29.18).
|
||||
List<String> get issuerAlternativeNames =>
|
||||
extensionObject(oid: OID.issuerAltName)?.valueAsStrings ?? <String>[];
|
||||
extensionObject(oid: OID.issuerAltName)?.alternativeNameAsStrings ?? <String>[];
|
||||
|
||||
///Gets the informations of the public key from this certificate.
|
||||
X509PublicKey? get publicKey {
|
||||
@ -321,81 +321,24 @@ class X509Certificate {
|
||||
|
||||
///Gets the certificate constraints path length from the
|
||||
///critical BasicConstraints extension, (OID = 2.5.29.19).
|
||||
int get basicConstraints {
|
||||
var sub = extensionObject(oid: OID.basicConstraints)
|
||||
?.block
|
||||
?.lastSub()
|
||||
?.lastSub()
|
||||
?.lastSub();
|
||||
if (sub != null) {
|
||||
if (sub.value is List<int>) {
|
||||
return (sub.value as List<int>).length;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
BasicConstraintExtension? get basicConstraints => extensionObject(oid: OID.basicConstraints) as BasicConstraintExtension?;
|
||||
|
||||
///Gets the raw bits from the Subject Key Identifier (SKID) extension, (OID = 2.5.29.14).
|
||||
List<int> get subjectKeyIdentifier =>
|
||||
extensionObject(oid: OID.subjectKeyIdentifier)
|
||||
?.block
|
||||
?.lastSub()
|
||||
?.lastSub()
|
||||
?.value ??
|
||||
<int>[];
|
||||
SubjectKeyIdentifierExtension? get subjectKeyIdentifier => extensionObject(oid: OID.subjectKeyIdentifier) as SubjectKeyIdentifierExtension?;
|
||||
|
||||
///Gets the raw bits from the Authority Key Identifier extension, (OID = 2.5.29.35).
|
||||
List<int> get authorityKeyIdentifier =>
|
||||
extensionObject(oid: OID.authorityKeyIdentifier)
|
||||
?.block
|
||||
?.lastSub()
|
||||
?.lastSub()
|
||||
?.firstSub()
|
||||
?.value ??
|
||||
<int>[];
|
||||
AuthorityKeyIdentifierExtension? get authorityKeyIdentifier => extensionObject(oid: OID.authorityKeyIdentifier) as AuthorityKeyIdentifierExtension?;
|
||||
|
||||
///Gets the list of certificate policies from the CertificatePolicies extension, (OID = 2.5.29.32).
|
||||
List<String> get certificatePolicies =>
|
||||
extensionObject(oid: OID.certificatePolicies)
|
||||
?.block
|
||||
?.lastSub()
|
||||
?.firstSub()
|
||||
?.sub
|
||||
?.map((e) => e.firstSub()?.value as String)
|
||||
.toList() ??
|
||||
<String>[];
|
||||
CertificatePoliciesExtension? get certificatePolicies => extensionObject(oid: OID.certificatePolicies) as CertificatePoliciesExtension?;
|
||||
|
||||
///Gets the list of CRL distribution points from the CRLDistributionPoints extension, (OID = 2.5.29.31).
|
||||
List<String> get cRLDistributionPoints =>
|
||||
extensionObject(oid: OID.cRLDistributionPoints)
|
||||
?.block
|
||||
?.lastSub()
|
||||
?.firstSub()
|
||||
?.sub
|
||||
?.map((e) => e.firstSub()?.firstSub()?.firstSub()?.value as String)
|
||||
.toList() ??
|
||||
<String>[];
|
||||
CRLDistributionPointsExtension? get cRLDistributionPoints => extensionObject(oid: OID.cRLDistributionPoints) as CRLDistributionPointsExtension?;
|
||||
|
||||
///Gets the map of the format (as a key) and location (as a value) of additional information
|
||||
///about the CA who issued the certificate in which this extension appears
|
||||
///from the AuthorityInfoAccess extension, (OID = 1.3.6.1.5.5.5.7.1.1).
|
||||
Map<String, String> get authorityInfoAccess {
|
||||
var result = <String, String>{};
|
||||
var sub = extensionObject(oid: OID.authorityInfoAccess)
|
||||
?.block
|
||||
?.lastSub()
|
||||
?.firstSub()
|
||||
?.sub;
|
||||
if (sub != null) {
|
||||
sub.forEach((element) {
|
||||
if (element.subCount() > 1) {
|
||||
result.putIfAbsent(
|
||||
element.subAtIndex(0)!.value, () => element.subAtIndex(1)!.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
AuthorityInfoAccessExtension? get authorityInfoAccess => extensionObject(oid: OID.authorityInfoAccess) as AuthorityInfoAccessExtension?;
|
||||
|
||||
List<ASN1Object>? get extensionBlocks =>
|
||||
block1?.atIndex(X509BlockPosition.extensions)?.subAtIndex(0)?.sub;
|
||||
@ -410,46 +353,25 @@ class X509Certificate {
|
||||
?.findOid(oidValue: oidValue)
|
||||
?.parent;
|
||||
if (block != null) {
|
||||
if (oidValue == OID.basicConstraints.toValue()) {
|
||||
return BasicConstraintExtension(block: block);
|
||||
} else if (oidValue == OID.subjectKeyIdentifier.toValue()) {
|
||||
return SubjectKeyIdentifierExtension(block: block);
|
||||
} else if (oidValue == OID.authorityInfoAccess.toValue()) {
|
||||
return AuthorityInfoAccessExtension(block: block);
|
||||
} else if (oidValue == OID.authorityKeyIdentifier.toValue()) {
|
||||
return AuthorityKeyIdentifierExtension(block: block);
|
||||
} else if (oidValue == OID.certificatePolicies.toValue()) {
|
||||
return CertificatePoliciesExtension(block: block);
|
||||
} else if (oidValue == OID.cRLDistributionPoints.toValue()) {
|
||||
return CRLDistributionPointsExtension(block: block);
|
||||
}
|
||||
return X509Extension(block: block);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
///Format subject/issuer information in RFC1779
|
||||
String blockDistinguishedName({required ASN1Object block}) {
|
||||
var result = "";
|
||||
for (var oidName in ASN1DistinguishedNames.values) {
|
||||
var oidBlock = block.findOid(oidValue: oidName.oid());
|
||||
if (oidBlock != null) {
|
||||
if (result.isNotEmpty) {
|
||||
result += ", ";
|
||||
}
|
||||
result += oidName.representation();
|
||||
result += "=";
|
||||
|
||||
var sub = oidBlock.parent?.sub;
|
||||
if (sub != null && sub.length > 0) {
|
||||
var value = sub.last.value as String?;
|
||||
if (value != null) {
|
||||
var specialChar = ",+=\n<>#;\\";
|
||||
var quote = "";
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
var char = value[i];
|
||||
if (specialChar.contains(char)) {
|
||||
quote = "\"";
|
||||
}
|
||||
}
|
||||
result += quote;
|
||||
result += value;
|
||||
result += quote;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return description;
|
||||
@ -457,7 +379,7 @@ class X509Certificate {
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"basicConstraints": basicConstraints,
|
||||
"basicConstraints": basicConstraints?.toMap(),
|
||||
"subjectAlternativeNames": subjectAlternativeNames,
|
||||
"issuerAlternativeNames": issuerAlternativeNames,
|
||||
"extendedKeyUsage": extendedKeyUsage,
|
||||
@ -476,11 +398,11 @@ class X509Certificate {
|
||||
"nonCriticalExtensionOIDs": nonCriticalExtensionOIDs,
|
||||
"encoded": encoded,
|
||||
"publicKey": publicKey?.toMap(),
|
||||
"subjectKeyIdentifier": subjectKeyIdentifier,
|
||||
"authorityKeyIdentifier": authorityKeyIdentifier,
|
||||
"certificatePolicies": certificatePolicies,
|
||||
"cRLDistributionPoints": cRLDistributionPoints,
|
||||
"authorityInfoAccess": authorityInfoAccess,
|
||||
"subjectKeyIdentifier": subjectKeyIdentifier?.toMap(),
|
||||
"authorityKeyIdentifier": authorityKeyIdentifier?.toMap(),
|
||||
"certificatePolicies": certificatePolicies?.toMap(),
|
||||
"cRLDistributionPoints": cRLDistributionPoints?.toMap(),
|
||||
"authorityInfoAccess": authorityInfoAccess?.toMap(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
|
||||
import 'x509_certificate.dart';
|
||||
import 'asn1_object.dart';
|
||||
import 'oid.dart';
|
||||
import 'asn1_distinguished_names.dart';
|
||||
|
||||
class X509Extension {
|
||||
ASN1Object? block;
|
||||
@ -59,4 +65,413 @@ class X509Extension {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Used for SubjectAltName and IssuerAltName
|
||||
// Every name can be one of these subtype:
|
||||
// - otherName [0] INSTANCE OF OTHER-NAME,
|
||||
// - rfc822Name [1] IA5String,
|
||||
// - dNSName [2] IA5String,
|
||||
// - x400Address [3] ORAddress,
|
||||
// - directoryName [4] Name,
|
||||
// - ediPartyName [5] EDIPartyName,
|
||||
// - uniformResourceIdentifier [6] IA5String,
|
||||
// - IPAddress [7] OCTET STRING,
|
||||
// - registeredID [8] OBJECT IDENTIFIER
|
||||
//
|
||||
// Result does not support: x400Address and ediPartyName
|
||||
//
|
||||
List<String> get alternativeNameAsStrings {
|
||||
List<String> result = [];
|
||||
var sub = <ASN1Object>[];
|
||||
try {
|
||||
sub = block?.sub?.last.sub?.last.sub ?? <ASN1Object>[];
|
||||
} catch (e) {}
|
||||
for (var item in sub) {
|
||||
var name = generalName(item: item);
|
||||
if (name != null) {
|
||||
result.add(name);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String? generalName({required ASN1Object item}) {
|
||||
var nameType = item.identifier?.tagNumber().toValue();
|
||||
if (nameType == null) {
|
||||
return null;
|
||||
}
|
||||
switch (nameType) {
|
||||
case 0:
|
||||
String? name;
|
||||
try {
|
||||
name = item.sub?.last.sub?.last.value as String?;
|
||||
} catch (e) {}
|
||||
return name;
|
||||
case 1:
|
||||
case 2:
|
||||
case 6:
|
||||
String? name = item.value as String?;
|
||||
return name;
|
||||
case 4:
|
||||
return ASN1DistinguishedNames.string(block: item);
|
||||
case 7:
|
||||
var ip = item.value as List<int>?;
|
||||
if (ip != null) {
|
||||
return ip.map((e) => e.toString()).join(".");
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
var value = item.value as String?;
|
||||
if (value != null) {
|
||||
try {
|
||||
var data = utf8.encode(value);
|
||||
var oid = ASN1DERDecoder.decodeOid(contentData: data);
|
||||
return oid;
|
||||
} catch (e) {}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Recognition for Basic Constraint Extension (2.5.29.19)
|
||||
class BasicConstraintExtension extends X509Extension {
|
||||
BasicConstraintExtension({required block}) : super(block: block);
|
||||
|
||||
bool get isCA => valueAsBlock?.subAtIndex(0)?.subAtIndex(0)?.value as bool? ?? false;
|
||||
|
||||
int? get pathLenConstraint {
|
||||
var data = valueAsBlock?.subAtIndex(0)?.subAtIndex(0)?.value as List<int>?;
|
||||
if (data != null) {
|
||||
return data.length;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"isCA": isCA,
|
||||
"pathLenConstraint": pathLenConstraint,
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return toMap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Recognition for Subject Key Identifier Extension (2.5.29.14)
|
||||
class SubjectKeyIdentifierExtension extends X509Extension {
|
||||
SubjectKeyIdentifierExtension({required block}) : super(block: block);
|
||||
|
||||
@override
|
||||
List<int>? get value {
|
||||
var rawValue = valueAsBlock?.encoded;
|
||||
if (rawValue != null) {
|
||||
return ASN1DERDecoder.sequenceContent(data: rawValue.toList());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"value": value,
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return toMap();
|
||||
}
|
||||
}
|
||||
|
||||
class AuthorityInfoAccess {
|
||||
String method;
|
||||
String location;
|
||||
|
||||
AuthorityInfoAccess({required this.method, required this.location});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"method": method,
|
||||
"location": location,
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return toMap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Recognition for Authority Info Access Extension (1.3.6.1.5.5.7.1.1)
|
||||
class AuthorityInfoAccessExtension extends X509Extension {
|
||||
AuthorityInfoAccessExtension({required block}) : super(block: block);
|
||||
|
||||
List<AuthorityInfoAccess>? get infoAccess {
|
||||
if (valueAsBlock == null) {
|
||||
return null;
|
||||
}
|
||||
var subs = valueAsBlock!.subAtIndex(0)?.sub ?? <ASN1Object>[];
|
||||
List<AuthorityInfoAccess> result = <AuthorityInfoAccess>[];
|
||||
subs.forEach((sub) {
|
||||
var oidData = sub.subAtIndex(0)?.encoded;
|
||||
var nameBlock = sub.subAtIndex(1);
|
||||
if (oidData == null || nameBlock == null) {
|
||||
return;
|
||||
}
|
||||
var oid = ASN1DERDecoder.decodeOid(contentData: oidData.toList());
|
||||
var location = generalName(item: nameBlock);
|
||||
if (oid != null && location != null) {
|
||||
result.add(AuthorityInfoAccess(method: oid, location: location));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"infoAccess": infoAccess?.map((e) => e.toMap()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return toMap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Recognition for Authority Key Identifier Extension (2.5.29.35)
|
||||
class AuthorityKeyIdentifierExtension extends X509Extension {
|
||||
AuthorityKeyIdentifierExtension({required block}) : super(block: block);
|
||||
|
||||
///AuthorityKeyIdentifier ::= SEQUENCE {
|
||||
/// keyIdentifier [0] KeyIdentifier OPTIONAL,
|
||||
/// authorityCertIssuer [1] GeneralNames OPTIONAL,
|
||||
/// authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
|
||||
List<int>? get keyIdentifier {
|
||||
var sequence = valueAsBlock?.subAtIndex(0)?.sub;
|
||||
if (sequence == null) {
|
||||
return null;
|
||||
}
|
||||
ASN1Object? sub;
|
||||
try {
|
||||
sub = sequence.firstWhere((element) => element.identifier?.tagNumber().toValue() == 0);
|
||||
return sub.encoded;
|
||||
} catch (e) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String>? get certificateIssuer {
|
||||
var sequence = valueAsBlock?.subAtIndex(0)?.sub;
|
||||
if (sequence == null) {
|
||||
return null;
|
||||
}
|
||||
ASN1Object? sub;
|
||||
try {
|
||||
sub = sequence.firstWhere((element) => element.identifier?.tagNumber().toValue() == 1);
|
||||
List<String>? result;
|
||||
if (sub.sub != null) {
|
||||
result = <String>[];
|
||||
sub.sub?.forEach((e) {
|
||||
var name = generalName(item: e);
|
||||
if (name != null) {
|
||||
result!.add(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
} catch (e) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
List<int>? get serialNumber {
|
||||
var sequence = valueAsBlock?.subAtIndex(0)?.sub;
|
||||
if (sequence == null) {
|
||||
return null;
|
||||
}
|
||||
ASN1Object? sub;
|
||||
try {
|
||||
sub = sequence.firstWhere((element) => element.identifier?.tagNumber().toValue() == 2);
|
||||
return sub.encoded;
|
||||
} catch (e) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"keyIdentifier": keyIdentifier,
|
||||
"certificateIssuer": certificateIssuer,
|
||||
"serialNumber": serialNumber,
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return toMap();
|
||||
}
|
||||
}
|
||||
|
||||
class CertificatePolicyQualifier {
|
||||
String oid;
|
||||
String? value;
|
||||
|
||||
CertificatePolicyQualifier({required this.oid, this.value});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"oid": oid,
|
||||
"value": value,
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return toMap();
|
||||
}
|
||||
}
|
||||
class CertificatePolicy {
|
||||
String oid;
|
||||
List<CertificatePolicyQualifier>? qualifiers;
|
||||
|
||||
CertificatePolicy({required this.oid, this.qualifiers});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"oid": oid,
|
||||
"qualifiers": qualifiers?.map((e) => e.toMap()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return toMap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Recognition for Certificate Policies Extension (2.5.29.32)
|
||||
class CertificatePoliciesExtension extends X509Extension {
|
||||
CertificatePoliciesExtension({required block}) : super(block: block);
|
||||
|
||||
List<CertificatePolicy>? get policies {
|
||||
if (valueAsBlock == null) {
|
||||
return null;
|
||||
}
|
||||
var subs = valueAsBlock!.subAtIndex(0)?.sub ?? <ASN1Object>[];
|
||||
|
||||
List<CertificatePolicy> result = <CertificatePolicy>[];
|
||||
subs.forEach((sub) {
|
||||
var data = sub.subAtIndex(0)?.encoded;
|
||||
String? oid;
|
||||
if (data != null) {
|
||||
oid = ASN1DERDecoder.decodeOid(contentData: data.toList());
|
||||
if (oid == null) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
List<CertificatePolicyQualifier>? qualifiers;
|
||||
var subQualifiers = sub.subAtIndex(1);
|
||||
if (subQualifiers != null && subQualifiers.sub != null) {
|
||||
qualifiers = <CertificatePolicyQualifier>[];
|
||||
subQualifiers.sub!.forEach((sub) {
|
||||
var rawValue = sub.subAtIndex(0)?.encoded;
|
||||
String? oid;
|
||||
if (rawValue != null) {
|
||||
oid = ASN1DERDecoder.decodeOid(contentData: rawValue.toList());
|
||||
if (oid == null) {
|
||||
return;
|
||||
}
|
||||
var value = sub.subAtIndex(1)?.asString;
|
||||
qualifiers!.add(CertificatePolicyQualifier(oid: oid, value: value));
|
||||
}
|
||||
});
|
||||
}
|
||||
result.add(CertificatePolicy(oid: oid, qualifiers: qualifiers));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"policies": policies?.map((e) => e.toMap()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return toMap();
|
||||
}
|
||||
}
|
||||
|
||||
class CRLDistributionPointsExtension extends X509Extension {
|
||||
CRLDistributionPointsExtension({required block}) : super(block: block);
|
||||
|
||||
List<String>? get crls {
|
||||
if (valueAsBlock == null) {
|
||||
return null;
|
||||
}
|
||||
var subs = valueAsBlock!.subAtIndex(0)?.sub ?? <ASN1Object>[];
|
||||
List<String> result = <String>[];
|
||||
subs.forEach((sub) {
|
||||
var asString = sub.asString;
|
||||
if (asString != null) {
|
||||
result.add(asString);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"crls": crls,
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return toMap();
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter_inappwebview/src/X509Certificate/asn1_der_encoder.dart';
|
||||
|
||||
import 'asn1_decoder.dart';
|
||||
import 'asn1_object.dart';
|
||||
import 'oid.dart';
|
||||
@ -15,6 +17,14 @@ class X509PublicKey {
|
||||
|
||||
String? get algParams => pkBlock?.subAtIndex(0)?.subAtIndex(1)?.value;
|
||||
|
||||
Uint8List? get derEncodedKey {
|
||||
var value = pkBlock?.encoded;
|
||||
if (value != null) {
|
||||
return ASN1DEREncoder.encodeSequence(content: value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Uint8List? get encoded {
|
||||
var oid = OID.fromValue(algOid);
|
||||
var keyData = pkBlock?.subAtIndex(1)?.value ?? null;
|
||||
|
@ -70,7 +70,6 @@ class HeadlessInAppWebView implements WebView {
|
||||
this.androidOnRenderProcessUnresponsive,
|
||||
this.androidOnFormResubmission,
|
||||
this.androidOnScaleChanged,
|
||||
this.androidOnRequestFocus,
|
||||
this.androidOnReceivedIcon,
|
||||
this.androidOnReceivedTouchIconUrl,
|
||||
this.androidOnJsBeforeUnload,
|
||||
@ -230,9 +229,6 @@ class HeadlessInAppWebView implements WebView {
|
||||
@override
|
||||
final void Function(InAppWebViewController controller)? onWindowBlur;
|
||||
|
||||
@override
|
||||
final void Function(InAppWebViewController controller)? androidOnRequestFocus;
|
||||
|
||||
@override
|
||||
final void Function(InAppWebViewController controller, String url)?
|
||||
onDownloadStart;
|
||||
|
@ -686,14 +686,6 @@ class InAppBrowser {
|
||||
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebViewClient#onScaleChanged(android.webkit.WebView,%20float,%20float)
|
||||
void androidOnScaleChanged(double oldScale, double newScale) {}
|
||||
|
||||
///Event fired when there is a request to display and focus for this WebView.
|
||||
///This may happen due to another WebView opening a link in this WebView and requesting that this WebView be displayed.
|
||||
///
|
||||
///**NOTE**: available only on Android.
|
||||
///
|
||||
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebChromeClient#onRequestFocus(android.webkit.WebView)
|
||||
void androidOnRequestFocus() {}
|
||||
|
||||
///Event fired when there is new favicon for the current page.
|
||||
///
|
||||
///[icon] represents the favicon for the current page.
|
||||
|
@ -82,7 +82,6 @@ class InAppWebView extends StatefulWidget implements WebView {
|
||||
this.androidOnRenderProcessUnresponsive,
|
||||
this.androidOnFormResubmission,
|
||||
this.androidOnScaleChanged,
|
||||
this.androidOnRequestFocus,
|
||||
this.androidOnReceivedIcon,
|
||||
this.androidOnReceivedTouchIconUrl,
|
||||
this.androidOnJsBeforeUnload,
|
||||
@ -191,9 +190,6 @@ class InAppWebView extends StatefulWidget implements WebView {
|
||||
@override
|
||||
final void Function(InAppWebViewController controller)? onWindowBlur;
|
||||
|
||||
@override
|
||||
final void Function(InAppWebViewController controller)? androidOnRequestFocus;
|
||||
|
||||
@override
|
||||
final void Function(InAppWebViewController controller, Uint8List icon)?
|
||||
androidOnReceivedIcon;
|
||||
|
@ -373,11 +373,6 @@ class InAppWebViewController {
|
||||
else if (_inAppBrowser != null)
|
||||
_inAppBrowser!.androidOnScaleChanged(oldScale, newScale);
|
||||
break;
|
||||
case "onRequestFocus":
|
||||
if (_webview != null && _webview!.androidOnRequestFocus != null)
|
||||
_webview!.androidOnRequestFocus!(this);
|
||||
else if (_inAppBrowser != null) _inAppBrowser!.androidOnRequestFocus();
|
||||
break;
|
||||
case "onReceivedIcon":
|
||||
Uint8List icon = Uint8List.fromList(call.arguments["icon"].cast<int>());
|
||||
|
||||
@ -1250,15 +1245,26 @@ class InAppWebViewController {
|
||||
|
||||
///Loads the given [url] with optional [headers] specified as a map from name to value.
|
||||
///
|
||||
///[iosAllowingReadAccessTo], used in combination with [url] (using the `file://` scheme),
|
||||
///is an iOS-specific argument that represents the URL from which to read the web content.
|
||||
///This URL must be a file-based URL (using the `file://` scheme).
|
||||
///Specify the same value as the URL parameter to prevent WebView from reading any other content.
|
||||
///Specify a directory to give WebView permission to read additional files in the specified directory.
|
||||
///
|
||||
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#loadUrl(java.lang.String)
|
||||
///
|
||||
///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1414954-load
|
||||
///**Official iOS API**:
|
||||
///- https://developer.apple.com/documentation/webkit/wkwebview/1414954-load
|
||||
///- if [iosAllowingReadAccessTo] is used, https://developer.apple.com/documentation/webkit/wkwebview/1414973-loadfileurl
|
||||
Future<void> loadUrl(
|
||||
{required String url, Map<String, String> headers = const {}}) async {
|
||||
{required String url, Map<String, String> headers = const {}, String? iosAllowingReadAccessTo}) async {
|
||||
assert(url.isNotEmpty);
|
||||
assert(iosAllowingReadAccessTo == null || iosAllowingReadAccessTo.startsWith("file://"));
|
||||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('url', () => url);
|
||||
args.putIfAbsent('headers', () => headers);
|
||||
args.putIfAbsent('iosAllowingReadAccessTo', () => iosAllowingReadAccessTo);
|
||||
await _channel.invokeMethod('loadUrl', args);
|
||||
}
|
||||
|
||||
|
@ -529,14 +529,6 @@ abstract class WebView {
|
||||
InAppWebViewController controller, double oldScale, double newScale)?
|
||||
androidOnScaleChanged;
|
||||
|
||||
///Event fired when there is a request to display and focus for this WebView.
|
||||
///This may happen due to another WebView opening a link in this WebView and requesting that this WebView be displayed.
|
||||
///
|
||||
///**NOTE**: available only on Android.
|
||||
///
|
||||
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebChromeClient#onRequestFocus(android.webkit.WebView)
|
||||
final void Function(InAppWebViewController controller)? androidOnRequestFocus;
|
||||
|
||||
///Event fired when there is new favicon for the current page.
|
||||
///
|
||||
///[icon] represents the favicon for the current page.
|
||||
@ -696,7 +688,6 @@ abstract class WebView {
|
||||
this.androidOnRenderProcessUnresponsive,
|
||||
this.androidOnFormResubmission,
|
||||
this.androidOnScaleChanged,
|
||||
this.androidOnRequestFocus,
|
||||
this.androidOnReceivedIcon,
|
||||
this.androidOnReceivedTouchIconUrl,
|
||||
this.androidOnJsBeforeUnload,
|
||||
|
@ -923,6 +923,12 @@ class IOSInAppWebViewOptions
|
||||
///**NOTE**: available on iOS 13.0+.
|
||||
bool applePayAPIEnabled;
|
||||
|
||||
///Used in combination with [WebView.initialUrl] (using the `file://` scheme), it represents the URL from which to read the web content.
|
||||
///This URL must be a file-based URL (using the `file://` scheme).
|
||||
///Specify the same value as the [WebView.initialUrl] parameter to prevent WebView from reading any other content.
|
||||
///Specify a directory to give WebView permission to read additional files in the specified directory.
|
||||
String? allowingReadAccessTo;
|
||||
|
||||
IOSInAppWebViewOptions(
|
||||
{this.disallowOverScroll = false,
|
||||
this.enableViewportScale = false,
|
||||
@ -953,7 +959,10 @@ class IOSInAppWebViewOptions
|
||||
this.pageZoom = 1.0,
|
||||
this.limitsNavigationsToAppBoundDomains = false,
|
||||
this.useOnNavigationResponse = false,
|
||||
this.applePayAPIEnabled = false});
|
||||
this.applePayAPIEnabled = false,
|
||||
this.allowingReadAccessTo}) {
|
||||
assert(allowingReadAccessTo == null || allowingReadAccessTo!.startsWith("file://"));
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toMap() {
|
||||
@ -995,6 +1004,7 @@ class IOSInAppWebViewOptions
|
||||
"limitsNavigationsToAppBoundDomains": limitsNavigationsToAppBoundDomains,
|
||||
"useOnNavigationResponse": useOnNavigationResponse,
|
||||
"applePayAPIEnabled": applePayAPIEnabled,
|
||||
"allowingReadAccessTo": allowingReadAccessTo,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1050,6 +1060,7 @@ class IOSInAppWebViewOptions
|
||||
options.limitsNavigationsToAppBoundDomains = map["limitsNavigationsToAppBoundDomains"];
|
||||
options.useOnNavigationResponse = map["useOnNavigationResponse"];
|
||||
options.applePayAPIEnabled = map["applePayAPIEnabled"];
|
||||
options.allowingReadAccessTo = map["allowingReadAccessTo"];
|
||||
return options;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user