Commit 0e30767c authored by Lorenzo Pichilli's avatar Lorenzo Pichilli

code refactoring, added InAppBrowserManager and ChromeSafariBrowserManager...

code refactoring, added InAppBrowserManager and ChromeSafariBrowserManager classes on native code, updated webview options class names
parent 4d752ee9
...@@ -530,8 +530,7 @@ class MyInAppBrowser extends InAppBrowser { ...@@ -530,8 +530,7 @@ class MyInAppBrowser extends InAppBrowser {
@override @override
Future<ShouldOverrideUrlLoadingAction> shouldOverrideUrlLoading(ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async { Future<ShouldOverrideUrlLoadingAction> shouldOverrideUrlLoading(ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async {
print("\n\n override ${shouldOverrideUrlLoadingRequest.url}\n\n"); print("\n\n override ${shouldOverrideUrlLoadingRequest.url}\n\n");
this.webViewController.loadUrl(url: shouldOverrideUrlLoadingRequest.url); return ShouldOverrideUrlLoadingAction.ALLOW;
return ShouldOverrideUrlLoadingAction.CANCEL;
} }
@override @override
......
...@@ -5,7 +5,6 @@ import android.content.Intent; ...@@ -5,7 +5,6 @@ import android.content.Intent;
import android.graphics.Color; import android.graphics.Color;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import androidx.browser.customtabs.CustomTabsCallback; import androidx.browser.customtabs.CustomTabsCallback;
import androidx.browser.customtabs.CustomTabsIntent; import androidx.browser.customtabs.CustomTabsIntent;
...@@ -14,16 +13,21 @@ import androidx.browser.customtabs.CustomTabsSession; ...@@ -14,16 +13,21 @@ import androidx.browser.customtabs.CustomTabsSession;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.R; import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.Shared;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class ChromeCustomTabsActivity extends Activity { import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class ChromeCustomTabsActivity extends Activity implements MethodChannel.MethodCallHandler {
protected static final String LOG_TAG = "CustomTabsActivity"; protected static final String LOG_TAG = "CustomTabsActivity";
String uuid; public MethodChannel channel;
CustomTabsIntent.Builder builder; public String uuid;
ChromeCustomTabsOptions options; private CustomTabsIntent.Builder builder;
private ChromeCustomTabsOptions options;
private CustomTabActivityHelper customTabActivityHelper; private CustomTabActivityHelper customTabActivityHelper;
private CustomTabsSession customTabsSession; private CustomTabsSession customTabsSession;
private final int CHROME_CUSTOM_TAB_REQUEST_CODE = 100; private final int CHROME_CUSTOM_TAB_REQUEST_CODE = 100;
...@@ -39,13 +43,15 @@ public class ChromeCustomTabsActivity extends Activity { ...@@ -39,13 +43,15 @@ public class ChromeCustomTabsActivity extends Activity {
Bundle b = getIntent().getExtras(); Bundle b = getIntent().getExtras();
assert b != null; assert b != null;
uuid = b.getString("uuid"); uuid = b.getString("uuid");
channel = new MethodChannel(Shared.messenger, "com.pichillilorenzo/flutter_chromesafaribrowser_" + uuid);
channel.setMethodCallHandler(this);
final String url = b.getString("url"); final String url = b.getString("url");
options = new ChromeCustomTabsOptions(); options = new ChromeCustomTabsOptions();
options.parse((HashMap<String, Object>) b.getSerializable("options")); options.parse((HashMap<String, Object>) b.getSerializable("options"));
InAppWebViewFlutterPlugin.inAppBrowser.chromeCustomTabsActivities.put(uuid, this);
final ChromeCustomTabsActivity chromeCustomTabsActivity = this; final ChromeCustomTabsActivity chromeCustomTabsActivity = this;
customTabActivityHelper = new CustomTabActivityHelper(); customTabActivityHelper = new CustomTabActivityHelper();
...@@ -68,7 +74,7 @@ public class ChromeCustomTabsActivity extends Activity { ...@@ -68,7 +74,7 @@ public class ChromeCustomTabsActivity extends Activity {
finish(); finish();
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid); obj.put("uuid", uuid);
InAppWebViewFlutterPlugin.inAppBrowser.channel.invokeMethod("onChromeSafariBrowserClosed", obj); channel.invokeMethod("onChromeSafariBrowserClosed", obj);
} }
}); });
...@@ -79,14 +85,14 @@ public class ChromeCustomTabsActivity extends Activity { ...@@ -79,14 +85,14 @@ public class ChromeCustomTabsActivity extends Activity {
onChromeSafariBrowserOpened = true; onChromeSafariBrowserOpened = true;
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid); obj.put("uuid", uuid);
InAppWebViewFlutterPlugin.inAppBrowser.channel.invokeMethod("onChromeSafariBrowserOpened", obj); channel.invokeMethod("onChromeSafariBrowserOpened", obj);
} }
if (navigationEvent == NAVIGATION_FINISHED && !onChromeSafariBrowserCompletedInitialLoad) { if (navigationEvent == NAVIGATION_FINISHED && !onChromeSafariBrowserCompletedInitialLoad) {
onChromeSafariBrowserCompletedInitialLoad = true; onChromeSafariBrowserCompletedInitialLoad = true;
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid); obj.put("uuid", uuid);
InAppWebViewFlutterPlugin.inAppBrowser.channel.invokeMethod("onChromeSafariBrowserCompletedInitialLoad", obj); channel.invokeMethod("onChromeSafariBrowserCompletedInitialLoad", obj);
} }
} }
...@@ -113,6 +119,14 @@ public class ChromeCustomTabsActivity extends Activity { ...@@ -113,6 +119,14 @@ public class ChromeCustomTabsActivity extends Activity {
}); });
} }
@Override
public void onMethodCall(final MethodCall call, final MethodChannel.Result result) {
switch (call.method) {
default:
result.notImplemented();
}
}
private void prepareCustomTabs(CustomTabsIntent customTabsIntent) { private void prepareCustomTabs(CustomTabsIntent customTabsIntent) {
if (options.addDefaultShareMenuItem) if (options.addDefaultShareMenuItem)
builder.addDefaultShareMenuItem(); builder.addDefaultShareMenuItem();
...@@ -155,7 +169,7 @@ public class ChromeCustomTabsActivity extends Activity { ...@@ -155,7 +169,7 @@ public class ChromeCustomTabsActivity extends Activity {
finish(); finish();
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid); obj.put("uuid", uuid);
InAppWebViewFlutterPlugin.inAppBrowser.channel.invokeMethod("onChromeSafariBrowserClosed", obj); InAppWebViewFlutterPlugin.inAppBrowserManager.channel.invokeMethod("onChromeSafariBrowserClosed", obj);
} }
} }
......
package com.pichillilorenzo.flutter_inappwebview;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ChromeCustomTabsActivity;
import com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.CustomTabActivityHelper;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandler {
public MethodChannel channel;
protected static final String LOG_TAG = "ChromeBrowserManager";
public ChromeSafariBrowserManager(BinaryMessenger messenger) {
channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_chromesafaribrowser");
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(final MethodCall call, final MethodChannel.Result result) {
final Activity activity = Shared.activity;
final String uuid = (String) call.argument("uuid");
switch (call.method) {
case "open":
{
String url = (String) call.argument("url");
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
String uuidFallback = (String) call.argument("uuidFallback");
Map<String, String> headersFallback = (Map<String, String>) call.argument("headersFallback");
HashMap<String, Object> optionsFallback = (HashMap<String, Object>) call.argument("optionsFallback");
open(activity, uuid, url, options, uuidFallback, headersFallback, optionsFallback, result);
}
break;
default:
result.notImplemented();
}
}
public void open(Activity activity, String uuid, String url, HashMap<String, Object> options, String uuidFallback, Map<String, String> headersFallback, HashMap<String, Object> optionsFallback, MethodChannel.Result result) {
Intent intent = null;
Bundle extras = new Bundle();
extras.putString("fromActivity", activity.getClass().getName());
extras.putString("url", url);
extras.putBoolean("isData", false);
extras.putString("uuid", uuid);
extras.putSerializable("options", options);
extras.putSerializable("headers", (Serializable) headersFallback);
if (CustomTabActivityHelper.isAvailable(activity)) {
intent = new Intent(activity, ChromeCustomTabsActivity.class);
}
// check for webview fallback
else if (!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("options", optionsFallback);
else
extras.putSerializable("options", (new InAppBrowserOptions()).getHashMap());
intent = new Intent(activity, InAppBrowserActivity.class);
}
if (intent != null) {
intent.putExtras(extras);
activity.startActivity(intent);
result.success(true);
return;
}
result.error(LOG_TAG, "No WebView fallback declared.", null);
}
public void dispose() {
channel.setMethodCallHandler(null);
}
}
...@@ -38,6 +38,9 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { ...@@ -38,6 +38,9 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
public final MethodChannel channel; public final MethodChannel channel;
public FlutterWebView(BinaryMessenger messenger, final Context context, int id, HashMap<String, Object> params, View containerView) { public FlutterWebView(BinaryMessenger messenger, final Context context, int id, HashMap<String, Object> params, View containerView) {
channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_inappwebview_" + id);
channel.setMethodCallHandler(this);
DisplayListenerProxy displayListenerProxy = new DisplayListenerProxy(); DisplayListenerProxy displayListenerProxy = new DisplayListenerProxy();
DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
displayListenerProxy.onPreWebViewInitialization(displayManager); displayListenerProxy.onPreWebViewInitialization(displayManager);
...@@ -70,9 +73,6 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { ...@@ -70,9 +73,6 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
webView.prepare(); webView.prepare();
channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_inappwebview_" + id);
channel.setMethodCallHandler(this);
if (initialFile != null) { if (initialFile != null) {
try { try {
initialUrl = Util.getUrlAsset(initialFile); initialUrl = Util.getUrlAsset(initialFile);
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package com.pichillilorenzo.flutter_inappwebview;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Parcelable;
import android.provider.Browser;
import android.net.Uri;
import android.os.Bundle;
import android.webkit.MimeTypeMap;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.util.Log;
import androidx.annotation.RequiresApi;
import com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ChromeCustomTabsActivity;
import com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.CustomTabActivityHelper;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
/**
* InAppBrowser
*/
public class InAppBrowser implements MethodChannel.MethodCallHandler {
public MethodChannel channel;
public Map<String, InAppBrowserActivity> webViewActivities = new HashMap<>();
public Map<String, ChromeCustomTabsActivity> chromeCustomTabsActivities = new HashMap<>();
protected static final String LOG_TAG = "IABFlutterPlugin";
public InAppBrowser(BinaryMessenger messenger) {
channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_inappbrowser");
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(final MethodCall call, final Result result) {
String source;
String urlFile;
final Activity activity = Shared.activity;
final String uuid = (String) call.argument("uuid");
switch (call.method) {
case "open":
boolean isData = (boolean) call.argument("isData");
if (!isData) {
final String url_final = (String) call.argument("url");
final boolean useChromeSafariBrowser = (boolean) call.argument("useChromeSafariBrowser");
final Map<String, String> headers = (Map<String, String>) call.argument("headers");
Log.d(LOG_TAG, "use Chrome Custom Tabs = " + useChromeSafariBrowser);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (useChromeSafariBrowser) {
final String uuidFallback = (String) call.argument("uuidFallback");
final HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
final HashMap<String, Object> optionsFallback = (HashMap<String, Object>) call.argument("optionsFallback");
open(activity, uuid, uuidFallback, url_final, options, headers, true, optionsFallback, result);
} else {
String url = url_final;
final HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
final boolean isLocalFile = (boolean) call.argument("isLocalFile");
final boolean openWithSystemBrowser = (boolean) call.argument("openWithSystemBrowser");
if (isLocalFile) {
// check if the asset file exists
try {
url = Util.getUrlAsset(url);
} catch (IOException e) {
e.printStackTrace();
result.error(LOG_TAG, url + " asset file cannot be found!", e);
return;
}
}
// SYSTEM
if (openWithSystemBrowser) {
Log.d(LOG_TAG, "in system");
openExternal(activity, url, result);
} else {
//Load the dialer
if (url.startsWith(WebView.SCHEME_TEL)) {
try {
Log.d(LOG_TAG, "loading in dialer");
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url));
activity.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
}
}
// load in InAppBrowser
else {
Log.d(LOG_TAG, "loading in InAppBrowser");
open(activity, uuid, null, url, options, headers, false, null, result);
}
}
}
}
});
}
else {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
String data = (String) call.argument("data");
String mimeType = (String) call.argument("mimeType");
String encoding = (String) call.argument("encoding");
String baseUrl = (String) call.argument("baseUrl");
String historyUrl = (String) call.argument("historyUrl");
openData(activity, uuid, options, data, mimeType, encoding, baseUrl, historyUrl);
result.success(true);
}
});
}
break;
case "getUrl":
result.success(getUrl(uuid));
break;
case "getTitle":
result.success(getTitle(uuid));
break;
case "getProgress":
result.success(getProgress(uuid));
break;
case "loadUrl":
loadUrl(uuid, (String) call.argument("url"), (Map<String, String>) call.argument("headers"), result);
break;
case "postUrl":
postUrl(uuid, (String) call.argument("url"), (byte[]) call.argument("postData"), result);
break;
case "loadData":
{
String data = (String) call.argument("data");
String mimeType = (String) call.argument("mimeType");
String encoding = (String) call.argument("encoding");
String baseUrl = (String) call.argument("baseUrl");
String historyUrl = (String) call.argument("historyUrl");
loadData(uuid, data, mimeType, encoding, baseUrl, historyUrl, result);
}
break;
case "loadFile":
loadFile(uuid, (String) call.argument("url"), (Map<String, String>) call.argument("headers"), result);
break;
case "close":
close(activity, uuid, result);
break;
case "evaluateJavascript":
source = (String) call.argument("source");
evaluateJavascript(uuid, source, result);
break;
case "injectJavascriptFileFromUrl":
urlFile = (String) call.argument("urlFile");
injectJavascriptFileFromUrl(uuid, urlFile);
result.success(true);
break;
case "injectCSSCode":
source = (String) call.argument("source");
injectCSSCode(uuid, source);
result.success(true);
break;
case "injectCSSFileFromUrl":
urlFile = (String) call.argument("urlFile");
injectCSSFileFromUrl(uuid, urlFile);
result.success(true);
break;
case "show":
show(uuid);
result.success(true);
break;
case "hide":
hide(uuid);
result.success(true);
break;
case "reload":
reload(uuid);
result.success(true);
break;
case "goBack":
goBack(uuid);
result.success(true);
break;
case "canGoBack":
result.success(canGoBack(uuid));
break;
case "goForward":
goForward(uuid);
result.success(true);
break;
case "canGoForward":
result.success(canGoForward(uuid));
break;
case "goBackOrForward":
goBackOrForward(uuid, (Integer) call.argument("steps"));
result.success(true);
break;
case "canGoBackOrForward":
result.success(canGoBackOrForward(uuid, (Integer) call.argument("steps")));
break;
case "stopLoading":
stopLoading(uuid);
result.success(true);
break;
case "isLoading":
result.success(isLoading(uuid));
break;
case "isHidden":
result.success(isHidden(uuid));
break;
case "takeScreenshot":
result.success(takeScreenshot(uuid));
break;
case "setOptions":
{
String optionsType = (String) call.argument("optionsType");
switch (optionsType){
case "InAppBrowserOptions":
InAppBrowserOptions inAppBrowserOptions = new InAppBrowserOptions();
HashMap<String, Object> inAppBrowserOptionsMap = (HashMap<String, Object>) call.argument("options");
inAppBrowserOptions.parse(inAppBrowserOptionsMap);
setOptions(uuid, inAppBrowserOptions, inAppBrowserOptionsMap);
break;
default:
result.error(LOG_TAG, "Options " + optionsType + " not available.", null);
}
}
result.success(true);
break;
case "getOptions":
result.success(getOptions(uuid));
break;
case "getCopyBackForwardList":
result.success(getCopyBackForwardList(uuid));
break;
case "startSafeBrowsing":
startSafeBrowsing(uuid, result);
break;
case "setSafeBrowsingWhitelist":
setSafeBrowsingWhitelist(uuid, (List<String>) call.argument("hosts"), result);
break;
case "clearCache":
clearCache(uuid);
result.success(true);
break;
case "clearSslPreferences":
clearSslPreferences(uuid);
result.success(true);
break;
case "clearClientCertPreferences":
clearClientCertPreferences(uuid, result);
break;
case "findAllAsync":
String find = (String) call.argument("find");
findAllAsync(uuid, find);
result.success(true);
break;
case "findNext":
Boolean forward = (Boolean) call.argument("forward");
findNext(uuid, forward, result);
break;
case "clearMatches":
clearMatches(uuid, result);
break;
case "scrollTo":
{
Integer x = (Integer) call.argument("x");
Integer y = (Integer) call.argument("y");
scrollTo(uuid, x, y);
}
result.success(true);
break;
case "scrollBy":
{
Integer x = (Integer) call.argument("x");
Integer y = (Integer) call.argument("y");
scrollBy(uuid, x, y);
}
result.success(true);
break;
case "pause":
onPause(uuid);
result.success(true);
break;
case "resume":
onResume(uuid);
result.success(true);
break;
case "pauseTimers":
pauseTimers(uuid);
result.success(true);
break;
case "resumeTimers":
resumeTimers(uuid);
result.success(true);
break;
case "printCurrentPage":
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
printCurrentPage(uuid);
}
result.success(true);
break;
case "getContentHeight":
result.success(getContentHeight(uuid));
break;
case "zoomBy":
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Float zoomFactor = (Float) call.argument("zoomFactor");
zoomBy(uuid, zoomFactor);
}
result.success(true);
break;
case "getOriginalUrl":
result.success(getOriginalUrl(uuid));
break;
case "getScale":
result.success(getScale(uuid));
break;
default:
result.notImplemented();
}
}
public void evaluateJavascript(String uuid, String source, final Result result) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.evaluateJavascript(source, result);
} else {
Log.d(LOG_TAG, "webView is null");
}
}
public void injectJavascriptFileFromUrl(String uuid, String urlFile) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectJavascriptFileFromUrl(urlFile);
}
}
public void injectCSSCode(String uuid, String source) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectCSSCode(source);
}
}
public void injectCSSFileFromUrl(String uuid, String urlFile) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectCSSFileFromUrl(urlFile);
}
}
public static String getMimeType(String url) {
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
return type;
}
/**
* 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(Activity activity, String url, Result result) {
try {
Intent intent;
intent = new Intent(Intent.ACTION_VIEW);
// Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
// Adding the MIME type to http: URLs causes them to not be handled by the downloader.
Uri uri = Uri.parse(url);
if ("file".equals(uri.getScheme())) {
intent.setDataAndType(uri, getMimeType(url));
} else {
intent.setData(uri);
}
intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName());
// CB-10795: Avoid circular loops by preventing it from opening in the current app
this.openExternalExcludeCurrentApp(activity, 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, url + " cannot be opened: " + e.toString());
result.error(LOG_TAG, url + " cannot be opened!", null);
}
}
/**
* Opens the intent, providing a chooser that excludes the current app to avoid
* circular loops.
*/
public void openExternalExcludeCurrentApp(Activity activity, Intent intent) {
String currentPackage = activity.getPackageName();
boolean hasCurrentPackage = false;
PackageManager pm = activity.getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
ArrayList<Intent> targetIntents = new ArrayList<Intent>();
for (ResolveInfo ri : activities) {
if (!currentPackage.equals(ri.activityInfo.packageName)) {
Intent targetIntent = (Intent) intent.clone();
targetIntent.setPackage(ri.activityInfo.packageName);
targetIntents.add(targetIntent);
} else {
hasCurrentPackage = true;
}
}
// If the current app package isn't a target for this URL, then use
// the normal launch behavior
if (!hasCurrentPackage || targetIntents.size() == 0) {
activity.startActivity(intent);
}
// If there's only one possible intent, launch it directly
else if (targetIntents.size() == 1) {
activity.startActivity(targetIntents.get(0));
}
// 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[]{}));
activity.startActivity(chooser);
}
}
public void open(Activity activity, String uuid, String uuidFallback, String url, HashMap<String, Object> options, Map<String, String> headers, boolean useChromeSafariBrowser, HashMap<String, Object> optionsFallback, Result result) {
Intent intent = null;
Bundle extras = new Bundle();
extras.putString("fromActivity", activity.getClass().getName());
extras.putString("url", url);
extras.putBoolean("isData", false);
extras.putString("uuid", uuid);
extras.putSerializable("options", options);
extras.putSerializable("headers", (Serializable) headers);
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("options", optionsFallback);
else
extras.putSerializable("options", (new InAppBrowserOptions()).getHashMap());
extras.putSerializable("headers", (Serializable) headers);
intent = new Intent(activity, InAppBrowserActivity.class);
}
// native webview
else if (!useChromeSafariBrowser) {
intent = new Intent(activity, InAppBrowserActivity.class);
}
else {
Log.d(LOG_TAG, "No WebView fallback declared.");
}
if (intent != null) {
intent.putExtras(extras);
activity.startActivity(intent);
result.success(true);
return;
}
result.error(LOG_TAG, "No WebView fallback declared.", null);
}
public void openData(Activity activity, String uuid, HashMap<String, Object> options, String data, String mimeType, String encoding, String baseUrl, String historyUrl) {
Intent intent = new Intent(activity, InAppBrowserActivity.class);
Bundle extras = new Bundle();
extras.putBoolean("isData", true);
extras.putString("uuid", uuid);
extras.putSerializable("options", options);
extras.putString("data", data);
extras.putString("mimeType", mimeType);
extras.putString("encoding", encoding);
extras.putString("baseUrl", baseUrl);
extras.putString("historyUrl", historyUrl);
intent.putExtras(extras);
activity.startActivity(intent);
}
public String getUrl(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getUrl();
return null;
}
public String getTitle(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getWebViewTitle();
return null;
}
public Integer getProgress(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getProgress();
return null;
}
public void loadUrl(String uuid, String url, Map<String, String> headers, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
if (headers != null)
inAppBrowserActivity.loadUrl(url, headers, result);
else
inAppBrowserActivity.loadUrl(url, result);
}
}
public void postUrl(String uuid, String url, byte[] postData, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.postUrl(url, postData, result);
}
public void loadData(String uuid, String data, String mimeType, String encoding, String baseUrl, String historyUrl, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.loadData(data, mimeType, encoding, baseUrl, historyUrl, result);
}
public void loadFile(String uuid, String url, Map<String, String> headers, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
if (headers != null)
inAppBrowserActivity.loadFile(url, headers, result);
else
inAppBrowserActivity.loadFile(url, result);
}
}
public void show(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.show();
}
public void hide(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.hide();
}
public void reload(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.reload();
}
public boolean isLoading(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.isLoading();
return false;
}
public boolean isHidden(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.isHidden;
return false;
}
public void stopLoading(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.stopLoading();
}
public void goBack(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.goBack();
}
public boolean canGoBack(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.canGoBack();
return false;
}
public void goForward(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.goForward();
}
public boolean canGoForward(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.canGoForward();
return false;
}
public void goBackOrForward(String uuid, int steps) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.goBackOrForward(steps);
}
public boolean canGoBackOrForward(String uuid, int steps) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.canGoBackOrForward(steps);
return false;
}
public void close(Activity activity, final String uuid, final Result result) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid);
channel.invokeMethod("onExit", obj);
// The JS protects against multiple calls, so this should happen only when
// close() is called by other native code.
if (inAppBrowserActivity == null) {
if (result != null) {
result.success(true);
}
return;
}
inAppBrowserActivity.webView.setWebViewClient(new WebViewClient() {
// NB: wait for about:blank before dismissing
public void onPageFinished(WebView view, String url) {
inAppBrowserActivity.close();
}
});
// NB: From SDK 19: "If you call methods on WebView from any thread
// other than your app's UI thread, it can cause unexpected results."
// http://developer.android.com/guide/webapps/migrating.html#Threads
inAppBrowserActivity.webView.loadUrl("about:blank");
if (result != null) {
result.success(true);
}
}
});
}
else if (result != null) {
result.success(true);
}
}
public byte[] takeScreenshot(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.takeScreenshot();
return null;
}
public void setOptions(String uuid, InAppBrowserOptions options, HashMap<String, Object> optionsMap) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.setOptions(options, optionsMap);
}
public HashMap<String, Object> getOptions(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getOptions();
return null;
}
public HashMap<String, Object> getCopyBackForwardList(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getCopyBackForwardList();
return null;
}
public void startSafeBrowsing(String uuid, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.startSafeBrowsing(result);
result.success(false);
}
public void setSafeBrowsingWhitelist(String uuid, List<String> hosts, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.setSafeBrowsingWhitelist(hosts, result);
result.success(false);
}
public void clearCache(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearCache();
}
public void clearSslPreferences(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearSslPreferences();
}
public void clearClientCertPreferences(String uuid, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearClientCertPreferences(result);
result.success(false);
}
public void findAllAsync(String uuid, String find) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.findAllAsync(find);
}
public void findNext(String uuid, Boolean forward, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.findNext(forward, result);
result.success(false);
}
public void clearMatches(String uuid, Result result) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.clearMatches(result);
result.success(false);
}
public void scrollTo(String uuid, Integer x, Integer y) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.scrollTo(x, y);
}
public void scrollBy(String uuid, Integer x, Integer y) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.scrollBy(x, y);
}
public void onPause(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.onPauseWebView();
}
public void onResume(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.onResumeWebView();
}
public void pauseTimers(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.pauseTimers();
}
public void resumeTimers(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.resumeTimers();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void printCurrentPage(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.printCurrentPage();
}
public Integer getContentHeight(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getContentHeight();
return null;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void zoomBy(String uuid, Float zoomFactor) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
inAppBrowserActivity.zoomBy(zoomFactor);
}
public String getOriginalUrl(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getOriginalUrl();
return null;
}
public Float getScale(String uuid) {
InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null)
return inAppBrowserActivity.getScale();
return null;
}
public void dispose() {
channel.setMethodCallHandler(null);
for ( InAppBrowserActivity activity : webViewActivities.values()) {
activity.dispose();
}
}
}
...@@ -6,11 +6,6 @@ import android.graphics.Canvas; ...@@ -6,11 +6,6 @@ import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Picture; import android.graphics.Picture;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
...@@ -25,6 +20,10 @@ import android.webkit.WebViewClient; ...@@ -25,6 +20,10 @@ import android.webkit.WebViewClient;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.SearchView; import android.widget.SearchView;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView; import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView;
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebViewOptions; import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebViewOptions;
...@@ -34,11 +33,13 @@ import java.util.HashMap; ...@@ -34,11 +33,13 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class InAppBrowserActivity extends AppCompatActivity { public class InAppBrowserActivity extends AppCompatActivity implements MethodChannel.MethodCallHandler {
static final String LOG_TAG = "InAppBrowserActivity"; static final String LOG_TAG = "InAppBrowserActivity";
public MethodChannel channel;
public String uuid; public String uuid;
public InAppWebView webView; public InAppWebView webView;
public ActionBar actionBar; public ActionBar actionBar;
...@@ -54,13 +55,17 @@ public class InAppBrowserActivity extends AppCompatActivity { ...@@ -54,13 +55,17 @@ public class InAppBrowserActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
Bundle b = getIntent().getExtras();
uuid = b.getString("uuid");
channel = new MethodChannel(Shared.messenger, "com.pichillilorenzo/flutter_inappbrowser_" + uuid);
channel.setMethodCallHandler(this);
setContentView(R.layout.activity_web_view); setContentView(R.layout.activity_web_view);
webView = findViewById(R.id.webView); webView = findViewById(R.id.webView);
webView.inAppBrowserActivity = this; webView.inAppBrowserActivity = this;
Bundle b = getIntent().getExtras();
uuid = b.getString("uuid");
fromActivity = b.getString("fromActivity"); fromActivity = b.getString("fromActivity");
HashMap<String, Object> optionsMap = (HashMap<String, Object>) b.getSerializable("options"); HashMap<String, Object> optionsMap = (HashMap<String, Object>) b.getSerializable("options");
...@@ -72,8 +77,6 @@ public class InAppBrowserActivity extends AppCompatActivity { ...@@ -72,8 +77,6 @@ public class InAppBrowserActivity extends AppCompatActivity {
webViewOptions.parse(optionsMap); webViewOptions.parse(optionsMap);
webView.options = webViewOptions; webView.options = webViewOptions;
InAppWebViewFlutterPlugin.inAppBrowser.webViewActivities.put(uuid, this);
actionBar = getSupportActionBar(); actionBar = getSupportActionBar();
prepareView(); prepareView();
...@@ -95,8 +98,238 @@ public class InAppBrowserActivity extends AppCompatActivity { ...@@ -95,8 +98,238 @@ public class InAppBrowserActivity extends AppCompatActivity {
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid); obj.put("uuid", uuid);
InAppWebViewFlutterPlugin.inAppBrowser.channel.invokeMethod("onBrowserCreated", obj); channel.invokeMethod("onBrowserCreated", obj);
}
@Override
public void onMethodCall(final MethodCall call, final MethodChannel.Result result) {
switch (call.method) {
case "getUrl":
result.success(getUrl());
break;
case "getTitle":
result.success(getWebViewTitle());
break;
case "getProgress":
result.success(getProgress());
break;
case "loadUrl":
{
String url = (String) call.argument("url");
Map<String, String> headers = (Map<String, String>) call.argument("headers");
if (headers != null)
loadUrl(url, headers, result);
else
loadUrl(url, result);
}
break;
case "postUrl":
postUrl((String) call.argument("url"), (byte[]) call.argument("postData"), result);
break;
case "loadData":
{
String data = (String) call.argument("data");
String mimeType = (String) call.argument("mimeType");
String encoding = (String) call.argument("encoding");
String baseUrl = (String) call.argument("baseUrl");
String historyUrl = (String) call.argument("historyUrl");
loadData(data, mimeType, encoding, baseUrl, historyUrl, result);
}
break;
case "loadFile":
{
String url = (String) call.argument("url");
Map<String, String> headers = (Map<String, String>) call.argument("headers");
if (headers != null)
loadFile(url, headers, result);
else
loadFile(url, result);
}
break;
case "close":
close(result);
break;
case "evaluateJavascript":
{
String source = (String) call.argument("source");
evaluateJavascript(source, result);
}
break;
case "injectJavascriptFileFromUrl":
{
String urlFile = (String) call.argument("urlFile");
injectJavascriptFileFromUrl(urlFile);
}
result.success(true);
break;
case "injectCSSCode":
{
String source = (String) call.argument("source");
injectCSSCode(source);
}
result.success(true);
break;
case "injectCSSFileFromUrl":
{
String urlFile = (String) call.argument("urlFile");
injectCSSFileFromUrl(urlFile);
}
result.success(true);
break;
case "show":
show();
result.success(true);
break;
case "hide":
hide();
result.success(true);
break;
case "reload":
reload();
result.success(true);
break;
case "goBack":
goBack();
result.success(true);
break;
case "canGoBack":
result.success(canGoBack());
break;
case "goForward":
goForward();
result.success(true);
break;
case "canGoForward":
result.success(canGoForward());
break;
case "goBackOrForward":
goBackOrForward((Integer) call.argument("steps"));
result.success(true);
break;
case "canGoBackOrForward":
result.success(canGoBackOrForward((Integer) call.argument("steps")));
break;
case "stopLoading":
stopLoading();
result.success(true);
break;
case "isLoading":
result.success(isLoading());
break;
case "isHidden":
result.success(isHidden);
break;
case "takeScreenshot":
result.success(takeScreenshot());
break;
case "setOptions":
{
String optionsType = (String) call.argument("optionsType");
switch (optionsType){
case "InAppBrowserOptions":
InAppBrowserOptions inAppBrowserOptions = new InAppBrowserOptions();
HashMap<String, Object> inAppBrowserOptionsMap = (HashMap<String, Object>) call.argument("options");
inAppBrowserOptions.parse(inAppBrowserOptionsMap);
setOptions(inAppBrowserOptions, inAppBrowserOptionsMap);
break;
default:
result.error(LOG_TAG, "Options " + optionsType + " not available.", null);
}
}
result.success(true);
break;
case "getOptions":
result.success(getOptions());
break;
case "getCopyBackForwardList":
result.success(getCopyBackForwardList());
break;
case "startSafeBrowsing":
startSafeBrowsing(result);
break;
case "setSafeBrowsingWhitelist":
setSafeBrowsingWhitelist((List<String>) call.argument("hosts"), result);
break;
case "clearCache":
clearCache();
result.success(true);
break;
case "clearSslPreferences":
clearSslPreferences();
result.success(true);
break;
case "clearClientCertPreferences":
clearClientCertPreferences(result);
break;
case "findAllAsync":
String find = (String) call.argument("find");
findAllAsync(find);
result.success(true);
break;
case "findNext":
Boolean forward = (Boolean) call.argument("forward");
findNext(forward, result);
break;
case "clearMatches":
clearMatches(result);
break;
case "scrollTo":
{
Integer x = (Integer) call.argument("x");
Integer y = (Integer) call.argument("y");
scrollTo(x, y);
}
result.success(true);
break;
case "scrollBy":
{
Integer x = (Integer) call.argument("x");
Integer y = (Integer) call.argument("y");
scrollBy(x, y);
}
result.success(true);
break;
case "pause":
onPauseWebView();
result.success(true);
break;
case "resume":
onResumeWebView();
result.success(true);
break;
case "pauseTimers":
pauseTimers();
result.success(true);
break;
case "resumeTimers":
resumeTimers();
result.success(true);
break;
case "printCurrentPage":
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
printCurrentPage();
}
result.success(true);
break;
case "getContentHeight":
result.success(getContentHeight());
break;
case "zoomBy":
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Float zoomFactor = (Float) call.argument("zoomFactor");
zoomBy(zoomFactor);
}
result.success(true);
break;
case "getOriginalUrl":
result.success(getOriginalUrl());
break;
case "getScale":
result.success(getScale());
break;
default:
result.notImplemented();
}
} }
private void prepareView() { private void prepareView() {
...@@ -259,16 +492,38 @@ public class InAppBrowserActivity extends AppCompatActivity { ...@@ -259,16 +492,38 @@ public class InAppBrowserActivity extends AppCompatActivity {
if (canGoBack()) if (canGoBack())
goBack(); goBack();
else if (options.closeOnCannotGoBack) else if (options.closeOnCannotGoBack)
InAppWebViewFlutterPlugin.inAppBrowser.close(this, uuid, null); close(null);
return true; return true;
} }
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
} }
public void close() { public void close(final MethodChannel.Result result) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onExit", obj);
webView.setWebViewClient(new WebViewClient() {
// NB: wait for about:blank before dismissing
public void onPageFinished(WebView view, String url) {
hide(); hide();
finish(); finish();
} }
});
// NB: From SDK 19: "If you call methods on WebView from any thread
// other than your app's UI thread, it can cause unexpected results."
// http://developer.android.com/guide/webapps/migrating.html#Threads
webView.loadUrl("about:blank");
if (result != null) {
result.success(true);
}
}
});
}
public void reload() { public void reload() {
if (webView != null) if (webView != null)
...@@ -358,7 +613,7 @@ public class InAppBrowserActivity extends AppCompatActivity { ...@@ -358,7 +613,7 @@ public class InAppBrowserActivity extends AppCompatActivity {
} }
public void closeButtonClicked(MenuItem item) { public void closeButtonClicked(MenuItem item) {
InAppWebViewFlutterPlugin.inAppBrowser.close(this, uuid, null); close(null);
} }
public byte[] takeScreenshot() { public byte[] takeScreenshot() {
...@@ -525,20 +780,6 @@ public class InAppBrowserActivity extends AppCompatActivity { ...@@ -525,20 +780,6 @@ public class InAppBrowserActivity extends AppCompatActivity {
result.success(false); result.success(false);
} }
public void dispose() {
if (webView != null) {
webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
webView.dispose();
webView.destroy();
webView = null;
}
});
webView.loadUrl("about:blank");
}
}
public void scrollTo(Integer x, Integer y) { public void scrollTo(Integer x, Integer y) {
if (webView != null) if (webView != null)
webView.scrollTo(x, y); webView.scrollTo(x, y);
...@@ -598,4 +839,25 @@ public class InAppBrowserActivity extends AppCompatActivity { ...@@ -598,4 +839,25 @@ public class InAppBrowserActivity extends AppCompatActivity {
return webView.getUpdatedScale(); return webView.getUpdatedScale();
return null; return null;
} }
public void dispose() {
channel.setMethodCallHandler(null);
if (webView != null) {
webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
webView.dispose();
webView.destroy();
webView = null;
}
});
webView.loadUrl("about:blank");
}
}
@Override
public void onDestroy() {
dispose();
super.onDestroy();
}
} }
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package com.pichillilorenzo.flutter_inappwebview;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Parcelable;
import android.provider.Browser;
import android.net.Uri;
import android.os.Bundle;
import android.webkit.MimeTypeMap;
import android.util.Log;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.Result;
/**
* InAppBrowserManager
*/
public class InAppBrowserManager implements MethodChannel.MethodCallHandler {
public MethodChannel channel;
protected static final String LOG_TAG = "InAppBrowserManager";
public InAppBrowserManager(BinaryMessenger messenger) {
channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_inappbrowser");
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(final MethodCall call, final Result result) {
final Activity activity = Shared.activity;
final String uuid = (String) call.argument("uuid");
switch (call.method) {
case "openUrl":
{
String url = (String) call.argument("url");
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
Map<String, String> headers = (Map<String, String>) call.argument("headers");
openUrl(activity, uuid, url, options, headers);
}
result.success(true);
break;
case "openFile":
{
String url = (String) call.argument("url");
try {
url = Util.getUrlAsset(url);
} catch (IOException e) {
e.printStackTrace();
result.error(LOG_TAG, url + " asset file cannot be found!", e);
return;
}
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
Map<String, String> headers = (Map<String, String>) call.argument("headers");
openUrl(activity, uuid, url, options, headers);
}
result.success(true);
break;
case "openData":
{
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
String data = (String) call.argument("data");
String mimeType = (String) call.argument("mimeType");
String encoding = (String) call.argument("encoding");
String baseUrl = (String) call.argument("baseUrl");
String historyUrl = (String) call.argument("historyUrl");
openData(activity, uuid, options, data, mimeType, encoding, baseUrl, historyUrl);
}
result.success(true);
break;
case "openWithSystemBrowser":
{
String url = (String) call.argument("url");
openWithSystemBrowser(activity, url, result);
}
break;
default:
result.notImplemented();
}
}
public static String getMimeType(String url) {
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
return type;
}
/**
* Display a new browser with the specified URL.
*
* @param url the url to load.
* @param result
* @return "" if ok, or error message.
*/
public void openWithSystemBrowser(Activity activity, String url, Result result) {
try {
Intent intent;
intent = new Intent(Intent.ACTION_VIEW);
// Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
// Adding the MIME type to http: URLs causes them to not be handled by the downloader.
Uri uri = Uri.parse(url);
if ("file".equals(uri.getScheme())) {
intent.setDataAndType(uri, getMimeType(url));
} else {
intent.setData(uri);
}
intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName());
// CB-10795: Avoid circular loops by preventing it from opening in the current app
this.openExternalExcludeCurrentApp(activity, 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, url + " cannot be opened: " + e.toString());
result.error(LOG_TAG, url + " cannot be opened!", null);
}
}
/**
* Opens the intent, providing a chooser that excludes the current app to avoid
* circular loops.
*/
public void openExternalExcludeCurrentApp(Activity activity, Intent intent) {
String currentPackage = activity.getPackageName();
boolean hasCurrentPackage = false;
PackageManager pm = activity.getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
ArrayList<Intent> targetIntents = new ArrayList<Intent>();
for (ResolveInfo ri : activities) {
if (!currentPackage.equals(ri.activityInfo.packageName)) {
Intent targetIntent = (Intent) intent.clone();
targetIntent.setPackage(ri.activityInfo.packageName);
targetIntents.add(targetIntent);
} else {
hasCurrentPackage = true;
}
}
// If the current app package isn't a target for this URL, then use
// the normal launch behavior
if (!hasCurrentPackage || targetIntents.size() == 0) {
activity.startActivity(intent);
}
// If there's only one possible intent, launch it directly
else if (targetIntents.size() == 1) {
activity.startActivity(targetIntents.get(0));
}
// 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[]{}));
activity.startActivity(chooser);
}
}
public void openUrl(Activity activity, String uuid, String url, HashMap<String, Object> options, Map<String, String> headers) {
Bundle extras = new Bundle();
extras.putString("fromActivity", activity.getClass().getName());
extras.putString("url", url);
extras.putBoolean("isData", false);
extras.putString("uuid", uuid);
extras.putSerializable("options", options);
extras.putSerializable("headers", (Serializable) headers);
startInAppBrowserActivity(activity, extras);
}
public void openData(Activity activity, String uuid, HashMap<String, Object> options, String data, String mimeType, String encoding, String baseUrl, String historyUrl) {
Bundle extras = new Bundle();
extras.putBoolean("isData", true);
extras.putString("uuid", uuid);
extras.putSerializable("options", options);
extras.putString("data", data);
extras.putString("mimeType", mimeType);
extras.putString("encoding", encoding);
extras.putString("baseUrl", baseUrl);
extras.putString("historyUrl", historyUrl);
startInAppBrowserActivity(activity, extras);
}
public void startInAppBrowserActivity(Activity activity, Bundle extras) {
Intent intent = new Intent(activity, InAppBrowserActivity.class);
if (extras != null)
intent.putExtras(extras);
activity.startActivity(intent);
}
public void dispose() {
channel.setMethodCallHandler(null);
}
}
package com.pichillilorenzo.flutter_inappwebview.InAppWebView; package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
...@@ -21,13 +19,8 @@ import android.webkit.WebBackForwardList; ...@@ -21,13 +19,8 @@ import android.webkit.WebBackForwardList;
import android.webkit.WebHistoryItem; import android.webkit.WebHistoryItem;
import android.webkit.WebSettings; import android.webkit.WebSettings;
import android.webkit.WebStorage; import android.webkit.WebStorage;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ListView;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlocker; import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlocker;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerAction; import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerAction;
...@@ -37,7 +30,6 @@ import com.pichillilorenzo.flutter_inappwebview.FlutterWebView; ...@@ -37,7 +30,6 @@ import com.pichillilorenzo.flutter_inappwebview.FlutterWebView;
import com.pichillilorenzo.flutter_inappwebview.InAppBrowserActivity; import com.pichillilorenzo.flutter_inappwebview.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.JavaScriptBridgeInterface; import com.pichillilorenzo.flutter_inappwebview.JavaScriptBridgeInterface;
import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.Shared; import com.pichillilorenzo.flutter_inappwebview.Shared;
import com.pichillilorenzo.flutter_inappwebview.Util; import com.pichillilorenzo.flutter_inappwebview.Util;
...@@ -50,7 +42,6 @@ import java.util.Map; ...@@ -50,7 +42,6 @@ import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import static com.pichillilorenzo.flutter_inappwebview.InAppWebView.PreferredContentModeOptionType.fromValue; import static com.pichillilorenzo.flutter_inappwebview.InAppWebView.PreferredContentModeOptionType.fromValue;
...@@ -61,6 +52,7 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -61,6 +52,7 @@ final public class InAppWebView extends InputAwareWebView {
public InAppBrowserActivity inAppBrowserActivity; public InAppBrowserActivity inAppBrowserActivity;
public FlutterWebView flutterWebView; public FlutterWebView flutterWebView;
public MethodChannel channel;
public int id; public int id;
public InAppWebViewClient inAppWebViewClient; public InAppWebViewClient inAppWebViewClient;
public InAppWebViewChromeClient inAppWebViewChromeClient; public InAppWebViewChromeClient inAppWebViewChromeClient;
...@@ -123,7 +115,7 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -123,7 +115,7 @@ final public class InAppWebView extends InputAwareWebView {
static final String interceptAjaxRequestsJS = "(function(ajax) {" + static final String interceptAjaxRequestsJS = "(function(ajax) {" +
" var send = ajax.prototype.send;" + " var send = ajax.prototype.send;" +
" var open = ajax.prototype.open;" + " var openUrl = ajax.prototype.openUrl;" +
" var setRequestHeader = ajax.prototype.setRequestHeader;" + " var setRequestHeader = ajax.prototype.setRequestHeader;" +
" ajax.prototype._flutter_inappwebview_url = null;" + " ajax.prototype._flutter_inappwebview_url = null;" +
" ajax.prototype._flutter_inappwebview_method = null;" + " ajax.prototype._flutter_inappwebview_method = null;" +
...@@ -156,7 +148,7 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -156,7 +148,7 @@ final public class InAppWebView extends InputAwareWebView {
" }" + " }" +
" callback(null);" + " callback(null);" +
" };" + " };" +
" ajax.prototype.open = function(method, url, isAsync, user, password) {" + " ajax.prototype.openUrl = function(method, url, isAsync, user, password) {" +
" isAsync = (isAsync != null) ? isAsync : true;" + " isAsync = (isAsync != null) ? isAsync : true;" +
" this._flutter_inappwebview_url = url;" + " this._flutter_inappwebview_url = url;" +
" this._flutter_inappwebview_method = method;" + " this._flutter_inappwebview_method = method;" +
...@@ -164,7 +156,7 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -164,7 +156,7 @@ final public class InAppWebView extends InputAwareWebView {
" this._flutter_inappwebview_user = user;" + " this._flutter_inappwebview_user = user;" +
" this._flutter_inappwebview_password = password;" + " this._flutter_inappwebview_password = password;" +
" this._flutter_inappwebview_request_headers = {};" + " this._flutter_inappwebview_request_headers = {};" +
" open.call(this, method, url, isAsync, user, password);" + " openUrl.call(this, method, url, isAsync, user, password);" +
" };" + " };" +
" ajax.prototype.setRequestHeader = function(header, value) {" + " ajax.prototype.setRequestHeader = function(header, value) {" +
" this._flutter_inappwebview_request_headers[header] = value;" + " this._flutter_inappwebview_request_headers[header] = value;" +
...@@ -319,7 +311,7 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -319,7 +311,7 @@ final public class InAppWebView extends InputAwareWebView {
" };" + " };" +
" if ((self._flutter_inappwebview_method != result.method && result.method != null) || (self._flutter_inappwebview_url != result.url && result.url != null)) {" + " if ((self._flutter_inappwebview_method != result.method && result.method != null) || (self._flutter_inappwebview_url != result.url && result.url != null)) {" +
" self.abort();" + " self.abort();" +
" self.open(result.method, result.url, result.isAsync, result.user, result.password);" + " self.openUrl(result.method, result.url, result.isAsync, result.user, result.password);" +
" return;" + " return;" +
" }" + " }" +
" }" + " }" +
...@@ -532,6 +524,7 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -532,6 +524,7 @@ final public class InAppWebView extends InputAwareWebView {
this.inAppBrowserActivity = (InAppBrowserActivity) obj; this.inAppBrowserActivity = (InAppBrowserActivity) obj;
else if (obj instanceof FlutterWebView) else if (obj instanceof FlutterWebView)
this.flutterWebView = (FlutterWebView) obj; this.flutterWebView = (FlutterWebView) obj;
this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel;
this.id = id; this.id = id;
this.options = options; this.options = options;
} }
...@@ -689,7 +682,7 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -689,7 +682,7 @@ final public class InAppWebView extends InputAwareWebView {
obj.put("activeMatchOrdinal", activeMatchOrdinal); obj.put("activeMatchOrdinal", activeMatchOrdinal);
obj.put("numberOfMatches", numberOfMatches); obj.put("numberOfMatches", numberOfMatches);
obj.put("isDoneCounting", isDoneCounting); obj.put("isDoneCounting", isDoneCounting);
getChannel().invokeMethod("onFindResultReceived", obj); channel.invokeMethod("onFindResultReceived", obj);
} }
}); });
...@@ -1264,11 +1257,7 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -1264,11 +1257,7 @@ final public class InAppWebView extends InputAwareWebView {
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("x", x); obj.put("x", x);
obj.put("y", y); obj.put("y", y);
getChannel().invokeMethod("onScrollChanged", obj); channel.invokeMethod("onScrollChanged", obj);
}
private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppWebViewFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
} }
public void startSafeBrowsing(final MethodChannel.Result result) { public void startSafeBrowsing(final MethodChannel.Result result) {
...@@ -1304,7 +1293,7 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -1304,7 +1293,7 @@ final public class InAppWebView extends InputAwareWebView {
if (inAppBrowserActivity != null) if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url); obj.put("url", url);
getChannel().invokeMethod("onDownloadStart", obj); channel.invokeMethod("onDownloadStart", obj);
} }
} }
......
...@@ -2,7 +2,6 @@ package com.pichillilorenzo.flutter_inappwebview.InAppWebView; ...@@ -2,7 +2,6 @@ package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
...@@ -33,7 +32,6 @@ import com.pichillilorenzo.flutter_inappwebview.InAppBrowserActivity; ...@@ -33,7 +32,6 @@ import com.pichillilorenzo.flutter_inappwebview.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.R; import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.Shared; import com.pichillilorenzo.flutter_inappwebview.Shared;
import com.pichillilorenzo.flutter_inappwebview.Util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
...@@ -52,6 +50,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -52,6 +50,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
protected static final String LOG_TAG = "IABWebChromeClient"; protected static final String LOG_TAG = "IABWebChromeClient";
private FlutterWebView flutterWebView; private FlutterWebView flutterWebView;
private InAppBrowserActivity inAppBrowserActivity; private InAppBrowserActivity inAppBrowserActivity;
public MethodChannel channel;
private ValueCallback<Uri> mUploadMessage; private ValueCallback<Uri> mUploadMessage;
private final static int FILECHOOSER_RESULTCODE = 1; private final static int FILECHOOSER_RESULTCODE = 1;
...@@ -65,6 +64,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -65,6 +64,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
this.inAppBrowserActivity = (InAppBrowserActivity) obj; this.inAppBrowserActivity = (InAppBrowserActivity) obj;
else if (obj instanceof FlutterWebView) else if (obj instanceof FlutterWebView)
this.flutterWebView = (FlutterWebView) obj; this.flutterWebView = (FlutterWebView) obj;
this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel;
if (Shared.registrar != null) if (Shared.registrar != null)
Shared.registrar.addActivityResultListener(this); Shared.registrar.addActivityResultListener(this);
...@@ -121,7 +121,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -121,7 +121,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("message", message); obj.put("message", message);
getChannel().invokeMethod("onJsAlert", obj, new MethodChannel.Result() { channel.invokeMethod("onJsAlert", obj, new MethodChannel.Result() {
@Override @Override
public void success(Object response) { public void success(Object response) {
String responseMessage = null; String responseMessage = null;
...@@ -204,7 +204,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -204,7 +204,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("message", message); obj.put("message", message);
getChannel().invokeMethod("onJsConfirm", obj, new MethodChannel.Result() { channel.invokeMethod("onJsConfirm", obj, new MethodChannel.Result() {
@Override @Override
public void success(Object response) { public void success(Object response) {
String responseMessage = null; String responseMessage = null;
...@@ -301,7 +301,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -301,7 +301,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
obj.put("message", message); obj.put("message", message);
obj.put("defaultValue", defaultValue); obj.put("defaultValue", defaultValue);
getChannel().invokeMethod("onJsPrompt", obj, new MethodChannel.Result() { channel.invokeMethod("onJsPrompt", obj, new MethodChannel.Result() {
@Override @Override
public void success(Object response) { public void success(Object response) {
String responseMessage = null; String responseMessage = null;
...@@ -433,7 +433,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -433,7 +433,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
super.onPageStarted(v, url, favicon); super.onPageStarted(v, url, favicon);
obj.put("url", url); obj.put("url", url);
getChannel().invokeMethod("onCreateWindow", obj); channel.invokeMethod("onCreateWindow", obj);
// stop webview loading // stop webview loading
v.stopLoading(); v.stopLoading();
...@@ -449,7 +449,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -449,7 +449,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
} }
obj.put("url", data); obj.put("url", data);
getChannel().invokeMethod("onCreateWindow", obj); channel.invokeMethod("onCreateWindow", obj);
return false; return false;
} }
...@@ -459,7 +459,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -459,7 +459,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
if (inAppBrowserActivity != null) if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("origin", origin); obj.put("origin", origin);
getChannel().invokeMethod("onGeolocationPermissionsShowPrompt", obj, new MethodChannel.Result() { channel.invokeMethod("onGeolocationPermissionsShowPrompt", obj, new MethodChannel.Result() {
@Override @Override
public void success(Object o) { public void success(Object o) {
Map<String, Object> response = (Map<String, Object>) o; Map<String, Object> response = (Map<String, Object>) o;
...@@ -486,7 +486,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -486,7 +486,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null) if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
getChannel().invokeMethod("onGeolocationPermissionsHidePrompt", obj); channel.invokeMethod("onGeolocationPermissionsHidePrompt", obj);
} }
@Override @Override
...@@ -496,7 +496,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -496,7 +496,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("message", consoleMessage.message()); obj.put("message", consoleMessage.message());
obj.put("messageLevel", consoleMessage.messageLevel().ordinal()); obj.put("messageLevel", consoleMessage.messageLevel().ordinal());
getChannel().invokeMethod("onConsoleMessage", obj); channel.invokeMethod("onConsoleMessage", obj);
return true; return true;
} }
...@@ -518,7 +518,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -518,7 +518,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
if (inAppBrowserActivity != null) if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("progress", progress); obj.put("progress", progress);
getChannel().invokeMethod("onProgressChanged", obj); channel.invokeMethod("onProgressChanged", obj);
super.onProgressChanged(view, progress); super.onProgressChanged(view, progress);
} }
...@@ -608,7 +608,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -608,7 +608,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("origin", request.getOrigin().toString()); obj.put("origin", request.getOrigin().toString());
obj.put("resources", Arrays.asList(request.getResources())); obj.put("resources", Arrays.asList(request.getResources()));
getChannel().invokeMethod("onPermissionRequest", obj, new MethodChannel.Result() { channel.invokeMethod("onPermissionRequest", obj, new MethodChannel.Result() {
@Override @Override
public void success(Object response) { public void success(Object response) {
if (response != null) { if (response != null) {
...@@ -646,8 +646,4 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR ...@@ -646,8 +646,4 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}); });
} }
} }
private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppWebViewFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
}
} }
...@@ -17,7 +17,6 @@ import android.webkit.SslErrorHandler; ...@@ -17,7 +17,6 @@ import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
import android.webkit.WebResourceRequest; import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse; import android.webkit.WebResourceResponse;
import android.webkit.WebStorage;
import android.webkit.WebView; import android.webkit.WebView;
import android.webkit.WebViewClient; import android.webkit.WebViewClient;
...@@ -53,6 +52,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -53,6 +52,7 @@ public class InAppWebViewClient extends WebViewClient {
protected static final String LOG_TAG = "IABWebViewClient"; protected static final String LOG_TAG = "IABWebViewClient";
private FlutterWebView flutterWebView; private FlutterWebView flutterWebView;
private InAppBrowserActivity inAppBrowserActivity; private InAppBrowserActivity inAppBrowserActivity;
public MethodChannel channel;
private static int previousAuthRequestFailureCount = 0; private static int previousAuthRequestFailureCount = 0;
private static List<Credential> credentialsProposed = null; private static List<Credential> credentialsProposed = null;
...@@ -62,6 +62,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -62,6 +62,7 @@ public class InAppWebViewClient extends WebViewClient {
this.inAppBrowserActivity = (InAppBrowserActivity) obj; this.inAppBrowserActivity = (InAppBrowserActivity) obj;
else if (obj instanceof FlutterWebView) else if (obj instanceof FlutterWebView)
this.flutterWebView = (FlutterWebView) obj; this.flutterWebView = (FlutterWebView) obj;
this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel;
} }
@TargetApi(Build.VERSION_CODES.LOLLIPOP) @TargetApi(Build.VERSION_CODES.LOLLIPOP)
...@@ -125,7 +126,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -125,7 +126,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("androidHasGesture", hasGesture); obj.put("androidHasGesture", hasGesture);
obj.put("androidIsRedirect", isRedirect); obj.put("androidIsRedirect", isRedirect);
obj.put("iosWKNavigationType", null); obj.put("iosWKNavigationType", null);
getChannel().invokeMethod("shouldOverrideUrlLoading", obj, new MethodChannel.Result() { channel.invokeMethod("shouldOverrideUrlLoading", obj, new MethodChannel.Result() {
@Override @Override
public void success(Object response) { public void success(Object response) {
if (response != null) { if (response != null) {
...@@ -199,7 +200,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -199,7 +200,7 @@ public class InAppWebViewClient extends WebViewClient {
if (inAppBrowserActivity != null) if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url); obj.put("url", url);
getChannel().invokeMethod("onLoadStart", obj); channel.invokeMethod("onLoadStart", obj);
} }
...@@ -212,7 +213,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -212,7 +213,7 @@ public class InAppWebViewClient extends WebViewClient {
previousAuthRequestFailureCount = 0; previousAuthRequestFailureCount = 0;
credentialsProposed = null; credentialsProposed = null;
// CB-10395 InAppBrowser's WebView not storing cookies reliable to local device storage // CB-10395 InAppBrowserManager's WebView not storing cookies reliable to local device storage
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().flush(); CookieManager.getInstance().flush();
} else { } else {
...@@ -235,7 +236,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -235,7 +236,7 @@ public class InAppWebViewClient extends WebViewClient {
if (inAppBrowserActivity != null) if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url); obj.put("url", url);
getChannel().invokeMethod("onLoadStop", obj); channel.invokeMethod("onLoadStop", obj);
} }
@Override @Override
...@@ -245,7 +246,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -245,7 +246,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("uuid", inAppBrowserActivity.uuid); obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url); obj.put("url", url);
obj.put("androidIsReload", isReload); obj.put("androidIsReload", isReload);
getChannel().invokeMethod("onUpdateVisitedHistory", obj); channel.invokeMethod("onUpdateVisitedHistory", obj);
super.doUpdateVisitedHistory(view, url, isReload); super.doUpdateVisitedHistory(view, url, isReload);
} }
...@@ -264,7 +265,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -264,7 +265,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("url", failingUrl); obj.put("url", failingUrl);
obj.put("code", errorCode); obj.put("code", errorCode);
obj.put("message", description); obj.put("message", description);
getChannel().invokeMethod("onLoadError", obj); channel.invokeMethod("onLoadError", obj);
} }
@RequiresApi(api = Build.VERSION_CODES.M) @RequiresApi(api = Build.VERSION_CODES.M)
...@@ -278,7 +279,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -278,7 +279,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("url", request.getUrl().toString()); obj.put("url", request.getUrl().toString());
obj.put("statusCode", errorResponse.getStatusCode()); obj.put("statusCode", errorResponse.getStatusCode());
obj.put("description", errorResponse.getReasonPhrase()); obj.put("description", errorResponse.getReasonPhrase());
getChannel().invokeMethod("onLoadHttpError", obj); channel.invokeMethod("onLoadHttpError", obj);
} }
} }
...@@ -316,7 +317,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -316,7 +317,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("port", port); obj.put("port", port);
obj.put("previousFailureCount", previousAuthRequestFailureCount); obj.put("previousFailureCount", previousAuthRequestFailureCount);
getChannel().invokeMethod("onReceivedHttpAuthRequest", obj, new MethodChannel.Result() { channel.invokeMethod("onReceivedHttpAuthRequest", obj, new MethodChannel.Result() {
@Override @Override
public void success(Object response) { public void success(Object response) {
if (response != null) { if (response != null) {
...@@ -461,7 +462,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -461,7 +462,7 @@ public class InAppWebViewClient extends WebViewClient {
Log.d(LOG_TAG, obj.toString()); Log.d(LOG_TAG, obj.toString());
getChannel().invokeMethod("onReceivedServerTrustAuthRequest", obj, new MethodChannel.Result() { channel.invokeMethod("onReceivedServerTrustAuthRequest", obj, new MethodChannel.Result() {
@Override @Override
public void success(Object response) { public void success(Object response) {
if (response != null) { if (response != null) {
...@@ -520,7 +521,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -520,7 +521,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("realm", realm); obj.put("realm", realm);
obj.put("port", request.getPort()); obj.put("port", request.getPort());
getChannel().invokeMethod("onReceivedClientCertRequest", obj, new MethodChannel.Result() { channel.invokeMethod("onReceivedClientCertRequest", obj, new MethodChannel.Result() {
@Override @Override
public void success(Object response) { public void success(Object response) {
if (response != null) { if (response != null) {
...@@ -579,7 +580,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -579,7 +580,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("url", request.getUrl().toString()); obj.put("url", request.getUrl().toString());
obj.put("threatType", threatType); obj.put("threatType", threatType);
getChannel().invokeMethod("onSafeBrowsingHit", obj, new MethodChannel.Result() { channel.invokeMethod("onSafeBrowsingHit", obj, new MethodChannel.Result() {
@Override @Override
public void success(Object response) { public void success(Object response) {
if (response != null) { if (response != null) {
...@@ -652,7 +653,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -652,7 +653,7 @@ public class InAppWebViewClient extends WebViewClient {
Util.WaitFlutterResult flutterResult; Util.WaitFlutterResult flutterResult;
try { try {
flutterResult = Util.invokeMethodAndWait(getChannel(), "onLoadResourceCustomScheme", obj); flutterResult = Util.invokeMethodAndWait(channel, "onLoadResourceCustomScheme", obj);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
Log.e(LOG_TAG, e.getMessage()); Log.e(LOG_TAG, e.getMessage());
...@@ -701,9 +702,4 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -701,9 +702,4 @@ public class InAppWebViewClient extends WebViewClient {
public void onUnhandledKeyEvent(WebView view, KeyEvent event) { public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
} }
private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppWebViewFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
}
} }
...@@ -4,7 +4,6 @@ import android.app.Activity; ...@@ -4,7 +4,6 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.util.Log;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityAware;
...@@ -19,7 +18,8 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware { ...@@ -19,7 +18,8 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
protected static final String LOG_TAG = "InAppWebViewFlutterPL"; protected static final String LOG_TAG = "InAppWebViewFlutterPL";
public static InAppBrowser inAppBrowser; public static InAppBrowserManager inAppBrowserManager;
public static ChromeSafariBrowserManager chromeSafariBrowserManager;
public static InAppWebViewStatic inAppWebViewStatic; public static InAppWebViewStatic inAppWebViewStatic;
public static MyCookieManager myCookieManager; public static MyCookieManager myCookieManager;
public static CredentialDatabaseHandler credentialDatabaseHandler; public static CredentialDatabaseHandler credentialDatabaseHandler;
...@@ -46,8 +46,10 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware { ...@@ -46,8 +46,10 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
private void onAttachedToEngine(Context applicationContext, BinaryMessenger messenger, Activity activity, PlatformViewRegistry platformViewRegistry, FlutterView flutterView) { private void onAttachedToEngine(Context applicationContext, BinaryMessenger messenger, Activity activity, PlatformViewRegistry platformViewRegistry, FlutterView flutterView) {
Shared.applicationContext = applicationContext; Shared.applicationContext = applicationContext;
Shared.activity = activity; Shared.activity = activity;
Shared.messenger = messenger;
inAppBrowser = new InAppBrowser(messenger); inAppBrowserManager = new InAppBrowserManager(messenger);
chromeSafariBrowserManager = new ChromeSafariBrowserManager(messenger);
platformViewRegistry.registerViewFactory( platformViewRegistry.registerViewFactory(
"com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(messenger, flutterView)); "com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(messenger, flutterView));
...@@ -61,9 +63,13 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware { ...@@ -61,9 +63,13 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
@Override @Override
public void onDetachedFromEngine(FlutterPluginBinding binding) { public void onDetachedFromEngine(FlutterPluginBinding binding) {
if (inAppBrowser != null) { if (inAppBrowserManager != null) {
inAppBrowser.dispose(); inAppBrowserManager.dispose();
inAppBrowser = null; inAppBrowserManager = null;
}
if (chromeSafariBrowserManager != null) {
chromeSafariBrowserManager.dispose();
chromeSafariBrowserManager = null;
} }
if (myCookieManager != null) { if (myCookieManager != null) {
myCookieManager.dispose(); myCookieManager.dispose();
......
...@@ -9,13 +9,7 @@ import android.webkit.ValueCallback; ...@@ -9,13 +9,7 @@ import android.webkit.ValueCallback;
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView; import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
...@@ -25,6 +19,7 @@ public class JavaScriptBridgeInterface { ...@@ -25,6 +19,7 @@ public class JavaScriptBridgeInterface {
public static final String name = "flutter_inappwebview"; public static final String name = "flutter_inappwebview";
private FlutterWebView flutterWebView; private FlutterWebView flutterWebView;
private InAppBrowserActivity inAppBrowserActivity; private InAppBrowserActivity inAppBrowserActivity;
public MethodChannel channel;
// https://github.com/taylorhakes/promise-polyfill/blob/master/src/index.js // https://github.com/taylorhakes/promise-polyfill/blob/master/src/index.js
public static final String promisePolyfillJS = "if (window.Promise == null) {" + public static final String promisePolyfillJS = "if (window.Promise == null) {" +
...@@ -254,6 +249,7 @@ public class JavaScriptBridgeInterface { ...@@ -254,6 +249,7 @@ public class JavaScriptBridgeInterface {
this.inAppBrowserActivity = (InAppBrowserActivity) obj; this.inAppBrowserActivity = (InAppBrowserActivity) obj;
else if (obj instanceof FlutterWebView) else if (obj instanceof FlutterWebView)
this.flutterWebView = (FlutterWebView) obj; this.flutterWebView = (FlutterWebView) obj;
this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel;
} }
@JavascriptInterface @JavascriptInterface
...@@ -277,7 +273,7 @@ public class JavaScriptBridgeInterface { ...@@ -277,7 +273,7 @@ public class JavaScriptBridgeInterface {
webView.printCurrentPage(); webView.printCurrentPage();
} }
getChannel().invokeMethod("onCallJsHandler", obj, new MethodChannel.Result() { channel.invokeMethod("onCallJsHandler", obj, new MethodChannel.Result() {
@Override @Override
public void success(Object json) { public void success(Object json) {
if (webView == null) { if (webView == null) {
...@@ -305,8 +301,4 @@ public class JavaScriptBridgeInterface { ...@@ -305,8 +301,4 @@ public class JavaScriptBridgeInterface {
} }
}); });
} }
private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppWebViewFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
}
} }
...@@ -5,11 +5,13 @@ import android.content.Context; ...@@ -5,11 +5,13 @@ import android.content.Context;
import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.PluginRegistry; import io.flutter.plugin.common.PluginRegistry;
public class Shared { public class Shared {
public static Context applicationContext; public static Context applicationContext;
public static PluginRegistry.Registrar registrar; public static PluginRegistry.Registrar registrar;
public static BinaryMessenger messenger;
public static FlutterPlugin.FlutterAssets flutterAssets; public static FlutterPlugin.FlutterAssets flutterAssets;
public static ActivityPluginBinding activityPluginBinding; public static ActivityPluginBinding activityPluginBinding;
public static Activity activity; public static Activity activity;
......
...@@ -196,10 +196,9 @@ ...@@ -196,10 +196,9 @@
}; };
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2"; compatibilityVersion = "Xcode 3.2";
developmentRegion = English; developmentRegion = en;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
knownRegions = ( knownRegions = (
English,
en, en,
Base, Base,
); );
......
...@@ -38,9 +38,8 @@ class MyInAppBrowser extends InAppBrowser { ...@@ -38,9 +38,8 @@ class MyInAppBrowser extends InAppBrowser {
@override @override
Future<ShouldOverrideUrlLoadingAction> shouldOverrideUrlLoading(ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async { Future<ShouldOverrideUrlLoadingAction> shouldOverrideUrlLoading(ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async {
print("\n\n override ${shouldOverrideUrlLoadingRequest.url}\n\n"); print("\n\nOverride ${shouldOverrideUrlLoadingRequest.url}\n\n");
this.webViewController.loadUrl(url: shouldOverrideUrlLoadingRequest.url); return ShouldOverrideUrlLoadingAction.ALLOW;
return ShouldOverrideUrlLoadingAction.CANCEL;
} }
@override @override
...@@ -87,12 +86,13 @@ class _InAppBrowserExampleScreenState extends State<InAppBrowserExampleScreen> { ...@@ -87,12 +86,13 @@ class _InAppBrowserExampleScreenState extends State<InAppBrowserExampleScreen> {
drawer: myDrawer(context: context), drawer: myDrawer(context: context),
body: Center( body: Center(
child: RaisedButton( child: RaisedButton(
onPressed: () { onPressed: () async {
widget.browser.openFile( await widget.browser.openFile(
assetFilePath: "assets/index.html", assetFilePath: "assets/index.html",
options: InAppBrowserClassOptions( options: InAppBrowserClassOptions(
inAppWebViewWidgetOptions: InAppWebViewWidgetOptions( inAppWebViewWidgetOptions: InAppWebViewWidgetOptions(
crossPlatform: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
useShouldOverrideUrlLoading: true, useShouldOverrideUrlLoading: true,
useOnLoadResource: true, useOnLoadResource: true,
)))); ))));
......
...@@ -59,6 +59,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> { ...@@ -59,6 +59,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
), ),
onWebViewCreated: (InAppWebViewController controller) { onWebViewCreated: (InAppWebViewController controller) {
webView = controller; webView = controller;
print("onWebViewCreated");
}, },
onLoadStart: (InAppWebViewController controller, String url) { onLoadStart: (InAppWebViewController controller, String url) {
print("onLoadStart $url"); print("onLoadStart $url");
...@@ -71,6 +72,29 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> { ...@@ -71,6 +72,29 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
setState(() { setState(() {
this.url = url; this.url = url;
}); });
/*var origins = await WebStorageManager.instance().android.getOrigins();
for (var origin in origins) {
print(origin);
print(await WebStorageManager.instance().android.getQuotaForOrigin(origin: origin.origin));
print(await WebStorageManager.instance().android.getUsageForOrigin(origin: origin.origin));
}
await WebStorageManager.instance().android.deleteAllData();
print("\n\nDELETED\n\n");
origins = await WebStorageManager.instance().android.getOrigins();
for (var origin in origins) {
print(origin);
await WebStorageManager.instance().android.deleteOrigin(origin: origin.origin);
}*/
/*var records = await WebStorageManager.instance().ios.fetchDataRecords(dataTypes: IOSWKWebsiteDataType.ALL);
for(var record in records) {
print(record);
}
await WebStorageManager.instance().ios.removeDataModifiedSince(dataTypes: IOSWKWebsiteDataType.ALL, date: DateTime(0));
print("\n\nDELETED\n\n");
records = await WebStorageManager.instance().ios.fetchDataRecords(dataTypes: IOSWKWebsiteDataType.ALL);
for(var record in records) {
print(record);
}*/
}, },
onProgressChanged: (InAppWebViewController controller, int progress) { onProgressChanged: (InAppWebViewController controller, int progress) {
setState(() { setState(() {
......
//
// ChromeSafariBrowserManager.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 18/12/2019.
//
import Flutter
import UIKit
import WebKit
import Foundation
import AVFoundation
import SafariServices
public class ChromeSafariBrowserManager: NSObject, FlutterPlugin {
static var registrar: FlutterPluginRegistrar?
static var channel: FlutterMethodChannel?
var tmpWindow: UIWindow?
private var previousStatusBarStyle = -1
public static func register(with registrar: FlutterPluginRegistrar) {
}
init(registrar: FlutterPluginRegistrar) {
super.init()
ChromeSafariBrowserManager.registrar = registrar
ChromeSafariBrowserManager.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_chromesafaribrowser", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(self, channel: ChromeSafariBrowserManager.channel!)
}
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":
let url = arguments!["url"] as! String
let options = arguments!["options"] as! [String: Any?]
let uuidFallback: String = arguments!["uuidFallback"] as! String
let headersFallback = arguments!["headersFallback"] as! [String: String]
let optionsFallback = arguments!["optionsFallback"] as! [String: Any?]
open(uuid: uuid, url: url, options: options, uuidFallback: uuidFallback, headersFallback: headersFallback, optionsFallback: optionsFallback, result: result)
break
default:
result(FlutterMethodNotImplemented)
break
}
}
public func open(uuid: String, url: String, options: [String: Any?], uuidFallback: String?, headersFallback: [String: String], optionsFallback: [String: Any?], result: @escaping FlutterResult) {
let absoluteUrl = URL(string: url)!.absoluteURL
if self.previousStatusBarStyle == -1 {
self.previousStatusBarStyle = UIApplication.shared.statusBarStyle.rawValue
}
if !(self.tmpWindow != nil) {
let frame: CGRect = UIScreen.main.bounds
self.tmpWindow = UIWindow(frame: frame)
}
let tmpController = UIViewController()
let baseWindowLevel = UIApplication.shared.keyWindow?.windowLevel
self.tmpWindow!.rootViewController = tmpController
self.tmpWindow!.windowLevel = UIWindow.Level(baseWindowLevel!.rawValue + 1.0)
self.tmpWindow!.makeKeyAndVisible()
if #available(iOS 9.0, *) {
let safariOptions = SafariBrowserOptions()
let _ = safariOptions.parse(options: options)
let safari: SafariViewController
if #available(iOS 11.0, *) {
let config = SFSafariViewController.Configuration()
config.entersReaderIfAvailable = safariOptions.entersReaderIfAvailable
config.barCollapsingEnabled = safariOptions.barCollapsingEnabled
safari = SafariViewController(url: absoluteUrl, configuration: config)
} else {
// Fallback on earlier versions
safari = SafariViewController(url: absoluteUrl)
}
safari.uuid = uuid
safari.prepareMethodChannel()
safari.delegate = safari
safari.tmpWindow = tmpWindow
safari.safariOptions = safariOptions
tmpController.present(safari, animated: true) {
result(true)
}
return
}
else {
if uuidFallback == nil {
print("No WebView fallback declared.")
result(true)
return
}
SwiftFlutterPlugin.instance!.inAppBrowserManager!.openUrl(uuid: uuidFallback!, url: url, options: optionsFallback, headers: headersFallback)
}
}
}
...@@ -19,14 +19,14 @@ class CustomeSchemeHandler : NSObject, WKURLSchemeHandler { ...@@ -19,14 +19,14 @@ class CustomeSchemeHandler : NSObject, WKURLSchemeHandler {
if let url = urlSchemeTask.request.url, let scheme = url.scheme { if let url = urlSchemeTask.request.url, let scheme = url.scheme {
inAppWebView.onLoadResourceCustomScheme(scheme: scheme, url: url.absoluteString, result: {(result) -> Void in inAppWebView.onLoadResourceCustomScheme(scheme: scheme, url: url.absoluteString, result: {(result) -> Void in
if result is FlutterError { if result is FlutterError {
print((result as! FlutterError).message) print((result as! FlutterError).message ?? "")
} }
else if (result as? NSObject) == FlutterMethodNotImplemented {} else if (result as? NSObject) == FlutterMethodNotImplemented {}
else { else {
let json: [String: Any] let json: [String: Any]
if let r = result { if let r = result {
json = r as! [String: Any] json = r as! [String: Any]
let urlResponse = URLResponse(url: url, mimeType: json["content-type"] as! String, expectedContentLength: -1, textEncodingName: json["content-encoding"] as! String) let urlResponse = URLResponse(url: url, mimeType: (json["content-type"] as! String), expectedContentLength: -1, textEncodingName: (json["content-encoding"] as! String))
let data = json["data"] as! FlutterStandardTypedData let data = json["data"] as! FlutterStandardTypedData
if (self.schemeHandlers[urlSchemeTask.hash] != nil) { if (self.schemeHandlers[urlSchemeTask.hash] != nil) {
urlSchemeTask.didReceive(urlResponse) urlSchemeTask.didReceive(urlResponse)
......
...@@ -25,20 +25,20 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor ...@@ -25,20 +25,20 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
myView = UIView(frame: frame) myView = UIView(frame: frame)
let channelName = "com.pichillilorenzo/flutter_inappwebview_" + String(viewId) let channelName = "com.pichillilorenzo/flutter_inappwebview_" + String(viewId)
self.channel = FlutterMethodChannel(name: channelName, binaryMessenger: registrar.messenger()) channel = FlutterMethodChannel(name: channelName, binaryMessenger: registrar.messenger())
self.channel?.setMethodCallHandler(LeakAvoider(delegate: self).handle) channel!.setMethodCallHandler(LeakAvoider(delegate: self).handle)
let initialUrl = (args["initialUrl"] as? String)! let initialUrl = args["initialUrl"] as? String
let initialFile = args["initialFile"] as? String let initialFile = args["initialFile"] as? String
let initialData = args["initialData"] as? [String: String] let initialData = args["initialData"] as? [String: String]
let initialHeaders = (args["initialHeaders"] as? [String: String])! let initialHeaders = args["initialHeaders"] as? [String: String]
let initialOptions = (args["initialOptions"] as? [String: Any])! let initialOptions = args["initialOptions"] as! [String: Any?]
let options = InAppWebViewOptions() let options = InAppWebViewOptions()
options.parse(options: initialOptions) let _ = options.parse(options: initialOptions)
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(options: options) let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(options: options)
webView = InAppWebView(frame: myView!.bounds, configuration: preWebviewConfiguration, IABController: nil, channel: self.channel) webView = InAppWebView(frame: myView!.bounds, configuration: preWebviewConfiguration, IABController: nil, channel: channel!)
webView!.autoresizingMask = [.flexibleWidth, .flexibleHeight] webView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
myView!.addSubview(webView!) myView!.addSubview(webView!)
...@@ -76,7 +76,7 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor ...@@ -76,7 +76,7 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
deinit { deinit {
print("FlutterWebViewController - dealloc") print("FlutterWebViewController - dealloc")
self.channel?.setMethodCallHandler(nil) channel?.setMethodCallHandler(nil)
webView!.dispose() webView!.dispose()
webView = nil webView = nil
myView = nil myView = nil
...@@ -86,7 +86,7 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor ...@@ -86,7 +86,7 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
return myView! return myView!
} }
public func load(initialUrl: String, initialFile: String?, initialData: [String: String]?, initialHeaders: [String: String]) { public func load(initialUrl: String?, initialFile: String?, initialData: [String: String]?, initialHeaders: [String: String]?) {
if initialFile != nil { if initialFile != nil {
do { do {
try webView!.loadFile(url: initialFile!, headers: initialHeaders) try webView!.loadFile(url: initialFile!, headers: initialHeaders)
...@@ -98,14 +98,14 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor ...@@ -98,14 +98,14 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
} }
if initialData != nil { if initialData != nil {
let data = (initialData!["data"] as? String)! let data = initialData!["data"]!
let mimeType = (initialData!["mimeType"] as? String)! let mimeType = initialData!["mimeType"]!
let encoding = (initialData!["encoding"] as? String)! let encoding = initialData!["encoding"]!
let baseUrl = (initialData!["baseUrl"] as? String)! let baseUrl = initialData!["baseUrl"]!
webView!.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl) webView!.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
} }
else { else {
webView!.loadUrl(url: URL(string: initialUrl)!, headers: initialHeaders) webView!.loadUrl(url: URL(string: initialUrl!)!, headers: initialHeaders)
} }
} }
...@@ -263,7 +263,7 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor ...@@ -263,7 +263,7 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
if webView != nil { if webView != nil {
let inAppWebViewOptions = InAppWebViewOptions() let inAppWebViewOptions = InAppWebViewOptions()
let inAppWebViewOptionsMap = arguments!["options"] as! [String: Any] let inAppWebViewOptionsMap = arguments!["options"] as! [String: Any]
inAppWebViewOptions.parse(options: inAppWebViewOptionsMap) let _ = inAppWebViewOptions.parse(options: inAppWebViewOptionsMap)
webView!.setOptions(newOptions: inAppWebViewOptions, newOptionsMap: inAppWebViewOptionsMap) webView!.setOptions(newOptions: inAppWebViewOptions, newOptionsMap: inAppWebViewOptionsMap)
} }
result(true) result(true)
...@@ -277,8 +277,13 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor ...@@ -277,8 +277,13 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
case "findAllAsync": case "findAllAsync":
if webView != nil { if webView != nil {
let find = arguments!["find"] as! String let find = arguments!["find"] as! String
webView!.findAllAsync(find: find, completionHandler: nil) webView!.findAllAsync(find: find, completionHandler: {(value, error) in
if error != nil {
result(FlutterError(code: "FlutterWebViewController", message: error?.localizedDescription, details: nil))
return
}
result(true) result(true)
})
} else { } else {
result(false) result(false)
} }
...@@ -347,13 +352,12 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor ...@@ -347,13 +352,12 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
case "printCurrentPage": case "printCurrentPage":
if webView != nil { if webView != nil {
webView!.printCurrentPage(printCompletionHandler: {(completed, error) in webView!.printCurrentPage(printCompletionHandler: {(completed, error) in
if !completed, let e = error { if !completed, let _ = error {
result(false) result(false)
return return
} }
result(true) result(true)
}) })
} else { } else {
result(false) result(false)
} }
......
//
// InAppBrowserManager.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 18/12/2019.
//
import Flutter
import UIKit
import WebKit
import Foundation
import AVFoundation
let WEBVIEW_STORYBOARD = "WebView"
let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController"
public class InAppBrowserManager: NSObject, FlutterPlugin {
static var registrar: FlutterPluginRegistrar?
static var channel: FlutterMethodChannel?
var tmpWindow: UIWindow?
private var previousStatusBarStyle = -1
public static func register(with registrar: FlutterPluginRegistrar) {
}
init(registrar: FlutterPluginRegistrar) {
super.init()
InAppBrowserManager.registrar = registrar
InAppBrowserManager.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappbrowser", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(self, channel: InAppBrowserManager.channel!)
}
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 "openUrl":
let url = arguments!["url"] as! String
let options = arguments!["options"] as! [String: Any?]
let headers = arguments!["headers"] as! [String: String]
openUrl(uuid: uuid, url: url, options: options, headers: headers)
result(true)
break
case "openFile":
var url = arguments!["url"] as! String
let key = InAppBrowserManager.registrar!.lookupKey(forAsset: url)
let assetURL = Bundle.main.url(forResource: key, withExtension: nil)
if assetURL == nil {
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: url + " asset file cannot be found!", details: nil))
return
} else {
url = assetURL!.absoluteString
}
let options = arguments!["options"] as! [String: Any?]
let headers = arguments!["headers"] as! [String: String]
openUrl(uuid: uuid, url: url, options: options, headers: headers)
result(true)
break
case "openData":
let options = arguments!["options"] as! [String: Any?]
let data = arguments!["data"] as! String
let mimeType = arguments!["mimeType"] as! String
let encoding = arguments!["encoding"] as! String
let baseUrl = arguments!["baseUrl"] as! String
openData(uuid: uuid, options: options, data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
result(true)
break
case "openWithSystemBrowser":
let url = arguments!["url"] as! String
openWithSystemBrowser(url: url, result: result)
break
default:
result(FlutterMethodNotImplemented)
break
}
}
public func prepareInAppBrowserWebViewController(options: [String: Any?]) -> InAppBrowserWebViewController {
if self.previousStatusBarStyle == -1 {
self.previousStatusBarStyle = UIApplication.shared.statusBarStyle.rawValue
}
if !(self.tmpWindow != nil) {
let frame: CGRect = UIScreen.main.bounds
self.tmpWindow = UIWindow(frame: frame)
}
let tmpController = UIViewController()
let baseWindowLevel = UIApplication.shared.keyWindow?.windowLevel
self.tmpWindow!.rootViewController = tmpController
self.tmpWindow!.windowLevel = UIWindow.Level(baseWindowLevel!.rawValue + 1.0)
self.tmpWindow!.makeKeyAndVisible()
let browserOptions = InAppBrowserOptions()
let _ = browserOptions.parse(options: options)
let webViewOptions = InAppWebViewOptions()
let _ = webViewOptions.parse(options: options)
let storyboard = UIStoryboard(name: WEBVIEW_STORYBOARD, bundle: Bundle(for: InAppWebViewFlutterPlugin.self))
let webViewController = storyboard.instantiateViewController(withIdentifier: WEBVIEW_STORYBOARD_CONTROLLER_ID) as! InAppBrowserWebViewController
webViewController.browserOptions = browserOptions
webViewController.webViewOptions = webViewOptions
webViewController.isHidden = browserOptions.hidden
webViewController.previousStatusBarStyle = previousStatusBarStyle
return webViewController
}
public func openUrl(uuid: String, url: String, options: [String: Any?], headers: [String: String]) {
let absoluteUrl = URL(string: url)!.absoluteURL
let webViewController = prepareInAppBrowserWebViewController(options: options)
webViewController.uuid = uuid
webViewController.prepareMethodChannel()
webViewController.tmpWindow = tmpWindow
webViewController.initURL = absoluteUrl
webViewController.initHeaders = headers
if webViewController.isHidden {
webViewController.view.isHidden = true
tmpWindow!.rootViewController!.present(webViewController, animated: false, completion: {() -> Void in
})
webViewController.presentingViewController?.dismiss(animated: false, completion: {() -> Void in
self.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
})
}
else {
tmpWindow!.rootViewController!.present(webViewController, animated: true, completion: {() -> Void in
})
}
}
public func openData(uuid: String, options: [String: Any?], data: String, mimeType: String, encoding: String, baseUrl: String) {
let webViewController = prepareInAppBrowserWebViewController(options: options)
webViewController.uuid = uuid
webViewController.tmpWindow = tmpWindow
webViewController.initData = data
webViewController.initMimeType = mimeType
webViewController.initEncoding = encoding
webViewController.initBaseUrl = baseUrl
if webViewController.isHidden {
webViewController.view.isHidden = true
tmpWindow!.rootViewController!.present(webViewController, animated: false, completion: {() -> Void in
webViewController.webView.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
})
webViewController.presentingViewController?.dismiss(animated: false, completion: {() -> Void in
self.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
})
}
else {
tmpWindow!.rootViewController!.present(webViewController, animated: true, completion: {() -> Void in
webViewController.webView.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
})
}
}
public func openWithSystemBrowser(url: String, result: @escaping FlutterResult) {
let absoluteUrl = URL(string: url)!.absoluteURL
if !UIApplication.shared.canOpenURL(absoluteUrl) {
result(FlutterError(code: "InAppBrowserManager", message: url + " cannot be opened!", details: nil))
return
}
else {
if #available(iOS 10.0, *) {
UIApplication.shared.open(absoluteUrl, options: convertToUIApplicationOpenExternalURLOptionsKeyDictionary([:]), completionHandler: nil)
} else {
UIApplication.shared.openURL(absoluteUrl)
}
}
result(true)
}
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToUIApplicationOpenExternalURLOptionsKeyDictionary(_ input: [String: Any]) -> [UIApplication.OpenExternalURLOptionsKey: Any] {
return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
}
...@@ -14,55 +14,7 @@ import AVFoundation ...@@ -14,55 +14,7 @@ import AVFoundation
typealias OlderClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Any?) -> Void typealias OlderClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Any?) -> Void
typealias NewerClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void typealias NewerClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void
//extension WKWebView{ public class InAppWebView_IBWrapper: InAppWebView {
//
// var keyboardDisplayRequiresUserAction: Bool? {
// get {
// return self.keyboardDisplayRequiresUserAction
// }
// set {
// self.setKeyboardRequiresUserInteraction(newValue ?? true)
// }
// }
//
// func setKeyboardRequiresUserInteraction( _ value: Bool) {
//
// guard
// let WKContentViewClass: AnyClass = NSClassFromString("WKContentView") else {
// print("Cannot find the WKContentView class")
// return
// }
//
// let olderSelector: Selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:")
// let newerSelector: Selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:")
//
// if let method = class_getInstanceMethod(WKContentViewClass, olderSelector) {
//
// let originalImp: IMP = method_getImplementation(method)
// let original: OlderClosureType = unsafeBitCast(originalImp, to: OlderClosureType.self)
// let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3) in
// original(me, olderSelector, arg0, !value, arg2, arg3)
// }
// let imp: IMP = imp_implementationWithBlock(block)
// method_setImplementation(method, imp)
// }
//
// if let method = class_getInstanceMethod(WKContentViewClass, newerSelector) {
//
// let originalImp: IMP = method_getImplementation(method)
// let original: NewerClosureType = unsafeBitCast(originalImp, to: NewerClosureType.self)
// let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3, arg4) in
// original(me, newerSelector, arg0, !value, arg2, arg3, arg4)
// }
// let imp: IMP = imp_implementationWithBlock(block)
// method_setImplementation(method, imp)
// }
//
// }
//
//}
class InAppWebView_IBWrapper: InAppWebView {
required init(coder: NSCoder) { required init(coder: NSCoder) {
let config = WKWebViewConfiguration() let config = WKWebViewConfiguration()
super.init(frame: .zero, configuration: config, IABController: nil, channel: nil) super.init(frame: .zero, configuration: config, IABController: nil, channel: nil)
...@@ -70,7 +22,7 @@ class InAppWebView_IBWrapper: InAppWebView { ...@@ -70,7 +22,7 @@ class InAppWebView_IBWrapper: InAppWebView {
} }
} }
class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKUIDelegate, UITextFieldDelegate { public class InAppBrowserWebViewController: UIViewController, FlutterPlugin, UIScrollViewDelegate, WKUIDelegate, UITextFieldDelegate {
@IBOutlet var containerWebView: UIView! @IBOutlet var containerWebView: UIView!
@IBOutlet var closeButton: UIButton! @IBOutlet var closeButton: UIButton!
...@@ -90,8 +42,9 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU ...@@ -90,8 +42,9 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
@IBOutlet var webView_BottomFullScreenConstraint: NSLayoutConstraint! @IBOutlet var webView_BottomFullScreenConstraint: NSLayoutConstraint!
@IBOutlet var webView_TopFullScreenConstraint: NSLayoutConstraint! @IBOutlet var webView_TopFullScreenConstraint: NSLayoutConstraint!
var uuid: String = ""
var webView: InAppWebView! var webView: InAppWebView!
weak var navigationDelegate: SwiftFlutterPlugin? var channel: FlutterMethodChannel?
var initURL: URL? var initURL: URL?
var tmpWindow: UIWindow? var tmpWindow: UIWindow?
var browserOptions: InAppBrowserOptions? var browserOptions: InAppBrowserOptions?
...@@ -102,25 +55,245 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU ...@@ -102,25 +55,245 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
var initEncoding: String? var initEncoding: String?
var initBaseUrl: String? var initBaseUrl: String?
var isHidden = false var isHidden = false
var uuid: String = ""
var WKNavigationMap: [String: [String: Any]] = [:]
var startPageTime: Int64 = 0
var viewPrepared = false var viewPrepared = false
var previousStatusBarStyle = -1
required init(coder aDecoder: NSCoder) { required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)! super.init(coder: aDecoder)!
} }
override func viewWillAppear(_ animated: Bool) { public static func register(with registrar: FlutterPluginRegistrar) {
}
public func prepareMethodChannel() {
channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappbrowser_" + uuid, binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger())
SwiftFlutterPlugin.instance!.registrar!.addMethodCallDelegate(self, channel: channel!)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
switch call.method {
case "getUrl":
result(webView.url?.absoluteString)
break
case "getTitle":
result(webView.title)
break
case "getProgress":
let progress = Int(webView.estimatedProgress * 100)
result(progress)
break
case "loadUrl":
let url = arguments!["url"] as! String
let headers = arguments!["headers"] as? [String: String]
let absoluteUrl = URL(string: url)!.absoluteURL
webView.loadUrl(url: absoluteUrl, headers: headers)
result(true)
break
case "loadData":
let data = arguments!["data"] as! String
let mimeType = arguments!["mimeType"] as! String
let encoding = arguments!["encoding"] as! String
let baseUrl = arguments!["baseUrl"] as! String
webView.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
result(true)
break
case "postUrl":
let url = arguments!["url"] as! String
let postData = arguments!["postData"] as! FlutterStandardTypedData
let absoluteUrl = URL(string: url)!.absoluteURL
webView.postUrl(url: absoluteUrl, postData: postData.data, completionHandler: { () -> Void in
result(true)
})
break
case "loadFile":
let url = arguments!["url"] as! String
let headers = arguments!["headers"] as? [String: String]
do {
try webView.loadFile(url: url, headers: headers)
result(true)
}
catch let error as NSError {
dump(error)
result(FlutterError(code: "InAppBrowserWebViewController", message: error.localizedDescription, details: nil))
}
break
case "close":
close()
result(true)
break
case "show":
show()
result(true)
break
case "hide":
hide()
result(true)
break
case "reload":
webView.reload()
result(true)
break
case "goBack":
webView.goBack()
result(true)
break
case "canGoBack":
result(webView.canGoBack)
break
case "goForward":
webView.goForward()
result(true)
break
case "canGoForward":
result(webView.canGoForward)
break
case "goBackOrForward":
let steps = arguments!["steps"] as! Int
webView.goBackOrForward(steps: steps)
result(true)
break
case "canGoBackOrForward":
let steps = arguments!["steps"] as! Int
result(webView.canGoBackOrForward(steps: steps))
break
case "isLoading":
result(webView.isLoading == true)
break
case "stopLoading":
webView.stopLoading()
result(true)
break
case "isHidden":
result(isHidden == true)
break
case "evaluateJavascript":
let source = arguments!["source"] as! String
webView.evaluateJavascript(source: source, result: result)
break
case "injectJavascriptFileFromUrl":
let urlFile = arguments!["urlFile"] as! String
webView.injectJavascriptFileFromUrl(urlFile: urlFile)
result(true)
break
case "injectCSSCode":
let source = arguments!["source"] as! String
webView.injectCSSCode(source: source)
result(true)
break
case "injectCSSFileFromUrl":
let urlFile = arguments!["urlFile"] as! String
webView.injectCSSFileFromUrl(urlFile: urlFile)
result(true)
break
case "takeScreenshot":
webView.takeScreenshot(completionHandler: { (screenshot) -> Void in
result(screenshot)
})
break
case "setOptions":
let inAppBrowserOptions = InAppBrowserOptions()
let inAppBrowserOptionsMap = arguments!["options"] as! [String: Any]
let _ = inAppBrowserOptions.parse(options: inAppBrowserOptionsMap)
self.setOptions(newOptions: inAppBrowserOptions, newOptionsMap: inAppBrowserOptionsMap)
result(true)
break
case "getOptions":
result(getOptions())
break
case "getCopyBackForwardList":
result(webView.getCopyBackForwardList())
break
case "findAllAsync":
let find = arguments!["find"] as! String
webView.findAllAsync(find: find, completionHandler: {(value, error) in
if error != nil {
result(FlutterError(code: "InAppBrowserWebViewController", message: error?.localizedDescription, details: nil))
return
}
result(true)
})
break
case "findNext":
let forward = arguments!["forward"] as! Bool
webView.findNext(forward: forward, completionHandler: {(value, error) in
if error != nil {
result(FlutterError(code: "InAppBrowserWebViewController", message: error?.localizedDescription, details: nil))
return
}
result(true)
})
break
case "clearMatches":
webView.clearMatches(completionHandler: {(value, error) in
if error != nil {
result(FlutterError(code: "InAppBrowserWebViewController", message: error?.localizedDescription, details: nil))
return
}
result(true)
})
break
case "clearCache":
webView.clearCache()
result(true)
break
case "scrollTo":
let x = arguments!["x"] as! Int
let y = arguments!["y"] as! Int
webView.scrollTo(x: x, y: y)
result(true)
break
case "scrollBy":
let x = arguments!["x"] as! Int
let y = arguments!["y"] as! Int
webView.scrollTo(x: x, y: y)
result(true)
break
case "pauseTimers":
webView.pauseTimers()
result(true)
break
case "resumeTimers":
webView.resumeTimers()
result(true)
break
case "printCurrentPage":
webView.printCurrentPage(printCompletionHandler: {(completed, error) in
if !completed, let _ = error {
result(false)
return
}
result(true)
})
break
case "getContentHeight":
result(webView.getContentHeight())
break
case "reloadFromOrigin":
webView.reloadFromOrigin()
result(true)
break
case "getScale":
result(webView.getScale())
break
default:
result(FlutterMethodNotImplemented)
break
}
}
public override func viewWillAppear(_ animated: Bool) {
if !viewPrepared { if !viewPrepared {
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(options: webViewOptions) let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(options: webViewOptions)
self.webView = InAppWebView(frame: .zero, configuration: preWebviewConfiguration, IABController: self, channel: nil) self.webView = InAppWebView(frame: .zero, configuration: preWebviewConfiguration, IABController: self, channel: channel!)
self.containerWebView.addSubview(self.webView) self.containerWebView.addSubview(self.webView)
prepareConstraints() prepareConstraints()
prepareWebView() prepareWebView()
if #available(iOS 11.0, *) { if #available(iOS 11.0, *) {
if let contentBlockers = webView!.options?.contentBlockers, contentBlockers.count > 0 { if let contentBlockers = webView.options?.contentBlockers, contentBlockers.count > 0 {
do { do {
let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: []) let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: [])
let blockRules = String(data: jsonData, encoding: String.Encoding.utf8) let blockRules = String(data: jsonData, encoding: String.Encoding.utf8)
...@@ -138,7 +311,7 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU ...@@ -138,7 +311,7 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
self.initLoad(initURL: self.initURL, initData: self.initData, initMimeType: self.initMimeType, initEncoding: self.initEncoding, initBaseUrl: self.initBaseUrl, initHeaders: self.initHeaders) self.initLoad(initURL: self.initURL, initData: self.initData, initMimeType: self.initMimeType, initEncoding: self.initEncoding, initBaseUrl: self.initBaseUrl, initHeaders: self.initHeaders)
self.navigationDelegate?.onBrowserCreated(uuid: self.uuid, webView: self.webView) self.onBrowserCreated()
} }
return return
} catch { } catch {
...@@ -149,13 +322,13 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU ...@@ -149,13 +322,13 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
initLoad(initURL: initURL, initData: initData, initMimeType: initMimeType, initEncoding: initEncoding, initBaseUrl: initBaseUrl, initHeaders: initHeaders) initLoad(initURL: initURL, initData: initData, initMimeType: initMimeType, initEncoding: initEncoding, initBaseUrl: initBaseUrl, initHeaders: initHeaders)
navigationDelegate?.onBrowserCreated(uuid: uuid, webView: webView) onBrowserCreated()
} }
viewPrepared = true viewPrepared = true
super.viewWillAppear(animated) super.viewWillAppear(animated)
} }
func initLoad(initURL: URL?, initData: String?, initMimeType: String?, initEncoding: String?, initBaseUrl: String?, initHeaders: [String: String]?) { public func initLoad(initURL: URL?, initData: String?, initMimeType: String?, initEncoding: String?, initBaseUrl: String?, initHeaders: [String: String]?) {
if self.initData == nil { if self.initData == nil {
loadUrl(url: self.initURL!, headers: self.initHeaders) loadUrl(url: self.initURL!, headers: self.initHeaders)
} }
...@@ -164,7 +337,7 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU ...@@ -164,7 +337,7 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
} }
} }
override func viewDidLoad() { public override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
urlField.delegate = self urlField.delegate = self
...@@ -197,39 +370,28 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU ...@@ -197,39 +370,28 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
print("InAppBrowserWebViewController - dealloc") print("InAppBrowserWebViewController - dealloc")
} }
override func viewWillDisappear (_ animated: Bool) { public override func viewWillDisappear (_ animated: Bool) {
dispose()
super.viewWillDisappear(animated) super.viewWillDisappear(animated)
webView.dispose()
navigationDelegate = nil
transitioningDelegate = nil
urlField.delegate = nil
closeButton.removeTarget(self, action: #selector(self.close), for: .touchUpInside)
forwardButton.target = nil
forwardButton.target = nil
backButton.target = nil
reloadButton.target = nil
shareButton.target = nil
} }
func prepareConstraints () { public func prepareConstraints () {
containerWebView_BottomFullScreenConstraint = NSLayoutConstraint(item: self.containerWebView, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: 0) containerWebView_BottomFullScreenConstraint = NSLayoutConstraint(item: self.containerWebView!, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: 0)
containerWebView_TopFullScreenConstraint = NSLayoutConstraint(item: self.containerWebView, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: 0) containerWebView_TopFullScreenConstraint = NSLayoutConstraint(item: self.containerWebView!, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: 0)
webView.translatesAutoresizingMaskIntoConstraints = false webView.translatesAutoresizingMaskIntoConstraints = false
let height = NSLayoutConstraint(item: webView, attribute: .height, relatedBy: .equal, toItem: containerWebView, attribute: .height, multiplier: 1, constant: 0) let height = NSLayoutConstraint(item: self.webView!, attribute: .height, relatedBy: .equal, toItem: containerWebView, attribute: .height, multiplier: 1, constant: 0)
let width = NSLayoutConstraint(item: webView, attribute: .width, relatedBy: .equal, toItem: containerWebView, attribute: .width, multiplier: 1, constant: 0) let width = NSLayoutConstraint(item: self.webView!, attribute: .width, relatedBy: .equal, toItem: containerWebView, attribute: .width, multiplier: 1, constant: 0)
let leftConstraint = NSLayoutConstraint(item: webView, attribute: .leftMargin, relatedBy: .equal, toItem: containerWebView, attribute: .leftMargin, multiplier: 1, constant: 0) let leftConstraint = NSLayoutConstraint(item: self.webView!, attribute: .leftMargin, relatedBy: .equal, toItem: containerWebView, attribute: .leftMargin, multiplier: 1, constant: 0)
let rightConstraint = NSLayoutConstraint(item: webView, attribute: .rightMargin, relatedBy: .equal, toItem: containerWebView, attribute: .rightMargin, multiplier: 1, constant: 0) let rightConstraint = NSLayoutConstraint(item: self.webView!, attribute: .rightMargin, relatedBy: .equal, toItem: containerWebView, attribute: .rightMargin, multiplier: 1, constant: 0)
let bottomContraint = NSLayoutConstraint(item: webView, attribute: .bottomMargin, relatedBy: .equal, toItem: containerWebView, attribute: .bottomMargin, multiplier: 1, constant: 0) let bottomContraint = NSLayoutConstraint(item: self.webView!, attribute: .bottomMargin, relatedBy: .equal, toItem: containerWebView, attribute: .bottomMargin, multiplier: 1, constant: 0)
containerWebView.addConstraints([height, width, leftConstraint, rightConstraint, bottomContraint]) containerWebView.addConstraints([height, width, leftConstraint, rightConstraint, bottomContraint])
webView_BottomFullScreenConstraint = NSLayoutConstraint(item: self.webView, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.containerWebView, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: 0) webView_BottomFullScreenConstraint = NSLayoutConstraint(item: webView!, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.containerWebView, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: 0)
webView_TopFullScreenConstraint = NSLayoutConstraint(item: self.webView, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.containerWebView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: 0) webView_TopFullScreenConstraint = NSLayoutConstraint(item: webView!, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.containerWebView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: 0)
} }
func prepareWebView() { public func prepareWebView() {
//UIApplication.shared.statusBarStyle = preferredStatusBarStyle
self.webView.options = webViewOptions self.webView.options = webViewOptions
self.webView.prepare() self.webView.prepare()
...@@ -274,13 +436,13 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU ...@@ -274,13 +436,13 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
self.modalTransitionStyle = UIModalTransitionStyle(rawValue: (browserOptions?.transitionStyle)!)! self.modalTransitionStyle = UIModalTransitionStyle(rawValue: (browserOptions?.transitionStyle)!)!
} }
func loadUrl(url: URL, headers: [String: String]?) { public func loadUrl(url: URL, headers: [String: String]?) {
webView.loadUrl(url: url, headers: headers) webView.loadUrl(url: url, headers: headers)
updateUrlTextField(url: (webView.currentURL?.absoluteString)!) updateUrlTextField(url: (webView.currentURL?.absoluteString)!)
} }
// Load user requested url // Load user requested url
func textFieldShouldReturn(_ textField: UITextField) -> Bool { public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder() textField.resignFirstResponder()
if textField.text != nil && textField.text != "" { if textField.text != nil && textField.text != "" {
let url = textField.text?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) let url = textField.text?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
...@@ -298,69 +460,91 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU ...@@ -298,69 +460,91 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
webView.frame = frame webView.frame = frame
} }
@objc func reload () { public func show() {
isHidden = false
view.isHidden = false
// Run later to avoid the "took a long time" log message.
DispatchQueue.main.async(execute: {() -> Void in
let baseWindowLevel = UIApplication.shared.keyWindow?.windowLevel
self.tmpWindow?.windowLevel = UIWindow.Level(baseWindowLevel!.rawValue + 1.0)
self.tmpWindow?.makeKeyAndVisible()
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
self.tmpWindow?.rootViewController?.present(self, animated: true, completion: nil)
})
}
public func hide() {
isHidden = true
// Run later to avoid the "took a long time" log message.
DispatchQueue.main.async(execute: {() -> Void in
self.presentingViewController?.dismiss(animated: true, completion: {() -> Void in
self.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
if self.previousStatusBarStyle != -1 {
UIApplication.shared.statusBarStyle = UIStatusBarStyle(rawValue: self.previousStatusBarStyle)!
}
})
})
}
@objc public func reload () {
webView.reload() webView.reload()
} }
@objc func share () { @objc public func share () {
let vc = UIActivityViewController(activityItems: [webView.currentURL ?? ""], applicationActivities: []) let vc = UIActivityViewController(activityItems: [webView.currentURL ?? ""], applicationActivities: [])
present(vc, animated: true, completion: nil) present(vc, animated: true, completion: nil)
} }
@objc func close() { @objc public func close() {
//currentURL = nil
weak var weakSelf = self weak var weakSelf = self
if (weakSelf?.responds(to: #selector(getter: self.presentingViewController)))! { if (weakSelf?.responds(to: #selector(getter: self.presentingViewController)))! {
weakSelf?.presentingViewController?.dismiss(animated: true, completion: {() -> Void in weakSelf?.presentingViewController?.dismiss(animated: true, completion: {() -> Void in
self.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
}) })
} }
else { else {
weakSelf?.parent?.dismiss(animated: true, completion: {() -> Void in weakSelf?.parent?.dismiss(animated: true, completion: {() -> Void in
self.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
}) })
} }
if (self.navigationDelegate != nil) {
self.navigationDelegate?.browserExit(uuid: self.uuid)
}
} }
@objc func goBack() { @objc public func goBack() {
if canGoBack() { if canGoBack() {
webView.goBack() webView.goBack()
updateUrlTextField(url: (webView?.url?.absoluteString)!) updateUrlTextField(url: (webView?.url?.absoluteString)!)
} }
} }
func canGoBack() -> Bool { public func canGoBack() -> Bool {
return webView.canGoBack return webView.canGoBack
} }
@objc func goForward() { @objc public func goForward() {
if canGoForward() { if canGoForward() {
webView.goForward() webView.goForward()
updateUrlTextField(url: (webView?.url?.absoluteString)!) updateUrlTextField(url: (webView?.url?.absoluteString)!)
} }
} }
func canGoForward() -> Bool { public func canGoForward() -> Bool {
return webView.canGoForward return webView.canGoForward
} }
@objc func goBackOrForward(steps: Int) { @objc public func goBackOrForward(steps: Int) {
webView.goBackOrForward(steps: steps) webView.goBackOrForward(steps: steps)
updateUrlTextField(url: (webView?.url?.absoluteString)!) updateUrlTextField(url: (webView?.url?.absoluteString)!)
} }
func canGoBackOrForward(steps: Int) -> Bool { public func canGoBackOrForward(steps: Int) -> Bool {
return webView.canGoBackOrForward(steps: steps) return webView.canGoBackOrForward(steps: steps)
} }
func updateUrlTextField(url: String) { public func updateUrlTextField(url: String) {
urlField.text = url urlField.text = url
} }
...@@ -405,18 +589,18 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU ...@@ -405,18 +589,18 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
return hexInt return hexInt
} }
func setOptions(newOptions: InAppBrowserOptions, newOptionsMap: [String: Any]) { public func setOptions(newOptions: InAppBrowserOptions, newOptionsMap: [String: Any]) {
let newInAppWebViewOptions = InAppWebViewOptions() let newInAppWebViewOptions = InAppWebViewOptions()
newInAppWebViewOptions.parse(options: newOptionsMap) let _ = newInAppWebViewOptions.parse(options: newOptionsMap)
self.webView.setOptions(newOptions: newInAppWebViewOptions, newOptionsMap: newOptionsMap) self.webView.setOptions(newOptions: newInAppWebViewOptions, newOptionsMap: newOptionsMap)
if newOptionsMap["hidden"] != nil && browserOptions?.hidden != newOptions.hidden { if newOptionsMap["hidden"] != nil && browserOptions?.hidden != newOptions.hidden {
if newOptions.hidden { if newOptions.hidden {
self.navigationDelegate?.hide(uuid: self.uuid) hide()
} }
else { else {
self.navigationDelegate?.show(uuid: self.uuid) show()
} }
} }
...@@ -471,7 +655,7 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU ...@@ -471,7 +655,7 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
self.webViewOptions = newInAppWebViewOptions self.webViewOptions = newInAppWebViewOptions
} }
func getOptions() -> [String: Any]? { public func getOptions() -> [String: Any?]? {
if (self.browserOptions == nil || self.webView.getOptions() == nil) { if (self.browserOptions == nil || self.webView.getOptions() == nil) {
return nil return nil
} }
...@@ -480,4 +664,30 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU ...@@ -480,4 +664,30 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
return optionsMap return optionsMap
} }
public func dispose() {
webView.dispose()
if previousStatusBarStyle != -1 {
UIApplication.shared.statusBarStyle = UIStatusBarStyle(rawValue: previousStatusBarStyle)!
}
transitioningDelegate = nil
urlField.delegate = nil
closeButton.removeTarget(self, action: #selector(self.close), for: .touchUpInside)
forwardButton.target = nil
forwardButton.target = nil
backButton.target = nil
reloadButton.target = nil
shareButton.target = nil
tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
onExit()
channel!.setMethodCallHandler(nil)
}
public func onBrowserCreated() {
channel!.invokeMethod("onBrowserCreated", arguments: [])
}
public func onExit() {
channel!.invokeMethod("onExit", arguments: [])
}
} }
...@@ -890,7 +890,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -890,7 +890,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
var activateShouldOverrideUrlLoading = false var activateShouldOverrideUrlLoading = false
init(frame: CGRect, configuration: WKWebViewConfiguration, IABController: InAppBrowserWebViewController?, channel: FlutterMethodChannel?) { init(frame: CGRect, configuration: WKWebViewConfiguration, IABController: InAppBrowserWebViewController?, channel: FlutterMethodChannel?) {
super.init(frame: frame, configuration: configuration) super.init(frame: frame, configuration: configuration)
self.channel = channel self.channel = channel
self.IABController = IABController self.IABController = IABController
...@@ -1403,7 +1402,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -1403,7 +1402,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
self.options = newOptions self.options = newOptions
} }
func getOptions() -> [String: Any]? { func getOptions() -> [String: Any?]? {
if (self.options == nil) { if (self.options == nil) {
return nil return nil
} }
...@@ -1512,7 +1511,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -1512,7 +1511,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
shouldOverrideUrlLoading(url: url, method: navigationAction.request.httpMethod, headers: navigationAction.request.allHTTPHeaderFields, isForMainFrame: isForMainFrame, navigationType: navigationAction.navigationType, result: { (result) -> Void in shouldOverrideUrlLoading(url: url, method: navigationAction.request.httpMethod, headers: navigationAction.request.allHTTPHeaderFields, isForMainFrame: isForMainFrame, navigationType: navigationAction.navigationType, result: { (result) -> Void in
if result is FlutterError { if result is FlutterError {
print((result as! FlutterError).message) print((result as! FlutterError).message ?? "")
} }
else if (result as? NSObject) == FlutterMethodNotImplemented { else if (result as? NSObject) == FlutterMethodNotImplemented {
self.updateUrlTextFieldForIABController(navigationAction: navigationAction) self.updateUrlTextFieldForIABController(navigationAction: navigationAction)
...@@ -1642,7 +1641,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -1642,7 +1641,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
let port = challenge.protectionSpace.port let port = challenge.protectionSpace.port
onReceivedHttpAuthRequest(challenge: challenge, result: {(result) -> Void in onReceivedHttpAuthRequest(challenge: challenge, result: {(result) -> Void in
if result is FlutterError { if result is FlutterError {
print((result as! FlutterError).message) print((result as! FlutterError).message ?? "")
} }
else if (result as? NSObject) == FlutterMethodNotImplemented { else if (result as? NSObject) == FlutterMethodNotImplemented {
completionHandler(.performDefaultHandling, nil) completionHandler(.performDefaultHandling, nil)
...@@ -1711,7 +1710,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -1711,7 +1710,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
onReceivedServerTrustAuthRequest(challenge: challenge, result: {(result) -> Void in onReceivedServerTrustAuthRequest(challenge: challenge, result: {(result) -> Void in
if result is FlutterError { if result is FlutterError {
print((result as! FlutterError).message) print((result as! FlutterError).message ?? "")
} }
else if (result as? NSObject) == FlutterMethodNotImplemented { else if (result as? NSObject) == FlutterMethodNotImplemented {
completionHandler(.performDefaultHandling, nil) completionHandler(.performDefaultHandling, nil)
...@@ -1746,7 +1745,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -1746,7 +1745,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate {
onReceivedClientCertRequest(challenge: challenge, result: {(result) -> Void in onReceivedClientCertRequest(challenge: challenge, result: {(result) -> Void in
if result is FlutterError { if result is FlutterError {
print((result as! FlutterError).message) print((result as! FlutterError).message ?? "")
} }
else if (result as? NSObject) == FlutterMethodNotImplemented { else if (result as? NSObject) == FlutterMethodNotImplemented {
completionHandler(.performDefaultHandling, nil) completionHandler(.performDefaultHandling, nil)
...@@ -1832,7 +1831,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -1832,7 +1831,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
} else { } else {
print("Security Error: " + securityError.description) print("Security Error: " + securityError.description)
if #available(iOS 11.3, *) { if #available(iOS 11.3, *) {
print(SecCopyErrorMessageString(securityError,nil)) print(SecCopyErrorMessageString(securityError,nil) ?? "")
} }
} }
return identityAndTrust; return identityAndTrust;
...@@ -1863,7 +1862,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -1863,7 +1862,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
onJsAlert(message: message, result: {(result) -> Void in onJsAlert(message: message, result: {(result) -> Void in
if result is FlutterError { if result is FlutterError {
print((result as! FlutterError).message) print((result as! FlutterError).message ?? "")
} }
else if (result as? NSObject) == FlutterMethodNotImplemented { else if (result as? NSObject) == FlutterMethodNotImplemented {
self.createAlertDialog(message: message, responseMessage: nil, confirmButtonTitle: nil, completionHandler: completionHandler) self.createAlertDialog(message: message, responseMessage: nil, confirmButtonTitle: nil, completionHandler: completionHandler)
...@@ -1921,7 +1920,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -1921,7 +1920,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
onJsConfirm(message: message, result: {(result) -> Void in onJsConfirm(message: message, result: {(result) -> Void in
if result is FlutterError { if result is FlutterError {
print((result as! FlutterError).message) print((result as! FlutterError).message ?? "")
} }
else if (result as? NSObject) == FlutterMethodNotImplemented { else if (result as? NSObject) == FlutterMethodNotImplemented {
self.createConfirmDialog(message: message, responseMessage: nil, confirmButtonTitle: nil, cancelButtonTitle: nil, completionHandler: completionHandler) self.createConfirmDialog(message: message, responseMessage: nil, confirmButtonTitle: nil, cancelButtonTitle: nil, completionHandler: completionHandler)
...@@ -1993,7 +1992,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -1993,7 +1992,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
completionHandler: @escaping (String?) -> Void) { completionHandler: @escaping (String?) -> Void) {
onJsPrompt(message: message, defaultValue: defaultValue, result: {(result) -> Void in onJsPrompt(message: message, defaultValue: defaultValue, result: {(result) -> Void in
if result is FlutterError { if result is FlutterError {
print((result as! FlutterError).message) print((result as! FlutterError).message ?? "")
} }
else if (result as? NSObject) == FlutterMethodNotImplemented { else if (result as? NSObject) == FlutterMethodNotImplemented {
self.createPromptDialog(message: message, defaultValue: defaultValue, responseMessage: nil, confirmButtonTitle: nil, cancelButtonTitle: nil, value: nil, completionHandler: completionHandler) self.createPromptDialog(message: message, defaultValue: defaultValue, responseMessage: nil, confirmButtonTitle: nil, cancelButtonTitle: nil, value: nil, completionHandler: completionHandler)
...@@ -2069,102 +2068,56 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -2069,102 +2068,56 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
} }
public func onLoadStart(url: String) { public func onLoadStart(url: String) {
var arguments: [String: Any] = ["url": url] let arguments: [String: Any] = ["url": url]
if IABController != nil { channel?.invokeMethod("onLoadStart", arguments: arguments)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onLoadStart", arguments: arguments)
}
} }
public func onLoadStop(url: String) { public func onLoadStop(url: String) {
var arguments: [String: Any] = ["url": url] let arguments: [String: Any] = ["url": url]
if IABController != nil { channel?.invokeMethod("onLoadStop", arguments: arguments)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onLoadStop", arguments: arguments)
}
} }
public func onLoadError(url: String, error: Error) { public func onLoadError(url: String, error: Error) {
var arguments: [String: Any] = ["url": url, "code": error._code, "message": error.localizedDescription] let arguments: [String: Any] = ["url": url, "code": error._code, "message": error.localizedDescription]
if IABController != nil { channel?.invokeMethod("onLoadError", arguments: arguments)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onLoadError", arguments: arguments)
}
} }
public func onLoadHttpError(url: String, statusCode: Int, description: String) { public func onLoadHttpError(url: String, statusCode: Int, description: String) {
var arguments: [String: Any] = ["url": url, "statusCode": statusCode, "description": description] let arguments: [String: Any] = ["url": url, "statusCode": statusCode, "description": description]
if IABController != nil { channel?.invokeMethod("onLoadHttpError", arguments: arguments)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onLoadHttpError", arguments: arguments)
}
} }
public func onProgressChanged(progress: Int) { public func onProgressChanged(progress: Int) {
var arguments: [String: Any] = ["progress": progress] let arguments: [String: Any] = ["progress": progress]
if IABController != nil { channel?.invokeMethod("onProgressChanged", arguments: arguments)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onProgressChanged", arguments: arguments)
}
} }
public func onFindResultReceived(activeMatchOrdinal: Int, numberOfMatches: Int, isDoneCounting: Bool) { public func onFindResultReceived(activeMatchOrdinal: Int, numberOfMatches: Int, isDoneCounting: Bool) {
var arguments: [String : Any] = [ let arguments: [String : Any] = [
"activeMatchOrdinal": activeMatchOrdinal, "activeMatchOrdinal": activeMatchOrdinal,
"numberOfMatches": numberOfMatches, "numberOfMatches": numberOfMatches,
"isDoneCounting": isDoneCounting "isDoneCounting": isDoneCounting
] ]
channel?.invokeMethod("onFindResultReceived", arguments: arguments)
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onFindResultReceived", arguments: arguments)
}
} }
public func onScrollChanged(x: Int, y: Int) { public func onScrollChanged(x: Int, y: Int) {
var arguments: [String: Any] = ["x": x, "y": y] let arguments: [String: Any] = ["x": x, "y": y]
if IABController != nil { channel?.invokeMethod("onScrollChanged", arguments: arguments)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onScrollChanged", arguments: arguments)
}
} }
public func onDownloadStart(url: String) { public func onDownloadStart(url: String) {
var arguments: [String: Any] = ["url": url] let arguments: [String: Any] = ["url": url]
if IABController != nil { channel?.invokeMethod("onDownloadStart", arguments: arguments)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onDownloadStart", arguments: arguments)
}
} }
public func onLoadResourceCustomScheme(scheme: String, url: String, result: FlutterResult?) { public func onLoadResourceCustomScheme(scheme: String, url: String, result: FlutterResult?) {
var arguments: [String: Any] = ["scheme": scheme, "url": url] let arguments: [String: Any] = ["scheme": scheme, "url": url]
if IABController != nil { channel?.invokeMethod("onLoadResourceCustomScheme", arguments: arguments, result: result)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onLoadResourceCustomScheme", arguments: arguments, result: result)
}
} }
public func shouldOverrideUrlLoading(url: URL, method: String?, headers: [String: String]?, isForMainFrame: Bool, navigationType: WKNavigationType, result: FlutterResult?) { public func shouldOverrideUrlLoading(url: URL, method: String?, headers: [String: String]?, isForMainFrame: Bool, navigationType: WKNavigationType, result: FlutterResult?) {
var arguments: [String: Any?] = [ let arguments: [String: Any?] = [
"url": url.absoluteString, "url": url.absoluteString,
"method": method, "method": method,
"headers": headers, "headers": headers,
...@@ -2173,43 +2126,28 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -2173,43 +2126,28 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
"androidIsRedirect": nil, "androidIsRedirect": nil,
"iosWKNavigationType": navigationType.rawValue "iosWKNavigationType": navigationType.rawValue
] ]
if IABController != nil { channel?.invokeMethod("shouldOverrideUrlLoading", arguments: arguments, result: result)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("shouldOverrideUrlLoading", arguments: arguments, result: result)
}
} }
public func onCreateWindow(url: URL, navigationType: WKNavigationType) { public func onCreateWindow(url: URL, navigationType: WKNavigationType) {
var arguments: [String: Any?] = [ let arguments: [String: Any?] = [
"url": url.absoluteString, "url": url.absoluteString,
"androidIsDialog": nil, "androidIsDialog": nil,
"androidIsUserGesture": nil, "androidIsUserGesture": nil,
"iosWKNavigationType": navigationType.rawValue "iosWKNavigationType": navigationType.rawValue
] ]
if IABController != nil { channel?.invokeMethod("onCreateWindow", arguments: arguments)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onCreateWindow", arguments: arguments)
}
} }
public func onReceivedHttpAuthRequest(challenge: URLAuthenticationChallenge, result: FlutterResult?) { public func onReceivedHttpAuthRequest(challenge: URLAuthenticationChallenge, result: FlutterResult?) {
var arguments: [String: Any?] = [ let arguments: [String: Any?] = [
"host": challenge.protectionSpace.host, "host": challenge.protectionSpace.host,
"protocol": challenge.protectionSpace.protocol, "protocol": challenge.protectionSpace.protocol,
"realm": challenge.protectionSpace.realm, "realm": challenge.protectionSpace.realm,
"port": challenge.protectionSpace.port, "port": challenge.protectionSpace.port,
"previousFailureCount": challenge.previousFailureCount "previousFailureCount": challenge.previousFailureCount
] ]
if IABController != nil { channel?.invokeMethod("onReceivedHttpAuthRequest", arguments: arguments, result: result)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onReceivedHttpAuthRequest", arguments: arguments, result: result)
}
} }
public func onReceivedServerTrustAuthRequest(challenge: URLAuthenticationChallenge, result: FlutterResult?) { public func onReceivedServerTrustAuthRequest(challenge: URLAuthenticationChallenge, result: FlutterResult?) {
...@@ -2222,7 +2160,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -2222,7 +2160,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
serverCertificateData = NSData(bytes: data, length: size) serverCertificateData = NSData(bytes: data, length: size)
} }
var arguments: [String: Any?] = [ let arguments: [String: Any?] = [
"host": challenge.protectionSpace.host, "host": challenge.protectionSpace.host,
"protocol": challenge.protectionSpace.protocol, "protocol": challenge.protectionSpace.protocol,
"realm": challenge.protectionSpace.realm, "realm": challenge.protectionSpace.realm,
...@@ -2232,92 +2170,52 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -2232,92 +2170,52 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
"error": -1, "error": -1,
"message": "", "message": "",
] ]
if IABController != nil { channel?.invokeMethod("onReceivedServerTrustAuthRequest", arguments: arguments, result: result)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onReceivedServerTrustAuthRequest", arguments: arguments, result: result)
}
} }
public func onReceivedClientCertRequest(challenge: URLAuthenticationChallenge, result: FlutterResult?) { public func onReceivedClientCertRequest(challenge: URLAuthenticationChallenge, result: FlutterResult?) {
var arguments: [String: Any?] = [ let arguments: [String: Any?] = [
"host": challenge.protectionSpace.host, "host": challenge.protectionSpace.host,
"protocol": challenge.protectionSpace.protocol, "protocol": challenge.protectionSpace.protocol,
"realm": challenge.protectionSpace.realm, "realm": challenge.protectionSpace.realm,
"port": challenge.protectionSpace.port "port": challenge.protectionSpace.port
] ]
if IABController != nil { channel?.invokeMethod("onReceivedClientCertRequest", arguments: arguments, result: result)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onReceivedClientCertRequest", arguments: arguments, result: result)
}
} }
public func onJsAlert(message: String, result: FlutterResult?) { public func onJsAlert(message: String, result: FlutterResult?) {
var arguments: [String: Any] = ["message": message] let arguments: [String: Any] = ["message": message]
if IABController != nil { channel?.invokeMethod("onJsAlert", arguments: arguments, result: result)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onJsAlert", arguments: arguments, result: result)
}
} }
public func onJsConfirm(message: String, result: FlutterResult?) { public func onJsConfirm(message: String, result: FlutterResult?) {
var arguments: [String: Any] = ["message": message] let arguments: [String: Any] = ["message": message]
if IABController != nil { channel?.invokeMethod("onJsConfirm", arguments: arguments, result: result)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onJsConfirm", arguments: arguments, result: result)
}
} }
public func onJsPrompt(message: String, defaultValue: String?, result: FlutterResult?) { public func onJsPrompt(message: String, defaultValue: String?, result: FlutterResult?) {
var arguments: [String: Any] = ["message": message, "defaultValue": defaultValue as Any] let arguments: [String: Any] = ["message": message, "defaultValue": defaultValue as Any]
if IABController != nil { channel?.invokeMethod("onJsPrompt", arguments: arguments, result: result)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onJsPrompt", arguments: arguments, result: result)
}
} }
public func onConsoleMessage(message: String, messageLevel: Int) { public func onConsoleMessage(message: String, messageLevel: Int) {
var arguments: [String: Any] = ["message": message, "messageLevel": messageLevel] let arguments: [String: Any] = ["message": message, "messageLevel": messageLevel]
if IABController != nil { channel?.invokeMethod("onConsoleMessage", arguments: arguments)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onConsoleMessage", arguments: arguments)
}
} }
public func onUpdateVisitedHistory(url: String) { public func onUpdateVisitedHistory(url: String) {
var arguments: [String: Any?] = [ let arguments: [String: Any?] = [
"url": url, "url": url,
"androidIsReload": nil "androidIsReload": nil
] ]
if IABController != nil { channel?.invokeMethod("onUpdateVisitedHistory", arguments: arguments)
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onUpdateVisitedHistory", arguments: arguments)
}
} }
public func onCallJsHandler(handlerName: String, _callHandlerID: Int64, args: String) { public func onCallJsHandler(handlerName: String, _callHandlerID: Int64, args: String) {
var arguments: [String: Any] = ["handlerName": handlerName, "args": args] let arguments: [String: Any] = ["handlerName": handlerName, "args": args]
if IABController != nil { channel?.invokeMethod("onCallJsHandler", arguments: arguments, result: {(result) -> Void in
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onCallJsHandler", arguments: arguments, result: {(result) -> Void in
if result is FlutterError { if result is FlutterError {
print((result as! FlutterError).message) print((result as! FlutterError).message ?? "")
} }
else if (result as? NSObject) == FlutterMethodNotImplemented {} else if (result as? NSObject) == FlutterMethodNotImplemented {}
else { else {
...@@ -2329,7 +2227,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -2329,7 +2227,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
} }
}) })
} }
}
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name.starts(with: "console") { if message.name.starts(with: "console") {
...@@ -2377,10 +2274,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -2377,10 +2274,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
} }
} }
private func getChannel() -> FlutterMethodChannel? {
return (IABController != nil) ? SwiftFlutterPlugin.instance!.channel! : ((channel != nil) ? channel! : nil);
}
public func findAllAsync(find: String?, completionHandler: ((Any?, Error?) -> Void)?) { public func findAllAsync(find: String?, completionHandler: ((Any?, Error?) -> Void)?) {
let startSearch = "wkwebview_FindAllAsync('\(find ?? "")');" let startSearch = "wkwebview_FindAllAsync('\(find ?? "")');"
evaluateJavaScript(startSearch, completionHandler: completionHandler) evaluateJavaScript(startSearch, completionHandler: completionHandler)
......
...@@ -14,7 +14,7 @@ public class Options: NSObject { ...@@ -14,7 +14,7 @@ public class Options: NSObject {
super.init() super.init()
} }
func parse(options: [String: Any]) -> Options { func parse(options: [String: Any?]) -> Options {
for (key, value) in options { for (key, value) in options {
if self.responds(to: Selector(key)) { if self.responds(to: Selector(key)) {
self.setValue(value, forKey: key) self.setValue(value, forKey: key)
...@@ -23,8 +23,8 @@ public class Options: NSObject { ...@@ -23,8 +23,8 @@ public class Options: NSObject {
return self return self
} }
func getHashMap() -> [String: Any] { func getHashMap() -> [String: Any?] {
var options: [String: Any] = [:] var options: [String: Any?] = [:]
var counts = UInt32(); var counts = UInt32();
let properties = class_copyPropertyList(object_getClass(self), &counts); let properties = class_copyPropertyList(object_getClass(self), &counts);
for i in 0..<counts { for i in 0..<counts {
......
...@@ -9,16 +9,34 @@ import Foundation ...@@ -9,16 +9,34 @@ import Foundation
import SafariServices import SafariServices
@available(iOS 9.0, *) @available(iOS 9.0, *)
class SafariViewController: SFSafariViewController, SFSafariViewControllerDelegate { public class SafariViewController: SFSafariViewController, FlutterPlugin, SFSafariViewControllerDelegate {
weak var statusDelegate: SwiftFlutterPlugin? var channel: FlutterMethodChannel?
var tmpWindow: UIWindow? var tmpWindow: UIWindow?
var safariOptions: SafariBrowserOptions? var safariOptions: SafariBrowserOptions?
var uuid: String = "" var uuid: String = ""
override func viewWillAppear(_ animated: Bool) { public static func register(with registrar: FlutterPluginRegistrar) {
}
deinit {
print("SafariViewController - dealloc")
}
public func prepareMethodChannel() {
channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_chromesafaribrowser_" + uuid, binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger())
SwiftFlutterPlugin.instance!.registrar!.addMethodCallDelegate(self, channel: channel!)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
}
public override func viewWillAppear(_ animated: Bool) {
prepareSafariBrowser() prepareSafariBrowser()
super.viewWillAppear(animated) super.viewWillAppear(animated)
onChromeSafariBrowserOpened()
} }
func prepareSafariBrowser() { func prepareSafariBrowser() {
...@@ -45,50 +63,64 @@ class SafariViewController: SFSafariViewController, SFSafariViewControllerDelega ...@@ -45,50 +63,64 @@ class SafariViewController: SFSafariViewController, SFSafariViewControllerDelega
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(400), execute: {() -> Void in DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(400), execute: {() -> Void in
self.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0) self.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
UIApplication.shared.delegate?.window??.makeKeyAndVisible() UIApplication.shared.delegate?.window??.makeKeyAndVisible()
self.onChromeSafariBrowserClosed()
if (self.statusDelegate != nil) { self.dispose()
self.statusDelegate?.safariExit(uuid: self.uuid)
}
}) })
} }
func safariViewControllerDidFinish(_ controller: SFSafariViewController) { public func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
close() close()
} }
func safariViewController(_ controller: SFSafariViewController, public func safariViewController(_ controller: SFSafariViewController,
didCompleteInitialLoad didLoadSuccessfully: Bool) { didCompleteInitialLoad didLoadSuccessfully: Bool) {
if didLoadSuccessfully { if didLoadSuccessfully {
statusDelegate?.onChromeSafariBrowserCompletedInitialLoad(uuid: self.uuid) onChromeSafariBrowserCompletedInitialLoad()
} }
else { else {
print("Cant load successfully the 'SafariViewController'.") print("Cant load successfully the 'SafariViewController'.")
} }
} }
func safariViewController(_ controller: SFSafariViewController, activityItemsFor URL: URL, title: String?) -> [UIActivity] { public func safariViewController(_ controller: SFSafariViewController, activityItemsFor URL: URL, title: String?) -> [UIActivity] {
// print("activityItemsFor") // print("activityItemsFor")
// print(URL) // print(URL)
// print(title) // print(title)
return [] return []
} }
func safariViewController(_ controller: SFSafariViewController, excludedActivityTypesFor URL: URL, title: String?) -> [UIActivity.ActivityType] { public func safariViewController(_ controller: SFSafariViewController, excludedActivityTypesFor URL: URL, title: String?) -> [UIActivity.ActivityType] {
// print("excludedActivityTypesFor") // print("excludedActivityTypesFor")
// print(URL) // print(URL)
// print(title) // print(title)
return [] return []
} }
func safariViewController(_ controller: SFSafariViewController, initialLoadDidRedirectTo URL: URL) { public func safariViewController(_ controller: SFSafariViewController, initialLoadDidRedirectTo URL: URL) {
// print("initialLoadDidRedirectTo") // print("initialLoadDidRedirectTo")
// print(URL) // print(URL)
} }
public func onChromeSafariBrowserOpened() {
channel!.invokeMethod("onChromeSafariBrowserOpened", arguments: [])
}
public func onChromeSafariBrowserCompletedInitialLoad() {
channel!.invokeMethod("onChromeSafariBrowserCompletedInitialLoad", arguments: [])
}
public func onChromeSafariBrowserClosed() {
channel!.invokeMethod("onChromeSafariBrowserClosed", arguments: [])
}
public func dispose() {
delegate = nil
channel!.setMethodCallHandler(nil)
}
// Helper function to convert hex color string to UIColor // Helper function to convert hex color string to UIColor
// Assumes input like "#00FF00" (#RRGGBB). // Assumes input like "#00FF00" (#RRGGBB).
// Taken from https://stackoverflow.com/questions/1560081/how-can-i-create-a-uicolor-from-a-hex-string // Taken from https://stackoverflow.com/questions/1560081/how-can-i-create-a-uicolor-from-a-hex-string
func color(fromHexString: String, alpha:CGFloat? = 1.0) -> UIColor { func color(fromHexString: String, alpha:CGFloat? = 1.0) -> UIColor {
// Convert hex string to an integer // Convert hex string to an integer
......
...@@ -22,22 +22,16 @@ import Foundation ...@@ -22,22 +22,16 @@ import Foundation
import AVFoundation import AVFoundation
import SafariServices import SafariServices
let WEBVIEW_STORYBOARD = "WebView"
let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController"
extension Dictionary where Key: ExpressibleByStringLiteral {
public mutating func lowercaseKeys() {
for key in self.keys {
self[String(describing: key).lowercased() as! Key] = self.removeValue(forKey: key)
}
}
}
public class SwiftFlutterPlugin: NSObject, FlutterPlugin { public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
static var instance: SwiftFlutterPlugin? static var instance: SwiftFlutterPlugin?
var registrar: FlutterPluginRegistrar? var registrar: FlutterPluginRegistrar?
var channel: FlutterMethodChannel? var inAppWebViewStatic: InAppWebViewStatic?
var myCookieManager: Any?
var myWebStorageManager: Any?
var credentialDatabase: CredentialDatabase?
var inAppBrowserManager: InAppBrowserManager?
var chromeSafariBrowserManager: ChromeSafariBrowserManager?
var webViewControllers: [String: InAppBrowserWebViewController?] = [:] var webViewControllers: [String: InAppBrowserWebViewController?] = [:]
var safariViewControllers: [String: Any?] = [:] var safariViewControllers: [String: Any?] = [:]
...@@ -49,855 +43,21 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { ...@@ -49,855 +43,21 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
super.init() super.init()
self.registrar = registrar self.registrar = registrar
self.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappbrowser", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(self, channel: channel!)
}
public static func register(with registrar: FlutterPluginRegistrar) {
SwiftFlutterPlugin.instance = SwiftFlutterPlugin(with: registrar)
registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: "com.pichillilorenzo/flutter_inappwebview") registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: "com.pichillilorenzo/flutter_inappwebview")
InAppWebViewStatic(registrar: registrar) inAppBrowserManager = InAppBrowserManager(registrar: registrar)
if #available(iOS 11.0, *) { chromeSafariBrowserManager = ChromeSafariBrowserManager(registrar: registrar)
MyCookieManager(registrar: registrar) inAppWebViewStatic = InAppWebViewStatic(registrar: registrar)
}
if #available(iOS 9.0, *) {
MyWebStorageManager(registrar: registrar)
}
CredentialDatabase(registrar: registrar)
}
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)
break
case "getUrl":
if let webViewController = self.webViewControllers[uuid] {
result(webViewController!.webView.url?.absoluteString)
}
else {
result(nil)
}
break
case "getTitle":
if let webViewController = self.webViewControllers[uuid] {
result(webViewController!.webView.title)
}
else {
result(nil)
}
break
case "getProgress":
if let webViewController = self.webViewControllers[uuid] {
let progress = Int(webViewController!.webView.estimatedProgress * 100)
result(progress)
}
else {
result(nil)
}
break
case "loadUrl":
self.loadUrl(uuid: uuid, arguments: arguments!, result: result)
break
case "loadData":
self.loadData(uuid: uuid, arguments: arguments!, result: result)
break
case "postUrl":
self.postUrl(uuid: uuid, arguments: arguments!, result: result)
break
case "loadFile":
self.loadFile(uuid: uuid, arguments: arguments!, result: result)
break
case "close":
self.close(uuid: uuid)
result(true)
break
case "show":
self.show(uuid: uuid)
result(true)
break
case "hide":
self.hide(uuid: uuid)
result(true)
break
case "reload":
if let webViewController = self.webViewControllers[uuid] {
webViewController!.reload()
}
result(true)
break
case "goBack":
if let webViewController = self.webViewControllers[uuid] {
webViewController!.goBack()
}
result(true)
break
case "canGoBack":
if let webViewController = self.webViewControllers[uuid] {
result(webViewController!.canGoBack())
}
else {
result(false)
}
break
case "goForward":
if let webViewController = self.webViewControllers[uuid] {
webViewController!.goForward()
}
result(true)
break
case "canGoForward":
if let webViewController = self.webViewControllers[uuid] {
result(webViewController!.canGoForward())
}
else {
result(false)
}
break
case "goBackOrForward":
if let webViewController = self.webViewControllers[uuid] {
let steps = arguments!["steps"] as! Int
webViewController!.goBackOrForward(steps: steps)
}
result(true)
break
case "canGoBackOrForward":
if let webViewController = self.webViewControllers[uuid] {
let steps = arguments!["steps"] as! Int
result(webViewController!.canGoBackOrForward(steps: steps))
}
else {
result(false)
}
break
case "isLoading":
if let webViewController = self.webViewControllers[uuid] {
result(webViewController!.webView.isLoading == true)
}
else {
result(false)
}
break
case "stopLoading":
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.stopLoading()
}
result(true)
break
case "isHidden":
if let webViewController = self.webViewControllers[uuid] {
result(webViewController!.isHidden == true)
}
else {
result(false)
}
break
case "evaluateJavascript":
self.evaluateJavascript(uuid: uuid, arguments: arguments!, result: result)
break
case "injectJavascriptFileFromUrl":
self.injectJavascriptFileFromUrl(uuid: uuid, arguments: arguments!)
result(true)
break
case "injectCSSCode":
self.injectCSSCode(uuid: uuid, arguments: arguments!)
result(true)
break
case "injectCSSFileFromUrl":
self.injectCSSFileFromUrl(uuid: uuid, arguments: arguments!)
result(true)
break
case "takeScreenshot":
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.takeScreenshot(completionHandler: { (screenshot) -> Void in
result(screenshot)
})
}
else {
result(nil)
}
break
case "setOptions":
let optionsType = arguments!["optionsType"] as! String
switch (optionsType){
case "InAppBrowserOptions":
let inAppBrowserOptions = InAppBrowserOptions()
let inAppBrowserOptionsMap = arguments!["options"] as! [String: Any]
inAppBrowserOptions.parse(options: inAppBrowserOptionsMap)
self.setOptions(uuid: uuid, options: inAppBrowserOptions, optionsMap: inAppBrowserOptionsMap)
break
default:
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: "Options " + optionsType + " not available.", details: nil))
}
result(true)
break
case "getOptions":
result(self.getOptions(uuid: uuid))
break
case "getCopyBackForwardList":
result(self.getCopyBackForwardList(uuid: uuid))
break
case "findAllAsync":
let find = arguments!["find"] as! String
self.findAllAsync(uuid: uuid, find: find)
result(true)
break
case "findNext":
let forward = arguments!["forward"] as! Bool
self.findNext(uuid: uuid, forward: forward, result: result)
break
case "clearMatches":
self.clearMatches(uuid: uuid, result: result)
break
case "clearCache":
self.clearCache(uuid: uuid)
result(true)
break
case "scrollTo":
let x = arguments!["x"] as! Int
let y = arguments!["y"] as! Int
self.scrollTo(uuid: uuid, x: x, y: y)
result(true)
break
case "scrollBy":
let x = arguments!["x"] as! Int
let y = arguments!["y"] as! Int
self.scrollTo(uuid: uuid, x: x, y: y)
result(true)
break
case "pauseTimers":
self.pauseTimers(uuid: uuid)
result(true)
break
case "resumeTimers":
self.resumeTimers(uuid: uuid)
result(true)
break
case "printCurrentPage":
self.printCurrentPage(uuid: uuid, result: result)
break
case "getContentHeight":
result(self.getContentHeight(uuid: uuid))
break
case "reloadFromOrigin":
self.reloadFromOrigin(uuid: uuid)
result(true)
break
case "getScale":
result(self.getScale(uuid: uuid))
break
default:
result(FlutterMethodNotImplemented)
break
}
}
func close(uuid: String) {
if let webViewController = self.webViewControllers[uuid] {
// Things are cleaned up in browserExit.
webViewController?.close()
}
else {
print("IAB.close() called but it was already closed.")
}
}
func isSystemUrl(_ url: URL) -> Bool {
if (url.host == "itunes.apple.com") {
return true
}
return false
}
public func open(uuid: String, arguments: NSDictionary, result: @escaping FlutterResult) {
let isData: Bool = (arguments["isData"] as? Bool)!
if !isData {
let url: String = (arguments["url"] as? String)!
let headers = (arguments["headers"] as? [String: String])!
var absoluteUrl = URL(string: url)?.absoluteURL
let useChromeSafariBrowser = (arguments["useChromeSafariBrowser"] as? Bool)!
if useChromeSafariBrowser {
let uuidFallback = (arguments["uuidFallback"] as? String)!
let safariOptions = (arguments["options"] as? [String: Any])!
let optionsFallback = (arguments["optionsFallback"] as? [String: Any])!
open(uuid: uuid, uuidFallback: uuidFallback, inAppBrowser: absoluteUrl!, headers: headers, withOptions: safariOptions, useChromeSafariBrowser: true, withOptionsFallback: optionsFallback, result: result)
}
else {
let options = (arguments["options"] as? [String: Any])!
let isLocalFile = (arguments["isLocalFile"] as? Bool)!
var openWithSystemBrowser = (arguments["openWithSystemBrowser"] as? Bool)!
if isLocalFile {
let key = self.registrar!.lookupKey(forAsset: url)
let assetURL = Bundle.main.url(forResource: key, withExtension: nil)
if assetURL == nil {
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: url + " asset file cannot be found!", details: nil))
return
}
absoluteUrl = assetURL!
}
if isSystemUrl(absoluteUrl!) {
openWithSystemBrowser = true
}
if (openWithSystemBrowser) {
open(inSystem: absoluteUrl!, result: result)
}
else {
open(uuid: uuid, uuidFallback: nil, inAppBrowser: absoluteUrl!, headers: headers, withOptions: options, useChromeSafariBrowser: false, withOptionsFallback: nil, result: result)
}
}
}
else {
let options = (arguments["options"] as? [String: Any])!
let data = (arguments["data"] as? String)!
let mimeType = (arguments["mimeType"] as? String)!
let encoding = (arguments["encoding"] as? String)!
let baseUrl = (arguments["baseUrl"] as? String)!
open(uuid: uuid, options: options, data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
result(true)
}
}
func open(uuid: String, uuidFallback: String?, inAppBrowser url: URL, headers: [String: String], withOptions options: [String: Any], useChromeSafariBrowser: Bool, withOptionsFallback optionsFallback: [String: Any]?, result: @escaping FlutterResult) {
var uuid = uuid
if self.webViewControllers[uuid] != nil {
close(uuid: uuid)
}
let safariViewController = self.safariViewControllers[uuid]
if safariViewController != nil {
if #available(iOS 9.0, *) {
(safariViewController! as! SafariViewController).close()
self.safariViewControllers[uuid] = nil
} else {
// Fallback on earlier versions
}
}
if self.previousStatusBarStyle == -1 {
self.previousStatusBarStyle = UIApplication.shared.statusBarStyle.rawValue
}
if !(self.tmpWindow != nil) {
let frame: CGRect = UIScreen.main.bounds
self.tmpWindow = UIWindow(frame: frame)
}
let tmpController = UIViewController()
let baseWindowLevel = UIApplication.shared.keyWindow?.windowLevel
self.tmpWindow?.rootViewController = tmpController
self.tmpWindow?.windowLevel = UIWindow.Level(baseWindowLevel!.rawValue + 1.0)
self.tmpWindow?.makeKeyAndVisible()
let browserOptions: InAppBrowserOptions
let webViewOptions: InAppWebViewOptions
if useChromeSafariBrowser == true {
if #available(iOS 9.0, *) {
let safariOptions = SafariBrowserOptions()
safariOptions.parse(options: options)
let safari: SafariViewController
if #available(iOS 11.0, *) { if #available(iOS 11.0, *) {
let config = SFSafariViewController.Configuration() myCookieManager = MyCookieManager(registrar: registrar)
config.entersReaderIfAvailable = safariOptions.entersReaderIfAvailable
config.barCollapsingEnabled = safariOptions.barCollapsingEnabled
safari = SafariViewController(url: url, configuration: config)
} else {
// Fallback on earlier versions
safari = SafariViewController(url: url)
}
safari.uuid = uuid
safari.delegate = safari
safari.statusDelegate = self
safari.tmpWindow = tmpWindow
safari.safariOptions = safariOptions
self.safariViewControllers[uuid] = safari
tmpController.present(self.safariViewControllers[uuid]! as! SFSafariViewController, animated: true) {
self.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!)
webViewOptions = InAppWebViewOptions()
webViewOptions.parse(options: optionsFallback!)
}
}
else {
browserOptions = InAppBrowserOptions()
browserOptions.parse(options: options)
webViewOptions = InAppWebViewOptions()
webViewOptions.parse(options: options)
}
let storyboard = UIStoryboard(name: WEBVIEW_STORYBOARD, bundle: Bundle(for: InAppWebViewFlutterPlugin.self))
let vc = storyboard.instantiateViewController(withIdentifier: WEBVIEW_STORYBOARD_CONTROLLER_ID)
self.webViewControllers[uuid] = vc as? InAppBrowserWebViewController
let webViewController: InAppBrowserWebViewController = self.webViewControllers[uuid] as! InAppBrowserWebViewController
webViewController.uuid = uuid
webViewController.browserOptions = browserOptions
webViewController.webViewOptions = webViewOptions
webViewController.isHidden = browserOptions.hidden
webViewController.tmpWindow = tmpWindow
webViewController.initURL = url
webViewController.initHeaders = headers
webViewController.navigationDelegate = self
if browserOptions.hidden {
webViewController.view.isHidden = true
tmpController.present(webViewController, animated: false, completion: {() -> Void in
// if self.previousStatusBarStyle != -1 {
// UIApplication.shared.statusBarStyle = UIStatusBarStyle(rawValue: self.previousStatusBarStyle)!
// }
})
// if self.previousStatusBarStyle != -1 {
// UIApplication.shared.statusBarStyle = UIStatusBarStyle(rawValue: self.previousStatusBarStyle)!
// }
webViewController.presentingViewController?.dismiss(animated: false, completion: {() -> Void in
self.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
})
}
else {
tmpController.present(webViewController, animated: true, completion: nil)
}
result(true)
}
func open(uuid: String, options: [String: Any], data: String, mimeType: String, encoding: String, baseUrl: String) {
var uuid = uuid
if self.webViewControllers[uuid] != nil {
close(uuid: uuid)
}
if self.previousStatusBarStyle == -1 {
self.previousStatusBarStyle = UIApplication.shared.statusBarStyle.rawValue
}
if !(self.tmpWindow != nil) {
let frame: CGRect = UIScreen.main.bounds
self.tmpWindow = UIWindow(frame: frame)
}
let tmpController = UIViewController()
let baseWindowLevel = UIApplication.shared.keyWindow?.windowLevel
self.tmpWindow?.rootViewController = tmpController
self.tmpWindow?.windowLevel = UIWindow.Level(baseWindowLevel!.rawValue + 1.0)
self.tmpWindow?.makeKeyAndVisible()
let browserOptions: InAppBrowserOptions
let webViewOptions: InAppWebViewOptions
browserOptions = InAppBrowserOptions()
browserOptions.parse(options: options)
webViewOptions = InAppWebViewOptions()
webViewOptions.parse(options: options)
let storyboard = UIStoryboard(name: WEBVIEW_STORYBOARD, bundle: Bundle(for: InAppWebViewFlutterPlugin.self))
let vc = storyboard.instantiateViewController(withIdentifier: WEBVIEW_STORYBOARD_CONTROLLER_ID)
self.webViewControllers[uuid] = vc as? InAppBrowserWebViewController
let webViewController: InAppBrowserWebViewController = self.webViewControllers[uuid] as! InAppBrowserWebViewController
webViewController.uuid = uuid
webViewController.browserOptions = browserOptions
webViewController.webViewOptions = webViewOptions
webViewController.isHidden = browserOptions.hidden
webViewController.tmpWindow = tmpWindow
webViewController.initData = data
webViewController.initMimeType = mimeType
webViewController.initEncoding = encoding
webViewController.initBaseUrl = baseUrl
webViewController.navigationDelegate = self
if browserOptions.hidden {
webViewController.view.isHidden = true
tmpController.present(webViewController, animated: false, completion: {() -> Void in
webViewController.webView.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
})
webViewController.presentingViewController?.dismiss(animated: false, completion: {() -> Void in
self.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
})
}
else {
tmpController.present(webViewController, animated: true, completion: {() -> Void in
webViewController.webView.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
})
}
}
func open(inSystem url: URL, result: @escaping FlutterResult) {
if !UIApplication.shared.canOpenURL(url) {
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: url.absoluteString + " cannot be opened!", details: nil))
return
} }
else {
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: convertToUIApplicationOpenExternalURLOptionsKeyDictionary([:]), completionHandler: nil)
} else {
UIApplication.shared.openURL(url)
}
}
result(true)
}
public func show(uuid: String) {
if let webViewController = self.webViewControllers[uuid] {
if webViewController != nil {
webViewController?.isHidden = false
webViewController?.view.isHidden = false
// Run later to avoid the "took a long time" log message.
DispatchQueue.main.async(execute: {() -> Void in
if webViewController != nil {
let baseWindowLevel = UIApplication.shared.keyWindow?.windowLevel
self.tmpWindow?.windowLevel = UIWindow.Level(baseWindowLevel!.rawValue + 1.0)
self.tmpWindow?.makeKeyAndVisible()
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
self.tmpWindow?.rootViewController?.present(webViewController!, animated: true, completion: nil)
}
})
}
else {
print("Tried to hide IAB after it was closed.")
}
}
}
public func hide(uuid: String) {
if let webViewController = self.webViewControllers[uuid] {
if webViewController != nil {
webViewController?.isHidden = true
// Run later to avoid the "took a long time" log message.
DispatchQueue.main.async(execute: {() -> Void in
if webViewController != nil {
webViewController?.presentingViewController?.dismiss(animated: true, completion: {() -> Void in
self.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
if self.previousStatusBarStyle != -1 {
UIApplication.shared.statusBarStyle = UIStatusBarStyle(rawValue: self.previousStatusBarStyle)!
}
})
}
})
}
else {
print("Tried to hide IAB after it was closed.")
}
}
}
public func loadUrl(uuid: String, arguments: NSDictionary, result: @escaping FlutterResult) {
if let webViewController = self.webViewControllers[uuid] {
if let url = arguments["url"] as? String {
let headers = (arguments["headers"] as? [String: String])!
let absoluteUrl = URL(string: url)!.absoluteURL
webViewController!.loadUrl(url: absoluteUrl, headers: headers)
}
else {
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: "url is empty", details: nil))
return
}
result(true)
}
else {
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: "webView is null", details: nil))
}
}
public func loadData(uuid: String, arguments: NSDictionary, result: @escaping FlutterResult) {
if let webViewController = self.webViewControllers[uuid] {
let data = (arguments["data"] as? String)!
let mimeType = (arguments["mimeType"] as? String)!
let encoding = (arguments["encoding"] as? String)!
let baseUrl = (arguments["baseUrl"] as? String)!
webViewController!.webView.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
result(true)
}
else {
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: "webView is null", details: nil))
}
}
public func postUrl(uuid: String, arguments: NSDictionary, result: @escaping FlutterResult) {
if let webViewController = self.webViewControllers[uuid] {
if let url = arguments["url"] as? String {
let postData = (arguments["postData"] as? FlutterStandardTypedData)!
let absoluteUrl = URL(string: url)!.absoluteURL
webViewController!.webView.postUrl(url: absoluteUrl, postData: postData.data, completionHandler: { () -> Void in
result(true)
})
}
else {
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: "url is empty", details: nil))
return
}
}
else {
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: "webView is null", details: nil))
}
}
public func loadFile(uuid: String, arguments: NSDictionary, result: @escaping FlutterResult) {
if let webViewController = self.webViewControllers[uuid] {
if let url = arguments["url"] as? String {
let headers = (arguments["headers"] as? [String: String])!
do {
try webViewController!.webView.loadFile(url: url, headers: headers)
}
catch let error as NSError {
dump(error)
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: error.localizedDescription, details: nil))
return
}
}
else {
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: "url is empty", details: nil))
return
}
result(true)
}
else {
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: "webView is null", details: nil))
}
}
public func evaluateJavascript(uuid: String, arguments: NSDictionary, result: @escaping FlutterResult) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.evaluateJavascript(source: arguments["source"] as! String, result: result)
}
else {
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: "webView is null", details: nil))
}
}
public func injectJavascriptFileFromUrl(uuid: String, arguments: NSDictionary) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.injectJavascriptFileFromUrl(urlFile: arguments["urlFile"] as! String)
}
}
public func injectCSSCode(uuid: String, arguments: NSDictionary) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.injectCSSCode(source: arguments["source"] as! String)
}
}
public func injectCSSFileFromUrl(uuid: String, arguments: NSDictionary) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.injectCSSFileFromUrl(urlFile: arguments["urlFile"] as! String)
}
}
public func onBrowserCreated(uuid: String, webView: WKWebView) {
if let webViewController = self.webViewControllers[uuid] {
self.channel!.invokeMethod("onBrowserCreated", arguments: ["uuid": uuid])
}
}
public func onExit(uuid: String) {
self.channel!.invokeMethod("onExit", arguments: ["uuid": uuid])
}
public func onChromeSafariBrowserOpened(uuid: String) {
if self.safariViewControllers[uuid] != nil {
self.channel!.invokeMethod("onChromeSafariBrowserOpened", arguments: ["uuid": uuid])
}
}
public func onChromeSafariBrowserCompletedInitialLoad(uuid: String) {
if self.safariViewControllers[uuid] != nil {
self.channel!.invokeMethod("onChromeSafariBrowserCompletedInitialLoad", arguments: ["uuid": uuid])
}
}
public func onChromeSafariBrowserClosed(uuid: String) {
self.channel!.invokeMethod("onChromeSafariBrowserClosed", arguments: ["uuid": uuid])
}
public func safariExit(uuid: String) {
if let safariViewController = self.safariViewControllers[uuid] {
if #available(iOS 9.0, *) { if #available(iOS 9.0, *) {
(safariViewController as! SafariViewController).statusDelegate = nil myWebStorageManager = MyWebStorageManager(registrar: registrar)
(safariViewController as! SafariViewController).delegate = nil
}
self.safariViewControllers[uuid] = nil
onChromeSafariBrowserClosed(uuid: uuid)
}
}
public func browserExit(uuid: String) {
if let webViewController = self.webViewControllers[uuid] {
// Set navigationDelegate to nil to ensure no callbacks are received from it.
webViewController?.navigationDelegate = nil
// Don't recycle the ViewController since it may be consuming a lot of memory.
// Also - this is required for the PDF/User-Agent bug work-around.
self.webViewControllers[uuid] = nil
if previousStatusBarStyle != -1 {
UIApplication.shared.statusBarStyle = UIStatusBarStyle(rawValue: previousStatusBarStyle)!
}
onExit(uuid: uuid)
}
}
public func setOptions(uuid: String, options: InAppBrowserOptions, optionsMap: [String: Any]) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.setOptions(newOptions: options, newOptionsMap: optionsMap)
} }
credentialDatabase = CredentialDatabase(registrar: registrar)
} }
public func getOptions(uuid: String) -> [String: Any]? { public static func register(with registrar: FlutterPluginRegistrar) {
if let webViewController = self.webViewControllers[uuid] { SwiftFlutterPlugin.instance = SwiftFlutterPlugin(with: registrar)
return webViewController!.getOptions()
}
return nil
}
public func getCopyBackForwardList(uuid: String) -> [String: Any]? {
if let webViewController = self.webViewControllers[uuid] {
return webViewController!.webView.getCopyBackForwardList()
}
return nil
}
public func findAllAsync(uuid: String, find: String) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.findAllAsync(find: find, completionHandler: nil)
}
}
public func findNext(uuid: String, forward: Bool, result: @escaping FlutterResult) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.findNext(forward: forward, completionHandler: {(value, error) in
if error != nil {
result(FlutterError(code: "FlutterWebViewController", message: error?.localizedDescription, details: nil))
return
}
result(true)
})
} else {
result(false)
}
}
public func clearMatches(uuid: String, result: @escaping FlutterResult) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.clearMatches(completionHandler: {(value, error) in
if error != nil {
result(FlutterError(code: "FlutterWebViewController", message: error?.localizedDescription, details: nil))
return
}
result(true)
})
} else {
result(false)
}
}
public func clearCache(uuid: String) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.clearCache()
}
}
public func scrollTo(uuid: String, x: Int, y: Int) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.scrollTo(x: x, y: y)
}
}
public func scrollBy(uuid: String, x: Int, y: Int) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.scrollBy(x: x, y: y)
}
}
public func pauseTimers(uuid: String) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.pauseTimers()
}
}
public func resumeTimers(uuid: String) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.resumeTimers()
}
}
public func printCurrentPage(uuid: String, result: @escaping FlutterResult) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.printCurrentPage(printCompletionHandler: {(completed, error) in
if !completed, let e = error {
result(false)
return
}
result(true)
})
} else {
result(false)
}
}
public func getContentHeight(uuid: String) -> Int64? {
if let webViewController = self.webViewControllers[uuid] {
return webViewController!.webView.getContentHeight()
}
return nil
}
public func reloadFromOrigin(uuid: String) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.reloadFromOrigin()
}
}
public func getScale(uuid: String) -> Float? {
if let webViewController = self.webViewControllers[uuid] {
return webViewController!.webView.getScale()
}
return nil
} }
} }
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToUIApplicationOpenExternalURLOptionsKeyDictionary(_ input: [String: Any]) -> [UIApplication.OpenExternalURLOptionsKey: Any] {
return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
}
...@@ -24,7 +24,6 @@ library flutter_inappwebview; ...@@ -24,7 +24,6 @@ library flutter_inappwebview;
export 'src/types.dart'; export 'src/types.dart';
export 'src/in_app_webview.dart'; export 'src/in_app_webview.dart';
export 'src/in_app_browser.dart'; export 'src/in_app_browser.dart';
export 'src/channel_manager.dart';
export 'src/cookie_manager.dart'; export 'src/cookie_manager.dart';
export 'src/chrome_safari_browser.dart'; export 'src/chrome_safari_browser.dart';
export 'src/chrome_safari_browser.dart'; export 'src/chrome_safari_browser.dart';
......
import 'dart:async';
import 'dart:collection';
import 'package:flutter/services.dart';
import 'types.dart' show ListenerCallback;
class ChannelManager {
static const MethodChannel channel =
const MethodChannel('com.pichillilorenzo/flutter_inappbrowser');
static bool initialized = false;
static final listeners = HashMap<String, ListenerCallback>();
static Future<dynamic> _handleMethod(MethodCall call) async {
String uuid = call.arguments["uuid"];
return await listeners[uuid](call);
}
static void addListener(String key, ListenerCallback callback) {
if (!initialized) init();
listeners.putIfAbsent(key, () => callback);
}
static void init() {
channel.setMethodCallHandler(_handleMethod);
initialized = true;
}
}
...@@ -5,7 +5,6 @@ import 'package:flutter/foundation.dart'; ...@@ -5,7 +5,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'types.dart'; import 'types.dart';
import 'channel_manager.dart';
import 'in_app_browser.dart'; import 'in_app_browser.dart';
///ChromeSafariBrowser class. ///ChromeSafariBrowser class.
...@@ -18,12 +17,16 @@ class ChromeSafariBrowser { ...@@ -18,12 +17,16 @@ class ChromeSafariBrowser {
String uuid; String uuid;
InAppBrowser browserFallback; InAppBrowser browserFallback;
bool _isOpened = false; bool _isOpened = false;
MethodChannel _channel;
static const MethodChannel _sharedChannel = const MethodChannel('com.pichillilorenzo/flutter_chromesafaribrowser');
///Initialize the [ChromeSafariBrowser] instance with an [InAppBrowser] fallback instance or `null`. ///Initialize the [ChromeSafariBrowser] instance with an [InAppBrowser] fallback instance or `null`.
ChromeSafariBrowser({bFallback}) { ChromeSafariBrowser({bFallback}) {
uuid = uuidGenerator.v4(); uuid = uuidGenerator.v4();
browserFallback = bFallback; browserFallback = bFallback;
ChannelManager.addListener(uuid, handleMethod); this._channel =
MethodChannel('com.pichillilorenzo/flutter_chromesafaribrowser_$uuid');
this._channel.setMethodCallHandler(handleMethod);
_isOpened = false; _isOpened = false;
} }
...@@ -94,15 +97,13 @@ class ChromeSafariBrowser { ...@@ -94,15 +97,13 @@ class ChromeSafariBrowser {
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('uuidFallback',
() => (browserFallback != null) ? browserFallback.uuid : '');
args.putIfAbsent('url', () => url); args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headersFallback);
args.putIfAbsent('options', () => optionsMap); args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('uuidFallback',
() => (browserFallback != null) ? browserFallback.uuid : '');
args.putIfAbsent('headersFallback', () => headersFallback);
args.putIfAbsent('optionsFallback', () => optionsFallbackMap); args.putIfAbsent('optionsFallback', () => optionsFallbackMap);
args.putIfAbsent('isData', () => false); await _sharedChannel.invokeMethod('open', args);
args.putIfAbsent('useChromeSafariBrowser', () => true);
await ChannelManager.channel.invokeMethod('open', args);
this._isOpened = true; this._isOpened = true;
} }
......
...@@ -7,7 +7,6 @@ import 'package:flutter/services.dart'; ...@@ -7,7 +7,6 @@ import 'package:flutter/services.dart';
import 'webview_options.dart'; import 'webview_options.dart';
import 'types.dart'; import 'types.dart';
import 'channel_manager.dart';
import 'in_app_webview.dart' show InAppWebViewController; import 'in_app_webview.dart' show InAppWebViewController;
///InAppBrowser class. [webViewController] can be used to access the [InAppWebView] API. ///InAppBrowser class. [webViewController] can be used to access the [InAppWebView] API.
...@@ -18,6 +17,8 @@ class InAppBrowser { ...@@ -18,6 +17,8 @@ class InAppBrowser {
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap = Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap =
HashMap<String, JavaScriptHandlerCallback>(); HashMap<String, JavaScriptHandlerCallback>();
bool _isOpened = false; bool _isOpened = false;
MethodChannel _channel;
static const MethodChannel _sharedChannel = const MethodChannel('com.pichillilorenzo/flutter_inappbrowser');
/// WebView Controller that can be used to access the [InAppWebView] API. /// WebView Controller that can be used to access the [InAppWebView] API.
InAppWebViewController webViewController; InAppWebViewController webViewController;
...@@ -25,10 +26,12 @@ class InAppBrowser { ...@@ -25,10 +26,12 @@ class InAppBrowser {
/// ///
InAppBrowser() { InAppBrowser() {
uuid = uuidGenerator.v4(); uuid = uuidGenerator.v4();
ChannelManager.addListener(uuid, handleMethod); this._channel =
MethodChannel('com.pichillilorenzo/flutter_inappbrowser_$uuid');
this._channel.setMethodCallHandler(handleMethod);
_isOpened = false; _isOpened = false;
webViewController = new InAppWebViewController.fromInAppBrowser( webViewController = new InAppWebViewController.fromInAppBrowser(
uuid, ChannelManager.channel, this); uuid, this._channel, this);
} }
Future<dynamic> handleMethod(MethodCall call) async { Future<dynamic> handleMethod(MethodCall call) async {
...@@ -53,8 +56,8 @@ class InAppBrowser { ...@@ -53,8 +56,8 @@ class InAppBrowser {
///[headers]: The additional headers to be used in the HTTP request for this URL, specified as a map from name to value. ///[headers]: The additional headers to be used in the HTTP request for this URL, specified as a map from name to value.
/// ///
///[options]: Options for the [InAppBrowser]. ///[options]: Options for the [InAppBrowser].
Future<void> open( Future<void> openUrl(
{String url = "about:blank", {@required String url,
Map<String, String> headers = const {}, Map<String, String> headers = const {},
InAppBrowserClassOptions options}) async { InAppBrowserClassOptions options}) async {
assert(url != null && url.isNotEmpty); assert(url != null && url.isNotEmpty);
...@@ -83,14 +86,10 @@ class InAppBrowser { ...@@ -83,14 +86,10 @@ class InAppBrowser {
args.putIfAbsent('url', () => url); args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headers); args.putIfAbsent('headers', () => headers);
args.putIfAbsent('options', () => optionsMap); args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('openWithSystemBrowser', () => false); await _sharedChannel.invokeMethod('openUrl', args);
args.putIfAbsent('isLocalFile', () => false);
args.putIfAbsent('isData', () => false);
args.putIfAbsent('useChromeSafariBrowser', () => false);
await ChannelManager.channel.invokeMethod('open', args);
} }
///Opens the given [assetFilePath] file in a new [InAppBrowser] instance. The other arguments are the same of [InAppBrowser.open]. ///Opens the given [assetFilePath] file in a new [InAppBrowser] instance. The other arguments are the same of [InAppBrowser.openUrl].
/// ///
///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! ///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!
/// ///
...@@ -153,11 +152,7 @@ class InAppBrowser { ...@@ -153,11 +152,7 @@ class InAppBrowser {
args.putIfAbsent('url', () => assetFilePath); args.putIfAbsent('url', () => assetFilePath);
args.putIfAbsent('headers', () => headers); args.putIfAbsent('headers', () => headers);
args.putIfAbsent('options', () => optionsMap); args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('openWithSystemBrowser', () => false); await _sharedChannel.invokeMethod('openFile', args);
args.putIfAbsent('isLocalFile', () => true);
args.putIfAbsent('isData', () => false);
args.putIfAbsent('useChromeSafariBrowser', () => false);
await ChannelManager.channel.invokeMethod('open', args);
} }
///Opens a new [InAppBrowser] instance with [data] as a content, using [baseUrl] as the base URL for it. ///Opens a new [InAppBrowser] instance with [data] as a content, using [baseUrl] as the base URL for it.
...@@ -203,26 +198,16 @@ class InAppBrowser { ...@@ -203,26 +198,16 @@ class InAppBrowser {
args.putIfAbsent('mimeType', () => mimeType); args.putIfAbsent('mimeType', () => mimeType);
args.putIfAbsent('encoding', () => encoding); args.putIfAbsent('encoding', () => encoding);
args.putIfAbsent('baseUrl', () => baseUrl); args.putIfAbsent('baseUrl', () => baseUrl);
args.putIfAbsent('openWithSystemBrowser', () => false); args.putIfAbsent('historyUrl', () => androidHistoryUrl);
args.putIfAbsent('isLocalFile', () => false); await _sharedChannel.invokeMethod('openData', args);
args.putIfAbsent('isData', () => true);
args.putIfAbsent('useChromeSafariBrowser', () => false);
await ChannelManager.channel.invokeMethod('open', args);
} }
///This is a static method that opens an [url] in the system browser. You wont be able to use the [InAppBrowser] methods here! ///This is a static method that opens an [url] in the system browser. You wont be able to use the [InAppBrowser] methods here!
static Future<void> openWithSystemBrowser({@required String url}) async { static Future<void> openWithSystemBrowser({@required String url}) async {
assert(url != null && url.isNotEmpty); assert(url != null && url.isNotEmpty);
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => "");
args.putIfAbsent('url', () => url); args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => {}); return await _sharedChannel.invokeMethod('openWithSystemBrowser', args);
args.putIfAbsent('isLocalFile', () => false);
args.putIfAbsent('isData', () => false);
args.putIfAbsent('openWithSystemBrowser', () => true);
args.putIfAbsent('useChromeSafariBrowser', () => false);
args.putIfAbsent('options', () => {});
return await ChannelManager.channel.invokeMethod('open', args);
} }
///Displays an [InAppBrowser] window that was opened hidden. Calling this has no effect if the [InAppBrowser] was already visible. ///Displays an [InAppBrowser] window that was opened hidden. Calling this has no effect if the [InAppBrowser] was already visible.
...@@ -230,31 +215,28 @@ class InAppBrowser { ...@@ -230,31 +215,28 @@ class InAppBrowser {
this.throwIsNotOpened(); this.throwIsNotOpened();
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); args.putIfAbsent('uuid', () => uuid);
await ChannelManager.channel.invokeMethod('show', args); await _channel.invokeMethod('show', args);
} }
///Hides the [InAppBrowser] window. Calling this has no effect if the [InAppBrowser] was already hidden. ///Hides the [InAppBrowser] window. Calling this has no effect if the [InAppBrowser] was already hidden.
Future<void> hide() async { Future<void> hide() async {
this.throwIsNotOpened(); this.throwIsNotOpened();
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); await _channel.invokeMethod('hide', args);
await ChannelManager.channel.invokeMethod('hide', args);
} }
///Closes the [InAppBrowser] window. ///Closes the [InAppBrowser] window.
Future<void> close() async { Future<void> close() async {
this.throwIsNotOpened(); this.throwIsNotOpened();
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); await _channel.invokeMethod('close', args);
await ChannelManager.channel.invokeMethod('close', args);
} }
///Check if the Web View of the [InAppBrowser] instance is hidden. ///Check if the Web View of the [InAppBrowser] instance is hidden.
Future<bool> isHidden() async { Future<bool> isHidden() async {
this.throwIsNotOpened(); this.throwIsNotOpened();
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); return await _channel.invokeMethod('isHidden', args);
return await ChannelManager.channel.invokeMethod('isHidden', args);
} }
///Sets the [InAppBrowser] options with the new [options] and evaluates them. ///Sets the [InAppBrowser] options with the new [options] and evaluates them.
...@@ -280,23 +262,19 @@ class InAppBrowser { ...@@ -280,23 +262,19 @@ class InAppBrowser {
} }
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('options', () => optionsMap); args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('optionsType', () => "InAppBrowserOptions"); await _channel.invokeMethod('setOptions', args);
await ChannelManager.channel.invokeMethod('setOptions', args);
} }
///Gets the current [InAppBrowser] options as a `Map`. Returns `null` if the options are not setted yet. ///Gets the current [InAppBrowser] options as a `Map`. Returns `null` if the options are not setted yet.
Future<InAppBrowserClassOptions> getOptions() async { Future<InAppBrowserClassOptions> getOptions() async {
this.throwIsNotOpened(); this.throwIsNotOpened();
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('optionsType', () => "InAppBrowserOptions");
InAppBrowserClassOptions inAppBrowserClassOptions = InAppBrowserClassOptions inAppBrowserClassOptions =
InAppBrowserClassOptions(); InAppBrowserClassOptions();
Map<dynamic, dynamic> options = Map<dynamic, dynamic> options =
await ChannelManager.channel.invokeMethod('getOptions', args); await _channel.invokeMethod('getOptions', args);
if (options != null) { if (options != null) {
options = options.cast<String, dynamic>(); options = options.cast<String, dynamic>();
inAppBrowserClassOptions.crossPlatform = inAppBrowserClassOptions.crossPlatform =
......
...@@ -9,8 +9,6 @@ import 'webview_options.dart'; ...@@ -9,8 +9,6 @@ import 'webview_options.dart';
var uuidGenerator = new Uuid(); var uuidGenerator = new Uuid();
typedef Future<dynamic> ListenerCallback(MethodCall call);
///This type represents a callback, added with [addJavaScriptHandler], that listens to post messages sent from JavaScript. ///This type represents a callback, added with [addJavaScriptHandler], that listens to post messages sent from JavaScript.
/// ///
///The Android implementation uses [addJavascriptInterface](https://developer.android.com/reference/android/webkit/WebView#addJavascriptInterface(java.lang.Object,%20java.lang.String)). ///The Android implementation uses [addJavascriptInterface](https://developer.android.com/reference/android/webkit/WebView#addJavascriptInterface(java.lang.Object,%20java.lang.String)).
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment