Added InAppWebView keep alive feature, Added hasJavaScriptHandler, hasUserScript, hasWebMessageListener InAppWebViewController methods, HeadlessInAppWebView.webViewController could be null, Removed throwIfAlreadyOpened, throwIfNotOpened InAppBrowser methods, Removed throwIfAlreadyOpened, throwIfNotOpened ChromeSafariBrowser methods
This commit is contained in:
parent
b6725128a8
commit
5a113f6e8a
|
@ -1,5 +1,10 @@
|
|||
## 6.0.0-beta.24
|
||||
|
||||
- Added InAppWebView keep alive feature
|
||||
- Added `hasJavaScriptHandler`, `hasUserScript`, `hasWebMessageListener` InAppWebViewController methods
|
||||
- `HeadlessInAppWebView.webViewController` could be `null`
|
||||
- Removed `throwIfAlreadyOpened`, `throwIfNotOpened` InAppBrowser methods
|
||||
- Removed `throwIfAlreadyOpened`, `throwIfNotOpened` ChromeSafariBrowser methods
|
||||
- Merged "fix #1389 #1315 contextMenu ios 13" [#1575](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1575) (thanks to [heralight](https://github.com/heralight))
|
||||
- Merged "fix: remove ignored flutter_export_environment.sh" [#1593](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1593) (thanks to [Sunbreak](https://github.com/Sunbreak))
|
||||
- Merged "Fix AndroidX migration URL in README.md" [#1529](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1529) (thanks to [cslee](https://github.com/cslee))
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package com.pichillilorenzo.flutter_inappwebview;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebView;
|
||||
import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebViewManager;
|
||||
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.FlutterWebView;
|
||||
import com.pichillilorenzo.flutter_inappwebview.webview.PlatformWebView;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.WebViewImplementation;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import io.flutter.plugin.common.StandardMessageCodec;
|
||||
import io.flutter.plugin.platform.PlatformView;
|
||||
import io.flutter.plugin.platform.PlatformViewFactory;
|
||||
|
||||
public class FlutterWebViewFactory extends PlatformViewFactory {
|
||||
public static final String VIEW_TYPE_ID = "com.pichillilorenzo/flutter_inappwebview";
|
||||
private final InAppWebViewFlutterPlugin plugin;
|
||||
|
||||
public FlutterWebViewFactory(final InAppWebViewFlutterPlugin plugin) {
|
||||
super(StandardMessageCodec.INSTANCE);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformView create(Context context, int id, Object args) {
|
||||
HashMap<String, Object> params = (HashMap<String, Object>) args;
|
||||
PlatformWebView flutterWebView = null;
|
||||
|
||||
String headlessWebViewId = (String) params.get("headlessWebViewId");
|
||||
if (headlessWebViewId != null) {
|
||||
HeadlessInAppWebView headlessInAppWebView = HeadlessInAppWebViewManager.webViews.get(headlessWebViewId);
|
||||
if (headlessInAppWebView != null) {
|
||||
flutterWebView = headlessInAppWebView.disposeAndGetFlutterWebView();
|
||||
}
|
||||
}
|
||||
|
||||
if (flutterWebView == null) {
|
||||
WebViewImplementation implementation = WebViewImplementation.fromValue((Integer) params.get("implementation"));
|
||||
switch (implementation) {
|
||||
case NATIVE:
|
||||
default:
|
||||
flutterWebView = new FlutterWebView(plugin, context, id, params);
|
||||
}
|
||||
flutterWebView.makeInitialLoad(params);
|
||||
}
|
||||
|
||||
return flutterWebView;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,8 @@ import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobManager;
|
|||
import com.pichillilorenzo.flutter_inappwebview.proxy.ProxyManager;
|
||||
import com.pichillilorenzo.flutter_inappwebview.service_worker.ServiceWorkerManager;
|
||||
import com.pichillilorenzo.flutter_inappwebview.tracing.TracingControllerManager;
|
||||
import com.pichillilorenzo.flutter_inappwebview.webview.FlutterWebViewFactory;
|
||||
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewManager;
|
||||
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
|
||||
|
@ -39,7 +41,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
|
|||
@Nullable
|
||||
public ChromeSafariBrowserManager chromeSafariBrowserManager;
|
||||
@Nullable
|
||||
public InAppWebViewStatic inAppWebViewStatic;
|
||||
public InAppWebViewManager inAppWebViewManager;
|
||||
@Nullable
|
||||
public MyCookieManager myCookieManager;
|
||||
@Nullable
|
||||
|
@ -56,11 +58,6 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
|
|||
public PrintJobManager printJobManager;
|
||||
@Nullable
|
||||
public TracingControllerManager tracingControllerManager;
|
||||
@Nullable
|
||||
public static ValueCallback<Uri> filePathCallbackLegacy;
|
||||
@Nullable
|
||||
public static ValueCallback<Uri[]> filePathCallback;
|
||||
|
||||
public FlutterWebViewFactory flutterWebViewFactory;
|
||||
public Context applicationContext;
|
||||
public PluginRegistry.Registrar registrar;
|
||||
|
@ -110,7 +107,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
|
|||
FlutterWebViewFactory.VIEW_TYPE_ID, flutterWebViewFactory);
|
||||
|
||||
platformUtil = new PlatformUtil(this);
|
||||
inAppWebViewStatic = new InAppWebViewStatic(this);
|
||||
inAppWebViewManager = new InAppWebViewManager(this);
|
||||
myCookieManager = new MyCookieManager(this);
|
||||
myWebStorage = new MyWebStorage(this);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
|
@ -122,7 +119,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
|
|||
webViewFeatureManager = new WebViewFeatureManager(this);
|
||||
proxyManager = new ProxyManager(this);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
printJobManager = new PrintJobManager();
|
||||
printJobManager = new PrintJobManager(this);
|
||||
}
|
||||
tracingControllerManager = new TracingControllerManager(this);
|
||||
}
|
||||
|
@ -157,9 +154,9 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
|
|||
credentialDatabaseHandler.dispose();
|
||||
credentialDatabaseHandler = null;
|
||||
}
|
||||
if (inAppWebViewStatic != null) {
|
||||
inAppWebViewStatic.dispose();
|
||||
inAppWebViewStatic = null;
|
||||
if (inAppWebViewManager != null) {
|
||||
inAppWebViewManager.dispose();
|
||||
inAppWebViewManager = null;
|
||||
}
|
||||
if (serviceWorkerManager != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
serviceWorkerManager.dispose();
|
||||
|
@ -181,8 +178,6 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
|
|||
tracingControllerManager.dispose();
|
||||
tracingControllerManager = null;
|
||||
}
|
||||
filePathCallbackLegacy = null;
|
||||
filePathCallback = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -393,6 +393,5 @@ public class MyCookieManager extends ChannelDelegateImpl {
|
|||
public void dispose() {
|
||||
super.dispose();
|
||||
plugin = null;
|
||||
cookieManager = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,6 +134,5 @@ public class MyWebStorage extends ChannelDelegateImpl {
|
|||
public void dispose() {
|
||||
super.dispose();
|
||||
plugin = null;
|
||||
webStorageManager = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ public class ActionBroadcastReceiver extends BroadcastReceiver {
|
|||
protected static final String LOG_TAG = "ActionBroadcastReceiver";
|
||||
public static final String KEY_ACTION_ID = "com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ACTION_ID";
|
||||
public static final String KEY_ACTION_VIEW_ID = "com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ACTION_VIEW_ID";
|
||||
public static final String KEY_ACTION_MANAGER_ID = "com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ACTION_MANAGER_ID";
|
||||
public static final String KEY_URL_TITLE = "android.intent.extra.SUBJECT";
|
||||
|
||||
@Override
|
||||
|
@ -21,19 +22,25 @@ public class ActionBroadcastReceiver extends BroadcastReceiver {
|
|||
if (url != null) {
|
||||
Bundle b = intent.getExtras();
|
||||
String viewId = b.getString(KEY_ACTION_VIEW_ID);
|
||||
String managerId = b.getString(KEY_ACTION_MANAGER_ID);
|
||||
|
||||
if (clickedId == -1) {
|
||||
int id = b.getInt(KEY_ACTION_ID);
|
||||
String title = b.getString(KEY_URL_TITLE);
|
||||
if (managerId != null) {
|
||||
ChromeSafariBrowserManager chromeSafariBrowserManager = ChromeSafariBrowserManager.shared.get(managerId);
|
||||
if (chromeSafariBrowserManager != null) {
|
||||
if (clickedId == -1) {
|
||||
int id = b.getInt(KEY_ACTION_ID);
|
||||
String title = b.getString(KEY_URL_TITLE);
|
||||
|
||||
ChromeCustomTabsActivity browser = ChromeSafariBrowserManager.browsers.get(viewId);
|
||||
if (browser != null && browser.channelDelegate != null) {
|
||||
browser.channelDelegate.onItemActionPerform(id, url, title);
|
||||
}
|
||||
} else {
|
||||
ChromeCustomTabsActivity browser = ChromeSafariBrowserManager.browsers.get(viewId);
|
||||
if (browser != null && browser.channelDelegate != null) {
|
||||
browser.channelDelegate.onSecondaryItemActionPerform(browser.getResources().getResourceName(clickedId), url);
|
||||
ChromeCustomTabsActivity browser = chromeSafariBrowserManager.browsers.get(viewId);
|
||||
if (browser != null && browser.channelDelegate != null) {
|
||||
browser.channelDelegate.onItemActionPerform(id, url, title);
|
||||
}
|
||||
} else {
|
||||
ChromeCustomTabsActivity browser = chromeSafariBrowserManager.browsers.get(viewId);
|
||||
if (browser != null && browser.channelDelegate != null) {
|
||||
browser.channelDelegate.onSecondaryItemActionPerform(browser.getResources().getResourceName(clickedId), url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
|||
manager = ChromeSafariBrowserManager.shared.get(managerId);
|
||||
if (manager == null || manager.plugin == null || manager.plugin.messenger == null) return;
|
||||
|
||||
ChromeSafariBrowserManager.browsers.put(id, this);
|
||||
manager.browsers.put(id, this);
|
||||
|
||||
MethodChannel channel = new MethodChannel(manager.plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
|
||||
channelDelegate = new ChromeCustomTabsChannelDelegate(this, channel);
|
||||
|
@ -271,6 +271,7 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
|||
|
||||
Bundle extras = new Bundle();
|
||||
extras.putString(ActionBroadcastReceiver.KEY_ACTION_VIEW_ID, id);
|
||||
extras.putString(ActionBroadcastReceiver.KEY_ACTION_MANAGER_ID, manager != null ? manager.id : null);
|
||||
broadcastIntent.putExtras(extras);
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
|
@ -355,6 +356,7 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
|||
Bundle extras = new Bundle();
|
||||
extras.putInt(ActionBroadcastReceiver.KEY_ACTION_ID, actionSourceId);
|
||||
extras.putString(ActionBroadcastReceiver.KEY_ACTION_VIEW_ID, id);
|
||||
extras.putString(ActionBroadcastReceiver.KEY_ACTION_MANAGER_ID, manager != null ? manager.id : null);
|
||||
actionIntent.putExtras(extras);
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
|
@ -374,8 +376,10 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable {
|
|||
channelDelegate.dispose();
|
||||
channelDelegate = null;
|
||||
}
|
||||
if (ChromeSafariBrowserManager.browsers.containsKey(id)) {
|
||||
ChromeSafariBrowserManager.browsers.put(id, null);
|
||||
if (manager != null) {
|
||||
if (manager.browsers.containsKey(id)) {
|
||||
manager.browsers.put(id, null);
|
||||
}
|
||||
}
|
||||
manager = null;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public class ChromeSafariBrowserManager extends ChannelDelegateImpl {
|
|||
public InAppWebViewFlutterPlugin plugin;
|
||||
public String id;
|
||||
public static final Map<String, ChromeSafariBrowserManager> shared = new HashMap<>();
|
||||
public static final Map<String, ChromeCustomTabsActivity> browsers = new HashMap<>();
|
||||
public final Map<String, ChromeCustomTabsActivity> browsers = new HashMap<>();
|
||||
|
||||
public ChromeSafariBrowserManager(final InAppWebViewFlutterPlugin plugin) {
|
||||
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
@ -130,17 +131,21 @@ public class HeadlessInAppWebView implements Disposable {
|
|||
channelDelegate.dispose();
|
||||
channelDelegate = null;
|
||||
}
|
||||
if (HeadlessInAppWebViewManager.webViews.containsKey(id)) {
|
||||
HeadlessInAppWebViewManager.webViews.put(id, null);
|
||||
}
|
||||
if (plugin != null && plugin.activity != null) {
|
||||
ViewGroup contentView = plugin.activity.findViewById(android.R.id.content);
|
||||
if (contentView != null) {
|
||||
ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0);
|
||||
if (mainView != null && flutterWebView != null) {
|
||||
View view = flutterWebView.getView();
|
||||
if (view != null) {
|
||||
mainView.removeView(flutterWebView.getView());
|
||||
if (plugin != null) {
|
||||
HeadlessInAppWebViewManager headlessInAppWebViewManager = plugin.headlessInAppWebViewManager;
|
||||
if (headlessInAppWebViewManager != null && headlessInAppWebViewManager.webViews.containsKey(id)) {
|
||||
headlessInAppWebViewManager.webViews.put(id, null);
|
||||
}
|
||||
Activity activity = plugin.activity;
|
||||
if (activity != null) {
|
||||
ViewGroup contentView = plugin.activity.findViewById(android.R.id.content);
|
||||
if (contentView != null) {
|
||||
ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0);
|
||||
if (mainView != null && flutterWebView != null) {
|
||||
View view = flutterWebView.getView();
|
||||
if (view != null) {
|
||||
mainView.removeView(flutterWebView.getView());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ public class HeadlessInAppWebViewManager extends ChannelDelegateImpl {
|
|||
protected static final String LOG_TAG = "HeadlessInAppWebViewManager";
|
||||
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview";
|
||||
|
||||
public static final Map<String, HeadlessInAppWebView> webViews = new HashMap<>();
|
||||
public final Map<String, HeadlessInAppWebView> webViews = new HashMap<>();
|
||||
@Nullable
|
||||
public InAppWebViewFlutterPlugin plugin;
|
||||
|
||||
|
@ -76,7 +76,7 @@ public class HeadlessInAppWebViewManager extends ChannelDelegateImpl {
|
|||
}
|
||||
FlutterWebView flutterWebView = new FlutterWebView(plugin, context, id, params);
|
||||
HeadlessInAppWebView headlessInAppWebView = new HeadlessInAppWebView(plugin, id, flutterWebView);
|
||||
HeadlessInAppWebViewManager.webViews.put(id, headlessInAppWebView);
|
||||
webViews.put(id, headlessInAppWebView);
|
||||
|
||||
headlessInAppWebView.prepare(params);
|
||||
headlessInAppWebView.onWebViewCreated();
|
||||
|
@ -93,5 +93,6 @@ public class HeadlessInAppWebViewManager extends ChannelDelegateImpl {
|
|||
}
|
||||
}
|
||||
webViews.clear();
|
||||
plugin = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,10 +141,12 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
|
|||
prepareView();
|
||||
|
||||
if (windowId != -1) {
|
||||
Message resultMsg = InAppWebViewChromeClient.windowWebViewMessages.get(windowId);
|
||||
if (resultMsg != null) {
|
||||
((WebView.WebViewTransport) resultMsg.obj).setWebView(webView);
|
||||
resultMsg.sendToTarget();
|
||||
if (webView.plugin != null && webView.plugin.inAppWebViewManager != null) {
|
||||
Message resultMsg = webView.plugin.inAppWebViewManager.windowWebViewMessages.get(windowId);
|
||||
if (resultMsg != null) {
|
||||
((WebView.WebViewTransport) resultMsg.obj).setWebView(webView);
|
||||
resultMsg.sendToTarget();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String initialFile = b.getString("initialFile");
|
||||
|
|
|
@ -21,6 +21,8 @@ public class PrintJobController implements Disposable {
|
|||
@NonNull
|
||||
public String id;
|
||||
@Nullable
|
||||
public InAppWebViewFlutterPlugin plugin;
|
||||
@Nullable
|
||||
public PrintJobChannelDelegate channelDelegate;
|
||||
@Nullable
|
||||
public android.print.PrintJob job;
|
||||
|
@ -30,6 +32,7 @@ public class PrintJobController implements Disposable {
|
|||
public PrintJobController(@NonNull String id, @NonNull android.print.PrintJob job,
|
||||
@Nullable PrintJobSettings settings, @NonNull InAppWebViewFlutterPlugin plugin) {
|
||||
this.id = id;
|
||||
this.plugin = plugin;
|
||||
this.job = job;
|
||||
this.settings = settings;
|
||||
final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
|
||||
|
@ -61,12 +64,16 @@ public class PrintJobController implements Disposable {
|
|||
channelDelegate.dispose();
|
||||
channelDelegate = null;
|
||||
}
|
||||
if (PrintJobManager.jobs.containsKey(id)) {
|
||||
PrintJobManager.jobs.put(id, null);
|
||||
if (plugin != null) {
|
||||
PrintJobManager printJobManager = plugin.printJobManager;
|
||||
if (printJobManager != null && printJobManager.jobs.containsKey(id)) {
|
||||
printJobManager.jobs.put(id, null);
|
||||
}
|
||||
}
|
||||
if (job != null) {
|
||||
job = null;
|
||||
}
|
||||
plugin = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,12 +82,16 @@ public class PrintJobController implements Disposable {
|
|||
channelDelegate.dispose();
|
||||
channelDelegate = null;
|
||||
}
|
||||
if (PrintJobManager.jobs.containsKey(id)) {
|
||||
PrintJobManager.jobs.put(id, null);
|
||||
if (plugin != null) {
|
||||
PrintJobManager printJobManager = plugin.printJobManager;
|
||||
if (printJobManager != null && printJobManager.jobs.containsKey(id)) {
|
||||
printJobManager.jobs.put(id, null);
|
||||
}
|
||||
}
|
||||
if (job != null) {
|
||||
job.cancel();
|
||||
job = null;
|
||||
}
|
||||
plugin = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,11 @@ package com.pichillilorenzo.flutter_inappwebview.print_job;
|
|||
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
@ -34,11 +37,13 @@ import java.util.Map;
|
|||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public class PrintJobManager implements Disposable {
|
||||
protected static final String LOG_TAG = "PrintJobManager";
|
||||
|
||||
public static final Map<String, PrintJobController> jobs = new HashMap<>();
|
||||
@Nullable
|
||||
public InAppWebViewFlutterPlugin plugin;
|
||||
public final Map<String, PrintJobController> jobs = new HashMap<>();
|
||||
|
||||
public PrintJobManager() {
|
||||
public PrintJobManager(@NonNull final InAppWebViewFlutterPlugin plugin) {
|
||||
super();
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
|
@ -49,5 +54,6 @@ public class PrintJobManager implements Disposable {
|
|||
}
|
||||
}
|
||||
jobs.clear();
|
||||
plugin = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,21 +124,6 @@ public class ProxyManager extends ChannelDelegateImpl {
|
|||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
if (proxyController != null) {
|
||||
// Clears the proxy settings
|
||||
proxyController.clearProxyOverride(new Executor() {
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
|
||||
}
|
||||
}, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
}
|
||||
});
|
||||
proxyController = null;
|
||||
}
|
||||
plugin = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,10 +99,6 @@ public class ServiceWorkerManager implements Disposable {
|
|||
channelDelegate.dispose();
|
||||
channelDelegate = null;
|
||||
}
|
||||
if (serviceWorkerController != null) {
|
||||
serviceWorkerController.setServiceWorkerClient(dummyServiceWorkerClientCompat());
|
||||
serviceWorkerController = null;
|
||||
}
|
||||
plugin = null;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,6 @@ public class TracingControllerManager implements Disposable {
|
|||
channelDelegate.dispose();
|
||||
channelDelegate = null;
|
||||
}
|
||||
tracingController = null;
|
||||
plugin = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||
|
||||
public enum WebViewImplementation {
|
||||
NATIVE(0);
|
||||
|
||||
private final int value;
|
||||
|
||||
private WebViewImplementation(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean equalsValue(int otherValue) {
|
||||
return value == otherValue;
|
||||
}
|
||||
|
||||
public static WebViewImplementation fromValue(int value) {
|
||||
for( WebViewImplementation type : WebViewImplementation.values()) {
|
||||
if(value == type.value)
|
||||
return type;
|
||||
}
|
||||
throw new IllegalArgumentException("No enum constant: " + value);
|
||||
}
|
||||
|
||||
public int rawValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.valueOf(this.value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package com.pichillilorenzo.flutter_inappwebview.webview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
|
||||
import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebView;
|
||||
import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebViewManager;
|
||||
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.FlutterWebView;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import io.flutter.plugin.common.StandardMessageCodec;
|
||||
import io.flutter.plugin.platform.PlatformView;
|
||||
import io.flutter.plugin.platform.PlatformViewFactory;
|
||||
|
||||
public class FlutterWebViewFactory extends PlatformViewFactory {
|
||||
public static final String VIEW_TYPE_ID = "com.pichillilorenzo/flutter_inappwebview";
|
||||
private final InAppWebViewFlutterPlugin plugin;
|
||||
|
||||
public FlutterWebViewFactory(final InAppWebViewFlutterPlugin plugin) {
|
||||
super(StandardMessageCodec.INSTANCE);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformView create(Context context, int id, Object args) {
|
||||
HashMap<String, Object> params = (HashMap<String, Object>) args;
|
||||
FlutterWebView flutterWebView = null;
|
||||
Object viewId = id;
|
||||
|
||||
String keepAliveId = (String) params.get("keepAliveId");
|
||||
String headlessWebViewId = (String) params.get("headlessWebViewId");
|
||||
|
||||
HeadlessInAppWebViewManager headlessInAppWebViewManager = plugin.headlessInAppWebViewManager;
|
||||
if (headlessWebViewId != null && headlessInAppWebViewManager != null) {
|
||||
HeadlessInAppWebView headlessInAppWebView = headlessInAppWebViewManager.webViews.get(headlessWebViewId);
|
||||
if (headlessInAppWebView != null) {
|
||||
flutterWebView = headlessInAppWebView.disposeAndGetFlutterWebView();
|
||||
if (flutterWebView != null) {
|
||||
flutterWebView.keepAliveId = keepAliveId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InAppWebViewManager inAppWebViewManager = plugin.inAppWebViewManager;
|
||||
if (keepAliveId != null && flutterWebView == null && inAppWebViewManager != null) {
|
||||
flutterWebView = inAppWebViewManager.keepAliveWebViews.get(keepAliveId);
|
||||
if (flutterWebView != null) {
|
||||
// be sure to remove the view from the previous parent.
|
||||
View view = flutterWebView.getView();
|
||||
if (view != null) {
|
||||
ViewGroup parent = (ViewGroup) view.getParent();
|
||||
if (parent != null) {
|
||||
parent.removeView(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean shouldMakeInitialLoad = flutterWebView == null;
|
||||
if (flutterWebView == null) {
|
||||
if (keepAliveId != null) {
|
||||
viewId = keepAliveId;
|
||||
}
|
||||
flutterWebView = new FlutterWebView(plugin, context, viewId, params);
|
||||
}
|
||||
|
||||
if (keepAliveId != null && inAppWebViewManager != null) {
|
||||
inAppWebViewManager.keepAliveWebViews.put(keepAliveId, flutterWebView);
|
||||
}
|
||||
|
||||
if (shouldMakeInitialLoad) {
|
||||
flutterWebView.makeInitialLoad(params);
|
||||
}
|
||||
|
||||
return flutterWebView;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
package com.pichillilorenzo.flutter_inappwebview;
|
||||
package com.pichillilorenzo.flutter_inappwebview.webview;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Message;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
|
@ -13,9 +16,12 @@ import androidx.annotation.Nullable;
|
|||
import androidx.webkit.WebViewCompat;
|
||||
import androidx.webkit.WebViewFeature;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
|
||||
import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebView;
|
||||
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
|
||||
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.FlutterWebView;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -25,14 +31,19 @@ import java.util.Set;
|
|||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
|
||||
public class InAppWebViewStatic extends ChannelDelegateImpl {
|
||||
protected static final String LOG_TAG = "InAppWebViewStatic";
|
||||
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static";
|
||||
public class InAppWebViewManager extends ChannelDelegateImpl {
|
||||
protected static final String LOG_TAG = "InAppWebViewManager";
|
||||
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_manager";
|
||||
|
||||
@Nullable
|
||||
public InAppWebViewFlutterPlugin plugin;
|
||||
|
||||
public InAppWebViewStatic(final InAppWebViewFlutterPlugin plugin) {
|
||||
public final Map<String, FlutterWebView> keepAliveWebViews = new HashMap<>();
|
||||
|
||||
public final Map<Integer, Message> windowWebViewMessages = new HashMap<>();
|
||||
public int windowAutoincrementId = 0;
|
||||
|
||||
public InAppWebViewManager(final InAppWebViewFlutterPlugin plugin) {
|
||||
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
@ -41,7 +52,11 @@ public class InAppWebViewStatic extends ChannelDelegateImpl {
|
|||
public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) {
|
||||
switch (call.method) {
|
||||
case "getDefaultUserAgent":
|
||||
result.success(WebSettings.getDefaultUserAgent(plugin.applicationContext));
|
||||
if (plugin != null) {
|
||||
result.success(WebSettings.getDefaultUserAgent(plugin.applicationContext));
|
||||
} else {
|
||||
result.success(null);
|
||||
}
|
||||
break;
|
||||
case "clearClientCertPreferences":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
|
@ -118,6 +133,13 @@ public class InAppWebViewStatic extends ChannelDelegateImpl {
|
|||
result.success(false);
|
||||
}
|
||||
break;
|
||||
case "disposeKeepAlive":
|
||||
final String keepAliveId = (String) call.argument("keepAliveId");
|
||||
if (keepAliveId != null) {
|
||||
disposeKeepAlive(keepAliveId);
|
||||
}
|
||||
result.success(true);
|
||||
break;
|
||||
default:
|
||||
result.notImplemented();
|
||||
}
|
||||
|
@ -133,9 +155,37 @@ public class InAppWebViewStatic extends ChannelDelegateImpl {
|
|||
return webViewPackageInfoMap;
|
||||
}
|
||||
|
||||
public void disposeKeepAlive(@NonNull String keepAliveId) {
|
||||
FlutterWebView flutterWebView = keepAliveWebViews.get(keepAliveId);
|
||||
if (flutterWebView != null) {
|
||||
flutterWebView.keepAliveId = null;
|
||||
// be sure to remove the view from the previous parent.
|
||||
View view = flutterWebView.getView();
|
||||
if (view != null) {
|
||||
ViewGroup parent = (ViewGroup) view.getParent();
|
||||
if (parent != null) {
|
||||
parent.removeView(view);
|
||||
}
|
||||
}
|
||||
flutterWebView.dispose();
|
||||
}
|
||||
if (keepAliveWebViews.containsKey(keepAliveId)) {
|
||||
keepAliveWebViews.put(keepAliveId, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
Collection<FlutterWebView> flutterWebViews = keepAliveWebViews.values();
|
||||
for (FlutterWebView flutterWebView : flutterWebViews) {
|
||||
String keepAliveId = flutterWebView.keepAliveId;
|
||||
if (keepAliveId != null) {
|
||||
disposeKeepAlive(flutterWebView.keepAliveId);
|
||||
}
|
||||
}
|
||||
keepAliveWebViews.clear();
|
||||
windowWebViewMessages.clear();
|
||||
plugin = null;
|
||||
}
|
||||
}
|
|
@ -76,9 +76,11 @@ public class JavaScriptBridgeInterface {
|
|||
|
||||
@Override
|
||||
public void defaultBehaviour(@Nullable Boolean handledByClient) {
|
||||
PrintJobController printJobController = PrintJobManager.jobs.get(printJobId);
|
||||
if (printJobController != null) {
|
||||
printJobController.disposeNoCancel();
|
||||
if (inAppWebView != null && inAppWebView.plugin != null && inAppWebView.plugin.printJobManager != null) {
|
||||
PrintJobController printJobController = inAppWebView.plugin.printJobManager.jobs.get(printJobId);
|
||||
if (printJobController != null) {
|
||||
printJobController.disposeNoCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,12 +42,16 @@ public class FlutterWebView implements PlatformWebView {
|
|||
public InAppWebView webView;
|
||||
@Nullable
|
||||
public PullToRefreshLayout pullToRefreshLayout;
|
||||
@Nullable
|
||||
public String keepAliveId;
|
||||
|
||||
public FlutterWebView(final InAppWebViewFlutterPlugin plugin, final Context context, Object id,
|
||||
HashMap<String, Object> params) {
|
||||
DisplayListenerProxy displayListenerProxy = new DisplayListenerProxy();
|
||||
DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
|
||||
displayListenerProxy.onPreWebViewInitialization(displayManager);
|
||||
|
||||
keepAliveId = (String) params.get("keepAliveId");
|
||||
|
||||
Map<String, Object> initialSettings = (Map<String, Object>) params.get("initialSettings");
|
||||
Map<String, Object> contextMenu = (Map<String, Object>) params.get("contextMenu");
|
||||
|
@ -101,26 +105,28 @@ public class FlutterWebView implements PlatformWebView {
|
|||
final Map<String, String> initialData = (Map<String, String>) params.get("initialData");
|
||||
|
||||
if (windowId != null) {
|
||||
Message resultMsg = InAppWebViewChromeClient.windowWebViewMessages.get(windowId);
|
||||
if (resultMsg != null) {
|
||||
((WebView.WebViewTransport) resultMsg.obj).setWebView(webView);
|
||||
resultMsg.sendToTarget();
|
||||
if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
|
||||
// for some reason, if a WebView is created using a window id,
|
||||
// the initial plugin and user scripts injected
|
||||
// with WebViewCompat.addDocumentStartJavaScript will not be added!
|
||||
// https://github.com/pichillilorenzo/flutter_inappwebview/issues/1455
|
||||
//
|
||||
// Also, calling the prepareAndAddUserScripts method right after won't work,
|
||||
// so use the View.post method here.
|
||||
webView.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (webView != null) {
|
||||
webView.prepareAndAddUserScripts();
|
||||
if (webView.plugin != null && webView.plugin.inAppWebViewManager != null) {
|
||||
Message resultMsg = webView.plugin.inAppWebViewManager.windowWebViewMessages.get(windowId);
|
||||
if (resultMsg != null) {
|
||||
((WebView.WebViewTransport) resultMsg.obj).setWebView(webView);
|
||||
resultMsg.sendToTarget();
|
||||
if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
|
||||
// for some reason, if a WebView is created using a window id,
|
||||
// the initial plugin and user scripts injected
|
||||
// with WebViewCompat.addDocumentStartJavaScript will not be added!
|
||||
// https://github.com/pichillilorenzo/flutter_inappwebview/issues/1455
|
||||
//
|
||||
// Also, calling the prepareAndAddUserScripts method right after won't work,
|
||||
// so use the View.post method here.
|
||||
webView.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (webView != null) {
|
||||
webView.prepareAndAddUserScripts();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -151,7 +157,7 @@ public class FlutterWebView implements PlatformWebView {
|
|||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (webView != null) {
|
||||
if (keepAliveId == null && webView != null) {
|
||||
if (webView.channelDelegate != null) {
|
||||
webView.channelDelegate.dispose();
|
||||
}
|
||||
|
@ -183,7 +189,7 @@ public class FlutterWebView implements PlatformWebView {
|
|||
webView.destroy();
|
||||
webView = null;
|
||||
}
|
||||
|
||||
|
||||
if (pullToRefreshLayout != null) {
|
||||
pullToRefreshLayout.dispose();
|
||||
pullToRefreshLayout = null;
|
||||
|
|
|
@ -1439,10 +1439,10 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
|
|||
// Create a printCurrentPage job with name and adapter instance
|
||||
android.print.PrintJob job = printManager.print(jobName, printAdapter, builder.build());
|
||||
|
||||
if (settings != null && settings.handledByClient) {
|
||||
if (settings != null && settings.handledByClient && plugin.printJobManager != null) {
|
||||
String id = UUID.randomUUID().toString();
|
||||
PrintJobController printJobController = new PrintJobController(id, job, settings, plugin);
|
||||
PrintJobManager.jobs.put(printJobController.id, printJobController);
|
||||
plugin.printJobManager.jobs.put(printJobController.id, printJobController);
|
||||
return id;
|
||||
}
|
||||
} else {
|
||||
|
@ -2011,8 +2011,8 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
|
|||
webViewAssetLoaderExt.dispose();
|
||||
webViewAssetLoaderExt = null;
|
||||
}
|
||||
if (windowId != null) {
|
||||
InAppWebViewChromeClient.windowWebViewMessages.remove(windowId);
|
||||
if (windowId != null && plugin != null && plugin.inAppWebViewManager != null) {
|
||||
plugin.inAppWebViewManager.windowWebViewMessages.remove(windowId);
|
||||
}
|
||||
mainLooperHandler.removeCallbacksAndMessages(null);
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
|
|
|
@ -77,14 +77,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
|||
|
||||
protected static final String LOG_TAG = "IABWebChromeClient";
|
||||
private InAppBrowserDelegate inAppBrowserDelegate;
|
||||
public static Map<Integer, Message> windowWebViewMessages = new HashMap<>();
|
||||
private static int windowAutoincrementId = 0;
|
||||
|
||||
private static final int PICKER = 1;
|
||||
private static final int PICKER_LEGACY = 3;
|
||||
final String DEFAULT_MIME_TYPES = "*/*";
|
||||
private static Uri videoOutputFileUri;
|
||||
private static Uri imageOutputFileUri;
|
||||
|
||||
protected static final FrameLayout.LayoutParams FULLSCREEN_LAYOUT_PARAMS = new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER);
|
||||
|
@ -115,6 +111,15 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
|||
@Nullable
|
||||
public InAppWebView inAppWebView;
|
||||
|
||||
@Nullable
|
||||
private ValueCallback<Uri> filePathCallbackLegacy;
|
||||
@Nullable
|
||||
private ValueCallback<Uri[]> filePathCallback;
|
||||
@Nullable
|
||||
private Uri videoOutputFileUri;
|
||||
@Nullable
|
||||
private Uri imageOutputFileUri;
|
||||
|
||||
public InAppWebViewChromeClient(@NonNull final InAppWebViewFlutterPlugin plugin,
|
||||
@NonNull InAppWebView inAppWebView, InAppBrowserDelegate inAppBrowserDelegate) {
|
||||
super();
|
||||
|
@ -610,8 +615,11 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
|||
|
||||
@Override
|
||||
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, final Message resultMsg) {
|
||||
windowAutoincrementId++;
|
||||
final int windowId = windowAutoincrementId;
|
||||
int windowId = 0;
|
||||
if (plugin != null && plugin.inAppWebViewManager != null) {
|
||||
plugin.inAppWebViewManager.windowAutoincrementId++;
|
||||
windowId = plugin.inAppWebViewManager.windowAutoincrementId;
|
||||
}
|
||||
|
||||
WebView.HitTestResult result = view.getHitTestResult();
|
||||
String url = result.getExtra();
|
||||
|
@ -639,9 +647,12 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
|||
isDialog
|
||||
);
|
||||
|
||||
windowWebViewMessages.put(windowId, resultMsg);
|
||||
if (plugin != null && plugin.inAppWebViewManager != null) {
|
||||
plugin.inAppWebViewManager.windowWebViewMessages.put(windowId, resultMsg);
|
||||
}
|
||||
|
||||
if (inAppWebView != null && inAppWebView.channelDelegate != null) {
|
||||
int finalWindowId = windowId;
|
||||
inAppWebView.channelDelegate.onCreateWindow(createWindowAction, new WebViewChannelDelegate.CreateWindowCallback() {
|
||||
@Override
|
||||
public boolean nonNullSuccess(@NonNull Boolean handledByClient) {
|
||||
|
@ -650,7 +661,9 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
|||
|
||||
@Override
|
||||
public void defaultBehaviour(@Nullable Boolean handledByClient) {
|
||||
InAppWebViewChromeClient.windowWebViewMessages.remove(windowId);
|
||||
if (plugin != null && plugin.inAppWebViewManager != null) {
|
||||
plugin.inAppWebViewManager.windowWebViewMessages.remove(finalWindowId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -824,7 +837,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
|||
|
||||
@Override
|
||||
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (InAppWebViewFlutterPlugin.filePathCallback == null && InAppWebViewFlutterPlugin.filePathCallbackLegacy == null) {
|
||||
if (filePathCallback == null && filePathCallbackLegacy == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -838,8 +851,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
|||
results = getSelectedFiles(data, resultCode);
|
||||
}
|
||||
|
||||
if (InAppWebViewFlutterPlugin.filePathCallback != null) {
|
||||
InAppWebViewFlutterPlugin.filePathCallback.onReceiveValue(results);
|
||||
if (filePathCallback != null) {
|
||||
filePathCallback.onReceiveValue(results);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -848,13 +861,14 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
|||
if (resultCode == RESULT_OK) {
|
||||
result = data != null ? data.getData() : getCapturedMediaFile();
|
||||
}
|
||||
|
||||
InAppWebViewFlutterPlugin.filePathCallbackLegacy.onReceiveValue(result);
|
||||
if (filePathCallbackLegacy != null) {
|
||||
filePathCallbackLegacy.onReceiveValue(result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
InAppWebViewFlutterPlugin.filePathCallback = null;
|
||||
InAppWebViewFlutterPlugin.filePathCallbackLegacy = null;
|
||||
filePathCallback = null;
|
||||
filePathCallbackLegacy = null;
|
||||
imageOutputFileUri = null;
|
||||
videoOutputFileUri = null;
|
||||
|
||||
|
@ -921,7 +935,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
|||
}
|
||||
|
||||
public void startPickerIntent(ValueCallback<Uri> filePathCallback, String acceptType, @Nullable String capture) {
|
||||
InAppWebViewFlutterPlugin.filePathCallbackLegacy = filePathCallback;
|
||||
filePathCallbackLegacy = filePathCallback;
|
||||
|
||||
boolean images = acceptsImages(acceptType);
|
||||
boolean video = acceptsVideo(acceptType);
|
||||
|
@ -965,7 +979,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
|||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public boolean startPickerIntent(final ValueCallback<Uri[]> callback, final String[] acceptTypes,
|
||||
final boolean allowMultiple, final boolean captureEnabled) {
|
||||
InAppWebViewFlutterPlugin.filePathCallback = callback;
|
||||
filePathCallback = callback;
|
||||
|
||||
boolean images = acceptsImages(acceptTypes);
|
||||
boolean video = acceptsVideo(acceptTypes);
|
||||
|
@ -1289,7 +1303,11 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
|
|||
inAppBrowserDelegate.getActivityResultListeners().clear();
|
||||
inAppBrowserDelegate = null;
|
||||
}
|
||||
plugin = null;
|
||||
filePathCallbackLegacy = null;
|
||||
filePathCallback = null;
|
||||
videoOutputFileUri = null;
|
||||
imageOutputFileUri = null;
|
||||
inAppWebView = null;
|
||||
plugin = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ void customMenuItem() {
|
|||
expect(chromeSafariBrowser.isOpened(), true);
|
||||
expect(() async {
|
||||
await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1);
|
||||
}, throwsA(isInstanceOf<ChromeSafariBrowserAlreadyOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||
await chromeSafariBrowser.close();
|
||||
|
|
|
@ -26,7 +26,7 @@ void customTabs() {
|
|||
expect(chromeSafariBrowser.isOpened(), true);
|
||||
expect(() async {
|
||||
await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1);
|
||||
}, throwsA(isInstanceOf<ChromeSafariBrowserAlreadyOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||
await chromeSafariBrowser.close();
|
||||
|
@ -45,7 +45,7 @@ void customTabs() {
|
|||
expect(chromeSafariBrowser.isOpened(), true);
|
||||
expect(() async {
|
||||
await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1);
|
||||
}, throwsA(isInstanceOf<ChromeSafariBrowserAlreadyOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||
await chromeSafariBrowser.close();
|
||||
|
@ -71,7 +71,7 @@ void customTabs() {
|
|||
expect(chromeSafariBrowser.isOpened(), true);
|
||||
expect(() async {
|
||||
await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1);
|
||||
}, throwsA(isInstanceOf<ChromeSafariBrowserAlreadyOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||
await chromeSafariBrowser.updateActionButton(
|
||||
|
|
|
@ -50,7 +50,7 @@ void openAndClose() {
|
|||
expect(chromeSafariBrowser.isOpened(), true);
|
||||
expect(() async {
|
||||
await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1);
|
||||
}, throwsA(isInstanceOf<ChromeSafariBrowserAlreadyOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||
await chromeSafariBrowser.close();
|
||||
|
|
|
@ -22,7 +22,7 @@ void sfSafariViewController() {
|
|||
expect(chromeSafariBrowser.isOpened(), true);
|
||||
expect(() async {
|
||||
await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1);
|
||||
}, throwsA(isInstanceOf<ChromeSafariBrowserAlreadyOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
expect(await chromeSafariBrowser.firstPageLoaded.future, true);
|
||||
await chromeSafariBrowser.close();
|
||||
|
|
|
@ -24,7 +24,7 @@ void trustedWebActivity() {
|
|||
expect(chromeSafariBrowser.isOpened(), true);
|
||||
expect(() async {
|
||||
await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1);
|
||||
}, throwsA(isInstanceOf<ChromeSafariBrowserAlreadyOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||
await chromeSafariBrowser.close();
|
||||
|
@ -44,7 +44,7 @@ void trustedWebActivity() {
|
|||
expect(chromeSafariBrowser.isOpened(), true);
|
||||
expect(() async {
|
||||
await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1);
|
||||
}, throwsA(isInstanceOf<ChromeSafariBrowserAlreadyOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes);
|
||||
await chromeSafariBrowser.close();
|
||||
|
|
|
@ -19,7 +19,7 @@ void openDataAndClose() {
|
|||
expect(inAppBrowser.isOpened(), false);
|
||||
expect(() async {
|
||||
await inAppBrowser.show();
|
||||
}, throwsA(isInstanceOf<InAppBrowserNotOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
await inAppBrowser.openData(
|
||||
data: """
|
||||
|
@ -46,7 +46,7 @@ void openDataAndClose() {
|
|||
expect(() async {
|
||||
await inAppBrowser.openUrlRequest(
|
||||
urlRequest: URLRequest(url: TEST_URL_1));
|
||||
}, throwsA(isInstanceOf<InAppBrowserAlreadyOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
await inAppBrowser.firstPageLoaded.future;
|
||||
var controller = inAppBrowser.webViewController;
|
||||
|
|
|
@ -19,7 +19,7 @@ void openFileAndClose() {
|
|||
expect(inAppBrowser.isOpened(), false);
|
||||
expect(() async {
|
||||
await inAppBrowser.show();
|
||||
}, throwsA(isInstanceOf<InAppBrowserNotOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
await inAppBrowser.openFile(
|
||||
assetFilePath: "test_assets/in_app_webview_initial_file_test.html");
|
||||
|
@ -28,7 +28,7 @@ void openFileAndClose() {
|
|||
expect(() async {
|
||||
await inAppBrowser.openUrlRequest(
|
||||
urlRequest: URLRequest(url: TEST_URL_1));
|
||||
}, throwsA(isInstanceOf<InAppBrowserAlreadyOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
await inAppBrowser.firstPageLoaded.future;
|
||||
var controller = inAppBrowser.webViewController;
|
||||
|
|
|
@ -19,7 +19,7 @@ void openUrlAndClose() {
|
|||
expect(inAppBrowser.isOpened(), false);
|
||||
expect(() async {
|
||||
await inAppBrowser.show();
|
||||
}, throwsA(isInstanceOf<InAppBrowserNotOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
await inAppBrowser.openUrlRequest(urlRequest: URLRequest(url: TEST_URL_1));
|
||||
await inAppBrowser.browserCreated.future;
|
||||
|
@ -27,7 +27,7 @@ void openUrlAndClose() {
|
|||
expect(() async {
|
||||
await inAppBrowser.openUrlRequest(
|
||||
urlRequest: URLRequest(url: TEST_CROSS_PLATFORM_URL_1));
|
||||
}, throwsA(isInstanceOf<InAppBrowserAlreadyOpenedException>()));
|
||||
}, throwsException);
|
||||
|
||||
await inAppBrowser.firstPageLoaded.future;
|
||||
var controller = inAppBrowser.webViewController;
|
||||
|
|
|
@ -86,7 +86,7 @@ class _HeadlessInAppWebViewExampleScreenState
|
|||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
if (headlessWebView?.isRunning() ?? false) {
|
||||
await headlessWebView?.webViewController.evaluateJavascript(
|
||||
await headlessWebView?.webViewController?.evaluateJavascript(
|
||||
source: """console.log('Here is the message!');""");
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
|
|
|
@ -126,7 +126,6 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
|||
pullToRefreshController: pullToRefreshController,
|
||||
onWebViewCreated: (controller) async {
|
||||
webViewController = controller;
|
||||
print(await controller.getUrl());
|
||||
},
|
||||
onLoadStart: (controller, url) async {
|
||||
setState(() {
|
||||
|
|
|
@ -11,6 +11,7 @@ import Flutter
|
|||
public class FindInteractionController : NSObject, Disposable {
|
||||
|
||||
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_find_interaction_";
|
||||
var plugin: SwiftFlutterPlugin?
|
||||
var webView: InAppWebView?
|
||||
var channelDelegate: FindInteractionChannelDelegate?
|
||||
var settings: FindInteractionSettings?
|
||||
|
@ -48,13 +49,16 @@ public class FindInteractionController : NSObject, Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
public init(registrar: FlutterPluginRegistrar, id: Any, webView: InAppWebView, settings: FindInteractionSettings?) {
|
||||
public init(plugin: SwiftFlutterPlugin, id: Any, webView: InAppWebView, settings: FindInteractionSettings?) {
|
||||
super.init()
|
||||
self.plugin = plugin
|
||||
self.webView = webView
|
||||
self.settings = settings
|
||||
let channel = FlutterMethodChannel(name: FindInteractionController.METHOD_CHANNEL_NAME_PREFIX + String(describing: id),
|
||||
binaryMessenger: registrar.messenger())
|
||||
self.channelDelegate = FindInteractionChannelDelegate(findInteractionController: self, channel: channel)
|
||||
if let registrar = plugin.registrar {
|
||||
let channel = FlutterMethodChannel(name: FindInteractionController.METHOD_CHANNEL_NAME_PREFIX + String(describing: id),
|
||||
binaryMessenger: registrar.messenger())
|
||||
self.channelDelegate = FindInteractionChannelDelegate(findInteractionController: self, channel: channel)
|
||||
}
|
||||
}
|
||||
|
||||
public func prepare() {
|
||||
|
@ -148,6 +152,7 @@ public class FindInteractionController : NSObject, Disposable {
|
|||
channelDelegate = nil
|
||||
webView = nil
|
||||
activeFindSession = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -79,7 +79,7 @@ public class HeadlessInAppWebView : Disposable {
|
|||
public func dispose() {
|
||||
channelDelegate?.dispose()
|
||||
channelDelegate = nil
|
||||
HeadlessInAppWebViewManager.webViews[id] = nil
|
||||
plugin?.headlessInAppWebViewManager?.webViews[id] = nil
|
||||
flutterWebView = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import AVFoundation
|
|||
public class HeadlessInAppWebViewManager: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview"
|
||||
var plugin: SwiftFlutterPlugin?
|
||||
static var webViews: [String: HeadlessInAppWebView?] = [:]
|
||||
var webViews: [String: HeadlessInAppWebView?] = [:]
|
||||
|
||||
init(plugin: SwiftFlutterPlugin) {
|
||||
super.init(channel: FlutterMethodChannel(name: HeadlessInAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger()))
|
||||
|
@ -40,15 +40,15 @@ public class HeadlessInAppWebViewManager: ChannelDelegate {
|
|||
}
|
||||
|
||||
public func run(id: String, params: [String: Any?]) {
|
||||
guard let plugin = plugin, let registrar = plugin.registrar else {
|
||||
guard let plugin = plugin else {
|
||||
return
|
||||
}
|
||||
let flutterWebView = FlutterWebViewController(registrar: registrar,
|
||||
let flutterWebView = FlutterWebViewController(plugin: plugin,
|
||||
withFrame: CGRect.zero,
|
||||
viewIdentifier: id,
|
||||
params: params as NSDictionary)
|
||||
let headlessInAppWebView = HeadlessInAppWebView(plugin: plugin, id: id, flutterWebView: flutterWebView)
|
||||
HeadlessInAppWebViewManager.webViews[id] = headlessInAppWebView
|
||||
webViews[id] = headlessInAppWebView
|
||||
|
||||
headlessInAppWebView.prepare(params: params as NSDictionary)
|
||||
headlessInAppWebView.onWebViewCreated()
|
||||
|
@ -57,11 +57,11 @@ public class HeadlessInAppWebViewManager: ChannelDelegate {
|
|||
|
||||
public override func dispose() {
|
||||
super.dispose()
|
||||
let headlessWebViews = HeadlessInAppWebViewManager.webViews.values
|
||||
let headlessWebViews = webViews.values
|
||||
headlessWebViews.forEach { (headlessWebView: HeadlessInAppWebView?) in
|
||||
headlessWebView?.dispose()
|
||||
}
|
||||
HeadlessInAppWebViewManager.webViews.removeAll()
|
||||
webViews.removeAll()
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
var isHidden = false
|
||||
|
||||
public override func loadView() {
|
||||
guard let registrar = plugin?.registrar else {
|
||||
guard let plugin = plugin, let registrar = plugin.registrar else {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -55,13 +55,13 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
}
|
||||
|
||||
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(settings: webViewSettings)
|
||||
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
if let wId = windowId, let webViewTransport = plugin.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView = webViewTransport.webView
|
||||
webView!.contextMenu = contextMenu
|
||||
webView!.initialUserScripts = userScripts
|
||||
} else {
|
||||
webView = InAppWebView(id: nil,
|
||||
registrar: nil,
|
||||
plugin: nil,
|
||||
frame: .zero,
|
||||
configuration: preWebviewConfiguration,
|
||||
contextMenu: contextMenu,
|
||||
|
@ -74,17 +74,18 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
|
||||
webView.inAppBrowserDelegate = self
|
||||
webView.id = id
|
||||
webView.plugin = plugin
|
||||
webView.channelDelegate = WebViewChannelDelegate(webView: webView, channel: channel)
|
||||
|
||||
let pullToRefreshSettings = PullToRefreshSettings()
|
||||
let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings)
|
||||
let pullToRefreshControl = PullToRefreshControl(registrar: registrar, id: id, settings: pullToRefreshSettings)
|
||||
let pullToRefreshControl = PullToRefreshControl(plugin: plugin, id: id, settings: pullToRefreshSettings)
|
||||
webView.pullToRefreshControl = pullToRefreshControl
|
||||
pullToRefreshControl.delegate = webView
|
||||
pullToRefreshControl.prepare()
|
||||
|
||||
let findInteractionController = FindInteractionController(
|
||||
registrar: registrar,
|
||||
plugin: plugin,
|
||||
id: id, webView: webView, settings: nil)
|
||||
webView.findInteractionController = findInteractionController
|
||||
findInteractionController.prepare()
|
||||
|
@ -132,7 +133,7 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
}
|
||||
}
|
||||
|
||||
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
if let wId = windowId, let webViewTransport = plugin?.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView?.load(webViewTransport.request)
|
||||
channelDelegate?.onBrowserCreated()
|
||||
} else {
|
||||
|
|
|
@ -11,13 +11,16 @@ import WebKit
|
|||
public class FlutterWebViewController: NSObject, FlutterPlatformView, Disposable {
|
||||
|
||||
var myView: UIView?
|
||||
var keepAliveId: String?
|
||||
|
||||
init(registrar: FlutterPluginRegistrar, withFrame frame: CGRect, viewIdentifier viewId: Any, params: NSDictionary) {
|
||||
init(plugin: SwiftFlutterPlugin, withFrame frame: CGRect, viewIdentifier viewId: Any, params: NSDictionary) {
|
||||
super.init()
|
||||
|
||||
myView = UIView(frame: frame)
|
||||
myView!.clipsToBounds = true
|
||||
|
||||
keepAliveId = params["keepAliveId"] as? String
|
||||
|
||||
let initialSettings = params["initialSettings"] as! [String: Any?]
|
||||
let contextMenu = params["contextMenu"] as? [String: Any]
|
||||
let windowId = params["windowId"] as? Int64
|
||||
|
@ -37,18 +40,21 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView, Disposable
|
|||
|
||||
var webView: InAppWebView?
|
||||
|
||||
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
if let wId = windowId, let webViewTransport = plugin.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView = webViewTransport.webView
|
||||
webView!.id = viewId
|
||||
let channel = FlutterMethodChannel(name: InAppWebView.METHOD_CHANNEL_NAME_PREFIX + String(describing: viewId),
|
||||
binaryMessenger: registrar.messenger())
|
||||
webView!.channelDelegate = WebViewChannelDelegate(webView: webView!, channel: channel)
|
||||
webView!.plugin = plugin
|
||||
if let registrar = plugin.registrar {
|
||||
let channel = FlutterMethodChannel(name: InAppWebView.METHOD_CHANNEL_NAME_PREFIX + String(describing: viewId),
|
||||
binaryMessenger: registrar.messenger())
|
||||
webView!.channelDelegate = WebViewChannelDelegate(webView: webView!, channel: channel)
|
||||
}
|
||||
webView!.frame = myView!.bounds
|
||||
webView!.contextMenu = contextMenu
|
||||
webView!.initialUserScripts = userScripts
|
||||
} else {
|
||||
webView = InAppWebView(id: viewId,
|
||||
registrar: registrar,
|
||||
plugin: plugin,
|
||||
frame: myView!.bounds,
|
||||
configuration: preWebviewConfiguration,
|
||||
contextMenu: contextMenu,
|
||||
|
@ -57,13 +63,13 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView, Disposable
|
|||
|
||||
let pullToRefreshSettings = PullToRefreshSettings()
|
||||
let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings)
|
||||
let pullToRefreshControl = PullToRefreshControl(registrar: registrar, id: viewId, settings: pullToRefreshSettings)
|
||||
let pullToRefreshControl = PullToRefreshControl(plugin: plugin, id: viewId, settings: pullToRefreshSettings)
|
||||
webView!.pullToRefreshControl = pullToRefreshControl
|
||||
pullToRefreshControl.delegate = webView!
|
||||
pullToRefreshControl.prepare()
|
||||
|
||||
let findInteractionController = FindInteractionController(
|
||||
registrar: registrar,
|
||||
plugin: plugin,
|
||||
id: viewId, webView: webView!, settings: nil)
|
||||
webView!.findInteractionController = findInteractionController
|
||||
findInteractionController.prepare()
|
||||
|
@ -132,7 +138,7 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView, Disposable
|
|||
}
|
||||
load(initialUrlRequest: initialUrlRequest, initialFile: initialFile, initialData: initialData)
|
||||
}
|
||||
else if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
else if let wId = windowId, let webViewTransport = webView.plugin?.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView.load(webViewTransport.request)
|
||||
}
|
||||
}
|
||||
|
@ -180,10 +186,12 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView, Disposable
|
|||
}
|
||||
|
||||
public func dispose() {
|
||||
if let webView = webView() {
|
||||
webView.dispose()
|
||||
if keepAliveId == nil {
|
||||
if let webView = webView() {
|
||||
webView.dispose()
|
||||
}
|
||||
myView = nil
|
||||
}
|
||||
myView = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -10,11 +10,11 @@ import Foundation
|
|||
|
||||
public class FlutterWebViewFactory: NSObject, FlutterPlatformViewFactory {
|
||||
static let VIEW_TYPE_ID = "com.pichillilorenzo/flutter_inappwebview"
|
||||
private var registrar: FlutterPluginRegistrar?
|
||||
private var plugin: SwiftFlutterPlugin
|
||||
|
||||
init(registrar: FlutterPluginRegistrar?) {
|
||||
init(plugin: SwiftFlutterPlugin) {
|
||||
self.plugin = plugin
|
||||
super.init()
|
||||
self.registrar = registrar
|
||||
}
|
||||
|
||||
public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
|
||||
|
@ -23,18 +23,48 @@ public class FlutterWebViewFactory: NSObject, FlutterPlatformViewFactory {
|
|||
|
||||
public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
|
||||
let arguments = args as? NSDictionary
|
||||
var flutterWebView: FlutterWebViewController?
|
||||
var id: Any = viewId
|
||||
|
||||
if let headlessWebViewId = arguments?["headlessWebViewId"] as? String,
|
||||
let headlessWebView = HeadlessInAppWebViewManager.webViews[headlessWebViewId],
|
||||
let keepAliveId = arguments?["keepAliveId"] as? String
|
||||
let headlessWebViewId = arguments?["headlessWebViewId"] as? String
|
||||
|
||||
if let headlessWebViewId = headlessWebViewId,
|
||||
let headlessWebView = plugin.headlessInAppWebViewManager?.webViews[headlessWebViewId],
|
||||
let platformView = headlessWebView?.disposeAndGetFlutterWebView(withFrame: frame) {
|
||||
return platformView
|
||||
flutterWebView = platformView
|
||||
flutterWebView?.keepAliveId = keepAliveId
|
||||
}
|
||||
|
||||
let webviewController = FlutterWebViewController(registrar: registrar!,
|
||||
withFrame: frame,
|
||||
viewIdentifier: viewId,
|
||||
params: arguments!)
|
||||
webviewController.makeInitialLoad(params: arguments!)
|
||||
return webviewController
|
||||
if let keepAliveId = keepAliveId,
|
||||
flutterWebView == nil,
|
||||
let keepAliveWebView = plugin.inAppWebViewManager?.keepAliveWebViews[keepAliveId] {
|
||||
flutterWebView = keepAliveWebView
|
||||
if let view = flutterWebView?.view() {
|
||||
// remove from parent
|
||||
view.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
let shouldMakeInitialLoad = flutterWebView == nil
|
||||
if flutterWebView == nil {
|
||||
if let keepAliveId = keepAliveId {
|
||||
id = keepAliveId
|
||||
}
|
||||
flutterWebView = FlutterWebViewController(plugin: plugin,
|
||||
withFrame: frame,
|
||||
viewIdentifier: id,
|
||||
params: arguments!)
|
||||
}
|
||||
|
||||
if let keepAliveId = keepAliveId {
|
||||
plugin.inAppWebViewManager?.keepAliveWebViews[keepAliveId] = flutterWebView!
|
||||
}
|
||||
|
||||
if shouldMakeInitialLoad {
|
||||
flutterWebView?.makeInitialLoad(params: arguments!)
|
||||
}
|
||||
|
||||
return flutterWebView!
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
|||
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_"
|
||||
|
||||
var id: Any? // viewId
|
||||
var registrar: FlutterPluginRegistrar?
|
||||
var plugin: SwiftFlutterPlugin?
|
||||
var windowId: Int64?
|
||||
var windowCreated = false
|
||||
var inAppBrowserDelegate: InAppBrowserDelegate?
|
||||
|
@ -61,21 +61,18 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
|||
|
||||
var customIMPs: [IMP] = []
|
||||
|
||||
static var windowWebViews: [Int64:WebViewTransport] = [:]
|
||||
static var windowAutoincrementId: Int64 = 0;
|
||||
|
||||
var callAsyncJavaScriptBelowIOS14Results: [String:((Any?) -> Void)] = [:]
|
||||
|
||||
var oldZoomScale = Float(1.0)
|
||||
|
||||
init(id: Any?, registrar: FlutterPluginRegistrar?, frame: CGRect, configuration: WKWebViewConfiguration,
|
||||
init(id: Any?, plugin: SwiftFlutterPlugin?, frame: CGRect, configuration: WKWebViewConfiguration,
|
||||
contextMenu: [String: Any]?, userScripts: [UserScript] = []) {
|
||||
super.init(frame: frame, configuration: configuration)
|
||||
self.id = id
|
||||
self.registrar = registrar
|
||||
if let id = id, let registrar = registrar {
|
||||
self.plugin = plugin
|
||||
if let id = id, let registrar = plugin?.registrar {
|
||||
let channel = FlutterMethodChannel(name: InAppWebView.METHOD_CHANNEL_NAME_PREFIX + String(describing: id),
|
||||
binaryMessenger: registrar.messenger())
|
||||
binaryMessenger: registrar.messenger())
|
||||
self.channelDelegate = WebViewChannelDelegate(webView: self, channel: channel)
|
||||
}
|
||||
self.contextMenu = contextMenu
|
||||
|
@ -940,8 +937,8 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
|||
}
|
||||
|
||||
public func loadFile(assetFilePath: String) throws {
|
||||
if let registrar = registrar {
|
||||
let assetURL = try Util.getUrlAsset(registrar: registrar, assetFilePath: assetFilePath)
|
||||
if let plugin = plugin {
|
||||
let assetURL = try Util.getUrlAsset(plugin: plugin, assetFilePath: assetFilePath)
|
||||
let urlRequest = URLRequest(url: assetURL)
|
||||
loadUrl(urlRequest: urlRequest, allowingReadAccessTo: nil)
|
||||
}
|
||||
|
@ -2090,8 +2087,8 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
|||
|
||||
var path: String = certificatePath
|
||||
do {
|
||||
if let registrar = self.registrar {
|
||||
path = try Util.getAbsPathAsset(registrar: registrar, assetFilePath: certificatePath)
|
||||
if let plugin = self.plugin {
|
||||
path = try Util.getAbsPathAsset(plugin: plugin, assetFilePath: certificatePath)
|
||||
}
|
||||
} catch {}
|
||||
|
||||
|
@ -2464,10 +2461,14 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
|||
createWebViewWith configuration: WKWebViewConfiguration,
|
||||
for navigationAction: WKNavigationAction,
|
||||
windowFeatures: WKWindowFeatures) -> WKWebView? {
|
||||
InAppWebView.windowAutoincrementId += 1
|
||||
let windowId = InAppWebView.windowAutoincrementId
|
||||
var windowId: Int64 = 0
|
||||
let inAppWebViewManager = plugin?.inAppWebViewManager
|
||||
if let inAppWebViewManager = inAppWebViewManager {
|
||||
inAppWebViewManager.windowAutoincrementId += 1
|
||||
windowId = inAppWebViewManager.windowAutoincrementId
|
||||
}
|
||||
|
||||
let windowWebView = InAppWebView(id: nil, registrar: nil, frame: CGRect.zero, configuration: configuration, contextMenu: nil)
|
||||
let windowWebView = InAppWebView(id: nil, plugin: nil, frame: CGRect.zero, configuration: configuration, contextMenu: nil)
|
||||
windowWebView.windowId = windowId
|
||||
|
||||
let webViewTransport = WebViewTransport(
|
||||
|
@ -2475,7 +2476,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
|||
request: navigationAction.request
|
||||
)
|
||||
|
||||
InAppWebView.windowWebViews[windowId] = webViewTransport
|
||||
inAppWebViewManager?.windowWebViews[windowId] = webViewTransport
|
||||
windowWebView.stopLoading()
|
||||
|
||||
let createWindowAction = CreateWindowAction(navigationAction: navigationAction, windowId: windowId, windowFeatures: windowFeatures, isDialog: nil)
|
||||
|
@ -2485,8 +2486,8 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
|||
return !handledByClient
|
||||
}
|
||||
callback.defaultBehaviour = { (handledByClient: Bool?) in
|
||||
if InAppWebView.windowWebViews[windowId] != nil {
|
||||
InAppWebView.windowWebViews.removeValue(forKey: windowId)
|
||||
if inAppWebViewManager?.windowWebViews[windowId] != nil {
|
||||
inAppWebViewManager?.windowWebViews.removeValue(forKey: windowId)
|
||||
}
|
||||
self.loadUrl(urlRequest: navigationAction.request, allowingReadAccessTo: nil)
|
||||
}
|
||||
|
@ -2752,7 +2753,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
|||
|
||||
let _windowId = body["_windowId"] as? Int64
|
||||
var webView = self
|
||||
if let wId = _windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
if let wId = _windowId, let webViewTransport = plugin?.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView = webViewTransport.webView
|
||||
}
|
||||
webView.channelDelegate?.onConsoleMessage(message: consoleMessage, messageLevel: messageLevel)
|
||||
|
@ -2769,7 +2770,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
|||
return !handledByClient
|
||||
}
|
||||
callback.defaultBehaviour = { (handledByClient: Bool?) in
|
||||
if let printJob = PrintJobManager.jobs[printJobId] {
|
||||
if let printJob = self.plugin?.printJobManager?.jobs[printJobId] {
|
||||
printJob?.disposeNoDismiss()
|
||||
}
|
||||
}
|
||||
|
@ -2787,7 +2788,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
|||
|
||||
let _windowId = body["_windowId"] as? Int64
|
||||
var webView = self
|
||||
if let wId = _windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
if let wId = _windowId, let webViewTransport = plugin?.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView = webViewTransport.webView
|
||||
}
|
||||
|
||||
|
@ -2829,7 +2830,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
|
||||
let _windowId = body["_windowId"] as? Int64
|
||||
var webView = self
|
||||
if let wId = _windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
if let wId = _windowId, let webViewTransport = plugin?.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView = webViewTransport.webView
|
||||
}
|
||||
webView.findInteractionController?.channelDelegate?.onFindResultReceived(activeMatchOrdinal: activeMatchOrdinal, numberOfMatches: numberOfMatches, isDoneCounting: isDoneCounting)
|
||||
|
@ -2979,9 +2980,9 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
}
|
||||
|
||||
let animated = settings?.animated ?? true
|
||||
if let id = printJobId, let registrar = registrar {
|
||||
let printJob = PrintJobController(registrar: registrar, id: id, job: printController, settings: settings)
|
||||
PrintJobManager.jobs[id] = printJob
|
||||
if let id = printJobId, let plugin = plugin {
|
||||
let printJob = PrintJobController(plugin: plugin, id: id, job: printController, settings: settings)
|
||||
plugin.printJobManager?.jobs[id] = printJob
|
||||
printJob.present(animated: animated, completionHandler: completionHandler)
|
||||
} else {
|
||||
printController.present(animated: animated, completionHandler: completionHandler)
|
||||
|
@ -3123,12 +3124,12 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
}
|
||||
|
||||
public func createWebMessageChannel(completionHandler: ((WebMessageChannel?) -> Void)? = nil) -> WebMessageChannel? {
|
||||
guard let registrar = registrar else {
|
||||
guard let plugin = plugin else {
|
||||
completionHandler?(nil)
|
||||
return nil
|
||||
}
|
||||
let id = NSUUID().uuidString
|
||||
let webMessageChannel = WebMessageChannel(registrar: registrar, id: id)
|
||||
let webMessageChannel = WebMessageChannel(plugin: plugin, id: id)
|
||||
webMessageChannel.initJsInstance(webView: self, completionHandler: completionHandler)
|
||||
webMessageChannels[id] = webMessageChannel
|
||||
|
||||
|
@ -3216,8 +3217,8 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
if #available(iOS 11.0, *) {
|
||||
configuration.userContentController.removeAllContentRuleLists()
|
||||
}
|
||||
} else if let wId = windowId, InAppWebView.windowWebViews[wId] != nil {
|
||||
InAppWebView.windowWebViews.removeValue(forKey: wId)
|
||||
} else if let wId = windowId, plugin?.inAppWebViewManager?.windowWebViews[wId] != nil {
|
||||
plugin?.inAppWebViewManager?.windowWebViews.removeValue(forKey: wId)
|
||||
}
|
||||
configuration.userContentController.dispose(windowId: windowId)
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
|
@ -3245,7 +3246,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
SharedLastTouchPointTimestamp.removeValue(forKey: self)
|
||||
callAsyncJavaScriptBelowIOS14Results.removeAll()
|
||||
super.removeFromSuperview()
|
||||
registrar = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// InAppWebViewStatic.swift
|
||||
// InAppWebViewManager.swift
|
||||
// flutter_inappwebview
|
||||
//
|
||||
// Created by Lorenzo Pichilli on 08/12/2019.
|
||||
|
@ -8,14 +8,18 @@
|
|||
import Foundation
|
||||
import WebKit
|
||||
|
||||
public class InAppWebViewStatic: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static"
|
||||
public class InAppWebViewManager: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_manager"
|
||||
var plugin: SwiftFlutterPlugin?
|
||||
var webViewForUserAgent: WKWebView?
|
||||
var defaultUserAgent: String?
|
||||
|
||||
var keepAliveWebViews: [String:FlutterWebViewController?] = [:]
|
||||
var windowWebViews: [Int64:WebViewTransport] = [:]
|
||||
var windowAutoincrementId: Int64 = 0
|
||||
|
||||
init(plugin: SwiftFlutterPlugin) {
|
||||
super.init(channel: FlutterMethodChannel(name: InAppWebViewStatic.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger()))
|
||||
super.init(channel: FlutterMethodChannel(name: InAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger()))
|
||||
self.plugin = plugin
|
||||
}
|
||||
|
||||
|
@ -36,6 +40,11 @@ public class InAppWebViewStatic: ChannelDelegate {
|
|||
result(false)
|
||||
}
|
||||
break
|
||||
case "disposeKeepAlive":
|
||||
let keepAliveId = arguments!["keepAliveId"] as! String
|
||||
disposeKeepAlive(keepAliveId: keepAliveId)
|
||||
result(true)
|
||||
break
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
break
|
||||
|
@ -67,11 +76,27 @@ public class InAppWebViewStatic: ChannelDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
public func disposeKeepAlive(keepAliveId: String) {
|
||||
if let flutterWebView = keepAliveWebViews[keepAliveId] as? FlutterWebViewController {
|
||||
flutterWebView.keepAliveId = nil
|
||||
flutterWebView.dispose()
|
||||
keepAliveWebViews[keepAliveId] = nil
|
||||
}
|
||||
}
|
||||
|
||||
public override func dispose() {
|
||||
super.dispose()
|
||||
plugin = nil
|
||||
let keepAliveWebViewValues = keepAliveWebViews.values
|
||||
keepAliveWebViewValues.forEach {(keepAliveWebView: FlutterWebViewController?) in
|
||||
if let keepAliveId = keepAliveWebView?.keepAliveId {
|
||||
disposeKeepAlive(keepAliveId: keepAliveId)
|
||||
}
|
||||
}
|
||||
keepAliveWebViews.removeAll()
|
||||
windowWebViews.removeAll()
|
||||
webViewForUserAgent = nil
|
||||
defaultUserAgent = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
deinit {
|
|
@ -10,18 +10,20 @@ import Foundation
|
|||
public class WebMessageChannel : FlutterMethodCallDelegate {
|
||||
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_web_message_channel_"
|
||||
var id: String
|
||||
var plugin: SwiftFlutterPlugin?
|
||||
var channelDelegate: WebMessageChannelChannelDelegate?
|
||||
weak var webView: InAppWebView?
|
||||
var ports: [WebMessagePort] = []
|
||||
var registrar: FlutterPluginRegistrar?
|
||||
|
||||
public init(registrar: FlutterPluginRegistrar, id: String) {
|
||||
public init(plugin: SwiftFlutterPlugin, id: String) {
|
||||
self.id = id
|
||||
self.registrar = registrar
|
||||
self.plugin = plugin
|
||||
super.init()
|
||||
let channel = FlutterMethodChannel(name: WebMessageChannel.METHOD_CHANNEL_NAME_PREFIX + id,
|
||||
binaryMessenger: registrar.messenger())
|
||||
self.channelDelegate = WebMessageChannelChannelDelegate(webMessageChannel: self, channel: channel)
|
||||
if let registrar = plugin.registrar {
|
||||
let channel = FlutterMethodChannel(name: WebMessageChannel.METHOD_CHANNEL_NAME_PREFIX + id,
|
||||
binaryMessenger: registrar.messenger())
|
||||
self.channelDelegate = WebMessageChannelChannelDelegate(webMessageChannel: self, channel: channel)
|
||||
}
|
||||
self.ports = [
|
||||
WebMessagePort(name: "port1", webMessageChannel: self),
|
||||
WebMessagePort(name: "port2", webMessageChannel: self)
|
||||
|
@ -67,7 +69,7 @@ public class WebMessageChannel : FlutterMethodCallDelegate {
|
|||
})();
|
||||
""")
|
||||
webView = nil
|
||||
registrar = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -15,17 +15,19 @@ public class WebMessageListener : FlutterMethodCallDelegate {
|
|||
var allowedOriginRules: Set<String>
|
||||
var channelDelegate: WebMessageListenerChannelDelegate?
|
||||
weak var webView: InAppWebView?
|
||||
var registrar: FlutterPluginRegistrar?
|
||||
var plugin: SwiftFlutterPlugin?
|
||||
|
||||
public init(registrar: FlutterPluginRegistrar, id: String, jsObjectName: String, allowedOriginRules: Set<String>) {
|
||||
public init(plugin: SwiftFlutterPlugin, id: String, jsObjectName: String, allowedOriginRules: Set<String>) {
|
||||
self.id = id
|
||||
self.registrar = registrar
|
||||
self.plugin = plugin
|
||||
self.jsObjectName = jsObjectName
|
||||
self.allowedOriginRules = allowedOriginRules
|
||||
super.init()
|
||||
let channel = FlutterMethodChannel(name: WebMessageListener.METHOD_CHANNEL_NAME_PREFIX + self.id + "_" + self.jsObjectName,
|
||||
binaryMessenger: registrar.messenger())
|
||||
self.channelDelegate = WebMessageListenerChannelDelegate(webMessageListener: self, channel: channel)
|
||||
if let registrar = plugin.registrar {
|
||||
let channel = FlutterMethodChannel(name: WebMessageListener.METHOD_CHANNEL_NAME_PREFIX + self.id + "_" + self.jsObjectName,
|
||||
binaryMessenger: registrar.messenger())
|
||||
self.channelDelegate = WebMessageListenerChannelDelegate(webMessageListener: self, channel: channel)
|
||||
}
|
||||
}
|
||||
|
||||
public func assertOriginRulesValid() throws {
|
||||
|
@ -116,12 +118,12 @@ public class WebMessageListener : FlutterMethodCallDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
public static func fromMap(registrar: FlutterPluginRegistrar, map: [String:Any?]?) -> WebMessageListener? {
|
||||
public static func fromMap(plugin: SwiftFlutterPlugin, map: [String:Any?]?) -> WebMessageListener? {
|
||||
guard let map = map else {
|
||||
return nil
|
||||
}
|
||||
return WebMessageListener(
|
||||
registrar: registrar,
|
||||
plugin: plugin,
|
||||
id: map["id"] as! String,
|
||||
jsObjectName: map["jsObjectName"] as! String,
|
||||
allowedOriginRules: Set(map["allowedOriginRules"] as! [String])
|
||||
|
@ -180,7 +182,7 @@ public class WebMessageListener : FlutterMethodCallDelegate {
|
|||
channelDelegate?.dispose()
|
||||
channelDelegate = nil
|
||||
webView = nil
|
||||
registrar = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -536,9 +536,9 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
|||
}
|
||||
break
|
||||
case .addWebMessageListener:
|
||||
if let webView = webView, let registrar = webView.registrar {
|
||||
if let webView = webView, let plugin = webView.plugin {
|
||||
let webMessageListenerMap = arguments!["webMessageListener"] as! [String: Any?]
|
||||
let webMessageListener = WebMessageListener.fromMap(registrar: registrar, map: webMessageListenerMap)!
|
||||
let webMessageListener = WebMessageListener.fromMap(plugin: plugin, map: webMessageListenerMap)!
|
||||
do {
|
||||
try webView.addWebMessageListener(webMessageListener: webMessageListener)
|
||||
result(false)
|
||||
|
|
|
@ -18,7 +18,7 @@ public enum PrintJobState: Int {
|
|||
public class PrintJobController : NSObject, Disposable, UIPrintInteractionControllerDelegate {
|
||||
static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_printjobcontroller_"
|
||||
var id: String
|
||||
var registrar: FlutterPluginRegistrar?
|
||||
var plugin: SwiftFlutterPlugin?
|
||||
var job: UIPrintInteractionController?
|
||||
var settings: PrintJobSettings?
|
||||
var printFormatter: UIPrintFormatter?
|
||||
|
@ -27,18 +27,20 @@ public class PrintJobController : NSObject, Disposable, UIPrintInteractionContro
|
|||
var state = PrintJobState.created
|
||||
var creationTime = Int64(Date().timeIntervalSince1970 * 1000)
|
||||
|
||||
public init(registrar: FlutterPluginRegistrar, id: String, job: UIPrintInteractionController? = nil, settings: PrintJobSettings? = nil) {
|
||||
public init(plugin: SwiftFlutterPlugin, id: String, job: UIPrintInteractionController? = nil, settings: PrintJobSettings? = nil) {
|
||||
self.id = id
|
||||
self.registrar = registrar
|
||||
self.plugin = plugin
|
||||
super.init()
|
||||
self.job = job
|
||||
self.settings = settings
|
||||
self.printFormatter = job?.printFormatter
|
||||
self.printPageRenderer = job?.printPageRenderer
|
||||
self.job?.delegate = self
|
||||
let channel = FlutterMethodChannel(name: PrintJobController.METHOD_CHANNEL_NAME_PREFIX + id,
|
||||
binaryMessenger: registrar.messenger())
|
||||
self.channelDelegate = PrintJobChannelDelegate(printJobController: self, channel: channel)
|
||||
if let registrar = plugin.registrar {
|
||||
let channel = FlutterMethodChannel(name: PrintJobController.METHOD_CHANNEL_NAME_PREFIX + id,
|
||||
binaryMessenger: registrar.messenger())
|
||||
self.channelDelegate = PrintJobChannelDelegate(printJobController: self, channel: channel)
|
||||
}
|
||||
}
|
||||
|
||||
public func printInteractionControllerWillStartJob(_ printInteractionController: UIPrintInteractionController) {
|
||||
|
@ -82,7 +84,8 @@ public class PrintJobController : NSObject, Disposable, UIPrintInteractionContro
|
|||
printPageRenderer = nil
|
||||
job?.delegate = nil
|
||||
job = nil
|
||||
PrintJobManager.jobs[id] = nil
|
||||
plugin?.printJobManager?.jobs[id] = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
public func dispose() {
|
||||
|
@ -93,7 +96,7 @@ public class PrintJobController : NSObject, Disposable, UIPrintInteractionContro
|
|||
job?.delegate = nil
|
||||
job?.dismiss(animated: false)
|
||||
job = nil
|
||||
PrintJobManager.jobs[id] = nil
|
||||
registrar = nil
|
||||
plugin?.printJobManager?.jobs[id] = nil
|
||||
plugin = nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,18 +8,21 @@
|
|||
import Foundation
|
||||
|
||||
public class PrintJobManager: NSObject, Disposable {
|
||||
static var jobs: [String: PrintJobController?] = [:]
|
||||
var plugin: SwiftFlutterPlugin?
|
||||
var jobs: [String: PrintJobController?] = [:]
|
||||
|
||||
public override init() {
|
||||
public init(plugin: SwiftFlutterPlugin?) {
|
||||
super.init()
|
||||
self.plugin = plugin
|
||||
}
|
||||
|
||||
public func dispose() {
|
||||
let jobs = PrintJobManager.jobs.values
|
||||
jobs.forEach { (job: PrintJobController?) in
|
||||
let jobValues = jobs.values
|
||||
jobValues.forEach { (job: PrintJobController?) in
|
||||
job?.dispose()
|
||||
}
|
||||
PrintJobManager.jobs.removeAll()
|
||||
jobs.removeAll()
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -10,17 +10,21 @@ import Flutter
|
|||
|
||||
public class PullToRefreshControl : UIRefreshControl, Disposable {
|
||||
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_";
|
||||
var plugin: SwiftFlutterPlugin?
|
||||
var channelDelegate: PullToRefreshChannelDelegate?
|
||||
var settings: PullToRefreshSettings?
|
||||
var shouldCallOnRefresh = false
|
||||
var delegate: PullToRefreshDelegate?
|
||||
|
||||
public init(registrar: FlutterPluginRegistrar, id: Any, settings: PullToRefreshSettings?) {
|
||||
public init(plugin: SwiftFlutterPlugin, id: Any, settings: PullToRefreshSettings?) {
|
||||
super.init()
|
||||
self.plugin = plugin
|
||||
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)
|
||||
if let registrar = plugin.registrar {
|
||||
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) {
|
||||
|
@ -59,6 +63,7 @@ public class PullToRefreshControl : UIRefreshControl, Disposable {
|
|||
channelDelegate = nil
|
||||
removeTarget(self, action: #selector(updateShouldCallOnRefresh), for: .valueChanged)
|
||||
delegate = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -15,9 +15,8 @@ import SafariServices
|
|||
public class ChromeSafariBrowserManager: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_chromesafaribrowser"
|
||||
var plugin: SwiftFlutterPlugin?
|
||||
static var browsers: [String: SafariViewController?] = [:]
|
||||
@available(iOS 15.0, *)
|
||||
static var prewarmingTokens: [String: SFSafariViewController.PrewarmingToken?] = [:]
|
||||
var browsers: [String: SafariViewController?] = [:]
|
||||
var prewarmingTokens: [String: Any?] = [:]
|
||||
|
||||
init(plugin: SwiftFlutterPlugin) {
|
||||
super.init(channel: FlutterMethodChannel(name: ChromeSafariBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger()))
|
||||
|
@ -61,7 +60,7 @@ public class ChromeSafariBrowserManager: ChannelDelegate {
|
|||
}
|
||||
let prewarmingToken = SFSafariViewController.prewarmConnections(to: URLs)
|
||||
let prewarmingTokenId = NSUUID().uuidString
|
||||
ChromeSafariBrowserManager.prewarmingTokens[prewarmingTokenId] = prewarmingToken
|
||||
prewarmingTokens[prewarmingTokenId] = prewarmingToken
|
||||
result([
|
||||
"id": prewarmingTokenId
|
||||
])
|
||||
|
@ -72,9 +71,9 @@ public class ChromeSafariBrowserManager: ChannelDelegate {
|
|||
if #available(iOS 15.0, *) {
|
||||
let prewarmingToken = arguments!["prewarmingToken"] as! [String:Any?]
|
||||
if let prewarmingTokenId = prewarmingToken["id"] as? String,
|
||||
let prewarmingToken = ChromeSafariBrowserManager.prewarmingTokens[prewarmingTokenId] {
|
||||
let prewarmingToken = prewarmingTokens[prewarmingTokenId] as? SFSafariViewController.PrewarmingToken? {
|
||||
prewarmingToken?.invalidate()
|
||||
ChromeSafariBrowserManager.prewarmingTokens[prewarmingTokenId] = nil
|
||||
prewarmingTokens[prewarmingTokenId] = nil
|
||||
}
|
||||
result(true)
|
||||
} else {
|
||||
|
@ -115,7 +114,7 @@ public class ChromeSafariBrowserManager: ChannelDelegate {
|
|||
result(true)
|
||||
}
|
||||
|
||||
ChromeSafariBrowserManager.browsers[id] = safari
|
||||
browsers[id] = safari
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -125,17 +124,20 @@ public class ChromeSafariBrowserManager: ChannelDelegate {
|
|||
|
||||
public override func dispose() {
|
||||
super.dispose()
|
||||
let browsers = ChromeSafariBrowserManager.browsers.values
|
||||
browsers.forEach { (browser: SafariViewController?) in
|
||||
let browserValues = browsers.values
|
||||
browserValues.forEach { (browser: SafariViewController?) in
|
||||
browser?.close(result: nil)
|
||||
browser?.dispose()
|
||||
}
|
||||
ChromeSafariBrowserManager.browsers.removeAll()
|
||||
browsers.removeAll()
|
||||
if #available(iOS 15.0, *) {
|
||||
ChromeSafariBrowserManager.prewarmingTokens.values.forEach { (prewarmingToken: SFSafariViewController.PrewarmingToken?) in
|
||||
prewarmingToken?.invalidate()
|
||||
let prewarmingTokensValues = prewarmingTokens.values
|
||||
prewarmingTokensValues.forEach { (prewarmingToken: Any?) in
|
||||
if let prewarmingToken = prewarmingToken as? SFSafariViewController.PrewarmingToken? {
|
||||
prewarmingToken?.invalidate()
|
||||
}
|
||||
}
|
||||
ChromeSafariBrowserManager.prewarmingTokens.removeAll()
|
||||
prewarmingTokens.removeAll()
|
||||
}
|
||||
plugin = nil
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import Foundation
|
||||
|
||||
class CustomUIActivity : UIActivity {
|
||||
var plugin: SwiftFlutterPlugin
|
||||
var viewId: String
|
||||
var id: Int64
|
||||
var url: URL
|
||||
|
@ -16,7 +17,8 @@ class CustomUIActivity : UIActivity {
|
|||
var label: String?
|
||||
var image: UIImage?
|
||||
|
||||
init(viewId: String, id: Int64, url: URL, title: String?, label: String?, type: UIActivity.ActivityType?, image: UIImage?) {
|
||||
init(plugin: SwiftFlutterPlugin, viewId: String, id: Int64, url: URL, title: String?, label: String?, type: UIActivity.ActivityType?, image: UIImage?) {
|
||||
self.plugin = plugin
|
||||
self.viewId = viewId
|
||||
self.id = id
|
||||
self.url = url
|
||||
|
@ -47,7 +49,7 @@ class CustomUIActivity : UIActivity {
|
|||
}
|
||||
|
||||
override func perform() {
|
||||
let browser = ChromeSafariBrowserManager.browsers[viewId]
|
||||
let browser = plugin.chromeSafariBrowserManager?.browsers[viewId]
|
||||
browser??.channelDelegate?.onItemActionPerform(id: id, url: url, title: title)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,9 +105,14 @@ public class SafariViewController: SFSafariViewController, SFSafariViewControlle
|
|||
}
|
||||
|
||||
public func safariViewController(_ controller: SFSafariViewController, activityItemsFor URL: URL, title: String?) -> [UIActivity] {
|
||||
guard let plugin = plugin else {
|
||||
return []
|
||||
}
|
||||
var uiActivities: [UIActivity] = []
|
||||
menuItemList.forEach { (menuItem) in
|
||||
let activity = CustomUIActivity(viewId: id, id: menuItem["id"] as! Int64, url: URL, title: title, label: menuItem["label"] as? String, type: nil, image: .fromMap(map: menuItem["image"] as? [String:Any?]))
|
||||
let activity = CustomUIActivity(plugin: plugin, viewId: id, id: menuItem["id"] as! Int64, url: URL,
|
||||
title: title, label: menuItem["label"] as? String, type: nil,
|
||||
image: .fromMap(map: menuItem["image"] as? [String:Any?]))
|
||||
uiActivities.append(activity)
|
||||
}
|
||||
return uiActivities
|
||||
|
@ -125,7 +130,7 @@ public class SafariViewController: SFSafariViewController, SFSafariViewControlle
|
|||
channelDelegate?.dispose()
|
||||
channelDelegate = nil
|
||||
delegate = nil
|
||||
ChromeSafariBrowserManager.browsers[id] = nil
|
||||
plugin?.chromeSafariBrowserManager?.browsers[id] = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
|||
|
||||
var registrar: FlutterPluginRegistrar?
|
||||
var platformUtil: PlatformUtil?
|
||||
var inAppWebViewStatic: InAppWebViewStatic?
|
||||
var inAppWebViewManager: InAppWebViewManager?
|
||||
var myCookieManager: Any?
|
||||
var myWebStorageManager: Any?
|
||||
var credentialDatabase: CredentialDatabase?
|
||||
|
@ -43,13 +43,13 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
|||
super.init()
|
||||
|
||||
self.registrar = registrar
|
||||
registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: FlutterWebViewFactory.VIEW_TYPE_ID)
|
||||
registrar.register(FlutterWebViewFactory(plugin: self) as FlutterPlatformViewFactory, withId: FlutterWebViewFactory.VIEW_TYPE_ID)
|
||||
|
||||
platformUtil = PlatformUtil(plugin: self)
|
||||
inAppBrowserManager = InAppBrowserManager(plugin: self)
|
||||
headlessInAppWebViewManager = HeadlessInAppWebViewManager(plugin: self)
|
||||
chromeSafariBrowserManager = ChromeSafariBrowserManager(plugin: self)
|
||||
inAppWebViewStatic = InAppWebViewStatic(plugin: self)
|
||||
inAppWebViewManager = InAppWebViewManager(plugin: self)
|
||||
credentialDatabase = CredentialDatabase(plugin: self)
|
||||
if #available(iOS 11.0, *) {
|
||||
myCookieManager = MyCookieManager(plugin: self)
|
||||
|
@ -58,7 +58,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
|||
myWebStorageManager = MyWebStorageManager(plugin: self)
|
||||
}
|
||||
webAuthenticationSessionManager = WebAuthenticationSessionManager(plugin: self)
|
||||
printJobManager = PrintJobManager()
|
||||
printJobManager = PrintJobManager(plugin: self)
|
||||
}
|
||||
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
|
@ -74,8 +74,8 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
|
|||
headlessInAppWebViewManager = nil
|
||||
chromeSafariBrowserManager?.dispose()
|
||||
chromeSafariBrowserManager = nil
|
||||
inAppWebViewStatic?.dispose()
|
||||
inAppWebViewStatic = nil
|
||||
inAppWebViewManager?.dispose()
|
||||
inAppWebViewManager = nil
|
||||
credentialDatabase?.dispose()
|
||||
credentialDatabase = nil
|
||||
if #available(iOS 11.0, *) {
|
||||
|
|
|
@ -11,17 +11,17 @@ import WebKit
|
|||
var SharedLastTouchPointTimestamp: [InAppWebView: Int64] = [:]
|
||||
|
||||
public class Util {
|
||||
public static func getUrlAsset(registrar: FlutterPluginRegistrar, assetFilePath: String) throws -> URL {
|
||||
let key = registrar.lookupKey(forAsset: assetFilePath)
|
||||
guard let assetURL = Bundle.main.url(forResource: key, withExtension: nil) else {
|
||||
public static func getUrlAsset(plugin: SwiftFlutterPlugin, assetFilePath: String) throws -> URL {
|
||||
guard let key = plugin.registrar?.lookupKey(forAsset: assetFilePath),
|
||||
let assetURL = Bundle.main.url(forResource: key, withExtension: nil) else {
|
||||
throw NSError(domain: assetFilePath + " asset file cannot be found!", code: 0)
|
||||
}
|
||||
return assetURL
|
||||
}
|
||||
|
||||
public static func getAbsPathAsset(registrar: FlutterPluginRegistrar, assetFilePath: String) throws -> String {
|
||||
let key = registrar.lookupKey(forAsset: assetFilePath)
|
||||
guard let assetAbsPath = Bundle.main.path(forResource: key, ofType: nil) else {
|
||||
public static func getAbsPathAsset(plugin: SwiftFlutterPlugin, assetFilePath: String) throws -> String {
|
||||
guard let key = plugin.registrar?.lookupKey(forAsset: assetFilePath),
|
||||
let assetAbsPath = Bundle.main.path(forResource: key, ofType: nil) else {
|
||||
throw NSError(domain: assetFilePath + " asset file cannot be found!", code: 0)
|
||||
}
|
||||
return assetAbsPath
|
||||
|
|
|
@ -98,7 +98,7 @@ public class WebAuthenticationSession : NSObject, ASWebAuthenticationPresentatio
|
|||
channelDelegate?.dispose()
|
||||
channelDelegate = nil
|
||||
session = nil
|
||||
WebAuthenticationSessionManager.sessions[id] = nil
|
||||
plugin?.webAuthenticationSessionManager?.sessions[id] = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import SafariServices
|
|||
public class WebAuthenticationSessionManager: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_webauthenticationsession"
|
||||
var plugin: SwiftFlutterPlugin?
|
||||
static var sessions: [String: WebAuthenticationSession?] = [:]
|
||||
var sessions: [String: WebAuthenticationSession?] = [:]
|
||||
|
||||
init(plugin: SwiftFlutterPlugin) {
|
||||
super.init(channel: FlutterMethodChannel(name: WebAuthenticationSessionManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger()))
|
||||
|
@ -53,7 +53,7 @@ public class WebAuthenticationSessionManager: ChannelDelegate {
|
|||
let _ = initialSettings.parse(settings: settings)
|
||||
let session = WebAuthenticationSession(plugin: plugin, id: id, url: sessionUrl, callbackURLScheme: callbackURLScheme, settings: initialSettings)
|
||||
session.prepare()
|
||||
WebAuthenticationSessionManager.sessions[id] = session
|
||||
sessions[id] = session
|
||||
result(true)
|
||||
return
|
||||
}
|
||||
|
@ -63,12 +63,12 @@ public class WebAuthenticationSessionManager: ChannelDelegate {
|
|||
|
||||
public override func dispose() {
|
||||
super.dispose()
|
||||
let sessions = WebAuthenticationSessionManager.sessions.values
|
||||
sessions.forEach { (session: WebAuthenticationSession?) in
|
||||
let sessionValues = sessions.values
|
||||
sessionValues.forEach { (session: WebAuthenticationSession?) in
|
||||
session?.cancel()
|
||||
session?.dispose()
|
||||
}
|
||||
WebAuthenticationSessionManager.sessions.removeAll()
|
||||
sessions.removeAll()
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export 'service_worker_controller.dart';
|
||||
export 'webview_feature.dart' show WebViewFeature, AndroidWebViewFeature;
|
||||
export 'proxy_controller.dart';
|
||||
export 'proxy_controller.dart' show ProxyController, ProxySettings;
|
||||
export 'webview_asset_loader.dart'
|
||||
show
|
||||
WebViewAssetLoader,
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import 'dart:async';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart';
|
||||
import '../types/proxy_rule.dart';
|
||||
import 'webview_feature.dart';
|
||||
import '../in_app_webview/webview.dart';
|
||||
import '../types/main.dart';
|
||||
|
||||
part 'proxy_controller.g.dart';
|
||||
|
||||
///Manages setting and clearing a process-specific override for the Android system-wide proxy settings that govern network requests made by [WebView].
|
||||
///
|
||||
///[WebView] may make network requests in order to fetch content that is not otherwise read from the file system or provided directly by application code.
|
||||
|
@ -78,7 +82,8 @@ class ProxyController {
|
|||
///
|
||||
///**Supported Platforms/Implementations**:
|
||||
///- Android native WebView ([Official API - ProxyConfig](https://developer.android.com/reference/androidx/webkit/ProxyConfig))
|
||||
class ProxySettings {
|
||||
@ExchangeableObject(copyMethod: true)
|
||||
class ProxySettings_ {
|
||||
///List of bypass rules.
|
||||
///
|
||||
///A bypass rule describes URLs that should skip proxy override settings and make a direct connection instead. These can be URLs or IP addresses. Wildcards are accepted.
|
||||
|
@ -99,7 +104,7 @@ class ProxySettings {
|
|||
///Port number is optional and defaults to `80` for `HTTP`, `443` for `HTTPS` and `1080` for `SOCKS`.
|
||||
///
|
||||
///The correct syntax for hosts is defined by [RFC 3986](https://tools.ietf.org/html/rfc3986#section-3.2.2).
|
||||
List<ProxyRule> proxyRules;
|
||||
List<ProxyRule_> proxyRules;
|
||||
|
||||
///Hostnames without a period in them (and that are not IP literals) will skip proxy settings and be connected to directly instead. Examples: `"abc"`, `"local"`, `"some-domain"`.
|
||||
///
|
||||
|
@ -128,7 +133,7 @@ class ProxySettings {
|
|||
///**NOTE**: available only if [WebViewFeature.PROXY_OVERRIDE_REVERSE_BYPASS] feature is supported.
|
||||
bool reverseBypassEnabled;
|
||||
|
||||
ProxySettings(
|
||||
ProxySettings_(
|
||||
{this.bypassRules = const [],
|
||||
this.directs = const [],
|
||||
this.proxyRules = const [],
|
||||
|
@ -136,40 +141,40 @@ class ProxySettings {
|
|||
this.removeImplicitRules,
|
||||
this.reverseBypassEnabled = false});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"bypassRules": bypassRules,
|
||||
"directs": directs,
|
||||
"proxyRules": proxyRules.map((e) => e.toMap()).toList(),
|
||||
"bypassSimpleHostnames": bypassSimpleHostnames,
|
||||
"removeImplicitRules": removeImplicitRules,
|
||||
"reverseBypassEnabled": reverseBypassEnabled
|
||||
};
|
||||
}
|
||||
|
||||
static ProxySettings fromMap(Map<String, dynamic> map) {
|
||||
var settings = ProxySettings();
|
||||
settings.bypassRules = map["bypassRules"];
|
||||
settings.directs = map["directs"];
|
||||
settings.proxyRules = (map["proxyRules"].cast<Map<String, dynamic>>()
|
||||
as List<Map<String, dynamic>>)
|
||||
.map((e) => ProxyRule.fromMap(e)) as List<ProxyRule>;
|
||||
settings.bypassSimpleHostnames = map["bypassSimpleHostnames"];
|
||||
settings.removeImplicitRules = map["removeImplicitRules"];
|
||||
settings.reverseBypassEnabled = map["reverseBypassEnabled"];
|
||||
return settings;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return this.toMap();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
|
||||
ProxySettings copy() {
|
||||
return ProxySettings.fromMap(this.toMap());
|
||||
}
|
||||
// Map<String, dynamic> toMap() {
|
||||
// return {
|
||||
// "bypassRules": bypassRules,
|
||||
// "directs": directs,
|
||||
// "proxyRules": proxyRules.map((e) => e.toMap()).toList(),
|
||||
// "bypassSimpleHostnames": bypassSimpleHostnames,
|
||||
// "removeImplicitRules": removeImplicitRules,
|
||||
// "reverseBypassEnabled": reverseBypassEnabled
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// static ProxySettings fromMap(Map<String, dynamic> map) {
|
||||
// var settings = ProxySettings();
|
||||
// settings.bypassRules = map["bypassRules"];
|
||||
// settings.directs = map["directs"];
|
||||
// settings.proxyRules = (map["proxyRules"].cast<Map<String, dynamic>>()
|
||||
// as List<Map<String, dynamic>>)
|
||||
// .map((e) => ProxyRule.fromMap(e)) as List<ProxyRule>;
|
||||
// settings.bypassSimpleHostnames = map["bypassSimpleHostnames"];
|
||||
// settings.removeImplicitRules = map["removeImplicitRules"];
|
||||
// settings.reverseBypassEnabled = map["reverseBypassEnabled"];
|
||||
// return settings;
|
||||
// }
|
||||
//
|
||||
// Map<String, dynamic> toJson() {
|
||||
// return this.toMap();
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// String toString() {
|
||||
// return 'ProxySettings{bypassRules: $bypassRules, directs: $directs, proxyRules: $proxyRules, bypassSimpleHostnames: $bypassSimpleHostnames, removeImplicitRules: $removeImplicitRules, reverseBypassEnabled: $reverseBypassEnabled}';
|
||||
// }
|
||||
//
|
||||
// ProxySettings copy() {
|
||||
// return ProxySettings.fromMap(this.toMap());
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'proxy_controller.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// ExchangeableObjectGenerator
|
||||
// **************************************************************************
|
||||
|
||||
///Class that represents the settings used to configure the [ProxyController].
|
||||
///
|
||||
///**Supported Platforms/Implementations**:
|
||||
///- Android native WebView ([Official API - ProxyConfig](https://developer.android.com/reference/androidx/webkit/ProxyConfig))
|
||||
class ProxySettings {
|
||||
///List of bypass rules.
|
||||
///
|
||||
///A bypass rule describes URLs that should skip proxy override settings and make a direct connection instead. These can be URLs or IP addresses. Wildcards are accepted.
|
||||
///For instance, the rule "*example.com" would mean that requests to "http://example.com" and "www.example.com" would not be directed to any proxy,
|
||||
///instead, would be made directly to the origin specified by the URL.
|
||||
List<String> bypassRules;
|
||||
|
||||
///Hostnames without a period in them (and that are not IP literals) will skip proxy settings and be connected to directly instead. Examples: `"abc"`, `"local"`, `"some-domain"`.
|
||||
///
|
||||
///Hostnames with a trailing dot are not considered simple by this definition.
|
||||
bool? bypassSimpleHostnames;
|
||||
|
||||
///List of scheme filters.
|
||||
///
|
||||
///URLs that match these scheme filters are connected to directly instead of using a proxy server.
|
||||
List<String> directs;
|
||||
|
||||
///List of proxy rules to be used for all URLs. This method can be called multiple times to add multiple rules. Additional rules have decreasing precedence.
|
||||
///
|
||||
///Proxy is a string in the format `[scheme://]host[:port]`.
|
||||
///Scheme is optional, if present must be `HTTP`, `HTTPS` or [SOCKS](https://tools.ietf.org/html/rfc1928) and defaults to `HTTP`.
|
||||
///Host is one of an IPv6 literal with brackets, an IPv4 literal or one or more labels separated by a period.
|
||||
///Port number is optional and defaults to `80` for `HTTP`, `443` for `HTTPS` and `1080` for `SOCKS`.
|
||||
///
|
||||
///The correct syntax for hosts is defined by [RFC 3986](https://tools.ietf.org/html/rfc3986#section-3.2.2).
|
||||
List<ProxyRule> proxyRules;
|
||||
|
||||
///By default, certain hostnames implicitly bypass the proxy if they are link-local IPs, or localhost addresses.
|
||||
///For instance hostnames matching any of (non-exhaustive list):
|
||||
///- localhost
|
||||
///- *.localhost
|
||||
///- [::1]
|
||||
///- 127.0.0.1/8
|
||||
///- 169.254/16
|
||||
///- [FE80::]/10
|
||||
///Set this to `true` to override the default behavior and force localhost and link-local URLs to be sent through the proxy.
|
||||
bool? removeImplicitRules;
|
||||
|
||||
///Reverse the bypass list.
|
||||
///
|
||||
///The default value is `false`, in which case all URLs will use proxy settings except the ones in the bypass list, which will be connected to directly instead.
|
||||
///
|
||||
///If set to `true`, then only URLs in the bypass list will use these proxy settings, and all other URLs will be connected to directly.
|
||||
///
|
||||
///Use [bypassRules] to add bypass rules.
|
||||
///
|
||||
///**NOTE**: available only if [WebViewFeature.PROXY_OVERRIDE_REVERSE_BYPASS] feature is supported.
|
||||
bool reverseBypassEnabled;
|
||||
ProxySettings(
|
||||
{this.bypassRules = const [],
|
||||
this.bypassSimpleHostnames,
|
||||
this.directs = const [],
|
||||
this.proxyRules = const [],
|
||||
this.removeImplicitRules,
|
||||
this.reverseBypassEnabled = false});
|
||||
|
||||
///Gets a possible [ProxySettings] instance from a [Map] value.
|
||||
static ProxySettings? fromMap(Map<String, dynamic>? map) {
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
final instance = ProxySettings(
|
||||
bypassSimpleHostnames: map['bypassSimpleHostnames'],
|
||||
removeImplicitRules: map['removeImplicitRules'],
|
||||
);
|
||||
instance.bypassRules =
|
||||
List<String>.from(map['bypassRules']!.cast<String>());
|
||||
instance.directs = List<String>.from(map['directs']!.cast<String>());
|
||||
instance.proxyRules = List<ProxyRule>.from(map['proxyRules']
|
||||
.map((e) => ProxyRule.fromMap(e?.cast<String, dynamic>())!));
|
||||
instance.reverseBypassEnabled = map['reverseBypassEnabled'];
|
||||
return instance;
|
||||
}
|
||||
|
||||
///Converts instance to a map.
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"bypassRules": bypassRules,
|
||||
"bypassSimpleHostnames": bypassSimpleHostnames,
|
||||
"directs": directs,
|
||||
"proxyRules": proxyRules.map((e) => e.toMap()).toList(),
|
||||
"removeImplicitRules": removeImplicitRules,
|
||||
"reverseBypassEnabled": reverseBypassEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
///Converts instance to a map.
|
||||
Map<String, dynamic> toJson() {
|
||||
return toMap();
|
||||
}
|
||||
|
||||
///Returns a copy of ProxySettings.
|
||||
ProxySettings copy() {
|
||||
return ProxySettings.fromMap(toMap()) ?? ProxySettings();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxySettings{bypassRules: $bypassRules, bypassSimpleHostnames: $bypassSimpleHostnames, directs: $directs, proxyRules: $proxyRules, removeImplicitRules: $removeImplicitRules, reverseBypassEnabled: $reverseBypassEnabled}';
|
||||
}
|
||||
}
|
|
@ -15,30 +15,6 @@ import '../debug_logging_settings.dart';
|
|||
import '../web_uri.dart';
|
||||
import 'chrome_safari_browser_settings.dart';
|
||||
|
||||
class ChromeSafariBrowserAlreadyOpenedException implements Exception {
|
||||
final dynamic message;
|
||||
|
||||
ChromeSafariBrowserAlreadyOpenedException([this.message]);
|
||||
|
||||
String toString() {
|
||||
Object? message = this.message;
|
||||
if (message == null) return "ChromeSafariBrowserAlreadyOpenedException";
|
||||
return "ChromeSafariBrowserAlreadyOpenedException: $message";
|
||||
}
|
||||
}
|
||||
|
||||
class ChromeSafariBrowserNotOpenedException implements Exception {
|
||||
final dynamic message;
|
||||
|
||||
ChromeSafariBrowserNotOpenedException([this.message]);
|
||||
|
||||
String toString() {
|
||||
Object? message = this.message;
|
||||
if (message == null) return "ChromeSafariBrowserNotOpenedException";
|
||||
return "ChromeSafariBrowserNotOpenedException: $message";
|
||||
}
|
||||
}
|
||||
|
||||
///This class uses native [Chrome Custom Tabs](https://developer.android.com/reference/android/support/customtabs/package-summary) on Android
|
||||
///and [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS.
|
||||
///
|
||||
|
@ -60,7 +36,7 @@ class ChromeSafariBrowser {
|
|||
Map<int, ChromeSafariBrowserMenuItem> _menuItems = new HashMap();
|
||||
ChromeSafariBrowserSecondaryToolbar? _secondaryToolbar;
|
||||
bool _isOpened = false;
|
||||
late MethodChannel _channel;
|
||||
MethodChannel? _channel;
|
||||
static const MethodChannel _sharedChannel =
|
||||
const MethodChannel('com.pichillilorenzo/flutter_chromesafaribrowser');
|
||||
|
||||
|
@ -68,7 +44,7 @@ class ChromeSafariBrowser {
|
|||
id = IdGenerator.generate();
|
||||
this._channel =
|
||||
MethodChannel('com.pichillilorenzo/flutter_chromesafaribrowser_$id');
|
||||
this._channel.setMethodCallHandler((call) async {
|
||||
this._channel?.setMethodCallHandler((call) async {
|
||||
try {
|
||||
return await _handleMethod(call);
|
||||
} on Error catch (e) {
|
||||
|
@ -79,6 +55,19 @@ class ChromeSafariBrowser {
|
|||
_isOpened = false;
|
||||
}
|
||||
|
||||
_init() {
|
||||
this._channel =
|
||||
MethodChannel('com.pichillilorenzo/flutter_chromesafaribrowser_$id');
|
||||
this._channel?.setMethodCallHandler((call) async {
|
||||
try {
|
||||
return await _handleMethod(call);
|
||||
} on Error catch (e) {
|
||||
print(e);
|
||||
print(e.stackTrace);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_debugLog(String method, dynamic args) {
|
||||
debugLog(
|
||||
className: this.runtimeType.toString(),
|
||||
|
@ -125,8 +114,9 @@ class ChromeSafariBrowser {
|
|||
onWillOpenInBrowser();
|
||||
break;
|
||||
case "onClosed":
|
||||
_isOpened = false;
|
||||
_dispose();
|
||||
onClosed();
|
||||
this._isOpened = false;
|
||||
break;
|
||||
case "onItemActionPerform":
|
||||
String url = call.arguments["url"];
|
||||
|
@ -208,6 +198,9 @@ class ChromeSafariBrowser {
|
|||
// ignore: deprecated_member_use_from_same_package
|
||||
ChromeSafariBrowserClassOptions? options,
|
||||
ChromeSafariBrowserSettings? settings}) async {
|
||||
assert(!_isOpened, 'The browser is already opened.');
|
||||
_isOpened = true;
|
||||
|
||||
if (Util.isIOS) {
|
||||
assert(url != null, 'The specified URL must not be null on iOS.');
|
||||
assert(['http', 'https'].contains(url!.scheme),
|
||||
|
@ -216,9 +209,8 @@ class ChromeSafariBrowser {
|
|||
if (url != null) {
|
||||
assert(url.toString().isNotEmpty, 'The specified URL must not be empty.');
|
||||
}
|
||||
this.throwIsAlreadyOpened(message: url != null ? 'Cannot open $url!' : '');
|
||||
|
||||
this._isOpened = true;
|
||||
_init();
|
||||
|
||||
List<Map<String, dynamic>> menuItemList = [];
|
||||
_menuItems.forEach((key, value) {
|
||||
|
@ -269,7 +261,7 @@ class ChromeSafariBrowser {
|
|||
args.putIfAbsent('otherLikelyURLs',
|
||||
() => otherLikelyURLs?.map((e) => e.toString()).toList());
|
||||
args.putIfAbsent('referrer', () => referrer?.toString());
|
||||
await _channel.invokeMethod("launchUrl", args);
|
||||
await _channel?.invokeMethod("launchUrl", args);
|
||||
}
|
||||
|
||||
///Tells the browser of a likely future navigation to a URL.
|
||||
|
@ -290,7 +282,7 @@ class ChromeSafariBrowser {
|
|||
args.putIfAbsent('url', () => url?.toString());
|
||||
args.putIfAbsent('otherLikelyURLs',
|
||||
() => otherLikelyURLs?.map((e) => e.toString()).toList());
|
||||
return await _channel.invokeMethod("mayLaunchUrl", args);
|
||||
return await _channel?.invokeMethod("mayLaunchUrl", args);
|
||||
}
|
||||
|
||||
///Requests to validate a relationship between the application and an origin.
|
||||
|
@ -315,7 +307,7 @@ class ChromeSafariBrowser {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('relation', () => relation.toNativeValue());
|
||||
args.putIfAbsent('origin', () => origin.toString());
|
||||
return await _channel.invokeMethod("validateRelationship", args);
|
||||
return await _channel?.invokeMethod("validateRelationship", args);
|
||||
}
|
||||
|
||||
///Closes the [ChromeSafariBrowser] instance.
|
||||
|
@ -325,7 +317,7 @@ class ChromeSafariBrowser {
|
|||
///- iOS
|
||||
Future<void> close() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod("close", args);
|
||||
await _channel?.invokeMethod("close", args);
|
||||
}
|
||||
|
||||
///Set a custom action button.
|
||||
|
@ -349,7 +341,7 @@ class ChromeSafariBrowser {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('icon', () => icon);
|
||||
args.putIfAbsent('description', () => description);
|
||||
await _channel.invokeMethod("updateActionButton", args);
|
||||
await _channel?.invokeMethod("updateActionButton", args);
|
||||
_actionButton?.icon = icon;
|
||||
_actionButton?.description = description;
|
||||
}
|
||||
|
@ -375,7 +367,7 @@ class ChromeSafariBrowser {
|
|||
ChromeSafariBrowserSecondaryToolbar secondaryToolbar) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('secondaryToolbar', () => secondaryToolbar.toMap());
|
||||
await _channel.invokeMethod("updateSecondaryToolbar", args);
|
||||
await _channel?.invokeMethod("updateSecondaryToolbar", args);
|
||||
this._secondaryToolbar = secondaryToolbar;
|
||||
}
|
||||
|
||||
|
@ -546,23 +538,13 @@ class ChromeSafariBrowser {
|
|||
///- Android
|
||||
///- iOS
|
||||
bool isOpened() {
|
||||
return this._isOpened;
|
||||
return _isOpened;
|
||||
}
|
||||
|
||||
void throwIsAlreadyOpened({String message = ''}) {
|
||||
if (this.isOpened()) {
|
||||
throw ChromeSafariBrowserAlreadyOpenedException([
|
||||
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is already opened.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
void throwIsNotOpened({String message = ''}) {
|
||||
if (!this.isOpened()) {
|
||||
throw ChromeSafariBrowserNotOpenedException([
|
||||
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is not opened.'
|
||||
]);
|
||||
}
|
||||
///Disposes the channel.
|
||||
void _dispose() {
|
||||
_channel?.setMethodCallHandler(null);
|
||||
_channel = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -275,7 +275,7 @@ class CookieManager {
|
|||
await pageLoaded.future;
|
||||
|
||||
List<String> documentCookies = (await headlessWebView.webViewController
|
||||
.evaluateJavascript(source: 'document.cookie') as String)
|
||||
!.evaluateJavascript(source: 'document.cookie') as String)
|
||||
.split(';')
|
||||
.map((documentCookie) => documentCookie.trim())
|
||||
.toList();
|
||||
|
|
|
@ -37,20 +37,6 @@ class FindInteractionController {
|
|||
|
||||
FindInteractionController({this.onFindResultReceived}) {}
|
||||
|
||||
void initMethodChannel(dynamic id) {
|
||||
this._channel = MethodChannel(
|
||||
'com.pichillilorenzo/flutter_inappwebview_find_interaction_$id');
|
||||
|
||||
this._channel?.setMethodCallHandler((call) async {
|
||||
try {
|
||||
return await _handleMethod(call);
|
||||
} on Error catch (e) {
|
||||
print(e);
|
||||
print(e.stackTrace);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_debugLog(String method, dynamic args) {
|
||||
debugLog(
|
||||
className: this.runtimeType.toString(),
|
||||
|
@ -217,4 +203,29 @@ class FindInteractionController {
|
|||
?.cast<String, dynamic>();
|
||||
return FindSession.fromMap(result);
|
||||
}
|
||||
|
||||
///Disposes the controller.
|
||||
void dispose({bool isKeepAlive = false}) {
|
||||
if (!isKeepAlive) {
|
||||
_channel?.setMethodCallHandler(null);
|
||||
}
|
||||
_channel = null;
|
||||
}
|
||||
}
|
||||
|
||||
extension InternalFindInteractionController on FindInteractionController {
|
||||
void init(dynamic id) {
|
||||
this._channel = MethodChannel(
|
||||
'com.pichillilorenzo/flutter_inappwebview_find_interaction_$id');
|
||||
|
||||
this._channel?.setMethodCallHandler((call) async {
|
||||
if (_channel == null) return null;
|
||||
try {
|
||||
return await _handleMethod(call);
|
||||
} on Error catch (e) {
|
||||
print(e);
|
||||
print(e.stackTrace);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
export 'find_interaction_controller.dart';
|
||||
export 'find_interaction_controller.dart' show FindInteractionController;
|
||||
|
|
|
@ -18,30 +18,7 @@ import '../print_job/main.dart';
|
|||
import '../web_uri.dart';
|
||||
import 'in_app_browser_settings.dart';
|
||||
import '../debug_logging_settings.dart';
|
||||
|
||||
class InAppBrowserAlreadyOpenedException implements Exception {
|
||||
final dynamic message;
|
||||
|
||||
InAppBrowserAlreadyOpenedException([this.message]);
|
||||
|
||||
String toString() {
|
||||
Object? message = this.message;
|
||||
if (message == null) return "InAppBrowserAlreadyOpenedException";
|
||||
return "InAppBrowserAlreadyOpenedException: $message";
|
||||
}
|
||||
}
|
||||
|
||||
class InAppBrowserNotOpenedException implements Exception {
|
||||
final dynamic message;
|
||||
|
||||
InAppBrowserNotOpenedException([this.message]);
|
||||
|
||||
String toString() {
|
||||
Object? message = this.message;
|
||||
if (message == null) return "InAppBrowserNotOpenedException";
|
||||
return "InAppBrowserNotOpenedException: $message";
|
||||
}
|
||||
}
|
||||
import '../pull_to_refresh/pull_to_refresh_controller.dart';
|
||||
|
||||
///This class uses the native WebView of the platform.
|
||||
///The [webViewController] field can be used to access the [InAppWebViewController] API.
|
||||
|
@ -70,11 +47,11 @@ class InAppBrowser {
|
|||
final UnmodifiableListView<UserScript>? initialUserScripts;
|
||||
|
||||
bool _isOpened = false;
|
||||
late MethodChannel _channel;
|
||||
MethodChannel? _channel;
|
||||
static const MethodChannel _sharedChannel =
|
||||
const MethodChannel('com.pichillilorenzo/flutter_inappbrowser');
|
||||
|
||||
late final InAppWebViewController _webViewController;
|
||||
InAppWebViewController? _webViewController;
|
||||
|
||||
///WebView Controller that can be used to access the [InAppWebViewController] API.
|
||||
///When [onExit] is fired, this will be `null` and cannot be used anymore.
|
||||
|
@ -85,18 +62,16 @@ class InAppBrowser {
|
|||
///The window id of a [CreateWindowAction.windowId].
|
||||
final int? windowId;
|
||||
|
||||
///Represents the WebView native implementation to be used.
|
||||
///The default value is [WebViewImplementation.NATIVE].
|
||||
final WebViewImplementation implementation;
|
||||
|
||||
InAppBrowser(
|
||||
{this.windowId,
|
||||
this.initialUserScripts,
|
||||
this.implementation = WebViewImplementation.NATIVE}) {
|
||||
this.initialUserScripts}) {
|
||||
id = IdGenerator.generate();
|
||||
}
|
||||
|
||||
_init() {
|
||||
this._channel =
|
||||
MethodChannel('com.pichillilorenzo/flutter_inappbrowser_$id');
|
||||
this._channel.setMethodCallHandler((call) async {
|
||||
this._channel?.setMethodCallHandler((call) async {
|
||||
try {
|
||||
return await _handleMethod(call);
|
||||
} on Error catch (e) {
|
||||
|
@ -104,9 +79,10 @@ class InAppBrowser {
|
|||
print(e.stackTrace);
|
||||
}
|
||||
});
|
||||
_isOpened = false;
|
||||
_webViewController = new InAppWebViewController.fromInAppBrowser(
|
||||
this._channel, this, this.initialUserScripts);
|
||||
this._channel!, this, this.initialUserScripts);
|
||||
pullToRefreshController?.init(id);
|
||||
findInteractionController?.init(id);
|
||||
}
|
||||
|
||||
_debugLog(String method, dynamic args) {
|
||||
|
@ -122,18 +98,16 @@ class InAppBrowser {
|
|||
switch (call.method) {
|
||||
case "onBrowserCreated":
|
||||
_debugLog(call.method, call.arguments);
|
||||
this._isOpened = true;
|
||||
this.pullToRefreshController?.initMethodChannel(id);
|
||||
this.findInteractionController?.initMethodChannel(id);
|
||||
onBrowserCreated();
|
||||
break;
|
||||
case "onExit":
|
||||
_debugLog(call.method, call.arguments);
|
||||
this._isOpened = false;
|
||||
_isOpened = false;
|
||||
_dispose();
|
||||
onExit();
|
||||
break;
|
||||
default:
|
||||
return _webViewController.handleMethod(call);
|
||||
return _webViewController?.handleMethod(call);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,8 +128,10 @@ class InAppBrowser {
|
|||
// ignore: deprecated_member_use_from_same_package
|
||||
@Deprecated('Use settings instead') InAppBrowserClassOptions? options,
|
||||
InAppBrowserClassSettings? settings}) async {
|
||||
this.throwIfAlreadyOpened(message: 'Cannot open $urlRequest!');
|
||||
assert(!_isOpened, 'The browser is already opened.');
|
||||
_isOpened = true;
|
||||
assert(urlRequest.url != null && urlRequest.url.toString().isNotEmpty);
|
||||
_init();
|
||||
|
||||
var initialSettings = settings?.toMap() ??
|
||||
options?.toMap() ??
|
||||
|
@ -173,7 +149,6 @@ class InAppBrowser {
|
|||
args.putIfAbsent('settings', () => initialSettings);
|
||||
args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {});
|
||||
args.putIfAbsent('windowId', () => windowId);
|
||||
args.putIfAbsent('implementation', () => implementation.toNativeValue());
|
||||
args.putIfAbsent('initialUserScripts',
|
||||
() => initialUserScripts?.map((e) => e.toMap()).toList() ?? []);
|
||||
args.putIfAbsent('pullToRefreshSettings', () => pullToRefreshSettings);
|
||||
|
@ -227,8 +202,10 @@ class InAppBrowser {
|
|||
// ignore: deprecated_member_use_from_same_package
|
||||
@Deprecated('Use settings instead') InAppBrowserClassOptions? options,
|
||||
InAppBrowserClassSettings? settings}) async {
|
||||
this.throwIfAlreadyOpened(message: 'Cannot open $assetFilePath!');
|
||||
assert(!_isOpened, 'The browser is already opened.');
|
||||
_isOpened = true;
|
||||
assert(assetFilePath.isNotEmpty);
|
||||
_init();
|
||||
|
||||
var initialSettings = settings?.toMap() ??
|
||||
options?.toMap() ??
|
||||
|
@ -246,7 +223,6 @@ class InAppBrowser {
|
|||
args.putIfAbsent('settings', () => initialSettings);
|
||||
args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {});
|
||||
args.putIfAbsent('windowId', () => windowId);
|
||||
args.putIfAbsent('implementation', () => implementation.toNativeValue());
|
||||
args.putIfAbsent('initialUserScripts',
|
||||
() => initialUserScripts?.map((e) => e.toMap()).toList() ?? []);
|
||||
args.putIfAbsent('pullToRefreshSettings', () => pullToRefreshSettings);
|
||||
|
@ -279,7 +255,9 @@ class InAppBrowser {
|
|||
// ignore: deprecated_member_use_from_same_package
|
||||
@Deprecated('Use settings instead') InAppBrowserClassOptions? options,
|
||||
InAppBrowserClassSettings? settings}) async {
|
||||
this.throwIfAlreadyOpened(message: 'Cannot open data!');
|
||||
assert(!_isOpened, 'The browser is already opened.');
|
||||
_isOpened = true;
|
||||
_init();
|
||||
|
||||
var initialSettings = settings?.toMap() ??
|
||||
options?.toMap() ??
|
||||
|
@ -302,7 +280,6 @@ class InAppBrowser {
|
|||
() => (historyUrl ?? androidHistoryUrl)?.toString() ?? "about:blank");
|
||||
args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {});
|
||||
args.putIfAbsent('windowId', () => windowId);
|
||||
args.putIfAbsent('implementation', () => implementation.toNativeValue());
|
||||
args.putIfAbsent('initialUserScripts',
|
||||
() => initialUserScripts?.map((e) => e.toMap()).toList() ?? []);
|
||||
args.putIfAbsent('pullToRefreshSettings', () => pullToRefreshSettings);
|
||||
|
@ -317,6 +294,7 @@ class InAppBrowser {
|
|||
///- MacOS
|
||||
static Future<void> openWithSystemBrowser({required WebUri url}) async {
|
||||
assert(url.toString().isNotEmpty);
|
||||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('url', () => url.toString());
|
||||
return await _sharedChannel.invokeMethod('openWithSystemBrowser', args);
|
||||
|
@ -329,9 +307,10 @@ class InAppBrowser {
|
|||
///- iOS
|
||||
///- MacOS
|
||||
Future<void> show() async {
|
||||
this.throwIfNotOpened();
|
||||
assert(_isOpened, 'The browser is not opened.');
|
||||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('show', args);
|
||||
await _channel?.invokeMethod('show', args);
|
||||
}
|
||||
|
||||
///Hides the [InAppBrowser] window. Calling this has no effect if the [InAppBrowser] was already hidden.
|
||||
|
@ -341,9 +320,10 @@ class InAppBrowser {
|
|||
///- iOS
|
||||
///- MacOS
|
||||
Future<void> hide() async {
|
||||
this.throwIfNotOpened();
|
||||
assert(_isOpened, 'The browser is not opened.');
|
||||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('hide', args);
|
||||
await _channel?.invokeMethod('hide', args);
|
||||
}
|
||||
|
||||
///Closes the [InAppBrowser] window.
|
||||
|
@ -353,9 +333,10 @@ class InAppBrowser {
|
|||
///- iOS
|
||||
///- MacOS
|
||||
Future<void> close() async {
|
||||
this.throwIfNotOpened();
|
||||
assert(_isOpened, 'The browser is not opened.');
|
||||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('close', args);
|
||||
await _channel?.invokeMethod('close', args);
|
||||
}
|
||||
|
||||
///Check if the Web View of the [InAppBrowser] instance is hidden.
|
||||
|
@ -365,29 +346,30 @@ class InAppBrowser {
|
|||
///- iOS
|
||||
///- MacOS
|
||||
Future<bool> isHidden() async {
|
||||
this.throwIfNotOpened();
|
||||
assert(_isOpened, 'The browser is not opened.');
|
||||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('isHidden', args);
|
||||
return await _channel?.invokeMethod('isHidden', args);
|
||||
}
|
||||
|
||||
///Use [setSettings] instead.
|
||||
@Deprecated('Use setSettings instead')
|
||||
Future<void> setOptions({required InAppBrowserClassOptions options}) async {
|
||||
this.throwIfNotOpened();
|
||||
assert(_isOpened, 'The browser is not opened.');
|
||||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('settings', () => options.toMap());
|
||||
await _channel.invokeMethod('setSettings', args);
|
||||
await _channel?.invokeMethod('setSettings', args);
|
||||
}
|
||||
|
||||
///Use [getSettings] instead.
|
||||
@Deprecated('Use getSettings instead')
|
||||
Future<InAppBrowserClassOptions?> getOptions() async {
|
||||
this.throwIfNotOpened();
|
||||
assert(_isOpened, 'The browser is not opened.');
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
|
||||
Map<dynamic, dynamic>? options =
|
||||
await _channel.invokeMethod('getSettings', args);
|
||||
await _channel?.invokeMethod('getSettings', args);
|
||||
if (options != null) {
|
||||
options = options.cast<String, dynamic>();
|
||||
return InAppBrowserClassOptions.fromMap(options as Map<String, dynamic>);
|
||||
|
@ -404,11 +386,11 @@ class InAppBrowser {
|
|||
///- MacOS
|
||||
Future<void> setSettings(
|
||||
{required InAppBrowserClassSettings settings}) async {
|
||||
this.throwIfNotOpened();
|
||||
assert(_isOpened, 'The browser is not opened.');
|
||||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('settings', () => settings.toMap());
|
||||
await _channel.invokeMethod('setSettings', args);
|
||||
await _channel?.invokeMethod('setSettings', args);
|
||||
}
|
||||
|
||||
///Gets the current [InAppBrowser] settings. Returns `null` if it wasn't able to get them.
|
||||
|
@ -418,11 +400,12 @@ class InAppBrowser {
|
|||
///- iOS
|
||||
///- MacOS
|
||||
Future<InAppBrowserClassSettings?> getSettings() async {
|
||||
this.throwIfNotOpened();
|
||||
assert(_isOpened, 'The browser is not opened.');
|
||||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
|
||||
Map<dynamic, dynamic>? settings =
|
||||
await _channel.invokeMethod('getSettings', args);
|
||||
await _channel?.invokeMethod('getSettings', args);
|
||||
if (settings != null) {
|
||||
settings = settings.cast<String, dynamic>();
|
||||
return InAppBrowserClassSettings.fromMap(
|
||||
|
@ -1321,19 +1304,15 @@ class InAppBrowser {
|
|||
///- iOS
|
||||
void onContentSizeChanged(Size oldContentSize, Size newContentSize) {}
|
||||
|
||||
void throwIfAlreadyOpened({String message = ''}) {
|
||||
if (this.isOpened()) {
|
||||
throw InAppBrowserAlreadyOpenedException([
|
||||
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is already opened.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
void throwIfNotOpened({String message = ''}) {
|
||||
if (!this.isOpened()) {
|
||||
throw InAppBrowserNotOpenedException([
|
||||
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is not opened.'
|
||||
]);
|
||||
}
|
||||
///Disposes the channel and controllers.
|
||||
void _dispose() {
|
||||
_channel?.setMethodCallHandler(null);
|
||||
_channel = null;
|
||||
_webViewController?.dispose();
|
||||
_webViewController = null;
|
||||
pullToRefreshController?.dispose();
|
||||
pullToRefreshController = null;
|
||||
findInteractionController?.dispose();
|
||||
findInteractionController = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:flutter/services.dart';
|
||||
|
||||
const IN_APP_WEBVIEW_STATIC_CHANNEL =
|
||||
const MethodChannel('com.pichillilorenzo/flutter_inappwebview_static');
|
||||
const MethodChannel('com.pichillilorenzo/flutter_inappwebview_manager');
|
||||
|
|
|
@ -8,7 +8,7 @@ import '../in_app_webview_controller.dart';
|
|||
///Use [InAppWebViewController] instead.
|
||||
@Deprecated("Use InAppWebViewController instead")
|
||||
class AndroidInAppWebViewController {
|
||||
late MethodChannel _channel;
|
||||
MethodChannel? _channel;
|
||||
|
||||
AndroidInAppWebViewController({required MethodChannel channel}) {
|
||||
this._channel = channel;
|
||||
|
@ -18,28 +18,28 @@ class AndroidInAppWebViewController {
|
|||
@Deprecated("Use InAppWebViewController.startSafeBrowsing instead")
|
||||
Future<bool> startSafeBrowsing() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('startSafeBrowsing', args);
|
||||
return await _channel?.invokeMethod('startSafeBrowsing', args);
|
||||
}
|
||||
|
||||
///Use [InAppWebViewController.clearSslPreferences] instead.
|
||||
@Deprecated("Use InAppWebViewController.clearSslPreferences instead")
|
||||
Future<void> clearSslPreferences() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('clearSslPreferences', args);
|
||||
await _channel?.invokeMethod('clearSslPreferences', args);
|
||||
}
|
||||
|
||||
///Use [InAppWebViewController.pause] instead.
|
||||
@Deprecated("Use InAppWebViewController.pause instead")
|
||||
Future<void> pause() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('pause', args);
|
||||
await _channel?.invokeMethod('pause', args);
|
||||
}
|
||||
|
||||
///Use [InAppWebViewController.resume] instead.
|
||||
@Deprecated("Use InAppWebViewController.resume instead")
|
||||
Future<void> resume() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('resume', args);
|
||||
await _channel?.invokeMethod('resume', args);
|
||||
}
|
||||
|
||||
///Use [InAppWebViewController.pageDown] instead.
|
||||
|
@ -47,7 +47,7 @@ class AndroidInAppWebViewController {
|
|||
Future<bool> pageDown({required bool bottom}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent("bottom", () => bottom);
|
||||
return await _channel.invokeMethod('pageDown', args);
|
||||
return await _channel?.invokeMethod('pageDown', args);
|
||||
}
|
||||
|
||||
///Use [InAppWebViewController.pageUp] instead.
|
||||
|
@ -55,28 +55,28 @@ class AndroidInAppWebViewController {
|
|||
Future<bool> pageUp({required bool top}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent("top", () => top);
|
||||
return await _channel.invokeMethod('pageUp', args);
|
||||
return await _channel?.invokeMethod('pageUp', args);
|
||||
}
|
||||
|
||||
///Use [InAppWebViewController.zoomIn] instead.
|
||||
@Deprecated("Use InAppWebViewController.zoomIn instead")
|
||||
Future<bool> zoomIn() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('zoomIn', args);
|
||||
return await _channel?.invokeMethod('zoomIn', args);
|
||||
}
|
||||
|
||||
///Use [InAppWebViewController.zoomOut] instead.
|
||||
@Deprecated("Use InAppWebViewController.zoomOut instead")
|
||||
Future<bool> zoomOut() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('zoomOut', args);
|
||||
return await _channel?.invokeMethod('zoomOut', args);
|
||||
}
|
||||
|
||||
///Use [InAppWebViewController.clearHistory] instead.
|
||||
@Deprecated("Use InAppWebViewController.clearHistory instead")
|
||||
Future<void> clearHistory() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('clearHistory', args);
|
||||
return await _channel?.invokeMethod('clearHistory', args);
|
||||
}
|
||||
|
||||
///Use [InAppWebViewController.clearClientCertPreferences] instead.
|
||||
|
@ -120,7 +120,11 @@ class AndroidInAppWebViewController {
|
|||
@Deprecated('Use InAppWebViewController.getOriginalUrl instead')
|
||||
Future<Uri?> getOriginalUrl() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
String? url = await _channel.invokeMethod('getOriginalUrl', args);
|
||||
String? url = await _channel?.invokeMethod('getOriginalUrl', args);
|
||||
return url != null ? Uri.tryParse(url) : null;
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_channel = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@ import '../in_app_webview_controller.dart';
|
|||
///Use [InAppWebViewController] instead.
|
||||
@Deprecated("Use InAppWebViewController instead")
|
||||
class IOSInAppWebViewController {
|
||||
late MethodChannel _channel;
|
||||
MethodChannel? _channel;
|
||||
|
||||
IOSInAppWebViewController({required MethodChannel channel}) {
|
||||
this._channel = channel;
|
||||
}
|
||||
|
@ -18,7 +19,7 @@ class IOSInAppWebViewController {
|
|||
@Deprecated("Use InAppWebViewController.reloadFromOrigin instead")
|
||||
Future<void> reloadFromOrigin() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('reloadFromOrigin', args);
|
||||
await _channel?.invokeMethod('reloadFromOrigin', args);
|
||||
}
|
||||
|
||||
///Use [InAppWebViewController.createPdf] instead.
|
||||
|
@ -31,21 +32,21 @@ class IOSInAppWebViewController {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('pdfConfiguration',
|
||||
() => pdfConfiguration?.toMap() ?? iosWKPdfConfiguration?.toMap());
|
||||
return await _channel.invokeMethod('createPdf', args);
|
||||
return await _channel?.invokeMethod('createPdf', args);
|
||||
}
|
||||
|
||||
///Use [InAppWebViewController.createWebArchiveData] instead.
|
||||
@Deprecated("Use InAppWebViewController.createWebArchiveData instead")
|
||||
Future<Uint8List?> createWebArchiveData() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('createWebArchiveData', args);
|
||||
return await _channel?.invokeMethod('createWebArchiveData', args);
|
||||
}
|
||||
|
||||
///Use [InAppWebViewController.hasOnlySecureContent] instead.
|
||||
@Deprecated("Use InAppWebViewController.hasOnlySecureContent instead")
|
||||
Future<bool> hasOnlySecureContent() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('hasOnlySecureContent', args);
|
||||
return await _channel?.invokeMethod('hasOnlySecureContent', args);
|
||||
}
|
||||
|
||||
///Use [InAppWebViewController.handlesURLScheme] instead.
|
||||
|
@ -53,4 +54,8 @@ class IOSInAppWebViewController {
|
|||
static Future<bool> handlesURLScheme(String urlScheme) async {
|
||||
return await InAppWebViewController.handlesURLScheme(urlScheme);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_channel = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:typed_data';
|
|||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_inappwebview/src/util.dart';
|
||||
import '../util.dart';
|
||||
|
||||
import '../context_menu.dart';
|
||||
import '../find_interaction/find_interaction_controller.dart';
|
||||
|
@ -38,10 +38,12 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
|||
|
||||
static const MethodChannel _sharedChannel =
|
||||
const MethodChannel('com.pichillilorenzo/flutter_headless_inappwebview');
|
||||
late MethodChannel _channel;
|
||||
MethodChannel? _channel;
|
||||
|
||||
InAppWebViewController? _webViewController;
|
||||
|
||||
///WebView Controller that can be used to access the [InAppWebViewController] API.
|
||||
late final InAppWebViewController webViewController;
|
||||
InAppWebViewController? get webViewController => _webViewController;
|
||||
|
||||
///{@macro flutter_inappwebview.WebView.windowId}
|
||||
final int? windowId;
|
||||
|
@ -74,7 +76,6 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
|||
this.initialUserScripts,
|
||||
this.pullToRefreshController,
|
||||
this.findInteractionController,
|
||||
this.implementation = WebViewImplementation.NATIVE,
|
||||
this.onWebViewCreated,
|
||||
this.onLoadStart,
|
||||
this.onLoadStop,
|
||||
|
@ -180,10 +181,15 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
|||
this.onMicrophoneCaptureStateChanged,
|
||||
this.onContentSizeChanged}) {
|
||||
id = IdGenerator.generate();
|
||||
webViewController = new InAppWebViewController(id, this);
|
||||
}
|
||||
|
||||
_init() {
|
||||
_webViewController = InAppWebViewController(id, this);
|
||||
pullToRefreshController?.init(id);
|
||||
findInteractionController?.init(id);
|
||||
this._channel =
|
||||
MethodChannel('com.pichillilorenzo/flutter_headless_inappwebview_$id');
|
||||
this._channel.setMethodCallHandler((call) async {
|
||||
this._channel?.setMethodCallHandler((call) async {
|
||||
try {
|
||||
return await handleMethod(call);
|
||||
} on Error catch (e) {
|
||||
|
@ -196,10 +202,8 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
|||
Future<dynamic> handleMethod(MethodCall call) async {
|
||||
switch (call.method) {
|
||||
case "onWebViewCreated":
|
||||
pullToRefreshController?.initMethodChannel(id);
|
||||
findInteractionController?.initMethodChannel(id);
|
||||
if (onWebViewCreated != null) {
|
||||
onWebViewCreated!(webViewController);
|
||||
if (onWebViewCreated != null && _webViewController != null) {
|
||||
onWebViewCreated!(_webViewController!);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -222,6 +226,7 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
|||
return;
|
||||
}
|
||||
_started = true;
|
||||
_init();
|
||||
|
||||
final initialSettings = this.initialSettings ?? InAppWebViewSettings();
|
||||
_inferInitialSettings(initialSettings);
|
||||
|
@ -249,7 +254,6 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
|||
'initialSettings': settingsMap,
|
||||
'contextMenu': this.contextMenu?.toMap() ?? {},
|
||||
'windowId': this.windowId,
|
||||
'implementation': this.implementation.toNativeValue(),
|
||||
'initialUserScripts':
|
||||
this.initialUserScripts?.map((e) => e.toMap()).toList() ?? [],
|
||||
'pullToRefreshSettings': pullToRefreshSettings,
|
||||
|
@ -306,9 +310,15 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
|||
return;
|
||||
}
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('dispose', args);
|
||||
await _channel?.invokeMethod('dispose', args);
|
||||
_channel?.setMethodCallHandler(null);
|
||||
_channel = null;
|
||||
_started = false;
|
||||
_running = false;
|
||||
_webViewController?.dispose();
|
||||
_webViewController = null;
|
||||
pullToRefreshController?.dispose();
|
||||
findInteractionController?.dispose();
|
||||
}
|
||||
|
||||
///Indicates if the headless WebView is running or not.
|
||||
|
@ -343,7 +353,7 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
|||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('size', () => size.toMap());
|
||||
await _channel.invokeMethod('setSize', args);
|
||||
await _channel?.invokeMethod('setSize', args);
|
||||
}
|
||||
|
||||
///Gets the current size in pixels of the WebView.
|
||||
|
@ -362,7 +372,7 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
|||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
Map<String, dynamic> sizeMap =
|
||||
(await _channel.invokeMethod('getSize', args))?.cast<String, dynamic>();
|
||||
(await _channel?.invokeMethod('getSize', args))?.cast<String, dynamic>();
|
||||
return MapSize.fromMap(sizeMap);
|
||||
}
|
||||
|
||||
|
@ -403,10 +413,6 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
|||
@override
|
||||
final FindInteractionController? findInteractionController;
|
||||
|
||||
///{@macro flutter_inappwebview.WebView.implementation}
|
||||
@override
|
||||
final WebViewImplementation implementation;
|
||||
|
||||
///Use [onGeolocationPermissionsHidePrompt] instead.
|
||||
@override
|
||||
@Deprecated('Use onGeolocationPermissionsHidePrompt instead')
|
||||
|
|
|
@ -8,8 +8,8 @@ import 'package:flutter/rendering.dart';
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter_inappwebview/src/in_app_webview/headless_in_app_webview.dart';
|
||||
import 'package:flutter_inappwebview/src/util.dart';
|
||||
import 'headless_in_app_webview.dart';
|
||||
import '../util.dart';
|
||||
|
||||
import '../find_interaction/find_interaction_controller.dart';
|
||||
import '../web/web_platform_manager.dart';
|
||||
|
@ -23,6 +23,8 @@ import 'webview.dart';
|
|||
import 'in_app_webview_controller.dart';
|
||||
import 'in_app_webview_settings.dart';
|
||||
import '../pull_to_refresh/main.dart';
|
||||
import '../pull_to_refresh/pull_to_refresh_controller.dart';
|
||||
import 'in_app_webview_keep_alive.dart';
|
||||
|
||||
///{@template flutter_inappwebview.InAppWebView}
|
||||
///Flutter Widget for adding an **inline native WebView** integrated in the flutter widget tree.
|
||||
|
@ -46,7 +48,7 @@ class InAppWebView extends StatefulWidget implements WebView {
|
|||
@override
|
||||
final int? windowId;
|
||||
|
||||
///The [HeadlessInAppWebView] to use to initialize this widget
|
||||
///The [HeadlessInAppWebView] to use to initialize this widget.
|
||||
///
|
||||
///**Supported Platforms/Implementations**:
|
||||
///- Android native WebView
|
||||
|
@ -54,33 +56,46 @@ class InAppWebView extends StatefulWidget implements WebView {
|
|||
///- Web
|
||||
final HeadlessInAppWebView? headlessWebView;
|
||||
|
||||
///Used to keep alive this WebView.
|
||||
///Remember to dispose the [InAppWebViewKeepAlive] instance
|
||||
///using [InAppWebViewController.disposeKeepAlive].
|
||||
///
|
||||
///**Supported Platforms/Implementations**:
|
||||
///- Android native WebView
|
||||
///- iOS
|
||||
final InAppWebViewKeepAlive? keepAlive;
|
||||
|
||||
///{@macro flutter_inappwebview.InAppWebView}
|
||||
const InAppWebView({
|
||||
Key? key,
|
||||
this.windowId,
|
||||
this.keepAlive,
|
||||
this.initialUrlRequest,
|
||||
this.initialFile,
|
||||
this.initialData,
|
||||
@Deprecated('Use initialSettings instead') this.initialOptions,
|
||||
@Deprecated('Use initialSettings instead')
|
||||
this.initialOptions,
|
||||
this.initialSettings,
|
||||
this.initialUserScripts,
|
||||
this.pullToRefreshController,
|
||||
this.findInteractionController,
|
||||
this.implementation = WebViewImplementation.NATIVE,
|
||||
this.contextMenu,
|
||||
this.onWebViewCreated,
|
||||
this.onLoadStart,
|
||||
this.onLoadStop,
|
||||
@Deprecated("Use onReceivedError instead") this.onLoadError,
|
||||
@Deprecated("Use onReceivedError instead")
|
||||
this.onLoadError,
|
||||
this.onReceivedError,
|
||||
@Deprecated("Use onReceivedHttpError instead") this.onLoadHttpError,
|
||||
@Deprecated("Use onReceivedHttpError instead")
|
||||
this.onLoadHttpError,
|
||||
this.onReceivedHttpError,
|
||||
this.onConsoleMessage,
|
||||
this.onProgressChanged,
|
||||
this.shouldOverrideUrlLoading,
|
||||
this.onLoadResource,
|
||||
this.onScrollChanged,
|
||||
@Deprecated('Use onDownloadStartRequest instead') this.onDownloadStart,
|
||||
@Deprecated('Use onDownloadStartRequest instead')
|
||||
this.onDownloadStart,
|
||||
this.onDownloadStartRequest,
|
||||
@Deprecated('Use onLoadResourceWithCustomScheme instead')
|
||||
this.onLoadResourceCustomScheme,
|
||||
|
@ -100,7 +115,8 @@ class InAppWebView extends StatefulWidget implements WebView {
|
|||
this.onAjaxProgress,
|
||||
this.shouldInterceptFetchRequest,
|
||||
this.onUpdateVisitedHistory,
|
||||
@Deprecated("Use onPrintRequest instead") this.onPrint,
|
||||
@Deprecated("Use onPrintRequest instead")
|
||||
this.onPrint,
|
||||
this.onPrintRequest,
|
||||
this.onLongPressHitTestResult,
|
||||
this.onEnterFullscreen,
|
||||
|
@ -111,7 +127,8 @@ class InAppWebView extends StatefulWidget implements WebView {
|
|||
this.onWindowBlur,
|
||||
this.onOverScrolled,
|
||||
this.onZoomScaleChanged,
|
||||
@Deprecated('Use onSafeBrowsingHit instead') this.androidOnSafeBrowsingHit,
|
||||
@Deprecated('Use onSafeBrowsingHit instead')
|
||||
this.androidOnSafeBrowsingHit,
|
||||
this.onSafeBrowsingHit,
|
||||
@Deprecated('Use onPermissionRequest instead')
|
||||
this.androidOnPermissionRequest,
|
||||
|
@ -137,13 +154,16 @@ class InAppWebView extends StatefulWidget implements WebView {
|
|||
@Deprecated('Use onFormResubmission instead')
|
||||
this.androidOnFormResubmission,
|
||||
this.onFormResubmission,
|
||||
@Deprecated('Use onZoomScaleChanged instead') this.androidOnScaleChanged,
|
||||
@Deprecated('Use onReceivedIcon instead') this.androidOnReceivedIcon,
|
||||
@Deprecated('Use onZoomScaleChanged instead')
|
||||
this.androidOnScaleChanged,
|
||||
@Deprecated('Use onReceivedIcon instead')
|
||||
this.androidOnReceivedIcon,
|
||||
this.onReceivedIcon,
|
||||
@Deprecated('Use onReceivedTouchIconUrl instead')
|
||||
this.androidOnReceivedTouchIconUrl,
|
||||
this.onReceivedTouchIconUrl,
|
||||
@Deprecated('Use onJsBeforeUnload instead') this.androidOnJsBeforeUnload,
|
||||
@Deprecated('Use onJsBeforeUnload instead')
|
||||
this.androidOnJsBeforeUnload,
|
||||
this.onJsBeforeUnload,
|
||||
@Deprecated('Use onReceivedLoginRequest instead')
|
||||
this.androidOnReceivedLoginRequest,
|
||||
|
@ -222,10 +242,6 @@ class InAppWebView extends StatefulWidget implements WebView {
|
|||
@override
|
||||
final URLRequest? initialUrlRequest;
|
||||
|
||||
///{@macro flutter_inappwebview.WebView.implementation}
|
||||
@override
|
||||
final WebViewImplementation implementation;
|
||||
|
||||
///{@macro flutter_inappwebview.WebView.initialUserScripts}
|
||||
@override
|
||||
final UnmodifiableListView<UserScript>? initialUserScripts;
|
||||
|
@ -704,6 +720,15 @@ class _InAppWebViewState extends State<InAppWebView> {
|
|||
widget.pullToRefreshController?.options.toMap() ??
|
||||
PullToRefreshSettings(enabled: false).toMap();
|
||||
|
||||
if ((widget.headlessWebView?.isRunning() ?? false) &&
|
||||
widget.keepAlive != null) {
|
||||
final headlessId = widget.headlessWebView?.id;
|
||||
if (headlessId != null) {
|
||||
// force keep alive id to match headless webview id
|
||||
widget.keepAlive?.id = headlessId;
|
||||
}
|
||||
}
|
||||
|
||||
if (Util.isWeb) {
|
||||
return HtmlElementView(
|
||||
viewType: 'com.pichillilorenzo/flutter_inappwebview',
|
||||
|
@ -727,9 +752,7 @@ class _InAppWebViewState extends State<InAppWebView> {
|
|||
} else if (Util.isAndroid) {
|
||||
var useHybridComposition = (widget.initialSettings != null
|
||||
? initialSettings.useHybridComposition
|
||||
:
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
widget.initialOptions?.android.useHybridComposition) ??
|
||||
: widget.initialOptions?.android.useHybridComposition) ??
|
||||
true;
|
||||
|
||||
return PlatformViewLink(
|
||||
|
@ -762,11 +785,11 @@ class _InAppWebViewState extends State<InAppWebView> {
|
|||
'headlessWebViewId': widget.headlessWebView?.isRunning() ?? false
|
||||
? widget.headlessWebView?.id
|
||||
: null,
|
||||
'implementation': widget.implementation.toNativeValue(),
|
||||
'initialUserScripts':
|
||||
widget.initialUserScripts?.map((e) => e.toMap()).toList() ??
|
||||
[],
|
||||
'pullToRefreshSettings': pullToRefreshSettings
|
||||
'pullToRefreshSettings': pullToRefreshSettings,
|
||||
'keepAliveId': widget.keepAlive?.id
|
||||
},
|
||||
)
|
||||
..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
|
||||
|
@ -790,10 +813,10 @@ class _InAppWebViewState extends State<InAppWebView> {
|
|||
'headlessWebViewId': widget.headlessWebView?.isRunning() ?? false
|
||||
? widget.headlessWebView?.id
|
||||
: null,
|
||||
'implementation': widget.implementation.toNativeValue(),
|
||||
'initialUserScripts':
|
||||
widget.initialUserScripts?.map((e) => e.toMap()).toList() ?? [],
|
||||
'pullToRefreshSettings': pullToRefreshSettings
|
||||
'pullToRefreshSettings': pullToRefreshSettings,
|
||||
'keepAliveId': widget.keepAlive?.id
|
||||
},
|
||||
creationParamsCodec: const StandardMessageCodec(),
|
||||
);
|
||||
|
@ -810,13 +833,24 @@ class _InAppWebViewState extends State<InAppWebView> {
|
|||
@override
|
||||
void dispose() {
|
||||
dynamic viewId = _controller?.getViewId();
|
||||
debugLog(
|
||||
className: "InAppWebView",
|
||||
name: "WebView",
|
||||
id: viewId?.toString(),
|
||||
debugLoggingSettings: WebView.debugLoggingSettings,
|
||||
method: "dispose",
|
||||
args: []);
|
||||
if (viewId != null &&
|
||||
kIsWeb &&
|
||||
WebPlatformManager.webViews.containsKey(viewId)) {
|
||||
WebPlatformManager.webViews.remove(viewId);
|
||||
}
|
||||
super.dispose();
|
||||
final isKeepAlive = widget.keepAlive != null;
|
||||
_controller?.dispose(isKeepAlive: isKeepAlive);
|
||||
_controller = null;
|
||||
widget.pullToRefreshController?.dispose(isKeepAlive: isKeepAlive);
|
||||
widget.findInteractionController?.dispose(isKeepAlive: isKeepAlive);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
AndroidViewController _createAndroidViewController({
|
||||
|
@ -845,21 +879,25 @@ class _InAppWebViewState extends State<InAppWebView> {
|
|||
}
|
||||
|
||||
void _onPlatformViewCreated(int id) {
|
||||
final viewId = (!kIsWeb && (widget.headlessWebView?.isRunning() ?? false))
|
||||
? widget.headlessWebView?.id
|
||||
: id;
|
||||
dynamic viewId = id;
|
||||
if (!kIsWeb) {
|
||||
if (widget.headlessWebView?.isRunning() ?? false) {
|
||||
viewId = widget.headlessWebView?.id;
|
||||
}
|
||||
viewId = widget.keepAlive?.id ?? viewId ?? id;
|
||||
}
|
||||
widget.headlessWebView?.internalDispose();
|
||||
_controller = InAppWebViewController(viewId, widget);
|
||||
widget.pullToRefreshController?.initMethodChannel(viewId);
|
||||
widget.findInteractionController?.initMethodChannel(viewId);
|
||||
widget.pullToRefreshController?.init(viewId);
|
||||
widget.findInteractionController?.init(viewId);
|
||||
debugLog(
|
||||
className: "InAppWebView",
|
||||
name: "WebView",
|
||||
id: viewId?.toString(),
|
||||
debugLoggingSettings: WebView.debugLoggingSettings,
|
||||
method: "onWebViewCreated",
|
||||
args: []);
|
||||
if (widget.onWebViewCreated != null) {
|
||||
debugLog(
|
||||
className: "InAppWebView",
|
||||
name: "WebView",
|
||||
id: viewId?.toString(),
|
||||
debugLoggingSettings: WebView.debugLoggingSettings,
|
||||
method: "onWebViewCreated",
|
||||
args: []);
|
||||
widget.onWebViewCreated!(_controller!);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import 'in_app_webview.dart';
|
|||
import 'in_app_webview_settings.dart';
|
||||
import 'webview.dart';
|
||||
import '_static_channel.dart';
|
||||
import 'in_app_webview_keep_alive.dart';
|
||||
|
||||
import '../print_job/main.dart';
|
||||
import '../find_interaction/main.dart';
|
||||
|
@ -52,17 +53,23 @@ final _JAVASCRIPT_HANDLER_FORBIDDEN_NAMES = UnmodifiableListView<String>([
|
|||
///callback. Instead, if you are using an [InAppBrowser] instance, you can get it through the [InAppBrowser.webViewController] attribute.
|
||||
class InAppWebViewController {
|
||||
WebView? _webview;
|
||||
late MethodChannel _channel;
|
||||
static MethodChannel _staticChannel = IN_APP_WEBVIEW_STATIC_CHANNEL;
|
||||
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap =
|
||||
MethodChannel? _channel;
|
||||
static final MethodChannel _staticChannel = IN_APP_WEBVIEW_STATIC_CHANNEL;
|
||||
|
||||
// properties to be saved and restored for keep alive feature
|
||||
Map<String, JavaScriptHandlerCallback> _javaScriptHandlersMap =
|
||||
HashMap<String, JavaScriptHandlerCallback>();
|
||||
final Map<UserScriptInjectionTime, List<UserScript>> _userScripts = {
|
||||
Map<UserScriptInjectionTime, List<UserScript>> _userScripts = {
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START: <UserScript>[],
|
||||
UserScriptInjectionTime.AT_DOCUMENT_END: <UserScript>[]
|
||||
};
|
||||
Set<String> _webMessageListenerObjNames = Set();
|
||||
Map<String, ScriptHtmlTagAttributes> _injectedScriptsFromURL = {};
|
||||
|
||||
// static map that contains the properties to be saved and restored for keep alive feature
|
||||
static final Map<InAppWebViewKeepAlive, InAppWebViewControllerKeepAliveProps?>
|
||||
_keepAliveMap = {};
|
||||
|
||||
dynamic _id;
|
||||
|
||||
InAppBrowser? _inAppBrowser;
|
||||
|
@ -82,7 +89,8 @@ class InAppWebViewController {
|
|||
this._id = id;
|
||||
this._channel =
|
||||
MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id');
|
||||
this._channel.setMethodCallHandler((call) async {
|
||||
this._channel?.setMethodCallHandler((call) async {
|
||||
if (_channel == null) return null;
|
||||
try {
|
||||
return await handleMethod(call);
|
||||
} on Error catch (e) {
|
||||
|
@ -136,12 +144,31 @@ class InAppWebViewController {
|
|||
}
|
||||
|
||||
void _init() {
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
this.android = AndroidInAppWebViewController(channel: _channel);
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
this.ios = IOSInAppWebViewController(channel: _channel);
|
||||
this.webStorage = WebStorage(
|
||||
android = AndroidInAppWebViewController(channel: _channel!);
|
||||
ios = IOSInAppWebViewController(channel: _channel!);
|
||||
webStorage = WebStorage(
|
||||
localStorage: LocalStorage(this), sessionStorage: SessionStorage(this));
|
||||
|
||||
if (_webview is InAppWebView) {
|
||||
final keepAlive = (_webview as InAppWebView).keepAlive;
|
||||
if (keepAlive != null) {
|
||||
InAppWebViewControllerKeepAliveProps? props = _keepAliveMap[keepAlive];
|
||||
if (props == null) {
|
||||
// save controller properties to restore it later
|
||||
_keepAliveMap[keepAlive] = InAppWebViewControllerKeepAliveProps(
|
||||
injectedScriptsFromURL: _injectedScriptsFromURL,
|
||||
javaScriptHandlersMap: _javaScriptHandlersMap,
|
||||
userScripts: _userScripts,
|
||||
webMessageListenerObjNames: _webMessageListenerObjNames);
|
||||
} else {
|
||||
// restore controller properties
|
||||
_injectedScriptsFromURL = props.injectedScriptsFromURL;
|
||||
_javaScriptHandlersMap = props.javaScriptHandlersMap;
|
||||
_userScripts = props.userScripts;
|
||||
_webMessageListenerObjNames = props.webMessageListenerObjNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_debugLog(String method, dynamic args) {
|
||||
|
@ -1374,10 +1401,10 @@ class InAppWebViewController {
|
|||
return null;
|
||||
}
|
||||
|
||||
if (javaScriptHandlersMap.containsKey(handlerName)) {
|
||||
if (_javaScriptHandlersMap.containsKey(handlerName)) {
|
||||
// convert result to json
|
||||
try {
|
||||
return jsonEncode(await javaScriptHandlersMap[handlerName]!(args));
|
||||
return jsonEncode(await _javaScriptHandlersMap[handlerName]!(args));
|
||||
} catch (error, stacktrace) {
|
||||
developer.log(error.toString() + '\n' + stacktrace.toString(),
|
||||
name: 'JavaScript Handler "$handlerName"');
|
||||
|
@ -1404,7 +1431,7 @@ class InAppWebViewController {
|
|||
///- Web
|
||||
Future<WebUri?> getUrl() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
String? url = await _channel.invokeMethod('getUrl', args);
|
||||
String? url = await _channel?.invokeMethod('getUrl', args);
|
||||
return url != null ? WebUri(url) : null;
|
||||
}
|
||||
|
||||
|
@ -1419,7 +1446,7 @@ class InAppWebViewController {
|
|||
///- Web
|
||||
Future<String?> getTitle() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('getTitle', args);
|
||||
return await _channel?.invokeMethod('getTitle', args);
|
||||
}
|
||||
|
||||
///Gets the progress for the current page. The progress value is between 0 and 100.
|
||||
|
@ -1430,7 +1457,7 @@ class InAppWebViewController {
|
|||
///- MacOS ([Official API - WKWebView.estimatedProgress](https://developer.apple.com/documentation/webkit/wkwebview/1415007-estimatedprogress))
|
||||
Future<int?> getProgress() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('getProgress', args);
|
||||
return await _channel?.invokeMethod('getProgress', args);
|
||||
}
|
||||
|
||||
///Gets the content html of the page. It first tries to get the content through javascript.
|
||||
|
@ -1693,7 +1720,7 @@ class InAppWebViewController {
|
|||
() =>
|
||||
allowingReadAccessTo?.toString() ??
|
||||
iosAllowingReadAccessTo?.toString());
|
||||
await _channel.invokeMethod('loadUrl', args);
|
||||
await _channel?.invokeMethod('loadUrl', args);
|
||||
}
|
||||
|
||||
///Loads the given [url] with [postData] (x-www-form-urlencoded) using `POST` method into this WebView.
|
||||
|
@ -1717,7 +1744,7 @@ class InAppWebViewController {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('url', () => url.toString());
|
||||
args.putIfAbsent('postData', () => postData);
|
||||
await _channel.invokeMethod('postUrl', args);
|
||||
await _channel?.invokeMethod('postUrl', args);
|
||||
}
|
||||
|
||||
///Loads the given [data] into this WebView, using [baseUrl] as the base URL for the content.
|
||||
|
@ -1771,7 +1798,7 @@ class InAppWebViewController {
|
|||
() =>
|
||||
allowingReadAccessTo?.toString() ??
|
||||
iosAllowingReadAccessTo?.toString());
|
||||
await _channel.invokeMethod('loadData', args);
|
||||
await _channel?.invokeMethod('loadData', args);
|
||||
}
|
||||
|
||||
///Loads the given [assetFilePath].
|
||||
|
@ -1813,7 +1840,7 @@ class InAppWebViewController {
|
|||
assert(assetFilePath.isNotEmpty);
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('assetFilePath', () => assetFilePath);
|
||||
await _channel.invokeMethod('loadFile', args);
|
||||
await _channel?.invokeMethod('loadFile', args);
|
||||
}
|
||||
|
||||
///Reloads the WebView.
|
||||
|
@ -1827,7 +1854,7 @@ class InAppWebViewController {
|
|||
///- Web ([Official API - Location.reload](https://developer.mozilla.org/en-US/docs/Web/API/Location/reload))
|
||||
Future<void> reload() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('reload', args);
|
||||
await _channel?.invokeMethod('reload', args);
|
||||
}
|
||||
|
||||
///Goes back in the history of the WebView.
|
||||
|
@ -1841,7 +1868,7 @@ class InAppWebViewController {
|
|||
///- Web ([Official API - History.back](https://developer.mozilla.org/en-US/docs/Web/API/History/back))
|
||||
Future<void> goBack() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('goBack', args);
|
||||
await _channel?.invokeMethod('goBack', args);
|
||||
}
|
||||
|
||||
///Returns a boolean value indicating whether the WebView can move backward.
|
||||
|
@ -1852,7 +1879,7 @@ class InAppWebViewController {
|
|||
///- MacOS ([Official API - WKWebView.canGoBack](https://developer.apple.com/documentation/webkit/wkwebview/1414966-cangoback))
|
||||
Future<bool> canGoBack() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('canGoBack', args);
|
||||
return await _channel?.invokeMethod('canGoBack', args);
|
||||
}
|
||||
|
||||
///Goes forward in the history of the WebView.
|
||||
|
@ -1866,7 +1893,7 @@ class InAppWebViewController {
|
|||
///- Web ([Official API - History.forward](https://developer.mozilla.org/en-US/docs/Web/API/History/forward))
|
||||
Future<void> goForward() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('goForward', args);
|
||||
await _channel?.invokeMethod('goForward', args);
|
||||
}
|
||||
|
||||
///Returns a boolean value indicating whether the WebView can move forward.
|
||||
|
@ -1877,7 +1904,7 @@ class InAppWebViewController {
|
|||
///- MacOS ([Official API - WKWebView.canGoForward](https://developer.apple.com/documentation/webkit/wkwebview/1414962-cangoforward))
|
||||
Future<bool> canGoForward() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('canGoForward', args);
|
||||
return await _channel?.invokeMethod('canGoForward', args);
|
||||
}
|
||||
|
||||
///Goes to the history item that is the number of steps away from the current item. Steps is negative if backward and positive if forward.
|
||||
|
@ -1892,7 +1919,7 @@ class InAppWebViewController {
|
|||
Future<void> goBackOrForward({required int steps}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('steps', () => steps);
|
||||
await _channel.invokeMethod('goBackOrForward', args);
|
||||
await _channel?.invokeMethod('goBackOrForward', args);
|
||||
}
|
||||
|
||||
///Returns a boolean value indicating whether the WebView can go back or forward the given number of steps. Steps is negative if backward and positive if forward.
|
||||
|
@ -1904,7 +1931,7 @@ class InAppWebViewController {
|
|||
Future<bool> canGoBackOrForward({required int steps}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('steps', () => steps);
|
||||
return await _channel.invokeMethod('canGoBackOrForward', args);
|
||||
return await _channel?.invokeMethod('canGoBackOrForward', args);
|
||||
}
|
||||
|
||||
///Navigates to a [WebHistoryItem] from the back-forward [WebHistory.list] and sets it as the current item.
|
||||
|
@ -1932,7 +1959,7 @@ class InAppWebViewController {
|
|||
///- Web
|
||||
Future<bool> isLoading() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('isLoading', args);
|
||||
return await _channel?.invokeMethod('isLoading', args);
|
||||
}
|
||||
|
||||
///Stops the WebView from loading.
|
||||
|
@ -1946,7 +1973,7 @@ class InAppWebViewController {
|
|||
///- Web ([Official API - Window.stop](https://developer.mozilla.org/en-US/docs/Web/API/Window/stop))
|
||||
Future<void> stopLoading() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('stopLoading', args);
|
||||
await _channel?.invokeMethod('stopLoading', args);
|
||||
}
|
||||
|
||||
///Evaluates JavaScript [source] code into the WebView and returns the result of the evaluation.
|
||||
|
@ -1976,7 +2003,7 @@ class InAppWebViewController {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('source', () => source);
|
||||
args.putIfAbsent('contentWorld', () => contentWorld?.toMap());
|
||||
var data = await _channel.invokeMethod('evaluateJavascript', args);
|
||||
var data = await _channel?.invokeMethod('evaluateJavascript', args);
|
||||
if (data != null && (Util.isAndroid || Util.isWeb)) {
|
||||
try {
|
||||
// try to json decode the data coming from JavaScript
|
||||
|
@ -2015,7 +2042,7 @@ class InAppWebViewController {
|
|||
args.putIfAbsent('urlFile', () => urlFile.toString());
|
||||
args.putIfAbsent(
|
||||
'scriptHtmlTagAttributes', () => scriptHtmlTagAttributes?.toMap());
|
||||
await _channel.invokeMethod('injectJavascriptFileFromUrl', args);
|
||||
await _channel?.invokeMethod('injectJavascriptFileFromUrl', args);
|
||||
}
|
||||
|
||||
///Evaluates the content of a JavaScript file into the WebView from the flutter assets directory.
|
||||
|
@ -2055,7 +2082,7 @@ class InAppWebViewController {
|
|||
Future<void> injectCSSCode({required String source}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('source', () => source);
|
||||
await _channel.invokeMethod('injectCSSCode', args);
|
||||
await _channel?.invokeMethod('injectCSSCode', args);
|
||||
}
|
||||
|
||||
///Injects an external CSS file into the WebView from a defined url.
|
||||
|
@ -2082,7 +2109,7 @@ class InAppWebViewController {
|
|||
args.putIfAbsent('urlFile', () => urlFile.toString());
|
||||
args.putIfAbsent(
|
||||
'cssLinkHtmlTagAttributes', () => cssLinkHtmlTagAttributes?.toMap());
|
||||
await _channel.invokeMethod('injectCSSFileFromUrl', args);
|
||||
await _channel?.invokeMethod('injectCSSFileFromUrl', args);
|
||||
}
|
||||
|
||||
///Injects a CSS file into the WebView from the flutter assets directory.
|
||||
|
@ -2164,7 +2191,7 @@ class InAppWebViewController {
|
|||
required JavaScriptHandlerCallback callback}) {
|
||||
assert(!_JAVASCRIPT_HANDLER_FORBIDDEN_NAMES.contains(handlerName),
|
||||
'"$handlerName" is a forbidden name!');
|
||||
this.javaScriptHandlersMap[handlerName] = (callback);
|
||||
this._javaScriptHandlersMap[handlerName] = (callback);
|
||||
}
|
||||
|
||||
///Removes a JavaScript message handler previously added with the [addJavaScriptHandler] associated to [handlerName] key.
|
||||
|
@ -2177,7 +2204,17 @@ class InAppWebViewController {
|
|||
///- MacOS
|
||||
JavaScriptHandlerCallback? removeJavaScriptHandler(
|
||||
{required String handlerName}) {
|
||||
return this.javaScriptHandlersMap.remove(handlerName);
|
||||
return this._javaScriptHandlersMap.remove(handlerName);
|
||||
}
|
||||
|
||||
///Returns `true` if a JavaScript handler with [handlerName] already exists, otherwise `false`.
|
||||
///
|
||||
///**Supported Platforms/Implementations**:
|
||||
///- Android native WebView
|
||||
///- iOS
|
||||
///- MacOS
|
||||
bool hasJavaScriptHandler({required String handlerName}) {
|
||||
return this._javaScriptHandlersMap.containsKey(handlerName);
|
||||
}
|
||||
|
||||
///Takes a screenshot of the WebView's visible viewport and returns a [Uint8List]. Returns `null` if it wasn't be able to take it.
|
||||
|
@ -2197,7 +2234,7 @@ class InAppWebViewController {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent(
|
||||
'screenshotConfiguration', () => screenshotConfiguration?.toMap());
|
||||
return await _channel.invokeMethod('takeScreenshot', args);
|
||||
return await _channel?.invokeMethod('takeScreenshot', args);
|
||||
}
|
||||
|
||||
///Use [setSettings] instead.
|
||||
|
@ -2233,7 +2270,7 @@ class InAppWebViewController {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
|
||||
args.putIfAbsent('settings', () => settings.toMap());
|
||||
await _channel.invokeMethod('setSettings', args);
|
||||
await _channel?.invokeMethod('setSettings', args);
|
||||
}
|
||||
|
||||
///Gets the current WebView settings. Returns `null` if it wasn't able to get them.
|
||||
|
@ -2247,7 +2284,7 @@ class InAppWebViewController {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
|
||||
Map<dynamic, dynamic>? settings =
|
||||
await _channel.invokeMethod('getSettings', args);
|
||||
await _channel?.invokeMethod('getSettings', args);
|
||||
if (settings != null) {
|
||||
settings = settings.cast<String, dynamic>();
|
||||
return InAppWebViewSettings.fromMap(settings as Map<String, dynamic>);
|
||||
|
@ -2268,7 +2305,7 @@ class InAppWebViewController {
|
|||
Future<WebHistory?> getCopyBackForwardList() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
Map<String, dynamic>? result =
|
||||
(await _channel.invokeMethod('getCopyBackForwardList', args))
|
||||
(await _channel?.invokeMethod('getCopyBackForwardList', args))
|
||||
?.cast<String, dynamic>();
|
||||
return WebHistory.fromMap(result);
|
||||
}
|
||||
|
@ -2281,7 +2318,7 @@ class InAppWebViewController {
|
|||
///- MacOS
|
||||
Future<void> clearCache() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('clearCache', args);
|
||||
await _channel?.invokeMethod('clearCache', args);
|
||||
}
|
||||
|
||||
///Use [FindInteractionController.findAll] instead.
|
||||
|
@ -2289,7 +2326,7 @@ class InAppWebViewController {
|
|||
Future<void> findAllAsync({required String find}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('find', () => find);
|
||||
await _channel.invokeMethod('findAll', args);
|
||||
await _channel?.invokeMethod('findAll', args);
|
||||
}
|
||||
|
||||
///Use [FindInteractionController.findNext] instead.
|
||||
|
@ -2297,14 +2334,14 @@ class InAppWebViewController {
|
|||
Future<void> findNext({required bool forward}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('forward', () => forward);
|
||||
await _channel.invokeMethod('findNext', args);
|
||||
await _channel?.invokeMethod('findNext', args);
|
||||
}
|
||||
|
||||
///Use [FindInteractionController.clearMatches] instead.
|
||||
@Deprecated("Use FindInteractionController.clearMatches instead")
|
||||
Future<void> clearMatches() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('clearMatches', args);
|
||||
await _channel?.invokeMethod('clearMatches', args);
|
||||
}
|
||||
|
||||
///Use [tRexRunnerHtml] instead.
|
||||
|
@ -2342,7 +2379,7 @@ class InAppWebViewController {
|
|||
args.putIfAbsent('x', () => x);
|
||||
args.putIfAbsent('y', () => y);
|
||||
args.putIfAbsent('animated', () => animated);
|
||||
await _channel.invokeMethod('scrollTo', args);
|
||||
await _channel?.invokeMethod('scrollTo', args);
|
||||
}
|
||||
|
||||
///Moves the scrolled position of the WebView.
|
||||
|
@ -2368,7 +2405,7 @@ class InAppWebViewController {
|
|||
args.putIfAbsent('x', () => x);
|
||||
args.putIfAbsent('y', () => y);
|
||||
args.putIfAbsent('animated', () => animated);
|
||||
await _channel.invokeMethod('scrollBy', args);
|
||||
await _channel?.invokeMethod('scrollBy', args);
|
||||
}
|
||||
|
||||
///On Android native WebView, it pauses all layout, parsing, and JavaScript timers for all WebViews.
|
||||
|
@ -2384,7 +2421,7 @@ class InAppWebViewController {
|
|||
///- MacOS
|
||||
Future<void> pauseTimers() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('pauseTimers', args);
|
||||
await _channel?.invokeMethod('pauseTimers', args);
|
||||
}
|
||||
|
||||
///On Android, it resumes all layout, parsing, and JavaScript timers for all WebViews. This will resume dispatching all timers.
|
||||
|
@ -2399,7 +2436,7 @@ class InAppWebViewController {
|
|||
///- MacOS
|
||||
Future<void> resumeTimers() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('resumeTimers', args);
|
||||
await _channel?.invokeMethod('resumeTimers', args);
|
||||
}
|
||||
|
||||
///Prints the current page.
|
||||
|
@ -2422,7 +2459,7 @@ class InAppWebViewController {
|
|||
{PrintJobSettings? settings}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent("settings", () => settings?.toMap());
|
||||
String? jobId = await _channel.invokeMethod('printCurrentPage', args);
|
||||
String? jobId = await _channel?.invokeMethod('printCurrentPage', args);
|
||||
if (jobId != null) {
|
||||
return PrintJobController(id: jobId);
|
||||
}
|
||||
|
@ -2442,7 +2479,7 @@ class InAppWebViewController {
|
|||
///- Web ([Official API - Document.documentElement.scrollHeight](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight))
|
||||
Future<int?> getContentHeight() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
var height = await _channel.invokeMethod('getContentHeight', args);
|
||||
var height = await _channel?.invokeMethod('getContentHeight', args);
|
||||
if (height == null || height == 0) {
|
||||
// try to use javascript
|
||||
var scrollHeight = await evaluateJavascript(
|
||||
|
@ -2469,7 +2506,7 @@ class InAppWebViewController {
|
|||
///- Web ([Official API - Document.documentElement.scrollWidth](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollWidth))
|
||||
Future<int?> getContentWidth() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
var height = await _channel.invokeMethod('getContentWidth', args);
|
||||
var height = await _channel?.invokeMethod('getContentWidth', args);
|
||||
if (height == null || height == 0) {
|
||||
// try to use javascript
|
||||
var scrollHeight = await evaluateJavascript(
|
||||
|
@ -2503,7 +2540,7 @@ class InAppWebViewController {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('zoomFactor', () => zoomFactor);
|
||||
args.putIfAbsent('animated', () => iosAnimated ?? animated);
|
||||
return await _channel.invokeMethod('zoomBy', args);
|
||||
return await _channel?.invokeMethod('zoomBy', args);
|
||||
}
|
||||
|
||||
///Gets the URL that was originally requested for the current page.
|
||||
|
@ -2519,7 +2556,7 @@ class InAppWebViewController {
|
|||
///- Web
|
||||
Future<WebUri?> getOriginalUrl() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
String? url = await _channel.invokeMethod('getOriginalUrl', args);
|
||||
String? url = await _channel?.invokeMethod('getOriginalUrl', args);
|
||||
return url != null ? WebUri(url) : null;
|
||||
}
|
||||
|
||||
|
@ -2530,7 +2567,7 @@ class InAppWebViewController {
|
|||
///- iOS ([Official API - UIScrollView.zoomScale](https://developer.apple.com/documentation/uikit/uiscrollview/1619419-zoomscale))
|
||||
Future<double?> getZoomScale() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('getZoomScale', args);
|
||||
return await _channel?.invokeMethod('getZoomScale', args);
|
||||
}
|
||||
|
||||
///Use [getZoomScale] instead.
|
||||
|
@ -2554,7 +2591,7 @@ class InAppWebViewController {
|
|||
///- Web
|
||||
Future<String?> getSelectedText() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('getSelectedText', args);
|
||||
return await _channel?.invokeMethod('getSelectedText', args);
|
||||
}
|
||||
|
||||
///Gets the hit result for hitting an HTML elements.
|
||||
|
@ -2567,7 +2604,7 @@ class InAppWebViewController {
|
|||
Future<InAppWebViewHitTestResult?> getHitTestResult() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
Map<dynamic, dynamic>? hitTestResultMap =
|
||||
await _channel.invokeMethod('getHitTestResult', args);
|
||||
await _channel?.invokeMethod('getHitTestResult', args);
|
||||
|
||||
if (hitTestResultMap == null) {
|
||||
return null;
|
||||
|
@ -2589,7 +2626,7 @@ class InAppWebViewController {
|
|||
///- iOS ([Official API - UIResponder.resignFirstResponder](https://developer.apple.com/documentation/uikit/uiresponder/1621097-resignfirstresponder))
|
||||
Future<void> clearFocus() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('clearFocus', args);
|
||||
return await _channel?.invokeMethod('clearFocus', args);
|
||||
}
|
||||
|
||||
///Sets or updates the WebView context menu to be used next time it will appear.
|
||||
|
@ -2600,7 +2637,7 @@ class InAppWebViewController {
|
|||
Future<void> setContextMenu(ContextMenu? contextMenu) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent("contextMenu", () => contextMenu?.toMap());
|
||||
await _channel.invokeMethod('setContextMenu', args);
|
||||
await _channel?.invokeMethod('setContextMenu', args);
|
||||
_inAppBrowser?.contextMenu = contextMenu;
|
||||
}
|
||||
|
||||
|
@ -2614,7 +2651,7 @@ class InAppWebViewController {
|
|||
Future<RequestFocusNodeHrefResult?> requestFocusNodeHref() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
Map<dynamic, dynamic>? result =
|
||||
await _channel.invokeMethod('requestFocusNodeHref', args);
|
||||
await _channel?.invokeMethod('requestFocusNodeHref', args);
|
||||
return result != null
|
||||
? RequestFocusNodeHrefResult(
|
||||
url: result['url'] != null ? WebUri(result['url']) : null,
|
||||
|
@ -2634,7 +2671,7 @@ class InAppWebViewController {
|
|||
Future<RequestImageRefResult?> requestImageRef() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
Map<dynamic, dynamic>? result =
|
||||
await _channel.invokeMethod('requestImageRef', args);
|
||||
await _channel?.invokeMethod('requestImageRef', args);
|
||||
return result != null
|
||||
? RequestImageRefResult(
|
||||
url: result['url'] != null ? WebUri(result['url']) : null,
|
||||
|
@ -2730,7 +2767,7 @@ class InAppWebViewController {
|
|||
try {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
themeColor = UtilColor.fromStringRepresentation(
|
||||
await _channel.invokeMethod('getMetaThemeColor', args));
|
||||
await _channel?.invokeMethod('getMetaThemeColor', args));
|
||||
return themeColor;
|
||||
} catch (e) {
|
||||
// not implemented
|
||||
|
@ -2773,7 +2810,7 @@ class InAppWebViewController {
|
|||
///- Web ([Official API - Window.scrollX](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollX))
|
||||
Future<int?> getScrollX() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('getScrollX', args);
|
||||
return await _channel?.invokeMethod('getScrollX', args);
|
||||
}
|
||||
|
||||
///Returns the scrolled top position of the current WebView.
|
||||
|
@ -2789,7 +2826,7 @@ class InAppWebViewController {
|
|||
///- Web ([Official API - Window.scrollY](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY))
|
||||
Future<int?> getScrollY() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('getScrollY', args);
|
||||
return await _channel?.invokeMethod('getScrollY', args);
|
||||
}
|
||||
|
||||
///Gets the SSL certificate for the main top-level page or null if there is no certificate (the site is not secure).
|
||||
|
@ -2801,7 +2838,7 @@ class InAppWebViewController {
|
|||
Future<SslCertificate?> getCertificate() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
Map<String, dynamic>? sslCertificateMap =
|
||||
(await _channel.invokeMethod('getCertificate', args))
|
||||
(await _channel?.invokeMethod('getCertificate', args))
|
||||
?.cast<String, dynamic>();
|
||||
return SslCertificate.fromMap(sslCertificateMap);
|
||||
}
|
||||
|
@ -2824,7 +2861,7 @@ class InAppWebViewController {
|
|||
if (!(_userScripts[userScript.injectionTime]?.contains(userScript) ??
|
||||
false)) {
|
||||
_userScripts[userScript.injectionTime]?.add(userScript);
|
||||
await _channel.invokeMethod('addUserScript', args);
|
||||
await _channel?.invokeMethod('addUserScript', args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2870,7 +2907,7 @@ class InAppWebViewController {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('userScript', () => userScript.toMap());
|
||||
args.putIfAbsent('index', () => index);
|
||||
await _channel.invokeMethod('removeUserScript', args);
|
||||
await _channel?.invokeMethod('removeUserScript', args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -2907,7 +2944,7 @@ class InAppWebViewController {
|
|||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('groupName', () => groupName);
|
||||
await _channel.invokeMethod('removeUserScriptsByGroupName', args);
|
||||
await _channel?.invokeMethod('removeUserScriptsByGroupName', args);
|
||||
}
|
||||
|
||||
///Removes the [userScripts] from the webpage’s content.
|
||||
|
@ -2947,7 +2984,18 @@ class InAppWebViewController {
|
|||
_userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.clear();
|
||||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('removeAllUserScripts', args);
|
||||
await _channel?.invokeMethod('removeAllUserScripts', args);
|
||||
}
|
||||
|
||||
///Returns `true` if the [userScript] has been already added, otherwise `false`.
|
||||
///
|
||||
///**Supported Platforms/Implementations**:
|
||||
///- Android native WebView
|
||||
///- iOS
|
||||
///- MacOS
|
||||
bool hasUserScript({required UserScript userScript}) {
|
||||
return _userScripts[userScript.injectionTime]?.contains(userScript) ??
|
||||
false;
|
||||
}
|
||||
|
||||
///Executes the specified string as an asynchronous JavaScript function.
|
||||
|
@ -2991,7 +3039,7 @@ class InAppWebViewController {
|
|||
args.putIfAbsent('functionBody', () => functionBody);
|
||||
args.putIfAbsent('arguments', () => arguments);
|
||||
args.putIfAbsent('contentWorld', () => contentWorld?.toMap());
|
||||
var data = await _channel.invokeMethod('callAsyncJavaScript', args);
|
||||
var data = await _channel?.invokeMethod('callAsyncJavaScript', args);
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -3034,7 +3082,7 @@ class InAppWebViewController {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent("filePath", () => filePath);
|
||||
args.putIfAbsent("autoname", () => autoname);
|
||||
return await _channel.invokeMethod('saveWebArchive', args);
|
||||
return await _channel?.invokeMethod('saveWebArchive', args);
|
||||
}
|
||||
|
||||
///Indicates whether the webpage context is capable of using features that require [secure contexts](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts).
|
||||
|
@ -3051,7 +3099,7 @@ class InAppWebViewController {
|
|||
///- Web ([Official API - Window.isSecureContext](https://developer.mozilla.org/en-US/docs/Web/API/Window/isSecureContext))
|
||||
Future<bool> isSecureContext() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('isSecureContext', args);
|
||||
return await _channel?.invokeMethod('isSecureContext', args);
|
||||
}
|
||||
|
||||
///Creates a message channel to communicate with JavaScript and returns the message channel with ports that represent the endpoints of this message channel.
|
||||
|
@ -3074,7 +3122,7 @@ class InAppWebViewController {
|
|||
Future<WebMessageChannel?> createWebMessageChannel() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
Map<String, dynamic>? result =
|
||||
(await _channel.invokeMethod('createWebMessageChannel', args))
|
||||
(await _channel?.invokeMethod('createWebMessageChannel', args))
|
||||
?.cast<String, dynamic>();
|
||||
return WebMessageChannel.fromMap(result);
|
||||
}
|
||||
|
@ -3102,7 +3150,7 @@ class InAppWebViewController {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('message', () => message.toMap());
|
||||
args.putIfAbsent('targetOrigin', () => targetOrigin.toString());
|
||||
await _channel.invokeMethod('postWebMessage', args);
|
||||
await _channel?.invokeMethod('postWebMessage', args);
|
||||
}
|
||||
|
||||
///Adds a [WebMessageListener] to the WebView and injects a JavaScript object into each frame that the [WebMessageListener] will listen on.
|
||||
|
@ -3278,7 +3326,18 @@ class InAppWebViewController {
|
|||
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('webMessageListener', () => webMessageListener.toMap());
|
||||
await _channel.invokeMethod('addWebMessageListener', args);
|
||||
await _channel?.invokeMethod('addWebMessageListener', args);
|
||||
}
|
||||
|
||||
///Returns `true` if the [webMessageListener] has been already added, otherwise `false`.
|
||||
///
|
||||
///**Supported Platforms/Implementations**:
|
||||
///- Android native WebView
|
||||
///- iOS
|
||||
///- MacOS
|
||||
bool hasWebMessageListener(WebMessageListener webMessageListener) {
|
||||
return _webMessageListenerObjNames
|
||||
.contains(webMessageListener.jsObjectName);
|
||||
}
|
||||
|
||||
///Returns `true` if the webpage can scroll vertically, otherwise `false`.
|
||||
|
@ -3294,7 +3353,7 @@ class InAppWebViewController {
|
|||
///- Web
|
||||
Future<bool> canScrollVertically() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('canScrollVertically', args);
|
||||
return await _channel?.invokeMethod('canScrollVertically', args);
|
||||
}
|
||||
|
||||
///Returns `true` if the webpage can scroll horizontally, otherwise `false`.
|
||||
|
@ -3310,7 +3369,7 @@ class InAppWebViewController {
|
|||
///- Web
|
||||
Future<bool> canScrollHorizontally() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('canScrollHorizontally', args);
|
||||
return await _channel?.invokeMethod('canScrollHorizontally', args);
|
||||
}
|
||||
|
||||
///Starts Safe Browsing initialization.
|
||||
|
@ -3327,7 +3386,7 @@ class InAppWebViewController {
|
|||
///- Android native WebView ([Official API - WebView.startSafeBrowsing](https://developer.android.com/reference/android/webkit/WebView#startSafeBrowsing(android.content.Context,%20android.webkit.ValueCallback%3Cjava.lang.Boolean%3E)))
|
||||
Future<bool> startSafeBrowsing() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('startSafeBrowsing', args);
|
||||
return await _channel?.invokeMethod('startSafeBrowsing', args);
|
||||
}
|
||||
|
||||
///Clears the SSL preferences table stored in response to proceeding with SSL certificate errors.
|
||||
|
@ -3336,7 +3395,7 @@ class InAppWebViewController {
|
|||
///- Android native WebView ([Official API - WebView.clearSslPreferences](https://developer.android.com/reference/android/webkit/WebView#clearSslPreferences()))
|
||||
Future<void> clearSslPreferences() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('clearSslPreferences', args);
|
||||
await _channel?.invokeMethod('clearSslPreferences', args);
|
||||
}
|
||||
|
||||
///Does a best-effort attempt to pause any processing that can be paused safely, such as animations and geolocation. Note that this call does not pause JavaScript.
|
||||
|
@ -3346,7 +3405,7 @@ class InAppWebViewController {
|
|||
///- Android native WebView ([Official API - WebView.onPause](https://developer.android.com/reference/android/webkit/WebView#onPause()))
|
||||
Future<void> pause() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('pause', args);
|
||||
await _channel?.invokeMethod('pause', args);
|
||||
}
|
||||
|
||||
///Resumes a WebView after a previous call to [pause].
|
||||
|
@ -3355,7 +3414,7 @@ class InAppWebViewController {
|
|||
///- Android native WebView ([Official API - WebView.onResume](https://developer.android.com/reference/android/webkit/WebView#onResume()))
|
||||
Future<void> resume() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('resume', args);
|
||||
await _channel?.invokeMethod('resume', args);
|
||||
}
|
||||
|
||||
///Scrolls the contents of this WebView down by half the page size.
|
||||
|
@ -3368,7 +3427,7 @@ class InAppWebViewController {
|
|||
Future<bool> pageDown({required bool bottom}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent("bottom", () => bottom);
|
||||
return await _channel.invokeMethod('pageDown', args);
|
||||
return await _channel?.invokeMethod('pageDown', args);
|
||||
}
|
||||
|
||||
///Scrolls the contents of this WebView up by half the view size.
|
||||
|
@ -3381,7 +3440,7 @@ class InAppWebViewController {
|
|||
Future<bool> pageUp({required bool top}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent("top", () => top);
|
||||
return await _channel.invokeMethod('pageUp', args);
|
||||
return await _channel?.invokeMethod('pageUp', args);
|
||||
}
|
||||
|
||||
///Performs zoom in in this WebView.
|
||||
|
@ -3391,7 +3450,7 @@ class InAppWebViewController {
|
|||
///- Android native WebView ([Official API - WebView.zoomIn](https://developer.android.com/reference/android/webkit/WebView#zoomIn()))
|
||||
Future<bool> zoomIn() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('zoomIn', args);
|
||||
return await _channel?.invokeMethod('zoomIn', args);
|
||||
}
|
||||
|
||||
///Performs zoom out in this WebView.
|
||||
|
@ -3401,7 +3460,7 @@ class InAppWebViewController {
|
|||
///- Android native WebView ([Official API - WebView.zoomOut](https://developer.android.com/reference/android/webkit/WebView#zoomOut()))
|
||||
Future<bool> zoomOut() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('zoomOut', args);
|
||||
return await _channel?.invokeMethod('zoomOut', args);
|
||||
}
|
||||
|
||||
///Clears the internal back/forward list.
|
||||
|
@ -3410,7 +3469,7 @@ class InAppWebViewController {
|
|||
///- Android native WebView ([Official API - WebView.clearHistory](https://developer.android.com/reference/android/webkit/WebView#clearHistory()))
|
||||
Future<void> clearHistory() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('clearHistory', args);
|
||||
return await _channel?.invokeMethod('clearHistory', args);
|
||||
}
|
||||
|
||||
///Reloads the current page, performing end-to-end revalidation using cache-validating conditionals if possible.
|
||||
|
@ -3420,7 +3479,7 @@ class InAppWebViewController {
|
|||
///- MacOS ([Official API - WKWebView.reloadFromOrigin](https://developer.apple.com/documentation/webkit/wkwebview/1414956-reloadfromorigin))
|
||||
Future<void> reloadFromOrigin() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('reloadFromOrigin', args);
|
||||
await _channel?.invokeMethod('reloadFromOrigin', args);
|
||||
}
|
||||
|
||||
///Generates PDF data from the web view’s contents asynchronously.
|
||||
|
@ -3443,7 +3502,7 @@ class InAppWebViewController {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('pdfConfiguration',
|
||||
() => pdfConfiguration?.toMap() ?? iosWKPdfConfiguration?.toMap());
|
||||
return await _channel.invokeMethod('createPdf', args);
|
||||
return await _channel?.invokeMethod('createPdf', args);
|
||||
}
|
||||
|
||||
///Creates a web archive of the web view’s current contents asynchronously.
|
||||
|
@ -3458,7 +3517,7 @@ class InAppWebViewController {
|
|||
///- MacOS ([Official API - WKWebView.createWebArchiveData](https://developer.apple.com/documentation/webkit/wkwebview/3650491-createwebarchivedata))
|
||||
Future<Uint8List?> createWebArchiveData() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('createWebArchiveData', args);
|
||||
return await _channel?.invokeMethod('createWebArchiveData', args);
|
||||
}
|
||||
|
||||
///A Boolean value indicating whether all resources on the page have been loaded over securely encrypted connections.
|
||||
|
@ -3468,7 +3527,7 @@ class InAppWebViewController {
|
|||
///- MacOS ([Official API - WKWebView.hasOnlySecureContent](https://developer.apple.com/documentation/webkit/wkwebview/1415002-hasonlysecurecontent))
|
||||
Future<bool> hasOnlySecureContent() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('hasOnlySecureContent', args);
|
||||
return await _channel?.invokeMethod('hasOnlySecureContent', args);
|
||||
}
|
||||
|
||||
///Pauses playback of all media in the web view.
|
||||
|
@ -3482,7 +3541,7 @@ class InAppWebViewController {
|
|||
///- MacOS ([Official API - WKWebView.pauseAllMediaPlayback](https://developer.apple.com/documentation/webkit/wkwebview/3752240-pauseallmediaplayback)).
|
||||
Future<void> pauseAllMediaPlayback() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('pauseAllMediaPlayback', args);
|
||||
return await _channel?.invokeMethod('pauseAllMediaPlayback', args);
|
||||
}
|
||||
|
||||
///Changes whether the webpage is suspending playback of all media in the page.
|
||||
|
@ -3500,7 +3559,7 @@ class InAppWebViewController {
|
|||
Future<void> setAllMediaPlaybackSuspended({required bool suspended}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent("suspended", () => suspended);
|
||||
return await _channel.invokeMethod('setAllMediaPlaybackSuspended', args);
|
||||
return await _channel?.invokeMethod('setAllMediaPlaybackSuspended', args);
|
||||
}
|
||||
|
||||
///Closes all media the web view is presenting, including picture-in-picture video and fullscreen video.
|
||||
|
@ -3514,7 +3573,7 @@ class InAppWebViewController {
|
|||
///- MacOS ([Official API - WKWebView.closeAllMediaPresentations](https://developer.apple.com/documentation/webkit/wkwebview/3752235-closeallmediapresentations)).
|
||||
Future<void> closeAllMediaPresentations() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('closeAllMediaPresentations', args);
|
||||
return await _channel?.invokeMethod('closeAllMediaPresentations', args);
|
||||
}
|
||||
|
||||
///Requests the playback status of media in the web view.
|
||||
|
@ -3531,7 +3590,7 @@ class InAppWebViewController {
|
|||
Future<MediaPlaybackState?> requestMediaPlaybackState() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return MediaPlaybackState.fromNativeValue(
|
||||
await _channel.invokeMethod('requestMediaPlaybackState', args));
|
||||
await _channel?.invokeMethod('requestMediaPlaybackState', args));
|
||||
}
|
||||
|
||||
///Returns `true` if the [WebView] is in fullscreen mode, otherwise `false`.
|
||||
|
@ -3542,7 +3601,7 @@ class InAppWebViewController {
|
|||
///- MacOS
|
||||
Future<bool> isInFullscreen() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('isInFullscreen', args);
|
||||
return await _channel?.invokeMethod('isInFullscreen', args);
|
||||
}
|
||||
|
||||
///Returns a [MediaCaptureState] that indicates whether the webpage is using the camera to capture images or video.
|
||||
|
@ -3557,7 +3616,7 @@ class InAppWebViewController {
|
|||
Future<MediaCaptureState?> getCameraCaptureState() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return MediaCaptureState.fromNativeValue(
|
||||
await _channel.invokeMethod('getCameraCaptureState', args));
|
||||
await _channel?.invokeMethod('getCameraCaptureState', args));
|
||||
}
|
||||
|
||||
///Changes whether the webpage is using the camera to capture images or video.
|
||||
|
@ -3572,7 +3631,7 @@ class InAppWebViewController {
|
|||
Future<void> setCameraCaptureState({required MediaCaptureState state}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('state', () => state.toNativeValue());
|
||||
await _channel.invokeMethod('setCameraCaptureState', args);
|
||||
await _channel?.invokeMethod('setCameraCaptureState', args);
|
||||
}
|
||||
|
||||
///Returns a [MediaCaptureState] that indicates whether the webpage is using the microphone to capture audio.
|
||||
|
@ -3587,7 +3646,7 @@ class InAppWebViewController {
|
|||
Future<MediaCaptureState?> getMicrophoneCaptureState() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return MediaCaptureState.fromNativeValue(
|
||||
await _channel.invokeMethod('getMicrophoneCaptureState', args));
|
||||
await _channel?.invokeMethod('getMicrophoneCaptureState', args));
|
||||
}
|
||||
|
||||
///Changes whether the webpage is using the microphone to capture audio.
|
||||
|
@ -3603,7 +3662,7 @@ class InAppWebViewController {
|
|||
{required MediaCaptureState state}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('state', () => state.toNativeValue());
|
||||
await _channel.invokeMethod('setMicrophoneCaptureState', args);
|
||||
await _channel?.invokeMethod('setMicrophoneCaptureState', args);
|
||||
}
|
||||
|
||||
///Loads the web content from the data you provide as if the data were the response to the request.
|
||||
|
@ -3639,7 +3698,7 @@ class InAppWebViewController {
|
|||
args.putIfAbsent('urlRequest', () => urlRequest.toMap());
|
||||
args.putIfAbsent('data', () => data);
|
||||
args.putIfAbsent('urlResponse', () => urlResponse?.toMap());
|
||||
await _channel.invokeMethod('loadSimulatedRequest', args);
|
||||
await _channel?.invokeMethod('loadSimulatedRequest', args);
|
||||
}
|
||||
|
||||
///Returns the iframe `id` attribute used on the Web platform.
|
||||
|
@ -3648,7 +3707,7 @@ class InAppWebViewController {
|
|||
///- Web
|
||||
Future<String?> getIFrameId() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('getIFrameId', args);
|
||||
return await _channel?.invokeMethod('getIFrameId', args);
|
||||
}
|
||||
|
||||
///Gets the default user agent.
|
||||
|
@ -3812,6 +3871,19 @@ class InAppWebViewController {
|
|||
return await _staticChannel.invokeMethod('handlesURLScheme', args);
|
||||
}
|
||||
|
||||
///Disposes the WebView that is using the [keepAlive] instance
|
||||
///for the keep alive feature.
|
||||
///
|
||||
///**Supported Platforms/Implementations**:
|
||||
///- Android native WebView
|
||||
///- iOS
|
||||
static Future<void> disposeKeepAlive(InAppWebViewKeepAlive keepAlive) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('keepAliveId', () => keepAlive.id);
|
||||
await _staticChannel.invokeMethod('disposeKeepAlive', args);
|
||||
_keepAliveMap[keepAlive] = null;
|
||||
}
|
||||
|
||||
///Gets the html (with javascript) of the Chromium's t-rex runner game. Used in combination with [tRexRunnerCss].
|
||||
///
|
||||
///**Supported Platforms/Implementations**:
|
||||
|
@ -3831,7 +3903,7 @@ class InAppWebViewController {
|
|||
'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.css');
|
||||
|
||||
///Used internally.
|
||||
MethodChannel getChannel() {
|
||||
MethodChannel? getChannel() {
|
||||
return _channel;
|
||||
}
|
||||
|
||||
|
@ -3839,4 +3911,23 @@ class InAppWebViewController {
|
|||
dynamic getViewId() {
|
||||
return _id;
|
||||
}
|
||||
|
||||
///Disposes the controller.
|
||||
void dispose({bool isKeepAlive = false}) {
|
||||
if (!isKeepAlive) {
|
||||
_channel?.setMethodCallHandler(null);
|
||||
}
|
||||
android.dispose();
|
||||
ios.dispose();
|
||||
_channel = null;
|
||||
_webview = null;
|
||||
_inAppBrowser = null;
|
||||
webStorage.dispose();
|
||||
if (!isKeepAlive) {
|
||||
_javaScriptHandlersMap.clear();
|
||||
_userScripts.clear();
|
||||
_webMessageListenerObjNames.clear();
|
||||
_injectedScriptsFromURL.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import '../types/main.dart';
|
||||
import '../util.dart';
|
||||
import 'in_app_webview.dart';
|
||||
import 'in_app_webview_controller.dart';
|
||||
|
||||
///Class used to keep alive a [InAppWebView].
|
||||
class InAppWebViewKeepAlive {
|
||||
String _id = IdGenerator.generate();
|
||||
}
|
||||
|
||||
///Used internally
|
||||
extension InternalInAppWebViewKeepAlive on InAppWebViewKeepAlive {
|
||||
set id(String id) {
|
||||
_id = id;
|
||||
}
|
||||
|
||||
String get id => _id;
|
||||
}
|
||||
|
||||
///Used internally to save and restore [InAppWebViewController] properties
|
||||
///for the keep alive feature.
|
||||
class InAppWebViewControllerKeepAliveProps {
|
||||
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap;
|
||||
Map<UserScriptInjectionTime, List<UserScript>> userScripts;
|
||||
Set<String> webMessageListenerObjNames;
|
||||
Map<String, ScriptHtmlTagAttributes> injectedScriptsFromURL;
|
||||
|
||||
InAppWebViewControllerKeepAliveProps(
|
||||
{required this.javaScriptHandlersMap,
|
||||
required this.userScripts,
|
||||
required this.webMessageListenerObjNames,
|
||||
required this.injectedScriptsFromURL});
|
||||
}
|
|
@ -11,3 +11,4 @@ export 'headless_in_app_webview.dart' hide InternalHeadlessInAppWebView;
|
|||
export 'android/main.dart';
|
||||
export 'apple/main.dart';
|
||||
export '../find_interaction/find_interaction_controller.dart';
|
||||
export 'in_app_webview_keep_alive.dart' show InAppWebViewKeepAlive;
|
||||
|
|
|
@ -1191,12 +1191,6 @@ abstract class WebView {
|
|||
///{@endtemplate}
|
||||
final FindInteractionController? findInteractionController;
|
||||
|
||||
///{@template flutter_inappwebview.WebView.implementation}
|
||||
///Represents the WebView native implementation to be used.
|
||||
///The default value is [WebViewImplementation.NATIVE].
|
||||
///{@endtemplate}
|
||||
final WebViewImplementation implementation;
|
||||
|
||||
///{@macro flutter_inappwebview.WebView}
|
||||
WebView(
|
||||
{this.windowId,
|
||||
|
@ -1314,6 +1308,5 @@ abstract class WebView {
|
|||
this.contextMenu,
|
||||
this.initialUserScripts,
|
||||
this.pullToRefreshController,
|
||||
this.findInteractionController,
|
||||
this.implementation = WebViewImplementation.NATIVE});
|
||||
this.findInteractionController});
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ class PrintJobController implements Disposable {
|
|||
///Print job ID.
|
||||
final String id;
|
||||
|
||||
late MethodChannel _channel;
|
||||
MethodChannel? _channel;
|
||||
|
||||
///A completion handler used to handle the conclusion of the print job (for instance, to reset state) and to handle any errors encountered in printing.
|
||||
///
|
||||
|
@ -29,7 +29,7 @@ class PrintJobController implements Disposable {
|
|||
PrintJobController({required this.id}) {
|
||||
this._channel = MethodChannel(
|
||||
'com.pichillilorenzo/flutter_inappwebview_printjobcontroller_$id');
|
||||
this._channel.setMethodCallHandler((call) async {
|
||||
this._channel?.setMethodCallHandler((call) async {
|
||||
try {
|
||||
return await _handleMethod(call);
|
||||
} on Error catch (e) {
|
||||
|
@ -60,7 +60,7 @@ class PrintJobController implements Disposable {
|
|||
///- Android native WebView ([Official API - PrintJob.cancel](https://developer.android.com/reference/android/print/PrintJob#cancel()))
|
||||
Future<void> cancel() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('cancel', args);
|
||||
await _channel?.invokeMethod('cancel', args);
|
||||
}
|
||||
|
||||
///Restarts this print job.
|
||||
|
@ -70,7 +70,7 @@ class PrintJobController implements Disposable {
|
|||
///- Android native WebView ([Official API - PrintJob.restart](https://developer.android.com/reference/android/print/PrintJob#restart()))
|
||||
Future<void> restart() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('restart', args);
|
||||
await _channel?.invokeMethod('restart', args);
|
||||
}
|
||||
|
||||
///Dismisses the printing-options sheet or popover.
|
||||
|
@ -85,7 +85,7 @@ class PrintJobController implements Disposable {
|
|||
Future<void> dismiss({bool animated: true}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent("animated", () => animated);
|
||||
await _channel.invokeMethod('dismiss', args);
|
||||
await _channel?.invokeMethod('dismiss', args);
|
||||
}
|
||||
|
||||
///Gets the [PrintJobInfo] that describes this job.
|
||||
|
@ -101,7 +101,7 @@ class PrintJobController implements Disposable {
|
|||
Future<PrintJobInfo?> getInfo() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
Map<String, dynamic>? infoMap =
|
||||
(await _channel.invokeMethod('getInfo', args))?.cast<String, dynamic>();
|
||||
(await _channel?.invokeMethod('getInfo', args))?.cast<String, dynamic>();
|
||||
return PrintJobInfo.fromMap(infoMap);
|
||||
}
|
||||
|
||||
|
@ -114,6 +114,8 @@ class PrintJobController implements Disposable {
|
|||
@override
|
||||
Future<void> dispose() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod('dispose', args);
|
||||
await _channel?.invokeMethod('dispose', args);
|
||||
_channel?.setMethodCallHandler(null);
|
||||
_channel = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
export 'pull_to_refresh_controller.dart';
|
||||
export 'pull_to_refresh_controller.dart'
|
||||
show PullToRefreshController;
|
||||
export 'pull_to_refresh_settings.dart'
|
||||
show PullToRefreshSettings, PullToRefreshOptions;
|
||||
|
|
|
@ -44,19 +44,6 @@ class PullToRefreshController {
|
|||
this.settings = settings ?? PullToRefreshSettings();
|
||||
}
|
||||
|
||||
void initMethodChannel(dynamic id) {
|
||||
this._channel = MethodChannel(
|
||||
'com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_$id');
|
||||
this._channel?.setMethodCallHandler((call) async {
|
||||
try {
|
||||
return await _handleMethod(call);
|
||||
} on Error catch (e) {
|
||||
print(e);
|
||||
print(e.stackTrace);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_debugLog(String method, dynamic args) {
|
||||
debugLog(
|
||||
className: this.runtimeType.toString(),
|
||||
|
@ -228,4 +215,28 @@ class PullToRefreshController {
|
|||
args.putIfAbsent('attributedTitle', () => attributedTitle.toMap());
|
||||
await _channel?.invokeMethod('setStyledTitle', args);
|
||||
}
|
||||
|
||||
///Disposes the controller.
|
||||
void dispose({bool isKeepAlive = false}) {
|
||||
if (!isKeepAlive) {
|
||||
_channel?.setMethodCallHandler(null);
|
||||
}
|
||||
_channel = null;
|
||||
}
|
||||
}
|
||||
|
||||
extension InternalPullToRefreshController on PullToRefreshController {
|
||||
void init(dynamic id) {
|
||||
this._channel = MethodChannel(
|
||||
'com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_$id');
|
||||
this._channel?.setMethodCallHandler((call) async {
|
||||
if (_channel == null) return null;
|
||||
try {
|
||||
return await _handleMethod(call);
|
||||
} on Error catch (e) {
|
||||
print(e);
|
||||
print(e.stackTrace);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -198,7 +198,6 @@ export 'web_storage_type.dart' show WebStorageType;
|
|||
export 'website_data_record.dart'
|
||||
show WebsiteDataRecord, IOSWKWebsiteDataRecord;
|
||||
export 'website_data_type.dart' show WebsiteDataType, IOSWKWebsiteDataType;
|
||||
export 'webview_implementation.dart' show WebViewImplementation;
|
||||
export 'webview_package_info.dart'
|
||||
show WebViewPackageInfo, AndroidWebViewPackageInfo;
|
||||
export 'webview_render_process_action.dart' show WebViewRenderProcessAction;
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart';
|
||||
|
||||
import '../in_app_webview/webview.dart';
|
||||
|
||||
part 'webview_implementation.g.dart';
|
||||
|
||||
///Class that represents the [WebView] native implementation to be used.
|
||||
@ExchangeableEnum()
|
||||
class WebViewImplementation_ {
|
||||
// ignore: unused_field
|
||||
final int _value;
|
||||
const WebViewImplementation_._internal(this._value);
|
||||
|
||||
///Default native implementation, such as `WKWebView` for iOS and `android.webkit.WebView` for Android.
|
||||
static const NATIVE = const WebViewImplementation_._internal(0);
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'webview_implementation.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// ExchangeableEnumGenerator
|
||||
// **************************************************************************
|
||||
|
||||
///Class that represents the [WebView] native implementation to be used.
|
||||
class WebViewImplementation {
|
||||
final int _value;
|
||||
final int _nativeValue;
|
||||
const WebViewImplementation._internal(this._value, this._nativeValue);
|
||||
// ignore: unused_element
|
||||
factory WebViewImplementation._internalMultiPlatform(
|
||||
int value, Function nativeValue) =>
|
||||
WebViewImplementation._internal(value, nativeValue());
|
||||
|
||||
///Default native implementation, such as `WKWebView` for iOS and `android.webkit.WebView` for Android.
|
||||
static const NATIVE = WebViewImplementation._internal(0, 0);
|
||||
|
||||
///Set of all values of [WebViewImplementation].
|
||||
static final Set<WebViewImplementation> values = [
|
||||
WebViewImplementation.NATIVE,
|
||||
].toSet();
|
||||
|
||||
///Gets a possible [WebViewImplementation] instance from [int] value.
|
||||
static WebViewImplementation? fromValue(int? value) {
|
||||
if (value != null) {
|
||||
try {
|
||||
return WebViewImplementation.values
|
||||
.firstWhere((element) => element.toValue() == value);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
///Gets a possible [WebViewImplementation] instance from a native value.
|
||||
static WebViewImplementation? fromNativeValue(int? value) {
|
||||
if (value != null) {
|
||||
try {
|
||||
return WebViewImplementation.values
|
||||
.firstWhere((element) => element.toNativeValue() == value);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
///Gets [int] value.
|
||||
int toValue() => _value;
|
||||
|
||||
///Gets [int] native value.
|
||||
int toNativeValue() => _nativeValue;
|
||||
|
||||
@override
|
||||
int get hashCode => _value.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(value) => value == _value;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
switch (_value) {
|
||||
case 0:
|
||||
return 'NATIVE';
|
||||
}
|
||||
return _value.toString();
|
||||
}
|
||||
}
|
|
@ -56,7 +56,7 @@ class WebAuthenticationSession implements Disposable {
|
|||
///A completion handler the session calls when it completes successfully, or when the user cancels the session.
|
||||
WebAuthenticationSessionCompletionHandler onComplete;
|
||||
|
||||
late MethodChannel _channel;
|
||||
MethodChannel? _channel;
|
||||
static const MethodChannel _sharedChannel = const MethodChannel(
|
||||
'com.pichillilorenzo/flutter_webauthenticationsession');
|
||||
|
||||
|
@ -104,7 +104,7 @@ class WebAuthenticationSession implements Disposable {
|
|||
initialSettings ?? WebAuthenticationSessionSettings();
|
||||
this._channel = MethodChannel(
|
||||
'com.pichillilorenzo/flutter_webauthenticationsession_$id');
|
||||
this._channel.setMethodCallHandler((call) async {
|
||||
this._channel?.setMethodCallHandler((call) async {
|
||||
try {
|
||||
return await _handleMethod(call);
|
||||
} on Error catch (e) {
|
||||
|
@ -147,10 +147,10 @@ class WebAuthenticationSession implements Disposable {
|
|||
///- iOS ([Official API - ASWebAuthenticationSession.canStart](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/3516277-canstart))
|
||||
Future<bool> canStart() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('canStart', args);
|
||||
return await _channel?.invokeMethod('canStart', args);
|
||||
}
|
||||
|
||||
///Starts a web authentication session.
|
||||
///Starts the web authentication session.
|
||||
///
|
||||
///Returns a boolean value indicating whether the web authentication session started successfully.
|
||||
///
|
||||
|
@ -161,10 +161,10 @@ class WebAuthenticationSession implements Disposable {
|
|||
///- iOS ([Official API - ASWebAuthenticationSession.start](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990953-start))
|
||||
Future<bool> start() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('start', args);
|
||||
return await _channel?.invokeMethod('start', args);
|
||||
}
|
||||
|
||||
///Cancels a web authentication session.
|
||||
///Cancels the web authentication session.
|
||||
///
|
||||
///If the session has already presented a view with the authentication webpage, calling this method dismisses that view.
|
||||
///Calling [cancel] on an already canceled session has no effect.
|
||||
|
@ -173,17 +173,19 @@ class WebAuthenticationSession implements Disposable {
|
|||
///- iOS ([Official API - ASWebAuthenticationSession.cancel](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990951-cancel))
|
||||
Future<void> cancel() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod("cancel", args);
|
||||
await _channel?.invokeMethod("cancel", args);
|
||||
}
|
||||
|
||||
///Disposes a web authentication session.
|
||||
///Disposes the web authentication session.
|
||||
///
|
||||
///**Supported Platforms/Implementations**:
|
||||
///- iOS
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
await _channel.invokeMethod("dispose", args);
|
||||
await _channel?.invokeMethod("dispose", args);
|
||||
_channel?.setMethodCallHandler(null);
|
||||
_channel = null;
|
||||
}
|
||||
|
||||
///Returns `true` if [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession)
|
||||
|
|
|
@ -18,13 +18,13 @@ class WebMessageChannel {
|
|||
///The second [WebMessagePort] object of the channel.
|
||||
final WebMessagePort port2;
|
||||
|
||||
late MethodChannel _channel;
|
||||
MethodChannel? _channel;
|
||||
|
||||
WebMessageChannel(
|
||||
{required this.id, required this.port1, required this.port2}) {
|
||||
this._channel = MethodChannel(
|
||||
'com.pichillilorenzo/flutter_inappwebview_web_message_channel_$id');
|
||||
this._channel.setMethodCallHandler((call) async {
|
||||
this._channel?.setMethodCallHandler((call) async {
|
||||
try {
|
||||
return await _handleMethod(call);
|
||||
} on Error catch (e) {
|
||||
|
@ -97,7 +97,7 @@ class WebMessagePort {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('index', () => this._index);
|
||||
await _webMessageChannel._channel
|
||||
.invokeMethod('setWebMessageCallback', args);
|
||||
?.invokeMethod('setWebMessageCallback', args);
|
||||
this._onMessage = onMessage;
|
||||
}
|
||||
|
||||
|
@ -106,14 +106,14 @@ class WebMessagePort {
|
|||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('index', () => this._index);
|
||||
args.putIfAbsent('message', () => message.toMap());
|
||||
await _webMessageChannel._channel.invokeMethod('postMessage', args);
|
||||
await _webMessageChannel._channel?.invokeMethod('postMessage', args);
|
||||
}
|
||||
|
||||
///Close the message port and free any resources associated with it.
|
||||
Future<void> close() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('index', () => this._index);
|
||||
await _webMessageChannel._channel.invokeMethod('close', args);
|
||||
await _webMessageChannel._channel?.invokeMethod('close', args);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
|
|
|
@ -34,7 +34,7 @@ class WebMessageListener {
|
|||
///**Official Android API**: https://developer.android.com/reference/androidx/webkit/WebViewCompat.WebMessageListener#onPostMessage(android.webkit.WebView,%20androidx.webkit.WebMessageCompat,%20android.net.Uri,%20boolean,%20androidx.webkit.JavaScriptReplyProxy)
|
||||
OnPostMessageCallback? onPostMessage;
|
||||
|
||||
late MethodChannel _channel;
|
||||
MethodChannel? _channel;
|
||||
|
||||
WebMessageListener(
|
||||
{required this.jsObjectName,
|
||||
|
@ -47,7 +47,7 @@ class WebMessageListener {
|
|||
"allowedOriginRules cannot contain empty strings");
|
||||
this._channel = MethodChannel(
|
||||
'com.pichillilorenzo/flutter_inappwebview_web_message_listener_${id}_$jsObjectName');
|
||||
this._channel.setMethodCallHandler((call) async {
|
||||
this._channel?.setMethodCallHandler((call) async {
|
||||
try {
|
||||
return await _handleMethod(call);
|
||||
} on Error catch (e) {
|
||||
|
@ -114,6 +114,6 @@ class JavaScriptReplyProxy {
|
|||
Future<void> postMessage(String message) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('message', () => message);
|
||||
await _webMessageListener._channel.invokeMethod('postMessage', args);
|
||||
await _webMessageListener._channel?.invokeMethod('postMessage', args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,12 @@ class WebStorage {
|
|||
SessionStorage sessionStorage;
|
||||
|
||||
WebStorage({required this.localStorage, required this.sessionStorage});
|
||||
|
||||
///Disposes the web storage.
|
||||
void dispose() {
|
||||
localStorage.dispose();
|
||||
sessionStorage.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
///Class that represents a single web storage item of the JavaScript `window.sessionStorage` and `window.localStorage` objects.
|
||||
|
@ -51,7 +57,7 @@ class WebStorageItem {
|
|||
///Class that provides methods to manage the JavaScript [Storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage) object.
|
||||
///It is used by [LocalStorage] and [SessionStorage].
|
||||
class Storage {
|
||||
late InAppWebViewController _controller;
|
||||
InAppWebViewController? _controller;
|
||||
|
||||
///The web storage type: `window.sessionStorage` or `window.localStorage`.
|
||||
WebStorageType webStorageType;
|
||||
|
@ -69,7 +75,7 @@ class Storage {
|
|||
///- iOS
|
||||
///- Web
|
||||
Future<int?> length() async {
|
||||
var result = await _controller.evaluateJavascript(source: """
|
||||
var result = await _controller?.evaluateJavascript(source: """
|
||||
window.$webStorageType.length;
|
||||
""");
|
||||
return result != null ? int.parse(json.decode(result)) : null;
|
||||
|
@ -85,7 +91,7 @@ class Storage {
|
|||
///- Web
|
||||
Future<void> setItem({required String key, required dynamic value}) async {
|
||||
var encodedValue = json.encode(value);
|
||||
await _controller.evaluateJavascript(source: """
|
||||
await _controller?.evaluateJavascript(source: """
|
||||
window.$webStorageType.setItem("$key", ${value is String ? encodedValue : "JSON.stringify($encodedValue)"});
|
||||
""");
|
||||
}
|
||||
|
@ -99,7 +105,7 @@ class Storage {
|
|||
///- iOS
|
||||
///- Web
|
||||
Future<dynamic> getItem({required String key}) async {
|
||||
var itemValue = await _controller.evaluateJavascript(source: """
|
||||
var itemValue = await _controller?.evaluateJavascript(source: """
|
||||
window.$webStorageType.getItem("$key");
|
||||
""");
|
||||
|
||||
|
@ -123,7 +129,7 @@ class Storage {
|
|||
///- iOS
|
||||
///- Web
|
||||
Future<void> removeItem({required String key}) async {
|
||||
await _controller.evaluateJavascript(source: """
|
||||
await _controller?.evaluateJavascript(source: """
|
||||
window.$webStorageType.removeItem("$key");
|
||||
""");
|
||||
}
|
||||
|
@ -140,7 +146,7 @@ class Storage {
|
|||
var webStorageItems = <WebStorageItem>[];
|
||||
|
||||
List<Map<dynamic, dynamic>>? items =
|
||||
(await _controller.evaluateJavascript(source: """
|
||||
(await _controller?.evaluateJavascript(source: """
|
||||
(function() {
|
||||
var webStorageItems = [];
|
||||
for(var i = 0; i < window.$webStorageType.length; i++){
|
||||
|
@ -177,7 +183,7 @@ class Storage {
|
|||
///- iOS
|
||||
///- Web
|
||||
Future<void> clear() async {
|
||||
await _controller.evaluateJavascript(source: """
|
||||
await _controller?.evaluateJavascript(source: """
|
||||
window.$webStorageType.clear();
|
||||
""");
|
||||
}
|
||||
|
@ -192,11 +198,16 @@ class Storage {
|
|||
///- iOS
|
||||
///- Web
|
||||
Future<String> key({required int index}) async {
|
||||
var result = await _controller.evaluateJavascript(source: """
|
||||
var result = await _controller?.evaluateJavascript(source: """
|
||||
window.$webStorageType.key($index);
|
||||
""");
|
||||
return result != null ? json.decode(result) : null;
|
||||
}
|
||||
|
||||
///Disposes the storage.
|
||||
void dispose() {
|
||||
_controller = null;
|
||||
}
|
||||
}
|
||||
|
||||
///Class that provides methods to manage the JavaScript `window.localStorage` object.
|
||||
|
|
|
@ -11,6 +11,7 @@ import FlutterMacOS
|
|||
public class FindInteractionController : NSObject, Disposable {
|
||||
|
||||
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_find_interaction_";
|
||||
var plugin: InAppWebViewFlutterPlugin?
|
||||
var webView: InAppWebView?
|
||||
var channelDelegate: FindInteractionChannelDelegate?
|
||||
var settings: FindInteractionSettings?
|
||||
|
@ -18,13 +19,16 @@ public class FindInteractionController : NSObject, Disposable {
|
|||
var searchText: String?
|
||||
var activeFindSession: FindSession?
|
||||
|
||||
public init(registrar: FlutterPluginRegistrar, id: Any, webView: InAppWebView, settings: FindInteractionSettings?) {
|
||||
public init(plugin: InAppWebViewFlutterPlugin, id: Any, webView: InAppWebView, settings: FindInteractionSettings?) {
|
||||
super.init()
|
||||
self.plugin = plugin
|
||||
self.webView = webView
|
||||
self.settings = settings
|
||||
let channel = FlutterMethodChannel(name: FindInteractionController.METHOD_CHANNEL_NAME_PREFIX + String(describing: id),
|
||||
binaryMessenger: registrar.messenger)
|
||||
self.channelDelegate = FindInteractionChannelDelegate(findInteractionController: self, channel: channel)
|
||||
if let registrar = plugin.registrar {
|
||||
let channel = FlutterMethodChannel(name: FindInteractionController.METHOD_CHANNEL_NAME_PREFIX + String(describing: id),
|
||||
binaryMessenger: registrar.messenger)
|
||||
self.channelDelegate = FindInteractionChannelDelegate(findInteractionController: self, channel: channel)
|
||||
}
|
||||
}
|
||||
|
||||
public func prepare() {
|
||||
|
@ -87,6 +91,7 @@ public class FindInteractionController : NSObject, Disposable {
|
|||
channelDelegate = nil
|
||||
webView = nil
|
||||
activeFindSession = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -81,7 +81,7 @@ public class HeadlessInAppWebView : Disposable {
|
|||
public func dispose() {
|
||||
channelDelegate?.dispose()
|
||||
channelDelegate = nil
|
||||
HeadlessInAppWebViewManager.webViews[id] = nil
|
||||
plugin?.headlessInAppWebViewManager?.webViews[id] = nil
|
||||
if let view = flutterWebView?.view() {
|
||||
view.superview?.removeFromSuperview()
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import AVFoundation
|
|||
public class HeadlessInAppWebViewManager: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview"
|
||||
var plugin: InAppWebViewFlutterPlugin?
|
||||
static var webViews: [String: HeadlessInAppWebView?] = [:]
|
||||
var webViews: [String: HeadlessInAppWebView?] = [:]
|
||||
|
||||
init(plugin: InAppWebViewFlutterPlugin) {
|
||||
super.init(channel: FlutterMethodChannel(name: HeadlessInAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger))
|
||||
|
@ -40,15 +40,15 @@ public class HeadlessInAppWebViewManager: ChannelDelegate {
|
|||
}
|
||||
|
||||
public func run(id: String, params: [String: Any?]) {
|
||||
guard let plugin = plugin, let registrar = plugin.registrar else {
|
||||
guard let plugin = plugin else {
|
||||
return
|
||||
}
|
||||
let flutterWebView = FlutterWebViewController(registrar: registrar,
|
||||
let flutterWebView = FlutterWebViewController(plugin: plugin,
|
||||
withFrame: CGRect.zero,
|
||||
viewIdentifier: id,
|
||||
params: params as NSDictionary)
|
||||
let headlessInAppWebView = HeadlessInAppWebView(plugin: plugin, id: id, flutterWebView: flutterWebView)
|
||||
HeadlessInAppWebViewManager.webViews[id] = headlessInAppWebView
|
||||
webViews[id] = headlessInAppWebView
|
||||
|
||||
headlessInAppWebView.prepare(params: params as NSDictionary)
|
||||
headlessInAppWebView.onWebViewCreated()
|
||||
|
@ -57,11 +57,11 @@ public class HeadlessInAppWebViewManager: ChannelDelegate {
|
|||
|
||||
public override func dispose() {
|
||||
super.dispose()
|
||||
let headlessWebViews = HeadlessInAppWebViewManager.webViews.values
|
||||
let headlessWebViews = webViews.values
|
||||
headlessWebViews.forEach { (headlessWebView: HeadlessInAppWebView?) in
|
||||
headlessWebView?.dispose()
|
||||
}
|
||||
HeadlessInAppWebViewManager.webViews.removeAll()
|
||||
webViews.removeAll()
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ public class InAppBrowserWebViewController: NSViewController, InAppBrowserDelega
|
|||
var isHidden = false
|
||||
|
||||
public override func loadView() {
|
||||
guard let registrar = plugin?.registrar else {
|
||||
guard let plugin = plugin, let registrar = plugin.registrar else {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -46,12 +46,12 @@ public class InAppBrowserWebViewController: NSViewController, InAppBrowserDelega
|
|||
}
|
||||
|
||||
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(settings: webViewSettings)
|
||||
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
if let wId = windowId, let webViewTransport = plugin.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView = webViewTransport.webView
|
||||
webView!.initialUserScripts = userScripts
|
||||
} else {
|
||||
webView = InAppWebView(id: nil,
|
||||
registrar: nil,
|
||||
plugin: nil,
|
||||
frame: .zero,
|
||||
configuration: preWebviewConfiguration,
|
||||
userScripts: userScripts)
|
||||
|
@ -63,10 +63,11 @@ public class InAppBrowserWebViewController: NSViewController, InAppBrowserDelega
|
|||
|
||||
webView.inAppBrowserDelegate = self
|
||||
webView.id = id
|
||||
webView.plugin = plugin
|
||||
webView.channelDelegate = WebViewChannelDelegate(webView: webView, channel: channel)
|
||||
|
||||
let findInteractionController = FindInteractionController(
|
||||
registrar: registrar,
|
||||
plugin: plugin,
|
||||
id: id, webView: webView, settings: nil)
|
||||
webView.findInteractionController = findInteractionController
|
||||
findInteractionController.prepare()
|
||||
|
@ -99,7 +100,7 @@ public class InAppBrowserWebViewController: NSViewController, InAppBrowserDelega
|
|||
progressBar.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0.0).isActive = true
|
||||
progressBar.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0.0).isActive = true
|
||||
|
||||
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
if let wId = windowId, let webViewTransport = plugin?.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView?.load(webViewTransport.request)
|
||||
channelDelegate?.onBrowserCreated()
|
||||
} else {
|
||||
|
|
|
@ -12,12 +12,15 @@ import FlutterMacOS
|
|||
public class FlutterWebViewController: NSObject, /*FlutterPlatformView,*/ Disposable {
|
||||
|
||||
var myView: NSView?
|
||||
var keepAliveId: String?
|
||||
|
||||
init(registrar: FlutterPluginRegistrar, withFrame frame: CGRect, viewIdentifier viewId: Any, params: NSDictionary) {
|
||||
init(plugin: InAppWebViewFlutterPlugin, withFrame frame: CGRect, viewIdentifier viewId: Any, params: NSDictionary) {
|
||||
super.init()
|
||||
|
||||
myView = NSView(frame: frame)
|
||||
|
||||
keepAliveId = params["keepAliveId"] as? String
|
||||
|
||||
let initialSettings = params["initialSettings"] as! [String: Any?]
|
||||
let windowId = params["windowId"] as? Int64
|
||||
let initialUserScripts = params["initialUserScripts"] as? [[String: Any]]
|
||||
|
@ -35,24 +38,27 @@ public class FlutterWebViewController: NSObject, /*FlutterPlatformView,*/ Dispos
|
|||
|
||||
var webView: InAppWebView?
|
||||
|
||||
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
if let wId = windowId, let webViewTransport = plugin.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView = webViewTransport.webView
|
||||
webView!.id = viewId
|
||||
let channel = FlutterMethodChannel(name: InAppWebView.METHOD_CHANNEL_NAME_PREFIX + String(describing: viewId),
|
||||
binaryMessenger: registrar.messenger)
|
||||
webView!.channelDelegate = WebViewChannelDelegate(webView: webView!, channel: channel)
|
||||
webView!.plugin = plugin
|
||||
if let registrar = plugin.registrar {
|
||||
let channel = FlutterMethodChannel(name: InAppWebView.METHOD_CHANNEL_NAME_PREFIX + String(describing: viewId),
|
||||
binaryMessenger: registrar.messenger)
|
||||
webView!.channelDelegate = WebViewChannelDelegate(webView: webView!, channel: channel)
|
||||
}
|
||||
webView!.frame = myView!.bounds
|
||||
webView!.initialUserScripts = userScripts
|
||||
} else {
|
||||
webView = InAppWebView(id: viewId,
|
||||
registrar: registrar,
|
||||
plugin: plugin,
|
||||
frame: myView!.bounds,
|
||||
configuration: preWebviewConfiguration,
|
||||
userScripts: userScripts)
|
||||
}
|
||||
|
||||
let findInteractionController = FindInteractionController(
|
||||
registrar: registrar,
|
||||
plugin: plugin,
|
||||
id: viewId, webView: webView!, settings: nil)
|
||||
webView!.findInteractionController = findInteractionController
|
||||
findInteractionController.prepare()
|
||||
|
@ -121,7 +127,7 @@ public class FlutterWebViewController: NSObject, /*FlutterPlatformView,*/ Dispos
|
|||
}
|
||||
load(initialUrlRequest: initialUrlRequest, initialFile: initialFile, initialData: initialData)
|
||||
}
|
||||
else if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
else if let wId = windowId, let webViewTransport = webView.plugin?.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView.load(webViewTransport.request)
|
||||
}
|
||||
}
|
||||
|
@ -169,10 +175,12 @@ public class FlutterWebViewController: NSObject, /*FlutterPlatformView,*/ Dispos
|
|||
}
|
||||
|
||||
public func dispose() {
|
||||
if let webView = webView() {
|
||||
webView.dispose()
|
||||
if keepAliveId == nil {
|
||||
if let webView = webView() {
|
||||
webView.dispose()
|
||||
}
|
||||
myView = nil
|
||||
}
|
||||
myView = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -12,11 +12,11 @@ import Foundation
|
|||
|
||||
public class FlutterWebViewFactory: NSObject, FlutterPlatformViewFactory {
|
||||
static let VIEW_TYPE_ID = "com.pichillilorenzo/flutter_inappwebview"
|
||||
private var registrar: FlutterPluginRegistrar?
|
||||
private var plugin: InAppWebViewFlutterPlugin
|
||||
|
||||
init(registrar: FlutterPluginRegistrar?) {
|
||||
init(plugin: InAppWebViewFlutterPlugin) {
|
||||
self.plugin = plugin
|
||||
super.init()
|
||||
self.registrar = registrar
|
||||
}
|
||||
|
||||
public func createArgsCodec() -> (FlutterMessageCodec & NSObjectProtocol)? {
|
||||
|
@ -25,18 +25,48 @@ public class FlutterWebViewFactory: NSObject, FlutterPlatformViewFactory {
|
|||
|
||||
public func create(withViewIdentifier viewId: Int64, arguments args: Any?) -> NSView {
|
||||
let arguments = args as? NSDictionary
|
||||
var flutterWebView: FlutterWebViewController?
|
||||
var id: Any = viewId
|
||||
|
||||
if let headlessWebViewId = arguments?["headlessWebViewId"] as? String,
|
||||
let headlessWebView = HeadlessInAppWebViewManager.webViews[headlessWebViewId],
|
||||
let keepAliveId = arguments?["keepAliveId"] as? String
|
||||
let headlessWebViewId = arguments?["headlessWebViewId"] as? String
|
||||
|
||||
if let headlessWebViewId = headlessWebViewId,
|
||||
let headlessWebView = plugin.headlessInAppWebViewManager?.webViews[headlessWebViewId],
|
||||
let platformView = headlessWebView?.disposeAndGetFlutterWebView(withFrame: .zero) {
|
||||
return platformView.view()
|
||||
flutterWebView = platformView
|
||||
flutterWebView?.keepAliveId = keepAliveId
|
||||
}
|
||||
|
||||
let webviewController = FlutterWebViewController(registrar: registrar!,
|
||||
withFrame: .zero,
|
||||
viewIdentifier: viewId,
|
||||
params: arguments!)
|
||||
webviewController.makeInitialLoad(params: arguments!)
|
||||
return webviewController.view()
|
||||
if let keepAliveId = keepAliveId,
|
||||
flutterWebView == nil,
|
||||
let keepAliveWebView = plugin.inAppWebViewManager?.keepAliveWebViews[keepAliveId] {
|
||||
flutterWebView = keepAliveWebView
|
||||
if let view = flutterWebView?.view() {
|
||||
// remove from parent
|
||||
view.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
let shouldMakeInitialLoad = flutterWebView == nil
|
||||
if flutterWebView == nil {
|
||||
if let keepAliveId = keepAliveId {
|
||||
id = keepAliveId
|
||||
}
|
||||
flutterWebView = FlutterWebViewController(plugin: plugin,
|
||||
withFrame: .zero,
|
||||
viewIdentifier: id,
|
||||
params: arguments!)
|
||||
}
|
||||
|
||||
if let keepAliveId = keepAliveId {
|
||||
plugin.inAppWebViewManager?.keepAliveWebViews[keepAliveId] = flutterWebView!
|
||||
}
|
||||
|
||||
if shouldMakeInitialLoad {
|
||||
flutterWebView?.makeInitialLoad(params: arguments!)
|
||||
}
|
||||
|
||||
return flutterWebView!.view()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ public class InAppWebView: WKWebView, WKUIDelegate,
|
|||
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_"
|
||||
|
||||
var id: Any? // viewId
|
||||
var registrar: FlutterPluginRegistrar?
|
||||
var plugin: InAppWebViewFlutterPlugin?
|
||||
var windowId: Int64?
|
||||
var windowCreated = false
|
||||
var inAppBrowserDelegate: InAppBrowserDelegate?
|
||||
|
@ -43,19 +43,16 @@ public class InAppWebView: WKWebView, WKUIDelegate,
|
|||
|
||||
var customIMPs: [IMP] = []
|
||||
|
||||
static var windowWebViews: [Int64:WebViewTransport] = [:]
|
||||
static var windowAutoincrementId: Int64 = 0;
|
||||
|
||||
var callAsyncJavaScriptBelowIOS14Results: [String:((Any?) -> Void)] = [:]
|
||||
|
||||
var currentOpenPanel: NSOpenPanel?
|
||||
|
||||
init(id: Any?, registrar: FlutterPluginRegistrar?, frame: CGRect, configuration: WKWebViewConfiguration,
|
||||
init(id: Any?, plugin: InAppWebViewFlutterPlugin?, frame: CGRect, configuration: WKWebViewConfiguration,
|
||||
userScripts: [UserScript] = []) {
|
||||
super.init(frame: frame, configuration: configuration)
|
||||
self.id = id
|
||||
self.registrar = registrar
|
||||
if let id = id, let registrar = registrar {
|
||||
self.plugin = plugin
|
||||
if let id = id, let registrar = plugin?.registrar {
|
||||
let channel = FlutterMethodChannel(name: InAppWebView.METHOD_CHANNEL_NAME_PREFIX + String(describing: id),
|
||||
binaryMessenger: registrar.messenger)
|
||||
self.channelDelegate = WebViewChannelDelegate(webView: self, channel: channel)
|
||||
|
@ -1788,10 +1785,14 @@ public class InAppWebView: WKWebView, WKUIDelegate,
|
|||
createWebViewWith configuration: WKWebViewConfiguration,
|
||||
for navigationAction: WKNavigationAction,
|
||||
windowFeatures: WKWindowFeatures) -> WKWebView? {
|
||||
InAppWebView.windowAutoincrementId += 1
|
||||
let windowId = InAppWebView.windowAutoincrementId
|
||||
var windowId: Int64 = 0
|
||||
let inAppWebViewManager = plugin?.inAppWebViewManager
|
||||
if let inAppWebViewManager = inAppWebViewManager {
|
||||
inAppWebViewManager.windowAutoincrementId += 1
|
||||
windowId = inAppWebViewManager.windowAutoincrementId
|
||||
}
|
||||
|
||||
let windowWebView = InAppWebView(id: nil, registrar: nil, frame: CGRect.zero, configuration: configuration)
|
||||
let windowWebView = InAppWebView(id: nil, plugin: nil, frame: CGRect.zero, configuration: configuration)
|
||||
windowWebView.windowId = windowId
|
||||
|
||||
let webViewTransport = WebViewTransport(
|
||||
|
@ -1799,7 +1800,7 @@ public class InAppWebView: WKWebView, WKUIDelegate,
|
|||
request: navigationAction.request
|
||||
)
|
||||
|
||||
InAppWebView.windowWebViews[windowId] = webViewTransport
|
||||
inAppWebViewManager?.windowWebViews[windowId] = webViewTransport
|
||||
windowWebView.stopLoading()
|
||||
|
||||
let createWindowAction = CreateWindowAction(navigationAction: navigationAction, windowId: windowId, windowFeatures: windowFeatures, isDialog: nil)
|
||||
|
@ -1809,8 +1810,8 @@ public class InAppWebView: WKWebView, WKUIDelegate,
|
|||
return !handledByClient
|
||||
}
|
||||
callback.defaultBehaviour = { (handledByClient: Bool?) in
|
||||
if InAppWebView.windowWebViews[windowId] != nil {
|
||||
InAppWebView.windowWebViews.removeValue(forKey: windowId)
|
||||
if inAppWebViewManager?.windowWebViews[windowId] != nil {
|
||||
inAppWebViewManager?.windowWebViews.removeValue(forKey: windowId)
|
||||
}
|
||||
self.loadUrl(urlRequest: navigationAction.request, allowingReadAccessTo: nil)
|
||||
}
|
||||
|
@ -2066,7 +2067,7 @@ public class InAppWebView: WKWebView, WKUIDelegate,
|
|||
|
||||
let _windowId = body["_windowId"] as? Int64
|
||||
var webView = self
|
||||
if let wId = _windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
if let wId = _windowId, let webViewTransport = plugin?.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView = webViewTransport.webView
|
||||
}
|
||||
webView.channelDelegate?.onConsoleMessage(message: consoleMessage, messageLevel: messageLevel)
|
||||
|
@ -2083,7 +2084,7 @@ public class InAppWebView: WKWebView, WKUIDelegate,
|
|||
return !handledByClient
|
||||
}
|
||||
callback.defaultBehaviour = { (handledByClient: Bool?) in
|
||||
if let printJob = PrintJobManager.jobs[printJobId] {
|
||||
if let printJob = self.plugin?.printJobManager?.jobs[printJobId] {
|
||||
printJob?.disposeNoDismiss()
|
||||
}
|
||||
}
|
||||
|
@ -2101,7 +2102,7 @@ public class InAppWebView: WKWebView, WKUIDelegate,
|
|||
|
||||
let _windowId = body["_windowId"] as? Int64
|
||||
var webView = self
|
||||
if let wId = _windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
if let wId = _windowId, let webViewTransport = plugin?.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView = webViewTransport.webView
|
||||
}
|
||||
|
||||
|
@ -2143,7 +2144,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
|
||||
let _windowId = body["_windowId"] as? Int64
|
||||
var webView = self
|
||||
if let wId = _windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
if let wId = _windowId, let webViewTransport = plugin?.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView = webViewTransport.webView
|
||||
}
|
||||
webView.findInteractionController?.channelDelegate?.onFindResultReceived(activeMatchOrdinal: activeMatchOrdinal, numberOfMatches: numberOfMatches, isDoneCounting: isDoneCounting)
|
||||
|
@ -2155,7 +2156,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
|
||||
let _windowId = body["_windowId"] as? Int64
|
||||
var webView = self
|
||||
if let wId = _windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
if let wId = _windowId, let webViewTransport = plugin?.inAppWebViewManager?.windowWebViews[wId] {
|
||||
webView = webViewTransport.webView
|
||||
}
|
||||
webView.channelDelegate?.onScrollChanged(x: x, y: y)
|
||||
|
@ -2358,9 +2359,9 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
}
|
||||
}
|
||||
|
||||
if let id = printJobId, let registrar = registrar {
|
||||
let printJob = PrintJobController(registrar: registrar, id: id, job: printOperation, settings: settings)
|
||||
PrintJobManager.jobs[id] = printJob
|
||||
if let id = printJobId, let plugin = plugin {
|
||||
let printJob = PrintJobController(plugin: plugin, id: id, job: printOperation, settings: settings)
|
||||
plugin.printJobManager?.jobs[id] = printJob
|
||||
printJob.present(parentWindow: window, completionHandler: completionHandler)
|
||||
} else if let window = window {
|
||||
printJobCompletionHandler = completionHandler
|
||||
|
@ -2458,12 +2459,12 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
}
|
||||
|
||||
public func createWebMessageChannel(completionHandler: ((WebMessageChannel?) -> Void)? = nil) -> WebMessageChannel? {
|
||||
guard let registrar = registrar else {
|
||||
guard let plugin = plugin else {
|
||||
completionHandler?(nil)
|
||||
return nil
|
||||
}
|
||||
let id = NSUUID().uuidString
|
||||
let webMessageChannel = WebMessageChannel(registrar: registrar, id: id)
|
||||
let webMessageChannel = WebMessageChannel(plugin: plugin, id: id)
|
||||
webMessageChannel.initJsInstance(webView: self, completionHandler: completionHandler)
|
||||
webMessageChannels[id] = webMessageChannel
|
||||
|
||||
|
@ -2567,8 +2568,8 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
if #available(macOS 10.13, *) {
|
||||
configuration.userContentController.removeAllContentRuleLists()
|
||||
}
|
||||
} else if let wId = windowId, InAppWebView.windowWebViews[wId] != nil {
|
||||
InAppWebView.windowWebViews.removeValue(forKey: wId)
|
||||
} else if let wId = windowId, plugin?.inAppWebViewManager?.windowWebViews[wId] != nil {
|
||||
plugin?.inAppWebViewManager?.windowWebViews.removeValue(forKey: wId)
|
||||
}
|
||||
configuration.userContentController.dispose(windowId: windowId)
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
|
@ -2582,7 +2583,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
isPausedTimersCompletionHandler = nil
|
||||
callAsyncJavaScriptBelowIOS14Results.removeAll()
|
||||
super.removeFromSuperview()
|
||||
registrar = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// InAppWebViewStatic.swift
|
||||
// InAppWebViewManager.swift
|
||||
// flutter_inappwebview
|
||||
//
|
||||
// Created by Lorenzo Pichilli on 08/12/2019.
|
||||
|
@ -9,14 +9,18 @@ import Foundation
|
|||
import WebKit
|
||||
import FlutterMacOS
|
||||
|
||||
public class InAppWebViewStatic: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static"
|
||||
public class InAppWebViewManager: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_manager"
|
||||
var plugin: InAppWebViewFlutterPlugin?
|
||||
var webViewForUserAgent: WKWebView?
|
||||
var defaultUserAgent: String?
|
||||
|
||||
var keepAliveWebViews: [String:FlutterWebViewController?] = [:]
|
||||
var windowWebViews: [Int64:WebViewTransport] = [:]
|
||||
var windowAutoincrementId: Int64 = 0
|
||||
|
||||
init(plugin: InAppWebViewFlutterPlugin) {
|
||||
super.init(channel: FlutterMethodChannel(name: InAppWebViewStatic.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger))
|
||||
super.init(channel: FlutterMethodChannel(name: InAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger))
|
||||
self.plugin = plugin
|
||||
}
|
||||
|
||||
|
@ -37,6 +41,11 @@ public class InAppWebViewStatic: ChannelDelegate {
|
|||
result(false)
|
||||
}
|
||||
break
|
||||
case "disposeKeepAlive":
|
||||
let keepAliveId = arguments!["keepAliveId"] as! String
|
||||
disposeKeepAlive(keepAliveId: keepAliveId)
|
||||
result(true)
|
||||
break
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
break
|
||||
|
@ -68,11 +77,27 @@ public class InAppWebViewStatic: ChannelDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
public func disposeKeepAlive(keepAliveId: String) {
|
||||
if let flutterWebView = keepAliveWebViews[keepAliveId] as? FlutterWebViewController {
|
||||
flutterWebView.keepAliveId = nil
|
||||
flutterWebView.dispose()
|
||||
keepAliveWebViews[keepAliveId] = nil
|
||||
}
|
||||
}
|
||||
|
||||
public override func dispose() {
|
||||
super.dispose()
|
||||
plugin = nil
|
||||
let keepAliveWebViewValues = keepAliveWebViews.values
|
||||
keepAliveWebViewValues.forEach {(keepAliveWebView: FlutterWebViewController?) in
|
||||
if let keepAliveId = keepAliveWebView?.keepAliveId {
|
||||
disposeKeepAlive(keepAliveId: keepAliveId)
|
||||
}
|
||||
}
|
||||
keepAliveWebViews.removeAll()
|
||||
windowWebViews.removeAll()
|
||||
webViewForUserAgent = nil
|
||||
defaultUserAgent = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
deinit {
|
|
@ -11,18 +11,20 @@ import FlutterMacOS
|
|||
public class WebMessageChannel : FlutterMethodCallDelegate {
|
||||
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_web_message_channel_"
|
||||
var id: String
|
||||
var plugin: InAppWebViewFlutterPlugin?
|
||||
var channelDelegate: WebMessageChannelChannelDelegate?
|
||||
weak var webView: InAppWebView?
|
||||
var ports: [WebMessagePort] = []
|
||||
var registrar: FlutterPluginRegistrar?
|
||||
|
||||
public init(registrar: FlutterPluginRegistrar, id: String) {
|
||||
public init(plugin: InAppWebViewFlutterPlugin, id: String) {
|
||||
self.id = id
|
||||
self.registrar = registrar
|
||||
self.plugin = plugin
|
||||
super.init()
|
||||
let channel = FlutterMethodChannel(name: WebMessageChannel.METHOD_CHANNEL_NAME_PREFIX + id,
|
||||
binaryMessenger: registrar.messenger)
|
||||
self.channelDelegate = WebMessageChannelChannelDelegate(webMessageChannel: self, channel: channel)
|
||||
if let registrar = plugin.registrar {
|
||||
let channel = FlutterMethodChannel(name: WebMessageChannel.METHOD_CHANNEL_NAME_PREFIX + id,
|
||||
binaryMessenger: registrar.messenger)
|
||||
self.channelDelegate = WebMessageChannelChannelDelegate(webMessageChannel: self, channel: channel)
|
||||
}
|
||||
self.ports = [
|
||||
WebMessagePort(name: "port1", webMessageChannel: self),
|
||||
WebMessagePort(name: "port2", webMessageChannel: self)
|
||||
|
@ -68,7 +70,7 @@ public class WebMessageChannel : FlutterMethodCallDelegate {
|
|||
})();
|
||||
""")
|
||||
webView = nil
|
||||
registrar = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -16,17 +16,19 @@ public class WebMessageListener : FlutterMethodCallDelegate {
|
|||
var allowedOriginRules: Set<String>
|
||||
var channelDelegate: WebMessageListenerChannelDelegate?
|
||||
weak var webView: InAppWebView?
|
||||
var registrar: FlutterPluginRegistrar?
|
||||
var plugin: InAppWebViewFlutterPlugin?
|
||||
|
||||
public init(registrar: FlutterPluginRegistrar, id: String, jsObjectName: String, allowedOriginRules: Set<String>) {
|
||||
public init(plugin: InAppWebViewFlutterPlugin, id: String, jsObjectName: String, allowedOriginRules: Set<String>) {
|
||||
self.id = id
|
||||
self.registrar = registrar
|
||||
self.plugin = plugin
|
||||
self.jsObjectName = jsObjectName
|
||||
self.allowedOriginRules = allowedOriginRules
|
||||
super.init()
|
||||
let channel = FlutterMethodChannel(name: WebMessageListener.METHOD_CHANNEL_NAME_PREFIX + self.id + "_" + self.jsObjectName,
|
||||
binaryMessenger: registrar.messenger)
|
||||
self.channelDelegate = WebMessageListenerChannelDelegate(webMessageListener: self, channel: channel)
|
||||
if let registrar = plugin.registrar {
|
||||
let channel = FlutterMethodChannel(name: WebMessageListener.METHOD_CHANNEL_NAME_PREFIX + self.id + "_" + self.jsObjectName,
|
||||
binaryMessenger: registrar.messenger)
|
||||
self.channelDelegate = WebMessageListenerChannelDelegate(webMessageListener: self, channel: channel)
|
||||
}
|
||||
}
|
||||
|
||||
public func assertOriginRulesValid() throws {
|
||||
|
@ -117,12 +119,12 @@ public class WebMessageListener : FlutterMethodCallDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
public static func fromMap(registrar: FlutterPluginRegistrar, map: [String:Any?]?) -> WebMessageListener? {
|
||||
public static func fromMap(plugin: InAppWebViewFlutterPlugin, map: [String:Any?]?) -> WebMessageListener? {
|
||||
guard let map = map else {
|
||||
return nil
|
||||
}
|
||||
return WebMessageListener(
|
||||
registrar: registrar,
|
||||
plugin: plugin,
|
||||
id: map["id"] as! String,
|
||||
jsObjectName: map["jsObjectName"] as! String,
|
||||
allowedOriginRules: Set(map["allowedOriginRules"] as! [String])
|
||||
|
@ -181,7 +183,7 @@ public class WebMessageListener : FlutterMethodCallDelegate {
|
|||
channelDelegate?.dispose()
|
||||
channelDelegate = nil
|
||||
webView = nil
|
||||
registrar = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -507,9 +507,9 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
|||
}
|
||||
break
|
||||
case .addWebMessageListener:
|
||||
if let webView = webView, let registrar = webView.registrar {
|
||||
if let webView = webView, let plugin = webView.plugin {
|
||||
let webMessageListenerMap = arguments!["webMessageListener"] as! [String: Any?]
|
||||
let webMessageListener = WebMessageListener.fromMap(registrar: registrar, map: webMessageListenerMap)!
|
||||
let webMessageListener = WebMessageListener.fromMap(plugin: plugin, map: webMessageListenerMap)!
|
||||
do {
|
||||
try webView.addWebMessageListener(webMessageListener: webMessageListener)
|
||||
result(false)
|
||||
|
|
|
@ -27,14 +27,14 @@ public class InAppWebViewFlutterPlugin: NSObject, FlutterPlugin {
|
|||
|
||||
var registrar: FlutterPluginRegistrar?
|
||||
var platformUtil: PlatformUtil?
|
||||
var inAppWebViewStatic: InAppWebViewStatic?
|
||||
var inAppWebViewManager: InAppWebViewManager?
|
||||
var myCookieManager: Any?
|
||||
var myWebStorageManager: MyWebStorageManager?
|
||||
var credentialDatabase: CredentialDatabase?
|
||||
var inAppBrowserManager: InAppBrowserManager?
|
||||
var headlessInAppWebViewManager: HeadlessInAppWebViewManager?
|
||||
var webAuthenticationSessionManager: WebAuthenticationSessionManager?
|
||||
// var printJobManager: PrintJobManager?
|
||||
var printJobManager: PrintJobManager?
|
||||
|
||||
var webViewControllers: [String: InAppBrowserWebViewController?] = [:]
|
||||
var safariViewControllers: [String: Any?] = [:]
|
||||
|
@ -42,19 +42,19 @@ public class InAppWebViewFlutterPlugin: NSObject, FlutterPlugin {
|
|||
public init(with registrar: FlutterPluginRegistrar) {
|
||||
super.init()
|
||||
self.registrar = registrar
|
||||
registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: FlutterWebViewFactory.VIEW_TYPE_ID)
|
||||
registrar.register(FlutterWebViewFactory(plugin: self) as FlutterPlatformViewFactory, withId: FlutterWebViewFactory.VIEW_TYPE_ID)
|
||||
|
||||
platformUtil = PlatformUtil(plugin: self)
|
||||
inAppBrowserManager = InAppBrowserManager(plugin: self)
|
||||
headlessInAppWebViewManager = HeadlessInAppWebViewManager(plugin: self)
|
||||
inAppWebViewStatic = InAppWebViewStatic(plugin: self)
|
||||
inAppWebViewManager = InAppWebViewManager(plugin: self)
|
||||
credentialDatabase = CredentialDatabase(plugin: self)
|
||||
if #available(macOS 10.13, *) {
|
||||
myCookieManager = MyCookieManager(plugin: self)
|
||||
}
|
||||
myWebStorageManager = MyWebStorageManager(plugin: self)
|
||||
webAuthenticationSessionManager = WebAuthenticationSessionManager(plugin: self)
|
||||
// printJobManager = PrintJobManager()
|
||||
printJobManager = PrintJobManager(plugin: self)
|
||||
}
|
||||
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
|
@ -68,8 +68,8 @@ public class InAppWebViewFlutterPlugin: NSObject, FlutterPlugin {
|
|||
inAppBrowserManager = nil
|
||||
headlessInAppWebViewManager?.dispose()
|
||||
headlessInAppWebViewManager = nil
|
||||
inAppWebViewStatic?.dispose()
|
||||
inAppWebViewStatic = nil
|
||||
inAppWebViewManager?.dispose()
|
||||
inAppWebViewManager = nil
|
||||
credentialDatabase?.dispose()
|
||||
credentialDatabase = nil
|
||||
if #available(macOS 10.13, *) {
|
||||
|
@ -80,7 +80,7 @@ public class InAppWebViewFlutterPlugin: NSObject, FlutterPlugin {
|
|||
myWebStorageManager = nil
|
||||
webAuthenticationSessionManager?.dispose()
|
||||
webAuthenticationSessionManager = nil
|
||||
// printJobManager?.dispose()
|
||||
// printJobManager = nil
|
||||
printJobManager?.dispose()
|
||||
printJobManager = nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public enum PrintJobState: Int {
|
|||
public class PrintJobController : NSObject, Disposable {
|
||||
static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_printjobcontroller_"
|
||||
var id: String
|
||||
var registrar: FlutterPluginRegistrar?
|
||||
var plugin: InAppWebViewFlutterPlugin?
|
||||
var job: NSPrintOperation?
|
||||
var settings: PrintJobSettings?
|
||||
var channelDelegate: PrintJobChannelDelegate?
|
||||
|
@ -30,15 +30,17 @@ public class PrintJobController : NSObject, Disposable {
|
|||
_ success: Bool,
|
||||
_ contextInfo: UnsafeMutableRawPointer?) -> Void
|
||||
|
||||
public init(registrar: FlutterPluginRegistrar, id: String, job: NSPrintOperation? = nil, settings: PrintJobSettings? = nil) {
|
||||
public init(plugin: InAppWebViewFlutterPlugin, id: String, job: NSPrintOperation? = nil, settings: PrintJobSettings? = nil) {
|
||||
self.id = id
|
||||
self.registrar = registrar
|
||||
self.plugin = plugin
|
||||
super.init()
|
||||
self.job = job
|
||||
self.settings = settings
|
||||
let channel = FlutterMethodChannel(name: PrintJobController.METHOD_CHANNEL_NAME_PREFIX + id,
|
||||
binaryMessenger: registrar.messenger)
|
||||
self.channelDelegate = PrintJobChannelDelegate(printJobController: self, channel: channel)
|
||||
if let registrar = plugin.registrar {
|
||||
let channel = FlutterMethodChannel(name: PrintJobController.METHOD_CHANNEL_NAME_PREFIX + id,
|
||||
binaryMessenger: registrar.messenger)
|
||||
self.channelDelegate = PrintJobChannelDelegate(printJobController: self, channel: channel)
|
||||
}
|
||||
}
|
||||
|
||||
public func present(parentWindow: NSWindow? = nil, completionHandler: PrintJobController.CompletionHandler? = nil) {
|
||||
|
@ -76,7 +78,8 @@ public class PrintJobController : NSObject, Disposable {
|
|||
channelDelegate = nil
|
||||
completionHandler = nil
|
||||
job = nil
|
||||
PrintJobManager.jobs[id] = nil
|
||||
plugin?.printJobManager?.jobs[id] = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
public func dispose() {
|
||||
|
@ -84,7 +87,7 @@ public class PrintJobController : NSObject, Disposable {
|
|||
channelDelegate = nil
|
||||
completionHandler = nil
|
||||
job = nil
|
||||
PrintJobManager.jobs[id] = nil
|
||||
registrar = nil
|
||||
plugin?.printJobManager?.jobs[id] = nil
|
||||
plugin = nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,18 +8,21 @@
|
|||
import Foundation
|
||||
|
||||
public class PrintJobManager: NSObject, Disposable {
|
||||
static var jobs: [String: PrintJobController?] = [:]
|
||||
var plugin: InAppWebViewFlutterPlugin?
|
||||
var jobs: [String: PrintJobController?] = [:]
|
||||
|
||||
public override init() {
|
||||
public init(plugin: InAppWebViewFlutterPlugin?) {
|
||||
super.init()
|
||||
self.plugin = plugin
|
||||
}
|
||||
|
||||
public func dispose() {
|
||||
let jobs = PrintJobManager.jobs.values
|
||||
jobs.forEach { (job: PrintJobController?) in
|
||||
let jobValues = jobs.values
|
||||
jobValues.forEach { (job: PrintJobController?) in
|
||||
job?.dispose()
|
||||
}
|
||||
PrintJobManager.jobs.removeAll()
|
||||
jobs.removeAll()
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -91,7 +91,7 @@ public class WebAuthenticationSession : NSObject, ASWebAuthenticationPresentatio
|
|||
channelDelegate?.dispose()
|
||||
channelDelegate = nil
|
||||
session = nil
|
||||
WebAuthenticationSessionManager.sessions[id] = nil
|
||||
plugin?.webAuthenticationSessionManager?.sessions[id] = nil
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import SafariServices
|
|||
public class WebAuthenticationSessionManager: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_webauthenticationsession"
|
||||
var plugin: InAppWebViewFlutterPlugin?
|
||||
static var sessions: [String: WebAuthenticationSession?] = [:]
|
||||
var sessions: [String: WebAuthenticationSession?] = [:]
|
||||
|
||||
init(plugin: InAppWebViewFlutterPlugin) {
|
||||
super.init(channel: FlutterMethodChannel(name: WebAuthenticationSessionManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger))
|
||||
|
@ -53,7 +53,7 @@ public class WebAuthenticationSessionManager: ChannelDelegate {
|
|||
let _ = initialSettings.parse(settings: settings)
|
||||
let session = WebAuthenticationSession(plugin: plugin, id: id, url: sessionUrl, callbackURLScheme: callbackURLScheme, settings: initialSettings)
|
||||
session.prepare()
|
||||
WebAuthenticationSessionManager.sessions[id] = session
|
||||
sessions[id] = session
|
||||
result(true)
|
||||
return
|
||||
}
|
||||
|
@ -63,12 +63,12 @@ public class WebAuthenticationSessionManager: ChannelDelegate {
|
|||
|
||||
public override func dispose() {
|
||||
super.dispose()
|
||||
let sessions = WebAuthenticationSessionManager.sessions.values
|
||||
sessions.forEach { (session: WebAuthenticationSession?) in
|
||||
let sessionValues = sessions.values
|
||||
sessionValues.forEach { (session: WebAuthenticationSession?) in
|
||||
session?.cancel()
|
||||
session?.dispose()
|
||||
}
|
||||
WebAuthenticationSessionManager.sessions.removeAll()
|
||||
sessions.removeAll()
|
||||
plugin = nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue