added support for iOS inline native WebView integrated in the flutter widget tree (#18, #45), fix #54 #38 #26 #32 #33 #29 #15

This commit is contained in:
pichillilorenzo 2019-03-11 03:34:58 +01:00
parent 2b600fbb6c
commit 1dfa6323c6
14 changed files with 464 additions and 771 deletions

View File

@ -16,7 +16,19 @@
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="9b41f7a2-a71e-4923-91fb-249d7815b3e7" name="Default" comment=""> <list default="true" id="9b41f7a2-a71e-4923-91fb-249d7815b3e7" name="Default" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" 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$/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$/android/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/android/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/gradle/wrapper/gradle-wrapper.properties" beforeDir="false" afterPath="$PROJECT_DIR$/android/gradle/wrapper/gradle-wrapper.properties" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/android/gradle/wrapper/gradle-wrapper.properties" beforeDir="false" afterPath="$PROJECT_DIR$/example/android/gradle/wrapper/gradle-wrapper.properties" 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$/example/lib/webview_example.screen.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/webview_example.screen.dart" 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/InAppBrowserWebViewController.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/InAppBrowserWebViewController.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/Classes/InAppWebView.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/InAppWebView.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/pubspec.yaml" afterDir="false" />
</list> </list>
<ignored path="$PROJECT_DIR$/.dart_tool/" /> <ignored path="$PROJECT_DIR$/.dart_tool/" />
<ignored path="$PROJECT_DIR$/.idea/" /> <ignored path="$PROJECT_DIR$/.idea/" />
@ -36,8 +48,8 @@
<file leaf-file-name="flutter_inappbrowser.dart" pinned="false" current-in-tab="false"> <file leaf-file-name="flutter_inappbrowser.dart" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart"> <entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="4380"> <state relative-caret-position="415">
<caret line="323" column="41" selection-start-line="323" selection-start-column="41" selection-end-line="323" selection-end-column="41" /> <caret line="698" column="22" selection-start-line="698" selection-start-column="13" selection-end-line="698" selection-end-column="22" />
<folding> <folding>
<element signature="e#814#831#0" expanded="true" /> <element signature="e#814#831#0" expanded="true" />
</folding> </folding>
@ -45,13 +57,31 @@
</provider> </provider>
</entry> </entry>
</file> </file>
<file leaf-file-name="main.dart" pinned="false" current-in-tab="true"> <file leaf-file-name="CHANGELOG.md" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/example/lib/main.dart"> <entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="405"> <state relative-caret-position="195">
<caret line="27" column="18" lean-forward="true" selection-start-line="27" selection-start-column="18" selection-end-line="27" selection-end-column="18" /> <caret line="13" column="21" selection-start-line="13" selection-start-column="21" selection-end-line="13" selection-end-column="21" />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="pubspec.yaml" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="195">
<caret line="13" column="14" lean-forward="true" selection-start-line="13" selection-start-column="14" selection-end-line="13" selection-end-column="14" />
</state>
</provider>
</entry>
</file>
<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="text-editor">
<state relative-caret-position="589">
<caret line="72" column="7" lean-forward="true" selection-start-line="72" selection-start-column="7" selection-end-line="72" selection-end-column="7" />
<folding> <folding>
<element signature="e#0#20#0" expanded="true" /> <element signature="e#0#39#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
@ -68,20 +98,6 @@
</component> </component>
<component name="FindInProjectRecents"> <component name="FindInProjectRecents">
<findStrings> <findStrings>
<find>assert(</find>
<find>sNotEmpty()</find>
<find>loadData</find>
<find>_valide</find>
<find>initialized</find>
<find>HashMap</find>
<find>headers</find>
<find>.cast</find>
<find>WebView</find>
<find>print</find>
<find>throw</find>
<find>InAppWeb</find>
<find>Boolean</find>
<find>[WebHistory.list]</find>
<find>open</find> <find>open</find>
<find>Cannot laod</find> <find>Cannot laod</find>
<find>_throwIsNotOpened</find> <find>_throwIsNotOpened</find>
@ -98,6 +114,20 @@
<find>initialData</find> <find>initialData</find>
<find>openData</find> <find>openData</find>
<find>optionsType</find> <find>optionsType</find>
<find>InAppWebView</find>
<find>fromInAppBrowser</find>
<find>InAppWebViewController</find>
<find>_handleMethod</find>
<find>InAppBrowser</find>
<find>handlerTest</find>
<find>onLoadStart</find>
<find>distributionUrl</find>
<find>args.putIfAbsent('isData', () =&gt; false);</find>
<find>VERSIONING_SYSTEM</find>
<find>config.build_settings['SWIFT_VERSION']</find>
<find>BUILD TARGET</find>
<find>InAppWebView {</find>
<find>AndroidView</find>
</findStrings> </findStrings>
<replaceStrings> <replaceStrings>
<replace>activity.getPreferences(0)</replace> <replace>activity.getPreferences(0)</replace>
@ -132,26 +162,29 @@
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java" /> <option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java" />
<option value="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" /> <option value="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" />
<option value="$PROJECT_DIR$/example/ios/Podfile" /> <option value="$PROJECT_DIR$/example/ios/Podfile" />
<option value="$PROJECT_DIR$/android/build.gradle" />
<option value="$PROJECT_DIR$/example/html/css/style.css" /> <option value="$PROJECT_DIR$/example/html/css/style.css" />
<option value="$PROJECT_DIR$/example/html/index.html" /> <option value="$PROJECT_DIR$/example/html/index.html" />
<option value="$PROJECT_DIR$/example/assets/css/style.css" /> <option value="$PROJECT_DIR$/example/assets/css/style.css" />
<option value="$PROJECT_DIR$/example/assets/index.html" /> <option value="$PROJECT_DIR$/example/assets/index.html" />
<option value="$PROJECT_DIR$/example/ios/Flutter/Generated.xcconfig" /> <option value="$PROJECT_DIR$/example/ios/Flutter/Generated.xcconfig" />
<option value="$PROJECT_DIR$/example/pubspec.yaml" /> <option value="$PROJECT_DIR$/example/pubspec.yaml" />
<option value="$PROJECT_DIR$/example/ios/Runner/Info.plist" />
<option value="$PROJECT_DIR$/lib/flutter_inappbrowser.dart" />
<option value="$PROJECT_DIR$/example/lib/webview_example.screen.dart" />
<option value="$PROJECT_DIR$/example/lib/test.dart" />
<option value="$PROJECT_DIR$/example/lib/main.dart" />
<option value="$PROJECT_DIR$/android/build.gradle" />
<option value="$PROJECT_DIR$/android/gradle/wrapper/gradle-wrapper.properties" />
<option value="$PROJECT_DIR$/CHANGELOG.md" />
<option value="$PROJECT_DIR$/README.md" /> <option value="$PROJECT_DIR$/README.md" />
<option value="$PROJECT_DIR$/pubspec.yaml" /> <option value="$PROJECT_DIR$/pubspec.yaml" />
<option value="$PROJECT_DIR$/CHANGELOG.md" />
<option value="$PROJECT_DIR$/lib/flutter_inappbrowser.dart" />
<option value="$PROJECT_DIR$/example/ios/Runner/Info.plist" />
<option value="$PROJECT_DIR$/example/lib/main.dart" />
</list> </list>
</option> </option>
</component> </component>
<component name="ProjectFrameBounds" extendedState="6"> <component name="ProjectFrameBounds">
<option name="y" value="23" /> <option name="y" value="23" />
<option name="width" value="1641" /> <option name="width" value="1920" />
<option name="height" value="1027" /> <option name="height" value="1057" />
</component> </component>
<component name="ProjectLevelVcsManager" settingsEditedManually="true" /> <component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectView"> <component name="ProjectView">
@ -159,7 +192,35 @@
<foldersAlwaysOnTop value="true" /> <foldersAlwaysOnTop value="true" />
</navigator> </navigator>
<panes> <panes>
<pane id="AndroidView" /> <pane id="AndroidView">
<subPane>
<expand>
<path>
<item name="flutter_inappbrowser" type="1abcf292:AndroidViewProjectNode" />
<item name="flutter_inappbrowser_android" type="e9137016:NonAndroidModuleNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="1abcf292:AndroidViewProjectNode" />
<item name="flutter_inappbrowser_android" type="e9137016:NonAndroidModuleNode" />
<item name="java" type="f7eae187:NonAndroidSourceTypeNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="1abcf292:AndroidViewProjectNode" />
<item name="flutter_inappbrowser_android" type="e9137016:NonAndroidModuleNode" />
<item name="java" type="f7eae187:NonAndroidSourceTypeNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="1abcf292:AndroidViewProjectNode" />
<item name="flutter_inappbrowser_android" type="e9137016:NonAndroidModuleNode" />
<item name="java" type="f7eae187:NonAndroidSourceTypeNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="InAppWebView" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
<pane id="Scope"> <pane id="Scope">
<subPane subId="Project Files"> <subPane subId="Project Files">
<expand> <expand>
@ -178,29 +239,6 @@
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" /> <item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" /> <item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
</path> </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="ios" 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="ios" type="462c0819:PsiDirectoryNode" />
<item name="Runner" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="ios" type="462c0819:PsiDirectoryNode" />
</path>
<path> <path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" /> <item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" /> <item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
@ -368,33 +406,33 @@
<servers /> <servers />
</component> </component>
<component name="ToolWindowManager"> <component name="ToolWindowManager">
<frame x="0" y="23" width="1680" height="1027" extended-state="6" /> <frame x="0" y="23" width="1920" height="1057" extended-state="0" />
<editor active="true" /> <editor active="true" />
<layout> <layout>
<window_info anchor="bottom" id="Android Profiler" order="7" show_stripe_button="false" /> <window_info anchor="bottom" id="Android Profiler" order="7" show_stripe_button="false" />
<window_info anchor="bottom" id="TODO" order="6" /> <window_info anchor="bottom" id="TODO" order="6" />
<window_info anchor="bottom" id="Messages" order="12" weight="0.23585913" />
<window_info anchor="right" id="Palette&#9;" order="9" /> <window_info anchor="right" id="Palette&#9;" order="9" />
<window_info id="Image Layers" order="7" /> <window_info id="Image Layers" order="7" />
<window_info id="Build Variants" order="3" side_tool="true" /> <window_info id="Build Variants" order="3" side_tool="true" />
<window_info anchor="right" id="Capture Analysis" order="4" /> <window_info anchor="right" id="Capture Analysis" order="4" />
<window_info anchor="bottom" id="Event Log" order="8" sideWeight="0.5052169" side_tool="true" weight="0.34068358" /> <window_info anchor="bottom" id="Event Log" order="8" sideWeight="0.5052169" side_tool="true" weight="0.34068358" />
<window_info anchor="bottom" id="Dart Analysis" order="14" weight="0.32745314" /> <window_info anchor="bottom" id="Dart Analysis" order="14" weight="0.32745314" />
<window_info anchor="bottom" id="Run" order="2" sideWeight="0.49478307" weight="0.29437706" /> <window_info anchor="bottom" id="Run" order="2" sideWeight="0.49478307" visible="true" weight="0.36926362" />
<window_info anchor="bottom" id="Version Control" order="9" /> <window_info anchor="bottom" id="Version Control" order="9" />
<window_info active="true" anchor="bottom" id="Terminal" order="10" sideWeight="0.49533224" visible="true" weight="0.24696803" /> <window_info anchor="bottom" id="Terminal" order="10" sideWeight="0.49533224" weight="0.24653149" />
<window_info anchor="right" id="Flutter Outline" order="6" weight="0.32922077" /> <window_info anchor="right" id="Flutter Outline" order="6" weight="0.32922077" />
<window_info anchor="bottom" id="Logcat" order="11" /> <window_info anchor="bottom" id="Logcat" order="11" />
<window_info id="Captures" order="4" weight="0.32936507" /> <window_info id="Captures" order="4" weight="0.32936507" />
<window_info id="Capture Tool" order="6" /> <window_info id="Capture Tool" order="6" />
<window_info id="Designer" order="2" /> <window_info id="Designer" order="2" />
<window_info content_ui="combo" id="Project" order="0" sideWeight="0.49341142" visible="true" weight="0.13125764" /> <window_info active="true" content_ui="combo" id="Project" order="0" sideWeight="0.6615905" visible="true" weight="0.18210863" />
<window_info id="Structure" order="1" sideWeight="0.5065886" side_tool="true" visible="true" weight="0.13125764" /> <window_info id="Structure" order="1" sideWeight="0.33840948" side_tool="true" visible="true" weight="0.18210863" />
<window_info anchor="right" id="Device File Explorer" order="5" side_tool="true" /> <window_info anchor="right" id="Device File Explorer" order="5" side_tool="true" />
<window_info anchor="right" id="Theme Preview" order="7" /> <window_info anchor="right" id="Theme Preview" order="7" />
<window_info anchor="bottom" id="Debug" order="3" weight="0.34288865" /> <window_info anchor="bottom" id="Debug" order="3" weight="0.34288865" />
<window_info id="Favorites" order="5" side_tool="true" /> <window_info id="Favorites" order="5" side_tool="true" />
<window_info anchor="right" id="Flutter Inspector" order="3" weight="0.32938388" /> <window_info anchor="right" id="Flutter Inspector" order="3" weight="0.32938388" />
<window_info anchor="bottom" id="Messages" order="12" visible="true" weight="0.23594266" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" /> <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="Commander" order="0" weight="0.4" />
<window_info anchor="right" id="Assistant" order="8" visible="true" weight="0.3295129" /> <window_info anchor="right" id="Assistant" order="8" visible="true" weight="0.3295129" />
@ -418,55 +456,6 @@
</breakpoint-manager> </breakpoint-manager>
</component> </component>
<component name="editorHistoryManager"> <component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/ios/Classes/InAppBrowser.h" />
<entry file="file://$PROJECT_DIR$/ios/Classes/InAppBrowser.m" />
<entry file="file://$PROJECT_DIR$/LICENSE">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="15">
<caret line="1" column="31" selection-start-line="1" selection-start-column="31" selection-end-line="1" selection-end-column="31" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="90">
<caret line="6" lean-forward="true" selection-start-line="6" selection-end-line="6" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserClient.java" />
<entry file="file://$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserDialog.java" />
<entry file="file://$PROJECT_DIR$/example/ios/Flutter/Release.xcconfig">
<provider selected="true" editor-type-id="text-editor">
<state />
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Flutter/Debug.xcconfig">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" selection-start-line="2" selection-end-line="2" selection-end-column="24" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor">
<state />
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/ios/Classes/InAppBrowserWebViewController.swift">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="180">
<caret line="12" selection-start-line="12" selection-end-line="12" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="191">
<caret line="107" column="9" selection-start-line="107" selection-start-column="9" selection-end-line="107" selection-end-column="9" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/build.gradle"> <entry file="file://$PROJECT_DIR$/example/android/build.gradle">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state /> <state />
@ -510,23 +499,6 @@
<state relative-caret-position="-10645" /> <state relative-caret-position="-10645" />
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/android/settings.gradle">
<provider selected="true" editor-type-id="text-editor">
<state>
<caret column="20" selection-start-column="20" selection-end-column="20" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/local.properties">
<provider selected="true" editor-type-id="text-editor">
<state />
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/gradle.properties">
<provider selected="true" editor-type-id="text-editor">
<state />
</provider>
</entry>
<entry file="file://$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib/core/string.dart"> <entry file="file://$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib/core/string.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="173"> <state relative-caret-position="173">
@ -534,20 +506,6 @@
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/ios/flutter_inappbrowser.podspec">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="330">
<caret line="22" lean-forward="true" selection-start-line="22" selection-end-line="22" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="414">
<caret line="34" column="5" selection-start-line="34" selection-start-column="5" selection-end-line="34" selection-end-column="5" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/assets/images/dart.svg"> <entry file="file://$PROJECT_DIR$/example/assets/images/dart.svg">
<provider selected="true" editor-type-id="images"> <provider selected="true" editor-type-id="images">
<state /> <state />
@ -572,13 +530,6 @@
<state /> <state />
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/ios/Podfile">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="975">
<caret line="65" column="52" selection-start-line="65" selection-start-column="52" selection-end-line="65" selection-end-column="52" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/flutter_webview_example.iml"> <entry file="file://$PROJECT_DIR$/example/flutter_webview_example.iml">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state /> <state />
@ -643,54 +594,178 @@
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/pubspec.yaml"> <entry file="file://$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="15"> <state relative-caret-position="-1555">
<caret line="1" column="103" selection-start-line="1" selection-start-column="103" selection-end-line="1" selection-end-column="103" /> <caret line="2" selection-start-line="2" selection-end-line="2" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/CHANGELOG.md"> <entry file="file://$PROJECT_DIR$/ios/flutter_inappbrowser.podspec">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state> <state relative-caret-position="330">
<caret selection-end-line="3" selection-end-column="21" /> <caret line="22" selection-start-line="22" selection-end-line="22" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/README.md"> <entry file="file://$PROJECT_DIR$/example/lib/inline_example.screen.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="327"> <state relative-caret-position="52">
<caret line="601" column="21" selection-start-line="601" selection-start-column="21" selection-end-line="601" selection-end-column="21" /> <caret line="14" column="20" selection-start-line="14" selection-start-column="20" selection-end-line="14" selection-end-column="20" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Runner/Info.plist">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="735">
<caret line="49" column="4" selection-start-line="49" selection-start-column="4" selection-end-line="49" selection-end-column="4" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="4380">
<caret line="323" column="41" selection-start-line="323" selection-start-column="41" selection-end-line="323" selection-end-column="41" />
<folding> <folding>
<element signature="e#814#831#0" expanded="true" /> <element signature="e#0#39#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/webview_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="254">
<caret line="63" column="2" selection-start-line="63" selection-start-column="2" selection-end-line="63" selection-end-column="2" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/lib/main.dart"> <entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="405"> <state relative-caret-position="24">
<caret line="27" column="18" lean-forward="true" selection-start-line="27" selection-start-column="18" selection-end-line="27" selection-end-column="18" /> <caret line="27" column="18" selection-end-line="63" />
<folding> <folding>
<element signature="e#0#20#0" expanded="true" /> <element signature="e#0#20#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/lib/test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="590">
<caret line="475" selection-start-line="343" selection-end-line="475" />
<folding>
<element signature="e#0#16428#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/gradle.properties">
<provider selected="true" editor-type-id="text-editor">
<state />
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/local.properties">
<provider selected="true" editor-type-id="text-editor">
<state />
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/gradle/wrapper/gradle-wrapper.properties">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="75">
<caret line="5" selection-start-line="5" selection-end-line="5" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/settings.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="15">
<caret line="1" selection-start-line="1" selection-end-line="1" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/gradle/wrapper/gradle-wrapper.properties">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="75">
<caret line="5" selection-start-line="5" selection-end-line="5" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/chrome_safari_example.screen.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="317">
<caret line="24" column="80" selection-start-line="24" selection-start-column="68" selection-end-line="24" selection-end-column="80" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="110">
<caret line="10" column="55" selection-start-line="10" selection-start-column="55" selection-end-line="10" selection-end-column="55" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Flutter/App.framework/Info.plist">
<provider selected="true" editor-type-id="text-editor">
<state />
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Flutter/Flutter.framework/Info.plist">
<provider selected="true" editor-type-id="text-editor">
<state />
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Flutter/AppFrameworkInfo.plist">
<provider selected="true" editor-type-id="text-editor">
<state />
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Runner/Info.plist">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="511">
<caret line="49" column="4" selection-start-line="49" selection-start-column="4" selection-end-line="49" selection-end-column="4" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Runner.xcodeproj/project.pbxproj">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="211">
<caret line="453" column="10" selection-start-line="453" selection-start-column="10" selection-end-line="453" selection-end-column="10" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/ios/Podfile">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="614">
<caret line="66" column="44" selection-start-line="66" selection-start-column="6" selection-end-line="66" selection-end-column="44" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="415">
<caret line="698" column="22" selection-start-line="698" selection-start-column="13" selection-end-line="698" selection-end-column="22" />
<folding>
<element signature="e#814#831#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="589">
<caret line="72" column="7" lean-forward="true" selection-start-line="72" selection-start-column="7" selection-end-line="72" selection-end-column="7" />
<folding>
<element signature="e#0#39#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="195">
<caret line="13" column="21" selection-start-line="13" selection-start-column="21" selection-end-line="13" selection-end-column="21" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="195">
<caret line="13" column="14" lean-forward="true" selection-start-line="13" selection-start-column="14" selection-end-line="13" selection-end-column="14" />
</state>
</provider>
</entry>
</component> </component>
<component name="masterDetails"> <component name="masterDetails">
<states> <states>

View File

@ -1,3 +1,13 @@
## 0.6.0
- added support for **iOS** inline native WebView integrated in the flutter widget tree
- updated example folder (thanks to [marquesinijatinha](https://github.com/marquesinijatinha))
- Fixed bug where passing null to expiresDate failed (thanks to [Sense545](https://github.com/Sense545))
- Fixed iOS error: encode resourceURL (thanks to [igtm](https://github.com/igtm))
- Fixed iOS error: Double value cannot be converted to Int because the result would be greater than Int.max in 32-bit devices (thanks to [huzhiren](https://github.com/huzhiren))
- Fixed iOS error: problem in ChromeSafariBrowser (thanks to [marquesinijatinha](https://github.com/marquesinijatinha))
- Fixed Android build error caused by gradle and build gradle versions (thanks to [tje3d](https://github.com/tje3d))
## 0.5.51 ## 0.5.51
- updated `pubspec.yaml` - updated `pubspec.yaml`

View File

@ -15,12 +15,30 @@ This plugin is inspired by the popular [cordova-plugin-inappbrowser](https://git
- Flutter: ">=0.10.1 <2.0.0" - Flutter: ">=0.10.1 <2.0.0"
### IMPORTANT Note for iOS ### IMPORTANT Note for iOS
To be able to use this plugin on iOS, you need to create the Flutter App with `flutter create -i swift` (see [flutter/flutter#13422 (comment)](https://github.com/flutter/flutter/issues/13422#issuecomment-392133780)), otherwise, you will get this message: If you are starting a new fresh app, you need to create the Flutter App with `flutter create -i swift` (see [flutter/flutter#13422 (comment)](https://github.com/flutter/flutter/issues/13422#issuecomment-392133780)), otherwise, you will get this message:
``` ```
=== BUILD TARGET flutter_inappbrowser OF PROJECT Pods WITH CONFIGURATION Debug === === BUILD TARGET flutter_inappbrowser OF PROJECT Pods WITH CONFIGURATION Debug ===
The “Swift Language Version” (SWIFT_VERSION) build setting must be set to a supported value for targets which use Swift. Supported values are: 3.0, 4.0, 4.2. This setting can be set in the build settings editor. The “Swift Language Version” (SWIFT_VERSION) build setting must be set to a supported value for targets which use Swift. Supported values are: 3.0, 4.0, 4.2. This setting can be set in the build settings editor.
``` ```
that is not true! The Swift version that I have used is already a supported value: 4.0.
If you still have this problem, try to edit iOS `Podfile` like this (see [#15](https://github.com/pichillilorenzo/flutter_inappbrowser/issues/15)):
```
target 'Runner' do
use_frameworks! # required by simple_permission
...
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = '4.0' # required by simple_permission
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end
```
Instead, if you have already a non-swift project, you can check this issue to solve the problem: [Friction adding swift plugin to objective-c project](https://github.com/flutter/flutter/issues/16049).
## Getting Started ## Getting Started
@ -34,7 +52,7 @@ First, add `flutter_inappbrowser` as a [dependency in your pubspec.yaml file](ht
## Usage ## Usage
Classes: Classes:
- [InAppWebView](#inappwebview-class): Flutter Widget for adding an **inline native WebView** integrated in the flutter widget tree. [**Available only for Android** ([AndroidView](https://docs.flutter.io/flutter/widgets/AndroidView-class.html)) at this moment. For iOS, it will be available as soon as the Flutter team will release the corresponding dart class.]. - [InAppWebView](#inappwebview-class): Flutter Widget for adding an **inline native WebView** integrated in the flutter widget tree. To use `InAppWebView` class on iOS you need to opt-in for the embedded views preview by adding a boolean property to the app's `Info.plist` file, with the key `io.flutter.embedded_views_preview` and the value `YES`.
- [InAppBrowser](#inappbrowser-class): In-App Browser using native WebView. - [InAppBrowser](#inappbrowser-class): In-App Browser using native WebView.
- [ChromeSafariBrowser](#chromesafaribrowser-class): In-App Browser using [Chrome Custom Tabs](https://developer.android.com/reference/android/support/customtabs/package-summary) on Android / [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS. - [ChromeSafariBrowser](#chromesafaribrowser-class): In-App Browser using [Chrome Custom Tabs](https://developer.android.com/reference/android/support/customtabs/package-summary) on Android / [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS.
- [InAppLocalhostServer](#inapplocalhostserver-class): This class allows you to create a simple server on `http://localhost:[port]/`. The default `port` value is `8080`. - [InAppLocalhostServer](#inapplocalhostserver-class): This class allows you to create a simple server on `http://localhost:[port]/`. The default `port` value is `8080`.
@ -45,11 +63,10 @@ See the online [docs](https://pub.dartlang.org/documentation/flutter_inappbrowse
### `InAppWebView` class ### `InAppWebView` class
Flutter Widget for adding an **inline native WebView** integrated in the flutter widget tree. Flutter Widget for adding an **inline native WebView** integrated in the flutter widget tree.
[AndroidView](https://docs.flutter.io/flutter/widgets/AndroidView-class.html) is not officially stable yet! [AndroidView](https://docs.flutter.io/flutter/widgets/AndroidView-class.html) and [UiKitView](https://docs.flutter.io/flutter/widgets/UiKitView-class.html) is not officially stable yet!
So, if you want use it, you can but you will have some limitation such as the inability to use the keyboard! So, if you want use it, you can but you will have some limitation such as the inability to use the keyboard!
**Available only for Android** ([AndroidView](https://docs.flutter.io/flutter/widgets/AndroidView-class.html)) at this moment. To use `InAppWebView` class on iOS you need to opt-in for the embedded views preview by adding a boolean property to the app's `Info.plist` file, with the key `io.flutter.embedded_views_preview` and the value `YES`.
For iOS, it will be available as soon as the Flutter team will release the corresponding dart class.
Use `InAppWebViewController` to control the WebView instance. Use `InAppWebViewController` to control the WebView instance.
Example: Example:
@ -189,6 +206,10 @@ Screenshots:
![android](https://user-images.githubusercontent.com/5956938/47271038-7aebda80-d574-11e8-98fd-41e6bbc9fe2d.gif) ![android](https://user-images.githubusercontent.com/5956938/47271038-7aebda80-d574-11e8-98fd-41e6bbc9fe2d.gif)
- iOS:
![ios](https://user-images.githubusercontent.com/5956938/54096363-e1e72000-43ab-11e9-85c2-983a830ab7a0.gif)
#### InAppWebView.initialUrl #### InAppWebView.initialUrl
Initial url that will be loaded. Initial url that will be loaded.

View File

@ -8,7 +8,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.1.2' classpath 'com.android.tools.build:gradle:3.3.0'
} }
} }

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -359,14 +359,15 @@ public class InAppWebViewClient extends WebViewClient {
getChannel().invokeMethod("onLoadResource", obj); getChannel().invokeMethod("onLoadResource", obj);
return new WebResourceResponse( // this return is not working (it blocks some resources), so return null
response.header("content-type", "text/plain").split(";")[0].trim(), // return new WebResourceResponse(
response.header("content-encoding"), // response.header("content-type", "text/plain").split(";")[0].trim(),
response.code(), // response.header("content-encoding", "utf-8"),
reasonPhrase, // response.code(),
headersResponse, // reasonPhrase,
dataStream // headersResponse,
); // dataStream
// );
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
Log.d(LOG_TAG, e.getMessage()); Log.d(LOG_TAG, e.getMessage());

View File

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip

View File

@ -446,7 +446,7 @@
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0; SWIFT_VERSION = 4.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
}; };
@ -474,7 +474,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutter_inappbrowserExample; PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutter_inappbrowserExample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0; SWIFT_VERSION = 4.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
}; };

View File

@ -4,7 +4,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_inappbrowser/flutter_inappbrowser.dart'; import 'package:flutter_inappbrowser/flutter_inappbrowser.dart';
class MyInappBrowser extends InAppBrowser { class MyInappBrowser extends InAppBrowser {
@override
@override
Future onBrowserCreated() async { Future onBrowserCreated() async {
print("\n\nBrowser Ready!\n\n"); print("\n\nBrowser Ready!\n\n");
} }
@ -64,7 +65,7 @@ class MyInappBrowser extends InAppBrowser {
} }
class WebviewExampleScreen extends StatefulWidget { class WebviewExampleScreen extends StatefulWidget {
final InAppBrowser browser = new InAppBrowser(); final InAppBrowser browser = new MyInappBrowser();
@override @override
_WebviewExampleScreenState createState() => new _WebviewExampleScreenState(); _WebviewExampleScreenState createState() => new _WebviewExampleScreenState();
} }

View File

@ -20,7 +20,7 @@
<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/.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/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/build" /> <excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/build" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappbrowser/example/ios/Flutter/flutter_assets/packages" /> <excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/App.framework/flutter_assets/packages" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/flutter_assets/packages" /> <excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/flutter_assets/packages" />
</content> </content>
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />

View File

@ -14,73 +14,6 @@ import AVFoundation
typealias OlderClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Any?) -> Void typealias OlderClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Any?) -> Void
typealias NewerClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void typealias NewerClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void
// the message needs to be concatenated with '' in order to have the same behavior like on Android
let consoleLogJS = """
(function() {
var oldLogs = {
'consoleLog': console.log,
'consoleDebug': console.debug,
'consoleError': console.error,
'consoleInfo': console.info,
'consoleWarn': console.warn
};
for (var k in oldLogs) {
(function(oldLog) {
console[oldLog.replace('console', '').toLowerCase()] = function() {
var message = '';
for (var i in arguments) {
if (message == '') {
message += arguments[i];
}
else {
message += ' ' + arguments[i];
}
}
window.webkit.messageHandlers[oldLog].postMessage(message);
}
})(k);
}
})();
"""
let resourceObserverJS = """
(function() {
var observer = new PerformanceObserver(function(list) {
list.getEntries().forEach(function(entry) {
window.webkit.messageHandlers['resourceLoaded'].postMessage(JSON.stringify(entry));
});
});
observer.observe({entryTypes: ['resource', 'mark', 'measure']});
})();
"""
let JAVASCRIPT_BRIDGE_NAME = "flutter_inappbrowser"
let javaScriptBridgeJS = """
window.\(JAVASCRIPT_BRIDGE_NAME) = {};
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler = function(handlerName, ...args) {
window.webkit.messageHandlers['callHandler'].postMessage( {'handlerName': handlerName, 'args': JSON.stringify(args)} );
}
"""
func currentTimeInMilliSeconds() -> Int64 {
let currentDate = Date()
let since1970 = currentDate.timeIntervalSince1970
return Int64(since1970 * 1000)
}
func convertToDictionary(text: String) -> [String: Any]? {
if let data = text.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print(error.localizedDescription)
}
}
return nil
}
//extension WKWebView{ //extension WKWebView{
// //
// var keyboardDisplayRequiresUserAction: Bool? { // var keyboardDisplayRequiresUserAction: Bool? {
@ -137,7 +70,7 @@ class InAppWebView_IBWrapper: InAppWebView {
} }
} }
class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKUIDelegate, WKNavigationDelegate, UITextFieldDelegate, WKScriptMessageHandler { class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKUIDelegate, UITextFieldDelegate {
@IBOutlet var webView: InAppWebView_IBWrapper! @IBOutlet var webView: InAppWebView_IBWrapper!
@IBOutlet var closeButton: UIButton! @IBOutlet var closeButton: UIButton!
@ -156,7 +89,7 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
@IBOutlet var webView_TopFullScreenConstraint: NSLayoutConstraint! @IBOutlet var webView_TopFullScreenConstraint: NSLayoutConstraint!
weak var navigationDelegate: SwiftFlutterPlugin? weak var navigationDelegate: SwiftFlutterPlugin?
var currentURL: URL? var initURL: URL?
var tmpWindow: UIWindow? var tmpWindow: UIWindow?
var browserOptions: InAppBrowserOptions? var browserOptions: InAppBrowserOptions?
var webViewOptions: InAppWebViewOptions? var webViewOptions: InAppWebViewOptions?
@ -189,12 +122,12 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
webView.uiDelegate = self // webView.uiDelegate = self
webView.navigationDelegate = self // webView.navigationDelegate = nil
webView.scrollView.delegate = self // webView.scrollView.delegate = self
urlField.delegate = self urlField.delegate = self
urlField.text = self.currentURL?.absoluteString urlField.text = self.initURL?.absoluteString
closeButton.addTarget(self, action: #selector(self.close), for: .touchUpInside) closeButton.addTarget(self, action: #selector(self.close), for: .touchUpInside)
@ -218,7 +151,7 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
spinner.stopAnimating() spinner.stopAnimating()
if self.initData == nil { if self.initData == nil {
loadUrl(url: self.currentURL!, headers: self.initHeaders) loadUrl(url: self.initURL!, headers: self.initHeaders)
} }
else { else {
loadData(data: initData!, mimeType: initMimeType!, encoding: initEncoding!, baseUrl: initBaseUrl!) loadData(data: initData!, mimeType: initMimeType!, encoding: initEncoding!, baseUrl: initBaseUrl!)
@ -245,13 +178,8 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
func prepareWebView() { func prepareWebView() {
//UIApplication.shared.statusBarStyle = preferredStatusBarStyle //UIApplication.shared.statusBarStyle = preferredStatusBarStyle
self.webView.addObserver(self, self.webView.options = webViewOptions
forKeyPath: #keyPath(WKWebView.estimatedProgress), self.webView.prepare()
options: .new,
context: nil)
self.webView.configuration.userContentController = WKUserContentController()
self.webView.configuration.preferences = WKPreferences()
if (browserOptions?.hideUrlBar)! { if (browserOptions?.hideUrlBar)! {
self.urlField.isHidden = true self.urlField.isHidden = true
@ -290,133 +218,21 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
self.modalPresentationStyle = UIModalPresentationStyle(rawValue: (browserOptions?.presentationStyle)!)! self.modalPresentationStyle = UIModalPresentationStyle(rawValue: (browserOptions?.presentationStyle)!)!
self.modalTransitionStyle = UIModalTransitionStyle(rawValue: (browserOptions?.transitionStyle)!)! self.modalTransitionStyle = UIModalTransitionStyle(rawValue: (browserOptions?.transitionStyle)!)!
// prevent webView from bouncing
if (webViewOptions?.disallowOverScroll)! {
if self.webView.responds(to: #selector(getter: self.webView.scrollView)) {
self.webView.scrollView.bounces = false
}
else {
for subview: UIView in self.webView.subviews {
if subview is UIScrollView {
(subview as! UIScrollView).bounces = false
}
}
}
}
if (webViewOptions?.enableViewportScale)! {
let jscript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);"
let userScript = WKUserScript(source: jscript, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
self.webView.configuration.userContentController.addUserScript(userScript)
}
// Prevents long press on links that cause WKWebView exit
let jscriptWebkitTouchCallout = WKUserScript(source: "document.body.style.webkitTouchCallout='none';", injectionTime: .atDocumentEnd, forMainFrameOnly: true)
self.webView.configuration.userContentController.addUserScript(jscriptWebkitTouchCallout)
let consoleLogJSScript = WKUserScript(source: consoleLogJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
self.webView.configuration.userContentController.addUserScript(consoleLogJSScript)
self.webView.configuration.userContentController.add(self, name: "consoleLog")
self.webView.configuration.userContentController.add(self, name: "consoleDebug")
self.webView.configuration.userContentController.add(self, name: "consoleError")
self.webView.configuration.userContentController.add(self, name: "consoleInfo")
self.webView.configuration.userContentController.add(self, name: "consoleWarn")
let javaScriptBridgeJSScript = WKUserScript(source: javaScriptBridgeJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
self.webView.configuration.userContentController.addUserScript(javaScriptBridgeJSScript)
self.webView.configuration.userContentController.add(self, name: "callHandler")
let resourceObserverJSScript = WKUserScript(source: resourceObserverJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
self.webView.configuration.userContentController.addUserScript(resourceObserverJSScript)
self.webView.configuration.userContentController.add(self, name: "resourceLoaded")
if #available(iOS 10.0, *) {
self.webView.configuration.mediaTypesRequiringUserActionForPlayback = ((webViewOptions?.mediaPlaybackRequiresUserGesture)!) ? .all : []
} else {
// Fallback on earlier versions
self.webView.configuration.mediaPlaybackRequiresUserAction = (webViewOptions?.mediaPlaybackRequiresUserGesture)!
}
self.webView.configuration.allowsInlineMediaPlayback = (webViewOptions?.allowsInlineMediaPlayback)!
//self.webView.keyboardDisplayRequiresUserAction = browserOptions?.keyboardDisplayRequiresUserAction
self.webView.configuration.suppressesIncrementalRendering = (webViewOptions?.suppressesIncrementalRendering)!
self.webView.allowsBackForwardNavigationGestures = (webViewOptions?.allowsBackForwardNavigationGestures)!
if #available(iOS 9.0, *) {
self.webView.allowsLinkPreview = (webViewOptions?.allowsLinkPreview)!
}
if #available(iOS 10.0, *) {
self.webView.configuration.ignoresViewportScaleLimits = (webViewOptions?.ignoresViewportScaleLimits)!
}
self.webView.configuration.allowsInlineMediaPlayback = (webViewOptions?.allowsInlineMediaPlayback)!
if #available(iOS 9.0, *) {
self.webView.configuration.allowsPictureInPictureMediaPlayback = (webViewOptions?.allowsPictureInPictureMediaPlayback)!
}
self.webView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = (webViewOptions?.javaScriptCanOpenWindowsAutomatically)!
self.webView.configuration.preferences.javaScriptEnabled = (webViewOptions?.javaScriptEnabled)!
if ((webViewOptions?.userAgent)! != "") {
if #available(iOS 9.0, *) {
self.webView.customUserAgent = (webViewOptions?.userAgent)!
}
}
if (webViewOptions?.clearCache)! {
clearCache()
}
} }
func loadUrl(url: URL, headers: [String: String]?) { func loadUrl(url: URL, headers: [String: String]?) {
var request = URLRequest(url: url) webView.loadUrl(url: url, headers: headers)
currentURL = url updateUrlTextField(url: (webView.currentURL?.absoluteString)!)
updateUrlTextField(url: (currentURL?.absoluteString)!)
if let mutableRequest = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest {
for (key, value) in headers! {
mutableRequest.setValue(value, forHTTPHeaderField: key)
}
request = mutableRequest as URLRequest
}
webView.load(request)
} }
func loadData(data: String, mimeType: String, encoding: String, baseUrl: String) { func loadData(data: String, mimeType: String, encoding: String, baseUrl: String) {
let url = URL(string: baseUrl)! webView.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
currentURL = url
if #available(iOS 9.0, *) {
webView.load(data.data(using: .utf8)!, mimeType: mimeType, characterEncodingName: encoding, baseURL: url)
} else {
webView.loadHTMLString(data, baseURL: url)
}
} }
func postUrl(url: URL, postData: Data, result: @escaping FlutterResult) { func postUrl(url: URL, postData: Data, result: @escaping FlutterResult) {
var request = URLRequest(url: url) webView.postUrl(url: url, postData: postData, completionHandler: { () -> Void in
request.httpMethod = "POST" result(true)
request.httpBody = postData })
let task = URLSession.shared.dataTask(with: request) { (data : Data?, response : URLResponse?, error : Error?) in
var returnString = ""
if data != nil {
returnString = String(data: data!, encoding: .utf8) ?? ""
}
DispatchQueue.main.async(execute: {() -> Void in
self.webView.loadHTMLString(returnString, baseURL: url)
result(true)
})
}
task.resume()
} }
// Load user requested url // Load user requested url
@ -428,9 +244,8 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
webView.load(request) webView.load(request)
} }
else { else {
updateUrlTextField(url: (currentURL?.absoluteString)!) updateUrlTextField(url: (webView.currentURL?.absoluteString)!)
} }
//var list : WKBackForwardList = self.webView.backForwardList
return false return false
} }
@ -439,30 +254,12 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
webView.frame = frame webView.frame = frame
} }
func clearCache() {
if #available(iOS 9.0, *) {
//let websiteDataTypes = NSSet(array: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])
let date = NSDate(timeIntervalSince1970: 0)
WKWebsiteDataStore.default().removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: date as Date, completionHandler:{ })
} else {
var libraryPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.libraryDirectory, FileManager.SearchPathDomainMask.userDomainMask, false).first!
libraryPath += "/Cookies"
do {
try FileManager.default.removeItem(atPath: libraryPath)
} catch {
print("can't clear cache")
}
URLCache.shared.removeAllCachedResponses()
}
}
@objc func reload () { @objc func reload () {
webView.reload() webView.reload()
} }
@objc func share () { @objc func share () {
let vc = UIActivityViewController(activityItems: [currentURL ?? ""], applicationActivities: []) let vc = UIActivityViewController(activityItems: [webView.currentURL ?? ""], applicationActivities: [])
present(vc, animated: true, completion: nil) present(vc, animated: true, completion: nil)
} }
@ -569,237 +366,12 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
scanner.scanHexInt32(&hexInt) scanner.scanHexInt32(&hexInt)
return hexInt return hexInt
} }
func webView(_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url {
if url.absoluteString != self.currentURL?.absoluteString && (webViewOptions?.useOnLoadResource)! {
WKNavigationMap[url.absoluteString] = [
"startTime": currentTimeInMilliSeconds(),
"request": navigationAction.request
]
}
if navigationAction.navigationType == .linkActivated && (webViewOptions?.useShouldOverrideUrlLoading)! {
if navigationDelegate != nil {
navigationDelegate?.shouldOverrideUrlLoading(uuid: self.uuid, webView: webView, url: url)
}
decisionHandler(.cancel)
return
}
if navigationAction.navigationType == .linkActivated || navigationAction.navigationType == .backForward {
currentURL = url
updateUrlTextField(url: (url.absoluteString))
}
}
decisionHandler(.allow)
}
func webView(_ webView: WKWebView,
decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
if (webViewOptions?.useOnLoadResource)! {
if let url = navigationResponse.response.url {
if WKNavigationMap[url.absoluteString] != nil {
let startResourceTime: Int64 = (WKNavigationMap[url.absoluteString]!["startTime"] as! Int64)
let startTime: Int64 = startResourceTime - startPageTime;
let duration: Int64 = currentTimeInMilliSeconds() - startResourceTime;
self.didReceiveResourceResponse(navigationResponse.response, fromRequest: WKNavigationMap[url.absoluteString]!["request"] as? URLRequest, withData: Data(), startTime: startTime, duration: duration)
}
}
}
decisionHandler(.allow)
}
// func webView(_ webView: WKWebView,
// decidePolicyFor navigationResponse: WKNavigationResponse,
// decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
// let mimeType = navigationResponse.response.mimeType
// if mimeType != nil && !mimeType!.starts(with: "text/") {
// download(url: webView.url)
// decisionHandler(.cancel)
// return
// }
// decisionHandler(.allow)
// }
//
// func download (url: URL?) {
// let filename = url?.lastPathComponent
//
// let destination: DownloadRequest.DownloadFileDestination = { _, _ in
// let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
// let fileURL = documentsURL.appendingPathComponent(filename!)
//
// return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
// }
//
// Alamofire.download((url?.absoluteString)!, to: destination).downloadProgress { progress in
// print("Download Progress: \(progress.fractionCompleted)")
// }.response { response in
// if response.error == nil, let path = response.destinationURL?.path {
// UIAlertView(title: nil, message: "File saved to " + path, delegate: nil, cancelButtonTitle: nil).show()
// }
// else {
// UIAlertView(title: nil, message: "Cannot save " + filename!, delegate: nil, cancelButtonTitle: nil).show()
// }
// }
// }
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
self.startPageTime = currentTimeInMilliSeconds()
// loading url, start spinner, update back/forward
backButton.isEnabled = webView.canGoBack
forwardButton.isEnabled = webView.canGoForward
if (browserOptions?.spinner)! {
spinner.startAnimating()
}
if navigationDelegate != nil {
navigationDelegate?.onLoadStart(uuid: self.uuid, webView: webView)
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.WKNavigationMap = [:]
// update url, stop spinner, update back/forward
currentURL = webView.url
updateUrlTextField(url: (currentURL?.absoluteString)!)
backButton.isEnabled = webView.canGoBack
forwardButton.isEnabled = webView.canGoForward
spinner.stopAnimating()
if navigationDelegate != nil {
navigationDelegate?.onLoadStop(uuid: self.uuid, webView: webView)
}
}
func webView(_ view: WKWebView,
didFailProvisionalNavigation navigation: WKNavigation!,
withError error: Error) {
webView(view, didFail: navigation, withError: error)
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
backButton.isEnabled = webView.canGoBack
forwardButton.isEnabled = webView.canGoForward
spinner.stopAnimating()
if navigationDelegate != nil {
navigationDelegate?.onLoadError(uuid: self.uuid, webView: webView, error: error)
}
}
func didReceiveResourceResponse(_ response: URLResponse, fromRequest request: URLRequest?, withData data: Data, startTime: Int64, duration: Int64) {
if navigationDelegate != nil {
navigationDelegate?.onLoadResource(uuid: self.uuid, webView: webView, response: response, fromRequest: request, withData: data, startTime: startTime, duration: duration)
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if navigationDelegate != nil {
let x = Int(scrollView.contentOffset.x / scrollView.contentScaleFactor)
let y = Int(scrollView.contentOffset.y / scrollView.contentScaleFactor)
navigationDelegate?.onScrollChanged(uuid: self.uuid, webView: webView, x: x, y: y)
}
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name.starts(with: "console") {
var messageLevel = "LOG"
switch (message.name) {
case "consoleLog":
messageLevel = "LOG"
break;
case "consoleDebug":
// on Android, console.debug is TIP
messageLevel = "TIP"
break;
case "consoleError":
messageLevel = "ERROR"
break;
case "consoleInfo":
// on Android, console.info is LOG
messageLevel = "LOG"
break;
case "consoleWarn":
messageLevel = "WARNING"
break;
default:
messageLevel = "LOG"
break;
}
if navigationDelegate != nil {
navigationDelegate?.onConsoleMessage(uuid: self.uuid, sourceURL: "", lineNumber: 1, message: message.body as! String, messageLevel: messageLevel)
}
}
else if message.name == "resourceLoaded" && (webViewOptions?.useOnLoadResource)! {
if let resource = convertToDictionary(text: message.body as! String) {
let rawUrl = resource["name"] as! String
let encodedUrl = rawUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
let url = URL(string: encodedUrl)!
if !UIApplication.shared.canOpenURL(url) {
return
}
let startTime = Int64(resource["startTime"] as! Double)
let duration = Int64(resource["duration"] as! Double)
var urlRequest = URLRequest(url: url)
urlRequest.allHTTPHeaderFields = [:]
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: urlRequest) { (data, response, error) in
if error != nil {
print(error)
return
}
var withData = data
if withData == nil {
withData = Data()
}
self.didReceiveResourceResponse(response!, fromRequest: urlRequest, withData: withData!, startTime: startTime, duration: duration)
}
task.resume()
}
}
else if message.name == "callHandler" {
let body = message.body as! [String: Any]
let handlerName = body["handlerName"] as! String
let args = body["args"] as! String
if navigationDelegate != nil {
self.navigationDelegate?.onCallJsHandler(uuid: self.uuid, webView: webView, handlerName: handlerName, args: args)
}
}
}
func takeScreenshot (completionHandler: @escaping (_ screenshot: Data?) -> Void) {
if #available(iOS 11.0, *) {
self.webView.takeSnapshot(with: nil, completionHandler: {(image, error) -> Void in
var imageData: Data? = nil
if let screenshot = image {
imageData = UIImagePNGRepresentation(screenshot)!
}
completionHandler(imageData)
})
} else {
completionHandler(nil)
}
}
func setOptions(newOptions: InAppBrowserOptions, newOptionsMap: [String: Any]) { func setOptions(newOptions: InAppBrowserOptions, newOptionsMap: [String: Any]) {
let newInAppWebViewOptions = InAppWebViewOptions() let newInAppWebViewOptions = InAppWebViewOptions()
newInAppWebViewOptions.parse(options: newOptionsMap) newInAppWebViewOptions.parse(options: newOptionsMap)
self.webView.setOptions(newOptions: newInAppWebViewOptions, newOptionsMap: newOptionsMap)
if newOptionsMap["hidden"] != nil && browserOptions?.hidden != newOptions.hidden { if newOptionsMap["hidden"] != nil && browserOptions?.hidden != newOptions.hidden {
if newOptions.hidden { if newOptions.hidden {
@ -854,135 +426,18 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
if newOptionsMap["transitionStyle"] != nil && browserOptions?.transitionStyle != newOptions.transitionStyle { if newOptionsMap["transitionStyle"] != nil && browserOptions?.transitionStyle != newOptions.transitionStyle {
self.modalTransitionStyle = UIModalTransitionStyle(rawValue: newOptions.transitionStyle)! self.modalTransitionStyle = UIModalTransitionStyle(rawValue: newOptions.transitionStyle)!
} }
if newOptionsMap["disallowOverScroll"] != nil && webViewOptions?.disallowOverScroll != newInAppWebViewOptions.disallowOverScroll {
if self.webView.responds(to: #selector(getter: self.webView.scrollView)) {
self.webView.scrollView.bounces = !newInAppWebViewOptions.disallowOverScroll
}
else {
for subview: UIView in self.webView.subviews {
if subview is UIScrollView {
(subview as! UIScrollView).bounces = !newInAppWebViewOptions.disallowOverScroll
}
}
}
}
if newOptionsMap["enableViewportScale"] != nil && webViewOptions?.enableViewportScale != newInAppWebViewOptions.enableViewportScale && newInAppWebViewOptions.enableViewportScale {
let jscript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);"
self.webView.evaluateJavaScript(jscript, completionHandler: nil)
}
if newOptionsMap["mediaPlaybackRequiresUserGesture"] != nil && webViewOptions?.mediaPlaybackRequiresUserGesture != newInAppWebViewOptions.mediaPlaybackRequiresUserGesture {
if #available(iOS 10.0, *) {
self.webView.configuration.mediaTypesRequiringUserActionForPlayback = (newInAppWebViewOptions.mediaPlaybackRequiresUserGesture) ? .all : []
} else {
// Fallback on earlier versions
self.webView.configuration.mediaPlaybackRequiresUserAction = newInAppWebViewOptions.mediaPlaybackRequiresUserGesture
}
}
if newOptionsMap["allowsInlineMediaPlayback"] != nil && webViewOptions?.allowsInlineMediaPlayback != newInAppWebViewOptions.allowsInlineMediaPlayback {
self.webView.configuration.allowsInlineMediaPlayback = newInAppWebViewOptions.allowsInlineMediaPlayback
}
// if newOptionsMap["keyboardDisplayRequiresUserAction"] != nil && browserOptions?.keyboardDisplayRequiresUserAction != newOptions.keyboardDisplayRequiresUserAction {
// self.webView.keyboardDisplayRequiresUserAction = newOptions.keyboardDisplayRequiresUserAction
// }
if newOptionsMap["suppressesIncrementalRendering"] != nil && webViewOptions?.suppressesIncrementalRendering != newInAppWebViewOptions.suppressesIncrementalRendering {
self.webView.configuration.suppressesIncrementalRendering = newInAppWebViewOptions.suppressesIncrementalRendering
}
if newOptionsMap["allowsBackForwardNavigationGestures"] != nil && webViewOptions?.allowsBackForwardNavigationGestures != newInAppWebViewOptions.allowsBackForwardNavigationGestures {
self.webView.allowsBackForwardNavigationGestures = newInAppWebViewOptions.allowsBackForwardNavigationGestures
}
if newOptionsMap["allowsLinkPreview"] != nil && webViewOptions?.allowsLinkPreview != newInAppWebViewOptions.allowsLinkPreview {
if #available(iOS 9.0, *) {
self.webView.allowsLinkPreview = newInAppWebViewOptions.allowsLinkPreview
}
}
if newOptionsMap["ignoresViewportScaleLimits"] != nil && webViewOptions?.ignoresViewportScaleLimits != newInAppWebViewOptions.ignoresViewportScaleLimits {
if #available(iOS 10.0, *) {
self.webView.configuration.ignoresViewportScaleLimits = newInAppWebViewOptions.ignoresViewportScaleLimits
}
}
if newOptionsMap["allowsInlineMediaPlayback"] != nil && webViewOptions?.allowsInlineMediaPlayback != newInAppWebViewOptions.allowsInlineMediaPlayback {
self.webView.configuration.allowsInlineMediaPlayback = newInAppWebViewOptions.allowsInlineMediaPlayback
}
if newOptionsMap["allowsPictureInPictureMediaPlayback"] != nil && webViewOptions?.allowsPictureInPictureMediaPlayback != newInAppWebViewOptions.allowsPictureInPictureMediaPlayback {
if #available(iOS 9.0, *) {
self.webView.configuration.allowsPictureInPictureMediaPlayback = newInAppWebViewOptions.allowsPictureInPictureMediaPlayback
}
}
if newOptionsMap["javaScriptCanOpenWindowsAutomatically"] != nil && webViewOptions?.javaScriptCanOpenWindowsAutomatically != newInAppWebViewOptions.javaScriptCanOpenWindowsAutomatically {
self.webView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = newInAppWebViewOptions.javaScriptCanOpenWindowsAutomatically
}
if newOptionsMap["javaScriptEnabled"] != nil && webViewOptions?.javaScriptEnabled != newInAppWebViewOptions.javaScriptEnabled {
self.webView.configuration.preferences.javaScriptEnabled = newInAppWebViewOptions.javaScriptEnabled
}
if newOptionsMap["userAgent"] != nil && webViewOptions?.userAgent != newInAppWebViewOptions.userAgent && (newInAppWebViewOptions.userAgent != "") {
if #available(iOS 9.0, *) {
self.webView.customUserAgent = newInAppWebViewOptions.userAgent
}
}
if newOptionsMap["clearCache"] != nil && newInAppWebViewOptions.clearCache {
clearCache()
}
self.browserOptions = newOptions self.browserOptions = newOptions
self.webViewOptions = newInAppWebViewOptions self.webViewOptions = newInAppWebViewOptions
} }
func getOptions() -> [String: Any]? { func getOptions() -> [String: Any]? {
if (self.browserOptions == nil || self.webViewOptions == nil) { if (self.browserOptions == nil || self.webView.getOptions() == nil) {
return nil return nil
} }
var optionsMap = self.browserOptions!.getHashMap() var optionsMap = self.browserOptions!.getHashMap()
optionsMap.merge(self.webViewOptions!.getHashMap(), uniquingKeysWith: { (current, _) in current }) optionsMap.merge(self.webView.getOptions()!, uniquingKeysWith: { (current, _) in current })
return optionsMap return optionsMap
} }
override func observeValue(forKeyPath keyPath: String?, of object: Any?,
change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "estimatedProgress" {
let progress = Int(webView.estimatedProgress * 100)
self.navigationDelegate?.onProgressChanged(uuid: self.uuid, webView: self.webView, progress: progress)
}
}
func getCopyBackForwardList() -> [String: Any] {
let currentList = self.webView.backForwardList
let currentIndex = currentList.backList.count
var completeList = currentList.backList
if currentList.currentItem != nil {
completeList.append(currentList.currentItem!)
}
completeList.append(contentsOf: currentList.forwardList)
var history: [[String: String]] = []
for historyItem in completeList {
var historyItemMap: [String: String] = [:]
historyItemMap["originalUrl"] = historyItem.initialURL.absoluteString
historyItemMap["title"] = historyItem.title
historyItemMap["url"] = historyItem.url.absoluteString
history.append(historyItemMap)
}
var result: [String: Any] = [:]
result["history"] = history
result["currentIndex"] = currentIndex
return result;
}
} }

View File

@ -8,6 +8,73 @@
import Foundation import Foundation
import WebKit import WebKit
func currentTimeInMilliSeconds() -> Int64 {
let currentDate = Date()
let since1970 = currentDate.timeIntervalSince1970
return Int64(since1970 * 1000)
}
func convertToDictionary(text: String) -> [String: Any]? {
if let data = text.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print(error.localizedDescription)
}
}
return nil
}
// the message needs to be concatenated with '' in order to have the same behavior like on Android
let consoleLogJS = """
(function() {
var oldLogs = {
'consoleLog': console.log,
'consoleDebug': console.debug,
'consoleError': console.error,
'consoleInfo': console.info,
'consoleWarn': console.warn
};
for (var k in oldLogs) {
(function(oldLog) {
console[oldLog.replace('console', '').toLowerCase()] = function() {
var message = '';
for (var i in arguments) {
if (message == '') {
message += arguments[i];
}
else {
message += ' ' + arguments[i];
}
}
window.webkit.messageHandlers[oldLog].postMessage(message);
}
})(k);
}
})();
"""
let resourceObserverJS = """
(function() {
var observer = new PerformanceObserver(function(list) {
list.getEntries().forEach(function(entry) {
window.webkit.messageHandlers['resourceLoaded'].postMessage(JSON.stringify(entry));
});
});
observer.observe({entryTypes: ['resource', 'mark', 'measure']});
})();
"""
let JAVASCRIPT_BRIDGE_NAME = "flutter_inappbrowser"
let javaScriptBridgeJS = """
window.\(JAVASCRIPT_BRIDGE_NAME) = {};
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler = function(handlerName, ...args) {
window.webkit.messageHandlers['callHandler'].postMessage( {'handlerName': handlerName, 'args': JSON.stringify(args)} );
}
"""
public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler { public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler {
var IABController: InAppBrowserWebViewController? var IABController: InAppBrowserWebViewController?
@ -87,7 +154,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
configuration.mediaPlaybackRequiresUserAction = (options?.mediaPlaybackRequiresUserGesture)! configuration.mediaPlaybackRequiresUserAction = (options?.mediaPlaybackRequiresUserGesture)!
} }
configuration.allowsInlineMediaPlayback = (options?.allowsInlineMediaPlayback)! configuration.allowsInlineMediaPlayback = (options?.allowsInlineMediaPlayback)!
//keyboardDisplayRequiresUserAction = browserOptions?.keyboardDisplayRequiresUserAction //keyboardDisplayRequiresUserAction = browserOptions?.keyboardDisplayRequiresUserAction
@ -436,6 +502,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
if navigationAction.navigationType == .linkActivated || navigationAction.navigationType == .backForward { if navigationAction.navigationType == .linkActivated || navigationAction.navigationType == .backForward {
currentURL = url currentURL = url
if IABController != nil {
IABController!.updateUrlTextField(url: (currentURL?.absoluteString)!)
}
} }
} }
@ -460,14 +529,66 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
decisionHandler(.allow) decisionHandler(.allow)
} }
// func webView(_ webView: WKWebView,
// decidePolicyFor navigationResponse: WKNavigationResponse,
// decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
// let mimeType = navigationResponse.response.mimeType
// if mimeType != nil && !mimeType!.starts(with: "text/") {
// download(url: webView.url)
// decisionHandler(.cancel)
// return
// }
// decisionHandler(.allow)
// }
//
// func download (url: URL?) {
// let filename = url?.lastPathComponent
//
// let destination: DownloadRequest.DownloadFileDestination = { _, _ in
// let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
// let fileURL = documentsURL.appendingPathComponent(filename!)
//
// return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
// }
//
// Alamofire.download((url?.absoluteString)!, to: destination).downloadProgress { progress in
// print("Download Progress: \(progress.fractionCompleted)")
// }.response { response in
// if response.error == nil, let path = response.destinationURL?.path {
// UIAlertView(title: nil, message: "File saved to " + path, delegate: nil, cancelButtonTitle: nil).show()
// }
// else {
// UIAlertView(title: nil, message: "Cannot save " + filename!, delegate: nil, cancelButtonTitle: nil).show()
// }
// }
// }
public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
self.startPageTime = currentTimeInMilliSeconds() self.startPageTime = currentTimeInMilliSeconds()
onLoadStart(url: (currentURL?.absoluteString)!) onLoadStart(url: (currentURL?.absoluteString)!)
if IABController != nil {
// loading url, start spinner, update back/forward
IABController!.backButton.isEnabled = canGoBack
IABController!.forwardButton.isEnabled = canGoForward
if (IABController!.browserOptions?.spinner)! {
IABController!.spinner.startAnimating()
}
}
} }
public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.WKNavigationMap = [:] self.WKNavigationMap = [:]
onLoadStop(url: (url?.absoluteString)!) currentURL = url
onLoadStop(url: (currentURL?.absoluteString)!)
if IABController != nil {
IABController!.updateUrlTextField(url: (currentURL?.absoluteString)!)
IABController!.backButton.isEnabled = canGoBack
IABController!.forwardButton.isEnabled = canGoForward
IABController!.spinner.stopAnimating()
}
} }
public func webView(_ view: WKWebView, public func webView(_ view: WKWebView,
@ -478,6 +599,12 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
onLoadError(url: (currentURL?.absoluteString)!, error: error) onLoadError(url: (currentURL?.absoluteString)!, error: error)
if IABController != nil {
IABController!.backButton.isEnabled = canGoBack
IABController!.forwardButton.isEnabled = canGoForward
IABController!.spinner.stopAnimating()
}
} }
public func scrollViewDidScroll(_ scrollView: UIScrollView) { public func scrollViewDidScroll(_ scrollView: UIScrollView) {
@ -609,7 +736,10 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
} }
else if message.name == "resourceLoaded" && (options?.useOnLoadResource)! { else if message.name == "resourceLoaded" && (options?.useOnLoadResource)! {
if let resource = convertToDictionary(text: message.body as! String) { if let resource = convertToDictionary(text: message.body as! String) {
let url = URL(string: resource["name"] as! String)! // escape special chars
let resourceName = (resource["name"] as! String).addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)
let url = URL(string: resourceName!)!
if !UIApplication.shared.canOpenURL(url) { if !UIApplication.shared.canOpenURL(url) {
return return
} }

View File

@ -211,7 +211,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
break break
case "takeScreenshot": case "takeScreenshot":
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
webViewController!.takeScreenshot(completionHandler: { (screenshot) -> Void in webViewController!.webView.takeScreenshot(completionHandler: { (screenshot) -> Void in
result(screenshot) result(screenshot)
}) })
} }
@ -420,7 +420,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
webViewController.webViewOptions = webViewOptions webViewController.webViewOptions = webViewOptions
webViewController.isHidden = browserOptions.hidden webViewController.isHidden = browserOptions.hidden
webViewController.tmpWindow = tmpWindow webViewController.tmpWindow = tmpWindow
webViewController.currentURL = url webViewController.initURL = url
webViewController.initHeaders = headers webViewController.initHeaders = headers
webViewController.navigationDelegate = self webViewController.navigationDelegate = self
@ -708,21 +708,21 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
func onLoadStart(uuid: String, webView: WKWebView) { func onLoadStart(uuid: String, webView: WKWebView) {
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
let url: String = webViewController!.currentURL!.absoluteString let url: String = webViewController!.webView.currentURL!.absoluteString
SwiftFlutterPlugin.channel!.invokeMethod("onLoadStart", arguments: ["uuid": uuid, "url": url]) SwiftFlutterPlugin.channel!.invokeMethod("onLoadStart", arguments: ["uuid": uuid, "url": url])
} }
} }
func onLoadStop(uuid: String, webView: WKWebView) { func onLoadStop(uuid: String, webView: WKWebView) {
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
let url: String = webViewController!.currentURL!.absoluteString let url: String = webViewController!.webView.currentURL!.absoluteString
SwiftFlutterPlugin.channel!.invokeMethod("onLoadStop", arguments: ["uuid": uuid, "url": url]) SwiftFlutterPlugin.channel!.invokeMethod("onLoadStop", arguments: ["uuid": uuid, "url": url])
} }
} }
func onLoadError(uuid: String, webView: WKWebView, error: Error) { func onLoadError(uuid: String, webView: WKWebView, error: Error) {
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
let url: String = webViewController!.currentURL!.absoluteString let url: String = webViewController!.webView.currentURL!.absoluteString
let arguments = ["uuid": uuid, "url": url, "code": error._code, "message": error.localizedDescription] as [String : Any] let arguments = ["uuid": uuid, "url": url, "code": error._code, "message": error.localizedDescription] as [String : Any]
SwiftFlutterPlugin.channel!.invokeMethod("onLoadError", arguments: arguments) SwiftFlutterPlugin.channel!.invokeMethod("onLoadError", arguments: arguments)
} }
@ -846,7 +846,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
func getCopyBackForwardList(uuid: String) -> [String: Any]? { func getCopyBackForwardList(uuid: String) -> [String: Any]? {
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
return webViewController!.getCopyBackForwardList() return webViewController!.webView.getCopyBackForwardList()
} }
return nil return nil
} }

View File

@ -1,6 +1,6 @@
name: flutter_inappbrowser name: flutter_inappbrowser
description: A Flutter plugin that allows you to add an inline webview or open an in-app browser window (inspired by the popular cordova-plugin-inappbrowser). description: A Flutter plugin that allows you to add an inline webview or open an in-app browser window (inspired by the popular cordova-plugin-inappbrowser).
version: 0.5.51 version: 0.6.0
author: Lorenzo Pichilli <pichillilorenzo@gmail.com> author: Lorenzo Pichilli <pichillilorenzo@gmail.com>
homepage: https://github.com/pichillilorenzo/flutter_inappbrowser homepage: https://github.com/pichillilorenzo/flutter_inappbrowser
@ -11,7 +11,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
uuid: ^1.0.3 uuid: ^2.0.0
mime: ^0.9.6+2 mime: ^0.9.6+2
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the