diff --git a/.idea/workspace.xml b/.idea/workspace.xml index e6069a4f..01d9d6d0 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -16,8 +16,19 @@ + + + + + + + + + + + @@ -37,8 +48,8 @@ - - + + @@ -46,28 +57,23 @@ - - + + - - + + - - - - + + - - - - - + + @@ -75,8 +81,8 @@ - - + + @@ -92,22 +98,6 @@ - getOp - onLoadError - StatefulWidget - onLoadResource - useShouldOverrideUrlLoading - ): - InAppLocalhostServer - local - openWithSystemBrowser - __userAgent__ - a - InApp - A [InApp - A `InApp - assets - Ui postUrl assert( sNotEmpty() @@ -122,6 +112,22 @@ throw InAppWeb Boolean + [WebHistory.list] + open + Cannot laod + _throwIsNotOpened + takeS + Completer + args.putIfAbsent('isLocalFile', () => true); + args.putIfAbsent('isLocalFile', () => + Opens the + _isOpened + initialFile + onBrowserCreated + getUrl + onScrollChanged + openData + initialData activity.getPreferences(0) @@ -165,9 +171,9 @@ @@ -183,18 +189,8 @@ + - - - - - - - - - + + @@ -374,16 +404,15 @@ - - - + + - + @@ -396,6 +425,7 @@ + @@ -419,11 +449,6 @@ - - - - - @@ -649,34 +674,24 @@ + + + + + + + - - - - - - - - - - - - - - - - - - - + + - - + + @@ -685,12 +700,24 @@ - - + + + + + + + + + + + + + + + + - - diff --git a/CHANGELOG.md b/CHANGELOG.md index 18e333d4..db02cffc 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 dbafe686..c019f2e9 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\ 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\ InAppWebViewController.getTitle + +Gets the title for the current page. + +```dart +inAppWebViewController.getTitle(); +``` + +#### Future\ InAppWebViewController.getProgress + +Gets the progress for the current page. The progress value is between 0 and 100. + +```dart +inAppWebViewController.getProgress(); +``` + +#### Future\\> InAppWebViewController.getFavicon + +Gets the favicon for the current page. + +```dart +inAppWebViewController.getFavicon(); +``` + #### Future\ 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 headers = con #### Future\ 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 headers = const {}, Map options = const {}}); ``` +#### static Future\ 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 options = const {}}); +``` + #### static Future\ 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 c82b1c23..287449be 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 initialData = (Map) params.get("initialData"); Map initialHeaders = (Map) params.get("initialHeaders"); HashMap initialOptions = (HashMap) 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) 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 7feeb450..817f52fa 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 optionsMap = (HashMap) b.getSerializable("options"); options = new InAppBrowserOptions(); @@ -62,16 +62,29 @@ public class InAppBrowserActivity extends AppCompatActivity { webViewOptions.parse(optionsMap); webView.options = webViewOptions; - headers = (HashMap) b.getSerializable("headers"); - InAppBrowserFlutterPlugin.webViewActivities.put(uuid, this); actionBar = getSupportActionBar(); prepareView(); - webView.loadUrl(url, headers); - //webView.loadData(" Document ciao \"not ", "text/assets", "utf8"); + Boolean isData = b.getBoolean("isData"); + if (!isData) { + headers = (HashMap) 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 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 d224f207..edabeadd 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 headers = (Map) call.argument("headers"); + final Map headers = (Map) 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 options = (HashMap) call.argument("options"); + final HashMap options = (HashMap) call.argument("options"); - final HashMap optionsFallback = (HashMap) call.argument("optionsFallback"); + final HashMap optionsFallback = (HashMap) call.argument("optionsFallback"); - open(uuid, uuidFallback, url_final, options, headers, true, optionsFallback, result); - } else { - - String url = url_final; - - final HashMap options = (HashMap) call.argument("options"); - - final boolean isLocalFile = (boolean) call.argument("isLocalFile"); - final boolean openWithSystemBrowser = (boolean) call.argument("openWithSystemBrowser"); - - if (isLocalFile) { - // check if the asset file exists - try { - url = Util.getUrlAsset(registrar, url); - } catch (IOException e) { - e.printStackTrace(); - result.error(LOG_TAG, url + " asset file cannot be found!", e); - return; - } - } - // SYSTEM - if (openWithSystemBrowser) { - Log.d(LOG_TAG, "in system"); - openExternal(url, result); + open(uuid, uuidFallback, url_final, options, headers, true, optionsFallback, result); } else { - //Load the dialer - if (url.startsWith(WebView.SCHEME_TEL)) { + + String url = url_final; + + final HashMap options = (HashMap) call.argument("options"); + + final boolean isLocalFile = (boolean) call.argument("isLocalFile"); + final boolean openWithSystemBrowser = (boolean) call.argument("openWithSystemBrowser"); + + if (isLocalFile) { + // check if the asset file exists try { - 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 options = (HashMap) 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) 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 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 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 1854de09..d234b141 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 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 cb69bfbe..553a2f87 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 = """ // // @@ -308,11 +320,13 @@ class _MyAppState extends State { // 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("Data example

This is a \"p\" tag

", 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 { // ), // child: InAppWebView( // initialUrl: "https://flutter.io/", +// //initialData: InAppWebViewInitialData("Data example

This is a \"p\" tag

"), // initialHeaders: { // // }, diff --git a/flutter_inappbrowser.iml b/flutter_inappbrowser.iml index 175d8e0e..4b6ef47a 100644 --- a/flutter_inappbrowser.iml +++ b/flutter_inappbrowser.iml @@ -20,6 +20,7 @@ + diff --git a/ios/Classes/InAppBrowserWebViewController.swift b/ios/Classes/InAppBrowserWebViewController.swift index 1e9804dd..6d36b553 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 1dede39d..14e56d4c 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 063f98d3..1f27e8f1 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,47 +261,60 @@ 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])! + if !isData { + 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 optionsFallback = (arguments["optionsFallback"] as? [String: Any])! - - open(uuid: uuid, uuidFallback: uuidFallback, inAppBrowser: absoluteUrl!, headers: headers, withOptions: safariOptions, useChromeSafariBrowser: true, withOptionsFallback: optionsFallback, 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 { + 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 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) - } + 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) } } @@ -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 45105344..11011279 100644 --- a/lib/flutter_inappbrowser.dart +++ b/lib/flutter_inappbrowser.dart @@ -127,6 +127,10 @@ class InAppBrowser { Future _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 openData(String data, {String mimeType = "text/html", String encoding = "utf8", String baseUrl = "about:blank", Map options = const {}}) async { + assert(data != null); + Map args = {}; + 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 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 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 { creationParams: { '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 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 getUrl() async { + Map args = {}; + if (_inAppBrowserUuid != null) { + _inAppBrowser._throwIsNotOpened(); + args.putIfAbsent('uuid', () => _inAppBrowserUuid); + } + return await _channel.invokeMethod('getUrl', args); + } + + ///Gets the title for the current page. + Future getTitle() async { + Map args = {}; + 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 getProgress() async { + Map args = {}; + if (_inAppBrowserUuid != null) { + _inAppBrowser._throwIsNotOpened(); + args.putIfAbsent('uuid', () => _inAppBrowserUuid); + } + return await _channel.invokeMethod('getProgress', args); + } + + ///Gets the favicon for the current page. + Future> getFavicon() async { + var completer = new Completer>(); + var faviconData = new List(); + 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 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 loadUrl(String url, {Map headers = const {}}) async { assert(url != null && url.isNotEmpty); diff --git a/pubspec.yaml b/pubspec.yaml index c646ded4..46eebaa6 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 homepage: https://github.com/pichillilorenzo/flutter_inappbrowser