added getHtml method, updated android config, remove block on long press webview android, fixed other issues
This commit is contained in:
parent
6518697e55
commit
299042f828
383
.idea/workspace.xml
generated
383
.idea/workspace.xml
generated
@ -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>!= "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>
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
org.gradle.jvmargs=-Xmx1536M
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(";");
|
||||
|
@ -116,4 +116,8 @@ public class CredentialDatabaseHandler implements MethodChannel.MethodCallHandle
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
channel.setMethodCallHandler(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -226,4 +226,7 @@ public class MyCookieManager implements MethodChannel.MethodCallHandler {
|
||||
return sdf.format(new Date(timestamp));
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
channel.setMethodCallHandler(null);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
BIN
example/assets/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
@ -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>
|
||||
|
@ -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"
|
||||
|
@ -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");
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)!)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user