diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 8c01449d..07de65f8 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -16,62 +16,16 @@
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -94,30 +48,30 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -126,10 +80,10 @@
-
+
-
-
+
+
@@ -145,7 +99,6 @@
- openFile
File
onExit
_handleMethod
@@ -175,6 +128,7 @@
_dispose
UIImagePNGRepresentation
png
+ cordova
activity.getPreferences(0)
@@ -193,7 +147,6 @@
-
+
@@ -248,6 +202,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -277,45 +270,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -466,8 +420,8 @@
-
-
+
+
@@ -477,7 +431,7 @@
-
+
@@ -485,7 +439,7 @@
-
+
@@ -513,9 +467,6 @@
-
-
-
@@ -525,13 +476,7 @@
-
-
-
-
-
-
-
+
@@ -742,13 +687,6 @@
-
-
-
-
-
-
-
@@ -773,30 +711,44 @@
-
+
-
-
+
+
+
-
-
+
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fb1f7afe..ea07554b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 1.3.0
+
+- Merge
+- Merge
+- Merge
+- Merge
+- Merge
+- Merge
+- Added `horizontalScrollBarEnabled` and `verticalScrollBarEnabled` options to enable/disable the corresponding scrollbar of the WebView [#165](https://github.com/pichillilorenzo/flutter_inappbrowser/issues/165)
+
+
## 1.2.1
- Merge "Add new option to control the contentMode in Android platform" [#101](https://github.com/pichillilorenzo/flutter_inappbrowser/pull/101) (thanks to [DreamBuddy](https://github.com/DreamBuddy))
diff --git a/README.md b/README.md
index 1a1b6727..9caeb112 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,6 @@
[![Donate to this project using Patreon](https://img.shields.io/badge/patreon-donate-yellow.svg)](https://www.patreon.com/bePatron?u=9269604)
A Flutter plugin that allows you to add an inline webview or open an in-app browser window.
-This plugin is inspired by the popular [cordova-plugin-inappbrowser](https://github.com/apache/cordova-plugin-inappbrowser)!
### Requirements
- Dart sdk: ">=2.1.0-dev.7.1 <3.0.0"
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index aaa8e933..3245b439 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
package="com.pichillilorenzo.flutter_inappbrowser">
+
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 d5b9129d..79d4e584 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
@@ -1,16 +1,26 @@
package com.pichillilorenzo.flutter_inappbrowser.InAppWebView;
+import android.Manifest;
+import android.app.Activity;
+import android.app.DownloadManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Picture;
+import android.net.Uri;
import android.os.Build;
+import android.os.Environment;
import android.util.AttributeSet;
import android.util.JsonReader;
import android.util.JsonToken;
import android.util.Log;
import android.webkit.CookieManager;
+import android.webkit.DownloadListener;
+import android.webkit.URLUtil;
import android.webkit.ValueCallback;
import android.webkit.WebBackForwardList;
import android.webkit.WebHistoryItem;
@@ -21,6 +31,7 @@ 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.RequestPermissionHandler;
import com.pichillilorenzo.flutter_inappbrowser.Util;
import java.io.ByteArrayOutputStream;
@@ -36,6 +47,8 @@ import io.flutter.plugin.common.PluginRegistry;
import okhttp3.Cache;
import okhttp3.OkHttpClient;
+import static android.content.Context.DOWNLOAD_SERVICE;
+
public class InAppWebView extends WebView {
static final String LOG_TAG = "InAppWebView";
@@ -110,6 +123,8 @@ public class InAppWebView extends WebView {
public void prepare() {
+ final Activity activity = (inAppBrowserActivity != null) ? inAppBrowserActivity : registrar.activity();
+
boolean isFromInAppBrowserActivity = inAppBrowserActivity != null;
httpClient = new OkHttpClient().newBuilder().cache(new Cache(getContext().getCacheDir(), okHttpClientCacheSize)).build();
@@ -122,39 +137,43 @@ public class InAppWebView extends WebView {
inAppWebViewClient = new InAppWebViewClient((isFromInAppBrowserActivity) ? inAppBrowserActivity : flutterWebView);
setWebViewClient(inAppWebViewClient);
-// final Activity activity = this;
-//
-// webView.setDownloadListener(new DownloadListener() {
-// @Override
-// public void onDownloadStart(final String url, final String userAgent,
-// final String contentDisposition, final String mimetype,
-// final long contentLength) {
-//
-// RequestPermissionHandler.checkAndRun(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE, RequestPermissionHandler.REQUEST_CODE_WRITE_EXTERNAL_STORAGE, new Runnable(){
-// @Override
-// public void run(){
-// DownloadManager.Request request = new DownloadManager.Request(
-// Uri.parse(url));
-//
-// final String filename = URLUtil.guessFileName(url, contentDisposition, mimetype);
-// request.allowScanningByMediaScanner();
-// request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //Notify client once download is completed!
-// request.setVisibleInDownloadsUi(true);
-// request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
-// DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
-// if (dm != null) {
-// dm.enqueue(request);
-// Toast.makeText(getApplicationContext(), "Downloading File: " + filename, //To notify the Client that the file is being downloaded
-// Toast.LENGTH_LONG).show();
-// }
-// else {
-// Toast.makeText(getApplicationContext(), "Cannot Download File: " + filename, //To notify the Client that the file cannot be downloaded
-// Toast.LENGTH_LONG).show();
-// }
-// }
-// });
-// }
-// });
+ activity.registerReceiver(onDownloadComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
+
+ setDownloadListener(new DownloadListener() {
+ @Override
+ public void onDownloadStart(final String url, final String userAgent,
+ final String contentDisposition, final String mimetype,
+ final long contentLength) {
+
+ RequestPermissionHandler.checkAndRun(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE, RequestPermissionHandler.REQUEST_CODE_WRITE_EXTERNAL_STORAGE, new Runnable(){
+ @Override
+ public void run(){
+
+ Log.e(LOG_TAG, url);
+ Log.e(LOG_TAG, contentDisposition);
+ Log.e(LOG_TAG, mimetype);
+
+ DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
+
+ final String filename = URLUtil.guessFileName(url, contentDisposition, mimetype);
+ request.allowScanningByMediaScanner();
+ request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //Notify client once download is completed!
+ request.setVisibleInDownloadsUi(true);
+ request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
+ DownloadManager dm = (DownloadManager) activity.getSystemService(DOWNLOAD_SERVICE);
+ if (dm != null) {
+ dm.enqueue(request);
+ //Toast.makeText(getApplicationContext(), "Downloading File: " + filename, //To notify the Client that the file is being downloaded
+ // Toast.LENGTH_LONG).show();
+ }
+ else {
+ //Toast.makeText(getApplicationContext(), "Cannot Download File: " + filename, //To notify the Client that the file cannot be downloaded
+ // Toast.LENGTH_LONG).show();
+ }
+ }
+ });
+ }
+ });
WebSettings settings = getSettings();
@@ -187,6 +206,8 @@ public class InAppWebView extends WebView {
settings.setUseWideViewPort(options.useWideViewPort);
settings.setSupportZoom(options.supportZoom);
settings.setTextZoom(options.textZoom);
+ setVerticalScrollBarEnabled(options.verticalScrollBarEnabled);
+ setHorizontalScrollBarEnabled(options.horizontalScrollBarEnabled);
if (options.transparentBackground) {
setBackgroundColor(Color.TRANSPARENT);
@@ -205,6 +226,19 @@ public class InAppWebView extends WebView {
}
}
+ private BroadcastReceiver onDownloadComplete = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ //Fetching the download id received with the broadcast
+ long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
+ //Checking if the received broadcast is for our enqueued download by matching download id
+ if (1 == id) { // test
+ //if (downloadID == id) {
+ //Toast.makeText(MainActivity.this, "Download Completed", Toast.LENGTH_SHORT).show();
+ }
+ }
+ };
+
public void loadUrl(String url, MethodChannel.Result result) {
if (!url.isEmpty()) {
loadUrl(url);
@@ -367,6 +401,12 @@ public class InAppWebView extends WebView {
if (newOptionsMap.get("textZoom") != null && options.textZoom != newOptions.textZoom)
settings.setTextZoom(newOptions.textZoom);
+ if (newOptionsMap.get("verticalScrollBarEnabled") != null && options.verticalScrollBarEnabled != newOptions.verticalScrollBarEnabled)
+ setVerticalScrollBarEnabled(newOptions.verticalScrollBarEnabled);
+
+ if (newOptionsMap.get("horizontalScrollBarEnabled") != null && options.horizontalScrollBarEnabled != newOptions.horizontalScrollBarEnabled)
+ setHorizontalScrollBarEnabled(newOptions.horizontalScrollBarEnabled);
+
if (newOptionsMap.get("transparentBackground") != null && options.transparentBackground != newOptions.transparentBackground) {
if (newOptions.transparentBackground) {
setBackgroundColor(Color.TRANSPARENT);
@@ -524,4 +564,11 @@ public class InAppWebView extends WebView {
private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.channel : flutterWebView.channel;
}
+
+ @Override
+ public void destroy() {
+ final Activity activity = (inAppBrowserActivity != null) ? inAppBrowserActivity : registrar.activity();
+ activity.unregisterReceiver(onDownloadComplete);
+ super.destroy();
+ }
}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java
index 14c9e89c..4d998f6f 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java
@@ -14,6 +14,8 @@ public class InAppWebViewOptions extends Options {
public boolean javaScriptCanOpenWindowsAutomatically = false;
public boolean mediaPlaybackRequiresUserGesture = true;
public int textZoom = 100;
+ public boolean verticalScrollBarEnabled = true;
+ public boolean horizontalScrollBarEnabled = true;
public boolean clearSessionCache = false;
public boolean builtInZoomControls = false;
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/RequestPermissionHandler.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/RequestPermissionHandler.java
index 76ccb1f0..cf5cbb29 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/RequestPermissionHandler.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/RequestPermissionHandler.java
@@ -15,6 +15,8 @@ public abstract class RequestPermissionHandler implements ActivityCompat.OnReque
private static Map> actionDictionary = new HashMap<>();
+ public static int REQUEST_CODE_WRITE_EXTERNAL_STORAGE = 1;
+
public static void checkAndRun(Activity activity, String permission, int requestCode, Runnable runnable) {
int permissionCheck = ContextCompat.checkSelfPermission(activity.getApplicationContext(), permission);
diff --git a/example/lib/inline_example.screen.dart b/example/lib/inline_example.screen.dart
index 360a4f2b..445126d7 100644
--- a/example/lib/inline_example.screen.dart
+++ b/example/lib/inline_example.screen.dart
@@ -55,8 +55,8 @@ class _InlineExampleScreenState extends State {
BoxDecoration(border: Border.all(color: Colors.blueAccent)),
child: InAppWebView(
//initialUrl: "https://www.youtube.com/embed/M7lc1UVf-VE?playsinline=1",
- //initialUrl: "https://flutter.dev/",
- initialFile: "assets/index.html",
+ initialUrl: "https://flutter.dev/",
+ //initialFile: "assets/index.html",
initialHeaders: {},
initialOptions: {
//"mediaPlaybackRequiresUserGesture": false,
diff --git a/ios/Classes/InAppWebView.swift b/ios/Classes/InAppWebView.swift
index 8f6dd4af..3ab4a3c4 100755
--- a/ios/Classes/InAppWebView.swift
+++ b/ios/Classes/InAppWebView.swift
@@ -82,8 +82,8 @@ window.\(JAVASCRIPT_BRIDGE_NAME).callHandler = function() {
let platformReadyJS = "window.dispatchEvent(new Event('flutterInAppBrowserPlatformReady'));";
-public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler {
-
+public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler, URLSessionDownloadDelegate {
+
var IABController: InAppBrowserWebViewController?
var IAWController: FlutterWebViewController?
var options: InAppWebViewOptions?
@@ -180,6 +180,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
configuration.preferences.javaScriptEnabled = (options?.javaScriptEnabled)!
+ scrollView.showsVerticalScrollIndicator = (options?.verticalScrollBarEnabled)!
+ scrollView.showsHorizontalScrollIndicator = (options?.horizontalScrollBarEnabled)!
+
if ((options?.userAgent)! != "") {
if #available(iOS 9.0, *) {
customUserAgent = (options?.userAgent)!
@@ -388,6 +391,13 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
configuration.preferences.javaScriptEnabled = newOptions.javaScriptEnabled
}
+ if newOptionsMap["verticalScrollBarEnabled"] != nil && options?.verticalScrollBarEnabled != newOptions.verticalScrollBarEnabled {
+ scrollView.showsVerticalScrollIndicator = newOptions.verticalScrollBarEnabled
+ }
+ if newOptionsMap["horizontalScrollBarEnabled"] != nil && options?.horizontalScrollBarEnabled != newOptions.horizontalScrollBarEnabled {
+ scrollView.showsHorizontalScrollIndicator = newOptions.horizontalScrollBarEnabled
+ }
+
if newOptionsMap["userAgent"] != nil && options?.userAgent != newOptions.userAgent && (newOptions.userAgent != "") {
if #available(iOS 9.0, *) {
customUserAgent = newOptions.userAgent
@@ -514,9 +524,8 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
public func webView(_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
-
+
if let url = navigationAction.request.url {
-
if url.absoluteString != url.absoluteString && (options?.useOnLoadResource)! {
WKNavigationMap[url.absoluteString] = [
"startTime": currentTimeInMilliSeconds(),
@@ -556,6 +565,17 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
}
}
+ let mimeType = navigationResponse.response.mimeType
+ if let url = navigationResponse.response.url {
+ if mimeType != nil && !mimeType!.starts(with: "text/") {
+ Downloader.load(delegate: self, url: url, completion: { (destinationUrl: URL) in
+ print(destinationUrl)
+ })
+ decisionHandler(.cancel)
+ return
+ }
+ }
+
decisionHandler(.allow)
}
@@ -647,6 +667,20 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
setNeedsLayout()
}
+ public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
+
+ }
+
+ public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
+ guard
+ let url = downloadTask.originalRequest?.url
+ else {
+ return
+ }
+ let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
+ let totalSize = ByteCountFormatter.string(fromByteCount: totalBytesExpectedToWrite, countStyle: .file)
+ }
+
public func onLoadStart(url: String) {
var arguments: [String: Any] = ["url": url]
if IABController != nil {
@@ -839,3 +873,47 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
return (IABController != nil) ? SwiftFlutterPlugin.channel! : ((IAWController != nil) ? IAWController!.channel! : nil);
}
}
+
+class Downloader {
+ class func load(delegate: URLSessionDelegate, url: URL, completion: @escaping (_ destinationUrl: URL) -> ()) {
+ let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last as! URL
+ let destinationUrl = documentsUrl.appendingPathComponent(url.lastPathComponent)
+
+ if FileManager.default.fileExists(atPath: destinationUrl.path) {
+ print("file already exists [\(destinationUrl.path)]")
+ //completion(path: destinationUrl.path!, error:nil)
+ return
+ }
+
+ let sessionConfig = URLSessionConfiguration.default
+ let session = URLSession(configuration: sessionConfig, delegate: delegate, delegateQueue: nil)
+ var request = URLRequest(url: url)
+ request.httpMethod = "GET"
+
+ let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
+ if let tempLocalUrl = tempLocalUrl, error == nil {
+ // Success
+ if let statusCode = (response as? HTTPURLResponse)?.statusCode {
+ if statusCode == 200 {
+ do {
+ try FileManager.default.moveItem(at: tempLocalUrl, to: destinationUrl)
+ completion(destinationUrl)
+ } catch (let writeError) {
+ print("error writing file \(destinationUrl) : \(writeError)")
+ //completion(path: destinationUrl.path!, error:nil)
+ }
+ } else {
+ //completion(path: destinationUrl.path!, error:nil)
+ }
+ } else {
+ //completion(path: destinationUrl.path!, error:nil)
+ }
+
+ } else {
+ print("Failure: %@", error?.localizedDescription);
+ //completion(path: destinationUrl.path!, error:nil)
+ }
+ }
+ task.resume()
+ }
+}
diff --git a/ios/Classes/InAppWebViewOptions.swift b/ios/Classes/InAppWebViewOptions.swift
index dfaf0eb3..788dd545 100755
--- a/ios/Classes/InAppWebViewOptions.swift
+++ b/ios/Classes/InAppWebViewOptions.swift
@@ -17,6 +17,8 @@ public class InAppWebViewOptions: Options {
var javaScriptEnabled = true
var javaScriptCanOpenWindowsAutomatically = false
var mediaPlaybackRequiresUserGesture = true
+ var verticalScrollBarEnabled = true
+ var horizontalScrollBarEnabled = true
var disallowOverScroll = false
var enableViewportScale = false
diff --git a/pubspec.yaml b/pubspec.yaml
index 45307837..917ddbaf 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: 1.2.1
+description: A Flutter plugin that allows you to add an inline webview or open an in-app browser window.
+version: 1.3.0
author: Lorenzo Pichilli
homepage: https://github.com/pichillilorenzo/flutter_inappbrowser