fixed iOS nil exception on URLRequest url property, update some iOS classes to use ChannelDelegate class and Disposable protocol, added some more null checks on Android

This commit is contained in:
Lorenzo Pichilli 2022-05-05 20:19:16 +02:00
parent 92abeea57f
commit 88e89bd102
42 changed files with 393 additions and 351 deletions

View File

@ -13,6 +13,7 @@ import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory; import io.flutter.plugin.platform.PlatformViewFactory;
public class FlutterWebViewFactory extends PlatformViewFactory { public class FlutterWebViewFactory extends PlatformViewFactory {
public static final String VIEW_TYPE_ID = "com.pichillilorenzo/flutter_inappwebview";
private final InAppWebViewFlutterPlugin plugin; private final InAppWebViewFlutterPlugin plugin;
public FlutterWebViewFactory(final InAppWebViewFlutterPlugin plugin) { public FlutterWebViewFactory(final InAppWebViewFlutterPlugin plugin) {

View File

@ -87,7 +87,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
chromeSafariBrowserManager = new ChromeSafariBrowserManager(this); chromeSafariBrowserManager = new ChromeSafariBrowserManager(this);
flutterWebViewFactory = new FlutterWebViewFactory(this); flutterWebViewFactory = new FlutterWebViewFactory(this);
platformViewRegistry.registerViewFactory( platformViewRegistry.registerViewFactory(
"com.pichillilorenzo/flutter_inappwebview", flutterWebViewFactory); FlutterWebViewFactory.VIEW_TYPE_ID, flutterWebViewFactory);
platformUtil = new PlatformUtil(this); platformUtil = new PlatformUtil(this);
inAppWebViewStatic = new InAppWebViewStatic(this); inAppWebViewStatic = new InAppWebViewStatic(this);

View File

@ -12,7 +12,6 @@ import androidx.webkit.WebViewCompat;
import androidx.webkit.WebViewFeature; import androidx.webkit.WebViewFeature;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashMap; import java.util.HashMap;
@ -24,7 +23,7 @@ import java.util.Set;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class InAppWebViewStatic extends ChannelDelegateImpl implements Disposable { public class InAppWebViewStatic extends ChannelDelegateImpl {
protected static final String LOG_TAG = "InAppWebViewStatic"; protected static final String LOG_TAG = "InAppWebViewStatic";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static"; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static";

View File

@ -9,7 +9,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
@ -23,10 +22,10 @@ import java.util.TimeZone;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class MyCookieManager extends ChannelDelegateImpl implements Disposable { public class MyCookieManager extends ChannelDelegateImpl {
protected static final String LOG_TAG = "MyCookieManager"; protected static final String LOG_TAG = "MyCookieManager";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager"; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager";
@Nullable
public static CookieManager cookieManager; public static CookieManager cookieManager;
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
@ -305,5 +304,6 @@ public class MyCookieManager extends ChannelDelegateImpl implements Disposable {
public void dispose() { public void dispose() {
super.dispose(); super.dispose();
plugin = null; plugin = null;
cookieManager = null;
} }
} }

View File

@ -7,7 +7,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -17,10 +16,11 @@ import java.util.Map;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class MyWebStorage extends ChannelDelegateImpl implements Disposable { public class MyWebStorage extends ChannelDelegateImpl {
protected static final String LOG_TAG = "MyWebStorage"; protected static final String LOG_TAG = "MyWebStorage";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager"; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager";
@Nullable
public static WebStorage webStorageManager; public static WebStorage webStorageManager;
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
@ -38,15 +38,23 @@ public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
getOrigins(result); getOrigins(result);
break; break;
case "deleteAllData": case "deleteAllData":
webStorageManager.deleteAllData(); if (webStorageManager == null) {
result.success(true); webStorageManager.deleteAllData();
result.success(true);
} else {
result.success(false);
}
break; break;
case "deleteOrigin": case "deleteOrigin":
{ {
String origin = (String) call.argument("origin"); if (webStorageManager == null) {
webStorageManager.deleteOrigin(origin); String origin = (String) call.argument("origin");
webStorageManager.deleteOrigin(origin);
result.success(true);
} else {
result.success(false);
}
} }
result.success(true);
break; break;
case "getQuotaForOrigin": case "getQuotaForOrigin":
{ {
@ -57,7 +65,7 @@ public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
case "getUsageForOrigin": case "getUsageForOrigin":
{ {
String origin = (String) call.argument("origin"); String origin = (String) call.argument("origin");
getUsageForOrigin(origin, result); getUsageForOrigin(origin, result);
} }
break; break;
default: default:
@ -66,6 +74,10 @@ public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
} }
public void getOrigins(final MethodChannel.Result result) { public void getOrigins(final MethodChannel.Result result) {
if (webStorageManager == null) {
result.success(new ArrayList<>());
return;
}
webStorageManager.getOrigins(new ValueCallback<Map>() { webStorageManager.getOrigins(new ValueCallback<Map>() {
@Override @Override
public void onReceiveValue(Map value) { public void onReceiveValue(Map value) {
@ -86,6 +98,10 @@ public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
} }
public void getQuotaForOrigin(String origin, final MethodChannel.Result result) { public void getQuotaForOrigin(String origin, final MethodChannel.Result result) {
if (webStorageManager == null) {
result.success(0);
return;
}
webStorageManager.getQuotaForOrigin(origin, new ValueCallback<Long>() { webStorageManager.getQuotaForOrigin(origin, new ValueCallback<Long>() {
@Override @Override
public void onReceiveValue(Long value) { public void onReceiveValue(Long value) {
@ -95,6 +111,10 @@ public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
} }
public void getUsageForOrigin(String origin, final MethodChannel.Result result) { public void getUsageForOrigin(String origin, final MethodChannel.Result result) {
if (webStorageManager == null) {
result.success(0);
return;
}
webStorageManager.getUsageForOrigin(origin, new ValueCallback<Long>() { webStorageManager.getUsageForOrigin(origin, new ValueCallback<Long>() {
@Override @Override
public void onReceiveValue(Long value) { public void onReceiveValue(Long value) {
@ -107,5 +127,6 @@ public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
public void dispose() { public void dispose() {
super.dispose(); super.dispose();
plugin = null; plugin = null;
webStorageManager = null;
} }
} }

View File

@ -6,7 +6,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
@ -16,7 +15,7 @@ import java.util.TimeZone;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class PlatformUtil extends ChannelDelegateImpl implements Disposable { public class PlatformUtil extends ChannelDelegateImpl {
protected static final String LOG_TAG = "PlatformUtil"; protected static final String LOG_TAG = "PlatformUtil";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil"; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil";

View File

@ -1,46 +0,0 @@
package com.pichillilorenzo.flutter_inappwebview;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class RequestPermissionHandler implements ActivityCompat.OnRequestPermissionsResultCallback {
private static Map<Integer, List<Runnable>> actionDictionary = new HashMap<>();
public static void checkAndRun(Activity activity, String permission, int requestCode, Runnable runnable) {
int permissionCheck = ContextCompat.checkSelfPermission(activity.getApplicationContext(), permission);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
if (actionDictionary.containsKey(requestCode))
actionDictionary.get(requestCode).add(runnable);
else
actionDictionary.put(requestCode, Arrays.asList(runnable));
ActivityCompat.requestPermissions(activity, new String[]{permission}, requestCode);
}
else
runnable.run();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
List<Runnable> callbacks = actionDictionary.get(requestCode);
for (Runnable runnable : callbacks) {
runnable.run();
callbacks.remove(runnable);
}
}
}
}

View File

@ -5,12 +5,11 @@ import androidx.annotation.Nullable;
import androidx.webkit.WebViewFeature; import androidx.webkit.WebViewFeature;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class WebViewFeatureManager extends ChannelDelegateImpl implements Disposable { public class WebViewFeatureManager extends ChannelDelegateImpl {
protected static final String LOG_TAG = "WebViewFeatureManager"; protected static final String LOG_TAG = "WebViewFeatureManager";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webviewfeature"; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webviewfeature";

View File

@ -9,7 +9,6 @@ import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.Util; import com.pichillilorenzo.flutter_inappwebview.Util;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
@ -20,7 +19,7 @@ import java.util.UUID;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class ChromeSafariBrowserManager extends ChannelDelegateImpl implements Disposable { public class ChromeSafariBrowserManager extends ChannelDelegateImpl {
protected static final String LOG_TAG = "ChromeBrowserManager"; protected static final String LOG_TAG = "ChromeBrowserManager";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_chromesafaribrowser"; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_chromesafaribrowser";

View File

@ -9,7 +9,6 @@ import androidx.annotation.RequiresApi;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.types.URLCredential; import com.pichillilorenzo.flutter_inappwebview.types.URLCredential;
import com.pichillilorenzo.flutter_inappwebview.types.URLProtectionSpace; import com.pichillilorenzo.flutter_inappwebview.types.URLProtectionSpace;
@ -22,10 +21,11 @@ import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
@RequiresApi(api = Build.VERSION_CODES.O) @RequiresApi(api = Build.VERSION_CODES.O)
public class CredentialDatabaseHandler extends ChannelDelegateImpl implements Disposable { public class CredentialDatabaseHandler extends ChannelDelegateImpl {
protected static final String LOG_TAG = "CredentialDatabaseHandler"; protected static final String LOG_TAG = "CredentialDatabaseHandler";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database"; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database";
@Nullable
public static CredentialDatabase credentialDatabase; public static CredentialDatabase credentialDatabase;
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
@ -42,80 +42,97 @@ public class CredentialDatabaseHandler extends ChannelDelegateImpl implements Di
case "getAllAuthCredentials": case "getAllAuthCredentials":
{ {
List<Map<String, Object>> allCredentials = new ArrayList<>(); List<Map<String, Object>> allCredentials = new ArrayList<>();
List<URLProtectionSpace> protectionSpaces = credentialDatabase.protectionSpaceDao.getAll(); if (credentialDatabase != null) {
for (URLProtectionSpace protectionSpace : protectionSpaces) { List<URLProtectionSpace> protectionSpaces = credentialDatabase.protectionSpaceDao.getAll();
List<Map<String, Object>> credentials = new ArrayList<>(); for (URLProtectionSpace protectionSpace : protectionSpaces) {
for (URLCredential credential : credentialDatabase.credentialDao.getAllByProtectionSpaceId(protectionSpace.getId())) { List<Map<String, Object>> credentials = new ArrayList<>();
credentials.add(credential.toMap()); for (URLCredential credential : credentialDatabase.credentialDao.getAllByProtectionSpaceId(protectionSpace.getId())) {
credentials.add(credential.toMap());
}
Map<String, Object> obj = new HashMap<>();
obj.put("protectionSpace", protectionSpace.toMap());
obj.put("credentials", credentials);
allCredentials.add(obj);
} }
Map<String, Object> obj = new HashMap<>();
obj.put("protectionSpace", protectionSpace.toMap());
obj.put("credentials", credentials);
allCredentials.add(obj);
} }
result.success(allCredentials); result.success(allCredentials);
} }
break; break;
case "getHttpAuthCredentials": case "getHttpAuthCredentials":
{ {
String host = (String) call.argument("host");
String protocol = (String) call.argument("protocol");
String realm = (String) call.argument("realm");
Integer port = (Integer) call.argument("port");
List<Map<String, Object>> credentials = new ArrayList<>(); List<Map<String, Object>> credentials = new ArrayList<>();
for (URLCredential credential : credentialDatabase.getHttpAuthCredentials(host, protocol, realm, port)) { if (credentialDatabase != null) {
credentials.add(credential.toMap()); String host = (String) call.argument("host");
String protocol = (String) call.argument("protocol");
String realm = (String) call.argument("realm");
Integer port = (Integer) call.argument("port");
for (URLCredential credential : credentialDatabase.getHttpAuthCredentials(host, protocol, realm, port)) {
credentials.add(credential.toMap());
}
} }
result.success(credentials); result.success(credentials);
} }
break; break;
case "setHttpAuthCredential": case "setHttpAuthCredential":
{ {
String host = (String) call.argument("host"); if (credentialDatabase != null) {
String protocol = (String) call.argument("protocol"); String host = (String) call.argument("host");
String realm = (String) call.argument("realm"); String protocol = (String) call.argument("protocol");
Integer port = (Integer) call.argument("port"); String realm = (String) call.argument("realm");
String username = (String) call.argument("username"); Integer port = (Integer) call.argument("port");
String password = (String) call.argument("password"); String username = (String) call.argument("username");
String password = (String) call.argument("password");
credentialDatabase.setHttpAuthCredential(host, protocol, realm, port, username, password); credentialDatabase.setHttpAuthCredential(host, protocol, realm, port, username, password);
result.success(true);
result.success(true); } else {
result.success(false);
}
} }
break; break;
case "removeHttpAuthCredential": case "removeHttpAuthCredential":
{ {
String host = (String) call.argument("host"); if (credentialDatabase != null) {
String protocol = (String) call.argument("protocol"); String host = (String) call.argument("host");
String realm = (String) call.argument("realm"); String protocol = (String) call.argument("protocol");
Integer port = (Integer) call.argument("port"); String realm = (String) call.argument("realm");
String username = (String) call.argument("username"); Integer port = (Integer) call.argument("port");
String password = (String) call.argument("password"); String username = (String) call.argument("username");
String password = (String) call.argument("password");
credentialDatabase.removeHttpAuthCredential(host, protocol, realm, port, username, password); credentialDatabase.removeHttpAuthCredential(host, protocol, realm, port, username, password);
result.success(true);
result.success(true); } else {
result.success(false);
}
} }
break; break;
case "removeHttpAuthCredentials": case "removeHttpAuthCredentials":
{ {
String host = (String) call.argument("host"); if (credentialDatabase != null) {
String protocol = (String) call.argument("protocol"); String host = (String) call.argument("host");
String realm = (String) call.argument("realm"); String protocol = (String) call.argument("protocol");
Integer port = (Integer) call.argument("port"); String realm = (String) call.argument("realm");
Integer port = (Integer) call.argument("port");
credentialDatabase.removeHttpAuthCredentials(host, protocol, realm, port); credentialDatabase.removeHttpAuthCredentials(host, protocol, realm, port);
result.success(true);
result.success(true); } else {
result.success(false);
}
} }
break; break;
case "clearAllAuthCredentials": case "clearAllAuthCredentials":
credentialDatabase.clearAllAuthCredentials(); if (credentialDatabase != null) {
if (plugin != null && plugin.applicationContext != null) { credentialDatabase.clearAllAuthCredentials();
WebViewDatabase.getInstance(plugin.applicationContext).clearHttpAuthUsernamePassword(); if (plugin != null && plugin.applicationContext != null) {
WebViewDatabase.getInstance(plugin.applicationContext).clearHttpAuthUsernamePassword();
}
result.success(true);
} else {
result.success(false);
} }
result.success(true);
break; break;
default: default:
result.notImplemented(); result.notImplemented();
@ -126,5 +143,6 @@ public class CredentialDatabaseHandler extends ChannelDelegateImpl implements Di
public void dispose() { public void dispose() {
super.dispose(); super.dispose();
plugin = null; plugin = null;
credentialDatabase = null;
} }
} }

View File

@ -27,7 +27,6 @@ import androidx.annotation.NonNull;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.FlutterWebView; import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.FlutterWebView;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
@ -37,7 +36,7 @@ import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.MethodChannel.Result;
public class HeadlessInAppWebViewManager extends ChannelDelegateImpl implements Disposable { public class HeadlessInAppWebViewManager extends ChannelDelegateImpl {
protected static final String LOG_TAG = "HeadlessInAppWebViewManager"; protected static final String LOG_TAG = "HeadlessInAppWebViewManager";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview"; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview";

View File

@ -37,7 +37,6 @@ import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
@ -53,7 +52,7 @@ import io.flutter.plugin.common.MethodChannel.Result;
/** /**
* InAppBrowserManager * InAppBrowserManager
*/ */
public class InAppBrowserManager extends ChannelDelegateImpl implements Disposable { public class InAppBrowserManager extends ChannelDelegateImpl {
protected static final String LOG_TAG = "InAppBrowserManager"; protected static final String LOG_TAG = "InAppBrowserManager";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappbrowser"; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappbrowser";

View File

@ -8,7 +8,6 @@ import androidx.webkit.WebViewFeature;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.types.ProxyRuleExt; import com.pichillilorenzo.flutter_inappwebview.types.ProxyRuleExt;
import java.util.HashMap; import java.util.HashMap;
@ -17,7 +16,7 @@ import java.util.concurrent.Executor;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class ProxyManager extends ChannelDelegateImpl implements Disposable { public class ProxyManager extends ChannelDelegateImpl {
protected static final String LOG_TAG = "ProxyManager"; protected static final String LOG_TAG = "ProxyManager";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_proxycontroller"; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_proxycontroller";

View File

@ -4,8 +4,7 @@ import androidx.annotation.Nullable;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public interface IChannelDelegate extends MethodChannel.MethodCallHandler { public interface IChannelDelegate extends MethodChannel.MethodCallHandler, Disposable {
@Nullable @Nullable
MethodChannel getChannel(); MethodChannel getChannel();
void dispose();
} }

View File

@ -1,6 +1,5 @@
package com.pichillilorenzo.flutter_inappwebview.types; package com.pichillilorenzo.flutter_inappwebview.types;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.util.Arrays; import java.util.Arrays;
@ -8,7 +7,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class URLRequest { public class URLRequest {
@NonNull @Nullable
private String url; private String url;
@Nullable @Nullable
private String method; private String method;
@ -17,7 +16,7 @@ public class URLRequest {
@Nullable @Nullable
private Map<String, String> headers; private Map<String, String> headers;
public URLRequest(@NonNull String url, @Nullable String method, @Nullable byte[] body, @Nullable Map<String, String> headers) { public URLRequest(@Nullable String url, @Nullable String method, @Nullable byte[] body, @Nullable Map<String, String> headers) {
this.url = url; this.url = url;
this.method = method; this.method = method;
this.body = body; this.body = body;
@ -30,10 +29,12 @@ public class URLRequest {
return null; return null;
} }
String url = (String) map.get("url"); String url = (String) map.get("url");
if (url == null) {
url = "about:blank";
}
String method = (String) map.get("method"); String method = (String) map.get("method");
byte[] body = (byte[]) map.get("body"); byte[] body = (byte[]) map.get("body");
Map<String, String> headers = (Map<String, String>) map.get("headers"); Map<String, String> headers = (Map<String, String>) map.get("headers");
assert url != null;
return new URLRequest(url, method, body, headers); return new URLRequest(url, method, body, headers);
} }
@ -55,12 +56,12 @@ public class URLRequest {
return urlRequestMap; return urlRequestMap;
} }
@NonNull @Nullable
public String getUrl() { public String getUrl() {
return url; return url;
} }
public void setUrl(@NonNull String url) { public void setUrl(@Nullable String url) {
this.url = url; this.url = url;
} }
@ -98,7 +99,7 @@ public class URLRequest {
URLRequest that = (URLRequest) o; URLRequest that = (URLRequest) o;
if (!url.equals(that.url)) return false; if (url != null ? !url.equals(that.url) : that.url != null) return false;
if (method != null ? !method.equals(that.method) : that.method != null) return false; if (method != null ? !method.equals(that.method) : that.method != null) return false;
if (!Arrays.equals(body, that.body)) return false; if (!Arrays.equals(body, that.body)) return false;
return headers != null ? headers.equals(that.headers) : that.headers == null; return headers != null ? headers.equals(that.headers) : that.headers == null;
@ -106,7 +107,7 @@ public class URLRequest {
@Override @Override
public int hashCode() { public int hashCode() {
int result = url.hashCode(); int result = url != null ? url.hashCode() : 0;
result = 31 * result + (method != null ? method.hashCode() : 0); result = 31 * result + (method != null ? method.hashCode() : 0);
result = 31 * result + Arrays.hashCode(body); result = 31 * result + Arrays.hashCode(body);
result = 31 * result + (headers != null ? headers.hashCode() : 0); result = 31 * result + (headers != null ? headers.hashCode() : 0);

View File

@ -3,11 +3,12 @@
export "FLUTTER_ROOT=/Users/lorenzopichilli/fvm/versions/2.10.4" export "FLUTTER_ROOT=/Users/lorenzopichilli/fvm/versions/2.10.4"
export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example" export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example"
export "COCOAPODS_PARALLEL_CODE_SIGN=true" export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_TARGET=lib/main.dart" export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/lib/main.dart"
export "FLUTTER_BUILD_DIR=build" export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=1.0.0" export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1" export "FLUTTER_BUILD_NUMBER=1"
export "DART_DEFINES=Zmx1dHRlci5pbnNwZWN0b3Iuc3RydWN0dXJlZEVycm9ycz10cnVl,RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
export "DART_OBFUSCATION=false" export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=false" export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false" export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.packages" export "PACKAGE_CONFIG=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/.dart_tool/package_config.json"

View File

@ -7,26 +7,18 @@
import Foundation import Foundation
class CredentialDatabase: NSObject, FlutterPlugin { class CredentialDatabase: ChannelDelegate {
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database"
static var registrar: FlutterPluginRegistrar? static var registrar: FlutterPluginRegistrar?
static var channel: FlutterMethodChannel?
static var credentialStore: URLCredentialStorage? static var credentialStore: URLCredentialStorage?
static func register(with registrar: FlutterPluginRegistrar) {
}
init(registrar: FlutterPluginRegistrar) { init(registrar: FlutterPluginRegistrar) {
super.init() super.init(channel: FlutterMethodChannel(name: CredentialDatabase.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
CredentialDatabase.registrar = registrar CredentialDatabase.registrar = registrar
CredentialDatabase.credentialStore = URLCredentialStorage.shared CredentialDatabase.credentialStore = URLCredentialStorage.shared
CredentialDatabase.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_credential_database", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(self, channel: CredentialDatabase.channel!)
} }
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary let arguments = call.arguments as? NSDictionary
switch call.method { switch call.method {
case "getAllAuthCredentials": case "getAllAuthCredentials":
@ -196,9 +188,8 @@ class CredentialDatabase: NSObject, FlutterPlugin {
} }
} }
public func dispose() { public override func dispose() {
CredentialDatabase.channel?.setMethodCallHandler(nil) super.dispose()
CredentialDatabase.channel = nil
CredentialDatabase.registrar = nil CredentialDatabase.registrar = nil
CredentialDatabase.credentialStore = nil CredentialDatabase.credentialStore = nil
} }

View File

@ -7,47 +7,22 @@
import Foundation import Foundation
public class HeadlessInAppWebView : FlutterMethodCallDelegate { public class HeadlessInAppWebView : Disposable {
static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_headless_inappwebview_"
var id: String var id: String
var channel: FlutterMethodChannel? var channelDelegate: HeadlessWebViewChannelDelegate?
var flutterWebView: FlutterWebViewController? var flutterWebView: FlutterWebViewController?
public init(id: String, flutterWebView: FlutterWebViewController) { public init(id: String, flutterWebView: FlutterWebViewController) {
self.id = id self.id = id
super.init()
self.flutterWebView = flutterWebView self.flutterWebView = flutterWebView
self.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_headless_inappwebview_" + id, let channel = FlutterMethodChannel(name: HeadlessInAppWebView.METHOD_CHANNEL_NAME_PREFIX + id,
binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger()) binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger())
self.channel?.setMethodCallHandler(self.handle) self.channelDelegate = HeadlessWebViewChannelDelegate(headlessWebView: self, channel: channel)
}
public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
switch call.method {
case "dispose":
dispose()
result(true)
break
case "setSize":
let sizeMap = arguments!["size"] as? [String: Any?]
if let size = Size2D.fromMap(map: sizeMap) {
setSize(size: size)
}
result(true)
break
case "getSize":
result(getSize()?.toMap())
break
default:
result(FlutterMethodNotImplemented)
break
}
} }
public func onWebViewCreated() { public func onWebViewCreated() {
let arguments: [String: Any?] = [:] channelDelegate?.onWebViewCreated();
channel?.invokeMethod("onWebViewCreated", arguments: arguments)
} }
public func prepare(params: NSDictionary) { public func prepare(params: NSDictionary) {
@ -87,8 +62,8 @@ public class HeadlessInAppWebView : FlutterMethodCallDelegate {
} }
public func dispose() { public func dispose() {
channel?.setMethodCallHandler(nil) channelDelegate?.dispose()
channel = nil channelDelegate = nil
HeadlessInAppWebViewManager.webViews[id] = nil HeadlessInAppWebViewManager.webViews[id] = nil
flutterWebView = nil flutterWebView = nil
} }

View File

@ -13,23 +13,17 @@ import WebKit
import Foundation import Foundation
import AVFoundation import AVFoundation
public class HeadlessInAppWebViewManager: NSObject, FlutterPlugin { public class HeadlessInAppWebViewManager: ChannelDelegate {
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview"
static var registrar: FlutterPluginRegistrar? static var registrar: FlutterPluginRegistrar?
static var channel: FlutterMethodChannel?
static var webViews: [String: HeadlessInAppWebView?] = [:] static var webViews: [String: HeadlessInAppWebView?] = [:]
public static func register(with registrar: FlutterPluginRegistrar) {
}
init(registrar: FlutterPluginRegistrar) { init(registrar: FlutterPluginRegistrar) {
super.init() super.init(channel: FlutterMethodChannel(name: HeadlessInAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
HeadlessInAppWebViewManager.registrar = registrar HeadlessInAppWebViewManager.registrar = registrar
HeadlessInAppWebViewManager.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_headless_inappwebview", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(self, channel: HeadlessInAppWebViewManager.channel!)
} }
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary let arguments = call.arguments as? NSDictionary
let id: String = arguments!["id"] as! String let id: String = arguments!["id"] as! String
@ -58,9 +52,8 @@ public class HeadlessInAppWebViewManager: NSObject, FlutterPlugin {
flutterWebView.makeInitialLoad(params: params as NSDictionary) flutterWebView.makeInitialLoad(params: params as NSDictionary)
} }
public func dispose() { public override func dispose() {
HeadlessInAppWebViewManager.channel?.setMethodCallHandler(nil) super.dispose()
HeadlessInAppWebViewManager.channel = nil
HeadlessInAppWebViewManager.registrar = nil HeadlessInAppWebViewManager.registrar = nil
let headlessWebViews = HeadlessInAppWebViewManager.webViews.values let headlessWebViews = HeadlessInAppWebViewManager.webViews.values
headlessWebViews.forEach { (headlessWebView: HeadlessInAppWebView?) in headlessWebViews.forEach { (headlessWebView: HeadlessInAppWebView?) in

View File

@ -0,0 +1,59 @@
//
// HeadlessWebViewChannelDelegate.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 05/05/22.
//
import Foundation
public class HeadlessWebViewChannelDelegate : ChannelDelegate {
private var headlessWebView: HeadlessInAppWebView?
public init(headlessWebView: HeadlessInAppWebView, channel: FlutterMethodChannel) {
super.init(channel: channel)
self.headlessWebView = headlessWebView
}
public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
switch call.method {
case "dispose":
if let headlessWebView = headlessWebView {
headlessWebView.dispose()
result(true)
} else {
result(false)
}
break
case "setSize":
if let headlessWebView = headlessWebView {
let sizeMap = arguments!["size"] as? [String: Any?]
if let size = Size2D.fromMap(map: sizeMap) {
headlessWebView.setSize(size: size)
}
result(true)
} else {
result(false)
}
break
case "getSize":
result(headlessWebView?.getSize()?.toMap())
break
default:
result(FlutterMethodNotImplemented)
break
}
}
public func onWebViewCreated() {
let arguments: [String: Any?] = [:]
channel?.invokeMethod("onWebViewCreated", arguments: arguments)
}
public override func dispose() {
super.dispose()
headlessWebView = nil
}
}

View File

@ -11,28 +11,21 @@ import WebKit
import Foundation import Foundation
import AVFoundation import AVFoundation
let WEBVIEW_STORYBOARD = "WebView" public class InAppBrowserManager: ChannelDelegate {
let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController" static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappbrowser"
let NAV_STORYBOARD_CONTROLLER_ID = "navController" static let WEBVIEW_STORYBOARD = "WebView"
static let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController"
public class InAppBrowserManager: NSObject, FlutterPlugin { static let NAV_STORYBOARD_CONTROLLER_ID = "navController"
static var registrar: FlutterPluginRegistrar? static var registrar: FlutterPluginRegistrar?
static var channel: FlutterMethodChannel?
private var previousStatusBarStyle = -1 private var previousStatusBarStyle = -1
public static func register(with registrar: FlutterPluginRegistrar) {
}
init(registrar: FlutterPluginRegistrar) { init(registrar: FlutterPluginRegistrar) {
super.init() super.init(channel: FlutterMethodChannel(name: InAppBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
InAppBrowserManager.registrar = registrar 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) { public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary let arguments = call.arguments as? NSDictionary
switch call.method { switch call.method {
@ -100,8 +93,8 @@ public class InAppBrowserManager: NSObject, FlutterPlugin {
} }
public func presentViewController(webViewController: InAppBrowserWebViewController) { public func presentViewController(webViewController: InAppBrowserWebViewController) {
let storyboard = UIStoryboard(name: WEBVIEW_STORYBOARD, bundle: Bundle(for: InAppWebViewFlutterPlugin.self)) let storyboard = UIStoryboard(name: InAppBrowserManager.WEBVIEW_STORYBOARD, bundle: Bundle(for: InAppWebViewFlutterPlugin.self))
let navController = storyboard.instantiateViewController(withIdentifier: NAV_STORYBOARD_CONTROLLER_ID) as! InAppBrowserNavigationController let navController = storyboard.instantiateViewController(withIdentifier: InAppBrowserManager.NAV_STORYBOARD_CONTROLLER_ID) as! InAppBrowserNavigationController
webViewController.edgesForExtendedLayout = [] webViewController.edgesForExtendedLayout = []
navController.pushViewController(webViewController, animated: false) navController.pushViewController(webViewController, animated: false)
webViewController.prepareNavigationControllerBeforeViewWillAppear() webViewController.prepareNavigationControllerBeforeViewWillAppear()
@ -141,9 +134,8 @@ public class InAppBrowserManager: NSObject, FlutterPlugin {
result(true) result(true)
} }
public func dispose() { public override func dispose() {
InAppBrowserManager.channel?.setMethodCallHandler(nil) super.dispose()
InAppBrowserManager.channel = nil
InAppBrowserManager.registrar = nil InAppBrowserManager.registrar = nil
} }
} }

View File

@ -65,11 +65,9 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
methodCallDelegate = InAppWebViewMethodHandler(webView: webView!) methodCallDelegate = InAppWebViewMethodHandler(webView: webView!)
channel!.setMethodCallHandler(LeakAvoider(delegate: methodCallDelegate!).handle) channel!.setMethodCallHandler(LeakAvoider(delegate: methodCallDelegate!).handle)
let pullToRefreshLayoutChannel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_" + id,
binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger())
let pullToRefreshSettings = PullToRefreshSettings() let pullToRefreshSettings = PullToRefreshSettings()
let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings) let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings)
let pullToRefreshControl = PullToRefreshControl(channel: pullToRefreshLayoutChannel, settings: pullToRefreshSettings) let pullToRefreshControl = PullToRefreshControl(registrar: SwiftFlutterPlugin.instance!.registrar!, id: id, settings: pullToRefreshSettings)
webView.pullToRefreshControl = pullToRefreshControl webView.pullToRefreshControl = pullToRefreshControl
pullToRefreshControl.delegate = webView pullToRefreshControl.delegate = webView
pullToRefreshControl.prepare() pullToRefreshControl.prepare()

View File

@ -10,7 +10,7 @@ import Foundation
import WebKit import WebKit
@available(iOS 11.0, *) @available(iOS 11.0, *)
class CustomeSchemeHandler : NSObject, WKURLSchemeHandler { class CustomSchemeHandler : NSObject, WKURLSchemeHandler {
var schemeHandlers: [Int:WKURLSchemeTask] = [:] var schemeHandlers: [Int:WKURLSchemeTask] = [:]
func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) { func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {

View File

@ -63,11 +63,9 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
methodCallDelegate = InAppWebViewMethodHandler(webView: webView!) methodCallDelegate = InAppWebViewMethodHandler(webView: webView!)
channel!.setMethodCallHandler(LeakAvoider(delegate: methodCallDelegate!).handle) channel!.setMethodCallHandler(LeakAvoider(delegate: methodCallDelegate!).handle)
let pullToRefreshLayoutChannel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_" + String(describing: viewId),
binaryMessenger: registrar.messenger())
let pullToRefreshSettings = PullToRefreshSettings() let pullToRefreshSettings = PullToRefreshSettings()
let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings) let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings)
let pullToRefreshControl = PullToRefreshControl(channel: pullToRefreshLayoutChannel, settings: pullToRefreshSettings) let pullToRefreshControl = PullToRefreshControl(registrar: registrar, id: viewId, settings: pullToRefreshSettings)
webView!.pullToRefreshControl = pullToRefreshControl webView!.pullToRefreshControl = pullToRefreshControl
pullToRefreshControl.delegate = webView! pullToRefreshControl.delegate = webView!
pullToRefreshControl.prepare() pullToRefreshControl.prepare()

View File

@ -9,6 +9,7 @@ import Flutter
import Foundation import Foundation
public class FlutterWebViewFactory: NSObject, FlutterPlatformViewFactory { public class FlutterWebViewFactory: NSObject, FlutterPlatformViewFactory {
static let VIEW_TYPE_ID = "com.pichillilorenzo/flutter_inappwebview"
private var registrar: FlutterPluginRegistrar? private var registrar: FlutterPluginRegistrar?
init(registrar: FlutterPluginRegistrar?) { init(registrar: FlutterPluginRegistrar?) {

View File

@ -565,7 +565,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
if #available(iOS 11.0, *) { if #available(iOS 11.0, *) {
for scheme in settings.resourceCustomSchemes { for scheme in settings.resourceCustomSchemes {
configuration.setURLSchemeHandler(CustomeSchemeHandler(), forURLScheme: scheme) configuration.setURLSchemeHandler(CustomSchemeHandler(), forURLScheme: scheme)
} }
if settings.sharedCookiesEnabled { if settings.sharedCookiesEnabled {
// More info to sending cookies with WKWebView // More info to sending cookies with WKWebView

View File

@ -8,24 +8,18 @@
import Foundation import Foundation
import WebKit import WebKit
class InAppWebViewStatic: NSObject, FlutterPlugin { class InAppWebViewStatic: ChannelDelegate {
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static"
static var registrar: FlutterPluginRegistrar? static var registrar: FlutterPluginRegistrar?
static var channel: FlutterMethodChannel?
static var webViewForUserAgent: WKWebView? static var webViewForUserAgent: WKWebView?
static var defaultUserAgent: String? static var defaultUserAgent: String?
static func register(with registrar: FlutterPluginRegistrar) {
}
init(registrar: FlutterPluginRegistrar) { init(registrar: FlutterPluginRegistrar) {
super.init() super.init(channel: FlutterMethodChannel(name: InAppWebViewStatic.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
InAppWebViewStatic.registrar = registrar InAppWebViewStatic.registrar = registrar
InAppWebViewStatic.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_static", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(self, channel: InAppWebViewStatic.channel!)
} }
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary let arguments = call.arguments as? NSDictionary
switch call.method { switch call.method {
@ -73,9 +67,8 @@ class InAppWebViewStatic: NSObject, FlutterPlugin {
} }
} }
public func dispose() { public override func dispose() {
InAppWebViewStatic.channel?.setMethodCallHandler(nil) super.dispose()
InAppWebViewStatic.channel = nil
InAppWebViewStatic.registrar = nil InAppWebViewStatic.registrar = nil
InAppWebViewStatic.webViewForUserAgent = nil InAppWebViewStatic.webViewForUserAgent = nil
InAppWebViewStatic.defaultUserAgent = nil InAppWebViewStatic.defaultUserAgent = nil

View File

@ -9,26 +9,18 @@ import Foundation
import WebKit import WebKit
@available(iOS 11.0, *) @available(iOS 11.0, *)
class MyCookieManager: NSObject, FlutterPlugin { class MyCookieManager: ChannelDelegate {
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager"
static var registrar: FlutterPluginRegistrar? static var registrar: FlutterPluginRegistrar?
static var channel: FlutterMethodChannel?
static var httpCookieStore: WKHTTPCookieStore? static var httpCookieStore: WKHTTPCookieStore?
static func register(with registrar: FlutterPluginRegistrar) {
}
init(registrar: FlutterPluginRegistrar) { init(registrar: FlutterPluginRegistrar) {
super.init() super.init(channel: FlutterMethodChannel(name: MyCookieManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
MyCookieManager.registrar = registrar MyCookieManager.registrar = registrar
MyCookieManager.httpCookieStore = WKWebsiteDataStore.default().httpCookieStore MyCookieManager.httpCookieStore = WKWebsiteDataStore.default().httpCookieStore
MyCookieManager.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_cookiemanager", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(self, channel: MyCookieManager.channel!)
} }
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary let arguments = call.arguments as? NSDictionary
switch call.method { switch call.method {
case "setCookie": case "setCookie":
@ -298,9 +290,8 @@ class MyCookieManager: NSObject, FlutterPlugin {
}) })
} }
public func dispose() { public override func dispose() {
MyCookieManager.channel?.setMethodCallHandler(nil) super.dispose()
MyCookieManager.channel = nil
MyCookieManager.registrar = nil MyCookieManager.registrar = nil
MyCookieManager.httpCookieStore = nil MyCookieManager.httpCookieStore = nil
} }

View File

@ -9,26 +9,18 @@ import Foundation
import WebKit import WebKit
@available(iOS 9.0, *) @available(iOS 9.0, *)
class MyWebStorageManager: NSObject, FlutterPlugin { class MyWebStorageManager: ChannelDelegate {
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager"
static var registrar: FlutterPluginRegistrar? static var registrar: FlutterPluginRegistrar?
static var channel: FlutterMethodChannel?
static var websiteDataStore: WKWebsiteDataStore? static var websiteDataStore: WKWebsiteDataStore?
static func register(with registrar: FlutterPluginRegistrar) {
}
init(registrar: FlutterPluginRegistrar) { init(registrar: FlutterPluginRegistrar) {
super.init() super.init(channel: FlutterMethodChannel(name: MyWebStorageManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
MyWebStorageManager.registrar = registrar MyWebStorageManager.registrar = registrar
MyWebStorageManager.websiteDataStore = WKWebsiteDataStore.default() MyWebStorageManager.websiteDataStore = WKWebsiteDataStore.default()
MyWebStorageManager.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_webstoragemanager", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(self, channel: MyWebStorageManager.channel!)
} }
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary let arguments = call.arguments as? NSDictionary
switch call.method { switch call.method {
case "fetchDataRecords": case "fetchDataRecords":
@ -108,9 +100,8 @@ class MyWebStorageManager: NSObject, FlutterPlugin {
} }
} }
public func dispose() { public override func dispose() {
MyWebStorageManager.channel?.setMethodCallHandler(nil) super.dispose()
MyWebStorageManager.channel = nil
MyWebStorageManager.registrar = nil MyWebStorageManager.registrar = nil
MyWebStorageManager.websiteDataStore = nil MyWebStorageManager.websiteDataStore = nil
} }

View File

@ -7,22 +7,16 @@
import Foundation import Foundation
class PlatformUtil: NSObject, FlutterPlugin { class PlatformUtil: ChannelDelegate {
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil"
static var registrar: FlutterPluginRegistrar? static var registrar: FlutterPluginRegistrar?
static var channel: FlutterMethodChannel?
static func register(with registrar: FlutterPluginRegistrar) {
}
init(registrar: FlutterPluginRegistrar) { init(registrar: FlutterPluginRegistrar) {
super.init() super.init(channel: FlutterMethodChannel(name: PlatformUtil.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
InAppWebViewStatic.registrar = registrar InAppWebViewStatic.registrar = registrar
InAppWebViewStatic.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_platformutil", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(self, channel: InAppWebViewStatic.channel!)
} }
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary let arguments = call.arguments as? NSDictionary
switch call.method { switch call.method {
@ -61,9 +55,8 @@ class PlatformUtil: NSObject, FlutterPlugin {
return formatter.string(from: PlatformUtil.getDateFromMilliseconds(date: date)) return formatter.string(from: PlatformUtil.getDateFromMilliseconds(date: date))
} }
public func dispose() { public override func dispose() {
PlatformUtil.channel?.setMethodCallHandler(nil) super.dispose()
PlatformUtil.channel = nil
PlatformUtil.registrar = nil PlatformUtil.registrar = nil
} }
} }

View File

@ -0,0 +1,90 @@
//
// PullToRefreshChannelDelegate.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 05/05/22.
//
import Foundation
public class PullToRefreshChannelDelegate : ChannelDelegate {
private var pullToRefreshControl: PullToRefreshControl?
public init(pullToRefreshControl: PullToRefreshControl , channel: FlutterMethodChannel) {
super.init(channel: channel)
self.pullToRefreshControl = pullToRefreshControl
}
public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
switch call.method {
case "setEnabled":
if let pullToRefreshView = pullToRefreshControl {
let enabled = arguments!["enabled"] as! Bool
if enabled {
pullToRefreshView.delegate?.enablePullToRefresh()
} else {
pullToRefreshView.delegate?.disablePullToRefresh()
}
result(true)
} else {
result(false)
}
break
case "setRefreshing":
if let pullToRefreshView = pullToRefreshControl {
let refreshing = arguments!["refreshing"] as! Bool
if refreshing {
pullToRefreshView.beginRefreshing()
} else {
pullToRefreshView.endRefreshing()
}
result(true)
} else {
result(false)
}
break
case "setColor":
if let pullToRefreshView = pullToRefreshControl {
let color = arguments!["color"] as! String
pullToRefreshView.tintColor = UIColor(hexString: color)
result(true)
} else {
result(false)
}
break
case "setBackgroundColor":
if let pullToRefreshView = pullToRefreshControl {
let color = arguments!["color"] as! String
pullToRefreshView.backgroundColor = UIColor(hexString: color)
result(true)
} else {
result(false)
}
break
case "setStyledTitle":
if let pullToRefreshView = pullToRefreshControl {
let attributedTitleMap = arguments!["attributedTitle"] as! [String: Any?]
pullToRefreshView.attributedTitle = NSAttributedString.fromMap(map: attributedTitleMap)
result(true)
} else {
result(false)
}
break
default:
result(FlutterMethodNotImplemented)
break
}
}
public func onRefresh() {
let arguments: [String: Any?] = [:]
channel?.invokeMethod("onRefresh", arguments: arguments)
}
public override func dispose() {
super.dispose()
pullToRefreshControl = nil
}
}

View File

@ -8,29 +8,26 @@
import Foundation import Foundation
import Flutter import Flutter
public class PullToRefreshControl : UIRefreshControl, FlutterPlugin { public class PullToRefreshControl : UIRefreshControl, Disposable {
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_";
var channel: FlutterMethodChannel? var channelDelegate: PullToRefreshChannelDelegate?
var settings: PullToRefreshSettings? var settings: PullToRefreshSettings?
var shouldCallOnRefresh = false var shouldCallOnRefresh = false
var delegate: PullToRefreshDelegate? var delegate: PullToRefreshDelegate?
public init(channel: FlutterMethodChannel?, settings: PullToRefreshSettings?) { public init(registrar: FlutterPluginRegistrar, id: Any, settings: PullToRefreshSettings?) {
super.init() super.init()
self.channel = channel
self.settings = settings self.settings = settings
let channel = FlutterMethodChannel(name: PullToRefreshControl.METHOD_CHANNEL_NAME_PREFIX + String(describing: id),
binaryMessenger: registrar.messenger())
self.channelDelegate = PullToRefreshChannelDelegate(pullToRefreshControl: self, channel: channel)
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
super.init(coder: coder) super.init(coder: coder)
} }
public static func register(with registrar: FlutterPluginRegistrar) {
}
public func prepare() { public func prepare() {
self.channel?.setMethodCallHandler(self.handle)
if let options = settings { if let options = settings {
if options.enabled { if options.enabled {
delegate?.enablePullToRefresh() delegate?.enablePullToRefresh()
@ -48,53 +45,9 @@ public class PullToRefreshControl : UIRefreshControl, FlutterPlugin {
addTarget(self, action: #selector(updateShouldCallOnRefresh), for: .valueChanged) addTarget(self, action: #selector(updateShouldCallOnRefresh), for: .valueChanged)
} }
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
switch call.method {
case "setEnabled":
let enabled = arguments!["enabled"] as! Bool
if enabled {
delegate?.enablePullToRefresh()
} else {
delegate?.disablePullToRefresh()
}
result(true)
break
case "setRefreshing":
let refreshing = arguments!["refreshing"] as! Bool
if refreshing {
self.beginRefreshing()
} else {
self.endRefreshing()
}
result(true)
break
case "setColor":
let color = arguments!["color"] as! String
tintColor = UIColor(hexString: color)
result(true)
break
case "setBackgroundColor":
let color = arguments!["color"] as! String
backgroundColor = UIColor(hexString: color)
result(true)
break
case "setStyledTitle":
let attributedTitleMap = arguments!["attributedTitle"] as! [String: Any?]
attributedTitle = NSAttributedString.fromMap(map: attributedTitleMap)
result(true)
break
default:
result(FlutterMethodNotImplemented)
break
}
}
public func onRefresh() { public func onRefresh() {
shouldCallOnRefresh = false shouldCallOnRefresh = false
let arguments: [String: Any?] = [:] channelDelegate?.onRefresh()
self.channel?.invokeMethod("onRefresh", arguments: arguments)
} }
@objc public func updateShouldCallOnRefresh() { @objc public func updateShouldCallOnRefresh() {
@ -102,7 +55,8 @@ public class PullToRefreshControl : UIRefreshControl, FlutterPlugin {
} }
public func dispose() { public func dispose() {
channel?.setMethodCallHandler(nil) channelDelegate?.dispose()
channelDelegate = nil
removeTarget(self, action: #selector(updateShouldCallOnRefresh), for: .valueChanged) removeTarget(self, action: #selector(updateShouldCallOnRefresh), for: .valueChanged)
delegate = nil delegate = nil
} }

View File

@ -12,22 +12,16 @@ import Foundation
import AVFoundation import AVFoundation
import SafariServices import SafariServices
public class ChromeSafariBrowserManager: NSObject, FlutterPlugin { public class ChromeSafariBrowserManager: ChannelDelegate {
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_chromesafaribrowser"
static var registrar: FlutterPluginRegistrar? static var registrar: FlutterPluginRegistrar?
static var channel: FlutterMethodChannel?
public static func register(with registrar: FlutterPluginRegistrar) {
}
init(registrar: FlutterPluginRegistrar) { init(registrar: FlutterPluginRegistrar) {
super.init() super.init(channel: FlutterMethodChannel(name: ChromeSafariBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
ChromeSafariBrowserManager.registrar = registrar 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) { public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary let arguments = call.arguments as? NSDictionary
switch call.method { switch call.method {
@ -92,9 +86,8 @@ public class ChromeSafariBrowserManager: NSObject, FlutterPlugin {
result(FlutterError.init(code: "ChromeSafariBrowserManager", message: "SafariViewController is not available!", details: nil)) result(FlutterError.init(code: "ChromeSafariBrowserManager", message: "SafariViewController is not available!", details: nil))
} }
public func dispose() { public override func dispose() {
ChromeSafariBrowserManager.channel?.setMethodCallHandler(nil) super.dispose()
ChromeSafariBrowserManager.channel = nil
ChromeSafariBrowserManager.registrar = nil ChromeSafariBrowserManager.registrar = nil
} }
} }

View File

@ -42,7 +42,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
super.init() super.init()
self.registrar = registrar self.registrar = registrar
registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: "com.pichillilorenzo/flutter_inappwebview") registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: FlutterWebViewFactory.VIEW_TYPE_ID)
platformUtil = PlatformUtil(registrar: registrar) platformUtil = PlatformUtil(registrar: registrar)
inAppBrowserManager = InAppBrowserManager(registrar: registrar) inAppBrowserManager = InAppBrowserManager(registrar: registrar)

View File

@ -0,0 +1,27 @@
//
// ChannelDelegate.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 04/05/22.
//
import Foundation
public class ChannelDelegate : FlutterMethodCallDelegate, Disposable {
var channel: FlutterMethodChannel?
public init(channel: FlutterMethodChannel) {
super.init()
self.channel = channel
self.channel?.setMethodCallHandler(handle)
}
public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
}
public func dispose() {
channel?.setMethodCallHandler(nil)
channel = nil
}
}

View File

@ -0,0 +1,12 @@
//
// Disposable.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 04/05/22.
//
import Foundation
public protocol Disposable {
func dispose() -> Void
}

View File

@ -9,8 +9,11 @@ import Foundation
extension URLRequest { extension URLRequest {
public init(fromPluginMap: [String:Any?]) { public init(fromPluginMap: [String:Any?]) {
let url = fromPluginMap["url"] as! String if let urlString = fromPluginMap["url"] as? String, let url = URL(string: urlString) {
self.init(url: URL(string: url)!) self.init(url: url)
} else {
self.init(url: URL(string: "about:blank")!)
}
if let method = fromPluginMap["method"] as? String { if let method = fromPluginMap["method"] as? String {
httpMethod = method httpMethod = method

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina5_5" orientation="portrait" appearance="light"/> <device id="retina5_5" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<deployment version="2048" identifier="iOS"/> <deployment version="2048" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/> <capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>

View File

@ -4,7 +4,7 @@ import 'url_request_network_service_type.dart';
///A URL load request that is independent of protocol or URL scheme. ///A URL load request that is independent of protocol or URL scheme.
class URLRequest { class URLRequest {
///The URL of the request. ///The URL of the request. Setting this to `null` will load `about:blank`.
Uri? url; Uri? url;
///The HTTP request method. ///The HTTP request method.