added getHtml method, updated android config, remove block on long press webview android, fixed other issues

This commit is contained in:
Lorenzo Pichilli 2019-11-02 19:58:01 +01:00
parent 6518697e55
commit 299042f828
35 changed files with 1363 additions and 1087 deletions

383
.idea/workspace.xml generated
View File

@ -15,23 +15,41 @@
</component>
<component name="ChangeListManager">
<list default="true" id="9b41f7a2-a71e-4923-91fb-249d7815b3e7" name="Default" comment="">
<change afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/example/assets/favicon.ico" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/CHANGELOG.md" beforeDir="false" afterPath="$PROJECT_DIR$/CHANGELOG.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/android/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/gradle.properties" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/AndroidManifest.xml" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/AndroidManifest.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ChromeCustomTabs/ChromeCustomTabsActivity.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ChromeCustomTabs/ChromeCustomTabsActivity.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerHandler.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/CredentialDatabaseHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/CredentialDatabaseHandler.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebView.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserActivity.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserActivity.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebChromeClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebChromeClient.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/lib/chrome_safari_example.screen.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/chrome_safari_example.screen.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InputAwareWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InputAwareWebView.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/JavaScriptBridgeInterface.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/JavaScriptBridgeInterface.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/MyCookieManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/MyCookieManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/Util.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/Util.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/android/gradle.properties" beforeDir="false" afterPath="$PROJECT_DIR$/example/android/gradle.properties" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/assets/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/example/assets/index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/Flutter/flutter_export_environment.sh" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Flutter/flutter_export_environment.sh" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/lib/inline_example.screen.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/inline_example.screen.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/example/pubspec.yaml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/Classes/FlutterWebViewController.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/FlutterWebViewController.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/Classes/InAppWebView.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/InAppWebView.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/channel_manager.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/channel_manager.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/cookie_manager.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/cookie_manager.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/http_auth_credentials_database.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/http_auth_credentials_database.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" beforeDir="false" afterPath="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/in_app_browser.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/in_app_browser.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/in_app_webview.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/in_app_webview.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/types.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/types.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/webview_options.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/webview_options.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js" beforeDir="false" afterPath="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/pubspec.yaml" afterDir="false" />
</list>
<ignored path="$PROJECT_DIR$/.dart_tool/" />
<ignored path="$PROJECT_DIR$/.idea/" />
@ -54,17 +72,26 @@
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="405">
<caret line="27" column="92" selection-start-line="27" selection-start-column="92" selection-end-line="27" selection-end-column="92" />
<state relative-caret-position="336">
<caret line="28" column="24" selection-start-line="28" selection-start-column="24" selection-end-line="28" selection-end-column="24" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="true">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="423">
<caret line="49" column="46" selection-start-line="49" selection-start-column="46" selection-end-line="49" selection-end-column="46" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="296">
<caret line="679" column="4" selection-start-line="679" selection-start-column="4" selection-end-line="679" selection-end-column="4" />
<state relative-caret-position="183">
<caret line="114" column="101" selection-start-line="114" selection-start-column="87" selection-end-line="114" selection-end-column="101" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
@ -73,22 +100,40 @@
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/types.dart">
<entry file="file://$PROJECT_DIR$/lib/src/webview_options.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="235">
<caret line="424" column="64" selection-start-line="424" selection-start-column="64" selection-end-line="424" selection-end-column="64" />
<state relative-caret-position="142">
<caret line="57" column="24" selection-start-line="57" selection-start-column="7" selection-end-line="57" selection-end-column="24" />
<folding>
<element signature="e#0#20#0" expanded="true" />
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/example/assets/index.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="888">
<caret line="79" column="11" selection-start-line="79" selection-start-column="11" selection-end-line="79" selection-end-column="11" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-107">
<caret line="8" column="36" selection-start-line="8" selection-start-column="36" selection-end-line="8" selection-end-column="36" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/example/lib/inline_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-60">
<caret line="85" column="43" selection-start-line="85" selection-start-column="43" selection-end-line="85" selection-end-column="43" />
<state relative-caret-position="294">
<caret line="261" column="187" selection-start-line="259" selection-start-column="14" selection-end-line="261" selection-end-column="187" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
@ -108,20 +153,6 @@
</component>
<component name="FindInProjectRecents">
<findStrings>
<find>a</find>
<find>as</find>
<find>IABWebViewClient</find>
<find>clearCache</find>
<find>Auth</find>
<find>onReceivedHttpAuthRequestCallback</find>
<find>Protection</find>
<find>cast</find>
<find>clear</find>
<find>HttpAuthResponse</find>
<find>ClientCertResponse</find>
<find>onReceivedServerTrustAuthRequest</find>
<find>ServerTrustAuthResponse</find>
<find>certific</find>
<find>CER</find>
<find>ServerTrustChallenge</find>
<find>cONTENTMODE</find>
@ -138,6 +169,20 @@
<find>on</find>
<find>findAll</find>
<find>getFave</find>
<find>Uri</find>
<find>!= &quot;an</find>
<find>_channel</find>
<find>getHtml</find>
<find>url</find>
<find>getOptions</find>
<find>gestureR</find>
<find>_dispose</find>
<find>dispose</find>
<find>Long</find>
<find>custom</find>
<find>scheme</find>
<find>useOnLoadResource</find>
<find>useShouldOverrideUrlLoading</find>
</findStrings>
<replaceStrings>
<replace>activity.getPreferences(0)</replace>
@ -175,7 +220,6 @@
<option value="$PROJECT_DIR$/android/gradle/wrapper/gradle-wrapper.properties" />
<option value="$PROJECT_DIR$/example/android/app/build.gradle" />
<option value="$PROJECT_DIR$/example/android/gradle.properties" />
<option value="$PROJECT_DIR$/android/build.gradle" />
<option value="$PROJECT_DIR$/example/android/build.gradle" />
<option value="$PROJECT_DIR$/example/assets/page-3.html" />
<option value="$PROJECT_DIR$/example/assets/page-2.html" />
@ -192,28 +236,29 @@
<option value="$PROJECT_DIR$/example/ios/Runner/Info.plist" />
<option value="$PROJECT_DIR$/example/lib/main.dart" />
<option value="$PROJECT_DIR$/lib/src/content_blocker.dart" />
<option value="$PROJECT_DIR$/example/assets/index.html" />
<option value="$PROJECT_DIR$/example/lib/webview_example.screen.dart" />
<option value="$PROJECT_DIR$/lib/src/credentials_database.dart" />
<option value="$PROJECT_DIR$/lib/flutter_inappbrowser.dart" />
<option value="$PROJECT_DIR$/example/pubspec.yaml" />
<option value="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" />
<option value="$PROJECT_DIR$/pubspec.yaml" />
<option value="$PROJECT_DIR$/lib/src/webview_options.dart" />
<option value="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js" />
<option value="$PROJECT_DIR$/lib/src/channel_manager.dart" />
<option value="$PROJECT_DIR$/lib/src/cookie_manager.dart" />
<option value="$PROJECT_DIR$/lib/src/http_auth_credentials_database.dart" />
<option value="$PROJECT_DIR$/example/lib/chrome_safari_example.screen.dart" />
<option value="$PROJECT_DIR$/lib/src/in_app_browser.dart" />
<option value="$PROJECT_DIR$/CHANGELOG.md" />
<option value="$PROJECT_DIR$/example/lib/inline_example.screen.dart" />
<option value="$PROJECT_DIR$/lib/src/types.dart" />
<option value="$PROJECT_DIR$/CHANGELOG.md" />
<option value="$PROJECT_DIR$/lib/src/in_app_browser.dart" />
<option value="$PROJECT_DIR$/android/build.gradle" />
<option value="$PROJECT_DIR$/example/pubspec.yaml" />
<option value="$PROJECT_DIR$/pubspec.yaml" />
<option value="$PROJECT_DIR$/lib/src/in_app_webview.dart" />
<option value="$PROJECT_DIR$/example/assets/index.html" />
<option value="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js" />
<option value="$PROJECT_DIR$/lib/src/webview_options.dart" />
<option value="$PROJECT_DIR$/example/lib/inline_example.screen.dart" />
</list>
</option>
</component>
<component name="ProjectFrameBounds" extendedState="6">
<component name="ProjectFrameBounds">
<option name="y" value="23" />
<option name="width" value="1920" />
<option name="height" value="1057" />
@ -235,33 +280,6 @@
<select />
</subPane>
</pane>
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="lib" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="lib" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="External Libraries" type="cb654da1:ExternalLibrariesNode" />
</path>
</expand>
<select />
</subPane>
</pane>
<pane id="PackagesPane" />
<pane id="AndroidView">
<subPane>
<expand>
@ -291,6 +309,54 @@
<select />
</subPane>
</pane>
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="android" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" />
<item name="assets" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="lib" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="lib" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="nodejs_server_test_auth_basic_and_ssl" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="External Libraries" type="cb654da1:ExternalLibrariesNode" />
</path>
</expand>
<select />
</subPane>
</pane>
<pane id="PackagesPane" />
</panes>
</component>
<component name="PropertiesComponent">
@ -310,13 +376,6 @@
<property name="show.migrate.to.gradle.popup" value="false" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/example/assets" />
<recent name="$PROJECT_DIR$" />
<recent name="$PROJECT_DIR$/example" />
<recent name="$PROJECT_DIR$/example/assets/images" />
<recent name="$PROJECT_DIR$/android/libs" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/example/assets" />
<recent name="$PROJECT_DIR$/lib/src" />
@ -324,6 +383,13 @@
<recent name="$PROJECT_DIR$/lib" />
<recent name="$PROJECT_DIR$/example/assets/images" />
</key>
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/example/assets" />
<recent name="$PROJECT_DIR$" />
<recent name="$PROJECT_DIR$/example" />
<recent name="$PROJECT_DIR$/example/assets/images" />
<recent name="$PROJECT_DIR$/android/libs" />
</key>
</component>
<component name="RunDashboard">
<option name="ruleStates">
@ -442,10 +508,9 @@
</component>
<component name="ToolWindowManager">
<frame x="0" y="23" width="1920" height="1057" extended-state="6" />
<editor active="true" />
<layout>
<window_info content_ui="combo" id="Project" order="0" sideWeight="0.59067357" visible="true" weight="0.15867944" />
<window_info id="Structure" order="1" sideWeight="0.40932643" side_tool="true" weight="0.15867944" />
<window_info content_ui="combo" id="Project" order="0" sideWeight="0.58835757" visible="true" weight="0.15867944" />
<window_info id="Structure" order="1" sideWeight="0.4116424" side_tool="true" visible="true" weight="0.15867944" />
<window_info id="Designer" order="2" />
<window_info id="Build Variants" order="3" side_tool="true" />
<window_info id="Captures" order="4" side_tool="true" weight="0.32936507" />
@ -455,7 +520,7 @@
<window_info id="Resources Explorer" order="8" />
<window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Find" order="1" weight="0.32642487" />
<window_info active="true" anchor="bottom" id="Run" order="2" sideWeight="0.49307775" visible="true" weight="0.3253886" />
<window_info active="true" anchor="bottom" id="Run" order="2" sideWeight="0.49307775" visible="true" weight="0.5015544" />
<window_info anchor="bottom" id="Debug" order="3" weight="0.34196892" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
@ -491,29 +556,6 @@
</ignored-roots>
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/example/assets/page-3.html" />
<entry file="file://$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib/convert/json.dart" />
<entry file="file://$PROJECT_DIR$/example/assets/page-2.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="162">
<caret line="15" column="63" selection-start-line="15" selection-start-column="63" selection-end-line="15" selection-end-column="63" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/assets/page-1.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="104">
<caret line="15" column="63" selection-start-line="15" selection-start-column="63" selection-end-line="15" selection-end-column="63" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="256">
<caret line="25" column="1" lean-forward="true" selection-start-line="25" selection-start-column="1" selection-end-line="25" selection-end-column="1" />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/flutter/packages/flutter/lib/src/widgets/platform_view.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-182">
@ -688,27 +730,6 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="210">
<caret line="14" column="16" selection-start-line="14" selection-start-column="16" selection-end-line="14" selection-end-column="16" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="315">
<caret line="21" column="28" selection-start-line="21" selection-start-column="28" selection-end-line="22" selection-end-column="23" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="225">
<caret line="15" column="2" lean-forward="true" selection-start-line="15" selection-start-column="2" selection-end-line="15" selection-end-column="2" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/.gitignore">
<provider selected="true" editor-type-id="text-editor" />
</entry>
@ -722,13 +743,6 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/assets/index.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="330">
<caret line="22" column="17" selection-start-line="22" selection-start-column="17" selection-end-line="22" selection-end-column="17" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/webview_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="302">
@ -785,30 +799,10 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/webview_options.dart">
<entry file="file://$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib/core/uri.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="198">
<caret line="168" column="6" selection-start-line="168" selection-start-column="6" selection-end-line="168" selection-end-column="6" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/in_app_browser.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="401">
<caret line="426" column="51" selection-start-line="426" selection-start-column="51" selection-end-line="426" selection-end-column="51" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="405">
<caret line="27" column="92" selection-start-line="27" selection-start-column="92" selection-end-line="27" selection-end-column="92" />
<state relative-caret-position="15">
<caret line="37" column="15" selection-start-line="37" selection-start-column="15" selection-end-line="37" selection-end-column="15" />
</state>
</provider>
</entry>
@ -822,26 +816,97 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/inline_example.screen.dart">
<entry file="file://$PROJECT_DIR$/lib/src/in_app_browser.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-60">
<caret line="85" column="43" selection-start-line="85" selection-start-column="43" selection-end-line="85" selection-end-column="43" />
<state relative-caret-position="76">
<caret line="268" column="65" selection-start-line="268" selection-start-column="65" selection-end-line="268" selection-end-column="65" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart">
<entry file="file://$PROJECT_DIR$/example/android/gradle.properties">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/android/local.properties">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/android/gradle.properties">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="296">
<caret line="679" column="4" selection-start-line="679" selection-start-column="4" selection-end-line="679" selection-end-column="4" />
<state relative-caret-position="141">
<caret line="12" column="32" selection-start-line="12" selection-start-column="32" selection-end-line="12" selection-end-column="32" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-107">
<caret line="8" column="36" selection-start-line="8" selection-start-column="36" selection-end-line="8" selection-end-column="36" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="256">
<caret line="25" selection-start-line="25" selection-end-line="25" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="336">
<caret line="28" column="24" selection-start-line="28" selection-start-column="24" selection-end-line="28" selection-end-column="24" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/assets/index.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="888">
<caret line="79" column="11" selection-start-line="79" selection-start-column="11" selection-end-line="79" selection-end-column="11" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="423">
<caret line="49" column="46" selection-start-line="49" selection-start-column="46" selection-end-line="49" selection-end-column="46" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/webview_options.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="142">
<caret line="57" column="24" selection-start-line="57" selection-start-column="7" selection-end-line="57" selection-end-column="24" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="183">
<caret line="114" column="101" selection-start-line="114" selection-start-column="87" selection-end-line="114" selection-end-column="101" />
<folding>
<element signature="e#0#17#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/inline_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="294">
<caret line="261" column="187" selection-start-line="259" selection-start-column="14" selection-end-line="261" selection-end-column="187" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</component>
<component name="masterDetails">
<states>

View File

@ -26,6 +26,7 @@
- Added `HttpAuthCredentialDatabase` class
- Added `onReceivedServerTrustAuthRequest` and `onReceivedClientCertRequest` events to manage SSL requests
- Added `onFindResultReceived` event, `findAllAsync`, `findNext` and `clearMatches` methods
- Added `getHtml` method
### BREAKING CHANGES
- Deleted `WebResourceRequest` class
@ -34,6 +35,7 @@
- Updated `onLoadResource` event
- Updated `CookieManager` class
- WebView options are now available with the new corresponding classes: `InAppWebViewOptions`, `AndroidInAppWebViewOptions`, `iOSInAppWebViewOptions`, `InAppBrowserOptions`, `AndroidInAppBrowserOptions`, `iOSInAppBrowserOptions`, `AndroidChromeCustomTabsOptions` and `iOSSafariOptions`
- Renamed `getFavicon` to `getFavicons`, now it returns a list of all favicons (`List<Favicon>`) found
## 1.2.1

View File

@ -33,11 +33,34 @@ android {
lintOptions {
disable 'InvalidPackage'
}
dependencies {
implementation 'androidx.webkit:webkit:1.0.0'
implementation 'androidx.browser:browser:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'com.squareup.okhttp3:mockwebserver:3.11.0'
}
}
dependencies {
implementation 'androidx.webkit:webkit:1.0.0'
implementation 'androidx.browser:browser:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'com.squareup.okhttp3:mockwebserver:3.11.0'
}
afterEvaluate {
def containsEmbeddingDependencies = false
for (def configuration : configurations.all) {
for (def dependency : configuration.dependencies) {
if (dependency.group == 'io.flutter' &&
dependency.name.startsWith('flutter_embedding') &&
dependency.isTransitive())
{
containsEmbeddingDependencies = true
break
}
}
}
if (!containsEmbeddingDependencies) {
android {
dependencies {
def lifecycle_version = "1.1.1"
compileOnly "android.arch.lifecycle:common-java8:$lifecycle_version"
compileOnly "android.arch.lifecycle:runtime:$lifecycle_version"
}
}
}
}

View File

@ -1,3 +0,0 @@
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M

View File

@ -1,9 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pichillilorenzo.flutter_inappbrowser">
<uses-permission android:name="android.permission.INTERNET" />
<application>
<activity android:theme="@style/AppTheme" android:name=".InAppBrowserActivity" android:configChanges="orientation|screenSize"></activity>
<activity android:theme="@style/ThemeTransparent" android:name=".ChromeCustomTabs.ChromeCustomTabsActivity" android:configChanges="orientation|screenSize"></activity>

View File

@ -36,7 +36,7 @@ public class ChromeCustomTabsActivity extends Activity {
options = new ChromeCustomTabsOptions();
options.parse((HashMap<String, Object>) b.getSerializable("options"));
InAppBrowserFlutterPlugin.instance.chromeCustomTabsActivities.put(uuid, this);
InAppBrowserFlutterPlugin.inAppBrowser.chromeCustomTabsActivities.put(uuid, this);
customTabActivityHelper = new CustomTabActivityHelper();
builder = new CustomTabsIntent.Builder();
@ -49,8 +49,8 @@ public class ChromeCustomTabsActivity extends Activity {
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid);
InAppBrowserFlutterPlugin.instance.channel.invokeMethod("onChromeSafariBrowserOpened", obj);
InAppBrowserFlutterPlugin.instance.channel.invokeMethod("onChromeSafariBrowserLoaded", obj);
InAppBrowserFlutterPlugin.inAppBrowser.channel.invokeMethod("onChromeSafariBrowserOpened", obj);
InAppBrowserFlutterPlugin.inAppBrowser.channel.invokeMethod("onChromeSafariBrowserLoaded", obj);
}
private void prepareCustomTabs() {
@ -86,7 +86,7 @@ public class ChromeCustomTabsActivity extends Activity {
finish();
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid);
InAppBrowserFlutterPlugin.instance.channel.invokeMethod("onChromeSafariBrowserClosed", obj);
InAppBrowserFlutterPlugin.inAppBrowser.channel.invokeMethod("onChromeSafariBrowserClosed", obj);
}
}

View File

@ -7,18 +7,16 @@ import android.util.Log;
import android.webkit.WebResourceResponse;
import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebView;
import com.pichillilorenzo.flutter_inappbrowser.Util;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.regex.Matcher;
@ -163,8 +161,7 @@ public class ContentBlockerHandler {
Response response = null;
try {
response = webView.httpClient.newCall(mRequest).execute();
response = Util.getUnsafeOkHttpClient().newCall(mRequest).execute();
byte[] dataBytes = response.body().bytes();
InputStream dataStream = new ByteArrayInputStream(dataBytes);
@ -195,7 +192,7 @@ public class ContentBlockerHandler {
}
public WebResourceResponse checkUrl(final InAppWebView webView, String url) throws URISyntaxException, InterruptedException, MalformedURLException {
ContentBlockerTriggerResourceType responseResourceType = getResourceTypeFromUrl(webView, url);
ContentBlockerTriggerResourceType responseResourceType = getResourceTypeFromUrl(url);
return checkUrl(webView, url, responseResourceType);
}
@ -204,7 +201,7 @@ public class ContentBlockerHandler {
return checkUrl(webView, url, responseResourceType);
}
public ContentBlockerTriggerResourceType getResourceTypeFromUrl(InAppWebView webView, String url) {
public ContentBlockerTriggerResourceType getResourceTypeFromUrl(String url) {
ContentBlockerTriggerResourceType responseResourceType = ContentBlockerTriggerResourceType.RAW;
if (url.startsWith("http://") || url.startsWith("https://")) {
@ -212,7 +209,7 @@ public class ContentBlockerHandler {
Request mRequest = new Request.Builder().url(url).head().build();
Response response = null;
try {
response = webView.httpClient.newCall(mRequest).execute();
response = Util.getUnsafeOkHttpClient().newCall(mRequest).execute();
if (response.header("content-type") != null) {
String[] contentTypeSplitted = response.header("content-type").split(";");

View File

@ -116,4 +116,8 @@ public class CredentialDatabaseHandler implements MethodChannel.MethodCallHandle
}
}
public void dispose() {
channel.setMethodCallHandler(null);
}
}

View File

@ -289,10 +289,6 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
result.success(false);
}
break;
case "dispose":
dispose();
result.success(true);
break;
default:
result.notImplemented();
}
@ -300,10 +296,12 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
@Override
public void dispose() {
channel.setMethodCallHandler(null);
if (webView != null) {
webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
webView.dispose();
webView.destroy();
webView = null;
}
@ -324,4 +322,12 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
webView.unlockInputConnection();
}
public void onFlutterViewAttached(View flutterView) {
webView.setContainerView(flutterView);
}
public void onFlutterViewDetached() {
webView.setContainerView(null);
}
}

View File

@ -0,0 +1,739 @@
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package com.pichillilorenzo.flutter_inappbrowser;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Parcelable;
import android.provider.Browser;
import android.net.Uri;
import android.os.Bundle;
import android.webkit.MimeTypeMap;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.util.Log;
import com.pichillilorenzo.flutter_inappbrowser.ChromeCustomTabs.ChromeCustomTabsActivity;
import com.pichillilorenzo.flutter_inappbrowser.ChromeCustomTabs.CustomTabActivityHelper;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
/**
* InAppBrowser
*/
public class InAppBrowser implements MethodChannel.MethodCallHandler {
public Registrar registrar;
public MethodChannel channel;
public Map<String, InAppBrowserActivity> webViewActivities = new HashMap<>();
public Map<String, ChromeCustomTabsActivity> chromeCustomTabsActivities = new HashMap<>();
protected static final String LOG_TAG = "IABFlutterPlugin";
public InAppBrowser(Registrar r) {
registrar = r;
channel = new MethodChannel(registrar.messenger(), "com.pichillilorenzo/flutter_inappbrowser");
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(final MethodCall call, final Result result) {
String source;
String urlFile;
final Activity activity = registrar.activity();
final String uuid = (String) call.argument("uuid");
switch (call.method) {
case "open":
boolean isData = (boolean) call.argument("isData");
if (!isData) {
final String url_final = (String) call.argument("url");
final boolean useChromeSafariBrowser = (boolean) call.argument("useChromeSafariBrowser");
final Map<String, String> headers = (Map<String, String>) call.argument("headers");
Log.d(LOG_TAG, "use Chrome Custom Tabs = " + useChromeSafariBrowser);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (useChromeSafariBrowser) {
final String uuidFallback = (String) call.argument("uuidFallback");
final HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
final HashMap<String, Object> optionsFallback = (HashMap<String, Object>) call.argument("optionsFallback");
open(activity, uuid, uuidFallback, url_final, options, headers, true, optionsFallback, result);
} else {
String url = url_final;
final HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
final boolean isLocalFile = (boolean) call.argument("isLocalFile");
final boolean openWithSystemBrowser = (boolean) call.argument("openWithSystemBrowser");
if (isLocalFile) {
// check if the asset file exists
try {
url = Util.getUrlAsset(registrar, url);
} catch (IOException e) {
e.printStackTrace();
result.error(LOG_TAG, url + " asset file cannot be found!", e);
return;
}
}
// SYSTEM
if (openWithSystemBrowser) {
Log.d(LOG_TAG, "in system");
openExternal(activity, url, result);
} else {
//Load the dialer
if (url.startsWith(WebView.SCHEME_TEL)) {
try {
Log.d(LOG_TAG, "loading in dialer");
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url));
activity.startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
}
}
// load in InAppBrowser
else {
Log.d(LOG_TAG, "loading in InAppBrowser");
open(activity, uuid, null, url, options, headers, false, null, result);
}
}
}
}
});
}
else {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
String data = (String) call.argument("data");
String mimeType = (String) call.argument("mimeType");
String encoding = (String) call.argument("encoding");
String baseUrl = (String) call.argument("baseUrl");
openData(activity, uuid, options, data, mimeType, encoding, baseUrl);
result.success(true);
}
});
}
break;
case "getUrl":
result.success(getUrl(uuid));
break;
case "getTitle":
result.success(getTitle(uuid));
break;
case "getProgress":
result.success(getProgress(uuid));
break;
case "loadUrl":
loadUrl(uuid, (String) call.argument("url"), (Map<String, String>) call.argument("headers"), result);
break;
case "postUrl":
postUrl(uuid, (String) call.argument("url"), (byte[]) call.argument("postData"), result);
break;
case "loadData":
{
String data = (String) call.argument("data");
String mimeType = (String) call.argument("mimeType");
String encoding = (String) call.argument("encoding");
String baseUrl = (String) call.argument("baseUrl");
loadData(uuid, data, mimeType, encoding, baseUrl, result);
}
break;
case "loadFile":
loadFile(uuid, (String) call.argument("url"), (Map<String, String>) call.argument("headers"), result);
break;
case "close":
close(activity, uuid, result);
break;
case "injectScriptCode":
source = (String) call.argument("source");
injectScriptCode(uuid, source, result);
break;
case "injectScriptFile":
urlFile = (String) call.argument("urlFile");
injectScriptFile(uuid, urlFile);
result.success(true);
break;
case "injectStyleCode":
source = (String) call.argument("source");
injectStyleCode(uuid, source);
result.success(true);
break;
case "injectStyleFile":
urlFile = (String) call.argument("urlFile");
injectStyleFile(uuid, urlFile);
result.success(true);
break;
case "show":
show(uuid);
result.success(true);
break;
case "hide":
hide(uuid);
result.success(true);
break;
case "reload":
reload(uuid);
result.success(true);
break;
case "goBack":
goBack(uuid);
result.success(true);
break;
case "canGoBack":
result.success(canGoBack(uuid));
break;
case "goForward":
goForward(uuid);
result.success(true);
break;
case "canGoForward":
result.success(canGoForward(uuid));
break;
case "goBackOrForward":
goBackOrForward(uuid, (Integer) call.argument("steps"));
result.success(true);
break;
case "canGoBackOrForward":
result.success(canGoBackOrForward(uuid, (Integer) call.argument("steps")));
break;
case "stopLoading":
stopLoading(uuid);
result.success(true);
break;
case "isLoading":
result.success(isLoading(uuid));
break;
case "isHidden":
result.success(isHidden(uuid));
break;
case "takeScreenshot":
result.success(takeScreenshot(uuid));
break;
case "setOptions":
{
String optionsType = (String) call.argument("optionsType");
switch (optionsType){
case "InAppBrowserOptions":
InAppBrowserOptions inAppBrowserOptions = new InAppBrowserOptions();
HashMap<String, Object> inAppBrowserOptionsMap = (HashMap<String, Object>) call.argument("options");
inAppBrowserOptions.parse(inAppBrowserOptionsMap);
setOptions(uuid, inAppBrowserOptions, inAppBrowserOptionsMap);
break;
default:
result.error(LOG_TAG, "Options " + optionsType + " not available.", null);
}
}
result.success(true);
break;
case "getOptions":
result.success(getOptions(uuid));
break;
case "getCopyBackForwardList":
result.success(getCopyBackForwardList(uuid));
break;
case "startSafeBrowsing":
startSafeBrowsing(uuid, result);
break;
case "setSafeBrowsingWhitelist":
setSafeBrowsingWhitelist(uuid, (List<String>) call.argument("hosts"), result);
break;
case "clearCache":
clearCache(uuid);
result.success(true);
break;
case "clearSslPreferences":
clearSslPreferences(uuid);
result.success(true);
break;
case "clearClientCertPreferences":
clearClientCertPreferences(uuid, result);
break;
case "findAllAsync":
String find = (String) call.argument("find");
findAllAsync(uuid, find);
result.success(true);
break;
case "findNext":
Boolean forward = (Boolean) call.argument("forward");
findNext(uuid, forward, result);
break;
case "clearMatches":
clearMatches(uuid, result);
break;
default:
result.notImplemented();
}
}
private void injectScriptCode(String uuid, String source, final Result result) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectScriptCode(source, result);
} else {
Log.d(LOG_TAG, "webView is null");
}
}
private void injectScriptFile(String uuid, String urlFile) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectScriptFile(urlFile);
}
}
private void injectStyleCode(String uuid, String source) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectStyleCode(source);
}
}
private void injectStyleFile(String uuid, String urlFile) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectStyleFile(urlFile);
}
}
public static String getMimeType(String url) {
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
return type;
}
/**
* Display a new browser with the specified URL.
*
* @param url the url to load.
* @param result
* @return "" if ok, or error message.
*/
public void openExternal(Activity activity, String url, Result result) {
try {
Intent intent;
intent = new Intent(Intent.ACTION_VIEW);
// Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
// Adding the MIME type to http: URLs causes them to not be handled by the downloader.
Uri uri = Uri.parse(url);
if ("file".equals(uri.getScheme())) {
intent.setDataAndType(uri, getMimeType(url));
} else {
intent.setData(uri);
}
intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName());
// CB-10795: Avoid circular loops by preventing it from opening in the current app
this.openExternalExcludeCurrentApp(activity, intent);
result.success(true);
// not catching FileUriExposedException explicitly because buildtools<24 doesn't know about it
} catch (java.lang.RuntimeException e) {
Log.d(LOG_TAG, url + " cannot be opened: " + e.toString());
result.error(LOG_TAG, url + " cannot be opened!", null);
}
}
/**
* Opens the intent, providing a chooser that excludes the current app to avoid
* circular loops.
*/
private void openExternalExcludeCurrentApp(Activity activity, Intent intent) {
String currentPackage = activity.getPackageName();
boolean hasCurrentPackage = false;
PackageManager pm = activity.getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
ArrayList<Intent> targetIntents = new ArrayList<Intent>();
for (ResolveInfo ri : activities) {
if (!currentPackage.equals(ri.activityInfo.packageName)) {
Intent targetIntent = (Intent) intent.clone();
targetIntent.setPackage(ri.activityInfo.packageName);
targetIntents.add(targetIntent);
} else {
hasCurrentPackage = true;
}
}
// If the current app package isn't a target for this URL, then use
// the normal launch behavior
if (!hasCurrentPackage || targetIntents.size() == 0) {
activity.startActivity(intent);
}
// If there's only one possible intent, launch it directly
else if (targetIntents.size() == 1) {
activity.startActivity(targetIntents.get(0));
}
// Otherwise, show a custom chooser without the current app listed
else if (targetIntents.size() > 0) {
Intent chooser = Intent.createChooser(targetIntents.remove(targetIntents.size() - 1), null);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{}));
activity.startActivity(chooser);
}
}
public void open(Activity activity, String uuid, String uuidFallback, String url, HashMap<String, Object> options, Map<String, String> headers, boolean useChromeSafariBrowser, HashMap<String, Object> optionsFallback, Result result) {
Intent intent = null;
Bundle extras = new Bundle();
extras.putString("fromActivity", activity.getClass().getName());
extras.putString("url", url);
extras.putBoolean("isData", false);
extras.putString("uuid", uuid);
extras.putSerializable("options", options);
extras.putSerializable("headers", (Serializable) headers);
if (useChromeSafariBrowser && CustomTabActivityHelper.isAvailable(activity)) {
intent = new Intent(activity, ChromeCustomTabsActivity.class);
}
// check for webview fallback
else if (useChromeSafariBrowser && !CustomTabActivityHelper.isAvailable(activity) && !uuidFallback.isEmpty()) {
Log.d(LOG_TAG, "WebView fallback declared.");
// overwrite with extras fallback parameters
extras.putString("uuid", uuidFallback);
if (optionsFallback != null)
extras.putSerializable("options", optionsFallback);
else
extras.putSerializable("options", (new InAppBrowserOptions()).getHashMap());
extras.putSerializable("headers", (Serializable) headers);
intent = new Intent(activity, InAppBrowserActivity.class);
}
// native webview
else if (!useChromeSafariBrowser) {
intent = new Intent(activity, InAppBrowserActivity.class);
}
else {
Log.d(LOG_TAG, "No WebView fallback declared.");
}
if (intent != null) {
intent.putExtras(extras);
activity.startActivity(intent);
result.success(true);
return;
}
result.error(LOG_TAG, "No WebView fallback declared.", null);
}
public void openData(Activity activity, String uuid, HashMap<String, Object> options, String data, String mimeType, String encoding, String baseUrl) {
Intent intent = new Intent(activity, InAppBrowserActivity.class);
Bundle extras = new Bundle();
extras.putBoolean("isData", true);
extras.putString("uuid", uuid);
extras.putSerializable("options", options);
extras.putString("data", data);
extras.putString("mimeType", mimeType);
extras.putString("encoding", encoding);
extras.putString("baseUrl", baseUrl);
intent.putExtras(extras);
activity.startActivity(intent);
}
private String getUrl(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getUrl();
return null;
}
private String getTitle(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getWebViewTitle();
return null;
}
private Integer getProgress(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getProgress();
return null;
}
public void loadUrl(String uuid, String url, Map<String, String> headers, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
if (headers != null)
inAppBrowserActivity.loadUrl(url, headers, result);
else
inAppBrowserActivity.loadUrl(url, result);
}
}
public void postUrl(String uuid, String url, byte[] postData, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.postUrl(url, postData, result);
}
public void loadData(String uuid, String data, String mimeType, String encoding, String baseUrl, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.loadData(data, mimeType, encoding, baseUrl, result);
}
public void loadFile(String uuid, String url, Map<String, String> headers, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
if (headers != null)
inAppBrowserActivity.loadFile(url, headers, result);
else
inAppBrowserActivity.loadFile(url, result);
}
}
public void show(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.show();
}
public void hide(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.hide();
}
public void reload(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.reload();
}
public boolean isLoading(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.isLoading();
return false;
}
public boolean isHidden(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.isHidden;
return false;
}
public void stopLoading(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.stopLoading();
}
public void goBack(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.goBack();
}
public boolean canGoBack(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.canGoBack();
return false;
}
public void goForward(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.goForward();
}
public boolean canGoForward(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.canGoForward();
return false;
}
public void goBackOrForward(String uuid, int steps) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.goBackOrForward(steps);
}
public boolean canGoBackOrForward(String uuid, int steps) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.canGoBackOrForward(steps);
return false;
}
public void close(Activity activity, final String uuid, final Result result) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid);
channel.invokeMethod("onExit", obj);
// The JS protects against multiple calls, so this should happen only when
// close() is called by other native code.
if (inAppBrowserActivity == null) {
if (result != null) {
result.success(true);
}
return;
}
inAppBrowserActivity.webView.setWebViewClient(new WebViewClient() {
// NB: wait for about:blank before dismissing
public void onPageFinished(WebView view, String url) {
inAppBrowserActivity.close();
}
});
// NB: From SDK 19: "If you call methods on WebView from any thread
// other than your app's UI thread, it can cause unexpected results."
// http://developer.android.com/guide/webapps/migrating.html#Threads
inAppBrowserActivity.webView.loadUrl("about:blank");
if (result != null) {
result.success(true);
}
}
});
}
else if (result != null) {
result.success(true);
}
}
public byte[] takeScreenshot(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.takeScreenshot();
return null;
}
public void setOptions(String uuid, InAppBrowserOptions options, HashMap<String, Object> optionsMap) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.setOptions(options, optionsMap);
}
public HashMap<String, Object> getOptions(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getOptions();
return null;
}
public HashMap<String, Object> getCopyBackForwardList(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getCopyBackForwardList();
return null;
}
public void startSafeBrowsing(String uuid, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.startSafeBrowsing(result);
result.success(false);
}
public void setSafeBrowsingWhitelist(String uuid, List<String> hosts, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.setSafeBrowsingWhitelist(hosts, result);
result.success(false);
}
public void clearCache(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearCache();
}
public void clearSslPreferences(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearSslPreferences();
}
public void clearClientCertPreferences(String uuid, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearClientCertPreferences(result);
result.success(false);
}
public void findAllAsync(String uuid, String find) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.findAllAsync(find);
}
public void findNext(String uuid, Boolean forward, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.findNext(forward, result);
result.success(false);
}
public void clearMatches(String uuid, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearMatches(result);
result.success(false);
}
public void dispose() {
channel.setMethodCallHandler(null);
for ( InAppBrowserActivity activity : webViewActivities.values()) {
activity.dispose();
}
}
}

View File

@ -1,6 +1,5 @@
package com.pichillilorenzo.flutter_inappbrowser;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@ -18,6 +17,9 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.SearchView;
@ -26,13 +28,10 @@ import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebViewOptions
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.app.FlutterActivity;
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.MethodChannel;
public class InAppBrowserActivity extends AppCompatActivity {
@ -71,7 +70,7 @@ public class InAppBrowserActivity extends AppCompatActivity {
webViewOptions.parse(optionsMap);
webView.options = webViewOptions;
InAppBrowserFlutterPlugin.instance.webViewActivities.put(uuid, this);
InAppBrowserFlutterPlugin.inAppBrowser.webViewActivities.put(uuid, this);
actionBar = getSupportActionBar();
@ -93,7 +92,7 @@ public class InAppBrowserActivity extends AppCompatActivity {
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid);
InAppBrowserFlutterPlugin.instance.channel.invokeMethod("onBrowserCreated", obj);
InAppBrowserFlutterPlugin.inAppBrowser.channel.invokeMethod("onBrowserCreated", obj);
}
@ -257,7 +256,7 @@ public class InAppBrowserActivity extends AppCompatActivity {
if (canGoBack())
goBack();
else if (options.closeOnCannotGoBack)
InAppBrowserFlutterPlugin.instance.close(this, uuid, null);
InAppBrowserFlutterPlugin.inAppBrowser.close(this, uuid, null);
return true;
}
return super.onKeyDown(keyCode, event);
@ -356,7 +355,7 @@ public class InAppBrowserActivity extends AppCompatActivity {
}
public void closeButtonClicked(MenuItem item) {
InAppBrowserFlutterPlugin.instance.close(this, uuid, null);
InAppBrowserFlutterPlugin.inAppBrowser.close(this, uuid, null);
}
public byte[] takeScreenshot() {
@ -522,4 +521,18 @@ public class InAppBrowserActivity extends AppCompatActivity {
else
result.success(false);
}
public void dispose() {
if (webView != null) {
webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
webView.dispose();
webView.destroy();
webView = null;
}
});
webView.loadUrl("about:blank");
}
}
}

View File

@ -1,754 +1,65 @@
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package com.pichillilorenzo.flutter_inappbrowser;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Parcelable;
import android.provider.Browser;
import android.net.Uri;
import android.os.Bundle;
import android.webkit.MimeTypeMap;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.util.Log;
import com.pichillilorenzo.flutter_inappbrowser.ChromeCustomTabs.ChromeCustomTabsActivity;
import com.pichillilorenzo.flutter_inappbrowser.ChromeCustomTabs.CustomTabActivityHelper;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
/**
* InAppBrowserFlutterPlugin
*/
public class InAppBrowserFlutterPlugin implements MethodCallHandler {
public static InAppBrowserFlutterPlugin instance;
public Registrar registrar;
public class InAppBrowserFlutterPlugin implements FlutterPlugin {
public PluginRegistry.Registrar registrar;
public MethodChannel channel;
public Map<String, InAppBrowserActivity> webViewActivities = new HashMap<>();
public Map<String, ChromeCustomTabsActivity> chromeCustomTabsActivities = new HashMap<>();
protected static final String LOG_TAG = "IABFlutterPlugin";
protected static final String LOG_TAG = "InAppBrowserFlutterPlugin";
public InAppBrowserFlutterPlugin(Registrar r) {
registrar = r;
channel = new MethodChannel(registrar.messenger(), "com.pichillilorenzo/flutter_inappbrowser");
channel.setMethodCallHandler(this);
}
public static InAppBrowser inAppBrowser;
public static MyCookieManager myCookieManager;
public static CredentialDatabaseHandler credentialDatabaseHandler;
/**
* Plugin registration.
*/
public static void registerWith(Registrar registrar) {
Activity activity = registrar.activity();
// registrar.activity() may return null because of Flutter's background execution feature
// described here: https://medium.com/flutter-io/executing-dart-in-the-background-with-flutter-plugins-and-geofencing-2b3e40a1a124
if (activity != null) {
instance = new InAppBrowserFlutterPlugin(registrar);
public InAppBrowserFlutterPlugin() {}
new MyCookieManager(registrar);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
new CredentialDatabaseHandler(registrar);
}
public static void registerWith(PluginRegistry.Registrar registrar) {
inAppBrowser = new InAppBrowser(registrar);
registrar
.platformViewRegistry()
.registerViewFactory(
"com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(registrar, registrar.view()));
registrar
.platformViewRegistry()
.registerViewFactory(
"com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(registrar, registrar.view()));
new MyCookieManager(registrar);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
new CredentialDatabaseHandler(registrar);
}
}
@Override
public void onMethodCall(final MethodCall call, final Result result) {
String source;
String urlFile;
final Activity activity = registrar.activity();
final String uuid = (String) call.argument("uuid");
switch (call.method) {
case "open":
boolean isData = (boolean) call.argument("isData");
if (!isData) {
final String url_final = (String) call.argument("url");
final boolean useChromeSafariBrowser = (boolean) call.argument("useChromeSafariBrowser");
final Map<String, String> headers = (Map<String, String>) call.argument("headers");
Log.d(LOG_TAG, "use Chrome Custom Tabs = " + useChromeSafariBrowser);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (useChromeSafariBrowser) {
final String uuidFallback = (String) call.argument("uuidFallback");
final HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
final HashMap<String, Object> optionsFallback = (HashMap<String, Object>) call.argument("optionsFallback");
open(activity, uuid, uuidFallback, url_final, options, headers, true, optionsFallback, result);
} else {
String url = url_final;
final HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
final boolean isLocalFile = (boolean) call.argument("isLocalFile");
final boolean openWithSystemBrowser = (boolean) call.argument("openWithSystemBrowser");
if (isLocalFile) {
// check if the asset file exists
try {
url = Util.getUrlAsset(registrar, url);
} catch (IOException e) {
e.printStackTrace();
result.error(LOG_TAG, url + " asset file cannot be found!", e);
return;
}
}
// SYSTEM
if (openWithSystemBrowser) {
Log.d(LOG_TAG, "in system");
openExternal(activity, url, result);
} else {
//Load the dialer
if (url.startsWith(WebView.SCHEME_TEL)) {
try {
Log.d(LOG_TAG, "loading in dialer");
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url));
activity.startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
}
}
// load in InAppBrowserFlutterPlugin
else {
Log.d(LOG_TAG, "loading in InAppBrowserFlutterPlugin");
open(activity, uuid, null, url, options, headers, false, null, result);
}
}
}
}
});
}
else {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
String data = (String) call.argument("data");
String mimeType = (String) call.argument("mimeType");
String encoding = (String) call.argument("encoding");
String baseUrl = (String) call.argument("baseUrl");
openData(activity, uuid, options, data, mimeType, encoding, baseUrl);
result.success(true);
}
});
}
break;
case "getUrl":
result.success(getUrl(uuid));
break;
case "getTitle":
result.success(getTitle(uuid));
break;
case "getProgress":
result.success(getProgress(uuid));
break;
case "loadUrl":
loadUrl(uuid, (String) call.argument("url"), (Map<String, String>) call.argument("headers"), result);
break;
case "postUrl":
postUrl(uuid, (String) call.argument("url"), (byte[]) call.argument("postData"), result);
break;
case "loadData":
{
String data = (String) call.argument("data");
String mimeType = (String) call.argument("mimeType");
String encoding = (String) call.argument("encoding");
String baseUrl = (String) call.argument("baseUrl");
loadData(uuid, data, mimeType, encoding, baseUrl, result);
}
break;
case "loadFile":
loadFile(uuid, (String) call.argument("url"), (Map<String, String>) call.argument("headers"), result);
break;
case "close":
close(activity, uuid, result);
break;
case "injectScriptCode":
source = (String) call.argument("source");
injectScriptCode(uuid, source, result);
break;
case "injectScriptFile":
urlFile = (String) call.argument("urlFile");
injectScriptFile(uuid, urlFile);
result.success(true);
break;
case "injectStyleCode":
source = (String) call.argument("source");
injectStyleCode(uuid, source);
result.success(true);
break;
case "injectStyleFile":
urlFile = (String) call.argument("urlFile");
injectStyleFile(uuid, urlFile);
result.success(true);
break;
case "show":
show(uuid);
result.success(true);
break;
case "hide":
hide(uuid);
result.success(true);
break;
case "reload":
reload(uuid);
result.success(true);
break;
case "goBack":
goBack(uuid);
result.success(true);
break;
case "canGoBack":
result.success(canGoBack(uuid));
break;
case "goForward":
goForward(uuid);
result.success(true);
break;
case "canGoForward":
result.success(canGoForward(uuid));
break;
case "goBackOrForward":
goBackOrForward(uuid, (Integer) call.argument("steps"));
result.success(true);
break;
case "canGoBackOrForward":
result.success(canGoBackOrForward(uuid, (Integer) call.argument("steps")));
break;
case "stopLoading":
stopLoading(uuid);
result.success(true);
break;
case "isLoading":
result.success(isLoading(uuid));
break;
case "isHidden":
result.success(isHidden(uuid));
break;
case "takeScreenshot":
result.success(takeScreenshot(uuid));
break;
case "setOptions":
{
String optionsType = (String) call.argument("optionsType");
switch (optionsType){
case "InAppBrowserOptions":
InAppBrowserOptions inAppBrowserOptions = new InAppBrowserOptions();
HashMap<String, Object> inAppBrowserOptionsMap = (HashMap<String, Object>) call.argument("options");
inAppBrowserOptions.parse(inAppBrowserOptionsMap);
setOptions(uuid, inAppBrowserOptions, inAppBrowserOptionsMap);
break;
default:
result.error(LOG_TAG, "Options " + optionsType + " not available.", null);
}
}
result.success(true);
break;
case "getOptions":
result.success(getOptions(uuid));
break;
case "getCopyBackForwardList":
result.success(getCopyBackForwardList(uuid));
break;
case "startSafeBrowsing":
startSafeBrowsing(uuid, result);
break;
case "setSafeBrowsingWhitelist":
setSafeBrowsingWhitelist(uuid, (List<String>) call.argument("hosts"), result);
break;
case "clearCache":
clearCache(uuid);
result.success(true);
break;
case "clearSslPreferences":
clearSslPreferences(uuid);
result.success(true);
break;
case "clearClientCertPreferences":
clearClientCertPreferences(uuid, result);
break;
case "findAllAsync":
String find = (String) call.argument("find");
findAllAsync(uuid, find);
result.success(true);
break;
case "findNext":
Boolean forward = (Boolean) call.argument("forward");
findNext(uuid, forward, result);
break;
case "clearMatches":
clearMatches(uuid, result);
break;
default:
result.notImplemented();
}
}
private void injectScriptCode(String uuid, String source, final Result result) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectScriptCode(source, result);
} else {
Log.d(LOG_TAG, "webView is null");
public void onAttachedToEngine(FlutterPluginBinding binding) {
//BinaryMessenger messenger = binding.getFlutterEngine().getDartExecutor();
inAppBrowser = new InAppBrowser(registrar);
binding
.getFlutterEngine()
.getPlatformViewsController()
.getRegistry()
.registerViewFactory(
"com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(registrar,null));
myCookieManager = new MyCookieManager(registrar);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
credentialDatabaseHandler = new CredentialDatabaseHandler(registrar);
}
}
private void injectScriptFile(String uuid, String urlFile) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectScriptFile(urlFile);
@Override
public void onDetachedFromEngine(FlutterPluginBinding binding) {
if (inAppBrowser != null) {
inAppBrowser.dispose();
inAppBrowser = null;
}
}
private void injectStyleCode(String uuid, String source) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectStyleCode(source);
if (myCookieManager != null) {
myCookieManager.dispose();
myCookieManager = null;
}
}
private void injectStyleFile(String uuid, String urlFile) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectStyleFile(urlFile);
if (credentialDatabaseHandler != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
credentialDatabaseHandler.dispose();
credentialDatabaseHandler = null;
}
}
public static String getMimeType(String url) {
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
return type;
}
/**
* Display a new browser with the specified URL.
*
* @param url the url to load.
* @param result
* @return "" if ok, or error message.
*/
public void openExternal(Activity activity, String url, Result result) {
try {
Intent intent;
intent = new Intent(Intent.ACTION_VIEW);
// Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
// Adding the MIME type to http: URLs causes them to not be handled by the downloader.
Uri uri = Uri.parse(url);
if ("file".equals(uri.getScheme())) {
intent.setDataAndType(uri, getMimeType(url));
} else {
intent.setData(uri);
}
intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName());
// CB-10795: Avoid circular loops by preventing it from opening in the current app
this.openExternalExcludeCurrentApp(activity, intent);
result.success(true);
// not catching FileUriExposedException explicitly because buildtools<24 doesn't know about it
} catch (java.lang.RuntimeException e) {
Log.d(LOG_TAG, url + " cannot be opened: " + e.toString());
result.error(LOG_TAG, url + " cannot be opened!", null);
}
}
/**
* Opens the intent, providing a chooser that excludes the current app to avoid
* circular loops.
*/
private void openExternalExcludeCurrentApp(Activity activity, Intent intent) {
String currentPackage = activity.getPackageName();
boolean hasCurrentPackage = false;
PackageManager pm = activity.getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
ArrayList<Intent> targetIntents = new ArrayList<Intent>();
for (ResolveInfo ri : activities) {
if (!currentPackage.equals(ri.activityInfo.packageName)) {
Intent targetIntent = (Intent) intent.clone();
targetIntent.setPackage(ri.activityInfo.packageName);
targetIntents.add(targetIntent);
} else {
hasCurrentPackage = true;
}
}
// If the current app package isn't a target for this URL, then use
// the normal launch behavior
if (!hasCurrentPackage || targetIntents.size() == 0) {
activity.startActivity(intent);
}
// If there's only one possible intent, launch it directly
else if (targetIntents.size() == 1) {
activity.startActivity(targetIntents.get(0));
}
// Otherwise, show a custom chooser without the current app listed
else if (targetIntents.size() > 0) {
Intent chooser = Intent.createChooser(targetIntents.remove(targetIntents.size() - 1), null);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{}));
activity.startActivity(chooser);
}
}
public void open(Activity activity, String uuid, String uuidFallback, String url, HashMap<String, Object> options, Map<String, String> headers, boolean useChromeSafariBrowser, HashMap<String, Object> optionsFallback, Result result) {
Intent intent = null;
Bundle extras = new Bundle();
extras.putString("fromActivity", activity.getClass().getName());
extras.putString("url", url);
extras.putBoolean("isData", false);
extras.putString("uuid", uuid);
extras.putSerializable("options", options);
extras.putSerializable("headers", (Serializable) headers);
if (useChromeSafariBrowser && CustomTabActivityHelper.isAvailable(activity)) {
intent = new Intent(activity, ChromeCustomTabsActivity.class);
}
// check for webview fallback
else if (useChromeSafariBrowser && !CustomTabActivityHelper.isAvailable(activity) && !uuidFallback.isEmpty()) {
Log.d(LOG_TAG, "WebView fallback declared.");
// overwrite with extras fallback parameters
extras.putString("uuid", uuidFallback);
if (optionsFallback != null)
extras.putSerializable("options", optionsFallback);
else
extras.putSerializable("options", (new InAppBrowserOptions()).getHashMap());
extras.putSerializable("headers", (Serializable) headers);
intent = new Intent(activity, InAppBrowserActivity.class);
}
// native webview
else if (!useChromeSafariBrowser) {
intent = new Intent(activity, InAppBrowserActivity.class);
}
else {
Log.d(LOG_TAG, "No WebView fallback declared.");
}
if (intent != null) {
intent.putExtras(extras);
activity.startActivity(intent);
result.success(true);
return;
}
result.error(LOG_TAG, "No WebView fallback declared.", null);
}
public void openData(Activity activity, String uuid, HashMap<String, Object> options, String data, String mimeType, String encoding, String baseUrl) {
Intent intent = new Intent(activity, InAppBrowserActivity.class);
Bundle extras = new Bundle();
extras.putBoolean("isData", true);
extras.putString("uuid", uuid);
extras.putSerializable("options", options);
extras.putString("data", data);
extras.putString("mimeType", mimeType);
extras.putString("encoding", encoding);
extras.putString("baseUrl", baseUrl);
intent.putExtras(extras);
activity.startActivity(intent);
}
private String getUrl(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getUrl();
return null;
}
private String getTitle(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getWebViewTitle();
return null;
}
private Integer getProgress(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getProgress();
return null;
}
public void loadUrl(String uuid, String url, Map<String, String> headers, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
if (headers != null)
inAppBrowserActivity.loadUrl(url, headers, result);
else
inAppBrowserActivity.loadUrl(url, result);
}
}
public void postUrl(String uuid, String url, byte[] postData, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.postUrl(url, postData, result);
}
public void loadData(String uuid, String data, String mimeType, String encoding, String baseUrl, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.loadData(data, mimeType, encoding, baseUrl, result);
}
public void loadFile(String uuid, String url, Map<String, String> headers, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
if (headers != null)
inAppBrowserActivity.loadFile(url, headers, result);
else
inAppBrowserActivity.loadFile(url, result);
}
}
public void show(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.show();
}
public void hide(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.hide();
}
public void reload(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.reload();
}
public boolean isLoading(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.isLoading();
return false;
}
public boolean isHidden(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.isHidden;
return false;
}
public void stopLoading(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.stopLoading();
}
public void goBack(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.goBack();
}
public boolean canGoBack(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.canGoBack();
return false;
}
public void goForward(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.goForward();
}
public boolean canGoForward(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.canGoForward();
return false;
}
public void goBackOrForward(String uuid, int steps) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.goBackOrForward(steps);
}
public boolean canGoBackOrForward(String uuid, int steps) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.canGoBackOrForward(steps);
return false;
}
public void close(Activity activity, final String uuid, final Result result) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid);
channel.invokeMethod("onExit", obj);
// The JS protects against multiple calls, so this should happen only when
// close() is called by other native code.
if (inAppBrowserActivity == null) {
if (result != null) {
result.success(true);
}
return;
}
inAppBrowserActivity.webView.setWebViewClient(new WebViewClient() {
// NB: wait for about:blank before dismissing
public void onPageFinished(WebView view, String url) {
inAppBrowserActivity.close();
}
});
// NB: From SDK 19: "If you call methods on WebView from any thread
// other than your app's UI thread, it can cause unexpected results."
// http://developer.android.com/guide/webapps/migrating.html#Threads
inAppBrowserActivity.webView.loadUrl("about:blank");
if (result != null) {
result.success(true);
}
}
});
}
else if (result != null) {
result.success(true);
}
}
public byte[] takeScreenshot(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.takeScreenshot();
return null;
}
public void setOptions(String uuid, InAppBrowserOptions options, HashMap<String, Object> optionsMap) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.setOptions(options, optionsMap);
}
public HashMap<String, Object> getOptions(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getOptions();
return null;
}
public HashMap<String, Object> getCopyBackForwardList(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getCopyBackForwardList();
return null;
}
public void startSafeBrowsing(String uuid, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.startSafeBrowsing(result);
result.success(false);
}
public void setSafeBrowsingWhitelist(String uuid, List<String> hosts, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.setSafeBrowsingWhitelist(hosts, result);
result.success(false);
}
public void clearCache(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearCache();
}
public void clearSslPreferences(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearSslPreferences();
}
public void clearClientCertPreferences(String uuid, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearClientCertPreferences(result);
result.success(false);
}
public void findAllAsync(String uuid, String find) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.findAllAsync(find);
}
public void findNext(String uuid, Boolean forward, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.findNext(forward, result);
result.success(false);
}
public void clearMatches(String uuid, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearMatches(result);
result.success(false);
}
}

View File

@ -2,7 +2,7 @@ package com.pichillilorenzo.flutter_inappbrowser;
public class InAppBrowserOptions extends Options {
static final String LOG_TAG = "InAppBrowserOptions";
public static final String LOG_TAG = "InAppBrowserOptions";
public boolean hidden = false;
public boolean toolbarTop = true;

View File

@ -538,6 +538,6 @@ public class InAppWebChromeClient extends WebChromeClient {
}
private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.instance.channel : flutterWebView.channel;
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
}
}

View File

@ -686,7 +686,7 @@ final public class InAppWebView extends InputAwareWebView {
}
private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.instance.channel : flutterWebView.channel;
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
}
public void startSafeBrowsing(final MethodChannel.Result result) {
@ -745,6 +745,11 @@ final public class InAppWebView extends InputAwareWebView {
webSettings.setBuiltInZoomControls(enabled);
}
@Override
public void dispose() {
super.dispose();
}
@Override
public void destroy() {
super.destroy();

View File

@ -224,7 +224,7 @@ public class InAppWebViewClient extends WebViewClient {
previousAuthRequestFailureCount = 0;
credentialsProposed = null;
// CB-10395 InAppBrowserFlutterPlugin's WebView not storing cookies reliable to local device storage
// CB-10395 InAppBrowser's WebView not storing cookies reliable to local device storage
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().flush();
} else {
@ -667,7 +667,7 @@ public class InAppWebViewClient extends WebViewClient {
}
private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.instance.channel : flutterWebView.channel;
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
}
}

View File

@ -10,7 +10,7 @@ import java.util.Map;
public class InAppWebViewOptions extends Options {
static final String LOG_TAG = "InAppWebViewOptions";
public static final String LOG_TAG = "InAppWebViewOptions";
public boolean useShouldOverrideUrlLoading = false;
public boolean useOnLoadResource = false;

View File

@ -4,6 +4,7 @@ import static android.content.Context.INPUT_METHOD_SERVICE;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebView;
@ -15,8 +16,8 @@ import android.webkit.WebView;
* https://github.com/flutter/plugins/blob/master/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java
*/
public class InputAwareWebView extends WebView {
private static final String LOG_TAG = "InputAwareWebView";
public View containerView;
private View threadedInputConnectionProxyView;
private ThreadedInputConnectionProxyAdapterView proxyAdapterView;
@ -40,6 +41,19 @@ public class InputAwareWebView extends WebView {
this.containerView = null;
}
public void setContainerView(View containerView) {
this.containerView = containerView;
if (proxyAdapterView == null) {
return;
}
Log.w(LOG_TAG, "The containerView has changed while the proxyAdapterView exists.");
if (containerView != null) {
setInputConnectionTarget(proxyAdapterView);
}
}
/**
* Set our proxy adapter view to use its cached input connection instead of creating new ones.
*
@ -82,8 +96,6 @@ public class InputAwareWebView extends WebView {
*/
@Override
public boolean checkInputConnectionProxy(final View view) {
if (containerView == null)
return super.checkInputConnectionProxy(view);
// Check to see if the view param is WebView's ThreadedInputConnectionProxyView.
View previousProxy = threadedInputConnectionProxyView;
threadedInputConnectionProxyView = view;
@ -91,6 +103,12 @@ public class InputAwareWebView extends WebView {
// This isn't a new ThreadedInputConnectionProxyView. Ignore it.
return super.checkInputConnectionProxy(view);
}
if (containerView == null) {
Log.e(
LOG_TAG,
"Can't create a proxy view because there's no container view. Text input may not work.");
return super.checkInputConnectionProxy(view);
}
// We've never seen this before, so we make the assumption that this is WebView's
// ThreadedInputConnectionProxyView. We are making the assumption that the only view that could
@ -115,8 +133,7 @@ public class InputAwareWebView extends WebView {
@Override
public void clearFocus() {
super.clearFocus();
if (containerView != null)
resetInputConnection();
resetInputConnection();
}
/**
@ -131,6 +148,10 @@ public class InputAwareWebView extends WebView {
// No need to reset the InputConnection to the default thread if we've never changed it.
return;
}
if (containerView == null) {
Log.e(LOG_TAG, "Can't reset the input connection to the container view because there is none.");
return;
}
setInputConnectionTarget(/*targetView=*/ containerView);
}
@ -143,6 +164,13 @@ public class InputAwareWebView extends WebView {
* InputConnections should be created on.
*/
private void setInputConnectionTarget(final View targetView) {
if (containerView == null) {
Log.e(
LOG_TAG,
"Can't set the input connection target because there is no containerView to use as a handler.");
return;
}
targetView.requestFocus();
containerView.post(
new Runnable() {

View File

@ -11,8 +11,6 @@ import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebView;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
@ -121,6 +119,6 @@ public class JavaScriptBridgeInterface {
}
private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.instance.channel : flutterWebView.channel;
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
}
}

View File

@ -226,4 +226,7 @@ public class MyCookieManager implements MethodChannel.MethodCallHandler {
return sdf.format(new Date(timestamp));
}
public void dispose() {
channel.setMethodCallHandler(null);
}
}

View File

@ -13,14 +13,24 @@ import java.security.Key;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import okhttp3.OkHttpClient;
public class Util {
@ -148,4 +158,50 @@ public class Util {
this.certificates = certificates;
}
}
public static OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
OkHttpClient okHttpClient = builder
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,3 +1,4 @@
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
android.enableR8=true

BIN
example/assets/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -8,6 +8,7 @@
<link rel="stylesheet" href="http://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<link rel="shortcut icon" href="favicon.ico">
</head>
<body class="text-center">
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
@ -26,6 +27,10 @@
<h1 class="cover-heading">Inline WebView</h1>
<img src="my-special-custom-scheme://images/flutter-logo.svg" alt="flutter logo">
<p class="lead">Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.</p>
<select name="" id="">
<option value="1">option 1</option>
<option value="2">option 2</option>
</select>
<p>
<img src="https://via.placeholder.com/100x50" alt="placeholder 100x50">
</p>

View File

@ -5,6 +5,6 @@ export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappbro
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
export "FLUTTER_FRAMEWORK_DIR=/Users/lorenzopichilli/flutter/bin/cache/artifacts/engine/ios-release"
export "FLUTTER_FRAMEWORK_DIR=/Users/lorenzopichilli/flutter/bin/cache/artifacts/engine/ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"

View File

@ -83,11 +83,11 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
BoxDecoration(border: Border.all(color: Colors.blueAccent)),
child: InAppWebView(
//initialUrl: "https://www.youtube.com/embed/M7lc1UVf-VE?playsinline=1",
initialUrl: "https://github.com",
//initialUrl: "https://github.com",
//initialUrl: "chrome://safe-browsing/match?type=malware",
//initialUrl: "http://192.168.1.20:8081/",
//initialUrl: "https://192.168.1.20:4433/",
//initialFile: "assets/index.html",
initialFile: "assets/index.html",
initialHeaders: {},
initialOptions: [
InAppWebViewOptions(
@ -143,8 +143,8 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
controller.clearSslPreferences();
controller.clearClientCertPreferences();
}
//controller.findAllAsync("a");
controller.getFavicon();
//controller.findAllAsync("flutter");
print(await controller.getFavicons());
},
onLoadError: (InAppWebViewController controller, String url, int code, String message) async {
print("error $url: $code, $message");

View File

@ -48,6 +48,7 @@ flutter:
- assets/page-2.html
- assets/css/
- assets/images/
- assets/favicon.ico
# To add assets to your application, add an assets section, like this:
# assets:

View File

@ -301,25 +301,9 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
}
result(true)
break
case "dispose":
dispose()
result(true)
break
default:
result(FlutterMethodNotImplemented)
break
}
}
public func dispose() {
if webView != nil {
webView!.IABController = nil
webView!.IAWController = nil
webView!.uiDelegate = nil
webView!.navigationDelegate = nil
webView!.scrollView.delegate = nil
webView!.stopLoading()
webView = nil
}
}
}

View File

@ -238,7 +238,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
var IAWController: FlutterWebViewController?
var options: InAppWebViewOptions?
var currentURL: URL?
var WKNavigationMap: [String: [String: Any]] = [:]
var startPageTime: Int64 = 0
static var credentialsProposed: [URLCredential] = []
@ -786,13 +785,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
let app = UIApplication.shared
if let url = navigationAction.request.url {
if url.absoluteString != url.absoluteString && (options?.useOnLoadResource)! {
WKNavigationMap[url.absoluteString] = [
"startTime": currentTimeInMilliSeconds(),
"request": navigationAction.request
]
}
// Handle target="_blank"
if navigationAction.targetFrame == nil && (options?.useOnTargetBlank)! {
onTargetBlank(url: url)
@ -834,17 +826,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
// if (options?.useOnLoadResource)! {
// if let url = navigationResponse.response.url {
// if WKNavigationMap[url.absoluteString] != nil {
// let startResourceTime: Int64 = (WKNavigationMap[url.absoluteString]!["startTime"] as! Int64)
// let startTime: Int64 = startResourceTime - startPageTime;
// let duration: Int64 = currentTimeInMilliSeconds() - startResourceTime;
// onLoadResource(response: navigationResponse.response, fromRequest: WKNavigationMap[url.absoluteString]!["request"] as? URLRequest, withData: Data(), startTime: startTime, duration: duration)
// }
// }
// }
if (options?.useOnDownloadStart)! {
let mimeType = navigationResponse.response.mimeType
if let url = navigationResponse.response.url {
@ -875,7 +856,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
}
public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.WKNavigationMap = [:]
currentURL = url
InAppWebView.credentialsProposed = []
onLoadStop(url: (currentURL?.absoluteString)!)

View File

@ -17,7 +17,7 @@ A new Flutter plugin.
s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter'
s.ios.deployment_target = '8.0'
s.platform = '8.0'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
s.swift_version = '5.0'
end

View File

@ -268,7 +268,8 @@ class InAppBrowser {
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('optionsType', () => "InAppBrowserOptions");
Map<dynamic, dynamic> options = await ChannelManager.channel.invokeMethod('getOptions', args);
options = options.cast<String, dynamic>();
if (options != null)
options = options.cast<String, dynamic>();
return options;
}

View File

@ -10,9 +10,10 @@ import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart';
import 'package:html/parser.dart' show parse;
import 'types.dart';
import 'in_app_browser.dart';
import 'channel_manager.dart';
import 'webview_options.dart';
/*
@ -255,15 +256,6 @@ class _InAppWebViewState extends State<InAppWebView> {
InAppWebViewController _controller;
@override
void dispose() {
super.dispose();
if (_controller != null) {
_controller._dispose();
_controller = null;
}
}
@override
Widget build(BuildContext context) {
Map<String, dynamic> initialOptions = {};
@ -273,7 +265,22 @@ class _InAppWebViewState extends State<InAppWebView> {
});
if (defaultTargetPlatform == TargetPlatform.android) {
return GestureDetector(
return AndroidView(
viewType: 'com.pichillilorenzo/flutter_inappwebview',
onPlatformViewCreated: _onPlatformViewCreated,
gestureRecognizers: widget.gestureRecognizers,
layoutDirection: TextDirection.rtl,
creationParams: <String, dynamic>{
'initialUrl': widget.initialUrl,
'initialFile': widget.initialFile,
'initialData': widget.initialData?.toMap(),
'initialHeaders': widget.initialHeaders,
'initialOptions': initialOptions
},
creationParamsCodec: const StandardMessageCodec(),
);
// onLongPress issue: https://github.com/flutter/plugins/blob/f31d16a6ca0c4bd6849cff925a00b6823973696b/packages/webview_flutter/lib/src/webview_android.dart#L31
/*return GestureDetector(
onLongPress: () {},
excludeFromSemantics: true,
child: AndroidView(
@ -290,7 +297,7 @@ class _InAppWebViewState extends State<InAppWebView> {
},
creationParamsCodec: const StandardMessageCodec(),
),
);
);*/
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
return UiKitView(
viewType: 'com.pichillilorenzo/flutter_inappwebview',
@ -593,105 +600,146 @@ class InAppWebViewController {
return await _channel.invokeMethod('getProgress', args);
}
///Gets the favicon for the current page.
Future<List<int>> getFavicon() async {
List<Favicon> favicons = [];
HttpClient client = new HttpClient();
var url = Uri.parse(await getUrl());
var htmlRequest = await client.getUrl(url);
var html = await (await htmlRequest.close()).transform(Utf8Decoder()).join();
/// TODO: parse HTML instead of using javascript code
try {
List<dynamic> faviconsJs = json.decode(await injectScriptCode("""
function flutter_inappbrowser_ger_favicons() {
var favicons = [];
var links = document.getElementsByTagName('link');
for (var i = 0; i < links.length; i++) {
var link = links[i];
if (link.rel.indexOf("icon") >= 0) {
favicons.push({
rel: link.rel,
href: link.href,
sizes: link.sizes
});
}
///Gets the content html of the page. It first tries to get the content through javascript.
///If this doesn't work, it tries to get the content reading the file:
///- checking if it is an asset (`file:///`) or
///- downloading it using an `HttpClient` through the WebView's current url.
Future<String> getHtml() async {
var html = "";
Map<String, dynamic> options = await getOptions();
if (options != null && options["javaScriptEnabled"] == true) {
html = await injectScriptCode("window.document.getElementsByTagName('html')[0].outerHTML;");
if (html.isNotEmpty)
return html;
}
return favicons;
}
flutter_inappbrowser_ger_favicons();
"""));
for(Map<String, dynamic> favicon in faviconsJs) {
String sizes = favicon["sizes"];
if (sizes != null && sizes != "any") {
List<String> sizesSplitted = sizes.split(" ");
for (String size in sizesSplitted) {
int width = int.parse(size.split("x")[0]);
int height = int.parse(size.split("x")[1]);
favicons.add(Favicon(url: favicon["href"], rel: favicon["rel"], width: width, height: height));
}
} else {
favicons.add(Favicon(url: favicon["href"], rel: favicon["rel"], width: null, height: null));
}
var webviewUrl = await getUrl();
if (webviewUrl.startsWith("file:///")) {
var assetPathSplitted = webviewUrl.split("/flutter_assets/");
var assetPath = assetPathSplitted[assetPathSplitted.length - 1];
var bytes = await rootBundle.load(assetPath);
html = utf8.decode(bytes.buffer.asUint8List());
}
else {
HttpClient client = new HttpClient();
var url = Uri.parse(webviewUrl);
try {
var htmlRequest = await client.getUrl(url);
html = await (await htmlRequest.close()).transform(Utf8Decoder()).join();
} catch (e) {
print(e);
}
} catch (e) {}
}
return html;
}
///Gets the list of all favicons for the current page.
Future<List<Favicon>> getFavicons() async {
List<Favicon> favicons = [];
var completer = new Completer<List<int>>();
var faviconData = new List<int>();
HttpClient client = new HttpClient();
var webviewUrl = await getUrl();
var url = (webviewUrl.startsWith("file:///")) ? Uri.file(webviewUrl) : Uri.parse(webviewUrl);
String manifestUrl;
var html = await getHtml();
if (html.isEmpty) {
return favicons;
}
var assetPathBase;
if (webviewUrl.startsWith("file:///")) {
var assetPathSplitted = webviewUrl.split("/flutter_assets/");
assetPathBase = assetPathSplitted[0] + "/flutter_assets/";
}
// get all link html elements
var document = parse(html);
var links = document.getElementsByTagName('link');
for (var link in links) {
var attributes = link.attributes;
if (attributes["rel"] == "manifest") {
manifestUrl = attributes["href"];
if (!_isUrlAbsolute(manifestUrl)) {
if (manifestUrl.startsWith("/")) {
manifestUrl = manifestUrl.substring(1);
}
manifestUrl = ((assetPathBase == null) ? url.scheme + "://" + url.host + "/" : assetPathBase) + manifestUrl;
}
continue;
}
if (!attributes["rel"].contains("icon")) {
continue;
}
favicons.addAll(_createFavicons(url, assetPathBase, attributes["href"], attributes["rel"], attributes["sizes"], false));
}
// try to get /favicon.ico
try {
var faviconUrl = url.scheme + "://" + url.host + "/favicon.ico";
await client.headUrl(Uri.parse(faviconUrl));
favicons.add(Favicon(url: faviconUrl, rel: "shortcut icon"));
} catch(e) {}
var manifestRequest;
try {
var manifestJsonUrl = url.scheme + "://" + url.host + "/manifest.json";
manifestRequest = await client.getUrl(Uri.parse(manifestJsonUrl));
} catch(e) {
/// TODO: find manifest throught rel="manifest"
print("/favicon.ico file not found: " + e.toString());
}
if (manifestRequest) {
Map<String, dynamic> manifest = json.decode(await (await manifestRequest.close()).transform(Utf8Decoder()).join());
// try to get the manifest file
HttpClientRequest manifestRequest;
HttpClientResponse manifestResponse;
bool manifestFound = false;
if (manifestUrl == null) {
manifestUrl = url.scheme + "://" + url.host + "/manifest.json";
}
try {
manifestRequest = await client.getUrl(Uri.parse(manifestUrl));
manifestResponse = await manifestRequest.close();
manifestFound = manifestResponse.statusCode == 200 && manifestResponse.headers.contentType?.mimeType == "application/json";
} catch(e) {
print("Manifest file not found: " + e.toString());
}
if (manifestFound) {
Map<String, dynamic> manifest = json.decode(await manifestResponse.transform(Utf8Decoder()).join());
if (manifest.containsKey("icons")) {
for(Map<String, dynamic> icon in manifest["icons"]) {
String url = icon["src"];
List<String> urlSplitted = url.split("/");
String sizes = icon["sizes"];
String rel = (sizes != null) ? urlSplitted[urlSplitted.length - 1].replaceFirst("-" + sizes, "").split(" ")[0].split(".")[0] : null;
if (sizes != null && sizes != "any") {
List<String> sizesSplitted = sizes.split(" ");
for (String size in sizesSplitted) {
int width = int.parse(size.split("x")[0]);
int height = int.parse(size.split("x")[1]);
favicons.add(Favicon(url: url, rel: rel, width: width, height: height));
}
} else {
favicons.add(Favicon(url: url, rel: rel, width: null, height: null));
}
favicons.addAll(_createFavicons(url, assetPathBase, icon["src"], icon["rel"], icon["sizes"], true));
}
}
}
//print(favicons);
return favicons;
}
// solution found here: https://stackoverflow.com/a/15750809/4637638
var googleFaviconUrl = Uri.parse("https://plus.google.com/_/favicon?domain_url=" + url.scheme + "://" + url.host);
client.getUrl(googleFaviconUrl).then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) {
response.listen((List<int> data) {
faviconData = data;
}, onDone: () => completer.complete(faviconData));
}).catchError((error) {
completer.completeError(error);
});
return completer.future;
bool _isUrlAbsolute(String url) {
return url.startsWith("http://") || url.startsWith("https://");
}
List<Favicon> _createFavicons(Uri url, String assetPathBase, String urlIcon, String rel, String sizes, bool isManifest) {
List<Favicon> favicons = [];
List<String> urlSplitted = urlIcon.split("/");
if (!_isUrlAbsolute(urlIcon)) {
if (urlIcon.startsWith("/")) {
urlIcon = urlIcon.substring(1);
}
urlIcon = ((assetPathBase == null) ? url.scheme + "://" + url.host + "/" : assetPathBase) + urlIcon;
}
if (isManifest) {
rel = (sizes != null) ? urlSplitted[urlSplitted.length - 1].replaceFirst("-" + sizes, "").split(" ")[0].split(".")[0] : null;
}
if (sizes != null && sizes.isNotEmpty && sizes != "any") {
List<String> sizesSplitted = sizes.split(" ");
for (String size in sizesSplitted) {
int width = int.parse(size.split("x")[0]);
int height = int.parse(size.split("x")[1]);
favicons.add(Favicon(url: urlIcon, rel: rel, width: width, height: height));
}
} else {
favicons.add(Favicon(url: urlIcon, rel: rel, width: null, height: null));
}
return favicons;
}
///Loads the given [url] with optional [headers] specified as a map from name to value.
@ -1001,7 +1049,6 @@ flutter_inappbrowser_ger_favicons();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('options', () => options);
args.putIfAbsent('optionsType', () => "InAppBrowserOptions");
await _channel.invokeMethod('setOptions', args);
}
@ -1012,9 +1059,9 @@ flutter_inappbrowser_ger_favicons();
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('optionsType', () => "InAppBrowserOptions");
Map<dynamic, dynamic> options = await ChannelManager.channel.invokeMethod('getOptions', args);
options = options.cast<String, dynamic>();
Map<dynamic, dynamic> options = await _channel.invokeMethod('getOptions', args);
if (options != null)
options = options.cast<String, dynamic>();
return options;
}
@ -1183,9 +1230,4 @@ flutter_inappbrowser_ger_favicons();
}
await _channel.invokeMethod('clearMatches', args);
}
///Dispose/Destroy the WebView.
Future<void> _dispose() async {
await _channel.invokeMethod('dispose');
}
}

View File

@ -43,6 +43,7 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOpti
this.resourceCustomSchemes = const [], this.contentBlockers = const [], this.preferredContentMode = InAppWebViewUserPreferredContentMode.RECOMMENDED}) {
if (this.minimumFontSize == null)
this.minimumFontSize = Platform.isAndroid ? 8 : 0;
assert(!this.resourceCustomSchemes.contains("http") && !this.resourceCustomSchemes.contains("https"));
}
@override

View File

@ -23,7 +23,16 @@ appHttps.get('/', (req, res) => {
// `localhost`.
if (req.client.authorized) {
res.send(`Hello ${cert.subject.CN}, your certificate was issued by ${cert.issuer.CN}!`)
res.send(`
<html>
<head>
<script src="/fakeResource" type="text/javascript"></script>
</head>
<body>
<p>Hello ${cert.subject.CN}, your certificate was issued by ${cert.issuer.CN}!</p>
</body>
</html>
`)
// They can still provide a certificate which is not accepted by us. Unfortunately, the `cert` object will be an empty
// object instead of `null` if there is no certificate at all, so we have to check for a known field rather than
// truthiness.
@ -34,6 +43,13 @@ appHttps.get('/', (req, res) => {
} else {
res.status(401).send(`Sorry, but you need to provide a client certificate to continue.`)
}
res.end()
})
appHttps.get('/fakeResource', (req, res) => {
res.set("Content-Type", "text/javascript")
res.send(`alert("HI");`)
res.end()
})
// Let's create our HTTPS server and we're ready to go.

View File

@ -5,14 +5,15 @@ author: Lorenzo Pichilli <pichillilorenzo@gmail.com>
homepage: https://github.com/pichillilorenzo/flutter_inappbrowser
environment:
sdk: ">=2.0.0-dev <3.0.0"
flutter: ">=0.10.1 <2.0.0"
sdk: ">=2.0.0-dev.68.0 <3.0.0"
flutter: ">=1.9.1+hotfix.5 <2.0.0"
dependencies:
flutter:
sdk: flutter
uuid: ^2.0.0
mime: ^0.9.6+2
html: ^0.14.0+3
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec