v0.4.0
This commit is contained in:
parent
c7356f33c8
commit
860a42e2ba
281
.idea/workspace.xml
generated
281
.idea/workspace.xml
generated
@ -15,13 +15,30 @@
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="9b41f7a2-a71e-4923-91fb-249d7815b3e7" name="Default" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/example/assets/css/style.css" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/example/assets/images/dart.svg" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/example/assets/index.html" 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$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/example/ios/Runner.xcodeproj/project.pbxproj" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Runner.xcodeproj/project.pbxproj" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/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/InAppBrowserWebChromeClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebChromeClient.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.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/Options.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/Options.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ChromeCustomTabsActivity.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ChromeCustomTabsActivity.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/CustomTabActivityHelper.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/CustomTabActivityHelper.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/example/ios/Runner/Info.plist" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Runner/Info.plist" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/example/lib/main.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/main.dart" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/example/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/example/pubspec.yaml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/flutter_inappbrowser.iml" beforeDir="false" afterPath="$PROJECT_DIR$/flutter_inappbrowser.iml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/ios/Classes/InAppBrowserOptions.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/InAppBrowserOptions.swift" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/ios/Classes/InAppBrowserWebViewController.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/InAppBrowserWebViewController.swift" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/ios/Classes/Options.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/Options.swift" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/ios/Classes/SafariViewController.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/SafariViewController.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$/ios/Storyboards/en.lproj/WebView.storyboard" beforeDir="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/flutter_inappbrowser.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/flutter_inappbrowser.dart" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/pubspec.yaml" afterDir="false" />
|
||||
</list>
|
||||
@ -43,20 +60,25 @@
|
||||
<file leaf-file-name="flutter_inappbrowser.dart" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="5791">
|
||||
<caret line="429" column="3" selection-start-line="429" selection-start-column="3" selection-end-line="429" selection-end-column="3" />
|
||||
<state relative-caret-position="128">
|
||||
<caret line="82" column="21" selection-start-line="82" selection-start-column="6" selection-end-line="82" selection-end-column="21" />
|
||||
<folding>
|
||||
<element signature="e#814#834#0" expanded="true" />
|
||||
<element signature="e#814#831#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="pubspec.yaml" 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="30">
|
||||
<caret line="2" column="14" selection-start-line="2" selection-start-column="14" selection-end-line="2" selection-end-column="14" />
|
||||
<file leaf-file-name="README.md" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/README.md">
|
||||
<provider selected="true" editor-type-id="split-provider[text-editor;MarkdownPreviewEditor]">
|
||||
<state split_layout="SPLIT">
|
||||
<first_editor relative-caret-position="4980">
|
||||
<caret line="332" column="20" lean-forward="true" selection-start-line="332" selection-start-column="20" selection-end-line="332" selection-end-column="41" />
|
||||
</first_editor>
|
||||
<second_editor>
|
||||
<markdownNavigatorState />
|
||||
</second_editor>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
@ -65,8 +87,8 @@
|
||||
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
|
||||
<provider selected="true" editor-type-id="split-provider[text-editor;MarkdownPreviewEditor]">
|
||||
<state split_layout="SPLIT">
|
||||
<first_editor relative-caret-position="30">
|
||||
<caret line="2" column="39" selection-start-line="2" selection-start-column="39" selection-end-line="2" selection-end-column="39" />
|
||||
<first_editor relative-caret-position="135">
|
||||
<caret line="9" lean-forward="true" selection-start-line="9" selection-end-line="9" />
|
||||
</first_editor>
|
||||
<second_editor>
|
||||
<markdownNavigatorState />
|
||||
@ -75,6 +97,18 @@
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="main.dart" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="165">
|
||||
<caret line="165" column="42" selection-start-line="165" selection-start-column="42" selection-end-line="165" selection-end-column="42" />
|
||||
<folding>
|
||||
<element signature="e#0#20#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
</leaf>
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
@ -86,11 +120,6 @@
|
||||
</component>
|
||||
<component name="FindInProjectRecents">
|
||||
<findStrings>
|
||||
<find>loadUrl</find>
|
||||
<find>showWebPage</find>
|
||||
<find>InAppBrowserClient</find>
|
||||
<find>LOG.</find>
|
||||
<find>preferences</find>
|
||||
<find>getPre</find>
|
||||
<find>client</find>
|
||||
<find>webView</find>
|
||||
@ -116,6 +145,11 @@
|
||||
<find>presentationStyle</find>
|
||||
<find>###</find>
|
||||
<find>inAppBrowserFallback</find>
|
||||
<find>target</find>
|
||||
<find>.assets</find>
|
||||
<find>_blank</find>
|
||||
<find>.html</find>
|
||||
<find>close(</find>
|
||||
</findStrings>
|
||||
<replaceStrings>
|
||||
<replace>activity.getPreferences(0)</replace>
|
||||
@ -142,7 +176,6 @@
|
||||
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutterwebview/InAppBrowserClient.java" />
|
||||
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutterwebview/InAppBrowserDialog.java" />
|
||||
<option value="$PROJECT_DIR$/android/settings.gradle" />
|
||||
<option value="$PROJECT_DIR$/example/pubspec.yaml" />
|
||||
<option value="$PROJECT_DIR$/ios/Classes/InAppBrowser.m" />
|
||||
<option value="$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift" />
|
||||
<option value="$PROJECT_DIR$/LICENSE" />
|
||||
@ -152,17 +185,23 @@
|
||||
<option value="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" />
|
||||
<option value="$PROJECT_DIR$/example/ios/Podfile" />
|
||||
<option value="$PROJECT_DIR$/android/build.gradle" />
|
||||
<option value="$PROJECT_DIR$/example/lib/main.dart" />
|
||||
<option value="$PROJECT_DIR$/lib/flutter_inappbrowser.dart" />
|
||||
<option value="$PROJECT_DIR$/README.md" />
|
||||
<option value="$PROJECT_DIR$/example/html/css/style.css" />
|
||||
<option value="$PROJECT_DIR$/example/html/index.html" />
|
||||
<option value="$PROJECT_DIR$/pubspec.yaml" />
|
||||
<option value="$PROJECT_DIR$/example/assets/css/style.css" />
|
||||
<option value="$PROJECT_DIR$/example/assets/index.html" />
|
||||
<option value="$PROJECT_DIR$/example/pubspec.yaml" />
|
||||
<option value="$PROJECT_DIR$/example/lib/main.dart" />
|
||||
<option value="$PROJECT_DIR$/README.md" />
|
||||
<option value="$PROJECT_DIR$/lib/flutter_inappbrowser.dart" />
|
||||
<option value="$PROJECT_DIR$/CHANGELOG.md" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectFrameBounds">
|
||||
<option name="y" value="23" />
|
||||
<option name="width" value="1920" />
|
||||
<option name="x" value="-1920" />
|
||||
<option name="y" value="-21" />
|
||||
<option name="width" value="1711" />
|
||||
<option name="height" value="1057" />
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||
@ -171,6 +210,18 @@
|
||||
<foldersAlwaysOnTop value="true" />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="Scope">
|
||||
<subPane subId="Project Files">
|
||||
<expand>
|
||||
<path>
|
||||
<item name="Root" type="cbb8eebc:String" user="Root" />
|
||||
<item name="flutter_inappbrowser" type="cbb8eebc:String" user="flutter_inappbrowser" />
|
||||
</path>
|
||||
</expand>
|
||||
<select />
|
||||
</subPane>
|
||||
</pane>
|
||||
<pane id="PackagesPane" />
|
||||
<pane id="ProjectPane">
|
||||
<subPane>
|
||||
<expand>
|
||||
@ -183,6 +234,23 @@
|
||||
<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="example" 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" />
|
||||
@ -193,19 +261,7 @@
|
||||
</subPane>
|
||||
<option name="show-excluded-files" value="false" />
|
||||
</pane>
|
||||
<pane id="PackagesPane" />
|
||||
<pane id="AndroidView" />
|
||||
<pane id="Scope">
|
||||
<subPane subId="Project Files">
|
||||
<expand>
|
||||
<path>
|
||||
<item name="Root" type="cbb8eebc:String" user="Root" />
|
||||
<item name="flutter_inappbrowser" type="cbb8eebc:String" user="flutter_inappbrowser" />
|
||||
</path>
|
||||
</expand>
|
||||
<select />
|
||||
</subPane>
|
||||
</pane>
|
||||
</panes>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
@ -224,12 +280,13 @@
|
||||
<property name="show.migrate.to.gradle.popup" value="false" />
|
||||
</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$/android/libs" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$/android/src/main/java" />
|
||||
</key>
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$/example/assets/images" />
|
||||
<recent name="$PROJECT_DIR$/android/libs" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunDashboard">
|
||||
<option name="ruleStates">
|
||||
@ -361,7 +418,7 @@
|
||||
<servers />
|
||||
</component>
|
||||
<component name="ToolWindowManager">
|
||||
<frame x="0" y="23" width="1920" height="1057" extended-state="0" />
|
||||
<frame x="-1920" y="-21" width="1711" height="1057" extended-state="0" />
|
||||
<editor active="true" />
|
||||
<layout>
|
||||
<window_info anchor="bottom" id="Android Profiler" order="7" show_stripe_button="false" />
|
||||
@ -372,22 +429,22 @@
|
||||
<window_info anchor="right" id="Capture Analysis" order="3" />
|
||||
<window_info anchor="bottom" id="Event Log" order="8" sideWeight="0.5035553" side_tool="true" weight="0.25689086" />
|
||||
<window_info anchor="bottom" id="Dart Analysis" order="14" weight="0.32855567" />
|
||||
<window_info anchor="bottom" id="Run" order="2" sideWeight="0.49644473" weight="0.20384204" />
|
||||
<window_info anchor="bottom" id="Run" order="2" sideWeight="0.49644473" weight="0.3628602" />
|
||||
<window_info anchor="bottom" id="Version Control" order="9" />
|
||||
<window_info anchor="bottom" id="Terminal" order="10" sideWeight="0.49644473" visible="true" weight="0.25506938" />
|
||||
<window_info anchor="bottom" id="Terminal" order="10" sideWeight="0.49644473" visible="true" weight="0.2529349" />
|
||||
<window_info anchor="right" id="Flutter Outline" order="3" weight="0.32922077" />
|
||||
<window_info anchor="bottom" id="Logcat" order="11" />
|
||||
<window_info id="Captures" order="2" weight="0.32936507" />
|
||||
<window_info id="Capture Tool" order="2" />
|
||||
<window_info id="Designer" order="2" />
|
||||
<window_info active="true" content_ui="combo" id="Project" order="0" sideWeight="0.49855492" visible="true" weight="0.15069222" />
|
||||
<window_info id="Structure" order="1" sideWeight="0.5014451" side_tool="true" weight="0.18293472" />
|
||||
<window_info active="true" content_ui="combo" id="Project" order="0" sideWeight="0.49724367" visible="true" weight="0.16956261" />
|
||||
<window_info id="Structure" order="1" sideWeight="0.50275636" side_tool="true" weight="0.1910871" />
|
||||
<window_info anchor="right" id="Device File Explorer" order="3" side_tool="true" />
|
||||
<window_info anchor="right" id="Theme Preview" order="3" />
|
||||
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
|
||||
<window_info id="Favorites" order="2" side_tool="true" />
|
||||
<window_info anchor="right" id="Flutter Inspector" order="3" weight="0.32987013" />
|
||||
<window_info anchor="bottom" id="Messages" order="12" weight="0.2370452" />
|
||||
<window_info anchor="bottom" id="Messages" order="12" weight="0.23692636" />
|
||||
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
||||
<window_info anchor="right" id="Commander" order="0" weight="0.4" />
|
||||
<window_info anchor="right" id="Assistant" order="4" visible="true" weight="0.32987013" />
|
||||
@ -396,13 +453,12 @@
|
||||
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
|
||||
<window_info anchor="bottom" id="Dependency Viewer" order="13" weight="0.32800853" />
|
||||
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
||||
<window_info anchor="bottom" id="Find" order="1" weight="0.328125" />
|
||||
<window_info anchor="bottom" id="Find" order="1" weight="0.3276414" />
|
||||
</layout>
|
||||
<layout-to-restore>
|
||||
<window_info id="Designer" order="4" />
|
||||
<window_info anchor="bottom" id="Dart Analysis" order="14" weight="0.3290735" />
|
||||
<window_info id="Build Variants" order="2" side_tool="true" />
|
||||
<window_info id="Image Layers" order="5" />
|
||||
<window_info anchor="bottom" id="Run" order="2" sideWeight="0.4973545" weight="0.32161874" />
|
||||
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
|
||||
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
|
||||
@ -414,25 +470,29 @@
|
||||
<window_info anchor="bottom" id="Android Profiler" order="7" show_stripe_button="false" />
|
||||
<window_info anchor="right" id="Commander" order="0" weight="0.4" />
|
||||
<window_info anchor="bottom" id="Event Log" order="8" sideWeight="0.5026455" side_tool="true" weight="0.31735888" />
|
||||
<window_info anchor="bottom" id="TODO" order="6" />
|
||||
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
||||
<window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.18376623" />
|
||||
<window_info anchor="right" id="Device File Explorer" order="4" side_tool="true" />
|
||||
<window_info anchor="right" id="Flutter Outline" order="3" weight="0.32936507" />
|
||||
<window_info anchor="bottom" id="Logcat" order="11" />
|
||||
<window_info anchor="bottom" id="Dependency Viewer" order="13" weight="0.32800853" />
|
||||
<window_info anchor="bottom" id="Version Control" order="9" />
|
||||
<window_info anchor="bottom" id="Terminal" order="10" sideWeight="0.4973545" visible="true" weight="0.27888888" />
|
||||
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
||||
<window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.18376623" />
|
||||
<window_info anchor="bottom" id="Messages" order="12" weight="0.23777778" />
|
||||
<window_info anchor="bottom" id="Message" order="0" />
|
||||
<window_info anchor="bottom" id="TODO" order="6" />
|
||||
<window_info id="Image Layers" order="5" />
|
||||
<window_info anchor="right" id="Palette	" order="5" />
|
||||
<window_info anchor="right" id="Theme Preview" order="7" />
|
||||
<window_info id="Structure" order="1" weight="0.24969475" />
|
||||
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
||||
<window_info anchor="bottom" id="Find" order="1" weight="0.3290735" />
|
||||
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
|
||||
</layout-to-restore>
|
||||
</component>
|
||||
<component name="UnknownFeatures">
|
||||
<option featureType="com.intellij.fileTypeFactory" implementationName="*.css" />
|
||||
</component>
|
||||
<component name="VcsContentAnnotationSettings">
|
||||
<option name="myLimit" value="2678400000" />
|
||||
</component>
|
||||
@ -442,21 +502,6 @@
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
<component name="editorHistoryManager">
|
||||
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="270">
|
||||
<caret line="18" column="34" lean-forward="true" selection-start-line="18" selection-start-column="34" selection-end-line="18" selection-end-column="34" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="135">
|
||||
<caret line="9" column="34" lean-forward="true" selection-start-line="9" selection-start-column="34" selection-end-line="9" selection-end-column="34" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutterwebview/WebViewActivity.java" />
|
||||
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/java/com/pichillilorenzo/flutterwebviewexample/MainActivity.java">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="135">
|
||||
@ -584,13 +629,6 @@
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state>
|
||||
<caret column="6" selection-start-column="6" selection-end-column="26" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1560">
|
||||
@ -647,30 +685,6 @@
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state>
|
||||
<caret line="1" column="64" selection-start-line="1" selection-start-column="64" selection-end-line="1" selection-end-column="64" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/README.md">
|
||||
<provider selected="true" editor-type-id="split-provider[text-editor;MarkdownPreviewEditor]">
|
||||
<state split_layout="SPLIT">
|
||||
<first_editor relative-caret-position="256">
|
||||
<caret line="52" column="66" selection-start-line="52" selection-start-column="66" selection-end-line="52" selection-end-column="66" />
|
||||
</first_editor>
|
||||
<second_editor>
|
||||
<markdownNavigatorState />
|
||||
</second_editor>
|
||||
</state>
|
||||
</provider>
|
||||
<provider editor-type-id="text-editor">
|
||||
<state relative-caret-position="247">
|
||||
<caret line="19" column="15" selection-start-line="19" selection-start-column="3" selection-end-line="19" selection-end-column="15" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/flutter_inappbrowser.iml">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="330">
|
||||
@ -692,39 +706,92 @@
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart">
|
||||
<entry file="file://$PROJECT_DIR$/example/assets/images/dart.svg">
|
||||
<provider selected="true" editor-type-id="images">
|
||||
<state />
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/example/assets/css/style.css">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="5791">
|
||||
<caret line="429" column="3" selection-start-line="429" selection-start-column="3" selection-end-line="429" selection-end-column="3" />
|
||||
<folding>
|
||||
<element signature="e#814#834#0" expanded="true" />
|
||||
</folding>
|
||||
<state relative-caret-position="75">
|
||||
<caret line="5" column="20" selection-start-line="5" selection-start-column="20" selection-end-line="5" selection-end-column="20" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/example/assets/index.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="435">
|
||||
<caret line="29" column="29" selection-start-line="29" selection-start-column="29" selection-end-line="29" selection-end-column="29" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="30">
|
||||
<caret line="2" column="14" selection-start-line="2" selection-start-column="14" selection-end-line="2" selection-end-column="14" />
|
||||
<state relative-caret-position="180">
|
||||
<caret line="12" column="14" selection-start-line="12" selection-start-column="14" selection-end-line="12" selection-end-column="14" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
|
||||
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="405">
|
||||
<caret line="27" column="13" selection-start-line="27" selection-start-column="13" selection-end-line="27" selection-end-column="13" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="165">
|
||||
<caret line="165" column="42" selection-start-line="165" selection-start-column="42" selection-end-line="165" selection-end-column="42" />
|
||||
<folding>
|
||||
<element signature="e#0#20#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="128">
|
||||
<caret line="82" column="21" selection-start-line="82" selection-start-column="6" selection-end-line="82" selection-end-column="21" />
|
||||
<folding>
|
||||
<element signature="e#814#831#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/README.md">
|
||||
<provider editor-type-id="text-editor">
|
||||
<state relative-caret-position="247">
|
||||
<caret line="19" column="15" selection-start-line="19" selection-start-column="3" selection-end-line="19" selection-end-column="15" />
|
||||
</state>
|
||||
</provider>
|
||||
<provider selected="true" editor-type-id="split-provider[text-editor;MarkdownPreviewEditor]">
|
||||
<state split_layout="SPLIT">
|
||||
<first_editor relative-caret-position="30">
|
||||
<caret line="2" column="39" selection-start-line="2" selection-start-column="39" selection-end-line="2" selection-end-column="39" />
|
||||
<first_editor relative-caret-position="4980">
|
||||
<caret line="332" column="20" lean-forward="true" selection-start-line="332" selection-start-column="20" selection-end-line="332" selection-end-column="41" />
|
||||
</first_editor>
|
||||
<second_editor>
|
||||
<markdownNavigatorState />
|
||||
</second_editor>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
|
||||
<provider editor-type-id="text-editor">
|
||||
<state relative-caret-position="30">
|
||||
<caret line="2" column="69" lean-forward="true" selection-start-line="2" selection-start-column="2" selection-end-line="2" selection-end-column="73" />
|
||||
</state>
|
||||
</provider>
|
||||
<provider selected="true" editor-type-id="split-provider[text-editor;MarkdownPreviewEditor]">
|
||||
<state split_layout="SPLIT">
|
||||
<first_editor relative-caret-position="135">
|
||||
<caret line="9" lean-forward="true" selection-start-line="9" selection-end-line="9" />
|
||||
</first_editor>
|
||||
<second_editor>
|
||||
<markdownNavigatorState />
|
||||
</second_editor>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</component>
|
||||
<component name="masterDetails">
|
||||
|
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,3 +1,13 @@
|
||||
## 0.4.0
|
||||
|
||||
- removed `target` parameter to `InAppBrowser.open()` method. To open the url on the system browser, use the `openWithSystemBrowser: true` option
|
||||
- fixes for the `_ChannelManager` private class
|
||||
- fixed `EXC_BAD_INSTRUCTION` onLoadStart in Swift
|
||||
- added `openWithSystemBrowser` and `isLocalFile` options
|
||||
- added `InAppBrowser.openWithSystemBrowser` method
|
||||
- added `InAppBrowser.openOnLocalhost` method
|
||||
- added `InAppBrowser.loadFile` method
|
||||
|
||||
## 0.3.2
|
||||
|
||||
- fixed WebView.storyboard path for iOS
|
||||
|
147
README.md
147
README.md
@ -56,13 +56,13 @@ class MyInAppBrowser extends InAppBrowser {
|
||||
await this.injectScriptCode("console.log({'testObject': 5});"); // the message will be: [object Object]
|
||||
await this.injectScriptCode("console.log('testObjectStringify', JSON.stringify({'testObject': 5}));"); // the message will be: testObjectStringify {"testObject": 5}
|
||||
await this.injectScriptCode("console.error('testError', false);"); // the message will be: testError false
|
||||
|
||||
|
||||
// add jquery library and custom javascript
|
||||
await this.injectScriptFile("https://code.jquery.com/jquery-3.3.1.min.js");
|
||||
this.injectScriptCode("""
|
||||
\$( "body" ).html( "Next Step..." )
|
||||
""");
|
||||
|
||||
|
||||
// add custom css
|
||||
this.injectStyleCode("""
|
||||
body {
|
||||
@ -81,7 +81,7 @@ class MyInAppBrowser extends InAppBrowser {
|
||||
void onExit() {
|
||||
print("\n\nBrowser closed!\n\n");
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
void shouldOverrideUrlLoading(String url) {
|
||||
print("\n\n override $url\n\n");
|
||||
@ -136,8 +136,8 @@ class _MyAppState extends State<MyApp> {
|
||||
title: const Text('Flutter InAppBrowser Plugin example app'),
|
||||
),
|
||||
body: new Center(
|
||||
child: new RaisedButton(onPressed: () {
|
||||
inAppBrowser.open(url: "https://flutter.io/", options: {
|
||||
child: new RaisedButton(onPressed: () async {
|
||||
await inAppBrowser.open(url: "https://flutter.io/", options: {
|
||||
"useShouldOverrideUrlLoading": true,
|
||||
"useOnLoadResource": true
|
||||
});
|
||||
@ -155,8 +155,10 @@ class _MyAppState extends State<MyApp> {
|
||||
|
||||
Opens a URL in a new InAppBrowser instance or the system browser.
|
||||
|
||||
**NOTE**: If you open the given `url` with the system browser (`openWithSystemBrowser: true`), you wont be able to use the `InAppBrowser` methods!
|
||||
|
||||
```dart
|
||||
inAppBrowser.open({String url = "about:blank", Map<String, String> headers = const {}, String target = "_self", Map<String, dynamic> options = const {}});
|
||||
inAppBrowser.open({String url = "about:blank", Map<String, String> headers = const {}, Map<String, dynamic> options = const {}});
|
||||
```
|
||||
|
||||
Opens an `url` in a new `InAppBrowser` instance or the system browser.
|
||||
@ -165,17 +167,13 @@ Opens an `url` in a new `InAppBrowser` instance or the system browser.
|
||||
|
||||
- `headers`: The additional headers to be used in the HTTP request for this URL, specified as a map from name to value.
|
||||
|
||||
- `target`: The target in which to load the `url`, an optional parameter that defaults to `_self`.
|
||||
|
||||
- `_self`: Opens in the `InAppBrowser`.
|
||||
- `_blank`: Opens in the `InAppBrowser`.
|
||||
- `_system`: Opens in the system's web browser.
|
||||
|
||||
- `options`: Options for the `InAppBrowser`.
|
||||
|
||||
All platforms support:
|
||||
- __useShouldOverrideUrlLoading__: Set to `true` to be able to listen at the `shouldOverrideUrlLoading` event. The default value is `false`.
|
||||
- __useOnLoadResource__: Set to `true` to be able to listen at the `onLoadResource()` event. The default value is `false`.
|
||||
- __openWithSystemBrowser__: Set to `true` to open the given `url` with the system browser. The default value is `false`.
|
||||
- __isLocalFile__: Set to `true` if the `url` is pointing to a local file (the file must be addded in the `assets` section of your `pubspec.yaml`. See `loadFile()` explanation). The default value is `false`.
|
||||
- __clearCache__: Set to `true` to have all the browser's cache cleared before the new window is opened. The default value is `false`.
|
||||
- __userAgent___: Set the custom WebView's user-agent.
|
||||
- __javaScriptEnabled__: Set to `true` to enable JavaScript. The default value is `true`.
|
||||
@ -185,9 +183,9 @@ Opens an `url` in a new `InAppBrowser` instance or the system browser.
|
||||
- __toolbarTopBackgroundColor__: Set the custom background color of the toolbat at the top.
|
||||
- __hideUrlBar__: Set to `true` to hide the url bar on the toolbar at the top. The default value is `false`.
|
||||
- __mediaPlaybackRequiresUserGesture__: Set to `true` to prevent HTML5 audio or video from autoplaying. The default value is `true`.
|
||||
|
||||
|
||||
**Android** supports these additional options:
|
||||
|
||||
|
||||
- __hideTitleBar__: Set to `true` if you want the title should be displayed. The default value is `false`.
|
||||
- __closeOnCannotGoBack__: Set to `false` to not close the InAppBrowser when the user click on the back button and the WebView cannot go back to the history. The default value is `true`.
|
||||
- __clearSessionCache__: Set to `true` to have the session cookie cache cleared before the new window is opened.
|
||||
@ -200,14 +198,14 @@ Opens an `url` in a new `InAppBrowser` instance or the system browser.
|
||||
- __progressBar__: Set to `false` to hide the progress bar at the bottom of the toolbar at the top. The default value is `true`.
|
||||
|
||||
**iOS** supports these additional options:
|
||||
|
||||
|
||||
- __disallowOverScroll__: Set to `true` to disable the bouncing of the WebView when the scrolling has reached an edge of the content. The default value is `false`.
|
||||
- __toolbarBottom__: Set to `false` to hide the toolbar at the bottom of the WebView. The default value is `true`.
|
||||
- __toolbarBottomBackgroundColor__: Set the custom background color of the toolbat at the bottom.
|
||||
- __toolbarBottomTranslucent__: Set to `true` to set the toolbar at the bottom translucent. The default value is `true`.
|
||||
- __closeButtonCaption__: Set the custom text for the close button.
|
||||
- __closeButtonColor__: Set the custom color for the close button.
|
||||
- __presentationStyle__: Set the custom modal presentation style when presenting the WebView. The default value is `0 //fullscreen`. See [UIModalPresentationStyle](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle) for all the available styles.
|
||||
- __presentationStyle__: Set the custom modal presentation style when presenting the WebView. The default value is `0 //fullscreen`. See [UIModalPresentationStyle](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle) for all the available styles.
|
||||
- __transitionStyle__: Set to the custom transition style when presenting the WebView. The default value is `0 //crossDissolve`. See [UIModalTransitionStyle](https://developer.apple.com/documentation/uikit/uimodaltransitionStyle) for all the available styles.
|
||||
- __enableViewportScale__: Set to `true` to allow a viewport meta tag to either disable or restrict the range of user scaling. The default value is `false`.
|
||||
- __suppressesIncrementalRendering__: Set to `true` if you want the WebView suppresses content rendering until it is fully loaded into memory.. The default value is `false`.
|
||||
@ -218,7 +216,7 @@ Opens an `url` in a new `InAppBrowser` instance or the system browser.
|
||||
- __allowsInlineMediaPlayback__: Set to `true` to allow HTML5 media playback to appear inline within the screen layout, using browser-supplied controls rather than native controls. For this to work, add the `webkit-playsinline` attribute to any `<video>` elements. The default value is `false`.
|
||||
- __allowsPictureInPictureMediaPlayback__: Set to `true` to allow HTML5 videos play picture-in-picture. The default value is `true`.
|
||||
- __spinner__: Set to `false` to hide the spinner when the WebView is loading a page. The default value is `true`.
|
||||
|
||||
|
||||
Example:
|
||||
```dart
|
||||
inAppBrowser.open('https://flutter.io/', options: {
|
||||
@ -231,7 +229,34 @@ inAppBrowser.open('https://flutter.io/', options: {
|
||||
"toolbarBottomTranslucent": false,
|
||||
"allowsLinkPreview": false
|
||||
});
|
||||
```
|
||||
```
|
||||
|
||||
#### static Future\<void\> InAppBrowser.openWithSystemBrowser
|
||||
|
||||
This is a static method that opens an `url` in the system browser.
|
||||
This has the same behaviour of an `InAppBrowser` instance calling the `open()` method with option `openWithSystemBrowser: true`.
|
||||
|
||||
```dart
|
||||
InAppBrowser.openWithSystemBrowser(String url);
|
||||
```
|
||||
|
||||
#### Future\<void\> InAppBrowser.openOnLocalhost
|
||||
|
||||
Serve the `assetFilePath` from Flutter assets on http://localhost:`port`/. It is similar to `InAppBrowser.open()` with option `isLocalFile: true`, but it starts a server.
|
||||
|
||||
**NOTE for iOS**: For the iOS Platform, you need to add the `NSAllowsLocalNetworking` key with `true` in the `Info.plist` file (See [ATS Configuration Basics](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35):
|
||||
```xml
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
<true/>
|
||||
</dict>
|
||||
```
|
||||
The `NSAllowsLocalNetworking` key is available since **iOS 10**.
|
||||
|
||||
```dart
|
||||
inAppBrowser.openOnLocalhost(String assetFilePath, {int port = 8080, Map<String, String> headers = const {}, Map<String, dynamic> options = const {}});
|
||||
```
|
||||
|
||||
#### Events
|
||||
|
||||
@ -239,7 +264,7 @@ Event fires when the `InAppBrowser` starts to load an `url`.
|
||||
```dart
|
||||
@override
|
||||
void onLoadStart(String url) {
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@ -247,7 +272,7 @@ Event fires when the `InAppBrowser` finishes loading an `url`.
|
||||
```dart
|
||||
@override
|
||||
void onLoadStop(String url) {
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@ -255,7 +280,7 @@ Event fires when the `InAppBrowser` encounters an error loading an `url`.
|
||||
```dart
|
||||
@override
|
||||
void onLoadError(String url, String code, String message) {
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@ -263,7 +288,7 @@ Event fires when the `InAppBrowser` window is closed.
|
||||
```dart
|
||||
@override
|
||||
void onExit() {
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@ -305,13 +330,49 @@ Loads the given `url` with optional `headers` specified as a map from name to va
|
||||
inAppBrowser.loadUrl(String url, {Map<String, String> headers = const {}});
|
||||
```
|
||||
|
||||
#### Future\<void\> InAppBrowser.loadFile
|
||||
|
||||
Loads the given `assetFilePath` with optional `headers` specified as a map from name to value.
|
||||
|
||||
To be able to load your local files (assets, js, css, etc.), you need to add them in the `assets` section of the `pubspec.yaml` file, otherwise they cannot be found!
|
||||
|
||||
Example of a `pubspec.yaml` file:
|
||||
```yaml
|
||||
...
|
||||
|
||||
# The following section is specific to Flutter.
|
||||
flutter:
|
||||
|
||||
# The following line ensures that the Material Icons font is
|
||||
# included with your application, so that you can use the icons in
|
||||
# the material Icons class.
|
||||
uses-material-design: true
|
||||
|
||||
assets:
|
||||
- assets/index.html
|
||||
- assets/css/
|
||||
- assets/images/
|
||||
|
||||
...
|
||||
```
|
||||
Example of a `main.dart` file:
|
||||
```dart
|
||||
...
|
||||
inAppBrowser.loadFile("assets/index.html");
|
||||
...
|
||||
```
|
||||
|
||||
```dart
|
||||
inAppBrowser.loadFile(String assetFilePath, {Map<String, String> headers = const {}});
|
||||
```
|
||||
|
||||
#### Future\<void\> InAppBrowser.show
|
||||
|
||||
Displays an `InAppBrowser` window that was opened hidden. Calling this has no effect if the `InAppBrowser` was already visible.
|
||||
|
||||
```dart
|
||||
inAppBrowser.show();
|
||||
```
|
||||
```
|
||||
|
||||
#### Future\<void\> InAppBrowser.hide
|
||||
|
||||
@ -319,7 +380,7 @@ Hides the `InAppBrowser` window. Calling this has no effect if the `InAppBrowser
|
||||
|
||||
```dart
|
||||
inAppBrowser.hide();
|
||||
```
|
||||
```
|
||||
|
||||
#### Future\<void\> InAppBrowser.close
|
||||
|
||||
@ -327,7 +388,7 @@ Closes the `InAppBrowser` window.
|
||||
|
||||
```dart
|
||||
inAppBrowser.close();
|
||||
```
|
||||
```
|
||||
|
||||
#### Future\<void\> InAppBrowser.reload
|
||||
|
||||
@ -335,7 +396,7 @@ Reloads the `InAppBrowser` window.
|
||||
|
||||
```dart
|
||||
inAppBrowser.reload();
|
||||
```
|
||||
```
|
||||
|
||||
#### Future\<void\> InAppBrowser.goBack
|
||||
|
||||
@ -343,7 +404,7 @@ Goes back in the history of the `InAppBrowser` window.
|
||||
|
||||
```dart
|
||||
inAppBrowser.goBack();
|
||||
```
|
||||
```
|
||||
|
||||
#### Future\<void\> InAppBrowser.goForward
|
||||
|
||||
@ -351,7 +412,7 @@ Goes forward in the history of the `InAppBrowser` window.
|
||||
|
||||
```dart
|
||||
inAppBrowser.goForward();
|
||||
```
|
||||
```
|
||||
|
||||
#### Future\<bool\> InAppBrowser.isLoading
|
||||
|
||||
@ -359,7 +420,7 @@ Check if the Web View of the `InAppBrowser` instance is in a loading state.
|
||||
|
||||
```dart
|
||||
inAppBrowser.isLoading();
|
||||
```
|
||||
```
|
||||
|
||||
#### Future\<void\> InAppBrowser.stopLoading
|
||||
|
||||
@ -367,7 +428,7 @@ Stops the Web View of the `InAppBrowser` instance from loading.
|
||||
|
||||
```dart
|
||||
inAppBrowser.stopLoading();
|
||||
```
|
||||
```
|
||||
|
||||
#### Future\<bool\> InAppBrowser.isHidden
|
||||
|
||||
@ -375,35 +436,35 @@ Check if the Web View of the `InAppBrowser` instance is hidden.
|
||||
|
||||
```dart
|
||||
inAppBrowser.isHidden();
|
||||
```
|
||||
```
|
||||
|
||||
#### Future\<String\> InAppBrowser.injectScriptCode
|
||||
|
||||
Injects JavaScript code into the `InAppBrowser` window and returns the result of the evaluation. (Only available when the target is set to `_blank` or to `_self`)
|
||||
Injects JavaScript code into the `InAppBrowser` window and returns the result of the evaluation.
|
||||
|
||||
```dart
|
||||
inAppBrowser.injectScriptCode(String source);
|
||||
```
|
||||
```
|
||||
|
||||
#### Future\<void\> InAppBrowser.injectScriptFile
|
||||
|
||||
Injects a JavaScript file into the `InAppBrowser` window. (Only available when the target is set to `_blank` or to `_self`)
|
||||
Injects a JavaScript file into the `InAppBrowser` window.
|
||||
|
||||
```dart
|
||||
inAppBrowser.injectScriptFile(String urlFile);
|
||||
```
|
||||
```
|
||||
|
||||
#### Future\<void\> InAppBrowser.injectStyleCode
|
||||
|
||||
Injects CSS into the `InAppBrowser` window. (Only available when the target is set to `_blank` or to `_self`)
|
||||
Injects CSS into the `InAppBrowser` window.
|
||||
|
||||
```dart
|
||||
inAppBrowser.injectStyleCode(String source);
|
||||
```
|
||||
```
|
||||
|
||||
#### Future\<void\> InAppBrowser.injectStyleFile
|
||||
|
||||
Injects a CSS file into the `InAppBrowser` window. (Only available when the target is set to `_blank` or to `_self`)
|
||||
Injects a CSS file into the `InAppBrowser` window.
|
||||
|
||||
```dart
|
||||
inAppBrowser.injectStyleFile(String urlFile);
|
||||
@ -462,13 +523,13 @@ class MyInAppBrowser extends InAppBrowser {
|
||||
void onExit() {
|
||||
print("\n\nBrowser closed!\n\n");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
MyInAppBrowser inAppBrowserFallback = new MyInAppBrowser();
|
||||
|
||||
class MyChromeSafariBrowser extends ChromeSafariBrowser {
|
||||
|
||||
|
||||
MyChromeSafariBrowser(browserFallback) : super(browserFallback);
|
||||
|
||||
@override
|
||||
@ -579,7 +640,7 @@ Event fires when the `ChromeSafariBrowser` is opened.
|
||||
```dart
|
||||
@override
|
||||
void onOpened() {
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@ -587,7 +648,7 @@ Event fires when the `ChromeSafariBrowser` is loaded.
|
||||
```dart
|
||||
@override
|
||||
void onLoaded() {
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@ -595,7 +656,7 @@ Event fires when the `ChromeSafariBrowser` is closed.
|
||||
```dart
|
||||
@override
|
||||
void onClosed() {
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -25,6 +25,7 @@ import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Parcelable;
|
||||
import android.provider.Browser;
|
||||
import android.net.Uri;
|
||||
@ -40,8 +41,10 @@ import android.util.Log;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappbrowser.chrome_custom_tabs.ChromeCustomTabsActivity;
|
||||
import com.pichillilorenzo.flutter_inappbrowser.chrome_custom_tabs.ChromeCustomTabsOptions;
|
||||
import com.pichillilorenzo.flutter_inappbrowser.chrome_custom_tabs.CustomTabActivityHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
@ -55,7 +58,9 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
||||
import io.flutter.plugin.common.MethodChannel.Result;
|
||||
import io.flutter.plugin.common.PluginRegistry.Registrar;
|
||||
|
||||
/** InAppBrowserFlutterPlugin */
|
||||
/**
|
||||
* InAppBrowserFlutterPlugin
|
||||
*/
|
||||
public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
|
||||
public static Registrar registrar;
|
||||
@ -64,9 +69,9 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
public static Map<String, WebViewActivity> webViewActivities = new HashMap<>();
|
||||
public static Map<String, ChromeCustomTabsActivity> chromeCustomTabsActivities = new HashMap<>();
|
||||
|
||||
private static final String NULL = "null";
|
||||
protected static final String LOG_TAG = "InAppBrowserFlutterP";
|
||||
protected static final String LOG_TAG = "IABFlutterPlugin";
|
||||
|
||||
static final String ANDROID_ASSET_URL = "file:///android_asset/";
|
||||
|
||||
public InAppBrowserFlutterPlugin(Registrar r, Activity activity) {
|
||||
registrar = r;
|
||||
@ -74,7 +79,9 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
channel = new MethodChannel(registrar.messenger(), "com.pichillilorenzo/flutter_inappbrowser");
|
||||
}
|
||||
|
||||
/** Plugin registration. */
|
||||
/**
|
||||
* Plugin registration.
|
||||
*/
|
||||
public static void registerWith(Registrar registrar) {
|
||||
final MethodChannel channel = new MethodChannel(registrar.messenger(), "com.pichillilorenzo/flutter_inappbrowser");
|
||||
channel.setMethodCallHandler(new InAppBrowserFlutterPlugin(registrar, registrar.activity()));
|
||||
@ -89,15 +96,7 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
|
||||
switch (call.method) {
|
||||
case "open":
|
||||
final String url = call.argument("url").toString();
|
||||
|
||||
String t = call.argument("target").toString();
|
||||
if (t == null || t.equals("") || t.equals(NULL)) {
|
||||
t = "_self";
|
||||
}
|
||||
final String target = t;
|
||||
|
||||
Log.d(LOG_TAG, "target = " + target);
|
||||
final String url_final = call.argument("url").toString();
|
||||
|
||||
final boolean useChromeSafariBrowser = (boolean) call.argument("useChromeSafariBrowser");
|
||||
|
||||
@ -119,19 +118,48 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
final InAppBrowserOptions optionsFallback = new InAppBrowserOptions();
|
||||
optionsFallback.parse((HashMap<String, Object>) call.argument("optionsFallback"));
|
||||
|
||||
open(uuid, uuidFallback, url, options, headers,true, optionsFallback);
|
||||
}
|
||||
else {
|
||||
open(uuid, uuidFallback, url_final, options, headers, true, optionsFallback, result);
|
||||
} else {
|
||||
|
||||
String url = url_final;
|
||||
|
||||
final InAppBrowserOptions options = new InAppBrowserOptions();
|
||||
options.parse((HashMap<String, Object>) call.argument("options"));
|
||||
|
||||
if ("_self".equals(target)) {
|
||||
Log.d(LOG_TAG, "in self");
|
||||
if (options.isLocalFile) {
|
||||
// check if the asset file exists
|
||||
String key = registrar.lookupKeyForAsset(url);
|
||||
AssetManager mg = registrar.activeContext().getResources().getAssets();
|
||||
InputStream is = null;
|
||||
boolean assetExists = false;
|
||||
try {
|
||||
is = mg.open(key);
|
||||
assetExists = true;
|
||||
} catch (IOException ex) {
|
||||
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!assetExists) {
|
||||
result.error(LOG_TAG, key + " asset file cannot be found!", null);
|
||||
return;
|
||||
}
|
||||
url = ANDROID_ASSET_URL + key;
|
||||
}
|
||||
// SYSTEM
|
||||
if (options.openWithSystemBrowser) {
|
||||
Log.d(LOG_TAG, "in system");
|
||||
openExternal(url, result);
|
||||
}
|
||||
else {
|
||||
//Load the dialer
|
||||
if (url.startsWith(WebView.SCHEME_TEL))
|
||||
{
|
||||
if (url.startsWith(WebView.SCHEME_TEL)) {
|
||||
try {
|
||||
Log.d(LOG_TAG, "loading in dialer");
|
||||
Intent intent = new Intent(Intent.ACTION_DIAL);
|
||||
@ -144,31 +172,21 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
// load in InAppBrowserFlutterPlugin
|
||||
else {
|
||||
Log.d(LOG_TAG, "loading in InAppBrowserFlutterPlugin");
|
||||
open(uuid, null, url, options, headers, false, null);
|
||||
open(uuid, null, url, options, headers, false, null, result);
|
||||
}
|
||||
}
|
||||
// SYSTEM
|
||||
else if ("_system".equals(target)) {
|
||||
Log.d(LOG_TAG, "in system");
|
||||
openExternal(url);
|
||||
}
|
||||
// BLANK - or anything else
|
||||
else {
|
||||
Log.d(LOG_TAG, "in blank");
|
||||
open(uuid, null, url, options, headers, false, null);
|
||||
}
|
||||
}
|
||||
|
||||
result.success(true);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "loadUrl":
|
||||
loadUrl(uuid, call.argument("url").toString(), (Map<String, String>) call.argument("headers"), result);
|
||||
break;
|
||||
case "loadFile":
|
||||
loadFile(uuid, call.argument("url").toString(), (Map<String, String>) call.argument("headers"), result);
|
||||
break;
|
||||
case "close":
|
||||
close(uuid);
|
||||
result.success(true);
|
||||
close(uuid, result);
|
||||
break;
|
||||
case "injectScriptCode":
|
||||
source = call.argument("source").toString();
|
||||
@ -237,18 +255,19 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
|
||||
/**
|
||||
* Inject an object (script or style) into the InAppBrowserFlutterPlugin WebView.
|
||||
*
|
||||
* <p>
|
||||
* This is a helper method for the inject{Script|Style}{Code|File} API calls, which
|
||||
* provides a consistent method for injecting JavaScript code into the document.
|
||||
*
|
||||
* <p>
|
||||
* If a wrapper string is supplied, then the source string will be JSON-encoded (adding
|
||||
* quotes) and wrapped using string formatting. (The wrapper string should have a single
|
||||
* '%s' marker)
|
||||
*
|
||||
* @param uuid
|
||||
* @param source The source object (filename or script/style text) to inject into
|
||||
* the document.
|
||||
* @param jsWrapper A JavaScript string to wrap the source string in, so that the object
|
||||
* is properly injected, or null if the source string is JavaScript text
|
||||
* @param source The source object (filename or script/style text) to inject into
|
||||
* the document.
|
||||
* @param jsWrapper A JavaScript string to wrap the source string in, so that the object
|
||||
* is properly injected, or null if the source string is JavaScript text
|
||||
* @param result
|
||||
*/
|
||||
private void injectDeferredObject(String uuid, String source, String jsWrapper, final Result result) {
|
||||
@ -259,7 +278,7 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
org.json.JSONArray jsonEsc = new org.json.JSONArray();
|
||||
jsonEsc.put(source);
|
||||
String jsonRepr = jsonEsc.toString();
|
||||
String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
|
||||
String jsonSourceString = jsonRepr.substring(1, jsonRepr.length() - 1);
|
||||
scriptToInject = String.format(jsWrapper, jsonSourceString);
|
||||
} else {
|
||||
scriptToInject = source;
|
||||
@ -295,8 +314,7 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
msg = reader2.nextString();
|
||||
|
||||
result.success(msg);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
result.success("");
|
||||
}
|
||||
|
||||
@ -332,9 +350,10 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
* 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(String url) {
|
||||
public void openExternal(String url, Result result) {
|
||||
try {
|
||||
Intent intent;
|
||||
intent = new Intent(Intent.ACTION_VIEW);
|
||||
@ -349,9 +368,11 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName());
|
||||
// CB-10795: Avoid circular loops by preventing it from opening in the current app
|
||||
this.openExternalExcludeCurrentApp(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, "InAppBrowserFlutterPlugin: Error loading url "+url+":"+ e.toString());
|
||||
Log.d(LOG_TAG, url + " cannot be opened: " + e.toString());
|
||||
result.error(LOG_TAG, url + " cannot be opened!", null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,11 +388,10 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
ArrayList<Intent> targetIntents = new ArrayList<Intent>();
|
||||
for (ResolveInfo ri : activities) {
|
||||
if (!currentPackage.equals(ri.activityInfo.packageName)) {
|
||||
Intent targetIntent = (Intent)intent.clone();
|
||||
Intent targetIntent = (Intent) intent.clone();
|
||||
targetIntent.setPackage(ri.activityInfo.packageName);
|
||||
targetIntents.add(targetIntent);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
hasCurrentPackage = true;
|
||||
}
|
||||
}
|
||||
@ -386,35 +406,57 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
}
|
||||
// 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[] {}));
|
||||
Intent chooser = Intent.createChooser(targetIntents.remove(targetIntents.size() - 1), null);
|
||||
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{}));
|
||||
activity.startActivity(chooser);
|
||||
}
|
||||
}
|
||||
|
||||
public static void open(String uuid, String uuidFallback, final String url, Options options, Map<String, String> headers, boolean useChromeSafariBrowser, InAppBrowserOptions optionsFallback) {
|
||||
Intent intent = new Intent(registrar.activity(), (useChromeSafariBrowser) ? ChromeCustomTabsActivity.class : WebViewActivity.class);
|
||||
public void open(String uuid, String uuidFallback, String url, Options options, Map<String, String> headers, boolean useChromeSafariBrowser, InAppBrowserOptions optionsFallback, Result result) {
|
||||
|
||||
Intent intent = null;
|
||||
Bundle extras = new Bundle();
|
||||
extras.putString("uuid", uuid);
|
||||
extras.putString("url", url);
|
||||
|
||||
extras.putString("uuid", uuid);
|
||||
extras.putSerializable("options", options.getHashMap());
|
||||
extras.putSerializable("headers", (Serializable) headers);
|
||||
if (useChromeSafariBrowser) {
|
||||
extras.putString("uuidFallback", uuidFallback);
|
||||
|
||||
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("optionsFallback", optionsFallback.getHashMap());
|
||||
extras.putSerializable("options", optionsFallback.getHashMap());
|
||||
else
|
||||
extras.putSerializable("optionsFallback", (new InAppBrowserOptions()).getHashMap());
|
||||
extras.putSerializable("options", (new InAppBrowserOptions()).getHashMap());
|
||||
extras.putSerializable("headers", (Serializable) headers);
|
||||
intent = new Intent(activity, WebViewActivity.class);
|
||||
}
|
||||
// native webview
|
||||
else if (!useChromeSafariBrowser) {
|
||||
intent = new Intent(activity, WebViewActivity.class);
|
||||
}
|
||||
else {
|
||||
Log.d(LOG_TAG, "No WebView fallback declared.");
|
||||
}
|
||||
|
||||
intent.putExtras(extras);
|
||||
if (intent != null) {
|
||||
intent.putExtras(extras);
|
||||
activity.startActivity(intent);
|
||||
result.success(true);
|
||||
return;
|
||||
}
|
||||
|
||||
registrar.activity().startActivity(intent);
|
||||
result.error(LOG_TAG, "No WebView fallback declared.", null);
|
||||
}
|
||||
|
||||
public void loadUrl(String uuid, String url, Map<String, String> headers, Result result) {
|
||||
WebViewActivity webViewActivity = webViewActivities.get(uuid);
|
||||
WebViewActivity webViewActivity = webViewActivities.get(uuid);
|
||||
if (webViewActivity != null) {
|
||||
if (headers != null)
|
||||
webViewActivity.loadUrl(url, headers, result);
|
||||
@ -423,6 +465,16 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public void loadFile(String uuid, String url, Map<String, String> headers, Result result) {
|
||||
WebViewActivity webViewActivity = webViewActivities.get(uuid);
|
||||
if (webViewActivity != null) {
|
||||
if (headers != null)
|
||||
webViewActivity.loadFile(url, headers, result);
|
||||
else
|
||||
webViewActivity.loadFile(url, result);
|
||||
}
|
||||
}
|
||||
|
||||
public void show(String uuid) {
|
||||
WebViewActivity webViewActivity = webViewActivities.get(uuid);
|
||||
if (webViewActivity != null)
|
||||
@ -488,7 +540,7 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
}
|
||||
|
||||
|
||||
public static void close(final String uuid) {
|
||||
public static void close(final String uuid, final Result result) {
|
||||
final WebViewActivity webViewActivity = webViewActivities.get(uuid);
|
||||
if (webViewActivity != null) {
|
||||
registrar.activity().runOnUiThread(new Runnable() {
|
||||
@ -501,8 +553,12 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
|
||||
// The JS protects against multiple calls, so this should happen only when
|
||||
// close() is called by other native code.
|
||||
if (webViewActivity == null)
|
||||
if (webViewActivity == null) {
|
||||
if (result != null) {
|
||||
result.success(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
webViewActivity.webView.setWebViewClient(new WebViewClient() {
|
||||
// NB: wait for about:blank before dismissing
|
||||
@ -514,8 +570,14 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
|
||||
// other than your app's UI thread, it can cause unexpected results."
|
||||
// http://developer.android.com/guide/webapps/migrating.html#Threads
|
||||
webViewActivity.webView.loadUrl("about:blank");
|
||||
if (result != null) {
|
||||
result.success(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (result != null) {
|
||||
result.success(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,29 +2,31 @@ package com.pichillilorenzo.flutter_inappbrowser;
|
||||
|
||||
public class InAppBrowserOptions extends Options {
|
||||
|
||||
final static String LOG_TAG = "InAppBrowserOptions";
|
||||
static final String LOG_TAG = "InAppBrowserOptions";
|
||||
|
||||
public boolean useShouldOverrideUrlLoading = false;
|
||||
public boolean useOnLoadResource = false;
|
||||
public boolean clearCache = false;
|
||||
public String userAgent = "";
|
||||
public boolean javaScriptEnabled = true;
|
||||
public boolean javaScriptCanOpenWindowsAutomatically = false;
|
||||
public boolean hidden = false;
|
||||
public boolean toolbarTop = true;
|
||||
public String toolbarTopBackgroundColor = "";
|
||||
public String toolbarTopFixedTitle = "";
|
||||
public boolean hideUrlBar = false;
|
||||
public boolean mediaPlaybackRequiresUserGesture = true;
|
||||
public boolean useShouldOverrideUrlLoading = false;
|
||||
public boolean useOnLoadResource = false;
|
||||
public boolean openWithSystemBrowser = false;
|
||||
public boolean clearCache = false;
|
||||
public String userAgent = "";
|
||||
public boolean javaScriptEnabled = true;
|
||||
public boolean javaScriptCanOpenWindowsAutomatically = false;
|
||||
public boolean hidden = false;
|
||||
public boolean toolbarTop = true;
|
||||
public String toolbarTopBackgroundColor = "";
|
||||
public String toolbarTopFixedTitle = "";
|
||||
public boolean hideUrlBar = false;
|
||||
public boolean mediaPlaybackRequiresUserGesture = true;
|
||||
public boolean isLocalFile = false;
|
||||
|
||||
public boolean hideTitleBar = false;
|
||||
public boolean closeOnCannotGoBack = true;
|
||||
public boolean clearSessionCache = false;
|
||||
public boolean builtInZoomControls = false;
|
||||
public boolean supportZoom = true;
|
||||
public boolean databaseEnabled = false;
|
||||
public boolean domStorageEnabled = false;
|
||||
public boolean useWideViewPort = true;
|
||||
public boolean safeBrowsingEnabled = true;
|
||||
public boolean progressBar = true;
|
||||
public boolean hideTitleBar = false;
|
||||
public boolean closeOnCannotGoBack = true;
|
||||
public boolean clearSessionCache = false;
|
||||
public boolean builtInZoomControls = false;
|
||||
public boolean supportZoom = true;
|
||||
public boolean databaseEnabled = false;
|
||||
public boolean domStorageEnabled = false;
|
||||
public boolean useWideViewPort = true;
|
||||
public boolean safeBrowsingEnabled = true;
|
||||
public boolean progressBar = true;
|
||||
}
|
||||
|
@ -16,112 +16,111 @@ import java.util.Map;
|
||||
|
||||
public class InAppBrowserWebChromeClient extends WebChromeClient {
|
||||
|
||||
protected static final String LOG_TAG = "IABWebChromeClient";
|
||||
private WebViewActivity activity;
|
||||
private ValueCallback<Uri[]> mUploadMessageArray;
|
||||
private ValueCallback<Uri> mUploadMessage;
|
||||
private final static int FILECHOOSER_RESULTCODE=1;
|
||||
protected static final String LOG_TAG = "IABWebChromeClient";
|
||||
private WebViewActivity activity;
|
||||
private ValueCallback<Uri[]> mUploadMessageArray;
|
||||
private ValueCallback<Uri> mUploadMessage;
|
||||
private final static int FILECHOOSER_RESULTCODE = 1;
|
||||
|
||||
public InAppBrowserWebChromeClient(WebViewActivity activity) {
|
||||
super();
|
||||
this.activity = activity;
|
||||
public InAppBrowserWebChromeClient(WebViewActivity activity) {
|
||||
super();
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", activity.uuid);
|
||||
obj.put("sourceURL", consoleMessage.sourceId());
|
||||
obj.put("lineNumber", consoleMessage.lineNumber());
|
||||
obj.put("message", consoleMessage.message());
|
||||
obj.put("messageLevel", consoleMessage.messageLevel().toString());
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onConsoleMessage", obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(WebView view, int progress) {
|
||||
if (activity.progressBar != null) {
|
||||
activity.progressBar.setVisibility(View.VISIBLE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
activity.progressBar.setProgress(progress, true);
|
||||
} else {
|
||||
activity.progressBar.setProgress(progress);
|
||||
}
|
||||
if (progress == 100) {
|
||||
activity.progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
super.onProgressChanged(view, progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", activity.uuid);
|
||||
obj.put("sourceURL", consoleMessage.sourceId());
|
||||
obj.put("lineNumber", consoleMessage.lineNumber());
|
||||
obj.put("message", consoleMessage.message());
|
||||
obj.put("messageLevel", consoleMessage.messageLevel().toString());
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onConsoleMessage", obj);
|
||||
return true;
|
||||
@Override
|
||||
public void onReceivedTitle(WebView view, String title) {
|
||||
super.onReceivedTitle(view, title);
|
||||
if (activity.actionBar != null && activity.options.toolbarTopFixedTitle.isEmpty())
|
||||
activity.actionBar.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedIcon(WebView view, Bitmap icon) {
|
||||
super.onReceivedIcon(view, icon);
|
||||
}
|
||||
|
||||
//The undocumented magic method override
|
||||
//Eclipse will swear at you if you try to put @Override here
|
||||
// For Android 3.0+
|
||||
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
|
||||
|
||||
mUploadMessage = uploadMsg;
|
||||
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
i.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
i.setType("image/*");
|
||||
activity.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
|
||||
|
||||
}
|
||||
|
||||
// For Android 3.0+
|
||||
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
|
||||
mUploadMessage = uploadMsg;
|
||||
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
i.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
i.setType("*/*");
|
||||
activity.startActivityForResult(
|
||||
Intent.createChooser(i, "File Browser"),
|
||||
FILECHOOSER_RESULTCODE);
|
||||
}
|
||||
|
||||
//For Android 4.1
|
||||
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
|
||||
mUploadMessage = uploadMsg;
|
||||
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
i.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
i.setType("image/*");
|
||||
activity.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
|
||||
|
||||
}
|
||||
|
||||
//For Android 5.0+
|
||||
public boolean onShowFileChooser(
|
||||
WebView webView, ValueCallback<Uri[]> filePathCallback,
|
||||
FileChooserParams fileChooserParams) {
|
||||
if (mUploadMessageArray != null) {
|
||||
mUploadMessageArray.onReceiveValue(null);
|
||||
}
|
||||
mUploadMessageArray = filePathCallback;
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(WebView view, int progress) {
|
||||
if (activity.progressBar != null) {
|
||||
activity.progressBar.setVisibility(View.VISIBLE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
activity.progressBar.setProgress(progress, true);
|
||||
}
|
||||
else {
|
||||
activity.progressBar.setProgress(progress);
|
||||
}
|
||||
if (progress == 100) {
|
||||
activity.progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
super.onProgressChanged(view, progress);
|
||||
}
|
||||
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
contentSelectionIntent.setType("*/*");
|
||||
Intent[] intentArray;
|
||||
intentArray = new Intent[0];
|
||||
|
||||
@Override
|
||||
public void onReceivedTitle(WebView view, String title) {
|
||||
super.onReceivedTitle(view, title);
|
||||
if (activity.actionBar != null && activity.options.toolbarTopFixedTitle.isEmpty())
|
||||
activity.actionBar.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedIcon(WebView view, Bitmap icon) {
|
||||
super.onReceivedIcon(view, icon);
|
||||
}
|
||||
|
||||
//The undocumented magic method override
|
||||
//Eclipse will swear at you if you try to put @Override here
|
||||
// For Android 3.0+
|
||||
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
|
||||
|
||||
mUploadMessage = uploadMsg;
|
||||
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
i.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
i.setType("image/*");
|
||||
activity.startActivityForResult(Intent.createChooser(i,"File Chooser"), FILECHOOSER_RESULTCODE);
|
||||
|
||||
}
|
||||
|
||||
// For Android 3.0+
|
||||
public void openFileChooser( ValueCallback uploadMsg, String acceptType ) {
|
||||
mUploadMessage = uploadMsg;
|
||||
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
i.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
i.setType("*/*");
|
||||
activity.startActivityForResult(
|
||||
Intent.createChooser(i, "File Browser"),
|
||||
FILECHOOSER_RESULTCODE);
|
||||
}
|
||||
|
||||
//For Android 4.1
|
||||
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
|
||||
mUploadMessage = uploadMsg;
|
||||
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
i.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
i.setType("image/*");
|
||||
activity.startActivityForResult( Intent.createChooser( i, "File Chooser" ), FILECHOOSER_RESULTCODE );
|
||||
|
||||
}
|
||||
|
||||
//For Android 5.0+
|
||||
public boolean onShowFileChooser(
|
||||
WebView webView, ValueCallback<Uri[]> filePathCallback,
|
||||
FileChooserParams fileChooserParams){
|
||||
if(mUploadMessageArray != null){
|
||||
mUploadMessageArray.onReceiveValue(null);
|
||||
}
|
||||
mUploadMessageArray = filePathCallback;
|
||||
|
||||
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
contentSelectionIntent.setType("*/*");
|
||||
Intent[] intentArray;
|
||||
intentArray = new Intent[0];
|
||||
|
||||
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
|
||||
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
|
||||
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
|
||||
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
|
||||
activity.startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
|
||||
return true;
|
||||
}
|
||||
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
|
||||
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
|
||||
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
|
||||
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
|
||||
activity.startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -23,337 +23,341 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class InAppBrowserWebViewClient extends WebViewClient {
|
||||
|
||||
protected static final String LOG_TAG = "IABWebViewClient";
|
||||
private WebViewActivity activity;
|
||||
Map<Integer, String> statusCodeMapping = new HashMap<Integer, String>();
|
||||
long startPageTime = 0;
|
||||
protected static final String LOG_TAG = "IABWebViewClient";
|
||||
private WebViewActivity activity;
|
||||
Map<Integer, String> statusCodeMapping = new HashMap<Integer, String>();
|
||||
long startPageTime = 0;
|
||||
|
||||
public InAppBrowserWebViewClient(WebViewActivity activity) {
|
||||
super();
|
||||
this.activity = activity;
|
||||
statusCodeMapping.put(100, "Continue");
|
||||
statusCodeMapping.put(101, "Switching Protocols");
|
||||
statusCodeMapping.put(200, "OK");
|
||||
statusCodeMapping.put(201, "Created");
|
||||
statusCodeMapping.put(202, "Accepted");
|
||||
statusCodeMapping.put(203, "Non-Authoritative Information");
|
||||
statusCodeMapping.put(204, "No Content");
|
||||
statusCodeMapping.put(205, "Reset Content");
|
||||
statusCodeMapping.put(206, "Partial Content");
|
||||
statusCodeMapping.put(300, "Multiple Choices");
|
||||
statusCodeMapping.put(301, "Moved Permanently");
|
||||
statusCodeMapping.put(302, "Found");
|
||||
statusCodeMapping.put(303, "See Other");
|
||||
statusCodeMapping.put(304, "Not Modified");
|
||||
statusCodeMapping.put(307, "Temporary Redirect");
|
||||
statusCodeMapping.put(308, "Permanent Redirect");
|
||||
statusCodeMapping.put(400, "Bad Request");
|
||||
statusCodeMapping.put(401, "Unauthorized");
|
||||
statusCodeMapping.put(403, "Forbidden");
|
||||
statusCodeMapping.put(404, "Not Found");
|
||||
statusCodeMapping.put(405, "Method Not Allowed");
|
||||
statusCodeMapping.put(406, "Not Acceptable");
|
||||
statusCodeMapping.put(407, "Proxy Authentication Required");
|
||||
statusCodeMapping.put(408, "Request Timeout");
|
||||
statusCodeMapping.put(409, "Conflict");
|
||||
statusCodeMapping.put(410, "Gone");
|
||||
statusCodeMapping.put(411, "Length Required");
|
||||
statusCodeMapping.put(412, "Precondition Failed");
|
||||
statusCodeMapping.put(413, "Payload Too Large");
|
||||
statusCodeMapping.put(414, "URI Too Long");
|
||||
statusCodeMapping.put(415, "Unsupported Media Type");
|
||||
statusCodeMapping.put(416, "Range Not Satisfiable");
|
||||
statusCodeMapping.put(417, "Expectation Failed");
|
||||
statusCodeMapping.put(418, "I'm a teapot");
|
||||
statusCodeMapping.put(422, "Unprocessable Entity");
|
||||
statusCodeMapping.put(425, "Too Early");
|
||||
statusCodeMapping.put(426, "Upgrade Required");
|
||||
statusCodeMapping.put(428, "Precondition Required");
|
||||
statusCodeMapping.put(429, "Too Many Requests");
|
||||
statusCodeMapping.put(431, "Request Header Fields Too Large");
|
||||
statusCodeMapping.put(451, "Unavailable For Legal Reasons");
|
||||
statusCodeMapping.put(500, "Internal Server Error");
|
||||
statusCodeMapping.put(501, "Not Implemented");
|
||||
statusCodeMapping.put(502, "Bad Gateway");
|
||||
statusCodeMapping.put(503, "Service Unavailable");
|
||||
statusCodeMapping.put(504, "Gateway Timeout");
|
||||
statusCodeMapping.put(505, "HTTP Version Not Supported");
|
||||
statusCodeMapping.put(511, "Network Authentication Required");
|
||||
public InAppBrowserWebViewClient(WebViewActivity activity) {
|
||||
super();
|
||||
this.activity = activity;
|
||||
statusCodeMapping.put(100, "Continue");
|
||||
statusCodeMapping.put(101, "Switching Protocols");
|
||||
statusCodeMapping.put(200, "OK");
|
||||
statusCodeMapping.put(201, "Created");
|
||||
statusCodeMapping.put(202, "Accepted");
|
||||
statusCodeMapping.put(203, "Non-Authoritative Information");
|
||||
statusCodeMapping.put(204, "No Content");
|
||||
statusCodeMapping.put(205, "Reset Content");
|
||||
statusCodeMapping.put(206, "Partial Content");
|
||||
statusCodeMapping.put(300, "Multiple Choices");
|
||||
statusCodeMapping.put(301, "Moved Permanently");
|
||||
statusCodeMapping.put(302, "Found");
|
||||
statusCodeMapping.put(303, "See Other");
|
||||
statusCodeMapping.put(304, "Not Modified");
|
||||
statusCodeMapping.put(307, "Temporary Redirect");
|
||||
statusCodeMapping.put(308, "Permanent Redirect");
|
||||
statusCodeMapping.put(400, "Bad Request");
|
||||
statusCodeMapping.put(401, "Unauthorized");
|
||||
statusCodeMapping.put(403, "Forbidden");
|
||||
statusCodeMapping.put(404, "Not Found");
|
||||
statusCodeMapping.put(405, "Method Not Allowed");
|
||||
statusCodeMapping.put(406, "Not Acceptable");
|
||||
statusCodeMapping.put(407, "Proxy Authentication Required");
|
||||
statusCodeMapping.put(408, "Request Timeout");
|
||||
statusCodeMapping.put(409, "Conflict");
|
||||
statusCodeMapping.put(410, "Gone");
|
||||
statusCodeMapping.put(411, "Length Required");
|
||||
statusCodeMapping.put(412, "Precondition Failed");
|
||||
statusCodeMapping.put(413, "Payload Too Large");
|
||||
statusCodeMapping.put(414, "URI Too Long");
|
||||
statusCodeMapping.put(415, "Unsupported Media Type");
|
||||
statusCodeMapping.put(416, "Range Not Satisfiable");
|
||||
statusCodeMapping.put(417, "Expectation Failed");
|
||||
statusCodeMapping.put(418, "I'm a teapot");
|
||||
statusCodeMapping.put(422, "Unprocessable Entity");
|
||||
statusCodeMapping.put(425, "Too Early");
|
||||
statusCodeMapping.put(426, "Upgrade Required");
|
||||
statusCodeMapping.put(428, "Precondition Required");
|
||||
statusCodeMapping.put(429, "Too Many Requests");
|
||||
statusCodeMapping.put(431, "Request Header Fields Too Large");
|
||||
statusCodeMapping.put(451, "Unavailable For Legal Reasons");
|
||||
statusCodeMapping.put(500, "Internal Server Error");
|
||||
statusCodeMapping.put(501, "Not Implemented");
|
||||
statusCodeMapping.put(502, "Bad Gateway");
|
||||
statusCodeMapping.put(503, "Service Unavailable");
|
||||
statusCodeMapping.put(504, "Gateway Timeout");
|
||||
statusCodeMapping.put(505, "HTTP Version Not Supported");
|
||||
statusCodeMapping.put(511, "Network Authentication Required");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
|
||||
|
||||
if (activity.options.useShouldOverrideUrlLoading) {
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", activity.uuid);
|
||||
obj.put("url", url);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("shouldOverrideUrlLoading", obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
|
||||
|
||||
if (activity.options.useShouldOverrideUrlLoading) {
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", activity.uuid);
|
||||
obj.put("url", url);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("shouldOverrideUrlLoading", obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (url.startsWith(WebView.SCHEME_TEL)) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_DIAL);
|
||||
intent.setData(Uri.parse(url));
|
||||
activity.startActivity(intent);
|
||||
return true;
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
|
||||
}
|
||||
}
|
||||
else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:") || url.startsWith("intent:")) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(url));
|
||||
activity.startActivity(intent);
|
||||
return true;
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
Log.e(LOG_TAG, "Error with " + url + ": " + e.toString());
|
||||
}
|
||||
}
|
||||
// If sms:5551212?body=This is the message
|
||||
else if (url.startsWith("sms:")) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
|
||||
// Get address
|
||||
String address;
|
||||
int parmIndex = url.indexOf('?');
|
||||
if (parmIndex == -1) {
|
||||
address = url.substring(4);
|
||||
} else {
|
||||
address = url.substring(4, parmIndex);
|
||||
|
||||
// If body, then set sms body
|
||||
Uri uri = Uri.parse(url);
|
||||
String query = uri.getQuery();
|
||||
if (query != null) {
|
||||
if (query.startsWith("body=")) {
|
||||
intent.putExtra("sms_body", query.substring(5));
|
||||
}
|
||||
}
|
||||
}
|
||||
intent.setData(Uri.parse("sms:" + address));
|
||||
intent.putExtra("address", address);
|
||||
intent.setType("vnd.android-dir/mms-sms");
|
||||
activity.startActivity(intent);
|
||||
return true;
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
Log.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return super.shouldOverrideUrlLoading(webView, url);
|
||||
|
||||
if (url.startsWith(WebView.SCHEME_TEL)) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_DIAL);
|
||||
intent.setData(Uri.parse(url));
|
||||
activity.startActivity(intent);
|
||||
return true;
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
|
||||
}
|
||||
} else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:") || url.startsWith("intent:")) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(url));
|
||||
activity.startActivity(intent);
|
||||
return true;
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
Log.e(LOG_TAG, "Error with " + url + ": " + e.toString());
|
||||
}
|
||||
}
|
||||
// If sms:5551212?body=This is the message
|
||||
else if (url.startsWith("sms:")) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
|
||||
|
||||
/*
|
||||
* onPageStarted fires the LOAD_START_EVENT
|
||||
*
|
||||
* @param view
|
||||
* @param url
|
||||
* @param favicon
|
||||
*/
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
super.onPageStarted(view, url, favicon);
|
||||
|
||||
startPageTime = System.currentTimeMillis();
|
||||
|
||||
activity.isLoading = true;
|
||||
|
||||
if (activity.searchView != null && !url.equals(activity.searchView.getQuery().toString())) {
|
||||
activity.searchView.setQuery(url, false);
|
||||
}
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", activity.uuid);
|
||||
obj.put("url", url);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadStart", obj);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
|
||||
activity.isLoading = false;
|
||||
|
||||
// CB-10395 InAppBrowserFlutterPlugin's WebView not storing cookies reliable to local device storage
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
CookieManager.getInstance().flush();
|
||||
// Get address
|
||||
String address;
|
||||
int parmIndex = url.indexOf('?');
|
||||
if (parmIndex == -1) {
|
||||
address = url.substring(4);
|
||||
} else {
|
||||
CookieSyncManager.getInstance().sync();
|
||||
}
|
||||
address = url.substring(4, parmIndex);
|
||||
|
||||
// https://issues.apache.org/jira/browse/CB-11248
|
||||
view.clearFocus();
|
||||
view.requestFocus();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
view.evaluateJavascript(WebViewActivity.consoleLogJS, null);
|
||||
view.evaluateJavascript(JavaScriptBridgeInterface.flutterInAppBroserJSClass, null);
|
||||
}
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", activity.uuid);
|
||||
obj.put("url", url);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadStop", obj);
|
||||
}
|
||||
|
||||
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
|
||||
super.onReceivedError(view, errorCode, description, failingUrl);
|
||||
|
||||
activity.isLoading = false;
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", activity.uuid);
|
||||
obj.put("url", failingUrl);
|
||||
obj.put("code", errorCode);
|
||||
obj.put("message", description);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadError", obj);
|
||||
}
|
||||
|
||||
public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) {
|
||||
super.onReceivedSslError(view, handler, error);
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", activity.uuid);
|
||||
obj.put("url", error.getUrl());
|
||||
obj.put("code", error.getPrimaryError());
|
||||
String message;
|
||||
switch (error.getPrimaryError()) {
|
||||
case SslError.SSL_DATE_INVALID:
|
||||
message = "The date of the certificate is invalid";
|
||||
break;
|
||||
case SslError.SSL_EXPIRED:
|
||||
message = "The certificate has expired";
|
||||
break;
|
||||
case SslError.SSL_IDMISMATCH:
|
||||
message = "Hostname mismatch";
|
||||
break;
|
||||
default:
|
||||
case SslError.SSL_INVALID:
|
||||
message = "A generic error occurred";
|
||||
break;
|
||||
case SslError.SSL_NOTYETVALID:
|
||||
message = "The certificate is not yet valid";
|
||||
break;
|
||||
case SslError.SSL_UNTRUSTED:
|
||||
message = "The certificate authority is not trusted";
|
||||
break;
|
||||
}
|
||||
obj.put("message", "SslError: " + message);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadError", obj);
|
||||
|
||||
handler.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* On received http auth request.
|
||||
*/
|
||||
@Override
|
||||
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
|
||||
// By default handle 401 like we'd normally do!
|
||||
super.onReceivedHttpAuthRequest(view, handler, host, realm);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request){
|
||||
|
||||
if (!request.getMethod().toLowerCase().equals("get") || !activity.options.useOnLoadResource) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String url = request.getUrl().toString();
|
||||
|
||||
try {
|
||||
Request mRequest = new Request.Builder().url(url).build();
|
||||
|
||||
long startResourceTime = System.currentTimeMillis();
|
||||
Response response = activity.httpClient.newCall(mRequest).execute();
|
||||
long startTime = startResourceTime - startPageTime;
|
||||
long duration = System.currentTimeMillis() - startResourceTime;
|
||||
|
||||
if (response.cacheResponse() != null) {
|
||||
duration = 0;
|
||||
// If body, then set sms body
|
||||
Uri uri = Uri.parse(url);
|
||||
String query = uri.getQuery();
|
||||
if (query != null) {
|
||||
if (query.startsWith("body=")) {
|
||||
intent.putExtra("sms_body", query.substring(5));
|
||||
}
|
||||
|
||||
String reasonPhrase = response.message();
|
||||
if (reasonPhrase.equals("")) {
|
||||
reasonPhrase = statusCodeMapping.get(response.code());
|
||||
}
|
||||
reasonPhrase = (reasonPhrase.equals("") || reasonPhrase == null) ? "OK" : reasonPhrase;
|
||||
|
||||
Map<String, String> headersResponse = new HashMap<String, String>();
|
||||
for (Map.Entry<String, List<String>> entry : response.headers().toMultimap().entrySet()) {
|
||||
StringBuilder value = new StringBuilder();
|
||||
for (String val: entry.getValue()) {
|
||||
value.append( (value.toString().isEmpty()) ? val : "; " + val );
|
||||
}
|
||||
headersResponse.put(entry.getKey().toLowerCase(), value.toString());
|
||||
}
|
||||
|
||||
Map<String, String> headersRequest = new HashMap<String, String>();
|
||||
for (Map.Entry<String, List<String>> entry : mRequest.headers().toMultimap().entrySet()) {
|
||||
StringBuilder value = new StringBuilder();
|
||||
for (String val: entry.getValue()) {
|
||||
value.append( (value.toString().isEmpty()) ? val : "; " + val );
|
||||
}
|
||||
headersRequest.put(entry.getKey().toLowerCase(), value.toString());
|
||||
}
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
Map<String, Object> res = new HashMap<>();
|
||||
Map<String, Object> req = new HashMap<>();
|
||||
|
||||
obj.put("uuid", activity.uuid);
|
||||
|
||||
byte[] dataBytes = response.body().bytes();
|
||||
InputStream dataStream = new ByteArrayInputStream(dataBytes);
|
||||
|
||||
res.put("url", url);
|
||||
res.put("statusCode", response.code());
|
||||
res.put("headers", headersResponse);
|
||||
res.put("startTime", startTime);
|
||||
res.put("duration", duration);
|
||||
res.put("data", dataBytes);
|
||||
|
||||
req.put("url", url);
|
||||
req.put("headers", headersRequest);
|
||||
req.put("method", mRequest.method());
|
||||
|
||||
obj.put("response", res);
|
||||
obj.put("request", req);
|
||||
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadResource", obj);
|
||||
|
||||
return new WebResourceResponse(
|
||||
response.header("content-type", "text/plain").split(";")[0].trim(),
|
||||
response.header("content-encoding"),
|
||||
response.code(),
|
||||
reasonPhrase,
|
||||
headersResponse,
|
||||
dataStream
|
||||
);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Log.d(LOG_TAG, e.getMessage());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.d(LOG_TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
intent.setData(Uri.parse("sms:" + address));
|
||||
intent.putExtra("address", address);
|
||||
intent.setType("vnd.android-dir/mms-sms");
|
||||
activity.startActivity(intent);
|
||||
return true;
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
Log.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return super.shouldOverrideUrlLoading(webView, url);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* onPageStarted fires the LOAD_START_EVENT
|
||||
*
|
||||
* @param view
|
||||
* @param url
|
||||
* @param favicon
|
||||
*/
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
super.onPageStarted(view, url, favicon);
|
||||
|
||||
startPageTime = System.currentTimeMillis();
|
||||
|
||||
activity.isLoading = true;
|
||||
|
||||
if (activity.searchView != null && !url.equals(activity.searchView.getQuery().toString())) {
|
||||
activity.searchView.setQuery(url, false);
|
||||
}
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", activity.uuid);
|
||||
obj.put("url", url);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadStart", obj);
|
||||
}
|
||||
|
||||
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
|
||||
activity.isLoading = false;
|
||||
|
||||
// CB-10395 InAppBrowserFlutterPlugin's WebView not storing cookies reliable to local device storage
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
CookieManager.getInstance().flush();
|
||||
} else {
|
||||
CookieSyncManager.getInstance().sync();
|
||||
}
|
||||
|
||||
// https://issues.apache.org/jira/browse/CB-11248
|
||||
view.clearFocus();
|
||||
view.requestFocus();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
view.evaluateJavascript(WebViewActivity.consoleLogJS, null);
|
||||
view.evaluateJavascript(JavaScriptBridgeInterface.flutterInAppBroserJSClass, null);
|
||||
}
|
||||
else {
|
||||
view.loadUrl("javascript:"+WebViewActivity.consoleLogJS);
|
||||
view.loadUrl("javascript:"+JavaScriptBridgeInterface.flutterInAppBroserJSClass);
|
||||
}
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", activity.uuid);
|
||||
obj.put("url", url);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadStop", obj);
|
||||
}
|
||||
|
||||
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
|
||||
super.onReceivedError(view, errorCode, description, failingUrl);
|
||||
|
||||
activity.isLoading = false;
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", activity.uuid);
|
||||
obj.put("url", failingUrl);
|
||||
obj.put("code", errorCode);
|
||||
obj.put("message", description);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadError", obj);
|
||||
}
|
||||
|
||||
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
|
||||
super.onReceivedSslError(view, handler, error);
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", activity.uuid);
|
||||
obj.put("url", error.getUrl());
|
||||
obj.put("code", error.getPrimaryError());
|
||||
String message;
|
||||
switch (error.getPrimaryError()) {
|
||||
case SslError.SSL_DATE_INVALID:
|
||||
message = "The date of the certificate is invalid";
|
||||
break;
|
||||
case SslError.SSL_EXPIRED:
|
||||
message = "The certificate has expired";
|
||||
break;
|
||||
case SslError.SSL_IDMISMATCH:
|
||||
message = "Hostname mismatch";
|
||||
break;
|
||||
default:
|
||||
case SslError.SSL_INVALID:
|
||||
message = "A generic error occurred";
|
||||
break;
|
||||
case SslError.SSL_NOTYETVALID:
|
||||
message = "The certificate is not yet valid";
|
||||
break;
|
||||
case SslError.SSL_UNTRUSTED:
|
||||
message = "The certificate authority is not trusted";
|
||||
break;
|
||||
}
|
||||
obj.put("message", "SslError: " + message);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadError", obj);
|
||||
|
||||
handler.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* On received http auth request.
|
||||
*/
|
||||
@Override
|
||||
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
|
||||
// By default handle 401 like we'd normally do!
|
||||
super.onReceivedHttpAuthRequest(view, handler, host, realm);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
|
||||
|
||||
if (!request.getMethod().toLowerCase().equals("get") || !activity.options.useOnLoadResource) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String url = request.getUrl().toString();
|
||||
|
||||
try {
|
||||
Request mRequest = new Request.Builder().url(url).build();
|
||||
|
||||
long startResourceTime = System.currentTimeMillis();
|
||||
Response response = activity.httpClient.newCall(mRequest).execute();
|
||||
long startTime = startResourceTime - startPageTime;
|
||||
startTime = (startTime < 0) ? 0 : startTime;
|
||||
long duration = System.currentTimeMillis() - startResourceTime;
|
||||
|
||||
if (response.cacheResponse() != null) {
|
||||
duration = 0;
|
||||
}
|
||||
|
||||
String reasonPhrase = response.message();
|
||||
if (reasonPhrase.equals("")) {
|
||||
reasonPhrase = statusCodeMapping.get(response.code());
|
||||
}
|
||||
reasonPhrase = (reasonPhrase.equals("") || reasonPhrase == null) ? "OK" : reasonPhrase;
|
||||
|
||||
Map<String, String> headersResponse = new HashMap<String, String>();
|
||||
for (Map.Entry<String, List<String>> entry : response.headers().toMultimap().entrySet()) {
|
||||
StringBuilder value = new StringBuilder();
|
||||
for (String val : entry.getValue()) {
|
||||
value.append((value.toString().isEmpty()) ? val : "; " + val);
|
||||
}
|
||||
headersResponse.put(entry.getKey().toLowerCase(), value.toString());
|
||||
}
|
||||
|
||||
Map<String, String> headersRequest = new HashMap<String, String>();
|
||||
for (Map.Entry<String, List<String>> entry : mRequest.headers().toMultimap().entrySet()) {
|
||||
StringBuilder value = new StringBuilder();
|
||||
for (String val : entry.getValue()) {
|
||||
value.append((value.toString().isEmpty()) ? val : "; " + val);
|
||||
}
|
||||
headersRequest.put(entry.getKey().toLowerCase(), value.toString());
|
||||
}
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
Map<String, Object> res = new HashMap<>();
|
||||
Map<String, Object> req = new HashMap<>();
|
||||
|
||||
obj.put("uuid", activity.uuid);
|
||||
|
||||
byte[] dataBytes = response.body().bytes();
|
||||
InputStream dataStream = new ByteArrayInputStream(dataBytes);
|
||||
|
||||
res.put("url", url);
|
||||
res.put("statusCode", response.code());
|
||||
res.put("headers", headersResponse);
|
||||
res.put("startTime", startTime);
|
||||
res.put("duration", duration);
|
||||
res.put("data", dataBytes);
|
||||
|
||||
req.put("url", url);
|
||||
req.put("headers", headersRequest);
|
||||
req.put("method", mRequest.method());
|
||||
|
||||
obj.put("response", res);
|
||||
obj.put("request", req);
|
||||
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadResource", obj);
|
||||
|
||||
return new WebResourceResponse(
|
||||
response.header("content-type", "text/plain").split(";")[0].trim(),
|
||||
response.header("content-encoding"),
|
||||
response.code(),
|
||||
reasonPhrase,
|
||||
headersResponse,
|
||||
dataStream
|
||||
);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Log.d(LOG_TAG, e.getMessage());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.d(LOG_TAG, e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -10,9 +10,9 @@ public class JavaScriptBridgeInterface {
|
||||
static final String name = "flutter_inappbrowser";
|
||||
WebViewActivity activity;
|
||||
|
||||
static final String flutterInAppBroserJSClass = "window." + name + ".callHandler = function(handlerName, ...args) {\n" +
|
||||
"window." + name + "._callHandler(handlerName, JSON.stringify(args));\n" +
|
||||
"}\n";
|
||||
static final String flutterInAppBroserJSClass = "window." + name + ".callHandler = function(handlerName, ...args) {" +
|
||||
"window." + name + "._callHandler(handlerName, JSON.stringify(args));" +
|
||||
"}";
|
||||
|
||||
JavaScriptBridgeInterface(WebViewActivity a) {
|
||||
activity = a;
|
||||
|
@ -9,32 +9,33 @@ import java.util.HashMap;
|
||||
|
||||
public class Options {
|
||||
|
||||
final static String LOG_TAG = "";
|
||||
static String LOG_TAG = "";
|
||||
|
||||
public void parse(HashMap<String, Object> options) {
|
||||
Iterator it = options.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, Object> pair = (Map.Entry<String, Object>)it.next();
|
||||
try {
|
||||
this.getClass().getDeclaredField(pair.getKey()).set(this, pair.getValue());
|
||||
} catch (NoSuchFieldException e) {
|
||||
Log.d(LOG_TAG, e.getMessage());
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.d(LOG_TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
public Options parse(HashMap<String, Object> options) {
|
||||
Iterator it = options.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, Object> pair = (Map.Entry<String, Object>) it.next();
|
||||
try {
|
||||
this.getClass().getDeclaredField(pair.getKey()).set(this, pair.getValue());
|
||||
} catch (NoSuchFieldException e) {
|
||||
Log.d(LOG_TAG, e.getMessage());
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.d(LOG_TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public HashMap<String, Object> getHashMap() {
|
||||
HashMap<String, Object> options = new HashMap<>();
|
||||
for (Field f: this.getClass().getDeclaredFields()) {
|
||||
try {
|
||||
options.put(f.getName(), f.get(this));
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.d(LOG_TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
return options;
|
||||
public HashMap<String, Object> getHashMap() {
|
||||
HashMap<String, Object> options = new HashMap<>();
|
||||
for (Field f : this.getClass().getDeclaredFields()) {
|
||||
try {
|
||||
options.put(f.getName(), f.get(this));
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.d(LOG_TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,85 +28,85 @@ import okhttp3.OkHttpClient;
|
||||
|
||||
public class WebViewActivity extends AppCompatActivity {
|
||||
|
||||
String uuid;
|
||||
WebView webView;
|
||||
ActionBar actionBar;
|
||||
InAppBrowserWebViewClient inAppBrowserWebViewClient;
|
||||
InAppBrowserWebChromeClient inAppBrowserWebChromeClient;
|
||||
SearchView searchView;
|
||||
InAppBrowserOptions options;
|
||||
Map<String, String> headers;
|
||||
ProgressBar progressBar;
|
||||
public boolean isLoading = false;
|
||||
public boolean isHidden = false;
|
||||
OkHttpClient httpClient;
|
||||
String uuid;
|
||||
WebView webView;
|
||||
ActionBar actionBar;
|
||||
InAppBrowserWebViewClient inAppBrowserWebViewClient;
|
||||
InAppBrowserWebChromeClient inAppBrowserWebChromeClient;
|
||||
SearchView searchView;
|
||||
InAppBrowserOptions options;
|
||||
Map<String, String> headers;
|
||||
ProgressBar progressBar;
|
||||
public boolean isLoading = false;
|
||||
public boolean isHidden = false;
|
||||
OkHttpClient httpClient;
|
||||
|
||||
static final String consoleLogJS = "(function() {\n"+
|
||||
" var oldLogs = {\n"+
|
||||
" 'log': console.log,\n"+
|
||||
" 'debug': console.debug,\n"+
|
||||
" 'error': console.error,\n"+
|
||||
" 'info': console.info,\n"+
|
||||
" 'warn': console.warn\n"+
|
||||
" };\n"+
|
||||
" for (var k in oldLogs) {\n"+
|
||||
" (function(oldLog) {\n"+
|
||||
" console[oldLog] = function() {\n"+
|
||||
" var message = ''\n"+
|
||||
" for (var i in arguments) {\n"+
|
||||
" if (message == '') {\n"+
|
||||
" message += arguments[i];\n"+
|
||||
" }\n"+
|
||||
" else {\n"+
|
||||
" message += ' ' + arguments[i];\n"+
|
||||
" }\n"+
|
||||
" }\n"+
|
||||
" oldLogs[oldLog].call(console, message);\n"+
|
||||
" }\n"+
|
||||
" })(k);\n"+
|
||||
" }\n"+
|
||||
"})();";
|
||||
static final String consoleLogJS = "(function() {" +
|
||||
" var oldLogs = {" +
|
||||
" 'log': console.log," +
|
||||
" 'debug': console.debug," +
|
||||
" 'error': console.error," +
|
||||
" 'info': console.info," +
|
||||
" 'warn': console.warn" +
|
||||
" };" +
|
||||
" for (var k in oldLogs) {" +
|
||||
" (function(oldLog) {" +
|
||||
" console[oldLog] = function() {" +
|
||||
" var message = '';" +
|
||||
" for (var i in arguments) {" +
|
||||
" if (message == '') {" +
|
||||
" message += arguments[i];" +
|
||||
" }" +
|
||||
" else {" +
|
||||
" message += ' ' + arguments[i];" +
|
||||
" }" +
|
||||
" }" +
|
||||
" oldLogs[oldLog].call(console, message);" +
|
||||
" }" +
|
||||
" })(k);" +
|
||||
" }" +
|
||||
"})();";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_web_view);
|
||||
setContentView(R.layout.activity_web_view);
|
||||
|
||||
webView = findViewById(R.id.webView);
|
||||
webView = findViewById(R.id.webView);
|
||||
|
||||
Bundle b = getIntent().getExtras();
|
||||
uuid = b.getString("uuid");
|
||||
String url = b.getString("url");
|
||||
Bundle b = getIntent().getExtras();
|
||||
uuid = b.getString("uuid");
|
||||
String url = b.getString("url");
|
||||
|
||||
options = new InAppBrowserOptions();
|
||||
options.parse((HashMap<String, Object>) b.getSerializable("options"));
|
||||
options = new InAppBrowserOptions();
|
||||
options.parse((HashMap<String, Object>) b.getSerializable("options"));
|
||||
|
||||
headers = (HashMap<String, String>) b.getSerializable("headers");
|
||||
headers = (HashMap<String, String>) b.getSerializable("headers");
|
||||
|
||||
InAppBrowserFlutterPlugin.webViewActivities.put(uuid, this);
|
||||
InAppBrowserFlutterPlugin.webViewActivities.put(uuid, this);
|
||||
|
||||
actionBar = getSupportActionBar();
|
||||
actionBar = getSupportActionBar();
|
||||
|
||||
prepareWebView();
|
||||
prepareWebView();
|
||||
|
||||
int cacheSize = 10 * 1024 * 1024; // 10MB
|
||||
httpClient = new OkHttpClient().newBuilder().cache(new Cache(getApplicationContext().getCacheDir(), cacheSize)).build();
|
||||
int cacheSize = 10 * 1024 * 1024; // 10MB
|
||||
httpClient = new OkHttpClient().newBuilder().cache(new Cache(getApplicationContext().getCacheDir(), cacheSize)).build();
|
||||
|
||||
webView.loadUrl(url, headers);
|
||||
//webView.loadData("<!DOCTYPE html> <html lang=\"en\"> <head> <meta charset=\"UTF-8\"> <title>Document</title> </head> <body> ciao <img src=\"https://via.placeholder.com/350x150\" /> <img src=\"./images/test\" alt=\"not found\" /></body> </html>", "text/html", "utf8");
|
||||
webView.loadUrl(url, headers);
|
||||
//webView.loadData("<!DOCTYPE assets> <assets lang=\"en\"> <head> <meta charset=\"UTF-8\"> <title>Document</title> </head> <body> ciao <img src=\"https://via.placeholder.com/350x150\" /> <img src=\"./images/test\" alt=\"not found\" /></body> </assets>", "text/assets", "utf8");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareWebView() {
|
||||
private void prepareWebView() {
|
||||
|
||||
webView.addJavascriptInterface(new JavaScriptBridgeInterface(this), JavaScriptBridgeInterface.name);
|
||||
webView.addJavascriptInterface(new JavaScriptBridgeInterface(this), JavaScriptBridgeInterface.name);
|
||||
|
||||
inAppBrowserWebChromeClient = new InAppBrowserWebChromeClient(this);
|
||||
webView.setWebChromeClient(inAppBrowserWebChromeClient);
|
||||
inAppBrowserWebChromeClient = new InAppBrowserWebChromeClient(this);
|
||||
webView.setWebChromeClient(inAppBrowserWebChromeClient);
|
||||
|
||||
inAppBrowserWebViewClient = new InAppBrowserWebViewClient(this);
|
||||
webView.setWebViewClient(inAppBrowserWebViewClient);
|
||||
inAppBrowserWebViewClient = new InAppBrowserWebViewClient(this);
|
||||
webView.setWebViewClient(inAppBrowserWebViewClient);
|
||||
|
||||
// final Activity activity = this;
|
||||
//
|
||||
@ -142,241 +142,256 @@ public class WebViewActivity extends AppCompatActivity {
|
||||
// }
|
||||
// });
|
||||
|
||||
WebSettings settings = webView.getSettings();
|
||||
WebSettings settings = webView.getSettings();
|
||||
|
||||
if (options.hidden)
|
||||
hide();
|
||||
else
|
||||
show();
|
||||
if (options.hidden)
|
||||
hide();
|
||||
else
|
||||
show();
|
||||
|
||||
settings.setJavaScriptEnabled(options.javaScriptEnabled);
|
||||
settings.setJavaScriptCanOpenWindowsAutomatically(options.javaScriptCanOpenWindowsAutomatically);
|
||||
settings.setBuiltInZoomControls(options.builtInZoomControls);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
settings.setSafeBrowsingEnabled(options.safeBrowsingEnabled);
|
||||
settings.setJavaScriptEnabled(options.javaScriptEnabled);
|
||||
settings.setJavaScriptCanOpenWindowsAutomatically(options.javaScriptCanOpenWindowsAutomatically);
|
||||
settings.setBuiltInZoomControls(options.builtInZoomControls);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
settings.setSafeBrowsingEnabled(options.safeBrowsingEnabled);
|
||||
|
||||
settings.setMediaPlaybackRequiresUserGesture(options.mediaPlaybackRequiresUserGesture);
|
||||
settings.setMediaPlaybackRequiresUserGesture(options.mediaPlaybackRequiresUserGesture);
|
||||
|
||||
settings.setDatabaseEnabled(options.databaseEnabled);
|
||||
settings.setDomStorageEnabled(options.domStorageEnabled);
|
||||
settings.setDatabaseEnabled(options.databaseEnabled);
|
||||
settings.setDomStorageEnabled(options.domStorageEnabled);
|
||||
|
||||
if (!options.userAgent.isEmpty())
|
||||
settings.setUserAgentString(options.userAgent);
|
||||
if (!options.userAgent.isEmpty())
|
||||
settings.setUserAgentString(options.userAgent);
|
||||
|
||||
if (options.clearCache)
|
||||
clearCache();
|
||||
else if (options.clearSessionCache)
|
||||
CookieManager.getInstance().removeSessionCookie();
|
||||
if (options.clearCache)
|
||||
clearCache();
|
||||
else if (options.clearSessionCache)
|
||||
CookieManager.getInstance().removeSessionCookie();
|
||||
|
||||
// Enable Thirdparty Cookies on >=Android 5.0 device
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
CookieManager.getInstance().setAcceptThirdPartyCookies(webView,true);
|
||||
// Enable Thirdparty Cookies on >=Android 5.0 device
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true);
|
||||
|
||||
settings.setLoadWithOverviewMode(true);
|
||||
settings.setUseWideViewPort(options.useWideViewPort);
|
||||
settings.setSupportZoom(options.supportZoom);
|
||||
settings.setLoadWithOverviewMode(true);
|
||||
settings.setUseWideViewPort(options.useWideViewPort);
|
||||
settings.setSupportZoom(options.supportZoom);
|
||||
|
||||
// fix webview scaling
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
|
||||
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING);
|
||||
else
|
||||
settings.setTextZoom(100);
|
||||
// fix webview scaling
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
|
||||
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING);
|
||||
else
|
||||
settings.setTextZoom(100);
|
||||
|
||||
if (options.progressBar)
|
||||
progressBar = findViewById(R.id.progressBar);
|
||||
if (options.progressBar)
|
||||
progressBar = findViewById(R.id.progressBar);
|
||||
|
||||
actionBar.setDisplayShowTitleEnabled(!options.hideTitleBar);
|
||||
actionBar.setDisplayShowTitleEnabled(!options.hideTitleBar);
|
||||
|
||||
if (!options.toolbarTop)
|
||||
actionBar.hide();
|
||||
if (!options.toolbarTop)
|
||||
actionBar.hide();
|
||||
|
||||
if (!options.toolbarTopBackgroundColor.isEmpty())
|
||||
actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor(options.toolbarTopBackgroundColor)));
|
||||
if (!options.toolbarTopBackgroundColor.isEmpty())
|
||||
actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor(options.toolbarTopBackgroundColor)));
|
||||
|
||||
if (!options.toolbarTopFixedTitle.isEmpty())
|
||||
actionBar.setTitle(options.toolbarTopFixedTitle);
|
||||
if (!options.toolbarTopFixedTitle.isEmpty())
|
||||
actionBar.setTitle(options.toolbarTopFixedTitle);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
// Inflate menu to add items to action bar if it is present.
|
||||
inflater.inflate(R.menu.menu_main, menu);
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
// Inflate menu to add items to action bar if it is present.
|
||||
inflater.inflate(R.menu.menu_main, menu);
|
||||
|
||||
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
|
||||
searchView.setFocusable(true);
|
||||
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
|
||||
searchView.setFocusable(true);
|
||||
|
||||
if (options.hideUrlBar)
|
||||
menu.findItem(R.id.menu_search).setVisible(false);
|
||||
if (options.hideUrlBar)
|
||||
menu.findItem(R.id.menu_search).setVisible(false);
|
||||
|
||||
searchView.setQuery(webView.getUrl(), false);
|
||||
searchView.setQuery(webView.getUrl(), false);
|
||||
|
||||
if (options.toolbarTopFixedTitle.isEmpty())
|
||||
actionBar.setTitle(webView.getTitle());
|
||||
if (options.toolbarTopFixedTitle.isEmpty())
|
||||
actionBar.setTitle(webView.getTitle());
|
||||
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
if (!query.isEmpty()) {
|
||||
webView.loadUrl(query);
|
||||
searchView.setQuery("", false);
|
||||
searchView.setIconified(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
|
||||
@Override
|
||||
public boolean onClose() {
|
||||
if (searchView.getQuery().toString().isEmpty())
|
||||
searchView.setQuery(webView.getUrl(), false);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void onFocusChange(View view, boolean b) {
|
||||
if (!b) {
|
||||
searchView.setQuery("", false);
|
||||
searchView.setIconified(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void loadUrl (String url, MethodChannel.Result result) {
|
||||
if (webView != null && !url.isEmpty()) {
|
||||
webView.loadUrl(url);
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
if (!query.isEmpty()) {
|
||||
webView.loadUrl(query);
|
||||
searchView.setQuery("", false);
|
||||
searchView.setIconified(true);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
result.error("Cannot load url", "", null);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadUrl (String url, Map<String, String> headers, MethodChannel.Result result) {
|
||||
if (webView != null && !url.isEmpty()) {
|
||||
webView.loadUrl(url, headers);
|
||||
}
|
||||
else {
|
||||
result.error("Cannot load url", "", null);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
|
||||
if (canGoBack())
|
||||
goBack();
|
||||
else if (options.closeOnCannotGoBack)
|
||||
InAppBrowserFlutterPlugin.close(uuid);
|
||||
return true;
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
hide();
|
||||
finish();
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
if (webView != null)
|
||||
webView.reload();
|
||||
}
|
||||
|
||||
public void goBack() {
|
||||
if (webView != null && canGoBack())
|
||||
webView.goBack();
|
||||
}
|
||||
|
||||
public void goForward() {
|
||||
if (webView != null && canGoForward())
|
||||
webView.goForward();
|
||||
}
|
||||
|
||||
public boolean canGoBack() {
|
||||
return webView.canGoBack();
|
||||
}
|
||||
|
||||
public boolean canGoForward() {
|
||||
return webView.canGoForward();
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
isHidden = true;
|
||||
Intent openActivity = new Intent(this, InAppBrowserFlutterPlugin.registrar.activity().getClass());
|
||||
openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
startActivityIfNeeded(openActivity, 0);
|
||||
}
|
||||
public void show() {
|
||||
isHidden = false;
|
||||
Intent openActivity = new Intent(InAppBrowserFlutterPlugin.registrar.activity(), WebViewActivity.class);
|
||||
openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
startActivityIfNeeded(openActivity, 0);
|
||||
}
|
||||
|
||||
public void stopLoading(){
|
||||
if (webView != null)
|
||||
webView.stopLoading();
|
||||
}
|
||||
|
||||
public boolean isLoading() {
|
||||
if (webView != null)
|
||||
return isLoading;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void clearCookies() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
CookieManager.getInstance().removeAllCookies(new ValueCallback<Boolean>() {
|
||||
@Override
|
||||
public void onReceiveValue(Boolean aBoolean) {
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
CookieManager.getInstance().removeAllCookie();
|
||||
});
|
||||
|
||||
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
|
||||
@Override
|
||||
public boolean onClose() {
|
||||
if (searchView.getQuery().toString().isEmpty())
|
||||
searchView.setQuery(webView.getUrl(), false);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void onFocusChange(View view, boolean b) {
|
||||
if (!b) {
|
||||
searchView.setQuery("", false);
|
||||
searchView.setIconified(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
private void clearCache() {
|
||||
webView.clearCache(true);
|
||||
clearCookies();
|
||||
webView.clearFormData();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void goBackButtonClicked(MenuItem item) {
|
||||
public void loadUrl(String url, MethodChannel.Result result) {
|
||||
if (webView != null && !url.isEmpty()) {
|
||||
webView.loadUrl(url);
|
||||
} else {
|
||||
result.error("Cannot load url", "", null);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadUrl(String url, Map<String, String> headers, MethodChannel.Result result) {
|
||||
if (webView != null && !url.isEmpty()) {
|
||||
webView.loadUrl(url, headers);
|
||||
} else {
|
||||
result.error("Cannot load url", "", null);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadFile(String url, MethodChannel.Result result) {
|
||||
if (webView != null && !url.isEmpty()) {
|
||||
webView.loadUrl(url);
|
||||
} else {
|
||||
result.error("Cannot load url", "", null);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadFile(String url, Map<String, String> headers, MethodChannel.Result result) {
|
||||
if (webView != null && !url.isEmpty()) {
|
||||
webView.loadUrl(url, headers);
|
||||
} else {
|
||||
result.error("Cannot load url", "", null);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
|
||||
if (canGoBack())
|
||||
goBack();
|
||||
else if (options.closeOnCannotGoBack)
|
||||
InAppBrowserFlutterPlugin.close(uuid, null);
|
||||
return true;
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
public void goForwardButtonClicked(MenuItem item) {
|
||||
goForward();
|
||||
}
|
||||
public void close() {
|
||||
hide();
|
||||
finish();
|
||||
}
|
||||
|
||||
public void shareButtonClicked(MenuItem item) {
|
||||
Intent share = new Intent(Intent.ACTION_SEND);
|
||||
share.setType("text/plain");
|
||||
share.putExtra(Intent.EXTRA_TEXT, webView.getUrl());
|
||||
startActivity(Intent.createChooser(share, "Share"));
|
||||
}
|
||||
public void reload() {
|
||||
if (webView != null)
|
||||
webView.reload();
|
||||
}
|
||||
|
||||
public void reloadButtonClicked(MenuItem item) {
|
||||
reload();
|
||||
}
|
||||
public void goBack() {
|
||||
if (webView != null && canGoBack())
|
||||
webView.goBack();
|
||||
}
|
||||
|
||||
public void closeButtonClicked(MenuItem item) {
|
||||
InAppBrowserFlutterPlugin.close(uuid);
|
||||
public void goForward() {
|
||||
if (webView != null && canGoForward())
|
||||
webView.goForward();
|
||||
}
|
||||
|
||||
public boolean canGoBack() {
|
||||
return webView.canGoBack();
|
||||
}
|
||||
|
||||
public boolean canGoForward() {
|
||||
return webView.canGoForward();
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
isHidden = true;
|
||||
Intent openActivity = new Intent(this, InAppBrowserFlutterPlugin.registrar.activity().getClass());
|
||||
openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
startActivityIfNeeded(openActivity, 0);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
isHidden = false;
|
||||
Intent openActivity = new Intent(InAppBrowserFlutterPlugin.registrar.activity(), WebViewActivity.class);
|
||||
openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
startActivityIfNeeded(openActivity, 0);
|
||||
}
|
||||
|
||||
public void stopLoading() {
|
||||
if (webView != null)
|
||||
webView.stopLoading();
|
||||
}
|
||||
|
||||
public boolean isLoading() {
|
||||
if (webView != null)
|
||||
return isLoading;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void clearCookies() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
CookieManager.getInstance().removeAllCookies(new ValueCallback<Boolean>() {
|
||||
@Override
|
||||
public void onReceiveValue(Boolean aBoolean) {
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
CookieManager.getInstance().removeAllCookie();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearCache() {
|
||||
webView.clearCache(true);
|
||||
clearCookies();
|
||||
webView.clearFormData();
|
||||
}
|
||||
|
||||
public void goBackButtonClicked(MenuItem item) {
|
||||
goBack();
|
||||
}
|
||||
|
||||
public void goForwardButtonClicked(MenuItem item) {
|
||||
goForward();
|
||||
}
|
||||
|
||||
public void shareButtonClicked(MenuItem item) {
|
||||
Intent share = new Intent(Intent.ACTION_SEND);
|
||||
share.setType("text/plain");
|
||||
share.putExtra(Intent.EXTRA_TEXT, webView.getUrl());
|
||||
startActivity(Intent.createChooser(share, "Share"));
|
||||
}
|
||||
|
||||
public void reloadButtonClicked(MenuItem item) {
|
||||
reload();
|
||||
}
|
||||
|
||||
public void closeButtonClicked(MenuItem item) {
|
||||
InAppBrowserFlutterPlugin.close(uuid, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,99 +17,78 @@ import java.util.Map;
|
||||
|
||||
public class ChromeCustomTabsActivity extends Activity {
|
||||
|
||||
protected static final String LOG_TAG = "CustomTabsActivity";
|
||||
String uuid;
|
||||
String uuidFallback;
|
||||
CustomTabsIntent.Builder builder;
|
||||
ChromeCustomTabsOptions options;
|
||||
Map<String, String> headersFallback;
|
||||
InAppBrowserOptions optionsFallback;
|
||||
private CustomTabActivityHelper customTabActivityHelper;
|
||||
private final int CHROME_CUSTOM_TAB_REQUEST_CODE = 100;
|
||||
protected static final String LOG_TAG = "CustomTabsActivity";
|
||||
String uuid;
|
||||
CustomTabsIntent.Builder builder;
|
||||
ChromeCustomTabsOptions options;
|
||||
private CustomTabActivityHelper customTabActivityHelper;
|
||||
private final int CHROME_CUSTOM_TAB_REQUEST_CODE = 100;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.chrome_custom_tabs_layout);
|
||||
setContentView(R.layout.chrome_custom_tabs_layout);
|
||||
|
||||
Bundle b = getIntent().getExtras();
|
||||
uuid = b.getString("uuid");
|
||||
uuidFallback = b.getString("uuidFallback");
|
||||
String url = b.getString("url");
|
||||
Bundle b = getIntent().getExtras();
|
||||
assert b != null;
|
||||
uuid = b.getString("uuid");
|
||||
String url = b.getString("url");
|
||||
|
||||
options = new ChromeCustomTabsOptions();
|
||||
options.parse((HashMap<String, Object>) b.getSerializable("options"));
|
||||
options = new ChromeCustomTabsOptions();
|
||||
options.parse((HashMap<String, Object>) b.getSerializable("options"));
|
||||
|
||||
headersFallback = (HashMap<String, String>) b.getSerializable("headers");
|
||||
InAppBrowserFlutterPlugin.chromeCustomTabsActivities.put(uuid, this);
|
||||
|
||||
optionsFallback = new InAppBrowserOptions();
|
||||
optionsFallback.parse((HashMap<String, Object>) b.getSerializable("optionsFallback"));
|
||||
customTabActivityHelper = new CustomTabActivityHelper();
|
||||
builder = new CustomTabsIntent.Builder();
|
||||
|
||||
InAppBrowserFlutterPlugin.chromeCustomTabsActivities.put(uuid, this);
|
||||
prepareCustomTabs();
|
||||
|
||||
customTabActivityHelper = new CustomTabActivityHelper();
|
||||
builder = new CustomTabsIntent.Builder();
|
||||
CustomTabsIntent customTabsIntent = builder.build();
|
||||
|
||||
prepareCustomTabs();
|
||||
CustomTabActivityHelper.openCustomTab(this, customTabsIntent, Uri.parse(url), CHROME_CUSTOM_TAB_REQUEST_CODE);
|
||||
|
||||
CustomTabsIntent customTabsIntent = builder.build();
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", uuid);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onChromeSafariBrowserOpened", obj);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onChromeSafariBrowserLoaded", obj);
|
||||
}
|
||||
|
||||
boolean chromeCustomTabsOpened = customTabActivityHelper.openCustomTab(this, customTabsIntent, Uri.parse(url), CHROME_CUSTOM_TAB_REQUEST_CODE,
|
||||
new CustomTabActivityHelper.CustomTabFallback() {
|
||||
@Override
|
||||
public void openUri(Activity activity, Uri uri) {
|
||||
if (!uuidFallback.isEmpty())
|
||||
InAppBrowserFlutterPlugin.open(uuidFallback, null, uri.toString(), optionsFallback, headersFallback, false, null);
|
||||
else {
|
||||
Log.d(LOG_TAG, "No WebView fallback declared.");
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
});
|
||||
private void prepareCustomTabs() {
|
||||
if (options.addShareButton)
|
||||
builder.addDefaultShareMenuItem();
|
||||
|
||||
if (chromeCustomTabsOpened) {
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", uuid);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onChromeSafariBrowserOpened", obj);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onChromeSafariBrowserLoaded", obj);
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareCustomTabs() {
|
||||
if (options.addShareButton)
|
||||
builder.addDefaultShareMenuItem();
|
||||
|
||||
if (!options.toolbarBackgroundColor.isEmpty())
|
||||
builder.setToolbarColor(Color.parseColor(options.toolbarBackgroundColor));
|
||||
|
||||
builder.setShowTitle(options.showTitle);
|
||||
|
||||
if (options.enableUrlBarHiding)
|
||||
builder.enableUrlBarHiding();
|
||||
|
||||
builder.setInstantAppsEnabled(options.instantAppsEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
customTabActivityHelper.bindCustomTabsService(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
customTabActivityHelper.unbindCustomTabsService(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == CHROME_CUSTOM_TAB_REQUEST_CODE) {
|
||||
finish();
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", uuid);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onChromeSafariBrowserClosed", obj);
|
||||
}
|
||||
if (!options.toolbarBackgroundColor.isEmpty())
|
||||
builder.setToolbarColor(Color.parseColor(options.toolbarBackgroundColor));
|
||||
|
||||
builder.setShowTitle(options.showTitle);
|
||||
|
||||
if (options.enableUrlBarHiding)
|
||||
builder.enableUrlBarHiding();
|
||||
|
||||
builder.setInstantAppsEnabled(options.instantAppsEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
customTabActivityHelper.bindCustomTabsService(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
customTabActivityHelper.unbindCustomTabsService(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == CHROME_CUSTOM_TAB_REQUEST_CODE) {
|
||||
finish();
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("uuid", uuid);
|
||||
InAppBrowserFlutterPlugin.channel.invokeMethod("onChromeSafariBrowserClosed", obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,26 +27,13 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback {
|
||||
* @param activity The host activity.
|
||||
* @param customTabsIntent a CustomTabsIntent to be used if Custom Tabs is available.
|
||||
* @param uri the Uri to be opened.
|
||||
* @param fallback a CustomTabFallback to be used if Custom Tabs is not available.
|
||||
*/
|
||||
public static boolean openCustomTab(Activity activity,
|
||||
public static void openCustomTab(Activity activity,
|
||||
CustomTabsIntent customTabsIntent,
|
||||
Uri uri,
|
||||
int requestCode,
|
||||
CustomTabFallback fallback) {
|
||||
//If we cant find a package name, it means theres no browser that supports
|
||||
//Chrome Custom Tabs installed. So, we fallback to the webview
|
||||
if (!isAvailable(activity)) {
|
||||
if (fallback != null) {
|
||||
fallback.openUri(activity, uri);
|
||||
}
|
||||
} else {
|
||||
//customTabsIntent.intent.setPackage(packageName);
|
||||
customTabsIntent.intent.setData(uri);
|
||||
activity.startActivityForResult(customTabsIntent.intent, requestCode);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
int requestCode) {
|
||||
customTabsIntent.intent.setData(uri);
|
||||
activity.startActivityForResult(customTabsIntent.intent, requestCode);
|
||||
}
|
||||
|
||||
public static boolean isAvailable(Activity activity) {
|
||||
@ -144,16 +131,4 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback {
|
||||
void onCustomTabsDisconnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* To be used as a fallback to open the Uri when Custom Tabs is not available.
|
||||
*/
|
||||
public interface CustomTabFallback {
|
||||
/**
|
||||
*
|
||||
* @param activity The Activity that wants to open the Uri.
|
||||
* @param uri The uri to be opened by the fallback.
|
||||
*/
|
||||
void openUri(Activity activity, Uri uri);
|
||||
}
|
||||
|
||||
}
|
7
example/assets/css/style.css
Normal file
7
example/assets/css/style.css
Normal file
@ -0,0 +1,7 @@
|
||||
body {
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
50
example/assets/images/dart.svg
Normal file
50
example/assets/images/dart.svg
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 439 137.29" enable-background="new 0 0 439 137.29" xml:space="preserve">
|
||||
<g>
|
||||
<g opacity="0.54">
|
||||
<path d="M207.08,20.2h27.55c9.35,0,17.51,1.93,24.49,5.8c6.97,3.87,12.33,9.25,16.07,16.13c3.74,6.89,5.61,14.79,5.61,23.72
|
||||
s-1.87,16.83-5.61,23.72s-9.1,12.26-16.07,16.13c-6.97,3.87-15.13,5.8-24.49,5.8h-27.55V20.2z M234.63,101.19
|
||||
c10.8,0,19.36-3.1,25.7-9.31c6.33-6.21,9.5-14.88,9.5-26.02s-3.17-19.81-9.5-26.02c-6.33-6.21-14.9-9.31-25.7-9.31H217.8v70.65
|
||||
h16.83V101.19z"/>
|
||||
<path d="M297.49,110.75c-3.74-1.87-6.63-4.44-8.67-7.72c-2.04-3.27-3.06-6.99-3.06-11.16c0-6.89,2.59-12.26,7.78-16.13
|
||||
c5.18-3.87,11.73-5.8,19.64-5.8c3.91,0,7.54,0.43,10.9,1.28s5.93,1.83,7.72,2.93V70.2c0-4.85-1.7-8.74-5.1-11.67
|
||||
c-3.4-2.93-7.7-4.4-12.88-4.4c-3.66,0-7.01,0.79-10.08,2.36c-3.06,1.57-5.48,3.76-7.27,6.57l-8.16-6.12
|
||||
c2.55-3.91,6.06-6.97,10.52-9.18c4.46-2.21,9.42-3.32,14.86-3.32c8.84,0,15.79,2.32,20.85,6.95c5.06,4.64,7.59,10.95,7.59,18.94
|
||||
v41.19H331.8v-9.31h-0.51c-1.87,3.15-4.68,5.82-8.42,8.03c-3.74,2.21-7.95,3.32-12.63,3.32
|
||||
C305.49,113.56,301.24,112.62,297.49,110.75z M321.47,101.19c3.14-1.87,5.65-4.38,7.52-7.52s2.81-6.59,2.81-10.33
|
||||
c-2.04-1.36-4.55-2.47-7.52-3.32c-2.98-0.85-6.12-1.28-9.44-1.28c-5.95,0-10.44,1.23-13.45,3.7c-3.02,2.47-4.53,5.66-4.53,9.56
|
||||
c0,3.57,1.36,6.46,4.08,8.67c2.72,2.21,6.16,3.32,10.33,3.32C314.92,103.99,318.33,103.06,321.47,101.19z"/>
|
||||
<path d="M353.57,47.5h10.33v10.33h0.51c1.53-3.83,4.12-6.8,7.78-8.93c3.65-2.12,7.65-3.19,11.99-3.19c1.87,0,3.44,0.13,4.72,0.38
|
||||
v11.1c-1.45-0.34-3.4-0.51-5.87-0.51c-5.53,0-10.01,1.83-13.45,5.48c-3.44,3.66-5.17,8.42-5.17,14.28v36.09h-10.84V47.5
|
||||
L353.57,47.5z M420.89,112.26c-2.25-0.86-4.14-2.03-5.68-3.51c-1.7-1.64-2.98-3.55-3.83-5.71c-0.85-2.16-1.28-4.8-1.28-7.92V56.3
|
||||
h-11.35v-9.82h11.35V28.12h10.84v18.36h15.81v9.82h-15.81v36.24c0,3.65,0.68,6.34,2.04,8.08c1.61,1.91,3.95,2.87,7.01,2.87
|
||||
c2.46,0,4.85-0.72,7.14-2.17v10.59c-1.28,0.59-2.57,1.02-3.89,1.28s-3,0.38-5.04,0.38C425.59,113.56,423.15,113.12,420.89,112.26z
|
||||
"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#01579B" d="M29.64,108.94L6.36,85.66c-2.76-2.84-4.48-6.84-4.48-10.75c0-1.81,1.02-4.64,1.79-6.27l21.49-44.77
|
||||
L29.64,108.94z"/>
|
||||
<path fill="#40C4FF" d="M109.34,28.35L86.06,5.07c-2.03-2.04-6.27-4.48-9.85-4.48c-3.08,0-6.1,0.62-8.06,1.79L25.17,23.87
|
||||
L109.34,28.35z"/>
|
||||
<polygon fill="#40C4FF" points="57.4,136.7 113.82,136.7 113.82,112.52 71.73,99.09 33.23,112.52 "/>
|
||||
<path fill="#29B6F6" d="M25.17,96.41c0,7.18,0.9,8.95,4.48,12.54l3.58,3.58h80.59l-39.4-44.77L25.17,23.88V96.41z"/>
|
||||
<path fill="#01579B" d="M96.8,23.87H25.16l88.65,88.65h24.18V57l-28.65-28.65C105.32,24.31,101.74,23.87,96.8,23.87z"/>
|
||||
<path opacity="0.2" fill="#FFFFFF" enable-background="new " d="M30.54,109.84c-3.58-3.6-4.48-7.14-4.48-13.43V24.77l-0.9-0.9
|
||||
V96.4C25.17,102.7,25.17,104.44,30.54,109.84l2.69,2.69l0,0L30.54,109.84z"/>
|
||||
<polygon opacity="0.2" fill="#263238" enable-background="new " points="137.1,56.11 137.1,111.63 112.92,111.63
|
||||
113.82,112.52 138,112.52 138,57.01 "/>
|
||||
<path opacity="0.2" fill="#FFFFFF" enable-background="new " d="M109.34,28.35c-4.44-4.44-8.08-4.48-13.43-4.48H25.17l0.9,0.9
|
||||
h69.85C98.58,24.77,105.33,24.32,109.34,28.35L109.34,28.35z"/>
|
||||
|
||||
<radialGradient id="SVGID_1_" cx="69.955" cy="60.8864" r="68.065" gradientTransform="matrix(1 0 0 -1 0 129.5328)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.1"/>
|
||||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
|
||||
</radialGradient>
|
||||
<path opacity="0.2" fill="url(#SVGID_1_)" enable-background="new " d="M137.1,56.11l-27.76-27.76L86.06,5.07
|
||||
c-2.03-2.04-6.27-4.48-9.85-4.48c-3.08,0-6.1,0.62-8.06,1.79L25.17,23.87L3.68,68.64c-0.77,1.63-1.79,4.46-1.79,6.27
|
||||
c0,3.91,1.72,7.91,4.48,10.75l21.46,21.3c0.51,0.63,1.11,1.27,1.83,1.98l0.9,0.9l2.69,2.69l23.28,23.28l0.9,0.9h55.52h0.9v-24.18
|
||||
h24.18v-0.06V57.01L137.1,56.11z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.1 KiB |
34
example/assets/index.html
Normal file
34
example/assets/index.html
Normal file
@ -0,0 +1,34 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="container">
|
||||
<img src="images/dart.svg" alt="dart logo">
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
One of three columns
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
One of three columns
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
One of three columns
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
console.log("hello");
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -2,6 +2,11 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
|
@ -1,8 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_inappbrowser/flutter_inappbrowser.dart';
|
||||
|
||||
class MyInAppBrowser extends InAppBrowser {
|
||||
|
||||
@override
|
||||
Future onLoadStart(String url) async {
|
||||
print("\n\nStarted $url\n\n");
|
||||
@ -13,6 +13,8 @@ class MyInAppBrowser extends InAppBrowser {
|
||||
Future onLoadStop(String url) async {
|
||||
print("\n\nStopped $url\n\n");
|
||||
|
||||
//print("\n\n ${await this.isHidden()} \n\n");
|
||||
|
||||
// await this.injectScriptCode("window.flutter_inappbrowser.callHandler('handlerTest', 1, 5,'string', {'key': 5}, [4,6,8]);");
|
||||
// await this.injectScriptCode("window.flutter_inappbrowser.callHandler('handlerTest2', false, null, undefined);");
|
||||
// await this.injectScriptCode("setTimeout(function(){window.flutter_inappbrowser.callHandler('handlerTest', 'anotherString');}, 1000);");
|
||||
@ -40,8 +42,7 @@ class MyInAppBrowser extends InAppBrowser {
|
||||
// var x = {"as":4, "dfdfg": 6};
|
||||
// x;
|
||||
// """));
|
||||
//print("\n\n ${await this.isHidden()} \n\n");
|
||||
|
||||
//
|
||||
// await this.injectScriptFile("https://code.jquery.com/jquery-3.3.1.min.js");
|
||||
// this.injectScriptCode("""
|
||||
// \$( "body" ).html( "Next Step..." )
|
||||
@ -73,29 +74,33 @@ class MyInAppBrowser extends InAppBrowser {
|
||||
}
|
||||
|
||||
@override
|
||||
void onLoadResource(WebResourceResponse response, WebResourceRequest request) {
|
||||
|
||||
print("Started at: " + response.startTime.toString() + "ms ---> duration: " + response.duration.toString() + "ms " + response.url);
|
||||
void onLoadResource(
|
||||
WebResourceResponse response, WebResourceRequest request) {
|
||||
print("Started at: " +
|
||||
response.startTime.toString() +
|
||||
"ms ---> duration: " +
|
||||
response.duration.toString() +
|
||||
"ms " +
|
||||
response.url);
|
||||
// if (response.headers["content-length"] != null)
|
||||
// print(response.headers["content-length"] + " length");
|
||||
}
|
||||
|
||||
@override
|
||||
void onConsoleMessage(ConsoleMessage consoleMessage) {
|
||||
// print("""
|
||||
// console output:
|
||||
// sourceURL: ${consoleMessage.sourceURL}
|
||||
// lineNumber: ${consoleMessage.lineNumber}
|
||||
// message: ${consoleMessage.message}
|
||||
// messageLevel: ${consoleMessage.messageLevel}
|
||||
// """);
|
||||
print("""
|
||||
console output:
|
||||
sourceURL: ${consoleMessage.sourceURL}
|
||||
lineNumber: ${consoleMessage.lineNumber}
|
||||
message: ${consoleMessage.message}
|
||||
messageLevel: ${consoleMessage.messageLevel}
|
||||
""");
|
||||
}
|
||||
}
|
||||
|
||||
MyInAppBrowser inAppBrowserFallback = new MyInAppBrowser();
|
||||
|
||||
class MyChromeSafariBrowser extends ChromeSafariBrowser {
|
||||
|
||||
MyChromeSafariBrowser(browserFallback) : super(browserFallback);
|
||||
|
||||
@override
|
||||
@ -115,9 +120,10 @@ class MyChromeSafariBrowser extends ChromeSafariBrowser {
|
||||
}
|
||||
|
||||
// adding a webview fallback
|
||||
MyChromeSafariBrowser chromeSafariBrowser = new MyChromeSafariBrowser(inAppBrowserFallback);
|
||||
MyChromeSafariBrowser chromeSafariBrowser =
|
||||
new MyChromeSafariBrowser(inAppBrowserFallback);
|
||||
|
||||
void main() {
|
||||
Future main() async {
|
||||
runApp(new MyApp());
|
||||
}
|
||||
|
||||
@ -127,11 +133,11 @@ class MyApp extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MyAppState extends State<MyApp> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// int indexTest = inAppBrowserFallback.addJavaScriptHandler("handlerTest", (arguments) async {
|
||||
// int indexTest = inAppBrowserFallback.addJavaScriptHandler("handlerTest",
|
||||
// (arguments) async {
|
||||
// print("handlerTest arguments");
|
||||
// print(arguments);
|
||||
// });
|
||||
@ -150,21 +156,45 @@ class _MyAppState extends State<MyApp> {
|
||||
title: const Text('Flutter InAppBrowser Plugin example app'),
|
||||
),
|
||||
body: new Center(
|
||||
child: new RaisedButton(onPressed: () {
|
||||
//chromeSafariBrowser.open("https://flutter.io/");
|
||||
inAppBrowserFallback.open(url: "https://flutter.io/", options: {
|
||||
//"useOnLoadResource": true,
|
||||
//"hidden": true,
|
||||
//"toolbarTopFixedTitle": "Fixed title",
|
||||
//"useShouldOverrideUrlLoading": true
|
||||
//"hideUrlBar": true,
|
||||
//"toolbarTop": false,
|
||||
//"toolbarBottom": false
|
||||
});
|
||||
child: new RaisedButton(
|
||||
onPressed: () async {
|
||||
// await chromeSafariBrowser.open("https://flutter.io/");
|
||||
|
||||
},
|
||||
child: Text("Open InAppBrowser")
|
||||
),
|
||||
// await InAppBrowser.openWithSystemBrowser("https://flutter.io/");
|
||||
|
||||
await inAppBrowserFallback.openOnLocalhost("assets/index.html", options: {
|
||||
"useOnLoadResource": true,
|
||||
//"hidden": true,
|
||||
//"toolbarTopFixedTitle": "Fixed title",
|
||||
//"useShouldOverrideUrlLoading": true
|
||||
//"hideUrlBar": true,
|
||||
//"toolbarTop": false,
|
||||
//"toolbarBottom": false
|
||||
});
|
||||
|
||||
// await inAppBrowserFallback.open(url: "assets/index.html", options: {
|
||||
// "isLocalFile": true,
|
||||
// "useOnLoadResource": true,
|
||||
// //"hidden": true,
|
||||
// //"toolbarTopFixedTitle": "Fixed title",
|
||||
// //"useShouldOverrideUrlLoading": true
|
||||
// //"hideUrlBar": true,
|
||||
// //"toolbarTop": false,
|
||||
// //"toolbarBottom": false
|
||||
// });
|
||||
|
||||
// await inAppBrowserFallback.open(url: "https://flutter.io/", options: {
|
||||
// //"useOnLoadResource": true,
|
||||
// //"hidden": true,
|
||||
// //"toolbarTopFixedTitle": "Fixed title",
|
||||
// //"useShouldOverrideUrlLoading": true
|
||||
// //"hideUrlBar": true,
|
||||
// //"toolbarTop": false,
|
||||
// //"toolbarBottom": false
|
||||
// });
|
||||
//await inAppBrowserFallback.openOnLocalhost("assets/index.html");
|
||||
},
|
||||
child: Text("Open InAppBrowser")),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -38,6 +38,11 @@ flutter:
|
||||
# the material Icons class.
|
||||
uses-material-design: true
|
||||
|
||||
assets:
|
||||
- assets/index.html
|
||||
- assets/css/
|
||||
- assets/images/
|
||||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
# assets:
|
||||
# - images/a_dot_burr.jpeg
|
||||
|
@ -14,6 +14,12 @@
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/flutter_plugin/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/flutter_plugin/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/flutter_plugin/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/flutter_assets/packages" />
|
||||
</content>
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
|
@ -12,6 +12,7 @@ public class InAppBrowserOptions: Options {
|
||||
|
||||
var useShouldOverrideUrlLoading = false
|
||||
var useOnLoadResource = false
|
||||
var openWithSystemBrowser = false;
|
||||
var clearCache = false
|
||||
var userAgent = ""
|
||||
var javaScriptEnabled = true
|
||||
@ -21,6 +22,7 @@ public class InAppBrowserOptions: Options {
|
||||
var toolbarTopBackgroundColor = ""
|
||||
var hideUrlBar = false
|
||||
var mediaPlaybackRequiresUserGesture = true
|
||||
var isLocalFile = false
|
||||
|
||||
var disallowOverScroll = false
|
||||
var toolbarBottom = true
|
||||
|
@ -81,7 +81,6 @@ func convertToDictionary(text: String) -> [String: Any]? {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
//extension WKWebView{
|
||||
//
|
||||
// var keyboardDisplayRequiresUserAction: Bool? {
|
||||
@ -139,6 +138,7 @@ class WKWebView_IBWrapper: WKWebView {
|
||||
}
|
||||
|
||||
class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate, UITextFieldDelegate, WKScriptMessageHandler {
|
||||
|
||||
@IBOutlet var webView: WKWebView_IBWrapper!
|
||||
@IBOutlet var closeButton: UIButton!
|
||||
@IBOutlet var reloadButton: UIBarButtonItem!
|
||||
@ -200,7 +200,7 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
|
||||
spinner.hidesWhenStopped = true
|
||||
spinner.isHidden = false
|
||||
spinner.stopAnimating()
|
||||
|
||||
|
||||
loadUrl(url: self.currentURL!, headers: self.initHeaders)
|
||||
|
||||
}
|
||||
@ -421,11 +421,7 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
|
||||
}
|
||||
|
||||
@objc func close() {
|
||||
currentURL = nil
|
||||
|
||||
if (navigationDelegate != nil) {
|
||||
navigationDelegate?.browserExit(uuid: self.uuid)
|
||||
}
|
||||
//currentURL = nil
|
||||
|
||||
weak var weakSelf = self
|
||||
|
||||
@ -435,12 +431,18 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
|
||||
weakSelf?.presentingViewController?.dismiss(animated: true, completion: {() -> Void in
|
||||
self.tmpWindow?.windowLevel = 0.0
|
||||
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
|
||||
if (self.navigationDelegate != nil) {
|
||||
self.navigationDelegate?.browserExit(uuid: self.uuid)
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
weakSelf?.parent?.dismiss(animated: true, completion: {() -> Void in
|
||||
self.tmpWindow?.windowLevel = 0.0
|
||||
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
|
||||
if (self.navigationDelegate != nil) {
|
||||
self.navigationDelegate?.browserExit(uuid: self.uuid)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@ -527,7 +529,9 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
|
||||
}
|
||||
|
||||
if navigationAction.navigationType == .linkActivated && (browserOptions?.useShouldOverrideUrlLoading)! {
|
||||
navigationDelegate?.shouldOverrideUrlLoading(uuid: self.uuid, webView: webView, url: url)
|
||||
if navigationDelegate != nil {
|
||||
navigationDelegate?.shouldOverrideUrlLoading(uuid: self.uuid, webView: webView, url: url)
|
||||
}
|
||||
decisionHandler(.cancel)
|
||||
return
|
||||
}
|
||||
@ -606,7 +610,9 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
|
||||
spinner.startAnimating()
|
||||
}
|
||||
|
||||
return (navigationDelegate?.onLoadStart(uuid: self.uuid, webView: webView))!
|
||||
if navigationDelegate != nil {
|
||||
navigationDelegate?.onLoadStart(uuid: self.uuid, webView: webView)
|
||||
}
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
@ -617,7 +623,10 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
|
||||
backButton.isEnabled = webView.canGoBack
|
||||
forwardButton.isEnabled = webView.canGoForward
|
||||
spinner.stopAnimating()
|
||||
navigationDelegate?.onLoadStop(uuid: self.uuid, webView: webView)
|
||||
|
||||
if navigationDelegate != nil {
|
||||
navigationDelegate?.onLoadStop(uuid: self.uuid, webView: webView)
|
||||
}
|
||||
}
|
||||
|
||||
func webView(_ view: WKWebView,
|
||||
@ -627,15 +636,19 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
|
||||
print("webView:didFailNavigationWithError - \(Int(error._code)): \(error.localizedDescription)")
|
||||
backButton.isEnabled = webView.canGoBack
|
||||
forwardButton.isEnabled = webView.canGoForward
|
||||
spinner.stopAnimating()
|
||||
navigationDelegate?.onLoadError(uuid: self.uuid, webView: webView, error: error)
|
||||
|
||||
if navigationDelegate != nil {
|
||||
navigationDelegate?.onLoadError(uuid: self.uuid, webView: webView, error: error)
|
||||
}
|
||||
}
|
||||
|
||||
func didReceiveResourceResponse(_ response: URLResponse, fromRequest request: URLRequest?, withData data: Data, startTime: Int, duration: Int) {
|
||||
navigationDelegate?.onLoadResource(uuid: self.uuid, webView: webView, response: response, fromRequest: request, withData: data, startTime: startTime, duration: duration)
|
||||
if navigationDelegate != nil {
|
||||
navigationDelegate?.onLoadResource(uuid: self.uuid, webView: webView, response: response, fromRequest: request, withData: data, startTime: startTime, duration: duration)
|
||||
}
|
||||
}
|
||||
|
||||
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||
@ -663,7 +676,9 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
|
||||
messageLevel = "LOG"
|
||||
break;
|
||||
}
|
||||
navigationDelegate?.onConsoleMessage(uuid: self.uuid, sourceURL: "", lineNumber: 1, message: message.body as! String, messageLevel: messageLevel)
|
||||
if navigationDelegate != nil {
|
||||
navigationDelegate?.onConsoleMessage(uuid: self.uuid, sourceURL: "", lineNumber: 1, message: message.body as! String, messageLevel: messageLevel)
|
||||
}
|
||||
}
|
||||
else if message.name == "resourceLoaded" {
|
||||
if let resource = convertToDictionary(text: message.body as! String) {
|
||||
@ -695,7 +710,9 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
|
||||
let body = message.body as! [String: Any]
|
||||
let handlerName = body["handlerName"] as! String
|
||||
let args = body["args"] as! String
|
||||
self.navigationDelegate?.onCallJsHandler(uuid: self.uuid, webView: webView, handlerName: handlerName, args: args)
|
||||
if navigationDelegate != nil {
|
||||
self.navigationDelegate?.onCallJsHandler(uuid: self.uuid, webView: webView, handlerName: handlerName, args: args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,12 +14,13 @@ public class Options: NSObject {
|
||||
super.init()
|
||||
}
|
||||
|
||||
public func parse(options: [String: Any]) {
|
||||
public func parse(options: [String: Any]) -> Options {
|
||||
for (key, value) in options {
|
||||
if self.responds(to: Selector(key)) {
|
||||
self.setValue(value, forKey: key)
|
||||
}
|
||||
}
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,15 +40,15 @@ class SafariViewController: SFSafariViewController, SFSafariViewControllerDelega
|
||||
}
|
||||
|
||||
func close() {
|
||||
if (statusDelegate != nil) {
|
||||
statusDelegate?.safariExit(uuid: self.uuid)
|
||||
}
|
||||
|
||||
dismiss(animated: true)
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(400), execute: {() -> Void in
|
||||
self.tmpWindow?.windowLevel = 0.0
|
||||
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
|
||||
|
||||
if (self.statusDelegate != nil) {
|
||||
self.statusDelegate?.safariExit(uuid: self.uuid)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -22,19 +22,6 @@ import Foundation
|
||||
import AVFoundation
|
||||
import SafariServices
|
||||
|
||||
//class CustomURLCache: URLCache {
|
||||
// override func cachedResponse(for request: URLRequest) -> CachedURLResponse? {
|
||||
// dump(request.url)
|
||||
// return super.cachedResponse(for: request)
|
||||
// }
|
||||
//
|
||||
// override func getCachedResponse(for dataTask: URLSessionDataTask,
|
||||
// completionHandler: @escaping (CachedURLResponse?) -> Void) {
|
||||
// dump(dataTask.response)
|
||||
// super.getCachedResponse(for: dataTask, completionHandler: completionHandler)
|
||||
// }
|
||||
//}
|
||||
|
||||
let WEBVIEW_STORYBOARD = "WebView"
|
||||
let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController"
|
||||
|
||||
@ -47,6 +34,9 @@ extension Dictionary where Key: ExpressibleByStringLiteral {
|
||||
}
|
||||
|
||||
public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
|
||||
static var registrar: FlutterPluginRegistrar?
|
||||
|
||||
var webViewControllers: [String: InAppBrowserWebViewController?] = [:]
|
||||
var safariViewControllers: [String: Any?] = [:]
|
||||
|
||||
@ -59,11 +49,8 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
}
|
||||
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
// URLProtocol.wk_registerScheme("http")
|
||||
// URLProtocol.wk_registerScheme("https")
|
||||
// URLProtocol.registerClass(MyURLProtocol.self)
|
||||
|
||||
//URLCache.shared = CustomURLCache()
|
||||
|
||||
SwiftFlutterPlugin.registrar = registrar
|
||||
|
||||
let channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappbrowser", binaryMessenger: registrar.messenger())
|
||||
let instance = SwiftFlutterPlugin(with: registrar)
|
||||
@ -73,7 +60,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
let arguments = call.arguments as? NSDictionary
|
||||
let uuid: String = (arguments!["uuid"] as? String)!
|
||||
|
||||
|
||||
switch call.method {
|
||||
case "open":
|
||||
self.open(uuid: uuid, arguments: arguments!, result: result)
|
||||
@ -177,7 +164,6 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
}
|
||||
else {
|
||||
print("IAB.close() called but it was already closed.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,41 +178,38 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
let url: String = (arguments["url"] as? String)!
|
||||
|
||||
let headers = (arguments["headers"] as? [String: String])!
|
||||
var target: String? = (arguments["target"] as? String)!
|
||||
target = target != nil ? target : "_self"
|
||||
let absoluteUrl = URL(string: url)?.absoluteURL
|
||||
|
||||
let useChromeSafariBrowser = (arguments["useChromeSafariBrowser"] as? Bool)
|
||||
|
||||
if useChromeSafariBrowser! {
|
||||
let uuidFallback = (arguments["uuidFallback"] as? String)!
|
||||
let options = (arguments["options"] as? [String: Any])!
|
||||
let optionsFallback = (arguments["optionsFallback"] as? [String: Any])!
|
||||
let safariOptions = SafariBrowserOptions()
|
||||
safariOptions.parse(options: (arguments["options"] as? [String: Any])!)
|
||||
|
||||
open(uuid: uuid, uuidFallback: uuidFallback, inAppBrowser: absoluteUrl!, headers: headers, withOptions: options, useChromeSafariBrowser: true, withOptionsFallback: optionsFallback);
|
||||
let optionsFallback = InAppBrowserOptions()
|
||||
optionsFallback.parse(options: (arguments["optionsFallback"] as? [String: Any])!)
|
||||
|
||||
open(uuid: uuid, uuidFallback: uuidFallback, inAppBrowser: absoluteUrl!, headers: headers, withOptions: safariOptions, useChromeSafariBrowser: true, withOptionsFallback: optionsFallback, result: result);
|
||||
}
|
||||
else {
|
||||
let options = (arguments["options"] as? [String: Any])!
|
||||
|
||||
let options = InAppBrowserOptions()
|
||||
options.parse(options: (arguments["options"] as? [String: Any])!)
|
||||
|
||||
if isSystemUrl(absoluteUrl!) {
|
||||
target = "_system"
|
||||
options.openWithSystemBrowser = true
|
||||
}
|
||||
|
||||
if (target == "_self" || target == "_target") {
|
||||
open(uuid: uuid, uuidFallback: nil, inAppBrowser: absoluteUrl!, headers: headers, withOptions: options, useChromeSafariBrowser: false, withOptionsFallback: nil)
|
||||
}
|
||||
else if (target == "_system") {
|
||||
open(inSystem: absoluteUrl!)
|
||||
if (options.openWithSystemBrowser) {
|
||||
open(inSystem: absoluteUrl!, result: result)
|
||||
}
|
||||
else {
|
||||
// anything else
|
||||
open(uuid: uuid, uuidFallback: nil, inAppBrowser: absoluteUrl!, headers: headers,withOptions: options, useChromeSafariBrowser: false, withOptionsFallback: nil)
|
||||
open(uuid: uuid, uuidFallback: nil, inAppBrowser: absoluteUrl!, headers: headers, withOptions: options, useChromeSafariBrowser: false, withOptionsFallback: nil, result: result)
|
||||
}
|
||||
}
|
||||
result(true)
|
||||
}
|
||||
|
||||
func open(uuid: String, uuidFallback: String?, inAppBrowser url: URL, headers: [String: String], withOptions options: [String: Any], useChromeSafariBrowser: Bool, withOptionsFallback optionsFallback: [String: Any]?) {
|
||||
func open(uuid: String, uuidFallback: String?, inAppBrowser url: URL, headers: [String: String], withOptions options: Options, useChromeSafariBrowser: Bool, withOptionsFallback optionsFallback: Options?, result: @escaping FlutterResult) {
|
||||
|
||||
var uuid = uuid
|
||||
|
||||
@ -235,7 +218,6 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
}
|
||||
|
||||
let safariViewController = self.safariViewControllers[uuid]
|
||||
|
||||
if safariViewController != nil {
|
||||
if #available(iOS 9.0, *) {
|
||||
(safariViewController! as! SafariViewController).close()
|
||||
@ -264,8 +246,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
|
||||
if useChromeSafariBrowser == true {
|
||||
if #available(iOS 9.0, *) {
|
||||
let safariOptions = SafariBrowserOptions()
|
||||
safariOptions.parse(options: options)
|
||||
let safariOptions = options as! SafariBrowserOptions
|
||||
|
||||
let safari: SafariViewController
|
||||
|
||||
@ -290,24 +271,37 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
|
||||
tmpController.present(self.safariViewControllers[uuid]! as! SFSafariViewController, animated: true)
|
||||
onChromeSafariBrowserOpened(uuid: uuid)
|
||||
result(true)
|
||||
|
||||
return
|
||||
}
|
||||
else {
|
||||
if uuidFallback == nil {
|
||||
print("No WebView fallback declared.")
|
||||
result(true)
|
||||
|
||||
return
|
||||
}
|
||||
uuid = uuidFallback!
|
||||
browserOptions = InAppBrowserOptions()
|
||||
browserOptions.parse(options: optionsFallback!)
|
||||
browserOptions = optionsFallback as! InAppBrowserOptions
|
||||
}
|
||||
}
|
||||
else {
|
||||
browserOptions = InAppBrowserOptions()
|
||||
browserOptions.parse(options: options)
|
||||
browserOptions = options as! InAppBrowserOptions
|
||||
}
|
||||
|
||||
|
||||
var currentURL = url
|
||||
|
||||
if browserOptions.isLocalFile {
|
||||
let key = SwiftFlutterPlugin.registrar!.lookupKey(forAsset: url.absoluteString)
|
||||
let assetURL = Bundle.main.url(forResource: key, withExtension: nil)
|
||||
if assetURL == nil {
|
||||
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: url.absoluteString + " asset file cannot be found!", details: nil))
|
||||
return
|
||||
}
|
||||
currentURL = assetURL!
|
||||
}
|
||||
|
||||
let storyboard = UIStoryboard(name: WEBVIEW_STORYBOARD, bundle: Bundle(for: InAppBrowserFlutterPlugin.self))
|
||||
let vc = storyboard.instantiateViewController(withIdentifier: WEBVIEW_STORYBOARD_CONTROLLER_ID)
|
||||
self.webViewControllers[uuid] = vc as? InAppBrowserWebViewController
|
||||
@ -316,7 +310,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
webViewController.browserOptions = browserOptions
|
||||
webViewController.isHidden = browserOptions.hidden
|
||||
webViewController.tmpWindow = tmpWindow
|
||||
webViewController.currentURL = url
|
||||
webViewController.currentURL = currentURL
|
||||
webViewController.initHeaders = headers
|
||||
webViewController.navigationDelegate = self
|
||||
|
||||
@ -338,6 +332,8 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
else {
|
||||
tmpController.present(webViewController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
result(true)
|
||||
}
|
||||
|
||||
public func loadUrl(uuid: String, arguments: NSDictionary, result: @escaping FlutterResult) {
|
||||
@ -350,7 +346,6 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
webViewController.loadUrl(url: absoluteUrl, headers: headers)
|
||||
}
|
||||
else {
|
||||
print("url is empty")
|
||||
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: "url is empty", details: nil))
|
||||
}
|
||||
result(true)
|
||||
@ -403,17 +398,18 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
func open(inSystem url: URL) {
|
||||
func open(inSystem url: URL, result: @escaping FlutterResult) {
|
||||
if !UIApplication.shared.canOpenURL(url) {
|
||||
NotificationCenter.default.post(Notification(name: Notification.Name(rawValue: "PluginHandleOpenURLNotification"), object: url))
|
||||
return
|
||||
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: url.absoluteString + " cannot be opened!", details: nil))
|
||||
}
|
||||
|
||||
if #available(iOS 10.0, *) {
|
||||
UIApplication.shared.open(url, options: [:], completionHandler: nil)
|
||||
} else {
|
||||
UIApplication.shared.openURL(url)
|
||||
else {
|
||||
if #available(iOS 10.0, *) {
|
||||
UIApplication.shared.open(url, options: [:], completionHandler: nil)
|
||||
} else {
|
||||
UIApplication.shared.openURL(url)
|
||||
}
|
||||
}
|
||||
result(true)
|
||||
}
|
||||
|
||||
// This is a helper method for the inject{Script|Style}{Code|File} API calls, which
|
||||
@ -429,7 +425,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
let jsonData: Data? = try? JSONSerialization.data(withJSONObject: [source], options: [])
|
||||
let sourceArrayString = String(data: jsonData!, encoding: String.Encoding.utf8)
|
||||
if sourceArrayString != nil {
|
||||
let sourceString: String? = (sourceArrayString! as NSString).substring(with: NSRange(location: 1, length: (sourceArrayString?.characters.count ?? 0) - 2))
|
||||
let sourceString: String? = (sourceArrayString! as NSString).substring(with: NSRange(location: 1, length: (sourceArrayString?.count ?? 0) - 2))
|
||||
let jsToInject = String(format: jsWrapper, sourceString!)
|
||||
|
||||
webViewController?.webView?.evaluateJavaScript(jsToInject, completionHandler: {(value, error) in
|
||||
@ -439,7 +435,6 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
|
||||
if error != nil {
|
||||
let userInfo = (error! as NSError).userInfo
|
||||
dump(userInfo)
|
||||
self.onConsoleMessage(uuid: uuid, sourceURL: (userInfo["WKJavaScriptExceptionSourceURL"] as? URL)?.absoluteString ?? "", lineNumber: userInfo["WKJavaScriptExceptionLineNumber"] as! Int, message: userInfo["WKJavaScriptExceptionMessage"] as! String, messageLevel: "ERROR")
|
||||
}
|
||||
|
||||
@ -458,7 +453,6 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
||||
result!(value)
|
||||
}
|
||||
} catch let error as NSError {
|
||||
print("Failed to load: \(error.localizedDescription)")
|
||||
result!(FlutterError(code: "InAppBrowserFlutterPlugin", message: "Failed to load: \(error.localizedDescription)", details: error))
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:typed_data';
|
||||
@ -26,6 +27,7 @@ import 'dart:convert';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'package:mime/mime.dart';
|
||||
|
||||
typedef Future<dynamic> ListenerCallback(MethodCall call);
|
||||
typedef Future<void> JavaScriptHandlerCallback(List<dynamic> arguments);
|
||||
@ -85,8 +87,7 @@ class _ChannelManager {
|
||||
|
||||
static Future<dynamic> _handleMethod(MethodCall call) async {
|
||||
String uuid = call.arguments["uuid"];
|
||||
listeners[uuid](call);
|
||||
return new Future.value("");
|
||||
return await listeners[uuid](call);
|
||||
}
|
||||
|
||||
static void addListener (String key, ListenerCallback callback) {
|
||||
@ -107,11 +108,14 @@ class InAppBrowser {
|
||||
|
||||
String uuid;
|
||||
Map<String, List<JavaScriptHandlerCallback>> javaScriptHandlersMap = HashMap<String, List<JavaScriptHandlerCallback>>();
|
||||
HttpServer _server;
|
||||
bool _isOpened = false;
|
||||
|
||||
///
|
||||
InAppBrowser () {
|
||||
uuid = _uuidGenerator.v4();
|
||||
_ChannelManager.addListener(uuid, _handleMethod);
|
||||
_isOpened = false;
|
||||
}
|
||||
|
||||
Future<dynamic> _handleMethod(MethodCall call) async {
|
||||
@ -131,6 +135,8 @@ class InAppBrowser {
|
||||
onLoadError(url, code, message);
|
||||
break;
|
||||
case "onExit":
|
||||
this._closeServer();
|
||||
this._isOpened = false;
|
||||
onExit();
|
||||
break;
|
||||
case "shouldOverrideUrlLoading":
|
||||
@ -183,133 +189,271 @@ class InAppBrowser {
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw UnimplementedError("Unimplemented ${call.method} method");
|
||||
}
|
||||
return new Future.value("");
|
||||
}
|
||||
|
||||
///Opens an [url] in a new [InAppBrowser] instance or the system browser.
|
||||
///Opens an [url] in a new [InAppBrowser] instance or in the system browser (`openWithSystemBrowser: true`).
|
||||
///
|
||||
///**NOTE**: If you open the given [url] with the system browser (`openWithSystemBrowser: true`), you wont be able to use the [InAppBrowser] methods!
|
||||
///
|
||||
///- [url]: The [url] to load. Call [encodeUriComponent()] on this if the [url] contains Unicode characters. The default value is `about:blank`.
|
||||
///
|
||||
///- [headers]: The additional headers to be used in the HTTP request for this URL, specified as a map from name to value.
|
||||
///
|
||||
///- [target]: The target in which to load the [url], an optional parameter that defaults to `_self`.
|
||||
///
|
||||
/// - `_self`: Opens in the [InAppBrowser].
|
||||
/// - `_blank`: Opens in the [InAppBrowser].
|
||||
/// - `_system`: Opens in the system's web browser.
|
||||
///
|
||||
///- [options]: Options for the [InAppBrowser].
|
||||
///
|
||||
/// All platforms support:
|
||||
/// - __useShouldOverrideUrlLoading__: Set to `true` to be able to listen at the [shouldOverrideUrlLoading()] event. The default value is `false`.
|
||||
/// - __useOnLoadResource__: Set to `true` to be able to listen at the [onLoadResource()] event. The default value is `false`.
|
||||
/// - __clearCache__: Set to `true` to have all the browser's cache cleared before the new window is opened. The default value is `false`.
|
||||
/// - __userAgent___: Set the custom WebView's user-agent.
|
||||
/// - __javaScriptEnabled__: Set to `true` to enable JavaScript. The default value is `true`.
|
||||
/// - __javaScriptCanOpenWindowsAutomatically__: Set to `true` to allow JavaScript open windows without user interaction. The default value is `false`.
|
||||
/// - __hidden__: Set to `true` to create the browser and load the page, but not show it. The `onLoadStop` event fires when loading is complete. Omit or set to `false` (default) to have the browser open and load normally.
|
||||
/// - __toolbarTop__: Set to `false` to hide the toolbar at the top of the WebView. The default value is `true`.
|
||||
/// - __toolbarTopBackgroundColor__: Set the custom background color of the toolbat at the top.
|
||||
/// - __hideUrlBar__: Set to `true` to hide the url bar on the toolbar at the top. The default value is `false`.
|
||||
/// - __mediaPlaybackRequiresUserGesture__: Set to `true` to prevent HTML5 audio or video from autoplaying. The default value is `true`.
|
||||
/// - All platforms support:
|
||||
/// - __useShouldOverrideUrlLoading__: Set to `true` to be able to listen at the [shouldOverrideUrlLoading()] event. The default value is `false`.
|
||||
/// - __useOnLoadResource__: Set to `true` to be able to listen at the [onLoadResource()] event. The default value is `false`.
|
||||
/// - __openWithSystemBrowser__: Set to `true` to open the given `url` with the system browser. The default value is `false`.
|
||||
/// - __isLocalFile__: Set to `true` if the [url] is pointing to a local file (the file must be addded in the `assets` section of your `pubspec.yaml`. See [loadFile()] explanation). The default value is `false`.
|
||||
/// - __clearCache__: Set to `true` to have all the browser's cache cleared before the new window is opened. The default value is `false`.
|
||||
/// - __userAgent___: Set the custom WebView's user-agent.
|
||||
/// - __javaScriptEnabled__: Set to `true` to enable JavaScript. The default value is `true`.
|
||||
/// - __javaScriptCanOpenWindowsAutomatically__: Set to `true` to allow JavaScript open windows without user interaction. The default value is `false`.
|
||||
/// - __hidden__: Set to `true` to create the browser and load the page, but not show it. The `onLoadStop` event fires when loading is complete. Omit or set to `false` (default) to have the browser open and load normally.
|
||||
/// - __toolbarTop__: Set to `false` to hide the toolbar at the top of the WebView. The default value is `true`.
|
||||
/// - __toolbarTopBackgroundColor__: Set the custom background color of the toolbat at the top.
|
||||
/// - __hideUrlBar__: Set to `true` to hide the url bar on the toolbar at the top. The default value is `false`.
|
||||
/// - __mediaPlaybackRequiresUserGesture__: Set to `true` to prevent HTML5 audio or video from autoplaying. The default value is `true`.
|
||||
///
|
||||
/// **Android** supports these additional options:
|
||||
/// - **Android** supports these additional options:
|
||||
///
|
||||
/// - __hideTitleBar__: Set to `true` if you want the title should be displayed. The default value is `false`.
|
||||
/// - __closeOnCannotGoBack__: Set to `false` to not close the InAppBrowser when the user click on the back button and the WebView cannot go back to the history. The default value is `true`.
|
||||
/// - __clearSessionCache__: Set to `true` to have the session cookie cache cleared before the new window is opened.
|
||||
/// - __builtInZoomControls__: Set to `true` if the WebView should use its built-in zoom mechanisms. The default value is `false`.
|
||||
/// - __supportZoom__: Set to `false` if the WebView should not support zooming using its on-screen zoom controls and gestures. The default value is `true`.
|
||||
/// - __databaseEnabled__: Set to `true` if you want the database storage API is enabled. The default value is `false`.
|
||||
/// - __domStorageEnabled__: Set to `true` if you want the DOM storage API is enabled. The default value is `false`.
|
||||
/// - __useWideViewPort__: Set to `true` if the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport. When the value of the setting is false, the layout width is always set to the width of the WebView control in device-independent (CSS) pixels. When the value is true and the page contains the viewport meta tag, the value of the width specified in the tag is used. If the page does not contain the tag or does not provide a width, then a wide viewport will be used. The default value is `true`.
|
||||
/// - __safeBrowsingEnabled__: Set to `true` if you want the Safe Browsing is enabled. Safe Browsing allows WebView to protect against malware and phishing attacks by verifying the links. The default value is `true`.
|
||||
/// - __progressBar__: Set to `false` to hide the progress bar at the bottom of the toolbar at the top. The default value is `true`.
|
||||
/// - __hideTitleBar__: Set to `true` if you want the title should be displayed. The default value is `false`.
|
||||
/// - __closeOnCannotGoBack__: Set to `false` to not close the InAppBrowser when the user click on the back button and the WebView cannot go back to the history. The default value is `true`.
|
||||
/// - __clearSessionCache__: Set to `true` to have the session cookie cache cleared before the new window is opened.
|
||||
/// - __builtInZoomControls__: Set to `true` if the WebView should use its built-in zoom mechanisms. The default value is `false`.
|
||||
/// - __supportZoom__: Set to `false` if the WebView should not support zooming using its on-screen zoom controls and gestures. The default value is `true`.
|
||||
/// - __databaseEnabled__: Set to `true` if you want the database storage API is enabled. The default value is `false`.
|
||||
/// - __domStorageEnabled__: Set to `true` if you want the DOM storage API is enabled. The default value is `false`.
|
||||
/// - __useWideViewPort__: Set to `true` if the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport. When the value of the setting is false, the layout width is always set to the width of the WebView control in device-independent (CSS) pixels. When the value is true and the page contains the viewport meta tag, the value of the width specified in the tag is used. If the page does not contain the tag or does not provide a width, then a wide viewport will be used. The default value is `true`.
|
||||
/// - __safeBrowsingEnabled__: Set to `true` if you want the Safe Browsing is enabled. Safe Browsing allows WebView to protect against malware and phishing attacks by verifying the links. The default value is `true`.
|
||||
/// - __progressBar__: Set to `false` to hide the progress bar at the bottom of the toolbar at the top. The default value is `true`.
|
||||
///
|
||||
/// **iOS** supports these additional options:
|
||||
/// - **iOS** supports these additional options:
|
||||
///
|
||||
/// - __disallowOverScroll__: Set to `true` to disable the bouncing of the WebView when the scrolling has reached an edge of the content. The default value is `false`.
|
||||
/// - __toolbarBottom__: Set to `false` to hide the toolbar at the bottom of the WebView. The default value is `true`.
|
||||
/// - __toolbarBottomBackgroundColor__: Set the custom background color of the toolbat at the bottom.
|
||||
/// - __toolbarBottomTranslucent__: Set to `true` to set the toolbar at the bottom translucent. The default value is `true`.
|
||||
/// - __closeButtonCaption__: Set the custom text for the close button.
|
||||
/// - __closeButtonColor__: Set the custom color for the close button.
|
||||
/// - __presentationStyle__: Set the custom modal presentation style when presenting the WebView. The default value is `0 //fullscreen`. See [UIModalPresentationStyle](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle) for all the available styles.
|
||||
/// - __transitionStyle__: Set to the custom transition style when presenting the WebView. The default value is `0 //crossDissolve`. See [UIModalTransitionStyle](https://developer.apple.com/documentation/uikit/uimodaltransitionStyle) for all the available styles.
|
||||
/// - __enableViewportScale__: Set to `true` to allow a viewport meta tag to either disable or restrict the range of user scaling. The default value is `false`.
|
||||
/// - __suppressesIncrementalRendering__: Set to `true` if you want the WebView suppresses content rendering until it is fully loaded into memory.. The default value is `false`.
|
||||
/// - __allowsAirPlayForMediaPlayback__: Set to `true` to allow AirPlay. The default value is `true`.
|
||||
/// - __allowsBackForwardNavigationGestures__: Set to `true` to allow the horizontal swipe gestures trigger back-forward list navigations. The default value is `true`.
|
||||
/// - __allowsLinkPreview__: Set to `true` to allow that pressing on a link displays a preview of the destination for the link. The default value is `true`.
|
||||
/// - __ignoresViewportScaleLimits__: Set to `true` if you want that the WebView should always allow scaling of the webpage, regardless of the author's intent. The ignoresViewportScaleLimits property overrides the `user-scalable` HTML property in a webpage. The default value is `false`.
|
||||
/// - __allowsInlineMediaPlayback__: Set to `true` to allow HTML5 media playback to appear inline within the screen layout, using browser-supplied controls rather than native controls. For this to work, add the `webkit-playsinline` attribute to any `<video>` elements. The default value is `false`.
|
||||
/// - __allowsPictureInPictureMediaPlayback__: Set to `true` to allow HTML5 videos play picture-in-picture. The default value is `true`.
|
||||
/// - __spinner__: Set to `false` to hide the spinner when the WebView is loading a page. The default value is `true`.
|
||||
Future<void> open({String url = "about:blank", Map<String, String> headers = const {}, String target = "_self", Map<String, dynamic> options = const {}}) async {
|
||||
/// - __disallowOverScroll__: Set to `true` to disable the bouncing of the WebView when the scrolling has reached an edge of the content. The default value is `false`.
|
||||
/// - __toolbarBottom__: Set to `false` to hide the toolbar at the bottom of the WebView. The default value is `true`.
|
||||
/// - __toolbarBottomBackgroundColor__: Set the custom background color of the toolbat at the bottom.
|
||||
/// - __toolbarBottomTranslucent__: Set to `true` to set the toolbar at the bottom translucent. The default value is `true`.
|
||||
/// - __closeButtonCaption__: Set the custom text for the close button.
|
||||
/// - __closeButtonColor__: Set the custom color for the close button.
|
||||
/// - __presentationStyle__: Set the custom modal presentation style when presenting the WebView. The default value is `0 //fullscreen`. See [UIModalPresentationStyle](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle) for all the available styles.
|
||||
/// - __transitionStyle__: Set to the custom transition style when presenting the WebView. The default value is `0 //crossDissolve`. See [UIModalTransitionStyle](https://developer.apple.com/documentation/uikit/uimodaltransitionStyle) for all the available styles.
|
||||
/// - __enableViewportScale__: Set to `true` to allow a viewport meta tag to either disable or restrict the range of user scaling. The default value is `false`.
|
||||
/// - __suppressesIncrementalRendering__: Set to `true` if you want the WebView suppresses content rendering until it is fully loaded into memory.. The default value is `false`.
|
||||
/// - __allowsAirPlayForMediaPlayback__: Set to `true` to allow AirPlay. The default value is `true`.
|
||||
/// - __allowsBackForwardNavigationGestures__: Set to `true` to allow the horizontal swipe gestures trigger back-forward list navigations. The default value is `true`.
|
||||
/// - __allowsLinkPreview__: Set to `true` to allow that pressing on a link displays a preview of the destination for the link. The default value is `true`.
|
||||
/// - __ignoresViewportScaleLimits__: Set to `true` if you want that the WebView should always allow scaling of the webpage, regardless of the author's intent. The ignoresViewportScaleLimits property overrides the `user-scalable` HTML property in a webpage. The default value is `false`.
|
||||
/// - __allowsInlineMediaPlayback__: Set to `true` to allow HTML5 media playback to appear inline within the screen layout, using browser-supplied controls rather than native controls. For this to work, add the `webkit-playsinline` attribute to any `<video>` elements. The default value is `false`.
|
||||
/// - __allowsPictureInPictureMediaPlayback__: Set to `true` to allow HTML5 videos play picture-in-picture. The default value is `true`.
|
||||
/// - __spinner__: Set to `false` to hide the spinner when the WebView is loading a page. The default value is `true`.
|
||||
Future<void> open({String url = "about:blank", Map<String, String> headers = const {}, Map<String, dynamic> options = const {}}) async {
|
||||
this._throwIsAlreadyOpened(message: 'Cannot open $url!');
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
args.putIfAbsent('url', () => url);
|
||||
args.putIfAbsent('headers', () => headers);
|
||||
args.putIfAbsent('target', () => target);
|
||||
args.putIfAbsent('options', () => options);
|
||||
args.putIfAbsent('useChromeSafariBrowser', () => false);
|
||||
await _ChannelManager.channel.invokeMethod('open', args);
|
||||
this._isOpened = true;
|
||||
}
|
||||
|
||||
///This is a static method that opens an [url] in the system browser.
|
||||
///This has the same behaviour of an [InAppBrowser] instance calling the [open()] method with option `openWithSystemBrowser: true`.
|
||||
static Future<void> openWithSystemBrowser(String url) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => "");
|
||||
args.putIfAbsent('url', () => url);
|
||||
args.putIfAbsent('headers', () => {});
|
||||
args.putIfAbsent('options', () => {"openWithSystemBrowser": true});
|
||||
args.putIfAbsent('useChromeSafariBrowser', () => false);
|
||||
return await _ChannelManager.channel.invokeMethod('open', args);
|
||||
}
|
||||
|
||||
Future<void> _startServer({int port = 8080}) async {
|
||||
|
||||
this._closeServer();
|
||||
var completer = new Completer();
|
||||
|
||||
runZoned(() {
|
||||
HttpServer.bind('127.0.0.1', port).then((server) {
|
||||
print('Server running at http://127.0.0.1:' + port.toString());
|
||||
|
||||
this._server = server;
|
||||
|
||||
server.listen((HttpRequest request) async {
|
||||
var body = List<int>();
|
||||
var path = request.requestedUri.path;
|
||||
path = (path.startsWith('/')) ? path.substring(1) : path;
|
||||
path += (path.endsWith('/')) ? 'index.html' : '';
|
||||
|
||||
try {
|
||||
body = (await rootBundle.load(path))
|
||||
.buffer.asUint8List();
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
request.response.close();
|
||||
return;
|
||||
}
|
||||
|
||||
var contentType = ['text', 'html'];
|
||||
if (!request.requestedUri.path.endsWith('/') && request.requestedUri.pathSegments.isNotEmpty) {
|
||||
var mimeType = lookupMimeType(request.requestedUri.path, headerBytes: body);
|
||||
if (mimeType != null) {
|
||||
contentType = mimeType.split('/');
|
||||
}
|
||||
}
|
||||
|
||||
request.response.headers.contentType = new ContentType(contentType[0], contentType[1], charset: 'utf-8');
|
||||
request.response.add(body);
|
||||
request.response.close();
|
||||
});
|
||||
|
||||
completer.complete();
|
||||
});
|
||||
}, onError: (e, stackTrace) => print('Error: $e $stackTrace'));
|
||||
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
Future<void> _closeServer() async {
|
||||
if (this._server != null) {
|
||||
final port = this._server.port;
|
||||
await this._server.close(force: true);
|
||||
print('Server running at http://127.0.0.1:$port closed');
|
||||
this._server = null;
|
||||
}
|
||||
}
|
||||
|
||||
///Serve the [assetFilePath] from Flutter assets on http://localhost:[port]/. It is similar to [InAppBrowser.open()] with option `isLocalFile: true`, but it starts a server.
|
||||
///
|
||||
///**NOTE for iOS**: For the iOS Platform, you need to add the `NSAllowsLocalNetworking` key with `true` in the `Info.plist` file (See [ATS Configuration Basics](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35):
|
||||
///```xml
|
||||
///<key>NSAppTransportSecurity</key>
|
||||
///<dict>
|
||||
/// <key>NSAllowsLocalNetworking</key>
|
||||
/// <true/>
|
||||
///</dict>
|
||||
///```
|
||||
///The `NSAllowsLocalNetworking` key is available since **iOS 10**.
|
||||
Future<void> openOnLocalhost(String assetFilePath, {int port = 8080, Map<String, String> headers = const {}, Map<String, dynamic> options = const {}}) async {
|
||||
this._throwIsAlreadyOpened(message: 'Cannot open $assetFilePath!');
|
||||
await this._startServer(port: port);
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
args.putIfAbsent('url', () => 'http://localhost:${this._server.port}/' + assetFilePath);
|
||||
args.putIfAbsent('headers', () => headers);
|
||||
options["isLocalFile"] = false;
|
||||
args.putIfAbsent('options', () => options);
|
||||
args.putIfAbsent('useChromeSafariBrowser', () => false);
|
||||
await _ChannelManager.channel.invokeMethod('open', args);
|
||||
this._isOpened = true;
|
||||
}
|
||||
|
||||
///Loads the given [url] with optional [headers] specified as a map from name to value.
|
||||
Future<void> loadUrl(String url, {Map<String, String> headers = const {}}) async {
|
||||
this._throwIsNotOpened(message: 'Cannot laod $url!');
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
args.putIfAbsent('url', () => url);
|
||||
args.putIfAbsent('headers', () => headers);
|
||||
return await _ChannelManager.channel.invokeMethod('loadUrl', args);
|
||||
await _ChannelManager.channel.invokeMethod('loadUrl', args);
|
||||
}
|
||||
|
||||
///Loads the given [assetFilePath] with optional [headers] specified as a map from name to value.
|
||||
///
|
||||
///To be able to load your local files (assets, js, css, etc.), you need to add them in the `assets` section of the `pubspec.yaml` file, otherwise they cannot be found!
|
||||
///
|
||||
///Example of a `pubspec.yaml` file:
|
||||
///```yaml
|
||||
///...
|
||||
///
|
||||
///# The following section is specific to Flutter.
|
||||
///flutter:
|
||||
///
|
||||
/// # The following line ensures that the Material Icons font is
|
||||
/// # included with your application, so that you can use the icons in
|
||||
/// # the material Icons class.
|
||||
/// uses-material-design: true
|
||||
///
|
||||
/// assets:
|
||||
/// - assets/index.html
|
||||
/// - assets/css/
|
||||
/// - assets/images/
|
||||
///
|
||||
///...
|
||||
///```
|
||||
///Example of a `main.dart` file:
|
||||
///```dart
|
||||
///...
|
||||
///inAppBrowser.loadFile("assets/index.html");
|
||||
///...
|
||||
///```
|
||||
Future<void> loadFile(String assetFilePath, {Map<String, String> headers = const {}}) async {
|
||||
this._throwIsNotOpened(message: 'Cannot laod $assetFilePath!');
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
args.putIfAbsent('url', () => assetFilePath);
|
||||
args.putIfAbsent('headers', () => headers);
|
||||
await _ChannelManager.channel.invokeMethod('loadFile', args);
|
||||
}
|
||||
|
||||
///Displays an [InAppBrowser] window that was opened hidden. Calling this has no effect if the [InAppBrowser] was already visible.
|
||||
Future<void> show() async {
|
||||
this._throwIsNotOpened();
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
return await _ChannelManager.channel.invokeMethod('show', args);
|
||||
await _ChannelManager.channel.invokeMethod('show', args);
|
||||
}
|
||||
|
||||
///Hides the [InAppBrowser] window. Calling this has no effect if the [InAppBrowser] was already hidden.
|
||||
Future<void> hide() async {
|
||||
this._throwIsNotOpened();
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
return await _ChannelManager.channel.invokeMethod('hide', args);
|
||||
await _ChannelManager.channel.invokeMethod('hide', args);
|
||||
}
|
||||
|
||||
///Closes the [InAppBrowser] window.
|
||||
Future<void> close() async {
|
||||
this._throwIsNotOpened();
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
return await _ChannelManager.channel.invokeMethod('close', args);
|
||||
await _ChannelManager.channel.invokeMethod('close', args);
|
||||
}
|
||||
|
||||
///Reloads the [InAppBrowser] window.
|
||||
Future<void> reload() async {
|
||||
this._throwIsNotOpened();
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
return await _ChannelManager.channel.invokeMethod('reload', args);
|
||||
await _ChannelManager.channel.invokeMethod('reload', args);
|
||||
}
|
||||
|
||||
///Goes back in the history of the [InAppBrowser] window.
|
||||
Future<void> goBack() async {
|
||||
this._throwIsNotOpened();
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
return await _ChannelManager.channel.invokeMethod('goBack', args);
|
||||
await _ChannelManager.channel.invokeMethod('goBack', args);
|
||||
}
|
||||
|
||||
///Goes forward in the history of the [InAppBrowser] window.
|
||||
Future<void> goForward() async {
|
||||
this._throwIsNotOpened();
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
return await _ChannelManager.channel.invokeMethod('goForward', args);
|
||||
await _ChannelManager.channel.invokeMethod('goForward', args);
|
||||
}
|
||||
|
||||
///Check if the Web View of the [InAppBrowser] instance is in a loading state.
|
||||
Future<bool> isLoading() async {
|
||||
this._throwIsNotOpened();
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
return await _ChannelManager.channel.invokeMethod('isLoading', args);
|
||||
@ -317,48 +461,54 @@ class InAppBrowser {
|
||||
|
||||
///Stops the Web View of the [InAppBrowser] instance from loading.
|
||||
Future<void> stopLoading() async {
|
||||
this._throwIsNotOpened();
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
return await _ChannelManager.channel.invokeMethod('stopLoading', args);
|
||||
await _ChannelManager.channel.invokeMethod('stopLoading', args);
|
||||
}
|
||||
|
||||
///Check if the Web View of the [InAppBrowser] instance is hidden.
|
||||
Future<bool> isHidden() async {
|
||||
this._throwIsNotOpened();
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
return await _ChannelManager.channel.invokeMethod('isHidden', args);
|
||||
}
|
||||
|
||||
///Injects JavaScript code into the [InAppBrowser] window and returns the result of the evaluation. (Only available when the target is set to `_blank` or to `_self`)
|
||||
///Injects JavaScript code into the [InAppBrowser] window and returns the result of the evaluation.
|
||||
Future<String> injectScriptCode(String source) async {
|
||||
this._throwIsNotOpened();
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
args.putIfAbsent('source', () => source);
|
||||
return await _ChannelManager.channel.invokeMethod('injectScriptCode', args);
|
||||
}
|
||||
|
||||
///Injects a JavaScript file into the [InAppBrowser] window. (Only available when the target is set to `_blank` or to `_self`)
|
||||
///Injects a JavaScript file into the [InAppBrowser] window.
|
||||
Future<void> injectScriptFile(String urlFile) async {
|
||||
this._throwIsNotOpened();
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
args.putIfAbsent('urlFile', () => urlFile);
|
||||
return await _ChannelManager.channel.invokeMethod('injectScriptFile', args);
|
||||
await _ChannelManager.channel.invokeMethod('injectScriptFile', args);
|
||||
}
|
||||
|
||||
///Injects CSS into the [InAppBrowser] window. (Only available when the target is set to `_blank` or to `_self`)
|
||||
///Injects CSS into the [InAppBrowser] window.
|
||||
Future<void> injectStyleCode(String source) async {
|
||||
this._throwIsNotOpened();
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
args.putIfAbsent('source', () => source);
|
||||
return await _ChannelManager.channel.invokeMethod('injectStyleCode', args);
|
||||
await _ChannelManager.channel.invokeMethod('injectStyleCode', args);
|
||||
}
|
||||
|
||||
///Injects a CSS file into the [InAppBrowser] window. (Only available when the target is set to `_blank` or to `_self`)
|
||||
///Injects a CSS file into the [InAppBrowser] window.
|
||||
Future<void> injectStyleFile(String urlFile) async {
|
||||
this._throwIsNotOpened();
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
args.putIfAbsent('urlFile', () => urlFile);
|
||||
return await _ChannelManager.channel.invokeMethod('injectStyleFile', args);
|
||||
await _ChannelManager.channel.invokeMethod('injectStyleFile', args);
|
||||
}
|
||||
|
||||
///Adds/Appends a JavaScript message handler [callback] ([JavaScriptHandlerCallback]) that listen to post messages sent from JavaScript by the handler with name [handlerName].
|
||||
@ -419,7 +569,7 @@ class InAppBrowser {
|
||||
///
|
||||
///**NOTE**: In order to be able to listen this event, you need to set `useOnLoadResource` option to `true`.
|
||||
///
|
||||
///**NOTE only for iOS**: In some cases, the [response.data] of a [response] with `text/html` encoding could be empty.
|
||||
///**NOTE only for iOS**: In some cases, the [response.data] of a [response] with `text/assets` encoding could be empty.
|
||||
void onLoadResource(WebResourceResponse response, WebResourceRequest request) {
|
||||
|
||||
}
|
||||
@ -429,6 +579,22 @@ class InAppBrowser {
|
||||
|
||||
}
|
||||
|
||||
///Returns `true` if the browser is opened, otherwise `false`.
|
||||
bool isOpened() {
|
||||
return this._isOpened;
|
||||
}
|
||||
|
||||
void _throwIsAlreadyOpened({String message = ''}) {
|
||||
if (this.isOpened()) {
|
||||
throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is already opened.']);
|
||||
}
|
||||
}
|
||||
|
||||
void _throwIsNotOpened({String message = ''}) {
|
||||
if (!this.isOpened()) {
|
||||
throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is not opened.']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///ChromeSafariBrowser class.
|
||||
@ -440,12 +606,14 @@ class InAppBrowser {
|
||||
class ChromeSafariBrowser {
|
||||
String uuid;
|
||||
InAppBrowser browserFallback;
|
||||
bool _isOpened = false;
|
||||
|
||||
///Initialize the [ChromeSafariBrowser] instance with a [InAppBrowser] fallback instance or `null`.
|
||||
ChromeSafariBrowser (bf) {
|
||||
uuid = _uuidGenerator.v4();
|
||||
browserFallback = bf;
|
||||
_ChannelManager.addListener(uuid, _handleMethod);
|
||||
_isOpened = false;
|
||||
}
|
||||
|
||||
Future<dynamic> _handleMethod(MethodCall call) async {
|
||||
@ -458,9 +626,11 @@ class ChromeSafariBrowser {
|
||||
break;
|
||||
case "onChromeSafariBrowserClosed":
|
||||
onClosed();
|
||||
this._isOpened = false;
|
||||
break;
|
||||
default:
|
||||
throw UnimplementedError("Unimplemented ${call.method} method");
|
||||
}
|
||||
return new Future.value("");
|
||||
}
|
||||
|
||||
///Opens an [url] in a new [ChromeSafariBrowser] instance or the system browser.
|
||||
@ -491,16 +661,17 @@ class ChromeSafariBrowser {
|
||||
///- __presentationStyle__: Set the custom modal presentation style when presenting the WebView. The default value is `0 //fullscreen`. See [UIModalPresentationStyle](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle) for all the available styles.
|
||||
///- __transitionStyle__: Set to the custom transition style when presenting the WebView. The default value is `0 //crossDissolve`. See [UIModalTransitionStyle](https://developer.apple.com/documentation/uikit/uimodaltransitionStyle) for all the available styles.
|
||||
Future<void> open(String url, {Map<String, dynamic> options = const {}, Map<String, String> headersFallback = const {}, Map<String, dynamic> optionsFallback = const {}}) async {
|
||||
this._throwIsAlreadyOpened(message: 'Cannot open $url!');
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('uuid', () => uuid);
|
||||
args.putIfAbsent('uuidFallback', () => (browserFallback != null) ? browserFallback.uuid : '');
|
||||
args.putIfAbsent('url', () => url);
|
||||
args.putIfAbsent('headers', () => headersFallback);
|
||||
args.putIfAbsent('target', () => "");
|
||||
args.putIfAbsent('options', () => options);
|
||||
args.putIfAbsent('optionsFallback', () => optionsFallback);
|
||||
args.putIfAbsent('useChromeSafariBrowser', () => true);
|
||||
return await _ChannelManager.channel.invokeMethod('open', args);
|
||||
await _ChannelManager.channel.invokeMethod('open', args);
|
||||
this._isOpened = true;
|
||||
}
|
||||
|
||||
///Event fires when the [ChromeSafariBrowser] is opened.
|
||||
@ -517,4 +688,20 @@ class ChromeSafariBrowser {
|
||||
void onClosed() {
|
||||
|
||||
}
|
||||
|
||||
bool isOpened() {
|
||||
return this._isOpened;
|
||||
}
|
||||
|
||||
void _throwIsAlreadyOpened({String message = ''}) {
|
||||
if (this.isOpened()) {
|
||||
throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is already opened.']);
|
||||
}
|
||||
}
|
||||
|
||||
void _throwIsNotOpened({String message = ''}) {
|
||||
if (!this.isOpened()) {
|
||||
throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is not opened.']);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
name: flutter_inappbrowser
|
||||
description: A Flutter plugin that allows you to open an in-app browser window. (inspired by the popular cordova-plugin-inappbrowser).
|
||||
version: 0.3.2
|
||||
version: 0.4.0
|
||||
author: Lorenzo Pichilli <pichillilorenzo@gmail.com>
|
||||
homepage: https://github.com/pichillilorenzo/flutter_inappbrowser
|
||||
|
||||
@ -11,6 +11,7 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
uuid: ^1.0.3
|
||||
mime: ^0.9.6+2
|
||||
|
||||
# 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