diff --git a/.idea/workspace.xml b/.idea/workspace.xml index e6069a4f0f617cc4dc5eba829512241250cc503b..01d9d6d05cb5d2dcbe8fef9adbfc01cc93a810d0 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -16,8 +16,19 @@ <component name="ChangeListManager"> <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$/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/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebView.java" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserActivity.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserActivity.java" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/example/lib/main.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/main.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$/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> <ignored path="$PROJECT_DIR$/.dart_tool/" /> <ignored path="$PROJECT_DIR$/.idea/" /> @@ -37,8 +48,8 @@ <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="104"> - <caret line="932" column="46" selection-start-line="932" selection-start-column="20" selection-end-line="932" selection-end-column="46" /> + <state relative-caret-position="176"> + <caret line="256" column="65" lean-forward="true" selection-start-line="256" selection-start-column="5" selection-end-line="256" selection-end-column="65" /> <folding> <element signature="e#814#831#0" expanded="true" /> </folding> @@ -46,28 +57,23 @@ </provider> </entry> </file> - <file leaf-file-name="README.md" pinned="false" current-in-tab="true"> - <entry file="file://$PROJECT_DIR$/README.md"> + <file leaf-file-name="main.dart" pinned="false" current-in-tab="true"> + <entry file="file://$PROJECT_DIR$/example/lib/main.dart"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="510"> - <caret line="427" column="54" selection-start-line="427" selection-start-column="54" selection-end-line="427" selection-end-column="54" /> + <state relative-caret-position="513"> + <caret line="144" column="3" lean-forward="true" selection-start-line="144" selection-start-column="3" selection-end-line="144" selection-end-column="3" /> <folding> <element signature="e#0#20#0" expanded="true" /> - <element signature="e#0#39#0" expanded="true" /> - <element signature="e#0#39#0" expanded="true" /> </folding> </state> </provider> </entry> </file> - <file leaf-file-name="main.dart" pinned="false" current-in-tab="false"> - <entry file="file://$PROJECT_DIR$/example/lib/main.dart"> + <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="120"> - <caret line="8" column="25" lean-forward="true" selection-start-line="8" selection-start-column="25" selection-end-line="8" selection-end-column="25" /> - <folding> - <element signature="e#0#20#0" expanded="true" /> - </folding> + <state relative-caret-position="2955"> + <caret line="197" column="29" selection-start-line="197" selection-start-column="18" selection-end-line="197" selection-end-column="29" /> </state> </provider> </entry> @@ -75,8 +81,8 @@ <file leaf-file-name="CHANGELOG.md" pinned="false" current-in-tab="false"> <entry file="file://$PROJECT_DIR$/CHANGELOG.md"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="45"> - <caret line="3" column="130" selection-start-line="3" selection-start-column="2" selection-end-line="3" selection-end-column="130" /> + <state relative-caret-position="135"> + <caret line="9" column="20" selection-start-line="9" selection-start-column="9" selection-end-line="9" selection-end-column="20" /> </state> </provider> </entry> @@ -92,22 +98,6 @@ </component> <component name="FindInProjectRecents"> <findStrings> - <find>getOp</find> - <find>onLoadError</find> - <find>StatefulWidget</find> - <find>onLoadResource</find> - <find>useShouldOverrideUrlLoading</find> - <find>):</find> - <find>InAppLocalhostServer</find> - <find>local</find> - <find>openWithSystemBrowser</find> - <find>__userAgent__</find> - <find>a</find> - <find>InApp</find> - <find>A [InApp</find> - <find>A `InApp</find> - <find>assets</find> - <find>Ui</find> <find>postUrl</find> <find>assert(</find> <find>sNotEmpty()</find> @@ -122,6 +112,22 @@ <find>throw</find> <find>InAppWeb</find> <find>Boolean</find> + <find>[WebHistory.list]</find> + <find>open</find> + <find>Cannot laod</find> + <find>_throwIsNotOpened</find> + <find>takeS</find> + <find>Completer</find> + <find>args.putIfAbsent('isLocalFile', () => true);</find> + <find>args.putIfAbsent('isLocalFile', () =></find> + <find>Opens the</find> + <find>_isOpened</find> + <find>initialFile</find> + <find>onBrowserCreated</find> + <find>getUrl</find> + <find>onScrollChanged</find> + <find>openData</find> + <find>initialData</find> </findStrings> <replaceStrings> <replace>activity.getPreferences(0)</replace> @@ -165,9 +171,9 @@ <option value="$PROJECT_DIR$/example/pubspec.yaml" /> <option value="$PROJECT_DIR$/pubspec.yaml" /> <option value="$PROJECT_DIR$/CHANGELOG.md" /> - <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/lib/main.dart" /> </list> </option> </component> @@ -183,18 +189,8 @@ <foldersAlwaysOnTop value="true" /> </navigator> <panes> + <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> <pane id="ProjectPane"> <subPane> <expand> @@ -202,6 +198,30 @@ <item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" /> <item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" /> </path> + <path> + <item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" /> + <item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" /> + <item name="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="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" /> @@ -212,7 +232,17 @@ </subPane> <option name="show-excluded-files" value="false" /> </pane> - <pane id="PackagesPane" /> + <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"> @@ -374,16 +404,15 @@ <layout> <window_info anchor="bottom" id="Android Profiler" order="7" show_stripe_button="false" /> <window_info anchor="bottom" id="TODO" order="6" /> - <window_info active="true" anchor="bottom" id="Messages" order="12" visible="true" weight="0.23594266" /> <window_info anchor="right" id="Palette	" order="9" /> <window_info id="Image Layers" order="7" /> <window_info id="Build Variants" order="3" side_tool="true" /> <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="Dart Analysis" order="14" weight="0.3276414" /> - <window_info anchor="bottom" id="Run" order="2" sideWeight="0.49478307" weight="0.34068358" /> + <window_info anchor="bottom" id="Dart Analysis" order="14" weight="0.32745314" /> + <window_info active="true" anchor="bottom" id="Run" order="2" sideWeight="0.49478307" visible="true" weight="0.29437706" /> <window_info anchor="bottom" id="Version Control" order="9" /> - <window_info anchor="bottom" id="Terminal" order="10" sideWeight="0.49533224" weight="0.1786108" /> + <window_info anchor="bottom" id="Terminal" order="10" sideWeight="0.49533224" weight="0.24696803" /> <window_info anchor="right" id="Flutter Outline" order="6" weight="0.32922077" /> <window_info anchor="bottom" id="Logcat" order="11" /> <window_info id="Captures" order="4" weight="0.32936507" /> @@ -396,6 +425,7 @@ <window_info anchor="bottom" id="Debug" order="3" weight="0.34288865" /> <window_info id="Favorites" order="5" side_tool="true" /> <window_info anchor="right" id="Flutter Inspector" order="3" weight="0.32938388" /> + <window_info anchor="bottom" id="Messages" order="12" weight="0.23594266" /> <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="8" visible="true" weight="0.3295129" /> @@ -419,11 +449,6 @@ </breakpoint-manager> </component> <component name="editorHistoryManager"> - <entry file="file://$PROJECT_DIR$/example/android/gradle.properties"> - <provider selected="true" editor-type-id="text-editor"> - <state /> - </provider> - </entry> <entry file="file://$PROJECT_DIR$/ios/Classes/InAppBrowser.h" /> <entry file="file://$PROJECT_DIR$/ios/Classes/InAppBrowser.m" /> <entry file="file://$PROJECT_DIR$/LICENSE"> @@ -649,48 +674,50 @@ </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/pubspec.yaml"> + <entry file="file://$PROJECT_DIR$/example/ios/Runner/Info.plist"> <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 relative-caret-position="390"> + <caret line="26" column="44" selection-start-line="26" selection-start-column="44" selection-end-line="26" selection-end-column="44" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/CHANGELOG.md"> + <entry file="file://$PROJECT_DIR$/pubspec.yaml"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="45"> - <caret line="3" column="130" selection-start-line="3" selection-start-column="2" selection-end-line="3" selection-end-column="130" /> + <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> </provider> </entry> - <entry file="file://$PROJECT_DIR$/example/lib/main.dart"> + <entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="120"> - <caret line="8" column="25" lean-forward="true" selection-start-line="8" selection-start-column="25" selection-end-line="8" selection-end-column="25" /> + <state relative-caret-position="176"> + <caret line="256" column="65" lean-forward="true" selection-start-line="256" selection-start-column="5" selection-end-line="256" selection-end-column="65" /> <folding> - <element signature="e#0#20#0" expanded="true" /> + <element signature="e#814#831#0" expanded="true" /> </folding> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart"> + <entry file="file://$PROJECT_DIR$/README.md"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="104"> - <caret line="932" column="46" selection-start-line="932" selection-start-column="20" selection-end-line="932" selection-end-column="46" /> - <folding> - <element signature="e#814#831#0" expanded="true" /> - </folding> + <state relative-caret-position="2955"> + <caret line="197" column="29" selection-start-line="197" selection-start-column="18" selection-end-line="197" selection-end-column="29" /> </state> </provider> </entry> - <entry file="file://$PROJECT_DIR$/README.md"> + <entry file="file://$PROJECT_DIR$/CHANGELOG.md"> + <provider selected="true" editor-type-id="text-editor"> + <state relative-caret-position="135"> + <caret line="9" column="20" selection-start-line="9" selection-start-column="9" selection-end-line="9" selection-end-column="20" /> + </state> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/example/lib/main.dart"> <provider selected="true" editor-type-id="text-editor"> - <state relative-caret-position="510"> - <caret line="427" column="54" selection-start-line="427" selection-start-column="54" selection-end-line="427" selection-end-column="54" /> + <state relative-caret-position="513"> + <caret line="144" column="3" lean-forward="true" selection-start-line="144" selection-start-column="3" selection-end-line="144" selection-end-column="3" /> <folding> <element signature="e#0#20#0" expanded="true" /> - <element signature="e#0#39#0" expanded="true" /> - <element signature="e#0#39#0" expanded="true" /> </folding> </state> </provider> diff --git a/CHANGELOG.md b/CHANGELOG.md index 18e333d4b7564f33df54afce9c26cdff40794628..db02cffcaf9c40bcd05bd4a8ad1b08233a9ca7a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,18 @@ +## 0.5.5 + +- added `getUrl` method for the `InAppWebViewController` class +- added `getTitle` method for the `InAppWebViewController` class +- added `getProgress` method for the `InAppWebViewController` class +- added `getFavicon` method for the `InAppWebViewController` class +- added `onScrollChanged` event for the `InAppWebViewController` and `InAppBrowser` class +- added `onBrowserCreated` event for the `InAppBrowser` class +- added `openData` method for the `InAppBrowser` class +- added `initialData` property for the `InAppWebView` widget + ## 0.5.4 - added `WebHistory` and `WebHistoryItem` class -- added `getCopyBackForwardList`, `goBackOrForward`, `canGoBackOrForward` and `goTo` methods for `InAppWebView` and `InAppBrowser` +- added `getCopyBackForwardList`, `goBackOrForward`, `canGoBackOrForward` and `goTo` methods for the `InAppWebViewController` class ## 0.5.3 @@ -10,8 +21,8 @@ ## 0.5.2 - fixed some missing `result.success()` on Android and iOS -- added `postUrl()` method for `InAppWebView` and `InAppBrowser` -- added `loadData()` method for `InAppWebView` and `InAppBrowser` +- added `postUrl()` method for the `InAppWebViewController` class +- added `loadData()` method for the `InAppWebViewController` class ## 0.5.1 diff --git a/README.md b/README.md index dbafe6864e543fa2eb41000e8605eb6b68898cf9..c019f2e9b1bf1629221eb9d3704b765d766b0e20 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,8 @@ Classes: - [InAppLocalhostServer](#inapplocalhostserver-class): This class allows you to create a simple server on `http://localhost:[port]/`. The default `port` value is `8080`. - [CookieManager](#cookiemanager-class): Manages the cookies used by WebView instances. **NOTE for iOS**: available from iOS 11.0+. +See the online [docs](https://pub.dartlang.org/documentation/flutter_inappbrowser/latest/) to get the full documentation. + ### `InAppWebView` class Flutter Widget for adding an **inline native WebView** integrated in the flutter widget tree. @@ -193,6 +195,9 @@ Initial url that will be loaded. #### InAppWebView.initialFile Initial asset file that will be loaded. See `InAppWebView.loadFile()` for explanation. +#### InAppWebView.initialData +Initial `InAppWebViewInitialData` that will be loaded. + #### InAppWebView.initialHeaders Initial headers that will be used. @@ -302,6 +307,49 @@ InAppWebView( } ``` +Event `onScrollChanged` fires when the `InAppWebView` scrolls. +`x` represents the current horizontal scroll origin in pixels. +`y` represents the current vertical scroll origin in pixels. +```dart +InAppWebView( + initialUrl: "https://flutter.io/", + onScrollChanged: (InAppWebViewController controller, int x, int y) {} +} +``` + +#### Future\<String\> InAppWebViewController.getUrl + +Gets the URL for the current page. +This is not always the same as the URL passed to `InAppWebView.onLoadStarted` because although the load for that URL has begun, the current page may not have changed. + +```dart +inAppWebViewController.getUrl(); +``` + +#### Future\<String\> InAppWebViewController.getTitle + +Gets the title for the current page. + +```dart +inAppWebViewController.getTitle(); +``` + +#### Future\<int\> InAppWebViewController.getProgress + +Gets the progress for the current page. The progress value is between 0 and 100. + +```dart +inAppWebViewController.getProgress(); +``` + +#### Future\<List\<int\>\> InAppWebViewController.getFavicon + +Gets the favicon for the current page. + +```dart +inAppWebViewController.getFavicon(); +``` + #### Future\<void\> InAppWebViewController.loadUrl Loads the given `url` with optional `headers` specified as a map from name to value. @@ -744,7 +792,7 @@ inAppBrowser.open({String url = "about:blank", Map<String, String> headers = con #### Future\<void\> InAppBrowser.openFile -Opens the giver `assetFilePath` file in a new `InAppBrowser` instance. The other arguments are the same of `InAppBrowser.open()`. +Opens the given `assetFilePath` file in a new `InAppBrowser` instance. The other arguments are the same of `InAppBrowser.open()`. 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! @@ -778,6 +826,16 @@ inAppBrowser.openFile("assets/index.html"); inAppBrowser.openFile(String assetFilePath, {Map<String, String> headers = const {}, Map<String, dynamic> options = const {}}); ``` +#### static Future\<void\> InAppBrowser.openData + +Opens a new `InAppBrowser` instance with `data` as a content, using `baseUrl` as the base URL for it. +The `mimeType` parameter specifies the format of the data. +The `encoding` parameter specifies the encoding of the data. + +```dart +InAppBrowser.openData(String data, {String mimeType = "text/html", String encoding = "utf8", String baseUrl = "about:blank", Map<String, dynamic> options = const {}}); +``` + #### static Future\<void\> InAppBrowser.openWithSystemBrowser This is a static method that opens an `url` in the system browser. You wont be able to use the `InAppBrowser` methods here! @@ -841,6 +899,14 @@ inAppBrowser.isOpened(); #### Events +Event `onBrowserCreated` fires when the `InAppBrowser` is created. +```dart + @override + void onBrowserCreated() { + + } +``` + Event `onLoadStart` fires when the `InAppBrowser` starts to load an `url`. ```dart @override @@ -911,6 +977,17 @@ Event `onLoadResource` fires when the `InAppBrowser` webview loads a resource. } ``` +Event `onScrollChanged` fires when the `InAppBrowser` webview scrolls. +`x` represents the current horizontal scroll origin in pixels. +`y` represents the current vertical scroll origin in pixels. +```dart + @override + void onScrollChanged(int x, int y) { + + } + +``` + ### `ChromeSafariBrowser` class [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. diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebView.java index c82b1c23458a3fd1c38f4379410ebaf1a7d311fd..287449be571fb6334fa45ca30748817a5d505b21 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebView.java @@ -40,12 +40,19 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { String initialUrl = (String) params.get("initialUrl"); String initialFile = (String) params.get("initialFile"); + Map<String, String> initialData = (Map<String, String>) params.get("initialData"); Map<String, String> initialHeaders = (Map<String, String>) params.get("initialHeaders"); HashMap<String, Object> initialOptions = (HashMap<String, Object>) params.get("initialOptions"); InAppWebViewOptions options = new InAppWebViewOptions(); options.parse(initialOptions); + webView = new InAppWebView(context, this, id, options); + webView.prepare(); + + channel = new MethodChannel(registrar.messenger(), "com.pichillilorenzo/flutter_inappwebview_" + id); + channel.setMethodCallHandler(this); + if (initialFile != null) { try { initialUrl = Util.getUrlAsset(registrar, initialFile); @@ -56,13 +63,15 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { } } - webView = new InAppWebView(context, this, id, options); - webView.prepare(); - - channel = new MethodChannel(registrar.messenger(), "com.pichillilorenzo/flutter_inappwebview_" + id); - channel.setMethodCallHandler(this); - - webView.loadUrl(initialUrl, initialHeaders); + if (initialData != null) { + String data = initialData.get("data"); + String mimeType = initialData.get("mimeType"); + String encoding = initialData.get("encoding"); + String baseUrl = initialData.get("baseUrl"); + webView.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, null); + } + else + webView.loadUrl(initialUrl, initialHeaders); } @Override @@ -76,6 +85,15 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { String jsWrapper; String urlFile; switch (call.method) { + case "getUrl": + result.success((webView != null) ? webView.getUrl() : null); + break; + case "getTitle": + result.success((webView != null) ? webView.getTitle() : null); + break; + case "getProgress": + result.success((webView != null) ? webView.getProgress() : null); + break; case "loadUrl": if (webView != null) webView.loadUrl(call.argument("url").toString(), (Map<String, String>) call.argument("headers"), result); diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserActivity.java index 7feeb450569b63f9d092a429e72d4a5a59786a8b..817f52fadcfa9335c606b715ab522b2f7dc07963 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserActivity.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserActivity.java @@ -52,7 +52,7 @@ public class InAppBrowserActivity extends AppCompatActivity { Bundle b = getIntent().getExtras(); uuid = b.getString("uuid"); - String url = b.getString("url"); + HashMap<String, Object> optionsMap = (HashMap<String, Object>) b.getSerializable("options"); options = new InAppBrowserOptions(); @@ -62,16 +62,29 @@ public class InAppBrowserActivity extends AppCompatActivity { webViewOptions.parse(optionsMap); webView.options = webViewOptions; - headers = (HashMap<String, String>) b.getSerializable("headers"); - InAppBrowserFlutterPlugin.webViewActivities.put(uuid, this); actionBar = getSupportActionBar(); prepareView(); - 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"); + Boolean isData = b.getBoolean("isData"); + if (!isData) { + headers = (HashMap<String, String>) b.getSerializable("headers"); + String url = b.getString("url"); + webView.loadUrl(url, headers); + } + else { + String data = b.getString("data"); + String mimeType = b.getString("mimeType"); + String encoding = b.getString("encoding"); + String baseUrl = b.getString("baseUrl"); + webView.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, null); + } + + Map<String, Object> obj = new HashMap<>(); + obj.put("uuid", uuid); + InAppBrowserFlutterPlugin.channel.invokeMethod("onBrowserCreated", obj); } @@ -164,6 +177,24 @@ public class InAppBrowserActivity extends AppCompatActivity { return true; } + public String getUrl() { + if (webView != null) + return webView.getUrl(); + return null; + } + + public String getWebViewTitle() { + if (webView != null) + return webView.getTitle(); + return null; + } + + public Integer getProgress() { + if (webView != null) + return webView.getProgress(); + return null; + } + public void loadUrl(String url, MethodChannel.Result result) { if (webView != null) { webView.loadUrl(url, result); diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java index d224f20774a8716f1d3a6ace29d6ea5194122d9e..edabeadd6d25d9a8b273bc4927bbacbd3c9845f4 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java @@ -97,71 +97,97 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler { switch (call.method) { case "open": - final String url_final = call.argument("url").toString(); + boolean isData = (boolean) call.argument("isData"); + if (!isData) { + final String url_final = call.argument("url").toString(); - final boolean useChromeSafariBrowser = (boolean) call.argument("useChromeSafariBrowser"); + final boolean useChromeSafariBrowser = (boolean) call.argument("useChromeSafariBrowser"); - final Map<String, String> headers = (Map<String, String>) call.argument("headers"); + final Map<String, String> headers = (Map<String, String>) call.argument("headers"); - Log.d(LOG_TAG, "use Chrome Custom Tabs = " + useChromeSafariBrowser); + Log.d(LOG_TAG, "use Chrome Custom Tabs = " + useChromeSafariBrowser); - this.activity.runOnUiThread(new Runnable() { - @Override - public void run() { + this.activity.runOnUiThread(new Runnable() { + @Override + public void run() { - if (useChromeSafariBrowser) { + if (useChromeSafariBrowser) { - final String uuidFallback = (String) call.argument("uuidFallback"); + final String uuidFallback = (String) call.argument("uuidFallback"); - final HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options"); + final HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options"); - final HashMap<String, Object> optionsFallback = (HashMap<String, Object>) call.argument("optionsFallback"); + final HashMap<String, Object> optionsFallback = (HashMap<String, Object>) call.argument("optionsFallback"); - open(uuid, uuidFallback, url_final, options, headers, true, optionsFallback, result); - } else { + open(uuid, uuidFallback, url_final, options, headers, true, optionsFallback, result); + } else { - String url = url_final; + String url = url_final; - final HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options"); + final HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options"); - final boolean isLocalFile = (boolean) call.argument("isLocalFile"); - final boolean openWithSystemBrowser = (boolean) call.argument("openWithSystemBrowser"); + final boolean isLocalFile = (boolean) call.argument("isLocalFile"); + final boolean openWithSystemBrowser = (boolean) call.argument("openWithSystemBrowser"); - if (isLocalFile) { - // check if the asset file exists - try { - url = Util.getUrlAsset(registrar, url); - } catch (IOException e) { - e.printStackTrace(); - result.error(LOG_TAG, url + " asset file cannot be found!", e); - return; - } - } - // SYSTEM - if (openWithSystemBrowser) { - Log.d(LOG_TAG, "in system"); - openExternal(url, result); - } else { - //Load the dialer - if (url.startsWith(WebView.SCHEME_TEL)) { + if (isLocalFile) { + // check if the asset file exists try { - Log.d(LOG_TAG, "loading in dialer"); - Intent intent = new Intent(Intent.ACTION_DIAL); - intent.setData(Uri.parse(url)); - activity.startActivity(intent); - } catch (android.content.ActivityNotFoundException e) { - Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString()); + url = Util.getUrlAsset(registrar, url); + } catch (IOException e) { + e.printStackTrace(); + result.error(LOG_TAG, url + " asset file cannot be found!", e); + return; } } - // load in InAppBrowserFlutterPlugin - else { - Log.d(LOG_TAG, "loading in InAppBrowserFlutterPlugin"); - open(uuid, null, url, options, headers, false, null, result); + // SYSTEM + if (openWithSystemBrowser) { + Log.d(LOG_TAG, "in system"); + openExternal(url, result); + } else { + //Load the dialer + if (url.startsWith(WebView.SCHEME_TEL)) { + try { + Log.d(LOG_TAG, "loading in dialer"); + Intent intent = new Intent(Intent.ACTION_DIAL); + intent.setData(Uri.parse(url)); + activity.startActivity(intent); + } catch (android.content.ActivityNotFoundException e) { + Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString()); + } + } + // load in InAppBrowserFlutterPlugin + else { + Log.d(LOG_TAG, "loading in InAppBrowserFlutterPlugin"); + open(uuid, null, url, options, headers, false, null, result); + } } } } - } - }); + }); + } + else { + this.activity.runOnUiThread(new Runnable() { + @Override + public void run() { + HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options"); + String data = call.argument("data").toString(); + String mimeType = call.argument("mimeType").toString(); + String encoding = call.argument("encoding").toString(); + String baseUrl = call.argument("baseUrl").toString(); + openData(uuid, options, data, mimeType, encoding, baseUrl); + result.success(true); + } + }); + } + break; + case "getUrl": + result.success(getUrl(uuid)); + break; + case "getTitle": + result.success(getTitle(uuid)); + break; + case "getProgress": + result.success(getProgress(uuid)); break; case "loadUrl": loadUrl(uuid, call.argument("url").toString(), (Map<String, String>) call.argument("headers"), result); @@ -370,7 +396,7 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler { Intent intent = null; Bundle extras = new Bundle(); extras.putString("url", url); - + extras.putBoolean("isData", false); extras.putString("uuid", uuid); extras.putSerializable("options", options); extras.putSerializable("headers", (Serializable) headers); @@ -408,6 +434,43 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler { result.error(LOG_TAG, "No WebView fallback declared.", null); } + public void openData(String uuid, HashMap<String, Object> options, String data, String mimeType, String encoding, String baseUrl) { + Intent intent = new Intent(activity, InAppBrowserActivity.class); + Bundle extras = new Bundle(); + + extras.putBoolean("isData", true); + extras.putString("uuid", uuid); + extras.putSerializable("options", options); + extras.putString("data", data); + extras.putString("mimeType", mimeType); + extras.putString("encoding", encoding); + extras.putString("baseUrl", baseUrl); + + intent.putExtras(extras); + activity.startActivity(intent); + } + + private String getUrl(String uuid) { + InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid); + if (inAppBrowserActivity != null) + return inAppBrowserActivity.getUrl(); + return null; + } + + private String getTitle(String uuid) { + InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid); + if (inAppBrowserActivity != null) + return inAppBrowserActivity.getWebViewTitle(); + return null; + } + + private Integer getProgress(String uuid) { + InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid); + if (inAppBrowserActivity != null) + return inAppBrowserActivity.getProgress(); + return null; + } + public void loadUrl(String uuid, String url, Map<String, String> headers, Result result) { InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid); if (inAppBrowserActivity != null) { diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java index 1854de09bd4ce34c59b3438a1fb4b4de75f4b8de..d234b141ad28ec886a6cd4fbb954a6b5dc7f1c81 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java @@ -18,6 +18,7 @@ import android.webkit.WebView; import com.pichillilorenzo.flutter_inappbrowser.FlutterWebView; import com.pichillilorenzo.flutter_inappbrowser.InAppBrowserActivity; +import com.pichillilorenzo.flutter_inappbrowser.InAppBrowserFlutterPlugin; import com.pichillilorenzo.flutter_inappbrowser.JavaScriptBridgeInterface; import com.pichillilorenzo.flutter_inappbrowser.Util; @@ -431,4 +432,26 @@ public class InAppWebView extends WebView { return result; } + @Override + protected void onScrollChanged (int l, + int t, + int oldl, + int oldt) { + super.onScrollChanged(l, t, oldl, oldt); + + float scale = getResources().getDisplayMetrics().density; + int x = (int) (l/scale); + int y = (int) (t/scale); + + Map<String, Object> obj = new HashMap<>(); + if (inAppBrowserActivity != null) + obj.put("uuid", inAppBrowserActivity.uuid); + obj.put("x", x); + obj.put("y", y); + getChannel().invokeMethod("onScrollChanged", obj); + } + + private MethodChannel getChannel() { + return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.channel : flutterWebView.channel; + } } diff --git a/example/lib/main.dart b/example/lib/main.dart index cb69bfbef31ca509d98e0dfde9237c5a25f5e0c9..553a2f8702100535623d766ffed03fa1a8c387ad 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -4,6 +4,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_inappbrowser/flutter_inappbrowser.dart'; class MyInAppBrowser extends InAppBrowser { + @override + Future onBrowserCreated() async { + print("\n\nBrowser Ready!\n\n"); + } + @override Future onLoadStart(String url) async { print("\n\nStarted $url\n\n"); @@ -16,6 +21,7 @@ class MyInAppBrowser extends InAppBrowser { Future onLoadStop(String url) async { print("\n\nStopped $url\n\n"); +// print(base64.encode(await this.webViewController.getFavicon())); // WebHistory history = await this.webViewController.getCopyBackForwardList(); // print(history.list.length); // print(history.currentIndex); @@ -23,6 +29,7 @@ class MyInAppBrowser extends InAppBrowser { // for(WebHistoryItem item in history.list) { // print(item.title); // } + // // print(await this.webViewController.canGoBackOrForward(1)); // if (await this.webViewController.canGoBackOrForward(-2)) { @@ -132,6 +139,11 @@ class MyInAppBrowser extends InAppBrowser { // this.webViewController.injectStyleFile("https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"); } + @override + Future onScrollChanged(int x, int y) async { +// print(x.toString() + " " + y.toString()); + } + @override void onLoadError(String url, int code, String message) { print("\n\nCan't load $url.. Error: $message\n\n"); @@ -151,10 +163,10 @@ class MyInAppBrowser extends InAppBrowser { void shouldOverrideUrlLoading(String url) { print("\n\n override $url\n\n"); this.webViewController.loadUrl(url); - + // var postData = "username=my_username&password=my_password"; // inAppBrowserFallback.webViewController.postUrl("http://localhost:8080", utf8.encode(postData)); - + // var htmlData = """ //<!doctype html> //<html lang="en"> @@ -308,11 +320,13 @@ class _MyAppState extends State<MyApp> { // await CookieManager.setCookie("https://flutter.io/", "my_cookie2", "cookieValue2", domain: "flutter.io", expiresDate: 1540838864611); // await CookieManager.setCookie("https://flutter.io/", "my_cookie", "cookieValue", domain: "flutter.io", expiresDate: 1540838864611); +// await inAppBrowserFallback.openData("<html><head><title>Data example</title></head><body><p>This is a \"p\" tag</p></body></html>", options: {}); + await inAppBrowserFallback.open(url: "https://flutter.io/", options: { //"useOnLoadResource": true, //"hidden": true, //"toolbarTopFixedTitle": "Fixed title", - "useShouldOverrideUrlLoading": true + "useShouldOverrideUrlLoading": true, //"hideUrlBar": true, //"toolbarTop": false, //"toolbarBottom": false @@ -382,6 +396,7 @@ class _MyAppState extends State<MyApp> { // ), // child: InAppWebView( // initialUrl: "https://flutter.io/", +// //initialData: InAppWebViewInitialData("<html><head><title>Data example</title></head><body><p>This is a \"p\" tag</p></body></html>"), // initialHeaders: { // // }, diff --git a/flutter_inappbrowser.iml b/flutter_inappbrowser.iml index 175d8e0ec50072cba92927a540a3c87ee1686477..4b6ef47a5ddafc36b128738acdbaa8150319f5a3 100644 --- a/flutter_inappbrowser.iml +++ b/flutter_inappbrowser.iml @@ -20,6 +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/.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/ios/Flutter/flutter_assets/packages" /> <excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/flutter_assets/packages" /> </content> <orderEntry type="sourceFolder" forTests="false" /> diff --git a/ios/Classes/InAppBrowserWebViewController.swift b/ios/Classes/InAppBrowserWebViewController.swift index 1e9804dd14eb0695276d72d2ee0c8bf27f8c374a..6d36b553b7106978951d8f5cbcde87bb5f851d10 100644 --- a/ios/Classes/InAppBrowserWebViewController.swift +++ b/ios/Classes/InAppBrowserWebViewController.swift @@ -137,7 +137,7 @@ class InAppWebView_IBWrapper: InAppWebView { } } -class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate, UITextFieldDelegate, WKScriptMessageHandler { +class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKUIDelegate, WKNavigationDelegate, UITextFieldDelegate, WKScriptMessageHandler { @IBOutlet var webView: InAppWebView_IBWrapper! @IBOutlet var closeButton: UIButton! @@ -161,6 +161,10 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio var browserOptions: InAppBrowserOptions? var webViewOptions: InAppWebViewOptions? var initHeaders: [String: String]? + var initData: String? + var initMimeType: String? + var initEncoding: String? + var initBaseUrl: String? var isHidden = false var uuid: String = "" var WKNavigationMap: [String: [String: Any]] = [:] @@ -186,6 +190,7 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio webView.uiDelegate = self webView.navigationDelegate = self + webView.scrollView.delegate = self urlField.delegate = self urlField.text = self.currentURL?.absoluteString @@ -210,9 +215,15 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio spinner.hidesWhenStopped = true spinner.isHidden = false spinner.stopAnimating() - - loadUrl(url: self.currentURL!, headers: self.initHeaders) + if self.initData == nil { + loadUrl(url: self.currentURL!, headers: self.initHeaders) + } + else { + loadData(data: initData!, mimeType: initMimeType!, encoding: initEncoding!, baseUrl: initBaseUrl!) + } + + navigationDelegate?.onBrowserCreated(uuid: uuid, webView: webView) } // Prevent crashes on closing windows @@ -369,10 +380,11 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio currentURL = url updateUrlTextField(url: (currentURL?.absoluteString)!) - if headers != nil { + if let mutableRequest = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest { for (key, value) in headers! { - request.setValue(value, forHTTPHeaderField: key) + mutableRequest.setValue(value, forHTTPHeaderField: key) } + request = mutableRequest as URLRequest } webView.load(request) @@ -582,6 +594,7 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio currentURL = url updateUrlTextField(url: (url.absoluteString)) } + } @@ -693,6 +706,14 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio } } + 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" @@ -960,4 +981,5 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio return result; } + } diff --git a/ios/Classes/InAppWebView.swift b/ios/Classes/InAppWebView.swift index 1dede39db9b0b812965b625552ad03c70d9dea31..14e56d4c865655fb80da9ae413ae2875a148a153 100644 --- a/ios/Classes/InAppWebView.swift +++ b/ios/Classes/InAppWebView.swift @@ -10,6 +10,8 @@ import WebKit public class InAppWebView: WKWebView { + var historyOffset = 0 + public func goBackOrForward(steps: Int) { if canGoBackOrForward(steps: steps) { if (steps > 0) { diff --git a/ios/Classes/SwiftFlutterPlugin.swift b/ios/Classes/SwiftFlutterPlugin.swift index 063f98d34efe1571259ba21df95b28dec68ff528..1f27e8f1b45b51a951658c3c8841da3a9aeb2bbf 100644 --- a/ios/Classes/SwiftFlutterPlugin.swift +++ b/ios/Classes/SwiftFlutterPlugin.swift @@ -71,6 +71,31 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { case "open": self.open(uuid: uuid, arguments: arguments!, result: result) break + case "getUrl": + if let webViewController = self.webViewControllers[uuid] { + result(webViewController!.webView.url?.absoluteString) + } + else { + result(nil) + } + break + case "getTitle": + if let webViewController = self.webViewControllers[uuid] { + result(webViewController!.webView.title) + } + else { + result(nil) + } + break + case "getProgress": + if let webViewController = self.webViewControllers[uuid] { + let progress = Int(webViewController!.webView.estimatedProgress * 100) + result(progress) + } + else { + result(nil) + } + break case "loadUrl": self.loadUrl(uuid: uuid, arguments: arguments!, result: result) break @@ -97,19 +122,19 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { break case "reload": if let webViewController = self.webViewControllers[uuid] { - webViewController?.reload() + webViewController!.reload() } result(true) break case "goBack": if let webViewController = self.webViewControllers[uuid] { - webViewController?.goBack() + webViewController!.goBack() } result(true) break case "canGoBack": if let webViewController = self.webViewControllers[uuid] { - result(webViewController?.canGoBack() ?? false) + result(webViewController!.canGoBack()) } else { result(false) @@ -117,13 +142,13 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { break case "goForward": if let webViewController = self.webViewControllers[uuid] { - webViewController?.goForward() + webViewController!.goForward() } result(true) break case "canGoForward": if let webViewController = self.webViewControllers[uuid] { - result(webViewController?.canGoForward() ?? false) + result(webViewController!.canGoForward()) } else { result(false) @@ -132,14 +157,14 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { case "goBackOrForward": if let webViewController = self.webViewControllers[uuid] { let steps = arguments!["steps"] as! Int - webViewController?.goBackOrForward(steps: steps) + webViewController!.goBackOrForward(steps: steps) } result(true) break case "canGoBackOrForward": if let webViewController = self.webViewControllers[uuid] { let steps = arguments!["steps"] as! Int - result(webViewController?.canGoBackOrForward(steps: steps) ?? false) + result(webViewController!.canGoBackOrForward(steps: steps)) } else { result(false) @@ -147,7 +172,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { break case "isLoading": if let webViewController = self.webViewControllers[uuid] { - result((webViewController?.webView.isLoading ?? false) == true) + result(webViewController!.webView.isLoading == true) } else { result(false) @@ -155,13 +180,13 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { break case "stopLoading": if let webViewController = self.webViewControllers[uuid] { - webViewController?.webView.stopLoading() + webViewController!.webView.stopLoading() } result(true) break case "isHidden": if let webViewController = self.webViewControllers[uuid] { - result((webViewController?.isHidden ?? false) == true) + result(webViewController!.isHidden == true) } else { result(false) @@ -184,7 +209,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { break case "takeScreenshot": if let webViewController = self.webViewControllers[uuid] { - webViewController?.takeScreenshot(completionHandler: { (screenshot) -> Void in + webViewController!.takeScreenshot(completionHandler: { (screenshot) -> Void in result(screenshot) }) } @@ -236,48 +261,61 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { } public func open(uuid: String, arguments: NSDictionary, result: @escaping FlutterResult) { - let url: String = (arguments["url"] as? String)! - - let headers = (arguments["headers"] as? [String: String])! - var absoluteUrl = URL(string: url)?.absoluteURL - - let useChromeSafariBrowser = (arguments["useChromeSafariBrowser"] as? Bool)! + let isData: Bool = (arguments["isData"] as? Bool)! - if useChromeSafariBrowser { - let uuidFallback = (arguments["uuidFallback"] as? String)! - let safariOptions = (arguments["options"] as? [String: Any])! - - let optionsFallback = (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 isLocalFile = (arguments["isLocalFile"] as? Bool)! - var openWithSystemBrowser = (arguments["openWithSystemBrowser"] as? Bool)! - - if isLocalFile { - let key = SwiftFlutterPlugin.registrar!.lookupKey(forAsset: url) - let assetURL = Bundle.main.url(forResource: key, withExtension: nil) - if assetURL == nil { - result(FlutterError(code: "InAppBrowserFlutterPlugin", message: url + " asset file cannot be found!", details: nil)) - return - } - absoluteUrl = assetURL! - } + if !isData { + let url: String = (arguments["url"] as? String)! - if isSystemUrl(absoluteUrl!) { - openWithSystemBrowser = true - } + let headers = (arguments["headers"] as? [String: String])! + var absoluteUrl = URL(string: url)?.absoluteURL + + let useChromeSafariBrowser = (arguments["useChromeSafariBrowser"] as? Bool)! - if (openWithSystemBrowser) { - open(inSystem: absoluteUrl!, result: result) + if useChromeSafariBrowser { + let uuidFallback = (arguments["uuidFallback"] as? String)! + let safariOptions = (arguments["options"] as? [String: Any])! + + let optionsFallback = (arguments["optionsFallback"] as? [String: Any])! + + open(uuid: uuid, uuidFallback: uuidFallback, inAppBrowser: absoluteUrl!, headers: headers, withOptions: safariOptions, useChromeSafariBrowser: true, withOptionsFallback: optionsFallback, result: result); } else { - open(uuid: uuid, uuidFallback: nil, inAppBrowser: absoluteUrl!, headers: headers, withOptions: options, useChromeSafariBrowser: false, withOptionsFallback: nil, result: result) + let options = (arguments["options"] as? [String: Any])! + + let isLocalFile = (arguments["isLocalFile"] as? Bool)! + var openWithSystemBrowser = (arguments["openWithSystemBrowser"] as? Bool)! + + if isLocalFile { + let key = SwiftFlutterPlugin.registrar!.lookupKey(forAsset: url) + let assetURL = Bundle.main.url(forResource: key, withExtension: nil) + if assetURL == nil { + result(FlutterError(code: "InAppBrowserFlutterPlugin", message: url + " asset file cannot be found!", details: nil)) + return + } + absoluteUrl = assetURL! + } + + if isSystemUrl(absoluteUrl!) { + openWithSystemBrowser = true + } + + if (openWithSystemBrowser) { + open(inSystem: absoluteUrl!, result: result) + } + else { + open(uuid: uuid, uuidFallback: nil, inAppBrowser: absoluteUrl!, headers: headers, withOptions: options, useChromeSafariBrowser: false, withOptionsFallback: nil, result: result) + } } } + else { + let options = (arguments["options"] as? [String: Any])! + let data = (arguments["data"] as? String)! + let mimeType = (arguments["mimeType"] as? String)! + let encoding = (arguments["encoding"] as? String)! + let baseUrl = (arguments["baseUrl"] as? String)! + open(uuid: uuid, options: options, data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl) + result(true) + } } func open(uuid: String, uuidFallback: String?, inAppBrowser url: URL, headers: [String: String], withOptions options: [String: Any], useChromeSafariBrowser: Bool, withOptionsFallback optionsFallback: [String: Any]?, result: @escaping FlutterResult) { @@ -406,6 +444,71 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { result(true) } + func open(uuid: String, options: [String: Any], data: String, mimeType: String, encoding: String, baseUrl: String) { + + var uuid = uuid + + if self.webViewControllers[uuid] != nil { + close(uuid: uuid) + } + + if self.previousStatusBarStyle == -1 { + self.previousStatusBarStyle = UIApplication.shared.statusBarStyle.rawValue + } + + if !(self.tmpWindow != nil) { + let frame: CGRect = UIScreen.main.bounds + self.tmpWindow = UIWindow(frame: frame) + } + + let tmpController = UIViewController() + let baseWindowLevel = UIApplication.shared.keyWindow?.windowLevel + self.tmpWindow?.rootViewController = tmpController + self.tmpWindow?.windowLevel = UIWindowLevel(baseWindowLevel! + 1) + self.tmpWindow?.makeKeyAndVisible() + + let browserOptions: InAppBrowserOptions + let webViewOptions: InAppWebViewOptions + + browserOptions = InAppBrowserOptions() + browserOptions.parse(options: options) + + webViewOptions = InAppWebViewOptions() + webViewOptions.parse(options: options) + + 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 + let webViewController: InAppBrowserWebViewController = self.webViewControllers[uuid] as! InAppBrowserWebViewController + webViewController.uuid = uuid + webViewController.browserOptions = browserOptions + webViewController.webViewOptions = webViewOptions + webViewController.isHidden = browserOptions.hidden + webViewController.tmpWindow = tmpWindow + webViewController.initData = data + webViewController.initMimeType = mimeType + webViewController.initEncoding = encoding + webViewController.initBaseUrl = baseUrl + webViewController.navigationDelegate = self + + if browserOptions.hidden { + webViewController.view.isHidden = true + tmpController.present(webViewController, animated: false, completion: {() -> Void in + webViewController.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl) + }) + webViewController.presentingViewController?.dismiss(animated: false, completion: {() -> Void in + self.tmpWindow?.windowLevel = 0.0 + UIApplication.shared.delegate?.window??.makeKeyAndVisible() + }) + } + else { + tmpController.present(webViewController, animated: true, completion: {() -> Void in + webViewController.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl) + }) + } + + } + public func loadUrl(uuid: String, arguments: NSDictionary, result: @escaping FlutterResult) { let webViewController: InAppBrowserWebViewController = self.webViewControllers[uuid] as! InAppBrowserWebViewController if let url = arguments["url"] as? String { @@ -595,6 +698,12 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { injectDeferredObject(uuid: uuid, source: arguments["urlFile"] as! String, withWrapper: jsWrapper, result: result) } + func onBrowserCreated(uuid: String, webView: WKWebView) { + if let webViewController = self.webViewControllers[uuid] { + channel.invokeMethod("onBrowserCreated", arguments: ["uuid": uuid]) + } + } + func onLoadStart(uuid: String, webView: WKWebView) { if let webViewController = self.webViewControllers[uuid] { let url: String = webViewController!.currentURL!.absoluteString @@ -651,6 +760,12 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { } } + func onScrollChanged(uuid: String, webView: WKWebView, x: Int, y: Int) { + if let webViewController = self.webViewControllers[uuid] { + channel.invokeMethod("onScrollChanged", arguments: ["uuid": uuid, "x": x, "y": y]) + } + } + func onExit(uuid: String) { channel.invokeMethod("onExit", arguments: ["uuid": uuid]) } diff --git a/lib/flutter_inappbrowser.dart b/lib/flutter_inappbrowser.dart index 45105344e45865dfa6f3342c88c81ba5b7ca6672..11011279617bc99bbf790ab2e319a7507c3766ba 100644 --- a/lib/flutter_inappbrowser.dart +++ b/lib/flutter_inappbrowser.dart @@ -127,6 +127,10 @@ class InAppBrowser { Future<dynamic> _handleMethod(MethodCall call) async { switch(call.method) { + case "onBrowserCreated": + this._isOpened = true; + onBrowserCreated(); + break; case "onExit": this._isOpened = false; onExit(); @@ -199,12 +203,12 @@ class InAppBrowser { args.putIfAbsent('options', () => options); args.putIfAbsent('openWithSystemBrowser', () => false); args.putIfAbsent('isLocalFile', () => false); + args.putIfAbsent('isData', () => false); args.putIfAbsent('useChromeSafariBrowser', () => false); await _ChannelManager.channel.invokeMethod('open', args); - this._isOpened = true; } - ///Opens the giver [assetFilePath] file in a new [InAppBrowser] instance. The other arguments are the same of [InAppBrowser.open()]. + ///Opens the given [assetFilePath] file in a new [InAppBrowser] instance. The other arguments are the same of [InAppBrowser.open()]. /// ///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! /// @@ -243,9 +247,28 @@ class InAppBrowser { args.putIfAbsent('options', () => options); args.putIfAbsent('openWithSystemBrowser', () => false); args.putIfAbsent('isLocalFile', () => true); + args.putIfAbsent('isData', () => false); + args.putIfAbsent('useChromeSafariBrowser', () => false); + await _ChannelManager.channel.invokeMethod('open', args); + } + + ///Opens a new [InAppBrowser] instance with [data] as a content, using [baseUrl] as the base URL for it. + ///The [mimeType] parameter specifies the format of the data. + ///The [encoding] parameter specifies the encoding of the data. + Future<void> openData(String data, {String mimeType = "text/html", String encoding = "utf8", String baseUrl = "about:blank", Map<String, dynamic> options = const {}}) async { + assert(data != null); + Map<String, dynamic> args = <String, dynamic>{}; + args.putIfAbsent('uuid', () => uuid); + args.putIfAbsent('options', () => options); + args.putIfAbsent('data', () => data); + args.putIfAbsent('mimeType', () => mimeType); + args.putIfAbsent('encoding', () => encoding); + args.putIfAbsent('baseUrl', () => baseUrl); + args.putIfAbsent('openWithSystemBrowser', () => false); + args.putIfAbsent('isLocalFile', () => false); + args.putIfAbsent('isData', () => true); 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. You wont be able to use the [InAppBrowser] methods here! @@ -256,6 +279,7 @@ class InAppBrowser { args.putIfAbsent('url', () => url); args.putIfAbsent('headers', () => {}); args.putIfAbsent('isLocalFile', () => false); + args.putIfAbsent('isData', () => false); args.putIfAbsent('openWithSystemBrowser', () => true); args.putIfAbsent('useChromeSafariBrowser', () => false); return await _ChannelManager.channel.invokeMethod('open', args); @@ -319,6 +343,11 @@ class InAppBrowser { return this._isOpened; } + ///Event fires when the [InAppBrowser] is created. + void onBrowserCreated() { + + } + ///Event fires when the [InAppBrowser] starts to load an [url]. void onLoadStart(String url) { @@ -365,6 +394,13 @@ class InAppBrowser { } + ///Event fires when the [InAppBrowser] webview scrolls. + ///[x] represents the current horizontal scroll origin in pixels. + ///[y] represents the current vertical scroll origin in pixels. + void onScrollChanged(int x, int y) { + + } + void _throwIsAlreadyOpened({String message = ''}) { if (this.isOpened()) { throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is already opened.']); @@ -496,6 +532,28 @@ typedef void onWebViewProgressChangedCallback(InAppWebViewController controller, typedef void onWebViewConsoleMessageCallback(InAppWebViewController controller, ConsoleMessage consoleMessage); typedef void shouldOverrideUrlLoadingCallback(InAppWebViewController controller, String url); typedef void onWebViewLoadResourceCallback(InAppWebViewController controller, WebResourceResponse response, WebResourceRequest request); +typedef void onWebViewScrollChangedCallback(InAppWebViewController controller, int x, int y); + +///Initial [data] as a content for an [InAppWebView] instance, using [baseUrl] as the base URL for it. +///The [mimeType] property specifies the format of the data. +///The [encoding] property specifies the encoding of the data. +class InAppWebViewInitialData { + String data; + String mimeType; + String encoding; + String baseUrl; + + InAppWebViewInitialData(this.data, {this.mimeType = "text/html", this.encoding = "utf8", this.baseUrl = "about:blank"}); + + Map<String, String> toMap() { + return { + "data": data, + "mimeType": mimeType, + "encoding": encoding, + "baseUrl": baseUrl + }; + } +} ///InAppWebView Widget class. /// @@ -563,10 +621,17 @@ class InAppWebView extends StatefulWidget { ///**NOTE only for iOS**: In some cases, the [response.data] of a [response] with `text/assets` encoding could be empty. final onWebViewLoadResourceCallback onLoadResource; + ///Event fires when the [InAppWebView] scrolls. + ///[x] represents the current horizontal scroll origin in pixels. + ///[y] represents the current vertical scroll origin in pixels. + final onWebViewScrollChangedCallback onScrollChanged; + ///Initial url that will be loaded. final String initialUrl; ///Initial asset file that will be loaded. See [InAppWebView.loadFile()] for explanation. final String initialFile; + ///Initial [InAppWebViewInitialData] that will be loaded. + final InAppWebViewInitialData initialData; ///Initial headers that will be used. final Map<String, String> initialHeaders; ///Initial options that will be used. @@ -577,6 +642,7 @@ class InAppWebView extends StatefulWidget { Key key, this.initialUrl = "about:blank", this.initialFile, + this.initialData, this.initialHeaders = const {}, this.initialOptions = const {}, this.onWebViewCreated, @@ -587,6 +653,7 @@ class InAppWebView extends StatefulWidget { this.onProgressChanged, this.shouldOverrideUrlLoading, this.onLoadResource, + this.onScrollChanged, this.gestureRecognizers, }) : super(key: key); @@ -620,6 +687,7 @@ class _InAppWebViewState extends State<InAppWebView> { creationParams: <String, dynamic>{ 'initialUrl': widget.initialUrl, 'initialFile': widget.initialFile, + 'initialData': widget.initialData?.toMap(), 'initialHeaders': widget.initialHeaders, 'initialOptions': widget.initialOptions }, @@ -754,6 +822,14 @@ class InAppWebViewController { else _inAppBrowser.onConsoleMessage(ConsoleMessage(sourceURL, lineNumber, message, messageLevel)); break; + case "onScrollChanged": + int x = call.arguments["x"]; + int y = call.arguments["y"]; + if (_widget != null) + _widget.onScrollChanged(this, x, y); + else + _inAppBrowser.onScrollChanged(x, y); + break; case "onCallJsHandler": String handlerName = call.arguments["handlerName"]; List<dynamic> args = jsonDecode(call.arguments["args"]); @@ -768,6 +844,57 @@ class InAppWebViewController { } } + ///Gets the URL for the current page. + ///This is not always the same as the URL passed to [InAppWebView.onLoadStarted] because although the load for that URL has begun, the current page may not have changed. + Future<String> getUrl() async { + Map<String, dynamic> args = <String, dynamic>{}; + if (_inAppBrowserUuid != null) { + _inAppBrowser._throwIsNotOpened(); + args.putIfAbsent('uuid', () => _inAppBrowserUuid); + } + return await _channel.invokeMethod('getUrl', args); + } + + ///Gets the title for the current page. + Future<String> getTitle() async { + Map<String, dynamic> args = <String, dynamic>{}; + if (_inAppBrowserUuid != null) { + _inAppBrowser._throwIsNotOpened(); + args.putIfAbsent('uuid', () => _inAppBrowserUuid); + } + return await _channel.invokeMethod('getTitle', args); + } + + ///Gets the progress for the current page. The progress value is between 0 and 100. + Future<int> getProgress() async { + Map<String, dynamic> args = <String, dynamic>{}; + if (_inAppBrowserUuid != null) { + _inAppBrowser._throwIsNotOpened(); + args.putIfAbsent('uuid', () => _inAppBrowserUuid); + } + return await _channel.invokeMethod('getProgress', args); + } + + ///Gets the favicon for the current page. + Future<List<int>> getFavicon() async { + var completer = new Completer<List<int>>(); + var faviconData = new List<int>(); + HttpClient client = new HttpClient(); + var url = Uri.parse(await getUrl()); + // solution found here: https://stackoverflow.com/a/15750809/4637638 + var faviconUrl = Uri.parse("https://plus.google.com/_/favicon?domain_url=" + url.scheme + "://" + url.host); + + client.getUrl(faviconUrl).then((HttpClientRequest request) { + return request.close(); + }).then((HttpClientResponse response) { + response.listen((List<int> data) { + faviconData = data; + }, onDone: () => completer.complete(faviconData)); + }); + + return completer.future; + } + ///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 { assert(url != null && url.isNotEmpty); diff --git a/pubspec.yaml b/pubspec.yaml index c646ded47623d837f8effac8a194457aab6d52d8..46eebaa638ea0829b0f4c71089f17fe4e62e9552 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ 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). -version: 0.5.4 +version: 0.5.5 author: Lorenzo Pichilli <pichillilorenzo@gmail.com> homepage: https://github.com/pichillilorenzo/flutter_inappbrowser