code refactoring, added InAppBrowserManager and ChromeSafariBrowserManager classes on native code, updated webview options class names

This commit is contained in:
Lorenzo Pichilli 2019-12-18 21:34:40 +01:00
parent 4d752ee9d9
commit 0e30767c15
30 changed files with 1516 additions and 2250 deletions

View File

@ -81,7 +81,7 @@ See the online [API Reference](https://pub.dartlang.org/documentation/flutter_in
The API showed in this `README.md` file shows only a part of the documentation that conforms to the master branch only.
So, here you could have methods, options, and events that aren't published yet.
If you need a specific version, change the **GitHub branch** to your version or use the **online API Reference** (recommended).
If you need a specific version, change the **GitHub branch** to your version or use the **online API Reference** (recommended).
### Load a file inside `assets` folder
@ -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

View File

@ -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);
}
}

View File

@ -0,0 +1,90 @@
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);
}
}

View File

@ -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);

View File

@ -1,868 +0,0 @@
/*
*
* 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();
}
}
}

View File

@ -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,15 +492,37 @@ 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() {
hide();
finish();
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() {
@ -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();
}
}

View File

@ -0,0 +1,224 @@
/*
*
* 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);
}
}

View File

@ -1,8 +1,6 @@
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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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,
);

View File

@ -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,14 +86,15 @@ 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(
useShouldOverrideUrlLoading: true,
useOnLoadResource: true,
debuggingEnabled: true,
useShouldOverrideUrlLoading: true,
useOnLoadResource: true,
))));
},
child: Text("Open Webview Browser")),

View File

@ -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(() {

View File

@ -0,0 +1,108 @@
//
// 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)
}
}
}

View File

@ -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)

View File

@ -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)
}

View File

@ -0,0 +1,186 @@
//
// 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)})
}

View File

@ -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
}
@ -479,5 +663,31 @@ class InAppBrowserWebViewController: UIViewController, UIScrollViewDelegate, WKU
optionsMap.merge(self.webView.getOptions()!, uniquingKeysWith: { (current, _) in current })
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: [])
}
}

View File

@ -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,103 +2170,62 @@ 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
if result is FlutterError {
print((result as! FlutterError).message)
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 ?? "")
}
else if (result as? NSObject) == FlutterMethodNotImplemented {}
else {
var json = "null"
if let r = result {
json = r as! String
}
else if (result as? NSObject) == FlutterMethodNotImplemented {}
else {
var json = "null"
if let r = result {
json = r as! String
}
self.evaluateJavaScript("if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)](\(json)); delete window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)];}", completionHandler: nil)
}
})
}
self.evaluateJavaScript("if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)](\(json)); delete window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)];}", completionHandler: nil)
}
})
}
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
@ -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)

View File

@ -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 {

View File

@ -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

View File

@ -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!)
registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: "com.pichillilorenzo/flutter_inappwebview")
inAppBrowserManager = InAppBrowserManager(registrar: registrar)
chromeSafariBrowserManager = ChromeSafariBrowserManager(registrar: registrar)
inAppWebViewStatic = InAppWebViewStatic(registrar: registrar)
if #available(iOS 11.0, *) {
myCookieManager = MyCookieManager(registrar: registrar)
}
if #available(iOS 9.0, *) {
myWebStorageManager = MyWebStorageManager(registrar: registrar)
}
credentialDatabase = CredentialDatabase(registrar: registrar)
}
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
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
}
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)
}
}
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
}
}
// 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)})
}

View File

@ -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';

View File

@ -1,28 +0,0 @@
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;
}
}

View File

@ -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;
}

View File

@ -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 =

View File

@ -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)).