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 {
@override
Future<ShouldOverrideUrlLoadingAction> shouldOverrideUrlLoading(ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async {
print("\n\n override ${shouldOverrideUrlLoadingRequest.url}\n\n");
this.webViewController.loadUrl(url: shouldOverrideUrlLoadingRequest.url);
return ShouldOverrideUrlLoadingAction.CANCEL;
return ShouldOverrideUrlLoadingAction.ALLOW;
}
@override
......
......@@ -5,7 +5,6 @@ import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import androidx.browser.customtabs.CustomTabsCallback;
import androidx.browser.customtabs.CustomTabsIntent;
......@@ -14,16 +13,21 @@ import androidx.browser.customtabs.CustomTabsSession;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.Shared;
import java.util.HashMap;
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";
String uuid;
CustomTabsIntent.Builder builder;
ChromeCustomTabsOptions options;
public MethodChannel channel;
public String uuid;
private CustomTabsIntent.Builder builder;
private ChromeCustomTabsOptions options;
private CustomTabActivityHelper customTabActivityHelper;
private CustomTabsSession customTabsSession;
private final int CHROME_CUSTOM_TAB_REQUEST_CODE = 100;
......@@ -39,13 +43,15 @@ public class ChromeCustomTabsActivity extends Activity {
Bundle b = getIntent().getExtras();
assert b != null;
uuid = b.getString("uuid");
channel = new MethodChannel(Shared.messenger, "com.pichillilorenzo/flutter_chromesafaribrowser_" + uuid);
channel.setMethodCallHandler(this);
final String url = b.getString("url");
options = new ChromeCustomTabsOptions();
options.parse((HashMap<String, Object>) b.getSerializable("options"));
InAppWebViewFlutterPlugin.inAppBrowser.chromeCustomTabsActivities.put(uuid, this);
final ChromeCustomTabsActivity chromeCustomTabsActivity = this;
customTabActivityHelper = new CustomTabActivityHelper();
......@@ -68,7 +74,7 @@ public class ChromeCustomTabsActivity extends Activity {
finish();
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid);
InAppWebViewFlutterPlugin.inAppBrowser.channel.invokeMethod("onChromeSafariBrowserClosed", obj);
channel.invokeMethod("onChromeSafariBrowserClosed", obj);
}
});
......@@ -79,14 +85,14 @@ public class ChromeCustomTabsActivity extends Activity {
onChromeSafariBrowserOpened = true;
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid);
InAppWebViewFlutterPlugin.inAppBrowser.channel.invokeMethod("onChromeSafariBrowserOpened", obj);
channel.invokeMethod("onChromeSafariBrowserOpened", obj);
}
if (navigationEvent == NAVIGATION_FINISHED && !onChromeSafariBrowserCompletedInitialLoad) {
onChromeSafariBrowserCompletedInitialLoad = true;
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid);
InAppWebViewFlutterPlugin.inAppBrowser.channel.invokeMethod("onChromeSafariBrowserCompletedInitialLoad", obj);
channel.invokeMethod("onChromeSafariBrowserCompletedInitialLoad", obj);
}
}
......@@ -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) {
if (options.addDefaultShareMenuItem)
builder.addDefaultShareMenuItem();
......@@ -155,7 +169,7 @@ public class ChromeCustomTabsActivity extends Activity {
finish();
Map<String, Object> obj = new HashMap<>();
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 {
public final MethodChannel channel;
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();
DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
displayListenerProxy.onPreWebViewInitialization(displayManager);
......@@ -70,9 +73,6 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
webView.prepare();
channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_inappwebview_" + id);
channel.setMethodCallHandler(this);
if (initialFile != null) {
try {
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;
import android.graphics.Color;
import android.graphics.Picture;
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.Bundle;
import android.util.Log;
......@@ -25,6 +20,10 @@ import android.webkit.WebViewClient;
import android.widget.ProgressBar;
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.InAppWebViewOptions;
......@@ -34,11 +33,13 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
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";
public MethodChannel channel;
public String uuid;
public InAppWebView webView;
public ActionBar actionBar;
......@@ -54,13 +55,17 @@ public class InAppBrowserActivity extends AppCompatActivity {
protected void onCreate(Bundle 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);
webView = findViewById(R.id.webView);
webView.inAppBrowserActivity = this;
Bundle b = getIntent().getExtras();
uuid = b.getString("uuid");
fromActivity = b.getString("fromActivity");
HashMap<String, Object> optionsMap = (HashMap<String, Object>) b.getSerializable("options");
......@@ -72,8 +77,6 @@ public class InAppBrowserActivity extends AppCompatActivity {
webViewOptions.parse(optionsMap);
webView.options = webViewOptions;
InAppWebViewFlutterPlugin.inAppBrowser.webViewActivities.put(uuid, this);
actionBar = getSupportActionBar();
prepareView();
......@@ -95,8 +98,238 @@ public class InAppBrowserActivity extends AppCompatActivity {
Map<String, Object> obj = new HashMap<>();
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() {
......@@ -259,16 +492,38 @@ public class InAppBrowserActivity extends AppCompatActivity {
if (canGoBack())
goBack();
else if (options.closeOnCannotGoBack)
InAppWebViewFlutterPlugin.inAppBrowser.close(this, uuid, null);
close(null);
return true;
}
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();
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() {
if (webView != null)
......@@ -358,7 +613,7 @@ public class InAppBrowserActivity extends AppCompatActivity {
}
public void closeButtonClicked(MenuItem item) {
InAppWebViewFlutterPlugin.inAppBrowser.close(this, uuid, null);
close(null);
}
public byte[] takeScreenshot() {
......@@ -525,20 +780,6 @@ public class InAppBrowserActivity extends AppCompatActivity {
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) {
if (webView != null)
webView.scrollTo(x, y);
......@@ -598,4 +839,25 @@ public class InAppBrowserActivity extends AppCompatActivity {
return webView.getUpdatedScale();
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;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
......@@ -21,13 +19,8 @@ import android.webkit.WebBackForwardList;
import android.webkit.WebHistoryItem;
import android.webkit.WebSettings;
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.appcompat.app.AlertDialog;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlocker;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerAction;
......@@ -37,7 +30,6 @@ import com.pichillilorenzo.flutter_inappwebview.FlutterWebView;
import com.pichillilorenzo.flutter_inappwebview.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.JavaScriptBridgeInterface;
import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.Shared;
import com.pichillilorenzo.flutter_inappwebview.Util;
......@@ -50,7 +42,6 @@ import java.util.Map;
import java.util.regex.Pattern;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import okhttp3.OkHttpClient;
import static com.pichillilorenzo.flutter_inappwebview.InAppWebView.PreferredContentModeOptionType.fromValue;
......@@ -61,6 +52,7 @@ final public class InAppWebView extends InputAwareWebView {
public InAppBrowserActivity inAppBrowserActivity;
public FlutterWebView flutterWebView;
public MethodChannel channel;
public int id;
public InAppWebViewClient inAppWebViewClient;
public InAppWebViewChromeClient inAppWebViewChromeClient;
......@@ -123,7 +115,7 @@ final public class InAppWebView extends InputAwareWebView {
static final String interceptAjaxRequestsJS = "(function(ajax) {" +
" var send = ajax.prototype.send;" +
" var open = ajax.prototype.open;" +
" var openUrl = ajax.prototype.openUrl;" +
" var setRequestHeader = ajax.prototype.setRequestHeader;" +
" ajax.prototype._flutter_inappwebview_url = null;" +
" ajax.prototype._flutter_inappwebview_method = null;" +
......@@ -156,7 +148,7 @@ final public class InAppWebView extends InputAwareWebView {
" }" +
" 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;" +
" this._flutter_inappwebview_url = url;" +
" this._flutter_inappwebview_method = method;" +
......@@ -164,7 +156,7 @@ final public class InAppWebView extends InputAwareWebView {
" this._flutter_inappwebview_user = user;" +
" this._flutter_inappwebview_password = password;" +
" 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) {" +
" this._flutter_inappwebview_request_headers[header] = value;" +
......@@ -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)) {" +
" 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;" +
" }" +
" }" +
......@@ -532,6 +524,7 @@ final public class InAppWebView extends InputAwareWebView {
this.inAppBrowserActivity = (InAppBrowserActivity) obj;
else if (obj instanceof FlutterWebView)
this.flutterWebView = (FlutterWebView) obj;
this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel;
this.id = id;
this.options = options;
}
......@@ -689,7 +682,7 @@ final public class InAppWebView extends InputAwareWebView {
obj.put("activeMatchOrdinal", activeMatchOrdinal);
obj.put("numberOfMatches", numberOfMatches);
obj.put("isDoneCounting", isDoneCounting);
getChannel().invokeMethod("onFindResultReceived", obj);
channel.invokeMethod("onFindResultReceived", obj);
}
});
......@@ -1264,11 +1257,7 @@ final public class InAppWebView extends InputAwareWebView {
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("x", x);
obj.put("y", y);
getChannel().invokeMethod("onScrollChanged", obj);
}
private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppWebViewFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
channel.invokeMethod("onScrollChanged", obj);
}
public void startSafeBrowsing(final MethodChannel.Result result) {
......@@ -1304,7 +1293,7 @@ final public class InAppWebView extends InputAwareWebView {
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url);
getChannel().invokeMethod("onDownloadStart", obj);
channel.invokeMethod("onDownloadStart", obj);
}
}
......
......@@ -2,7 +2,6 @@ package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
import android.annotation.TargetApi;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
......@@ -33,7 +32,6 @@ import com.pichillilorenzo.flutter_inappwebview.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.Shared;
import com.pichillilorenzo.flutter_inappwebview.Util;
import java.util.ArrayList;
import java.util.Arrays;
......@@ -52,6 +50,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
protected static final String LOG_TAG = "IABWebChromeClient";
private FlutterWebView flutterWebView;
private InAppBrowserActivity inAppBrowserActivity;
public MethodChannel channel;
private ValueCallback<Uri> mUploadMessage;
private final static int FILECHOOSER_RESULTCODE = 1;
......@@ -65,6 +64,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
this.inAppBrowserActivity = (InAppBrowserActivity) obj;
else if (obj instanceof FlutterWebView)
this.flutterWebView = (FlutterWebView) obj;
this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel;
if (Shared.registrar != null)
Shared.registrar.addActivityResultListener(this);
......@@ -121,7 +121,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("message", message);
getChannel().invokeMethod("onJsAlert", obj, new MethodChannel.Result() {
channel.invokeMethod("onJsAlert", obj, new MethodChannel.Result() {
@Override
public void success(Object response) {
String responseMessage = null;
......@@ -204,7 +204,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("message", message);
getChannel().invokeMethod("onJsConfirm", obj, new MethodChannel.Result() {
channel.invokeMethod("onJsConfirm", obj, new MethodChannel.Result() {
@Override
public void success(Object response) {
String responseMessage = null;
......@@ -301,7 +301,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
obj.put("message", message);
obj.put("defaultValue", defaultValue);
getChannel().invokeMethod("onJsPrompt", obj, new MethodChannel.Result() {
channel.invokeMethod("onJsPrompt", obj, new MethodChannel.Result() {
@Override
public void success(Object response) {
String responseMessage = null;
......@@ -433,7 +433,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
super.onPageStarted(v, url, favicon);
obj.put("url", url);
getChannel().invokeMethod("onCreateWindow", obj);
channel.invokeMethod("onCreateWindow", obj);
// stop webview loading
v.stopLoading();
......@@ -449,7 +449,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}
obj.put("url", data);
getChannel().invokeMethod("onCreateWindow", obj);
channel.invokeMethod("onCreateWindow", obj);
return false;
}
......@@ -459,7 +459,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("origin", origin);
getChannel().invokeMethod("onGeolocationPermissionsShowPrompt", obj, new MethodChannel.Result() {
channel.invokeMethod("onGeolocationPermissionsShowPrompt", obj, new MethodChannel.Result() {
@Override
public void success(Object o) {
Map<String, Object> response = (Map<String, Object>) o;
......@@ -486,7 +486,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
getChannel().invokeMethod("onGeolocationPermissionsHidePrompt", obj);
channel.invokeMethod("onGeolocationPermissionsHidePrompt", obj);
}
@Override
......@@ -496,7 +496,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("message", consoleMessage.message());
obj.put("messageLevel", consoleMessage.messageLevel().ordinal());
getChannel().invokeMethod("onConsoleMessage", obj);
channel.invokeMethod("onConsoleMessage", obj);
return true;
}
......@@ -518,7 +518,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("progress", progress);
getChannel().invokeMethod("onProgressChanged", obj);
channel.invokeMethod("onProgressChanged", obj);
super.onProgressChanged(view, progress);
}
......@@ -608,7 +608,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("origin", request.getOrigin().toString());
obj.put("resources", Arrays.asList(request.getResources()));
getChannel().invokeMethod("onPermissionRequest", obj, new MethodChannel.Result() {
channel.invokeMethod("onPermissionRequest", obj, new MethodChannel.Result() {
@Override
public void success(Object response) {
if (response != null) {
......@@ -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;
import android.webkit.ValueCallback;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewClient;
......@@ -53,6 +52,7 @@ public class InAppWebViewClient extends WebViewClient {
protected static final String LOG_TAG = "IABWebViewClient";
private FlutterWebView flutterWebView;
private InAppBrowserActivity inAppBrowserActivity;
public MethodChannel channel;
private static int previousAuthRequestFailureCount = 0;
private static List<Credential> credentialsProposed = null;
......@@ -62,6 +62,7 @@ public class InAppWebViewClient extends WebViewClient {
this.inAppBrowserActivity = (InAppBrowserActivity) obj;
else if (obj instanceof FlutterWebView)
this.flutterWebView = (FlutterWebView) obj;
this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
......@@ -125,7 +126,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("androidHasGesture", hasGesture);
obj.put("androidIsRedirect", isRedirect);
obj.put("iosWKNavigationType", null);
getChannel().invokeMethod("shouldOverrideUrlLoading", obj, new MethodChannel.Result() {
channel.invokeMethod("shouldOverrideUrlLoading", obj, new MethodChannel.Result() {
@Override
public void success(Object response) {
if (response != null) {
......@@ -199,7 +200,7 @@ public class InAppWebViewClient extends WebViewClient {
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url);
getChannel().invokeMethod("onLoadStart", obj);
channel.invokeMethod("onLoadStart", obj);
}
......@@ -212,7 +213,7 @@ public class InAppWebViewClient extends WebViewClient {
previousAuthRequestFailureCount = 0;
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) {
CookieManager.getInstance().flush();
} else {
......@@ -235,7 +236,7 @@ public class InAppWebViewClient extends WebViewClient {
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url);
getChannel().invokeMethod("onLoadStop", obj);
channel.invokeMethod("onLoadStop", obj);
}
@Override
......@@ -245,7 +246,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url);
obj.put("androidIsReload", isReload);
getChannel().invokeMethod("onUpdateVisitedHistory", obj);
channel.invokeMethod("onUpdateVisitedHistory", obj);
super.doUpdateVisitedHistory(view, url, isReload);
}
......@@ -264,7 +265,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("url", failingUrl);
obj.put("code", errorCode);
obj.put("message", description);
getChannel().invokeMethod("onLoadError", obj);
channel.invokeMethod("onLoadError", obj);
}
@RequiresApi(api = Build.VERSION_CODES.M)
......@@ -278,7 +279,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("url", request.getUrl().toString());
obj.put("statusCode", errorResponse.getStatusCode());
obj.put("description", errorResponse.getReasonPhrase());
getChannel().invokeMethod("onLoadHttpError", obj);
channel.invokeMethod("onLoadHttpError", obj);
}
}
......@@ -316,7 +317,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("port", port);
obj.put("previousFailureCount", previousAuthRequestFailureCount);
getChannel().invokeMethod("onReceivedHttpAuthRequest", obj, new MethodChannel.Result() {
channel.invokeMethod("onReceivedHttpAuthRequest", obj, new MethodChannel.Result() {
@Override
public void success(Object response) {
if (response != null) {
......@@ -461,7 +462,7 @@ public class InAppWebViewClient extends WebViewClient {
Log.d(LOG_TAG, obj.toString());
getChannel().invokeMethod("onReceivedServerTrustAuthRequest", obj, new MethodChannel.Result() {
channel.invokeMethod("onReceivedServerTrustAuthRequest", obj, new MethodChannel.Result() {
@Override
public void success(Object response) {
if (response != null) {
......@@ -520,7 +521,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("realm", realm);
obj.put("port", request.getPort());
getChannel().invokeMethod("onReceivedClientCertRequest", obj, new MethodChannel.Result() {
channel.invokeMethod("onReceivedClientCertRequest", obj, new MethodChannel.Result() {
@Override
public void success(Object response) {
if (response != null) {
......@@ -579,7 +580,7 @@ public class InAppWebViewClient extends WebViewClient {
obj.put("url", request.getUrl().toString());
obj.put("threatType", threatType);
getChannel().invokeMethod("onSafeBrowsingHit", obj, new MethodChannel.Result() {
channel.invokeMethod("onSafeBrowsingHit", obj, new MethodChannel.Result() {
@Override
public void success(Object response) {
if (response != null) {
......@@ -652,7 +653,7 @@ public class InAppWebViewClient extends WebViewClient {
Util.WaitFlutterResult flutterResult;
try {
flutterResult = Util.invokeMethodAndWait(getChannel(), "onLoadResourceCustomScheme", obj);
flutterResult = Util.invokeMethodAndWait(channel, "onLoadResourceCustomScheme", obj);
} catch (InterruptedException e) {
e.printStackTrace();
Log.e(LOG_TAG, e.getMessage());
......@@ -701,9 +702,4 @@ public class InAppWebViewClient extends WebViewClient {
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;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import android.webkit.ValueCallback;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
......@@ -19,7 +18,8 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
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 MyCookieManager myCookieManager;
public static CredentialDatabaseHandler credentialDatabaseHandler;
......@@ -46,8 +46,10 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
private void onAttachedToEngine(Context applicationContext, BinaryMessenger messenger, Activity activity, PlatformViewRegistry platformViewRegistry, FlutterView flutterView) {
Shared.applicationContext = applicationContext;
Shared.activity = activity;
Shared.messenger = messenger;
inAppBrowser = new InAppBrowser(messenger);
inAppBrowserManager = new InAppBrowserManager(messenger);
chromeSafariBrowserManager = new ChromeSafariBrowserManager(messenger);
platformViewRegistry.registerViewFactory(
"com.pichillilorenzo/flutter_inappwebview", new FlutterWebViewFactory(messenger, flutterView));
......@@ -61,9 +63,13 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
@Override
public void onDetachedFromEngine(FlutterPluginBinding binding) {
if (inAppBrowser != null) {
inAppBrowser.dispose();
inAppBrowser = null;
if (inAppBrowserManager != null) {
inAppBrowserManager.dispose();
inAppBrowserManager = null;
}
if (chromeSafariBrowserManager != null) {
chromeSafariBrowserManager.dispose();
chromeSafariBrowserManager = null;
}
if (myCookieManager != null) {
myCookieManager.dispose();
......
......@@ -9,13 +9,7 @@ import android.webkit.ValueCallback;
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.List;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
......@@ -25,6 +19,7 @@ public class JavaScriptBridgeInterface {
public static final String name = "flutter_inappwebview";
private FlutterWebView flutterWebView;
private InAppBrowserActivity inAppBrowserActivity;
public MethodChannel channel;
// https://github.com/taylorhakes/promise-polyfill/blob/master/src/index.js
public static final String promisePolyfillJS = "if (window.Promise == null) {" +
......@@ -254,6 +249,7 @@ public class JavaScriptBridgeInterface {
this.inAppBrowserActivity = (InAppBrowserActivity) obj;
else if (obj instanceof FlutterWebView)
this.flutterWebView = (FlutterWebView) obj;
this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel;
}
@JavascriptInterface
......@@ -277,7 +273,7 @@ public class JavaScriptBridgeInterface {
webView.printCurrentPage();
}
getChannel().invokeMethod("onCallJsHandler", obj, new MethodChannel.Result() {
channel.invokeMethod("onCallJsHandler", obj, new MethodChannel.Result() {
@Override
public void success(Object json) {
if (webView == null) {
......@@ -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;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.PluginRegistry;
public class Shared {
public static Context applicationContext;
public static PluginRegistry.Registrar registrar;
public static BinaryMessenger messenger;
public static FlutterPlugin.FlutterAssets flutterAssets;
public static ActivityPluginBinding activityPluginBinding;
public static Activity activity;
......
......@@ -196,10 +196,9 @@
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
Base,
);
......
......@@ -38,9 +38,8 @@ class MyInAppBrowser extends InAppBrowser {
@override
Future<ShouldOverrideUrlLoadingAction> shouldOverrideUrlLoading(ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async {
print("\n\n override ${shouldOverrideUrlLoadingRequest.url}\n\n");
this.webViewController.loadUrl(url: shouldOverrideUrlLoadingRequest.url);
return ShouldOverrideUrlLoadingAction.CANCEL;
print("\n\nOverride ${shouldOverrideUrlLoadingRequest.url}\n\n");
return ShouldOverrideUrlLoadingAction.ALLOW;
}
@override
......@@ -87,12 +86,13 @@ class _InAppBrowserExampleScreenState extends State<InAppBrowserExampleScreen> {
drawer: myDrawer(context: context),
body: Center(
child: RaisedButton(
onPressed: () {
widget.browser.openFile(
onPressed: () async {
await widget.browser.openFile(
assetFilePath: "assets/index.html",
options: InAppBrowserClassOptions(
inAppWebViewWidgetOptions: InAppWebViewWidgetOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
useShouldOverrideUrlLoading: true,
useOnLoadResource: true,
))));
......
......@@ -59,6 +59,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
print("onWebViewCreated");
},
onLoadStart: (InAppWebViewController controller, String url) {
print("onLoadStart $url");
......@@ -71,6 +72,29 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
setState(() {
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) {
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 {
if let url = urlSchemeTask.request.url, let scheme = url.scheme {
inAppWebView.onLoadResourceCustomScheme(scheme: scheme, url: url.absoluteString, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
print((result as! FlutterError).message ?? "")
}
else if (result as? NSObject) == FlutterMethodNotImplemented {}
else {
let json: [String: Any]
if let r = result {
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
if (self.schemeHandlers[urlSchemeTask.hash] != nil) {
urlSchemeTask.didReceive(urlResponse)
......
......@@ -25,20 +25,20 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
myView = UIView(frame: frame)
let channelName = "com.pichillilorenzo/flutter_inappwebview_" + String(viewId)
self.channel = FlutterMethodChannel(name: channelName, binaryMessenger: registrar.messenger())
self.channel?.setMethodCallHandler(LeakAvoider(delegate: self).handle)
channel = FlutterMethodChannel(name: channelName, binaryMessenger: registrar.messenger())
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 initialData = args["initialData"] as? [String: String]
let initialHeaders = (args["initialHeaders"] as? [String: String])!
let initialOptions = (args["initialOptions"] as? [String: Any])!
let initialHeaders = args["initialHeaders"] as? [String: String]
let initialOptions = args["initialOptions"] as! [String: Any?]
let options = InAppWebViewOptions()
options.parse(options: initialOptions)
let _ = options.parse(options: initialOptions)
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]
myView!.addSubview(webView!)
......@@ -76,7 +76,7 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
deinit {
print("FlutterWebViewController - dealloc")
self.channel?.setMethodCallHandler(nil)
channel?.setMethodCallHandler(nil)
webView!.dispose()
webView = nil
myView = nil
......@@ -86,7 +86,7 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
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 {
do {
try webView!.loadFile(url: initialFile!, headers: initialHeaders)
......@@ -98,14 +98,14 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
}
if initialData != nil {
let data = (initialData!["data"] as? String)!
let mimeType = (initialData!["mimeType"] as? String)!
let encoding = (initialData!["encoding"] as? String)!
let baseUrl = (initialData!["baseUrl"] as? String)!
let data = initialData!["data"]!
let mimeType = initialData!["mimeType"]!
let encoding = initialData!["encoding"]!
let baseUrl = initialData!["baseUrl"]!
webView!.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
}
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
if webView != nil {
let inAppWebViewOptions = InAppWebViewOptions()
let inAppWebViewOptionsMap = arguments!["options"] as! [String: Any]
inAppWebViewOptions.parse(options: inAppWebViewOptionsMap)
let _ = inAppWebViewOptions.parse(options: inAppWebViewOptionsMap)
webView!.setOptions(newOptions: inAppWebViewOptions, newOptionsMap: inAppWebViewOptionsMap)
}
result(true)
......@@ -277,8 +277,13 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
case "findAllAsync":
if webView != nil {
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)
})
} else {
result(false)
}
......@@ -347,13 +352,12 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
case "printCurrentPage":
if webView != nil {
webView!.printCurrentPage(printCompletionHandler: {(completed, error) in
if !completed, let e = error {
if !completed, let _ = error {
result(false)
return
}
result(true)
})
} else {
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
typealias OlderClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Any?) -> Void
typealias NewerClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void
//extension WKWebView{
//
// 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 {
public class InAppWebView_IBWrapper: InAppWebView {
required init(coder: NSCoder) {
let config = WKWebViewConfiguration()
super.init(frame: .zero, configuration: config, IABController: nil, channel: nil)
......@@ -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 closeButton: UIButton!
......@@ -90,8 +42,9 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
@IBOutlet var webView_BottomFullScreenConstraint: NSLayoutConstraint!
@IBOutlet var webView_TopFullScreenConstraint: NSLayoutConstraint!
var uuid: String = ""
var webView: InAppWebView!
weak var navigationDelegate: SwiftFlutterPlugin?
var channel: FlutterMethodChannel?
var initURL: URL?
var tmpWindow: UIWindow?
var browserOptions: InAppBrowserOptions?
......@@ -102,25 +55,245 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
var initEncoding: String?
var initBaseUrl: String?
var isHidden = false
var uuid: String = ""
var WKNavigationMap: [String: [String: Any]] = [:]
var startPageTime: Int64 = 0
var viewPrepared = false
var previousStatusBarStyle = -1
required init(coder aDecoder: NSCoder) {
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 {
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)
prepareConstraints()
prepareWebView()
if #available(iOS 11.0, *) {
if let contentBlockers = webView!.options?.contentBlockers, contentBlockers.count > 0 {
if let contentBlockers = webView.options?.contentBlockers, contentBlockers.count > 0 {
do {
let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: [])
let blockRules = String(data: jsonData, encoding: String.Encoding.utf8)
......@@ -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.navigationDelegate?.onBrowserCreated(uuid: self.uuid, webView: self.webView)
self.onBrowserCreated()
}
return
} catch {
......@@ -149,13 +322,13 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
initLoad(initURL: initURL, initData: initData, initMimeType: initMimeType, initEncoding: initEncoding, initBaseUrl: initBaseUrl, initHeaders: initHeaders)
navigationDelegate?.onBrowserCreated(uuid: uuid, webView: webView)
onBrowserCreated()
}
viewPrepared = true
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 {
loadUrl(url: self.initURL!, headers: self.initHeaders)
}
......@@ -164,7 +337,7 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
}
}
override func viewDidLoad() {
public override func viewDidLoad() {
super.viewDidLoad()
urlField.delegate = self
......@@ -197,39 +370,28 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
print("InAppBrowserWebViewController - dealloc")
}
override func viewWillDisappear (_ animated: Bool) {
public override func viewWillDisappear (_ animated: Bool) {
dispose()
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 () {
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)
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_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
let height = NSLayoutConstraint(item: 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 leftConstraint = NSLayoutConstraint(item: 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 bottomContraint = NSLayoutConstraint(item: webView, attribute: .bottomMargin, relatedBy: .equal, toItem: containerWebView, attribute: .bottomMargin, 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: self.webView!, attribute: .width, relatedBy: .equal, toItem: containerWebView, attribute: .width, 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: self.webView!, attribute: .rightMargin, relatedBy: .equal, toItem: containerWebView, attribute: .rightMargin, 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])
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_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_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: webView!, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.containerWebView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: 0)
}
func prepareWebView() {
//UIApplication.shared.statusBarStyle = preferredStatusBarStyle
public func prepareWebView() {
self.webView.options = webViewOptions
self.webView.prepare()
......@@ -274,13 +436,13 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
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)
updateUrlTextField(url: (webView.currentURL?.absoluteString)!)
}
// Load user requested url
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
if textField.text != nil && textField.text != "" {
let url = textField.text?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
......@@ -298,69 +460,91 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
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()
}
@objc func share () {
@objc public func share () {
let vc = UIActivityViewController(activityItems: [webView.currentURL ?? ""], applicationActivities: [])
present(vc, animated: true, completion: nil)
}
@objc func close() {
//currentURL = nil
@objc public func close() {
weak var weakSelf = self
if (weakSelf?.responds(to: #selector(getter: self.presentingViewController)))! {
weakSelf?.presentingViewController?.dismiss(animated: true, completion: {() -> Void in
self.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
})
}
else {
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() {
webView.goBack()
updateUrlTextField(url: (webView?.url?.absoluteString)!)
}
}
func canGoBack() -> Bool {
public func canGoBack() -> Bool {
return webView.canGoBack
}
@objc func goForward() {
@objc public func goForward() {
if canGoForward() {
webView.goForward()
updateUrlTextField(url: (webView?.url?.absoluteString)!)
}
}
func canGoForward() -> Bool {
public func canGoForward() -> Bool {
return webView.canGoForward
}
@objc func goBackOrForward(steps: Int) {
@objc public func goBackOrForward(steps: Int) {
webView.goBackOrForward(steps: steps)
updateUrlTextField(url: (webView?.url?.absoluteString)!)
}
func canGoBackOrForward(steps: Int) -> Bool {
public func canGoBackOrForward(steps: Int) -> Bool {
return webView.canGoBackOrForward(steps: steps)
}
func updateUrlTextField(url: String) {
public func updateUrlTextField(url: String) {
urlField.text = url
}
......@@ -405,18 +589,18 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
return hexInt
}
func setOptions(newOptions: InAppBrowserOptions, newOptionsMap: [String: Any]) {
public func setOptions(newOptions: InAppBrowserOptions, newOptionsMap: [String: Any]) {
let newInAppWebViewOptions = InAppWebViewOptions()
newInAppWebViewOptions.parse(options: newOptionsMap)
let _ = newInAppWebViewOptions.parse(options: newOptionsMap)
self.webView.setOptions(newOptions: newInAppWebViewOptions, newOptionsMap: newOptionsMap)
if newOptionsMap["hidden"] != nil && browserOptions?.hidden != newOptions.hidden {
if newOptions.hidden {
self.navigationDelegate?.hide(uuid: self.uuid)
hide()
}
else {
self.navigationDelegate?.show(uuid: self.uuid)
show()
}
}
......@@ -471,7 +655,7 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
self.webViewOptions = newInAppWebViewOptions
}
func getOptions() -> [String: Any]? {
public func getOptions() -> [String: Any?]? {
if (self.browserOptions == nil || self.webView.getOptions() == nil) {
return nil
}
......@@ -480,4 +664,30 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
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
var activateShouldOverrideUrlLoading = false
init(frame: CGRect, configuration: WKWebViewConfiguration, IABController: InAppBrowserWebViewController?, channel: FlutterMethodChannel?) {
super.init(frame: frame, configuration: configuration)
self.channel = channel
self.IABController = IABController
......@@ -1403,7 +1402,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
self.options = newOptions
}
func getOptions() -> [String: Any]? {
func getOptions() -> [String: Any?]? {
if (self.options == nil) {
return nil
}
......@@ -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
if result is FlutterError {
print((result as! FlutterError).message)
print((result as! FlutterError).message ?? "")
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
self.updateUrlTextFieldForIABController(navigationAction: navigationAction)
......@@ -1642,7 +1641,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
let port = challenge.protectionSpace.port
onReceivedHttpAuthRequest(challenge: challenge, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
print((result as! FlutterError).message ?? "")
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
completionHandler(.performDefaultHandling, nil)
......@@ -1711,7 +1710,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
onReceivedServerTrustAuthRequest(challenge: challenge, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
print((result as! FlutterError).message ?? "")
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
completionHandler(.performDefaultHandling, nil)
......@@ -1746,7 +1745,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate {
onReceivedClientCertRequest(challenge: challenge, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
print((result as! FlutterError).message ?? "")
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
completionHandler(.performDefaultHandling, nil)
......@@ -1832,7 +1831,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
} else {
print("Security Error: " + securityError.description)
if #available(iOS 11.3, *) {
print(SecCopyErrorMessageString(securityError,nil))
print(SecCopyErrorMessageString(securityError,nil) ?? "")
}
}
return identityAndTrust;
......@@ -1863,7 +1862,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
onJsAlert(message: message, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
print((result as! FlutterError).message ?? "")
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
self.createAlertDialog(message: message, responseMessage: nil, confirmButtonTitle: nil, completionHandler: completionHandler)
......@@ -1921,7 +1920,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
onJsConfirm(message: message, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
print((result as! FlutterError).message ?? "")
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
self.createConfirmDialog(message: message, responseMessage: nil, confirmButtonTitle: nil, cancelButtonTitle: nil, completionHandler: completionHandler)
......@@ -1993,7 +1992,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
completionHandler: @escaping (String?) -> Void) {
onJsPrompt(message: message, defaultValue: defaultValue, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
print((result as! FlutterError).message ?? "")
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
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
}
public func onLoadStart(url: String) {
var arguments: [String: Any] = ["url": url]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onLoadStart", arguments: arguments)
}
let arguments: [String: Any] = ["url": url]
channel?.invokeMethod("onLoadStart", arguments: arguments)
}
public func onLoadStop(url: String) {
var arguments: [String: Any] = ["url": url]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onLoadStop", arguments: arguments)
}
let arguments: [String: Any] = ["url": url]
channel?.invokeMethod("onLoadStop", arguments: arguments)
}
public func onLoadError(url: String, error: Error) {
var arguments: [String: Any] = ["url": url, "code": error._code, "message": error.localizedDescription]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onLoadError", arguments: arguments)
}
let arguments: [String: Any] = ["url": url, "code": error._code, "message": error.localizedDescription]
channel?.invokeMethod("onLoadError", arguments: arguments)
}
public func onLoadHttpError(url: String, statusCode: Int, description: String) {
var arguments: [String: Any] = ["url": url, "statusCode": statusCode, "description": description]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onLoadHttpError", arguments: arguments)
}
let arguments: [String: Any] = ["url": url, "statusCode": statusCode, "description": description]
channel?.invokeMethod("onLoadHttpError", arguments: arguments)
}
public func onProgressChanged(progress: Int) {
var arguments: [String: Any] = ["progress": progress]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onProgressChanged", arguments: arguments)
}
let arguments: [String: Any] = ["progress": progress]
channel?.invokeMethod("onProgressChanged", arguments: arguments)
}
public func onFindResultReceived(activeMatchOrdinal: Int, numberOfMatches: Int, isDoneCounting: Bool) {
var arguments: [String : Any] = [
let arguments: [String : Any] = [
"activeMatchOrdinal": activeMatchOrdinal,
"numberOfMatches": numberOfMatches,
"isDoneCounting": isDoneCounting
]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onFindResultReceived", arguments: arguments)
}
channel?.invokeMethod("onFindResultReceived", arguments: arguments)
}
public func onScrollChanged(x: Int, y: Int) {
var arguments: [String: Any] = ["x": x, "y": y]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onScrollChanged", arguments: arguments)
}
let arguments: [String: Any] = ["x": x, "y": y]
channel?.invokeMethod("onScrollChanged", arguments: arguments)
}
public func onDownloadStart(url: String) {
var arguments: [String: Any] = ["url": url]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onDownloadStart", arguments: arguments)
}
let arguments: [String: Any] = ["url": url]
channel?.invokeMethod("onDownloadStart", arguments: arguments)
}
public func onLoadResourceCustomScheme(scheme: String, url: String, result: FlutterResult?) {
var arguments: [String: Any] = ["scheme": scheme, "url": url]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onLoadResourceCustomScheme", arguments: arguments, result: result)
}
let arguments: [String: Any] = ["scheme": scheme, "url": url]
channel?.invokeMethod("onLoadResourceCustomScheme", arguments: arguments, result: result)
}
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,
"method": method,
"headers": headers,
......@@ -2173,43 +2126,28 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
"androidIsRedirect": nil,
"iosWKNavigationType": navigationType.rawValue
]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("shouldOverrideUrlLoading", arguments: arguments, result: result)
}
channel?.invokeMethod("shouldOverrideUrlLoading", arguments: arguments, result: result)
}
public func onCreateWindow(url: URL, navigationType: WKNavigationType) {
var arguments: [String: Any?] = [
let arguments: [String: Any?] = [
"url": url.absoluteString,
"androidIsDialog": nil,
"androidIsUserGesture": nil,
"iosWKNavigationType": navigationType.rawValue
]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onCreateWindow", arguments: arguments)
}
channel?.invokeMethod("onCreateWindow", arguments: arguments)
}
public func onReceivedHttpAuthRequest(challenge: URLAuthenticationChallenge, result: FlutterResult?) {
var arguments: [String: Any?] = [
let arguments: [String: Any?] = [
"host": challenge.protectionSpace.host,
"protocol": challenge.protectionSpace.protocol,
"realm": challenge.protectionSpace.realm,
"port": challenge.protectionSpace.port,
"previousFailureCount": challenge.previousFailureCount
]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onReceivedHttpAuthRequest", arguments: arguments, result: result)
}
channel?.invokeMethod("onReceivedHttpAuthRequest", arguments: arguments, result: result)
}
public func onReceivedServerTrustAuthRequest(challenge: URLAuthenticationChallenge, result: FlutterResult?) {
......@@ -2222,7 +2160,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
serverCertificateData = NSData(bytes: data, length: size)
}
var arguments: [String: Any?] = [
let arguments: [String: Any?] = [
"host": challenge.protectionSpace.host,
"protocol": challenge.protectionSpace.protocol,
"realm": challenge.protectionSpace.realm,
......@@ -2232,92 +2170,52 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
"error": -1,
"message": "",
]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onReceivedServerTrustAuthRequest", arguments: arguments, result: result)
}
channel?.invokeMethod("onReceivedServerTrustAuthRequest", arguments: arguments, result: result)
}
public func onReceivedClientCertRequest(challenge: URLAuthenticationChallenge, result: FlutterResult?) {
var arguments: [String: Any?] = [
let arguments: [String: Any?] = [
"host": challenge.protectionSpace.host,
"protocol": challenge.protectionSpace.protocol,
"realm": challenge.protectionSpace.realm,
"port": challenge.protectionSpace.port
]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onReceivedClientCertRequest", arguments: arguments, result: result)
}
channel?.invokeMethod("onReceivedClientCertRequest", arguments: arguments, result: result)
}
public func onJsAlert(message: String, result: FlutterResult?) {
var arguments: [String: Any] = ["message": message]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onJsAlert", arguments: arguments, result: result)
}
let arguments: [String: Any] = ["message": message]
channel?.invokeMethod("onJsAlert", arguments: arguments, result: result)
}
public func onJsConfirm(message: String, result: FlutterResult?) {
var arguments: [String: Any] = ["message": message]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onJsConfirm", arguments: arguments, result: result)
}
let arguments: [String: Any] = ["message": message]
channel?.invokeMethod("onJsConfirm", arguments: arguments, result: result)
}
public func onJsPrompt(message: String, defaultValue: String?, result: FlutterResult?) {
var arguments: [String: Any] = ["message": message, "defaultValue": defaultValue as Any]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onJsPrompt", arguments: arguments, result: result)
}
let arguments: [String: Any] = ["message": message, "defaultValue": defaultValue as Any]
channel?.invokeMethod("onJsPrompt", arguments: arguments, result: result)
}
public func onConsoleMessage(message: String, messageLevel: Int) {
var arguments: [String: Any] = ["message": message, "messageLevel": messageLevel]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onConsoleMessage", arguments: arguments)
}
let arguments: [String: Any] = ["message": message, "messageLevel": messageLevel]
channel?.invokeMethod("onConsoleMessage", arguments: arguments)
}
public func onUpdateVisitedHistory(url: String) {
var arguments: [String: Any?] = [
let arguments: [String: Any?] = [
"url": url,
"androidIsReload": nil
]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onUpdateVisitedHistory", arguments: arguments)
}
channel?.invokeMethod("onUpdateVisitedHistory", arguments: arguments)
}
public func onCallJsHandler(handlerName: String, _callHandlerID: Int64, args: String) {
var arguments: [String: Any] = ["handlerName": handlerName, "args": args]
if IABController != nil {
arguments["uuid"] = IABController!.uuid
}
if let channel = getChannel() {
channel.invokeMethod("onCallJsHandler", arguments: arguments, result: {(result) -> Void in
let arguments: [String: Any] = ["handlerName": handlerName, "args": args]
channel?.invokeMethod("onCallJsHandler", arguments: arguments, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
print((result as! FlutterError).message ?? "")
}
else if (result as? NSObject) == FlutterMethodNotImplemented {}
else {
......@@ -2329,7 +2227,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
}
})
}
}
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name.starts(with: "console") {
......@@ -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)?) {
let startSearch = "wkwebview_FindAllAsync('\(find ?? "")');"
evaluateJavaScript(startSearch, completionHandler: completionHandler)
......
......@@ -14,7 +14,7 @@ public class Options: NSObject {
super.init()
}
func parse(options: [String: Any]) -> Options {
func parse(options: [String: Any?]) -> Options {
for (key, value) in options {
if self.responds(to: Selector(key)) {
self.setValue(value, forKey: key)
......@@ -23,8 +23,8 @@ public class Options: NSObject {
return self
}
func getHashMap() -> [String: Any] {
var options: [String: Any] = [:]
func getHashMap() -> [String: Any?] {
var options: [String: Any?] = [:]
var counts = UInt32();
let properties = class_copyPropertyList(object_getClass(self), &counts);
for i in 0..<counts {
......
......@@ -9,16 +9,34 @@ import Foundation
import SafariServices
@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 safariOptions: SafariBrowserOptions?
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()
super.viewWillAppear(animated)
onChromeSafariBrowserOpened()
}
func prepareSafariBrowser() {
......@@ -45,50 +63,64 @@ class SafariViewController: SFSafariViewController, SFSafariViewControllerDelega
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(400), execute: {() -> Void in
self.tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
if (self.statusDelegate != nil) {
self.statusDelegate?.safariExit(uuid: self.uuid)
}
self.onChromeSafariBrowserClosed()
self.dispose()
})
}
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
public func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
close()
}
func safariViewController(_ controller: SFSafariViewController,
public func safariViewController(_ controller: SFSafariViewController,
didCompleteInitialLoad didLoadSuccessfully: Bool) {
if didLoadSuccessfully {
statusDelegate?.onChromeSafariBrowserCompletedInitialLoad(uuid: self.uuid)
onChromeSafariBrowserCompletedInitialLoad()
}
else {
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(URL)
// print(title)
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(URL)
// print(title)
return []
}
func safariViewController(_ controller: SFSafariViewController, initialLoadDidRedirectTo URL: URL) {
public func safariViewController(_ controller: SFSafariViewController, initialLoadDidRedirectTo URL: URL) {
// print("initialLoadDidRedirectTo")
// 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
// Assumes input like "#00FF00" (#RRGGBB).
// 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 {
// Convert hex string to an integer
......
......@@ -22,22 +22,16 @@ import Foundation
import AVFoundation
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 {
static var instance: SwiftFlutterPlugin?
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 safariViewControllers: [String: Any?] = [:]
......@@ -49,855 +43,21 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
super.init()
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")
InAppWebViewStatic(registrar: registrar)
if #available(iOS 11.0, *) {
MyCookieManager(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
inAppBrowserManager = InAppBrowserManager(registrar: registrar)
chromeSafariBrowserManager = ChromeSafariBrowserManager(registrar: registrar)
inAppWebViewStatic = InAppWebViewStatic(registrar: registrar)
if #available(iOS 11.0, *) {
let config = SFSafariViewController.Configuration()
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
myCookieManager = MyCookieManager(registrar: registrar)
}
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, *) {
(safariViewController as! SafariViewController).statusDelegate = nil
(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)
myWebStorageManager = MyWebStorageManager(registrar: registrar)
}
credentialDatabase = CredentialDatabase(registrar: registrar)
}
public func getOptions(uuid: String) -> [String: Any]? {
if let webViewController = self.webViewControllers[uuid] {
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
public static func register(with registrar: FlutterPluginRegistrar) {
SwiftFlutterPlugin.instance = SwiftFlutterPlugin(with: registrar)
}
}
// 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;
export 'src/types.dart';
export 'src/in_app_webview.dart';
export 'src/in_app_browser.dart';
export 'src/channel_manager.dart';
export 'src/cookie_manager.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';
import 'package:flutter/services.dart';
import 'types.dart';
import 'channel_manager.dart';
import 'in_app_browser.dart';
///ChromeSafariBrowser class.
......@@ -18,12 +17,16 @@ class ChromeSafariBrowser {
String uuid;
InAppBrowser browserFallback;
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`.
ChromeSafariBrowser({bFallback}) {
uuid = uuidGenerator.v4();
browserFallback = bFallback;
ChannelManager.addListener(uuid, handleMethod);
this._channel =
MethodChannel('com.pichillilorenzo/flutter_chromesafaribrowser_$uuid');
this._channel.setMethodCallHandler(handleMethod);
_isOpened = false;
}
......@@ -94,15 +97,13 @@ class ChromeSafariBrowser {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('uuidFallback',
() => (browserFallback != null) ? browserFallback.uuid : '');
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headersFallback);
args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('uuidFallback',
() => (browserFallback != null) ? browserFallback.uuid : '');
args.putIfAbsent('headersFallback', () => headersFallback);
args.putIfAbsent('optionsFallback', () => optionsFallbackMap);
args.putIfAbsent('isData', () => false);
args.putIfAbsent('useChromeSafariBrowser', () => true);
await ChannelManager.channel.invokeMethod('open', args);
await _sharedChannel.invokeMethod('open', args);
this._isOpened = true;
}
......
......@@ -7,7 +7,6 @@ import 'package:flutter/services.dart';
import 'webview_options.dart';
import 'types.dart';
import 'channel_manager.dart';
import 'in_app_webview.dart' show InAppWebViewController;
///InAppBrowser class. [webViewController] can be used to access the [InAppWebView] API.
......@@ -18,6 +17,8 @@ class InAppBrowser {
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap =
HashMap<String, JavaScriptHandlerCallback>();
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.
InAppWebViewController webViewController;
......@@ -25,10 +26,12 @@ class InAppBrowser {
///
InAppBrowser() {
uuid = uuidGenerator.v4();
ChannelManager.addListener(uuid, handleMethod);
this._channel =
MethodChannel('com.pichillilorenzo/flutter_inappbrowser_$uuid');
this._channel.setMethodCallHandler(handleMethod);
_isOpened = false;
webViewController = new InAppWebViewController.fromInAppBrowser(
uuid, ChannelManager.channel, this);
uuid, this._channel, this);
}
Future<dynamic> handleMethod(MethodCall call) async {
......@@ -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.
///
///[options]: Options for the [InAppBrowser].
Future<void> open(
{String url = "about:blank",
Future<void> openUrl(
{@required String url,
Map<String, String> headers = const {},
InAppBrowserClassOptions options}) async {
assert(url != null && url.isNotEmpty);
......@@ -83,14 +86,10 @@ class InAppBrowser {
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headers);
args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('openWithSystemBrowser', () => false);
args.putIfAbsent('isLocalFile', () => false);
args.putIfAbsent('isData', () => false);
args.putIfAbsent('useChromeSafariBrowser', () => false);
await ChannelManager.channel.invokeMethod('open', args);
await _sharedChannel.invokeMethod('openUrl', 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!
///
......@@ -153,11 +152,7 @@ class InAppBrowser {
args.putIfAbsent('url', () => assetFilePath);
args.putIfAbsent('headers', () => headers);
args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('openWithSystemBrowser', () => false);
args.putIfAbsent('isLocalFile', () => true);
args.putIfAbsent('isData', () => false);
args.putIfAbsent('useChromeSafariBrowser', () => false);
await ChannelManager.channel.invokeMethod('open', args);
await _sharedChannel.invokeMethod('openFile', args);
}
///Opens a new [InAppBrowser] instance with [data] as a content, using [baseUrl] as the base URL for it.
......@@ -203,26 +198,16 @@ class InAppBrowser {
args.putIfAbsent('mimeType', () => mimeType);
args.putIfAbsent('encoding', () => encoding);
args.putIfAbsent('baseUrl', () => baseUrl);
args.putIfAbsent('openWithSystemBrowser', () => false);
args.putIfAbsent('isLocalFile', () => false);
args.putIfAbsent('isData', () => true);
args.putIfAbsent('useChromeSafariBrowser', () => false);
await ChannelManager.channel.invokeMethod('open', args);
args.putIfAbsent('historyUrl', () => androidHistoryUrl);
await _sharedChannel.invokeMethod('openData', args);
}
///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 {
assert(url != null && url.isNotEmpty);
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => "");
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => {});
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);
return await _sharedChannel.invokeMethod('openWithSystemBrowser', args);
}
///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 {
this.throwIsNotOpened();
Map<String, dynamic> args = <String, dynamic>{};
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.
Future<void> hide() async {
this.throwIsNotOpened();
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
await ChannelManager.channel.invokeMethod('hide', args);
await _channel.invokeMethod('hide', args);
}
///Closes the [InAppBrowser] window.
Future<void> close() async {
this.throwIsNotOpened();
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
await ChannelManager.channel.invokeMethod('close', args);
await _channel.invokeMethod('close', args);
}
///Check if the Web View of the [InAppBrowser] instance is hidden.
Future<bool> isHidden() async {
this.throwIsNotOpened();
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
return await ChannelManager.channel.invokeMethod('isHidden', args);
return await _channel.invokeMethod('isHidden', args);
}
///Sets the [InAppBrowser] options with the new [options] and evaluates them.
......@@ -280,23 +262,19 @@ class InAppBrowser {
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('options', () => optionsMap);
args.putIfAbsent('optionsType', () => "InAppBrowserOptions");
await ChannelManager.channel.invokeMethod('setOptions', args);
await _channel.invokeMethod('setOptions', args);
}
///Gets the current [InAppBrowser] options as a `Map`. Returns `null` if the options are not setted yet.
Future<InAppBrowserClassOptions> getOptions() async {
this.throwIsNotOpened();
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('optionsType', () => "InAppBrowserOptions");
InAppBrowserClassOptions inAppBrowserClassOptions =
InAppBrowserClassOptions();
Map<dynamic, dynamic> options =
await ChannelManager.channel.invokeMethod('getOptions', args);
await _channel.invokeMethod('getOptions', args);
if (options != null) {
options = options.cast<String, dynamic>();
inAppBrowserClassOptions.crossPlatform =
......
......@@ -9,8 +9,6 @@ import 'webview_options.dart';
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.
///
///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