) call.argument("headers"), result);
+ break;
case "close":
- close(uuid);
- result.success(true);
+ close(uuid, result);
break;
case "injectScriptCode":
source = call.argument("source").toString();
@@ -237,18 +255,19 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
/**
* Inject an object (script or style) into the InAppBrowserFlutterPlugin WebView.
- *
+ *
* This is a helper method for the inject{Script|Style}{Code|File} API calls, which
* provides a consistent method for injecting JavaScript code into the document.
- *
+ *
* If a wrapper string is supplied, then the source string will be JSON-encoded (adding
* quotes) and wrapped using string formatting. (The wrapper string should have a single
* '%s' marker)
+ *
* @param uuid
- * @param source The source object (filename or script/style text) to inject into
- * the document.
- * @param jsWrapper A JavaScript string to wrap the source string in, so that the object
- * is properly injected, or null if the source string is JavaScript text
+ * @param source The source object (filename or script/style text) to inject into
+ * the document.
+ * @param jsWrapper A JavaScript string to wrap the source string in, so that the object
+ * is properly injected, or null if the source string is JavaScript text
* @param result
*/
private void injectDeferredObject(String uuid, String source, String jsWrapper, final Result result) {
@@ -259,7 +278,7 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
org.json.JSONArray jsonEsc = new org.json.JSONArray();
jsonEsc.put(source);
String jsonRepr = jsonEsc.toString();
- String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
+ String jsonSourceString = jsonRepr.substring(1, jsonRepr.length() - 1);
scriptToInject = String.format(jsWrapper, jsonSourceString);
} else {
scriptToInject = source;
@@ -295,8 +314,7 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
msg = reader2.nextString();
result.success(msg);
- }
- else {
+ } else {
result.success("");
}
@@ -332,9 +350,10 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
* Display a new browser with the specified URL.
*
* @param url the url to load.
+ * @param result
* @return "" if ok, or error message.
*/
- public void openExternal(String url) {
+ public void openExternal(String url, Result result) {
try {
Intent intent;
intent = new Intent(Intent.ACTION_VIEW);
@@ -349,9 +368,11 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName());
// CB-10795: Avoid circular loops by preventing it from opening in the current app
this.openExternalExcludeCurrentApp(intent);
+ result.success(true);
// not catching FileUriExposedException explicitly because buildtools<24 doesn't know about it
} catch (java.lang.RuntimeException e) {
- Log.d(LOG_TAG, "InAppBrowserFlutterPlugin: Error loading url "+url+":"+ e.toString());
+ Log.d(LOG_TAG, url + " cannot be opened: " + e.toString());
+ result.error(LOG_TAG, url + " cannot be opened!", null);
}
}
@@ -367,11 +388,10 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
ArrayList targetIntents = new ArrayList();
for (ResolveInfo ri : activities) {
if (!currentPackage.equals(ri.activityInfo.packageName)) {
- Intent targetIntent = (Intent)intent.clone();
+ Intent targetIntent = (Intent) intent.clone();
targetIntent.setPackage(ri.activityInfo.packageName);
targetIntents.add(targetIntent);
- }
- else {
+ } else {
hasCurrentPackage = true;
}
}
@@ -386,35 +406,57 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
}
// Otherwise, show a custom chooser without the current app listed
else if (targetIntents.size() > 0) {
- Intent chooser = Intent.createChooser(targetIntents.remove(targetIntents.size()-1), null);
- chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[] {}));
+ Intent chooser = Intent.createChooser(targetIntents.remove(targetIntents.size() - 1), null);
+ chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{}));
activity.startActivity(chooser);
}
}
- public static void open(String uuid, String uuidFallback, final String url, Options options, Map headers, boolean useChromeSafariBrowser, InAppBrowserOptions optionsFallback) {
- Intent intent = new Intent(registrar.activity(), (useChromeSafariBrowser) ? ChromeCustomTabsActivity.class : WebViewActivity.class);
+ public void open(String uuid, String uuidFallback, String url, Options options, Map headers, boolean useChromeSafariBrowser, InAppBrowserOptions optionsFallback, Result result) {
+ Intent intent = null;
Bundle extras = new Bundle();
- extras.putString("uuid", uuid);
extras.putString("url", url);
+
+ extras.putString("uuid", uuid);
extras.putSerializable("options", options.getHashMap());
extras.putSerializable("headers", (Serializable) headers);
- if (useChromeSafariBrowser) {
- extras.putString("uuidFallback", uuidFallback);
+
+ if (useChromeSafariBrowser && CustomTabActivityHelper.isAvailable(activity)) {
+ intent = new Intent(activity, ChromeCustomTabsActivity.class);
+ }
+ // check for webview fallback
+ else if (useChromeSafariBrowser && !CustomTabActivityHelper.isAvailable(activity) && !uuidFallback.isEmpty()) {
+ Log.d(LOG_TAG, "WebView fallback declared.");
+ // overwrite with extras fallback parameters
+ extras.putString("uuid", uuidFallback);
if (optionsFallback != null)
- extras.putSerializable("optionsFallback", optionsFallback.getHashMap());
+ extras.putSerializable("options", optionsFallback.getHashMap());
else
- extras.putSerializable("optionsFallback", (new InAppBrowserOptions()).getHashMap());
+ extras.putSerializable("options", (new InAppBrowserOptions()).getHashMap());
+ extras.putSerializable("headers", (Serializable) headers);
+ intent = new Intent(activity, WebViewActivity.class);
+ }
+ // native webview
+ else if (!useChromeSafariBrowser) {
+ intent = new Intent(activity, WebViewActivity.class);
+ }
+ else {
+ Log.d(LOG_TAG, "No WebView fallback declared.");
}
- intent.putExtras(extras);
+ if (intent != null) {
+ intent.putExtras(extras);
+ activity.startActivity(intent);
+ result.success(true);
+ return;
+ }
- registrar.activity().startActivity(intent);
+ result.error(LOG_TAG, "No WebView fallback declared.", null);
}
public void loadUrl(String uuid, String url, Map headers, Result result) {
- WebViewActivity webViewActivity = webViewActivities.get(uuid);
+ WebViewActivity webViewActivity = webViewActivities.get(uuid);
if (webViewActivity != null) {
if (headers != null)
webViewActivity.loadUrl(url, headers, result);
@@ -423,6 +465,16 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
}
}
+ public void loadFile(String uuid, String url, Map headers, Result result) {
+ WebViewActivity webViewActivity = webViewActivities.get(uuid);
+ if (webViewActivity != null) {
+ if (headers != null)
+ webViewActivity.loadFile(url, headers, result);
+ else
+ webViewActivity.loadFile(url, result);
+ }
+ }
+
public void show(String uuid) {
WebViewActivity webViewActivity = webViewActivities.get(uuid);
if (webViewActivity != null)
@@ -488,7 +540,7 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
}
- public static void close(final String uuid) {
+ public static void close(final String uuid, final Result result) {
final WebViewActivity webViewActivity = webViewActivities.get(uuid);
if (webViewActivity != null) {
registrar.activity().runOnUiThread(new Runnable() {
@@ -501,8 +553,12 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
// The JS protects against multiple calls, so this should happen only when
// close() is called by other native code.
- if (webViewActivity == null)
+ if (webViewActivity == null) {
+ if (result != null) {
+ result.success(true);
+ }
return;
+ }
webViewActivity.webView.setWebViewClient(new WebViewClient() {
// NB: wait for about:blank before dismissing
@@ -514,8 +570,14 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
// other than your app's UI thread, it can cause unexpected results."
// http://developer.android.com/guide/webapps/migrating.html#Threads
webViewActivity.webView.loadUrl("about:blank");
+ if (result != null) {
+ result.success(true);
+ }
}
});
}
+ else if (result != null) {
+ result.success(true);
+ }
}
}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java
index 08101acb..ec33f116 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java
@@ -2,29 +2,31 @@ package com.pichillilorenzo.flutter_inappbrowser;
public class InAppBrowserOptions extends Options {
- final static String LOG_TAG = "InAppBrowserOptions";
+ static final String LOG_TAG = "InAppBrowserOptions";
- public boolean useShouldOverrideUrlLoading = false;
- public boolean useOnLoadResource = false;
- public boolean clearCache = false;
- public String userAgent = "";
- public boolean javaScriptEnabled = true;
- public boolean javaScriptCanOpenWindowsAutomatically = false;
- public boolean hidden = false;
- public boolean toolbarTop = true;
- public String toolbarTopBackgroundColor = "";
- public String toolbarTopFixedTitle = "";
- public boolean hideUrlBar = false;
- public boolean mediaPlaybackRequiresUserGesture = true;
+ public boolean useShouldOverrideUrlLoading = false;
+ public boolean useOnLoadResource = false;
+ public boolean openWithSystemBrowser = false;
+ public boolean clearCache = false;
+ public String userAgent = "";
+ public boolean javaScriptEnabled = true;
+ public boolean javaScriptCanOpenWindowsAutomatically = false;
+ public boolean hidden = false;
+ public boolean toolbarTop = true;
+ public String toolbarTopBackgroundColor = "";
+ public String toolbarTopFixedTitle = "";
+ public boolean hideUrlBar = false;
+ public boolean mediaPlaybackRequiresUserGesture = true;
+ public boolean isLocalFile = false;
- public boolean hideTitleBar = false;
- public boolean closeOnCannotGoBack = true;
- public boolean clearSessionCache = false;
- public boolean builtInZoomControls = false;
- public boolean supportZoom = true;
- public boolean databaseEnabled = false;
- public boolean domStorageEnabled = false;
- public boolean useWideViewPort = true;
- public boolean safeBrowsingEnabled = true;
- public boolean progressBar = true;
+ public boolean hideTitleBar = false;
+ public boolean closeOnCannotGoBack = true;
+ public boolean clearSessionCache = false;
+ public boolean builtInZoomControls = false;
+ public boolean supportZoom = true;
+ public boolean databaseEnabled = false;
+ public boolean domStorageEnabled = false;
+ public boolean useWideViewPort = true;
+ public boolean safeBrowsingEnabled = true;
+ public boolean progressBar = true;
}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebChromeClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebChromeClient.java
index fbb2872d..d940b64b 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebChromeClient.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebChromeClient.java
@@ -16,112 +16,111 @@ import java.util.Map;
public class InAppBrowserWebChromeClient extends WebChromeClient {
- protected static final String LOG_TAG = "IABWebChromeClient";
- private WebViewActivity activity;
- private ValueCallback mUploadMessageArray;
- private ValueCallback mUploadMessage;
- private final static int FILECHOOSER_RESULTCODE=1;
+ protected static final String LOG_TAG = "IABWebChromeClient";
+ private WebViewActivity activity;
+ private ValueCallback mUploadMessageArray;
+ private ValueCallback mUploadMessage;
+ private final static int FILECHOOSER_RESULTCODE = 1;
- public InAppBrowserWebChromeClient(WebViewActivity activity) {
- super();
- this.activity = activity;
+ public InAppBrowserWebChromeClient(WebViewActivity activity) {
+ super();
+ this.activity = activity;
+ }
+
+ @Override
+ public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
+ Map obj = new HashMap<>();
+ obj.put("uuid", activity.uuid);
+ obj.put("sourceURL", consoleMessage.sourceId());
+ obj.put("lineNumber", consoleMessage.lineNumber());
+ obj.put("message", consoleMessage.message());
+ obj.put("messageLevel", consoleMessage.messageLevel().toString());
+ InAppBrowserFlutterPlugin.channel.invokeMethod("onConsoleMessage", obj);
+ return true;
+ }
+
+ @Override
+ public void onProgressChanged(WebView view, int progress) {
+ if (activity.progressBar != null) {
+ activity.progressBar.setVisibility(View.VISIBLE);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ activity.progressBar.setProgress(progress, true);
+ } else {
+ activity.progressBar.setProgress(progress);
+ }
+ if (progress == 100) {
+ activity.progressBar.setVisibility(View.GONE);
+ }
}
+ super.onProgressChanged(view, progress);
+ }
- @Override
- public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
- Map obj = new HashMap<>();
- obj.put("uuid", activity.uuid);
- obj.put("sourceURL", consoleMessage.sourceId());
- obj.put("lineNumber", consoleMessage.lineNumber());
- obj.put("message", consoleMessage.message());
- obj.put("messageLevel", consoleMessage.messageLevel().toString());
- InAppBrowserFlutterPlugin.channel.invokeMethod("onConsoleMessage", obj);
- return true;
+ @Override
+ public void onReceivedTitle(WebView view, String title) {
+ super.onReceivedTitle(view, title);
+ if (activity.actionBar != null && activity.options.toolbarTopFixedTitle.isEmpty())
+ activity.actionBar.setTitle(title);
+ }
+
+ @Override
+ public void onReceivedIcon(WebView view, Bitmap icon) {
+ super.onReceivedIcon(view, icon);
+ }
+
+ //The undocumented magic method override
+ //Eclipse will swear at you if you try to put @Override here
+ // For Android 3.0+
+ public void openFileChooser(ValueCallback uploadMsg) {
+
+ mUploadMessage = uploadMsg;
+ Intent i = new Intent(Intent.ACTION_GET_CONTENT);
+ i.addCategory(Intent.CATEGORY_OPENABLE);
+ i.setType("image/*");
+ activity.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
+
+ }
+
+ // For Android 3.0+
+ public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
+ mUploadMessage = uploadMsg;
+ Intent i = new Intent(Intent.ACTION_GET_CONTENT);
+ i.addCategory(Intent.CATEGORY_OPENABLE);
+ i.setType("*/*");
+ activity.startActivityForResult(
+ Intent.createChooser(i, "File Browser"),
+ FILECHOOSER_RESULTCODE);
+ }
+
+ //For Android 4.1
+ public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) {
+ mUploadMessage = uploadMsg;
+ Intent i = new Intent(Intent.ACTION_GET_CONTENT);
+ i.addCategory(Intent.CATEGORY_OPENABLE);
+ i.setType("image/*");
+ activity.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
+
+ }
+
+ //For Android 5.0+
+ public boolean onShowFileChooser(
+ WebView webView, ValueCallback filePathCallback,
+ FileChooserParams fileChooserParams) {
+ if (mUploadMessageArray != null) {
+ mUploadMessageArray.onReceiveValue(null);
}
+ mUploadMessageArray = filePathCallback;
- @Override
- public void onProgressChanged(WebView view, int progress) {
- if (activity.progressBar != null) {
- activity.progressBar.setVisibility(View.VISIBLE);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- activity.progressBar.setProgress(progress, true);
- }
- else {
- activity.progressBar.setProgress(progress);
- }
- if (progress == 100) {
- activity.progressBar.setVisibility(View.GONE);
- }
- }
- super.onProgressChanged(view, progress);
- }
+ Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
+ contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
+ contentSelectionIntent.setType("*/*");
+ Intent[] intentArray;
+ intentArray = new Intent[0];
- @Override
- public void onReceivedTitle(WebView view, String title) {
- super.onReceivedTitle(view, title);
- if (activity.actionBar != null && activity.options.toolbarTopFixedTitle.isEmpty())
- activity.actionBar.setTitle(title);
- }
-
- @Override
- public void onReceivedIcon(WebView view, Bitmap icon) {
- super.onReceivedIcon(view, icon);
- }
-
- //The undocumented magic method override
- //Eclipse will swear at you if you try to put @Override here
- // For Android 3.0+
- public void openFileChooser(ValueCallback uploadMsg) {
-
- mUploadMessage = uploadMsg;
- Intent i = new Intent(Intent.ACTION_GET_CONTENT);
- i.addCategory(Intent.CATEGORY_OPENABLE);
- i.setType("image/*");
- activity.startActivityForResult(Intent.createChooser(i,"File Chooser"), FILECHOOSER_RESULTCODE);
-
- }
-
- // For Android 3.0+
- public void openFileChooser( ValueCallback uploadMsg, String acceptType ) {
- mUploadMessage = uploadMsg;
- Intent i = new Intent(Intent.ACTION_GET_CONTENT);
- i.addCategory(Intent.CATEGORY_OPENABLE);
- i.setType("*/*");
- activity.startActivityForResult(
- Intent.createChooser(i, "File Browser"),
- FILECHOOSER_RESULTCODE);
- }
-
- //For Android 4.1
- public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture){
- mUploadMessage = uploadMsg;
- Intent i = new Intent(Intent.ACTION_GET_CONTENT);
- i.addCategory(Intent.CATEGORY_OPENABLE);
- i.setType("image/*");
- activity.startActivityForResult( Intent.createChooser( i, "File Chooser" ), FILECHOOSER_RESULTCODE );
-
- }
-
- //For Android 5.0+
- public boolean onShowFileChooser(
- WebView webView, ValueCallback filePathCallback,
- FileChooserParams fileChooserParams){
- if(mUploadMessageArray != null){
- mUploadMessageArray.onReceiveValue(null);
- }
- mUploadMessageArray = filePathCallback;
-
- Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
- contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
- contentSelectionIntent.setType("*/*");
- Intent[] intentArray;
- intentArray = new Intent[0];
-
- Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
- chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
- chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
- chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
- activity.startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
- return true;
- }
+ Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
+ chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
+ chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
+ chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
+ activity.startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
+ return true;
+ }
}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.java
index 1e4e44e9..6594b99c 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.java
@@ -23,337 +23,341 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import io.flutter.plugin.common.MethodChannel;
import okhttp3.Request;
import okhttp3.Response;
public class InAppBrowserWebViewClient extends WebViewClient {
- protected static final String LOG_TAG = "IABWebViewClient";
- private WebViewActivity activity;
- Map statusCodeMapping = new HashMap();
- long startPageTime = 0;
+ protected static final String LOG_TAG = "IABWebViewClient";
+ private WebViewActivity activity;
+ Map statusCodeMapping = new HashMap();
+ long startPageTime = 0;
- public InAppBrowserWebViewClient(WebViewActivity activity) {
- super();
- this.activity = activity;
- statusCodeMapping.put(100, "Continue");
- statusCodeMapping.put(101, "Switching Protocols");
- statusCodeMapping.put(200, "OK");
- statusCodeMapping.put(201, "Created");
- statusCodeMapping.put(202, "Accepted");
- statusCodeMapping.put(203, "Non-Authoritative Information");
- statusCodeMapping.put(204, "No Content");
- statusCodeMapping.put(205, "Reset Content");
- statusCodeMapping.put(206, "Partial Content");
- statusCodeMapping.put(300, "Multiple Choices");
- statusCodeMapping.put(301, "Moved Permanently");
- statusCodeMapping.put(302, "Found");
- statusCodeMapping.put(303, "See Other");
- statusCodeMapping.put(304, "Not Modified");
- statusCodeMapping.put(307, "Temporary Redirect");
- statusCodeMapping.put(308, "Permanent Redirect");
- statusCodeMapping.put(400, "Bad Request");
- statusCodeMapping.put(401, "Unauthorized");
- statusCodeMapping.put(403, "Forbidden");
- statusCodeMapping.put(404, "Not Found");
- statusCodeMapping.put(405, "Method Not Allowed");
- statusCodeMapping.put(406, "Not Acceptable");
- statusCodeMapping.put(407, "Proxy Authentication Required");
- statusCodeMapping.put(408, "Request Timeout");
- statusCodeMapping.put(409, "Conflict");
- statusCodeMapping.put(410, "Gone");
- statusCodeMapping.put(411, "Length Required");
- statusCodeMapping.put(412, "Precondition Failed");
- statusCodeMapping.put(413, "Payload Too Large");
- statusCodeMapping.put(414, "URI Too Long");
- statusCodeMapping.put(415, "Unsupported Media Type");
- statusCodeMapping.put(416, "Range Not Satisfiable");
- statusCodeMapping.put(417, "Expectation Failed");
- statusCodeMapping.put(418, "I'm a teapot");
- statusCodeMapping.put(422, "Unprocessable Entity");
- statusCodeMapping.put(425, "Too Early");
- statusCodeMapping.put(426, "Upgrade Required");
- statusCodeMapping.put(428, "Precondition Required");
- statusCodeMapping.put(429, "Too Many Requests");
- statusCodeMapping.put(431, "Request Header Fields Too Large");
- statusCodeMapping.put(451, "Unavailable For Legal Reasons");
- statusCodeMapping.put(500, "Internal Server Error");
- statusCodeMapping.put(501, "Not Implemented");
- statusCodeMapping.put(502, "Bad Gateway");
- statusCodeMapping.put(503, "Service Unavailable");
- statusCodeMapping.put(504, "Gateway Timeout");
- statusCodeMapping.put(505, "HTTP Version Not Supported");
- statusCodeMapping.put(511, "Network Authentication Required");
+ public InAppBrowserWebViewClient(WebViewActivity activity) {
+ super();
+ this.activity = activity;
+ statusCodeMapping.put(100, "Continue");
+ statusCodeMapping.put(101, "Switching Protocols");
+ statusCodeMapping.put(200, "OK");
+ statusCodeMapping.put(201, "Created");
+ statusCodeMapping.put(202, "Accepted");
+ statusCodeMapping.put(203, "Non-Authoritative Information");
+ statusCodeMapping.put(204, "No Content");
+ statusCodeMapping.put(205, "Reset Content");
+ statusCodeMapping.put(206, "Partial Content");
+ statusCodeMapping.put(300, "Multiple Choices");
+ statusCodeMapping.put(301, "Moved Permanently");
+ statusCodeMapping.put(302, "Found");
+ statusCodeMapping.put(303, "See Other");
+ statusCodeMapping.put(304, "Not Modified");
+ statusCodeMapping.put(307, "Temporary Redirect");
+ statusCodeMapping.put(308, "Permanent Redirect");
+ statusCodeMapping.put(400, "Bad Request");
+ statusCodeMapping.put(401, "Unauthorized");
+ statusCodeMapping.put(403, "Forbidden");
+ statusCodeMapping.put(404, "Not Found");
+ statusCodeMapping.put(405, "Method Not Allowed");
+ statusCodeMapping.put(406, "Not Acceptable");
+ statusCodeMapping.put(407, "Proxy Authentication Required");
+ statusCodeMapping.put(408, "Request Timeout");
+ statusCodeMapping.put(409, "Conflict");
+ statusCodeMapping.put(410, "Gone");
+ statusCodeMapping.put(411, "Length Required");
+ statusCodeMapping.put(412, "Precondition Failed");
+ statusCodeMapping.put(413, "Payload Too Large");
+ statusCodeMapping.put(414, "URI Too Long");
+ statusCodeMapping.put(415, "Unsupported Media Type");
+ statusCodeMapping.put(416, "Range Not Satisfiable");
+ statusCodeMapping.put(417, "Expectation Failed");
+ statusCodeMapping.put(418, "I'm a teapot");
+ statusCodeMapping.put(422, "Unprocessable Entity");
+ statusCodeMapping.put(425, "Too Early");
+ statusCodeMapping.put(426, "Upgrade Required");
+ statusCodeMapping.put(428, "Precondition Required");
+ statusCodeMapping.put(429, "Too Many Requests");
+ statusCodeMapping.put(431, "Request Header Fields Too Large");
+ statusCodeMapping.put(451, "Unavailable For Legal Reasons");
+ statusCodeMapping.put(500, "Internal Server Error");
+ statusCodeMapping.put(501, "Not Implemented");
+ statusCodeMapping.put(502, "Bad Gateway");
+ statusCodeMapping.put(503, "Service Unavailable");
+ statusCodeMapping.put(504, "Gateway Timeout");
+ statusCodeMapping.put(505, "HTTP Version Not Supported");
+ statusCodeMapping.put(511, "Network Authentication Required");
+ }
+
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView webView, String url) {
+
+ if (activity.options.useShouldOverrideUrlLoading) {
+ Map obj = new HashMap<>();
+ obj.put("uuid", activity.uuid);
+ obj.put("url", url);
+ InAppBrowserFlutterPlugin.channel.invokeMethod("shouldOverrideUrlLoading", obj);
+ return true;
}
- @Override
- public boolean shouldOverrideUrlLoading(WebView webView, String url) {
-
- if (activity.options.useShouldOverrideUrlLoading) {
- Map obj = new HashMap<>();
- obj.put("uuid", activity.uuid);
- obj.put("url", url);
- InAppBrowserFlutterPlugin.channel.invokeMethod("shouldOverrideUrlLoading", obj);
- return true;
- }
-
- if (url.startsWith(WebView.SCHEME_TEL)) {
- try {
- Intent intent = new Intent(Intent.ACTION_DIAL);
- intent.setData(Uri.parse(url));
- activity.startActivity(intent);
- return true;
- } catch (android.content.ActivityNotFoundException e) {
- Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
- }
- }
- else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:") || url.startsWith("intent:")) {
- try {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- activity.startActivity(intent);
- return true;
- } catch (android.content.ActivityNotFoundException e) {
- Log.e(LOG_TAG, "Error with " + url + ": " + e.toString());
- }
- }
- // If sms:5551212?body=This is the message
- else if (url.startsWith("sms:")) {
- try {
- Intent intent = new Intent(Intent.ACTION_VIEW);
-
- // Get address
- String address;
- int parmIndex = url.indexOf('?');
- if (parmIndex == -1) {
- address = url.substring(4);
- } else {
- address = url.substring(4, parmIndex);
-
- // If body, then set sms body
- Uri uri = Uri.parse(url);
- String query = uri.getQuery();
- if (query != null) {
- if (query.startsWith("body=")) {
- intent.putExtra("sms_body", query.substring(5));
- }
- }
- }
- intent.setData(Uri.parse("sms:" + address));
- intent.putExtra("address", address);
- intent.setType("vnd.android-dir/mms-sms");
- activity.startActivity(intent);
- return true;
- } catch (android.content.ActivityNotFoundException e) {
- Log.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
- }
- }
-
- return super.shouldOverrideUrlLoading(webView, url);
-
+ if (url.startsWith(WebView.SCHEME_TEL)) {
+ try {
+ Intent intent = new Intent(Intent.ACTION_DIAL);
+ intent.setData(Uri.parse(url));
+ activity.startActivity(intent);
+ return true;
+ } catch (android.content.ActivityNotFoundException e) {
+ Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
+ }
+ } else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:") || url.startsWith("intent:")) {
+ try {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(url));
+ activity.startActivity(intent);
+ return true;
+ } catch (android.content.ActivityNotFoundException e) {
+ Log.e(LOG_TAG, "Error with " + url + ": " + e.toString());
+ }
}
+ // If sms:5551212?body=This is the message
+ else if (url.startsWith("sms:")) {
+ try {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
-
- /*
- * onPageStarted fires the LOAD_START_EVENT
- *
- * @param view
- * @param url
- * @param favicon
- */
- @Override
- public void onPageStarted(WebView view, String url, Bitmap favicon) {
- super.onPageStarted(view, url, favicon);
-
- startPageTime = System.currentTimeMillis();
-
- activity.isLoading = true;
-
- if (activity.searchView != null && !url.equals(activity.searchView.getQuery().toString())) {
- activity.searchView.setQuery(url, false);
- }
-
- Map obj = new HashMap<>();
- obj.put("uuid", activity.uuid);
- obj.put("url", url);
- InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadStart", obj);
- }
-
-
-
- public void onPageFinished(WebView view, String url) {
- super.onPageFinished(view, url);
-
- activity.isLoading = false;
-
- // CB-10395 InAppBrowserFlutterPlugin's WebView not storing cookies reliable to local device storage
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- CookieManager.getInstance().flush();
+ // Get address
+ String address;
+ int parmIndex = url.indexOf('?');
+ if (parmIndex == -1) {
+ address = url.substring(4);
} else {
- CookieSyncManager.getInstance().sync();
- }
+ address = url.substring(4, parmIndex);
- // https://issues.apache.org/jira/browse/CB-11248
- view.clearFocus();
- view.requestFocus();
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- view.evaluateJavascript(WebViewActivity.consoleLogJS, null);
- view.evaluateJavascript(JavaScriptBridgeInterface.flutterInAppBroserJSClass, null);
- }
-
- Map obj = new HashMap<>();
- obj.put("uuid", activity.uuid);
- obj.put("url", url);
- InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadStop", obj);
- }
-
- public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
- super.onReceivedError(view, errorCode, description, failingUrl);
-
- activity.isLoading = false;
-
- Map obj = new HashMap<>();
- obj.put("uuid", activity.uuid);
- obj.put("url", failingUrl);
- obj.put("code", errorCode);
- obj.put("message", description);
- InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadError", obj);
- }
-
- public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) {
- super.onReceivedSslError(view, handler, error);
-
- Map obj = new HashMap<>();
- obj.put("uuid", activity.uuid);
- obj.put("url", error.getUrl());
- obj.put("code", error.getPrimaryError());
- String message;
- switch (error.getPrimaryError()) {
- case SslError.SSL_DATE_INVALID:
- message = "The date of the certificate is invalid";
- break;
- case SslError.SSL_EXPIRED:
- message = "The certificate has expired";
- break;
- case SslError.SSL_IDMISMATCH:
- message = "Hostname mismatch";
- break;
- default:
- case SslError.SSL_INVALID:
- message = "A generic error occurred";
- break;
- case SslError.SSL_NOTYETVALID:
- message = "The certificate is not yet valid";
- break;
- case SslError.SSL_UNTRUSTED:
- message = "The certificate authority is not trusted";
- break;
- }
- obj.put("message", "SslError: " + message);
- InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadError", obj);
-
- handler.cancel();
- }
-
- /**
- * On received http auth request.
- */
- @Override
- public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
- // By default handle 401 like we'd normally do!
- super.onReceivedHttpAuthRequest(view, handler, host, realm);
- }
-
- @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
- @Override
- public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request){
-
- if (!request.getMethod().toLowerCase().equals("get") || !activity.options.useOnLoadResource) {
- return null;
- }
-
- final String url = request.getUrl().toString();
-
- try {
- Request mRequest = new Request.Builder().url(url).build();
-
- long startResourceTime = System.currentTimeMillis();
- Response response = activity.httpClient.newCall(mRequest).execute();
- long startTime = startResourceTime - startPageTime;
- long duration = System.currentTimeMillis() - startResourceTime;
-
- if (response.cacheResponse() != null) {
- duration = 0;
+ // If body, then set sms body
+ Uri uri = Uri.parse(url);
+ String query = uri.getQuery();
+ if (query != null) {
+ if (query.startsWith("body=")) {
+ intent.putExtra("sms_body", query.substring(5));
}
-
- String reasonPhrase = response.message();
- if (reasonPhrase.equals("")) {
- reasonPhrase = statusCodeMapping.get(response.code());
- }
- reasonPhrase = (reasonPhrase.equals("") || reasonPhrase == null) ? "OK" : reasonPhrase;
-
- Map headersResponse = new HashMap();
- for (Map.Entry> entry : response.headers().toMultimap().entrySet()) {
- StringBuilder value = new StringBuilder();
- for (String val: entry.getValue()) {
- value.append( (value.toString().isEmpty()) ? val : "; " + val );
- }
- headersResponse.put(entry.getKey().toLowerCase(), value.toString());
- }
-
- Map headersRequest = new HashMap();
- for (Map.Entry> entry : mRequest.headers().toMultimap().entrySet()) {
- StringBuilder value = new StringBuilder();
- for (String val: entry.getValue()) {
- value.append( (value.toString().isEmpty()) ? val : "; " + val );
- }
- headersRequest.put(entry.getKey().toLowerCase(), value.toString());
- }
-
- Map obj = new HashMap<>();
- Map res = new HashMap<>();
- Map req = new HashMap<>();
-
- obj.put("uuid", activity.uuid);
-
- byte[] dataBytes = response.body().bytes();
- InputStream dataStream = new ByteArrayInputStream(dataBytes);
-
- res.put("url", url);
- res.put("statusCode", response.code());
- res.put("headers", headersResponse);
- res.put("startTime", startTime);
- res.put("duration", duration);
- res.put("data", dataBytes);
-
- req.put("url", url);
- req.put("headers", headersRequest);
- req.put("method", mRequest.method());
-
- obj.put("response", res);
- obj.put("request", req);
-
- InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadResource", obj);
-
- return new WebResourceResponse(
- response.header("content-type", "text/plain").split(";")[0].trim(),
- response.header("content-encoding"),
- response.code(),
- reasonPhrase,
- headersResponse,
- dataStream
- );
- } catch (IOException e) {
- e.printStackTrace();
- Log.d(LOG_TAG, e.getMessage());
- } catch (Exception e) {
- e.printStackTrace();
- Log.d(LOG_TAG, e.getMessage());
+ }
}
-
- return null;
+ intent.setData(Uri.parse("sms:" + address));
+ intent.putExtra("address", address);
+ intent.setType("vnd.android-dir/mms-sms");
+ activity.startActivity(intent);
+ return true;
+ } catch (android.content.ActivityNotFoundException e) {
+ Log.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
+ }
}
+ return super.shouldOverrideUrlLoading(webView, url);
+
+ }
+
+
+ /*
+ * onPageStarted fires the LOAD_START_EVENT
+ *
+ * @param view
+ * @param url
+ * @param favicon
+ */
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ super.onPageStarted(view, url, favicon);
+
+ startPageTime = System.currentTimeMillis();
+
+ activity.isLoading = true;
+
+ if (activity.searchView != null && !url.equals(activity.searchView.getQuery().toString())) {
+ activity.searchView.setQuery(url, false);
+ }
+
+ Map obj = new HashMap<>();
+ obj.put("uuid", activity.uuid);
+ obj.put("url", url);
+ InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadStart", obj);
+ }
+
+
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+
+ activity.isLoading = false;
+
+ // CB-10395 InAppBrowserFlutterPlugin's WebView not storing cookies reliable to local device storage
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ CookieManager.getInstance().flush();
+ } else {
+ CookieSyncManager.getInstance().sync();
+ }
+
+ // https://issues.apache.org/jira/browse/CB-11248
+ view.clearFocus();
+ view.requestFocus();
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ view.evaluateJavascript(WebViewActivity.consoleLogJS, null);
+ view.evaluateJavascript(JavaScriptBridgeInterface.flutterInAppBroserJSClass, null);
+ }
+ else {
+ view.loadUrl("javascript:"+WebViewActivity.consoleLogJS);
+ view.loadUrl("javascript:"+JavaScriptBridgeInterface.flutterInAppBroserJSClass);
+ }
+
+ Map obj = new HashMap<>();
+ obj.put("uuid", activity.uuid);
+ obj.put("url", url);
+ InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadStop", obj);
+ }
+
+ public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+ super.onReceivedError(view, errorCode, description, failingUrl);
+
+ activity.isLoading = false;
+
+ Map obj = new HashMap<>();
+ obj.put("uuid", activity.uuid);
+ obj.put("url", failingUrl);
+ obj.put("code", errorCode);
+ obj.put("message", description);
+ InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadError", obj);
+ }
+
+ public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+ super.onReceivedSslError(view, handler, error);
+
+ Map obj = new HashMap<>();
+ obj.put("uuid", activity.uuid);
+ obj.put("url", error.getUrl());
+ obj.put("code", error.getPrimaryError());
+ String message;
+ switch (error.getPrimaryError()) {
+ case SslError.SSL_DATE_INVALID:
+ message = "The date of the certificate is invalid";
+ break;
+ case SslError.SSL_EXPIRED:
+ message = "The certificate has expired";
+ break;
+ case SslError.SSL_IDMISMATCH:
+ message = "Hostname mismatch";
+ break;
+ default:
+ case SslError.SSL_INVALID:
+ message = "A generic error occurred";
+ break;
+ case SslError.SSL_NOTYETVALID:
+ message = "The certificate is not yet valid";
+ break;
+ case SslError.SSL_UNTRUSTED:
+ message = "The certificate authority is not trusted";
+ break;
+ }
+ obj.put("message", "SslError: " + message);
+ InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadError", obj);
+
+ handler.cancel();
+ }
+
+ /**
+ * On received http auth request.
+ */
+ @Override
+ public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
+ // By default handle 401 like we'd normally do!
+ super.onReceivedHttpAuthRequest(view, handler, host, realm);
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ @Override
+ public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
+
+ if (!request.getMethod().toLowerCase().equals("get") || !activity.options.useOnLoadResource) {
+ return null;
+ }
+
+ final String url = request.getUrl().toString();
+
+ try {
+ Request mRequest = new Request.Builder().url(url).build();
+
+ long startResourceTime = System.currentTimeMillis();
+ Response response = activity.httpClient.newCall(mRequest).execute();
+ long startTime = startResourceTime - startPageTime;
+ startTime = (startTime < 0) ? 0 : startTime;
+ long duration = System.currentTimeMillis() - startResourceTime;
+
+ if (response.cacheResponse() != null) {
+ duration = 0;
+ }
+
+ String reasonPhrase = response.message();
+ if (reasonPhrase.equals("")) {
+ reasonPhrase = statusCodeMapping.get(response.code());
+ }
+ reasonPhrase = (reasonPhrase.equals("") || reasonPhrase == null) ? "OK" : reasonPhrase;
+
+ Map headersResponse = new HashMap();
+ for (Map.Entry> entry : response.headers().toMultimap().entrySet()) {
+ StringBuilder value = new StringBuilder();
+ for (String val : entry.getValue()) {
+ value.append((value.toString().isEmpty()) ? val : "; " + val);
+ }
+ headersResponse.put(entry.getKey().toLowerCase(), value.toString());
+ }
+
+ Map headersRequest = new HashMap();
+ for (Map.Entry> entry : mRequest.headers().toMultimap().entrySet()) {
+ StringBuilder value = new StringBuilder();
+ for (String val : entry.getValue()) {
+ value.append((value.toString().isEmpty()) ? val : "; " + val);
+ }
+ headersRequest.put(entry.getKey().toLowerCase(), value.toString());
+ }
+
+ Map obj = new HashMap<>();
+ Map res = new HashMap<>();
+ Map req = new HashMap<>();
+
+ obj.put("uuid", activity.uuid);
+
+ byte[] dataBytes = response.body().bytes();
+ InputStream dataStream = new ByteArrayInputStream(dataBytes);
+
+ res.put("url", url);
+ res.put("statusCode", response.code());
+ res.put("headers", headersResponse);
+ res.put("startTime", startTime);
+ res.put("duration", duration);
+ res.put("data", dataBytes);
+
+ req.put("url", url);
+ req.put("headers", headersRequest);
+ req.put("method", mRequest.method());
+
+ obj.put("response", res);
+ obj.put("request", req);
+
+ InAppBrowserFlutterPlugin.channel.invokeMethod("onLoadResource", obj);
+
+ return new WebResourceResponse(
+ response.header("content-type", "text/plain").split(";")[0].trim(),
+ response.header("content-encoding"),
+ response.code(),
+ reasonPhrase,
+ headersResponse,
+ dataStream
+ );
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.d(LOG_TAG, e.getMessage());
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.d(LOG_TAG, e.getMessage());
+ }
+
+ return null;
+ }
+
}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/JavaScriptBridgeInterface.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/JavaScriptBridgeInterface.java
index 88117897..ab3aa4a5 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/JavaScriptBridgeInterface.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/JavaScriptBridgeInterface.java
@@ -10,9 +10,9 @@ public class JavaScriptBridgeInterface {
static final String name = "flutter_inappbrowser";
WebViewActivity activity;
- static final String flutterInAppBroserJSClass = "window." + name + ".callHandler = function(handlerName, ...args) {\n" +
- "window." + name + "._callHandler(handlerName, JSON.stringify(args));\n" +
- "}\n";
+ static final String flutterInAppBroserJSClass = "window." + name + ".callHandler = function(handlerName, ...args) {" +
+ "window." + name + "._callHandler(handlerName, JSON.stringify(args));" +
+ "}";
JavaScriptBridgeInterface(WebViewActivity a) {
activity = a;
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/Options.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/Options.java
index a03e03cc..1961f98c 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/Options.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/Options.java
@@ -9,32 +9,33 @@ import java.util.HashMap;
public class Options {
- final static String LOG_TAG = "";
+ static String LOG_TAG = "";
- public void parse(HashMap options) {
- Iterator it = options.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry pair = (Map.Entry)it.next();
- try {
- this.getClass().getDeclaredField(pair.getKey()).set(this, pair.getValue());
- } catch (NoSuchFieldException e) {
- Log.d(LOG_TAG, e.getMessage());
- } catch (IllegalAccessException e) {
- Log.d(LOG_TAG, e.getMessage());
- }
- }
+ public Options parse(HashMap options) {
+ Iterator it = options.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry pair = (Map.Entry) it.next();
+ try {
+ this.getClass().getDeclaredField(pair.getKey()).set(this, pair.getValue());
+ } catch (NoSuchFieldException e) {
+ Log.d(LOG_TAG, e.getMessage());
+ } catch (IllegalAccessException e) {
+ Log.d(LOG_TAG, e.getMessage());
+ }
}
+ return this;
+ }
- public HashMap getHashMap() {
- HashMap options = new HashMap<>();
- for (Field f: this.getClass().getDeclaredFields()) {
- try {
- options.put(f.getName(), f.get(this));
- } catch (IllegalAccessException e) {
- Log.d(LOG_TAG, e.getMessage());
- }
- }
- return options;
+ public HashMap getHashMap() {
+ HashMap options = new HashMap<>();
+ for (Field f : this.getClass().getDeclaredFields()) {
+ try {
+ options.put(f.getName(), f.get(this));
+ } catch (IllegalAccessException e) {
+ Log.d(LOG_TAG, e.getMessage());
+ }
}
+ return options;
+ }
}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java
index 97d859ad..80cb5817 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java
@@ -28,85 +28,85 @@ import okhttp3.OkHttpClient;
public class WebViewActivity extends AppCompatActivity {
- String uuid;
- WebView webView;
- ActionBar actionBar;
- InAppBrowserWebViewClient inAppBrowserWebViewClient;
- InAppBrowserWebChromeClient inAppBrowserWebChromeClient;
- SearchView searchView;
- InAppBrowserOptions options;
- Map headers;
- ProgressBar progressBar;
- public boolean isLoading = false;
- public boolean isHidden = false;
- OkHttpClient httpClient;
+ String uuid;
+ WebView webView;
+ ActionBar actionBar;
+ InAppBrowserWebViewClient inAppBrowserWebViewClient;
+ InAppBrowserWebChromeClient inAppBrowserWebChromeClient;
+ SearchView searchView;
+ InAppBrowserOptions options;
+ Map headers;
+ ProgressBar progressBar;
+ public boolean isLoading = false;
+ public boolean isHidden = false;
+ OkHttpClient httpClient;
- static final String consoleLogJS = "(function() {\n"+
-" var oldLogs = {\n"+
-" 'log': console.log,\n"+
-" 'debug': console.debug,\n"+
-" 'error': console.error,\n"+
-" 'info': console.info,\n"+
-" 'warn': console.warn\n"+
-" };\n"+
-" for (var k in oldLogs) {\n"+
-" (function(oldLog) {\n"+
-" console[oldLog] = function() {\n"+
-" var message = ''\n"+
-" for (var i in arguments) {\n"+
-" if (message == '') {\n"+
-" message += arguments[i];\n"+
-" }\n"+
-" else {\n"+
-" message += ' ' + arguments[i];\n"+
-" }\n"+
-" }\n"+
-" oldLogs[oldLog].call(console, message);\n"+
-" }\n"+
-" })(k);\n"+
-" }\n"+
-"})();";
+ static final String consoleLogJS = "(function() {" +
+ " var oldLogs = {" +
+ " 'log': console.log," +
+ " 'debug': console.debug," +
+ " 'error': console.error," +
+ " 'info': console.info," +
+ " 'warn': console.warn" +
+ " };" +
+ " for (var k in oldLogs) {" +
+ " (function(oldLog) {" +
+ " console[oldLog] = function() {" +
+ " var message = '';" +
+ " for (var i in arguments) {" +
+ " if (message == '') {" +
+ " message += arguments[i];" +
+ " }" +
+ " else {" +
+ " message += ' ' + arguments[i];" +
+ " }" +
+ " }" +
+ " oldLogs[oldLog].call(console, message);" +
+ " }" +
+ " })(k);" +
+ " }" +
+ "})();";
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_web_view);
+ setContentView(R.layout.activity_web_view);
- webView = findViewById(R.id.webView);
+ webView = findViewById(R.id.webView);
- Bundle b = getIntent().getExtras();
- uuid = b.getString("uuid");
- String url = b.getString("url");
+ Bundle b = getIntent().getExtras();
+ uuid = b.getString("uuid");
+ String url = b.getString("url");
- options = new InAppBrowserOptions();
- options.parse((HashMap) b.getSerializable("options"));
+ options = new InAppBrowserOptions();
+ options.parse((HashMap) b.getSerializable("options"));
- headers = (HashMap) b.getSerializable("headers");
+ headers = (HashMap) b.getSerializable("headers");
- InAppBrowserFlutterPlugin.webViewActivities.put(uuid, this);
+ InAppBrowserFlutterPlugin.webViewActivities.put(uuid, this);
- actionBar = getSupportActionBar();
+ actionBar = getSupportActionBar();
- prepareWebView();
+ prepareWebView();
- int cacheSize = 10 * 1024 * 1024; // 10MB
- httpClient = new OkHttpClient().newBuilder().cache(new Cache(getApplicationContext().getCacheDir(), cacheSize)).build();
+ int cacheSize = 10 * 1024 * 1024; // 10MB
+ httpClient = new OkHttpClient().newBuilder().cache(new Cache(getApplicationContext().getCacheDir(), cacheSize)).build();
- webView.loadUrl(url, headers);
- //webView.loadData(" Document ciao ", "text/html", "utf8");
+ webView.loadUrl(url, headers);
+ //webView.loadData(" Document ciao ", "text/assets", "utf8");
- }
+ }
- private void prepareWebView() {
+ private void prepareWebView() {
- webView.addJavascriptInterface(new JavaScriptBridgeInterface(this), JavaScriptBridgeInterface.name);
+ webView.addJavascriptInterface(new JavaScriptBridgeInterface(this), JavaScriptBridgeInterface.name);
- inAppBrowserWebChromeClient = new InAppBrowserWebChromeClient(this);
- webView.setWebChromeClient(inAppBrowserWebChromeClient);
+ inAppBrowserWebChromeClient = new InAppBrowserWebChromeClient(this);
+ webView.setWebChromeClient(inAppBrowserWebChromeClient);
- inAppBrowserWebViewClient = new InAppBrowserWebViewClient(this);
- webView.setWebViewClient(inAppBrowserWebViewClient);
+ inAppBrowserWebViewClient = new InAppBrowserWebViewClient(this);
+ webView.setWebViewClient(inAppBrowserWebViewClient);
// final Activity activity = this;
//
@@ -142,241 +142,256 @@ public class WebViewActivity extends AppCompatActivity {
// }
// });
- WebSettings settings = webView.getSettings();
+ WebSettings settings = webView.getSettings();
- if (options.hidden)
- hide();
- else
- show();
+ if (options.hidden)
+ hide();
+ else
+ show();
- settings.setJavaScriptEnabled(options.javaScriptEnabled);
- settings.setJavaScriptCanOpenWindowsAutomatically(options.javaScriptCanOpenWindowsAutomatically);
- settings.setBuiltInZoomControls(options.builtInZoomControls);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
- settings.setSafeBrowsingEnabled(options.safeBrowsingEnabled);
+ settings.setJavaScriptEnabled(options.javaScriptEnabled);
+ settings.setJavaScriptCanOpenWindowsAutomatically(options.javaScriptCanOpenWindowsAutomatically);
+ settings.setBuiltInZoomControls(options.builtInZoomControls);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
+ settings.setSafeBrowsingEnabled(options.safeBrowsingEnabled);
- settings.setMediaPlaybackRequiresUserGesture(options.mediaPlaybackRequiresUserGesture);
+ settings.setMediaPlaybackRequiresUserGesture(options.mediaPlaybackRequiresUserGesture);
- settings.setDatabaseEnabled(options.databaseEnabled);
- settings.setDomStorageEnabled(options.domStorageEnabled);
+ settings.setDatabaseEnabled(options.databaseEnabled);
+ settings.setDomStorageEnabled(options.domStorageEnabled);
- if (!options.userAgent.isEmpty())
- settings.setUserAgentString(options.userAgent);
+ if (!options.userAgent.isEmpty())
+ settings.setUserAgentString(options.userAgent);
- if (options.clearCache)
- clearCache();
- else if (options.clearSessionCache)
- CookieManager.getInstance().removeSessionCookie();
+ if (options.clearCache)
+ clearCache();
+ else if (options.clearSessionCache)
+ CookieManager.getInstance().removeSessionCookie();
- // Enable Thirdparty Cookies on >=Android 5.0 device
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
- CookieManager.getInstance().setAcceptThirdPartyCookies(webView,true);
+ // Enable Thirdparty Cookies on >=Android 5.0 device
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
+ CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true);
- settings.setLoadWithOverviewMode(true);
- settings.setUseWideViewPort(options.useWideViewPort);
- settings.setSupportZoom(options.supportZoom);
+ settings.setLoadWithOverviewMode(true);
+ settings.setUseWideViewPort(options.useWideViewPort);
+ settings.setSupportZoom(options.supportZoom);
- // fix webview scaling
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
- settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING);
- else
- settings.setTextZoom(100);
+ // fix webview scaling
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
+ settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING);
+ else
+ settings.setTextZoom(100);
- if (options.progressBar)
- progressBar = findViewById(R.id.progressBar);
+ if (options.progressBar)
+ progressBar = findViewById(R.id.progressBar);
- actionBar.setDisplayShowTitleEnabled(!options.hideTitleBar);
+ actionBar.setDisplayShowTitleEnabled(!options.hideTitleBar);
- if (!options.toolbarTop)
- actionBar.hide();
+ if (!options.toolbarTop)
+ actionBar.hide();
- if (!options.toolbarTopBackgroundColor.isEmpty())
- actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor(options.toolbarTopBackgroundColor)));
+ if (!options.toolbarTopBackgroundColor.isEmpty())
+ actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor(options.toolbarTopBackgroundColor)));
- if (!options.toolbarTopFixedTitle.isEmpty())
- actionBar.setTitle(options.toolbarTopFixedTitle);
+ if (!options.toolbarTopFixedTitle.isEmpty())
+ actionBar.setTitle(options.toolbarTopFixedTitle);
- }
+ }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- // Inflate menu to add items to action bar if it is present.
- inflater.inflate(R.menu.menu_main, menu);
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ // Inflate menu to add items to action bar if it is present.
+ inflater.inflate(R.menu.menu_main, menu);
- searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
- searchView.setFocusable(true);
+ searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
+ searchView.setFocusable(true);
- if (options.hideUrlBar)
- menu.findItem(R.id.menu_search).setVisible(false);
+ if (options.hideUrlBar)
+ menu.findItem(R.id.menu_search).setVisible(false);
- searchView.setQuery(webView.getUrl(), false);
+ searchView.setQuery(webView.getUrl(), false);
- if (options.toolbarTopFixedTitle.isEmpty())
- actionBar.setTitle(webView.getTitle());
+ if (options.toolbarTopFixedTitle.isEmpty())
+ actionBar.setTitle(webView.getTitle());
- searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
- @Override
- public boolean onQueryTextSubmit(String query) {
- if (!query.isEmpty()) {
- webView.loadUrl(query);
- searchView.setQuery("", false);
- searchView.setIconified(true);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onQueryTextChange(String newText) {
- return false;
- }
-
- });
-
- searchView.setOnCloseListener(new SearchView.OnCloseListener() {
- @Override
- public boolean onClose() {
- if (searchView.getQuery().toString().isEmpty())
- searchView.setQuery(webView.getUrl(), false);
- return false;
- }
- });
-
- searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View view, boolean b) {
- if (!b) {
- searchView.setQuery("", false);
- searchView.setIconified(true);
- }
- }
- });
-
- return true;
- }
-
- public void loadUrl (String url, MethodChannel.Result result) {
- if (webView != null && !url.isEmpty()) {
- webView.loadUrl(url);
+ searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String query) {
+ if (!query.isEmpty()) {
+ webView.loadUrl(query);
+ searchView.setQuery("", false);
+ searchView.setIconified(true);
+ return true;
}
- else {
- result.error("Cannot load url", "", null);
- }
- }
-
- public void loadUrl (String url, Map headers, MethodChannel.Result result) {
- if (webView != null && !url.isEmpty()) {
- webView.loadUrl(url, headers);
- }
- else {
- result.error("Cannot load url", "", null);
- }
- }
-
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if ((keyCode == KeyEvent.KEYCODE_BACK)) {
- if (canGoBack())
- goBack();
- else if (options.closeOnCannotGoBack)
- InAppBrowserFlutterPlugin.close(uuid);
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
-
- public void close() {
- hide();
- finish();
- }
-
- public void reload() {
- if (webView != null)
- webView.reload();
- }
-
- public void goBack() {
- if (webView != null && canGoBack())
- webView.goBack();
- }
-
- public void goForward() {
- if (webView != null && canGoForward())
- webView.goForward();
- }
-
- public boolean canGoBack() {
- return webView.canGoBack();
- }
-
- public boolean canGoForward() {
- return webView.canGoForward();
- }
-
- public void hide() {
- isHidden = true;
- Intent openActivity = new Intent(this, InAppBrowserFlutterPlugin.registrar.activity().getClass());
- openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
- startActivityIfNeeded(openActivity, 0);
- }
- public void show() {
- isHidden = false;
- Intent openActivity = new Intent(InAppBrowserFlutterPlugin.registrar.activity(), WebViewActivity.class);
- openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
- startActivityIfNeeded(openActivity, 0);
- }
-
- public void stopLoading(){
- if (webView != null)
- webView.stopLoading();
- }
-
- public boolean isLoading() {
- if (webView != null)
- return isLoading;
return false;
- }
+ }
- private void clearCookies() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- CookieManager.getInstance().removeAllCookies(new ValueCallback() {
- @Override
- public void onReceiveValue(Boolean aBoolean) {
+ @Override
+ public boolean onQueryTextChange(String newText) {
+ return false;
+ }
- }
- });
- } else {
- CookieManager.getInstance().removeAllCookie();
+ });
+
+ searchView.setOnCloseListener(new SearchView.OnCloseListener() {
+ @Override
+ public boolean onClose() {
+ if (searchView.getQuery().toString().isEmpty())
+ searchView.setQuery(webView.getUrl(), false);
+ return false;
+ }
+ });
+
+ searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View view, boolean b) {
+ if (!b) {
+ searchView.setQuery("", false);
+ searchView.setIconified(true);
}
- }
+ }
+ });
- private void clearCache() {
- webView.clearCache(true);
- clearCookies();
- webView.clearFormData();
- }
+ return true;
+ }
- public void goBackButtonClicked(MenuItem item) {
+ public void loadUrl(String url, MethodChannel.Result result) {
+ if (webView != null && !url.isEmpty()) {
+ webView.loadUrl(url);
+ } else {
+ result.error("Cannot load url", "", null);
+ }
+ }
+
+ public void loadUrl(String url, Map headers, MethodChannel.Result result) {
+ if (webView != null && !url.isEmpty()) {
+ webView.loadUrl(url, headers);
+ } else {
+ result.error("Cannot load url", "", null);
+ }
+ }
+
+ public void loadFile(String url, MethodChannel.Result result) {
+ if (webView != null && !url.isEmpty()) {
+ webView.loadUrl(url);
+ } else {
+ result.error("Cannot load url", "", null);
+ }
+ }
+
+ public void loadFile(String url, Map headers, MethodChannel.Result result) {
+ if (webView != null && !url.isEmpty()) {
+ webView.loadUrl(url, headers);
+ } else {
+ result.error("Cannot load url", "", null);
+ }
+ }
+
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if ((keyCode == KeyEvent.KEYCODE_BACK)) {
+ if (canGoBack())
goBack();
+ else if (options.closeOnCannotGoBack)
+ InAppBrowserFlutterPlugin.close(uuid, null);
+ return true;
}
+ return super.onKeyDown(keyCode, event);
+ }
- public void goForwardButtonClicked(MenuItem item) {
- goForward();
- }
+ public void close() {
+ hide();
+ finish();
+ }
- public void shareButtonClicked(MenuItem item) {
- Intent share = new Intent(Intent.ACTION_SEND);
- share.setType("text/plain");
- share.putExtra(Intent.EXTRA_TEXT, webView.getUrl());
- startActivity(Intent.createChooser(share, "Share"));
- }
+ public void reload() {
+ if (webView != null)
+ webView.reload();
+ }
- public void reloadButtonClicked(MenuItem item) {
- reload();
- }
+ public void goBack() {
+ if (webView != null && canGoBack())
+ webView.goBack();
+ }
- public void closeButtonClicked(MenuItem item) {
- InAppBrowserFlutterPlugin.close(uuid);
+ public void goForward() {
+ if (webView != null && canGoForward())
+ webView.goForward();
+ }
+
+ public boolean canGoBack() {
+ return webView.canGoBack();
+ }
+
+ public boolean canGoForward() {
+ return webView.canGoForward();
+ }
+
+ public void hide() {
+ isHidden = true;
+ Intent openActivity = new Intent(this, InAppBrowserFlutterPlugin.registrar.activity().getClass());
+ openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+ startActivityIfNeeded(openActivity, 0);
+ }
+
+ public void show() {
+ isHidden = false;
+ Intent openActivity = new Intent(InAppBrowserFlutterPlugin.registrar.activity(), WebViewActivity.class);
+ openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+ startActivityIfNeeded(openActivity, 0);
+ }
+
+ public void stopLoading() {
+ if (webView != null)
+ webView.stopLoading();
+ }
+
+ public boolean isLoading() {
+ if (webView != null)
+ return isLoading;
+ return false;
+ }
+
+ private void clearCookies() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ CookieManager.getInstance().removeAllCookies(new ValueCallback() {
+ @Override
+ public void onReceiveValue(Boolean aBoolean) {
+
+ }
+ });
+ } else {
+ CookieManager.getInstance().removeAllCookie();
}
+ }
+
+ private void clearCache() {
+ webView.clearCache(true);
+ clearCookies();
+ webView.clearFormData();
+ }
+
+ public void goBackButtonClicked(MenuItem item) {
+ goBack();
+ }
+
+ public void goForwardButtonClicked(MenuItem item) {
+ goForward();
+ }
+
+ public void shareButtonClicked(MenuItem item) {
+ Intent share = new Intent(Intent.ACTION_SEND);
+ share.setType("text/plain");
+ share.putExtra(Intent.EXTRA_TEXT, webView.getUrl());
+ startActivity(Intent.createChooser(share, "Share"));
+ }
+
+ public void reloadButtonClicked(MenuItem item) {
+ reload();
+ }
+
+ public void closeButtonClicked(MenuItem item) {
+ InAppBrowserFlutterPlugin.close(uuid, null);
+ }
}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ChromeCustomTabsActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ChromeCustomTabsActivity.java
index aa15beeb..d516b925 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ChromeCustomTabsActivity.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ChromeCustomTabsActivity.java
@@ -17,99 +17,78 @@ import java.util.Map;
public class ChromeCustomTabsActivity extends Activity {
- protected static final String LOG_TAG = "CustomTabsActivity";
- String uuid;
- String uuidFallback;
- CustomTabsIntent.Builder builder;
- ChromeCustomTabsOptions options;
- Map headersFallback;
- InAppBrowserOptions optionsFallback;
- private CustomTabActivityHelper customTabActivityHelper;
- private final int CHROME_CUSTOM_TAB_REQUEST_CODE = 100;
+ protected static final String LOG_TAG = "CustomTabsActivity";
+ String uuid;
+ CustomTabsIntent.Builder builder;
+ ChromeCustomTabsOptions options;
+ private CustomTabActivityHelper customTabActivityHelper;
+ private final int CHROME_CUSTOM_TAB_REQUEST_CODE = 100;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
- setContentView(R.layout.chrome_custom_tabs_layout);
+ setContentView(R.layout.chrome_custom_tabs_layout);
- Bundle b = getIntent().getExtras();
- uuid = b.getString("uuid");
- uuidFallback = b.getString("uuidFallback");
- String url = b.getString("url");
+ Bundle b = getIntent().getExtras();
+ assert b != null;
+ uuid = b.getString("uuid");
+ String url = b.getString("url");
- options = new ChromeCustomTabsOptions();
- options.parse((HashMap) b.getSerializable("options"));
+ options = new ChromeCustomTabsOptions();
+ options.parse((HashMap) b.getSerializable("options"));
- headersFallback = (HashMap) b.getSerializable("headers");
+ InAppBrowserFlutterPlugin.chromeCustomTabsActivities.put(uuid, this);
- optionsFallback = new InAppBrowserOptions();
- optionsFallback.parse((HashMap) b.getSerializable("optionsFallback"));
+ customTabActivityHelper = new CustomTabActivityHelper();
+ builder = new CustomTabsIntent.Builder();
- InAppBrowserFlutterPlugin.chromeCustomTabsActivities.put(uuid, this);
+ prepareCustomTabs();
- customTabActivityHelper = new CustomTabActivityHelper();
- builder = new CustomTabsIntent.Builder();
+ CustomTabsIntent customTabsIntent = builder.build();
- prepareCustomTabs();
+ CustomTabActivityHelper.openCustomTab(this, customTabsIntent, Uri.parse(url), CHROME_CUSTOM_TAB_REQUEST_CODE);
- CustomTabsIntent customTabsIntent = builder.build();
+ Map obj = new HashMap<>();
+ obj.put("uuid", uuid);
+ InAppBrowserFlutterPlugin.channel.invokeMethod("onChromeSafariBrowserOpened", obj);
+ InAppBrowserFlutterPlugin.channel.invokeMethod("onChromeSafariBrowserLoaded", obj);
+ }
- boolean chromeCustomTabsOpened = customTabActivityHelper.openCustomTab(this, customTabsIntent, Uri.parse(url), CHROME_CUSTOM_TAB_REQUEST_CODE,
- new CustomTabActivityHelper.CustomTabFallback() {
- @Override
- public void openUri(Activity activity, Uri uri) {
- if (!uuidFallback.isEmpty())
- InAppBrowserFlutterPlugin.open(uuidFallback, null, uri.toString(), optionsFallback, headersFallback, false, null);
- else {
- Log.d(LOG_TAG, "No WebView fallback declared.");
- activity.finish();
- }
- }
- });
+ private void prepareCustomTabs() {
+ if (options.addShareButton)
+ builder.addDefaultShareMenuItem();
- if (chromeCustomTabsOpened) {
- Map obj = new HashMap<>();
- obj.put("uuid", uuid);
- InAppBrowserFlutterPlugin.channel.invokeMethod("onChromeSafariBrowserOpened", obj);
- InAppBrowserFlutterPlugin.channel.invokeMethod("onChromeSafariBrowserLoaded", obj);
- }
- }
-
- private void prepareCustomTabs() {
- if (options.addShareButton)
- builder.addDefaultShareMenuItem();
-
- if (!options.toolbarBackgroundColor.isEmpty())
- builder.setToolbarColor(Color.parseColor(options.toolbarBackgroundColor));
-
- builder.setShowTitle(options.showTitle);
-
- if (options.enableUrlBarHiding)
- builder.enableUrlBarHiding();
-
- builder.setInstantAppsEnabled(options.instantAppsEnabled);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- customTabActivityHelper.bindCustomTabsService(this);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- customTabActivityHelper.unbindCustomTabsService(this);
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == CHROME_CUSTOM_TAB_REQUEST_CODE) {
- finish();
- Map obj = new HashMap<>();
- obj.put("uuid", uuid);
- InAppBrowserFlutterPlugin.channel.invokeMethod("onChromeSafariBrowserClosed", obj);
- }
+ if (!options.toolbarBackgroundColor.isEmpty())
+ builder.setToolbarColor(Color.parseColor(options.toolbarBackgroundColor));
+
+ builder.setShowTitle(options.showTitle);
+
+ if (options.enableUrlBarHiding)
+ builder.enableUrlBarHiding();
+
+ builder.setInstantAppsEnabled(options.instantAppsEnabled);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ customTabActivityHelper.bindCustomTabsService(this);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ customTabActivityHelper.unbindCustomTabsService(this);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == CHROME_CUSTOM_TAB_REQUEST_CODE) {
+ finish();
+ Map obj = new HashMap<>();
+ obj.put("uuid", uuid);
+ InAppBrowserFlutterPlugin.channel.invokeMethod("onChromeSafariBrowserClosed", obj);
}
+ }
}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/CustomTabActivityHelper.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/CustomTabActivityHelper.java
index 7c7d9263..46694362 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/CustomTabActivityHelper.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/CustomTabActivityHelper.java
@@ -27,26 +27,13 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback {
* @param activity The host activity.
* @param customTabsIntent a CustomTabsIntent to be used if Custom Tabs is available.
* @param uri the Uri to be opened.
- * @param fallback a CustomTabFallback to be used if Custom Tabs is not available.
*/
- public static boolean openCustomTab(Activity activity,
+ public static void openCustomTab(Activity activity,
CustomTabsIntent customTabsIntent,
Uri uri,
- int requestCode,
- CustomTabFallback fallback) {
- //If we cant find a package name, it means theres no browser that supports
- //Chrome Custom Tabs installed. So, we fallback to the webview
- if (!isAvailable(activity)) {
- if (fallback != null) {
- fallback.openUri(activity, uri);
- }
- } else {
- //customTabsIntent.intent.setPackage(packageName);
- customTabsIntent.intent.setData(uri);
- activity.startActivityForResult(customTabsIntent.intent, requestCode);
- return true;
- }
- return false;
+ int requestCode) {
+ customTabsIntent.intent.setData(uri);
+ activity.startActivityForResult(customTabsIntent.intent, requestCode);
}
public static boolean isAvailable(Activity activity) {
@@ -144,16 +131,4 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback {
void onCustomTabsDisconnected();
}
- /**
- * To be used as a fallback to open the Uri when Custom Tabs is not available.
- */
- public interface CustomTabFallback {
- /**
- *
- * @param activity The Activity that wants to open the Uri.
- * @param uri The uri to be opened by the fallback.
- */
- void openUri(Activity activity, Uri uri);
- }
-
}
\ No newline at end of file
diff --git a/example/assets/css/style.css b/example/assets/css/style.css
new file mode 100644
index 00000000..842b9f8e
--- /dev/null
+++ b/example/assets/css/style.css
@@ -0,0 +1,7 @@
+body {
+ background-color: #333;
+ color: #fff;
+}
+img {
+ max-width: 100%;
+}
\ No newline at end of file
diff --git a/example/assets/images/dart.svg b/example/assets/images/dart.svg
new file mode 100644
index 00000000..261e2bbf
--- /dev/null
+++ b/example/assets/images/dart.svg
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/assets/index.html b/example/assets/index.html
new file mode 100644
index 00000000..30a1709a
--- /dev/null
+++ b/example/assets/index.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+ Document
+
+
+
+
+
+
+
+
+
+
+ One of three columns
+
+
+ One of three columns
+
+
+ One of three columns
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist
index 87f41fac..a448f967 100644
--- a/example/ios/Runner/Info.plist
+++ b/example/ios/Runner/Info.plist
@@ -2,6 +2,11 @@
+ NSAppTransportSecurity
+
+ NSAllowsLocalNetworking
+
+
CFBundleDevelopmentRegion
en
CFBundleExecutable
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 07a58c93..bbe1eb1b 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -1,8 +1,8 @@
+import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inappbrowser/flutter_inappbrowser.dart';
class MyInAppBrowser extends InAppBrowser {
-
@override
Future onLoadStart(String url) async {
print("\n\nStarted $url\n\n");
@@ -13,6 +13,8 @@ class MyInAppBrowser extends InAppBrowser {
Future onLoadStop(String url) async {
print("\n\nStopped $url\n\n");
+ //print("\n\n ${await this.isHidden()} \n\n");
+
// await this.injectScriptCode("window.flutter_inappbrowser.callHandler('handlerTest', 1, 5,'string', {'key': 5}, [4,6,8]);");
// await this.injectScriptCode("window.flutter_inappbrowser.callHandler('handlerTest2', false, null, undefined);");
// await this.injectScriptCode("setTimeout(function(){window.flutter_inappbrowser.callHandler('handlerTest', 'anotherString');}, 1000);");
@@ -40,8 +42,7 @@ class MyInAppBrowser extends InAppBrowser {
// var x = {"as":4, "dfdfg": 6};
// x;
// """));
- //print("\n\n ${await this.isHidden()} \n\n");
-
+//
// await this.injectScriptFile("https://code.jquery.com/jquery-3.3.1.min.js");
// this.injectScriptCode("""
// \$( "body" ).html( "Next Step..." )
@@ -73,29 +74,33 @@ class MyInAppBrowser extends InAppBrowser {
}
@override
- void onLoadResource(WebResourceResponse response, WebResourceRequest request) {
-
- print("Started at: " + response.startTime.toString() + "ms ---> duration: " + response.duration.toString() + "ms " + response.url);
+ void onLoadResource(
+ WebResourceResponse response, WebResourceRequest request) {
+ print("Started at: " +
+ response.startTime.toString() +
+ "ms ---> duration: " +
+ response.duration.toString() +
+ "ms " +
+ response.url);
// if (response.headers["content-length"] != null)
// print(response.headers["content-length"] + " length");
}
@override
void onConsoleMessage(ConsoleMessage consoleMessage) {
-// print("""
-// console output:
-// sourceURL: ${consoleMessage.sourceURL}
-// lineNumber: ${consoleMessage.lineNumber}
-// message: ${consoleMessage.message}
-// messageLevel: ${consoleMessage.messageLevel}
-// """);
+ print("""
+ console output:
+ sourceURL: ${consoleMessage.sourceURL}
+ lineNumber: ${consoleMessage.lineNumber}
+ message: ${consoleMessage.message}
+ messageLevel: ${consoleMessage.messageLevel}
+ """);
}
}
MyInAppBrowser inAppBrowserFallback = new MyInAppBrowser();
class MyChromeSafariBrowser extends ChromeSafariBrowser {
-
MyChromeSafariBrowser(browserFallback) : super(browserFallback);
@override
@@ -115,9 +120,10 @@ class MyChromeSafariBrowser extends ChromeSafariBrowser {
}
// adding a webview fallback
-MyChromeSafariBrowser chromeSafariBrowser = new MyChromeSafariBrowser(inAppBrowserFallback);
+MyChromeSafariBrowser chromeSafariBrowser =
+ new MyChromeSafariBrowser(inAppBrowserFallback);
-void main() {
+Future main() async {
runApp(new MyApp());
}
@@ -127,11 +133,11 @@ class MyApp extends StatefulWidget {
}
class _MyAppState extends State {
-
@override
void initState() {
super.initState();
-// int indexTest = inAppBrowserFallback.addJavaScriptHandler("handlerTest", (arguments) async {
+// int indexTest = inAppBrowserFallback.addJavaScriptHandler("handlerTest",
+// (arguments) async {
// print("handlerTest arguments");
// print(arguments);
// });
@@ -150,21 +156,45 @@ class _MyAppState extends State {
title: const Text('Flutter InAppBrowser Plugin example app'),
),
body: new Center(
- child: new RaisedButton(onPressed: () {
- //chromeSafariBrowser.open("https://flutter.io/");
- inAppBrowserFallback.open(url: "https://flutter.io/", options: {
- //"useOnLoadResource": true,
- //"hidden": true,
- //"toolbarTopFixedTitle": "Fixed title",
- //"useShouldOverrideUrlLoading": true
- //"hideUrlBar": true,
- //"toolbarTop": false,
- //"toolbarBottom": false
- });
+ child: new RaisedButton(
+ onPressed: () async {
+// await chromeSafariBrowser.open("https://flutter.io/");
- },
- child: Text("Open InAppBrowser")
- ),
+// await InAppBrowser.openWithSystemBrowser("https://flutter.io/");
+
+ await inAppBrowserFallback.openOnLocalhost("assets/index.html", options: {
+ "useOnLoadResource": true,
+ //"hidden": true,
+ //"toolbarTopFixedTitle": "Fixed title",
+ //"useShouldOverrideUrlLoading": true
+ //"hideUrlBar": true,
+ //"toolbarTop": false,
+ //"toolbarBottom": false
+ });
+
+// await inAppBrowserFallback.open(url: "assets/index.html", options: {
+// "isLocalFile": true,
+// "useOnLoadResource": true,
+// //"hidden": true,
+// //"toolbarTopFixedTitle": "Fixed title",
+// //"useShouldOverrideUrlLoading": true
+// //"hideUrlBar": true,
+// //"toolbarTop": false,
+// //"toolbarBottom": false
+// });
+
+// await inAppBrowserFallback.open(url: "https://flutter.io/", options: {
+// //"useOnLoadResource": true,
+// //"hidden": true,
+// //"toolbarTopFixedTitle": "Fixed title",
+// //"useShouldOverrideUrlLoading": true
+// //"hideUrlBar": true,
+// //"toolbarTop": false,
+// //"toolbarBottom": false
+// });
+ //await inAppBrowserFallback.openOnLocalhost("assets/index.html");
+ },
+ child: Text("Open InAppBrowser")),
),
),
);
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
index 92a511b8..9a1b0837 100644
--- a/example/pubspec.yaml
+++ b/example/pubspec.yaml
@@ -38,6 +38,11 @@ flutter:
# the material Icons class.
uses-material-design: true
+ assets:
+ - assets/index.html
+ - assets/css/
+ - assets/images/
+
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
diff --git a/flutter_inappbrowser.iml b/flutter_inappbrowser.iml
index c5627b49..175d8e0e 100644
--- a/flutter_inappbrowser.iml
+++ b/flutter_inappbrowser.iml
@@ -14,6 +14,12 @@
+
+
+
+
+
+
diff --git a/ios/Classes/InAppBrowserOptions.swift b/ios/Classes/InAppBrowserOptions.swift
index 121b9360..6bac1ed0 100644
--- a/ios/Classes/InAppBrowserOptions.swift
+++ b/ios/Classes/InAppBrowserOptions.swift
@@ -12,6 +12,7 @@ public class InAppBrowserOptions: Options {
var useShouldOverrideUrlLoading = false
var useOnLoadResource = false
+ var openWithSystemBrowser = false;
var clearCache = false
var userAgent = ""
var javaScriptEnabled = true
@@ -21,6 +22,7 @@ public class InAppBrowserOptions: Options {
var toolbarTopBackgroundColor = ""
var hideUrlBar = false
var mediaPlaybackRequiresUserGesture = true
+ var isLocalFile = false
var disallowOverScroll = false
var toolbarBottom = true
diff --git a/ios/Classes/InAppBrowserWebViewController.swift b/ios/Classes/InAppBrowserWebViewController.swift
index b9bc369e..0ea3e33e 100644
--- a/ios/Classes/InAppBrowserWebViewController.swift
+++ b/ios/Classes/InAppBrowserWebViewController.swift
@@ -81,7 +81,6 @@ func convertToDictionary(text: String) -> [String: Any]? {
return nil
}
-
//extension WKWebView{
//
// var keyboardDisplayRequiresUserAction: Bool? {
@@ -139,6 +138,7 @@ class WKWebView_IBWrapper: WKWebView {
}
class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate, UITextFieldDelegate, WKScriptMessageHandler {
+
@IBOutlet var webView: WKWebView_IBWrapper!
@IBOutlet var closeButton: UIButton!
@IBOutlet var reloadButton: UIBarButtonItem!
@@ -200,7 +200,7 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
spinner.hidesWhenStopped = true
spinner.isHidden = false
spinner.stopAnimating()
-
+
loadUrl(url: self.currentURL!, headers: self.initHeaders)
}
@@ -421,11 +421,7 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
}
@objc func close() {
- currentURL = nil
-
- if (navigationDelegate != nil) {
- navigationDelegate?.browserExit(uuid: self.uuid)
- }
+ //currentURL = nil
weak var weakSelf = self
@@ -435,12 +431,18 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
weakSelf?.presentingViewController?.dismiss(animated: true, completion: {() -> Void in
self.tmpWindow?.windowLevel = 0.0
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
+ if (self.navigationDelegate != nil) {
+ self.navigationDelegate?.browserExit(uuid: self.uuid)
+ }
})
}
else {
weakSelf?.parent?.dismiss(animated: true, completion: {() -> Void in
self.tmpWindow?.windowLevel = 0.0
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
+ if (self.navigationDelegate != nil) {
+ self.navigationDelegate?.browserExit(uuid: self.uuid)
+ }
})
}
})
@@ -527,7 +529,9 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
}
if navigationAction.navigationType == .linkActivated && (browserOptions?.useShouldOverrideUrlLoading)! {
- navigationDelegate?.shouldOverrideUrlLoading(uuid: self.uuid, webView: webView, url: url)
+ if navigationDelegate != nil {
+ navigationDelegate?.shouldOverrideUrlLoading(uuid: self.uuid, webView: webView, url: url)
+ }
decisionHandler(.cancel)
return
}
@@ -606,7 +610,9 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
spinner.startAnimating()
}
- return (navigationDelegate?.onLoadStart(uuid: self.uuid, webView: webView))!
+ if navigationDelegate != nil {
+ navigationDelegate?.onLoadStart(uuid: self.uuid, webView: webView)
+ }
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
@@ -617,7 +623,10 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
backButton.isEnabled = webView.canGoBack
forwardButton.isEnabled = webView.canGoForward
spinner.stopAnimating()
- navigationDelegate?.onLoadStop(uuid: self.uuid, webView: webView)
+
+ if navigationDelegate != nil {
+ navigationDelegate?.onLoadStop(uuid: self.uuid, webView: webView)
+ }
}
func webView(_ view: WKWebView,
@@ -627,15 +636,19 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
- print("webView:didFailNavigationWithError - \(Int(error._code)): \(error.localizedDescription)")
backButton.isEnabled = webView.canGoBack
forwardButton.isEnabled = webView.canGoForward
spinner.stopAnimating()
- navigationDelegate?.onLoadError(uuid: self.uuid, webView: webView, error: error)
+
+ if navigationDelegate != nil {
+ navigationDelegate?.onLoadError(uuid: self.uuid, webView: webView, error: error)
+ }
}
func didReceiveResourceResponse(_ response: URLResponse, fromRequest request: URLRequest?, withData data: Data, startTime: Int, duration: Int) {
- navigationDelegate?.onLoadResource(uuid: self.uuid, webView: webView, response: response, fromRequest: request, withData: data, startTime: startTime, duration: duration)
+ if navigationDelegate != nil {
+ navigationDelegate?.onLoadResource(uuid: self.uuid, webView: webView, response: response, fromRequest: request, withData: data, startTime: startTime, duration: duration)
+ }
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
@@ -663,7 +676,9 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
messageLevel = "LOG"
break;
}
- navigationDelegate?.onConsoleMessage(uuid: self.uuid, sourceURL: "", lineNumber: 1, message: message.body as! String, messageLevel: messageLevel)
+ if navigationDelegate != nil {
+ navigationDelegate?.onConsoleMessage(uuid: self.uuid, sourceURL: "", lineNumber: 1, message: message.body as! String, messageLevel: messageLevel)
+ }
}
else if message.name == "resourceLoaded" {
if let resource = convertToDictionary(text: message.body as! String) {
@@ -695,7 +710,9 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
let body = message.body as! [String: Any]
let handlerName = body["handlerName"] as! String
let args = body["args"] as! String
- self.navigationDelegate?.onCallJsHandler(uuid: self.uuid, webView: webView, handlerName: handlerName, args: args)
+ if navigationDelegate != nil {
+ self.navigationDelegate?.onCallJsHandler(uuid: self.uuid, webView: webView, handlerName: handlerName, args: args)
+ }
}
}
}
diff --git a/ios/Classes/Options.swift b/ios/Classes/Options.swift
index a71791b3..50332320 100644
--- a/ios/Classes/Options.swift
+++ b/ios/Classes/Options.swift
@@ -14,12 +14,13 @@ public class Options: NSObject {
super.init()
}
- public func parse(options: [String: Any]) {
+ public func parse(options: [String: Any]) -> Options {
for (key, value) in options {
if self.responds(to: Selector(key)) {
self.setValue(value, forKey: key)
}
}
+ return self
}
}
diff --git a/ios/Classes/SafariViewController.swift b/ios/Classes/SafariViewController.swift
index 218bb655..b4fc5b94 100644
--- a/ios/Classes/SafariViewController.swift
+++ b/ios/Classes/SafariViewController.swift
@@ -40,15 +40,15 @@ class SafariViewController: SFSafariViewController, SFSafariViewControllerDelega
}
func close() {
- if (statusDelegate != nil) {
- statusDelegate?.safariExit(uuid: self.uuid)
- }
-
dismiss(animated: true)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(400), execute: {() -> Void in
self.tmpWindow?.windowLevel = 0.0
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
+
+ if (self.statusDelegate != nil) {
+ self.statusDelegate?.safariExit(uuid: self.uuid)
+ }
})
}
diff --git a/ios/Classes/SwiftFlutterPlugin.swift b/ios/Classes/SwiftFlutterPlugin.swift
index 6ccd51b2..8ce6b5c3 100644
--- a/ios/Classes/SwiftFlutterPlugin.swift
+++ b/ios/Classes/SwiftFlutterPlugin.swift
@@ -22,19 +22,6 @@ import Foundation
import AVFoundation
import SafariServices
-//class CustomURLCache: URLCache {
-// override func cachedResponse(for request: URLRequest) -> CachedURLResponse? {
-// dump(request.url)
-// return super.cachedResponse(for: request)
-// }
-//
-// override func getCachedResponse(for dataTask: URLSessionDataTask,
-// completionHandler: @escaping (CachedURLResponse?) -> Void) {
-// dump(dataTask.response)
-// super.getCachedResponse(for: dataTask, completionHandler: completionHandler)
-// }
-//}
-
let WEBVIEW_STORYBOARD = "WebView"
let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController"
@@ -47,6 +34,9 @@ extension Dictionary where Key: ExpressibleByStringLiteral {
}
public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
+
+ static var registrar: FlutterPluginRegistrar?
+
var webViewControllers: [String: InAppBrowserWebViewController?] = [:]
var safariViewControllers: [String: Any?] = [:]
@@ -59,11 +49,8 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
}
public static func register(with registrar: FlutterPluginRegistrar) {
-// URLProtocol.wk_registerScheme("http")
-// URLProtocol.wk_registerScheme("https")
-// URLProtocol.registerClass(MyURLProtocol.self)
-
- //URLCache.shared = CustomURLCache()
+
+ SwiftFlutterPlugin.registrar = registrar
let channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappbrowser", binaryMessenger: registrar.messenger())
let instance = SwiftFlutterPlugin(with: registrar)
@@ -73,7 +60,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
let uuid: String = (arguments!["uuid"] as? String)!
-
+
switch call.method {
case "open":
self.open(uuid: uuid, arguments: arguments!, result: result)
@@ -177,7 +164,6 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
}
else {
print("IAB.close() called but it was already closed.")
- return
}
}
@@ -192,41 +178,38 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
let url: String = (arguments["url"] as? String)!
let headers = (arguments["headers"] as? [String: String])!
- var target: String? = (arguments["target"] as? String)!
- target = target != nil ? target : "_self"
let absoluteUrl = URL(string: url)?.absoluteURL
let useChromeSafariBrowser = (arguments["useChromeSafariBrowser"] as? Bool)
if useChromeSafariBrowser! {
let uuidFallback = (arguments["uuidFallback"] as? String)!
- let options = (arguments["options"] as? [String: Any])!
- let optionsFallback = (arguments["optionsFallback"] as? [String: Any])!
+ let safariOptions = SafariBrowserOptions()
+ safariOptions.parse(options: (arguments["options"] as? [String: Any])!)
- open(uuid: uuid, uuidFallback: uuidFallback, inAppBrowser: absoluteUrl!, headers: headers, withOptions: options, useChromeSafariBrowser: true, withOptionsFallback: optionsFallback);
+ let optionsFallback = InAppBrowserOptions()
+ optionsFallback.parse(options: (arguments["optionsFallback"] as? [String: Any])!)
+
+ open(uuid: uuid, uuidFallback: uuidFallback, inAppBrowser: absoluteUrl!, headers: headers, withOptions: safariOptions, useChromeSafariBrowser: true, withOptionsFallback: optionsFallback, result: result);
}
else {
- let options = (arguments["options"] as? [String: Any])!
-
+ let options = InAppBrowserOptions()
+ options.parse(options: (arguments["options"] as? [String: Any])!)
+
if isSystemUrl(absoluteUrl!) {
- target = "_system"
+ options.openWithSystemBrowser = true
}
- if (target == "_self" || target == "_target") {
- open(uuid: uuid, uuidFallback: nil, inAppBrowser: absoluteUrl!, headers: headers, withOptions: options, useChromeSafariBrowser: false, withOptionsFallback: nil)
- }
- else if (target == "_system") {
- open(inSystem: absoluteUrl!)
+ if (options.openWithSystemBrowser) {
+ open(inSystem: absoluteUrl!, result: result)
}
else {
- // anything else
- open(uuid: uuid, uuidFallback: nil, inAppBrowser: absoluteUrl!, headers: headers,withOptions: options, useChromeSafariBrowser: false, withOptionsFallback: nil)
+ open(uuid: uuid, uuidFallback: nil, inAppBrowser: absoluteUrl!, headers: headers, withOptions: options, useChromeSafariBrowser: false, withOptionsFallback: nil, result: result)
}
}
- result(true)
}
- func open(uuid: String, uuidFallback: String?, inAppBrowser url: URL, headers: [String: String], withOptions options: [String: Any], useChromeSafariBrowser: Bool, withOptionsFallback optionsFallback: [String: Any]?) {
+ func open(uuid: String, uuidFallback: String?, inAppBrowser url: URL, headers: [String: String], withOptions options: Options, useChromeSafariBrowser: Bool, withOptionsFallback optionsFallback: Options?, result: @escaping FlutterResult) {
var uuid = uuid
@@ -235,7 +218,6 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
}
let safariViewController = self.safariViewControllers[uuid]
-
if safariViewController != nil {
if #available(iOS 9.0, *) {
(safariViewController! as! SafariViewController).close()
@@ -264,8 +246,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
if useChromeSafariBrowser == true {
if #available(iOS 9.0, *) {
- let safariOptions = SafariBrowserOptions()
- safariOptions.parse(options: options)
+ let safariOptions = options as! SafariBrowserOptions
let safari: SafariViewController
@@ -290,24 +271,37 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
tmpController.present(self.safariViewControllers[uuid]! as! SFSafariViewController, animated: true)
onChromeSafariBrowserOpened(uuid: uuid)
+ result(true)
return
}
else {
if uuidFallback == nil {
print("No WebView fallback declared.")
+ result(true)
+
return
}
uuid = uuidFallback!
- browserOptions = InAppBrowserOptions()
- browserOptions.parse(options: optionsFallback!)
+ browserOptions = optionsFallback as! InAppBrowserOptions
}
}
else {
- browserOptions = InAppBrowserOptions()
- browserOptions.parse(options: options)
+ browserOptions = options as! InAppBrowserOptions
}
-
+
+ var currentURL = url
+
+ if browserOptions.isLocalFile {
+ let key = SwiftFlutterPlugin.registrar!.lookupKey(forAsset: url.absoluteString)
+ let assetURL = Bundle.main.url(forResource: key, withExtension: nil)
+ if assetURL == nil {
+ result(FlutterError(code: "InAppBrowserFlutterPlugin", message: url.absoluteString + " asset file cannot be found!", details: nil))
+ return
+ }
+ currentURL = assetURL!
+ }
+
let storyboard = UIStoryboard(name: WEBVIEW_STORYBOARD, bundle: Bundle(for: InAppBrowserFlutterPlugin.self))
let vc = storyboard.instantiateViewController(withIdentifier: WEBVIEW_STORYBOARD_CONTROLLER_ID)
self.webViewControllers[uuid] = vc as? InAppBrowserWebViewController
@@ -316,7 +310,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
webViewController.browserOptions = browserOptions
webViewController.isHidden = browserOptions.hidden
webViewController.tmpWindow = tmpWindow
- webViewController.currentURL = url
+ webViewController.currentURL = currentURL
webViewController.initHeaders = headers
webViewController.navigationDelegate = self
@@ -338,6 +332,8 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
else {
tmpController.present(webViewController, animated: true, completion: nil)
}
+
+ result(true)
}
public func loadUrl(uuid: String, arguments: NSDictionary, result: @escaping FlutterResult) {
@@ -350,7 +346,6 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
webViewController.loadUrl(url: absoluteUrl, headers: headers)
}
else {
- print("url is empty")
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: "url is empty", details: nil))
}
result(true)
@@ -403,17 +398,18 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
}
}
- func open(inSystem url: URL) {
+ func open(inSystem url: URL, result: @escaping FlutterResult) {
if !UIApplication.shared.canOpenURL(url) {
- NotificationCenter.default.post(Notification(name: Notification.Name(rawValue: "PluginHandleOpenURLNotification"), object: url))
- return
+ result(FlutterError(code: "InAppBrowserFlutterPlugin", message: url.absoluteString + " cannot be opened!", details: nil))
}
-
- if #available(iOS 10.0, *) {
- UIApplication.shared.open(url, options: [:], completionHandler: nil)
- } else {
- UIApplication.shared.openURL(url)
+ else {
+ if #available(iOS 10.0, *) {
+ UIApplication.shared.open(url, options: [:], completionHandler: nil)
+ } else {
+ UIApplication.shared.openURL(url)
+ }
}
+ result(true)
}
// This is a helper method for the inject{Script|Style}{Code|File} API calls, which
@@ -429,7 +425,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
let jsonData: Data? = try? JSONSerialization.data(withJSONObject: [source], options: [])
let sourceArrayString = String(data: jsonData!, encoding: String.Encoding.utf8)
if sourceArrayString != nil {
- let sourceString: String? = (sourceArrayString! as NSString).substring(with: NSRange(location: 1, length: (sourceArrayString?.characters.count ?? 0) - 2))
+ let sourceString: String? = (sourceArrayString! as NSString).substring(with: NSRange(location: 1, length: (sourceArrayString?.count ?? 0) - 2))
let jsToInject = String(format: jsWrapper, sourceString!)
webViewController?.webView?.evaluateJavaScript(jsToInject, completionHandler: {(value, error) in
@@ -439,7 +435,6 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
if error != nil {
let userInfo = (error! as NSError).userInfo
- dump(userInfo)
self.onConsoleMessage(uuid: uuid, sourceURL: (userInfo["WKJavaScriptExceptionSourceURL"] as? URL)?.absoluteString ?? "", lineNumber: userInfo["WKJavaScriptExceptionLineNumber"] as! Int, message: userInfo["WKJavaScriptExceptionMessage"] as! String, messageLevel: "ERROR")
}
@@ -458,7 +453,6 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
result!(value)
}
} catch let error as NSError {
- print("Failed to load: \(error.localizedDescription)")
result!(FlutterError(code: "InAppBrowserFlutterPlugin", message: "Failed to load: \(error.localizedDescription)", details: error))
}
diff --git a/lib/flutter_inappbrowser.dart b/lib/flutter_inappbrowser.dart
index 143ba271..44759e0c 100644
--- a/lib/flutter_inappbrowser.dart
+++ b/lib/flutter_inappbrowser.dart
@@ -19,6 +19,7 @@
*
*/
+import 'dart:io';
import 'dart:async';
import 'dart:collection';
import 'dart:typed_data';
@@ -26,6 +27,7 @@ import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:uuid/uuid.dart';
+import 'package:mime/mime.dart';
typedef Future ListenerCallback(MethodCall call);
typedef Future JavaScriptHandlerCallback(List arguments);
@@ -85,8 +87,7 @@ class _ChannelManager {
static Future _handleMethod(MethodCall call) async {
String uuid = call.arguments["uuid"];
- listeners[uuid](call);
- return new Future.value("");
+ return await listeners[uuid](call);
}
static void addListener (String key, ListenerCallback callback) {
@@ -107,11 +108,14 @@ class InAppBrowser {
String uuid;
Map> javaScriptHandlersMap = HashMap>();
+ HttpServer _server;
+ bool _isOpened = false;
///
InAppBrowser () {
uuid = _uuidGenerator.v4();
_ChannelManager.addListener(uuid, _handleMethod);
+ _isOpened = false;
}
Future _handleMethod(MethodCall call) async {
@@ -131,6 +135,8 @@ class InAppBrowser {
onLoadError(url, code, message);
break;
case "onExit":
+ this._closeServer();
+ this._isOpened = false;
onExit();
break;
case "shouldOverrideUrlLoading":
@@ -183,133 +189,271 @@ class InAppBrowser {
}
}
break;
+ default:
+ throw UnimplementedError("Unimplemented ${call.method} method");
}
- return new Future.value("");
}
- ///Opens an [url] in a new [InAppBrowser] instance or the system browser.
+ ///Opens an [url] in a new [InAppBrowser] instance or in the system browser (`openWithSystemBrowser: true`).
+ ///
+ ///**NOTE**: If you open the given [url] with the system browser (`openWithSystemBrowser: true`), you wont be able to use the [InAppBrowser] methods!
///
///- [url]: The [url] to load. Call [encodeUriComponent()] on this if the [url] contains Unicode characters. The default value is `about:blank`.
///
///- [headers]: The additional headers to be used in the HTTP request for this URL, specified as a map from name to value.
///
- ///- [target]: The target in which to load the [url], an optional parameter that defaults to `_self`.
- ///
- /// - `_self`: Opens in the [InAppBrowser].
- /// - `_blank`: Opens in the [InAppBrowser].
- /// - `_system`: Opens in the system's web browser.
- ///
///- [options]: Options for the [InAppBrowser].
///
- /// All platforms support:
- /// - __useShouldOverrideUrlLoading__: Set to `true` to be able to listen at the [shouldOverrideUrlLoading()] event. The default value is `false`.
- /// - __useOnLoadResource__: Set to `true` to be able to listen at the [onLoadResource()] event. The default value is `false`.
- /// - __clearCache__: Set to `true` to have all the browser's cache cleared before the new window is opened. The default value is `false`.
- /// - __userAgent___: Set the custom WebView's user-agent.
- /// - __javaScriptEnabled__: Set to `true` to enable JavaScript. The default value is `true`.
- /// - __javaScriptCanOpenWindowsAutomatically__: Set to `true` to allow JavaScript open windows without user interaction. The default value is `false`.
- /// - __hidden__: Set to `true` to create the browser and load the page, but not show it. The `onLoadStop` event fires when loading is complete. Omit or set to `false` (default) to have the browser open and load normally.
- /// - __toolbarTop__: Set to `false` to hide the toolbar at the top of the WebView. The default value is `true`.
- /// - __toolbarTopBackgroundColor__: Set the custom background color of the toolbat at the top.
- /// - __hideUrlBar__: Set to `true` to hide the url bar on the toolbar at the top. The default value is `false`.
- /// - __mediaPlaybackRequiresUserGesture__: Set to `true` to prevent HTML5 audio or video from autoplaying. The default value is `true`.
+ /// - All platforms support:
+ /// - __useShouldOverrideUrlLoading__: Set to `true` to be able to listen at the [shouldOverrideUrlLoading()] event. The default value is `false`.
+ /// - __useOnLoadResource__: Set to `true` to be able to listen at the [onLoadResource()] event. The default value is `false`.
+ /// - __openWithSystemBrowser__: Set to `true` to open the given `url` with the system browser. The default value is `false`.
+ /// - __isLocalFile__: Set to `true` if the [url] is pointing to a local file (the file must be addded in the `assets` section of your `pubspec.yaml`. See [loadFile()] explanation). The default value is `false`.
+ /// - __clearCache__: Set to `true` to have all the browser's cache cleared before the new window is opened. The default value is `false`.
+ /// - __userAgent___: Set the custom WebView's user-agent.
+ /// - __javaScriptEnabled__: Set to `true` to enable JavaScript. The default value is `true`.
+ /// - __javaScriptCanOpenWindowsAutomatically__: Set to `true` to allow JavaScript open windows without user interaction. The default value is `false`.
+ /// - __hidden__: Set to `true` to create the browser and load the page, but not show it. The `onLoadStop` event fires when loading is complete. Omit or set to `false` (default) to have the browser open and load normally.
+ /// - __toolbarTop__: Set to `false` to hide the toolbar at the top of the WebView. The default value is `true`.
+ /// - __toolbarTopBackgroundColor__: Set the custom background color of the toolbat at the top.
+ /// - __hideUrlBar__: Set to `true` to hide the url bar on the toolbar at the top. The default value is `false`.
+ /// - __mediaPlaybackRequiresUserGesture__: Set to `true` to prevent HTML5 audio or video from autoplaying. The default value is `true`.
///
- /// **Android** supports these additional options:
+ /// - **Android** supports these additional options:
///
- /// - __hideTitleBar__: Set to `true` if you want the title should be displayed. The default value is `false`.
- /// - __closeOnCannotGoBack__: Set to `false` to not close the InAppBrowser when the user click on the back button and the WebView cannot go back to the history. The default value is `true`.
- /// - __clearSessionCache__: Set to `true` to have the session cookie cache cleared before the new window is opened.
- /// - __builtInZoomControls__: Set to `true` if the WebView should use its built-in zoom mechanisms. The default value is `false`.
- /// - __supportZoom__: Set to `false` if the WebView should not support zooming using its on-screen zoom controls and gestures. The default value is `true`.
- /// - __databaseEnabled__: Set to `true` if you want the database storage API is enabled. The default value is `false`.
- /// - __domStorageEnabled__: Set to `true` if you want the DOM storage API is enabled. The default value is `false`.
- /// - __useWideViewPort__: Set to `true` if the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport. When the value of the setting is false, the layout width is always set to the width of the WebView control in device-independent (CSS) pixels. When the value is true and the page contains the viewport meta tag, the value of the width specified in the tag is used. If the page does not contain the tag or does not provide a width, then a wide viewport will be used. The default value is `true`.
- /// - __safeBrowsingEnabled__: Set to `true` if you want the Safe Browsing is enabled. Safe Browsing allows WebView to protect against malware and phishing attacks by verifying the links. The default value is `true`.
- /// - __progressBar__: Set to `false` to hide the progress bar at the bottom of the toolbar at the top. The default value is `true`.
+ /// - __hideTitleBar__: Set to `true` if you want the title should be displayed. The default value is `false`.
+ /// - __closeOnCannotGoBack__: Set to `false` to not close the InAppBrowser when the user click on the back button and the WebView cannot go back to the history. The default value is `true`.
+ /// - __clearSessionCache__: Set to `true` to have the session cookie cache cleared before the new window is opened.
+ /// - __builtInZoomControls__: Set to `true` if the WebView should use its built-in zoom mechanisms. The default value is `false`.
+ /// - __supportZoom__: Set to `false` if the WebView should not support zooming using its on-screen zoom controls and gestures. The default value is `true`.
+ /// - __databaseEnabled__: Set to `true` if you want the database storage API is enabled. The default value is `false`.
+ /// - __domStorageEnabled__: Set to `true` if you want the DOM storage API is enabled. The default value is `false`.
+ /// - __useWideViewPort__: Set to `true` if the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport. When the value of the setting is false, the layout width is always set to the width of the WebView control in device-independent (CSS) pixels. When the value is true and the page contains the viewport meta tag, the value of the width specified in the tag is used. If the page does not contain the tag or does not provide a width, then a wide viewport will be used. The default value is `true`.
+ /// - __safeBrowsingEnabled__: Set to `true` if you want the Safe Browsing is enabled. Safe Browsing allows WebView to protect against malware and phishing attacks by verifying the links. The default value is `true`.
+ /// - __progressBar__: Set to `false` to hide the progress bar at the bottom of the toolbar at the top. The default value is `true`.
///
- /// **iOS** supports these additional options:
+ /// - **iOS** supports these additional options:
///
- /// - __disallowOverScroll__: Set to `true` to disable the bouncing of the WebView when the scrolling has reached an edge of the content. The default value is `false`.
- /// - __toolbarBottom__: Set to `false` to hide the toolbar at the bottom of the WebView. The default value is `true`.
- /// - __toolbarBottomBackgroundColor__: Set the custom background color of the toolbat at the bottom.
- /// - __toolbarBottomTranslucent__: Set to `true` to set the toolbar at the bottom translucent. The default value is `true`.
- /// - __closeButtonCaption__: Set the custom text for the close button.
- /// - __closeButtonColor__: Set the custom color for the close button.
- /// - __presentationStyle__: Set the custom modal presentation style when presenting the WebView. The default value is `0 //fullscreen`. See [UIModalPresentationStyle](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle) for all the available styles.
- /// - __transitionStyle__: Set to the custom transition style when presenting the WebView. The default value is `0 //crossDissolve`. See [UIModalTransitionStyle](https://developer.apple.com/documentation/uikit/uimodaltransitionStyle) for all the available styles.
- /// - __enableViewportScale__: Set to `true` to allow a viewport meta tag to either disable or restrict the range of user scaling. The default value is `false`.
- /// - __suppressesIncrementalRendering__: Set to `true` if you want the WebView suppresses content rendering until it is fully loaded into memory.. The default value is `false`.
- /// - __allowsAirPlayForMediaPlayback__: Set to `true` to allow AirPlay. The default value is `true`.
- /// - __allowsBackForwardNavigationGestures__: Set to `true` to allow the horizontal swipe gestures trigger back-forward list navigations. The default value is `true`.
- /// - __allowsLinkPreview__: Set to `true` to allow that pressing on a link displays a preview of the destination for the link. The default value is `true`.
- /// - __ignoresViewportScaleLimits__: Set to `true` if you want that the WebView should always allow scaling of the webpage, regardless of the author's intent. The ignoresViewportScaleLimits property overrides the `user-scalable` HTML property in a webpage. The default value is `false`.
- /// - __allowsInlineMediaPlayback__: Set to `true` to allow HTML5 media playback to appear inline within the screen layout, using browser-supplied controls rather than native controls. For this to work, add the `webkit-playsinline` attribute to any `` elements. The default value is `false`.
- /// - __allowsPictureInPictureMediaPlayback__: Set to `true` to allow HTML5 videos play picture-in-picture. The default value is `true`.
- /// - __spinner__: Set to `false` to hide the spinner when the WebView is loading a page. The default value is `true`.
- Future open({String url = "about:blank", Map headers = const {}, String target = "_self", Map options = const {}}) async {
+ /// - __disallowOverScroll__: Set to `true` to disable the bouncing of the WebView when the scrolling has reached an edge of the content. The default value is `false`.
+ /// - __toolbarBottom__: Set to `false` to hide the toolbar at the bottom of the WebView. The default value is `true`.
+ /// - __toolbarBottomBackgroundColor__: Set the custom background color of the toolbat at the bottom.
+ /// - __toolbarBottomTranslucent__: Set to `true` to set the toolbar at the bottom translucent. The default value is `true`.
+ /// - __closeButtonCaption__: Set the custom text for the close button.
+ /// - __closeButtonColor__: Set the custom color for the close button.
+ /// - __presentationStyle__: Set the custom modal presentation style when presenting the WebView. The default value is `0 //fullscreen`. See [UIModalPresentationStyle](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle) for all the available styles.
+ /// - __transitionStyle__: Set to the custom transition style when presenting the WebView. The default value is `0 //crossDissolve`. See [UIModalTransitionStyle](https://developer.apple.com/documentation/uikit/uimodaltransitionStyle) for all the available styles.
+ /// - __enableViewportScale__: Set to `true` to allow a viewport meta tag to either disable or restrict the range of user scaling. The default value is `false`.
+ /// - __suppressesIncrementalRendering__: Set to `true` if you want the WebView suppresses content rendering until it is fully loaded into memory.. The default value is `false`.
+ /// - __allowsAirPlayForMediaPlayback__: Set to `true` to allow AirPlay. The default value is `true`.
+ /// - __allowsBackForwardNavigationGestures__: Set to `true` to allow the horizontal swipe gestures trigger back-forward list navigations. The default value is `true`.
+ /// - __allowsLinkPreview__: Set to `true` to allow that pressing on a link displays a preview of the destination for the link. The default value is `true`.
+ /// - __ignoresViewportScaleLimits__: Set to `true` if you want that the WebView should always allow scaling of the webpage, regardless of the author's intent. The ignoresViewportScaleLimits property overrides the `user-scalable` HTML property in a webpage. The default value is `false`.
+ /// - __allowsInlineMediaPlayback__: Set to `true` to allow HTML5 media playback to appear inline within the screen layout, using browser-supplied controls rather than native controls. For this to work, add the `webkit-playsinline` attribute to any `` elements. The default value is `false`.
+ /// - __allowsPictureInPictureMediaPlayback__: Set to `true` to allow HTML5 videos play picture-in-picture. The default value is `true`.
+ /// - __spinner__: Set to `false` to hide the spinner when the WebView is loading a page. The default value is `true`.
+ Future open({String url = "about:blank", Map headers = const {}, Map options = const {}}) async {
+ this._throwIsAlreadyOpened(message: 'Cannot open $url!');
Map args = {};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headers);
- args.putIfAbsent('target', () => target);
args.putIfAbsent('options', () => options);
args.putIfAbsent('useChromeSafariBrowser', () => false);
+ await _ChannelManager.channel.invokeMethod('open', args);
+ this._isOpened = true;
+ }
+
+ ///This is a static method that opens an [url] in the system browser.
+ ///This has the same behaviour of an [InAppBrowser] instance calling the [open()] method with option `openWithSystemBrowser: true`.
+ static Future openWithSystemBrowser(String url) async {
+ Map args = {};
+ args.putIfAbsent('uuid', () => "");
+ args.putIfAbsent('url', () => url);
+ args.putIfAbsent('headers', () => {});
+ args.putIfAbsent('options', () => {"openWithSystemBrowser": true});
+ args.putIfAbsent('useChromeSafariBrowser', () => false);
return await _ChannelManager.channel.invokeMethod('open', args);
}
+ Future _startServer({int port = 8080}) async {
+
+ this._closeServer();
+ var completer = new Completer();
+
+ runZoned(() {
+ HttpServer.bind('127.0.0.1', port).then((server) {
+ print('Server running at http://127.0.0.1:' + port.toString());
+
+ this._server = server;
+
+ server.listen((HttpRequest request) async {
+ var body = List();
+ var path = request.requestedUri.path;
+ path = (path.startsWith('/')) ? path.substring(1) : path;
+ path += (path.endsWith('/')) ? 'index.html' : '';
+
+ try {
+ body = (await rootBundle.load(path))
+ .buffer.asUint8List();
+ } catch (e) {
+ print(e.toString());
+ request.response.close();
+ return;
+ }
+
+ var contentType = ['text', 'html'];
+ if (!request.requestedUri.path.endsWith('/') && request.requestedUri.pathSegments.isNotEmpty) {
+ var mimeType = lookupMimeType(request.requestedUri.path, headerBytes: body);
+ if (mimeType != null) {
+ contentType = mimeType.split('/');
+ }
+ }
+
+ request.response.headers.contentType = new ContentType(contentType[0], contentType[1], charset: 'utf-8');
+ request.response.add(body);
+ request.response.close();
+ });
+
+ completer.complete();
+ });
+ }, onError: (e, stackTrace) => print('Error: $e $stackTrace'));
+
+ return completer.future;
+ }
+
+ Future _closeServer() async {
+ if (this._server != null) {
+ final port = this._server.port;
+ await this._server.close(force: true);
+ print('Server running at http://127.0.0.1:$port closed');
+ this._server = null;
+ }
+ }
+
+ ///Serve the [assetFilePath] from Flutter assets on http://localhost:[port]/. It is similar to [InAppBrowser.open()] with option `isLocalFile: true`, but it starts a server.
+ ///
+ ///**NOTE for iOS**: For the iOS Platform, you need to add the `NSAllowsLocalNetworking` key with `true` in the `Info.plist` file (See [ATS Configuration Basics](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35):
+ ///```xml
+ ///NSAppTransportSecurity
+ ///
+ /// NSAllowsLocalNetworking
+ ///
+ ///
+ ///```
+ ///The `NSAllowsLocalNetworking` key is available since **iOS 10**.
+ Future openOnLocalhost(String assetFilePath, {int port = 8080, Map headers = const {}, Map options = const {}}) async {
+ this._throwIsAlreadyOpened(message: 'Cannot open $assetFilePath!');
+ await this._startServer(port: port);
+ Map args = {};
+ args.putIfAbsent('uuid', () => uuid);
+ args.putIfAbsent('url', () => 'http://localhost:${this._server.port}/' + assetFilePath);
+ args.putIfAbsent('headers', () => headers);
+ options["isLocalFile"] = false;
+ args.putIfAbsent('options', () => options);
+ args.putIfAbsent('useChromeSafariBrowser', () => false);
+ await _ChannelManager.channel.invokeMethod('open', args);
+ this._isOpened = true;
+ }
+
///Loads the given [url] with optional [headers] specified as a map from name to value.
Future loadUrl(String url, {Map headers = const {}}) async {
+ this._throwIsNotOpened(message: 'Cannot laod $url!');
Map args = {};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headers);
- return await _ChannelManager.channel.invokeMethod('loadUrl', args);
+ await _ChannelManager.channel.invokeMethod('loadUrl', args);
+ }
+
+ ///Loads the given [assetFilePath] with optional [headers] specified as a map from name to value.
+ ///
+ ///To be able to load your local files (assets, js, css, etc.), you need to add them in the `assets` section of the `pubspec.yaml` file, otherwise they cannot be found!
+ ///
+ ///Example of a `pubspec.yaml` file:
+ ///```yaml
+ ///...
+ ///
+ ///# The following section is specific to Flutter.
+ ///flutter:
+ ///
+ /// # The following line ensures that the Material Icons font is
+ /// # included with your application, so that you can use the icons in
+ /// # the material Icons class.
+ /// uses-material-design: true
+ ///
+ /// assets:
+ /// - assets/index.html
+ /// - assets/css/
+ /// - assets/images/
+ ///
+ ///...
+ ///```
+ ///Example of a `main.dart` file:
+ ///```dart
+ ///...
+ ///inAppBrowser.loadFile("assets/index.html");
+ ///...
+ ///```
+ Future loadFile(String assetFilePath, {Map headers = const {}}) async {
+ this._throwIsNotOpened(message: 'Cannot laod $assetFilePath!');
+ Map args = {};
+ args.putIfAbsent('uuid', () => uuid);
+ args.putIfAbsent('url', () => assetFilePath);
+ args.putIfAbsent('headers', () => headers);
+ await _ChannelManager.channel.invokeMethod('loadFile', args);
}
///Displays an [InAppBrowser] window that was opened hidden. Calling this has no effect if the [InAppBrowser] was already visible.
Future show() async {
+ this._throwIsNotOpened();
Map args = {};
args.putIfAbsent('uuid', () => uuid);
- return await _ChannelManager.channel.invokeMethod('show', args);
+ await _ChannelManager.channel.invokeMethod('show', args);
}
///Hides the [InAppBrowser] window. Calling this has no effect if the [InAppBrowser] was already hidden.
Future hide() async {
+ this._throwIsNotOpened();
Map args = {};
args.putIfAbsent('uuid', () => uuid);
- return await _ChannelManager.channel.invokeMethod('hide', args);
+ await _ChannelManager.channel.invokeMethod('hide', args);
}
///Closes the [InAppBrowser] window.
Future close() async {
+ this._throwIsNotOpened();
Map args = {};
args.putIfAbsent('uuid', () => uuid);
- return await _ChannelManager.channel.invokeMethod('close', args);
+ await _ChannelManager.channel.invokeMethod('close', args);
}
///Reloads the [InAppBrowser] window.
Future reload() async {
+ this._throwIsNotOpened();
Map args = {};
args.putIfAbsent('uuid', () => uuid);
- return await _ChannelManager.channel.invokeMethod('reload', args);
+ await _ChannelManager.channel.invokeMethod('reload', args);
}
///Goes back in the history of the [InAppBrowser] window.
Future goBack() async {
+ this._throwIsNotOpened();
Map args = {};
args.putIfAbsent('uuid', () => uuid);
- return await _ChannelManager.channel.invokeMethod('goBack', args);
+ await _ChannelManager.channel.invokeMethod('goBack', args);
}
///Goes forward in the history of the [InAppBrowser] window.
Future goForward() async {
+ this._throwIsNotOpened();
Map args = {};
args.putIfAbsent('uuid', () => uuid);
- return await _ChannelManager.channel.invokeMethod('goForward', args);
+ await _ChannelManager.channel.invokeMethod('goForward', args);
}
///Check if the Web View of the [InAppBrowser] instance is in a loading state.
Future isLoading() async {
+ this._throwIsNotOpened();
Map args = {};
args.putIfAbsent('uuid', () => uuid);
return await _ChannelManager.channel.invokeMethod('isLoading', args);
@@ -317,48 +461,54 @@ class InAppBrowser {
///Stops the Web View of the [InAppBrowser] instance from loading.
Future stopLoading() async {
+ this._throwIsNotOpened();
Map args = {};
args.putIfAbsent('uuid', () => uuid);
- return await _ChannelManager.channel.invokeMethod('stopLoading', args);
+ await _ChannelManager.channel.invokeMethod('stopLoading', args);
}
///Check if the Web View of the [InAppBrowser] instance is hidden.
Future isHidden() async {
+ this._throwIsNotOpened();
Map args = {};
args.putIfAbsent('uuid', () => uuid);
return await _ChannelManager.channel.invokeMethod('isHidden', args);
}
- ///Injects JavaScript code into the [InAppBrowser] window and returns the result of the evaluation. (Only available when the target is set to `_blank` or to `_self`)
+ ///Injects JavaScript code into the [InAppBrowser] window and returns the result of the evaluation.
Future injectScriptCode(String source) async {
+ this._throwIsNotOpened();
Map args = {};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('source', () => source);
return await _ChannelManager.channel.invokeMethod('injectScriptCode', args);
}
- ///Injects a JavaScript file into the [InAppBrowser] window. (Only available when the target is set to `_blank` or to `_self`)
+ ///Injects a JavaScript file into the [InAppBrowser] window.
Future injectScriptFile(String urlFile) async {
+ this._throwIsNotOpened();
Map args = {};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('urlFile', () => urlFile);
- return await _ChannelManager.channel.invokeMethod('injectScriptFile', args);
+ await _ChannelManager.channel.invokeMethod('injectScriptFile', args);
}
- ///Injects CSS into the [InAppBrowser] window. (Only available when the target is set to `_blank` or to `_self`)
+ ///Injects CSS into the [InAppBrowser] window.
Future injectStyleCode(String source) async {
+ this._throwIsNotOpened();
Map args = {};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('source', () => source);
- return await _ChannelManager.channel.invokeMethod('injectStyleCode', args);
+ await _ChannelManager.channel.invokeMethod('injectStyleCode', args);
}
- ///Injects a CSS file into the [InAppBrowser] window. (Only available when the target is set to `_blank` or to `_self`)
+ ///Injects a CSS file into the [InAppBrowser] window.
Future injectStyleFile(String urlFile) async {
+ this._throwIsNotOpened();
Map args = {};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('urlFile', () => urlFile);
- return await _ChannelManager.channel.invokeMethod('injectStyleFile', args);
+ await _ChannelManager.channel.invokeMethod('injectStyleFile', args);
}
///Adds/Appends a JavaScript message handler [callback] ([JavaScriptHandlerCallback]) that listen to post messages sent from JavaScript by the handler with name [handlerName].
@@ -419,7 +569,7 @@ class InAppBrowser {
///
///**NOTE**: In order to be able to listen this event, you need to set `useOnLoadResource` option to `true`.
///
- ///**NOTE only for iOS**: In some cases, the [response.data] of a [response] with `text/html` encoding could be empty.
+ ///**NOTE only for iOS**: In some cases, the [response.data] of a [response] with `text/assets` encoding could be empty.
void onLoadResource(WebResourceResponse response, WebResourceRequest request) {
}
@@ -429,6 +579,22 @@ class InAppBrowser {
}
+ ///Returns `true` if the browser is opened, otherwise `false`.
+ bool isOpened() {
+ return this._isOpened;
+ }
+
+ void _throwIsAlreadyOpened({String message = ''}) {
+ if (this.isOpened()) {
+ throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is already opened.']);
+ }
+ }
+
+ void _throwIsNotOpened({String message = ''}) {
+ if (!this.isOpened()) {
+ throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is not opened.']);
+ }
+ }
}
///ChromeSafariBrowser class.
@@ -440,12 +606,14 @@ class InAppBrowser {
class ChromeSafariBrowser {
String uuid;
InAppBrowser browserFallback;
+ bool _isOpened = false;
///Initialize the [ChromeSafariBrowser] instance with a [InAppBrowser] fallback instance or `null`.
ChromeSafariBrowser (bf) {
uuid = _uuidGenerator.v4();
browserFallback = bf;
_ChannelManager.addListener(uuid, _handleMethod);
+ _isOpened = false;
}
Future _handleMethod(MethodCall call) async {
@@ -458,9 +626,11 @@ class ChromeSafariBrowser {
break;
case "onChromeSafariBrowserClosed":
onClosed();
+ this._isOpened = false;
break;
+ default:
+ throw UnimplementedError("Unimplemented ${call.method} method");
}
- return new Future.value("");
}
///Opens an [url] in a new [ChromeSafariBrowser] instance or the system browser.
@@ -491,16 +661,17 @@ class ChromeSafariBrowser {
///- __presentationStyle__: Set the custom modal presentation style when presenting the WebView. The default value is `0 //fullscreen`. See [UIModalPresentationStyle](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle) for all the available styles.
///- __transitionStyle__: Set to the custom transition style when presenting the WebView. The default value is `0 //crossDissolve`. See [UIModalTransitionStyle](https://developer.apple.com/documentation/uikit/uimodaltransitionStyle) for all the available styles.
Future open(String url, {Map options = const {}, Map headersFallback = const {}, Map optionsFallback = const {}}) async {
+ this._throwIsAlreadyOpened(message: 'Cannot open $url!');
Map args = {};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('uuidFallback', () => (browserFallback != null) ? browserFallback.uuid : '');
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headersFallback);
- args.putIfAbsent('target', () => "");
args.putIfAbsent('options', () => options);
args.putIfAbsent('optionsFallback', () => optionsFallback);
args.putIfAbsent('useChromeSafariBrowser', () => true);
- return await _ChannelManager.channel.invokeMethod('open', args);
+ await _ChannelManager.channel.invokeMethod('open', args);
+ this._isOpened = true;
}
///Event fires when the [ChromeSafariBrowser] is opened.
@@ -517,4 +688,20 @@ class ChromeSafariBrowser {
void onClosed() {
}
+
+ bool isOpened() {
+ return this._isOpened;
+ }
+
+ void _throwIsAlreadyOpened({String message = ''}) {
+ if (this.isOpened()) {
+ throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is already opened.']);
+ }
+ }
+
+ void _throwIsNotOpened({String message = ''}) {
+ if (!this.isOpened()) {
+ throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is not opened.']);
+ }
+ }
}
\ No newline at end of file
diff --git a/pubspec.yaml b/pubspec.yaml
index 4c695cea..2d24d6b3 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: flutter_inappbrowser
description: A Flutter plugin that allows you to open an in-app browser window. (inspired by the popular cordova-plugin-inappbrowser).
-version: 0.3.2
+version: 0.4.0
author: Lorenzo Pichilli
homepage: https://github.com/pichillilorenzo/flutter_inappbrowser
@@ -11,6 +11,7 @@ dependencies:
flutter:
sdk: flutter
uuid: ^1.0.3
+ mime: ^0.9.6+2
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec