Added ProcessGlobalConfig for Android WebViews, Added disableWebView static method on InAppWebViewController for Android, Added support for Android WebViewFeature.isStartupFeatureSupported, WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS, WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX, WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, Added WebMessage.type property, WebMessage.data property is of type dynamic, JavaScriptReplyProxy.postMessage is of type WebMessage, changed WebMessageListener.onPostMessage and WebMessagePort.setWebMessageCallback methods signature
This commit is contained in:
parent
a0bbbba7f1
commit
8dfddc2e12
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -1,3 +1,16 @@
|
||||||
|
## 6.0.0-beta.28
|
||||||
|
|
||||||
|
- Added `ProcessGlobalConfig` for Android WebViews
|
||||||
|
- Added `disableWebView` static method on `InAppWebViewController` for Android
|
||||||
|
- Added support for Android `WebViewFeature.isStartupFeatureSupported`, `WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS`, `WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX`, `WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER`
|
||||||
|
- Added `WebMessage.type` property
|
||||||
|
|
||||||
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
- `WebMessage.data` property is of type `dynamic`
|
||||||
|
- `JavaScriptReplyProxy.postMessage` is of type `WebMessage`
|
||||||
|
- `WebMessageListener.onPostMessage` and `WebMessagePort.setWebMessageCallback` methods signature
|
||||||
|
|
||||||
## 6.0.0-beta.27
|
## 6.0.0-beta.27
|
||||||
|
|
||||||
- Added `requestPostMessageChannel`, `postMessage`, `isEngagementSignalsApiAvailable` methods on `ChromeSafariBrowser` for Android
|
- Added `requestPostMessageChannel`, `postMessage`, `isEngagementSignalsApiAvailable` methods on `ChromeSafariBrowser` for Android
|
||||||
|
|
|
@ -2,29 +2,28 @@ package com.pichillilorenzo.flutter_inappwebview;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.webkit.ValueCallback;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ChromeSafariBrowserManager;
|
import com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ChromeSafariBrowserManager;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.credential_database.CredentialDatabaseHandler;
|
import com.pichillilorenzo.flutter_inappwebview.credential_database.CredentialDatabaseHandler;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserManager;
|
|
||||||
import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebViewManager;
|
import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebViewManager;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserManager;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobManager;
|
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobManager;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.process_global_config.ProcessGlobalConfigManager;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.proxy.ProxyManager;
|
import com.pichillilorenzo.flutter_inappwebview.proxy.ProxyManager;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.service_worker.ServiceWorkerManager;
|
import com.pichillilorenzo.flutter_inappwebview.service_worker.ServiceWorkerManager;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.tracing.TracingControllerManager;
|
import com.pichillilorenzo.flutter_inappwebview.tracing.TracingControllerManager;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.webview.FlutterWebViewFactory;
|
import com.pichillilorenzo.flutter_inappwebview.webview.FlutterWebViewFactory;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewManager;
|
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewManager;
|
||||||
|
|
||||||
|
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
||||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
|
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
|
||||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
|
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
|
||||||
import io.flutter.plugin.common.BinaryMessenger;
|
import io.flutter.plugin.common.BinaryMessenger;
|
||||||
import io.flutter.plugin.common.PluginRegistry;
|
import io.flutter.plugin.common.PluginRegistry;
|
||||||
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
|
||||||
import io.flutter.plugin.platform.PlatformViewRegistry;
|
import io.flutter.plugin.platform.PlatformViewRegistry;
|
||||||
import io.flutter.view.FlutterView;
|
import io.flutter.view.FlutterView;
|
||||||
|
|
||||||
|
@ -58,6 +57,8 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
|
||||||
public PrintJobManager printJobManager;
|
public PrintJobManager printJobManager;
|
||||||
@Nullable
|
@Nullable
|
||||||
public TracingControllerManager tracingControllerManager;
|
public TracingControllerManager tracingControllerManager;
|
||||||
|
@Nullable
|
||||||
|
public ProcessGlobalConfigManager processGlobalConfigManager;
|
||||||
public FlutterWebViewFactory flutterWebViewFactory;
|
public FlutterWebViewFactory flutterWebViewFactory;
|
||||||
public Context applicationContext;
|
public Context applicationContext;
|
||||||
public PluginRegistry.Registrar registrar;
|
public PluginRegistry.Registrar registrar;
|
||||||
|
@ -122,6 +123,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
|
||||||
printJobManager = new PrintJobManager(this);
|
printJobManager = new PrintJobManager(this);
|
||||||
}
|
}
|
||||||
tracingControllerManager = new TracingControllerManager(this);
|
tracingControllerManager = new TracingControllerManager(this);
|
||||||
|
processGlobalConfigManager = new ProcessGlobalConfigManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -178,6 +180,10 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
|
||||||
tracingControllerManager.dispose();
|
tracingControllerManager.dispose();
|
||||||
tracingControllerManager = null;
|
tracingControllerManager = null;
|
||||||
}
|
}
|
||||||
|
if (processGlobalConfigManager != null) {
|
||||||
|
processGlobalConfigManager.dispose();
|
||||||
|
processGlobalConfigManager = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -28,6 +28,12 @@ public class WebViewFeatureManager extends ChannelDelegateImpl {
|
||||||
String feature = (String) call.argument("feature");
|
String feature = (String) call.argument("feature");
|
||||||
result.success(WebViewFeature.isFeatureSupported(feature));
|
result.success(WebViewFeature.isFeatureSupported(feature));
|
||||||
break;
|
break;
|
||||||
|
case "isStartupFeatureSupported":
|
||||||
|
if (plugin != null && plugin.activity != null) {
|
||||||
|
String startupFeature = (String) call.argument("startupFeature");
|
||||||
|
result.success(WebViewFeature.isStartupFeatureSupported(plugin.activity, startupFeature));
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
result.notImplemented();
|
result.notImplemented();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
package com.pichillilorenzo.flutter_inappwebview.process_global_config;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.webkit.ProcessGlobalConfig;
|
||||||
|
import androidx.webkit.WebViewFeature;
|
||||||
|
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshSettings;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.flutter.plugin.common.MethodCall;
|
||||||
|
import io.flutter.plugin.common.MethodChannel;
|
||||||
|
|
||||||
|
public class ProcessGlobalConfigManager extends ChannelDelegateImpl {
|
||||||
|
protected static final String LOG_TAG = "ProcessGlobalConfigManager";
|
||||||
|
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_processglobalconfig";
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public InAppWebViewFlutterPlugin plugin;
|
||||||
|
|
||||||
|
public ProcessGlobalConfigManager(@NonNull final InAppWebViewFlutterPlugin plugin) {
|
||||||
|
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
|
||||||
|
switch (call.method) {
|
||||||
|
case "apply":
|
||||||
|
if (plugin != null && plugin.activity != null) {
|
||||||
|
ProcessGlobalConfigSettings settings = (new ProcessGlobalConfigSettings())
|
||||||
|
.parse((Map<String, Object>) call.argument("settings"));
|
||||||
|
ProcessGlobalConfig.apply(settings.toProcessGlobalConfig(plugin.activity));
|
||||||
|
}
|
||||||
|
result.success(true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result.notImplemented();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
plugin = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
package com.pichillilorenzo.flutter_inappwebview.process_global_config;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.webkit.ProcessGlobalConfig;
|
||||||
|
import androidx.webkit.WebViewFeature;
|
||||||
|
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.ISettings;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ProcessGlobalConfigSettings implements ISettings<ProcessGlobalConfig> {
|
||||||
|
public static final String LOG_TAG = "ProcessGlobalConfigSettings";
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String dataDirectorySuffix;
|
||||||
|
@Nullable
|
||||||
|
public DirectoryBasePaths directoryBasePaths;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public ProcessGlobalConfigSettings parse(@NonNull Map<String, Object> settings) {
|
||||||
|
for (Map.Entry<String, Object> pair : settings.entrySet()) {
|
||||||
|
String key = pair.getKey();
|
||||||
|
Object value = pair.getValue();
|
||||||
|
if (value == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case "dataDirectorySuffix":
|
||||||
|
dataDirectorySuffix = (String) value;
|
||||||
|
break;
|
||||||
|
case "directoryBasePaths":
|
||||||
|
directoryBasePaths = (new DirectoryBasePaths()).parse((Map<String, Object>) value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProcessGlobalConfig toProcessGlobalConfig(@NonNull Context context) {
|
||||||
|
ProcessGlobalConfig config = new ProcessGlobalConfig();
|
||||||
|
if (dataDirectorySuffix != null &&
|
||||||
|
WebViewFeature.isStartupFeatureSupported(context, WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX)) {
|
||||||
|
config.setDataDirectorySuffix(context, dataDirectorySuffix);
|
||||||
|
}
|
||||||
|
if (directoryBasePaths != null &&
|
||||||
|
WebViewFeature.isStartupFeatureSupported(context, WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS)) {
|
||||||
|
config.setDirectoryBasePaths(context,
|
||||||
|
new File(directoryBasePaths.dataDirectoryBasePath),
|
||||||
|
new File(directoryBasePaths.cacheDirectoryBasePath));
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
@NonNull
|
||||||
|
public Map<String, Object> toMap() {
|
||||||
|
Map<String, Object> settings = new HashMap<>();
|
||||||
|
settings.put("dataDirectorySuffix", dataDirectorySuffix);
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getRealSettings(@NonNull ProcessGlobalConfig processGlobalConfig) {
|
||||||
|
Map<String, Object> realSettings = toMap();
|
||||||
|
return realSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DirectoryBasePaths implements ISettings<Object> {
|
||||||
|
public static final String LOG_TAG = "ProcessGlobalConfigSettings";
|
||||||
|
|
||||||
|
public String cacheDirectoryBasePath;
|
||||||
|
public String dataDirectoryBasePath;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public DirectoryBasePaths parse(@NonNull Map<String, Object> settings) {
|
||||||
|
for (Map.Entry<String, Object> pair : settings.entrySet()) {
|
||||||
|
String key = pair.getKey();
|
||||||
|
Object value = pair.getValue();
|
||||||
|
if (value == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case "cacheDirectoryBasePath":
|
||||||
|
cacheDirectoryBasePath = (String) value;
|
||||||
|
break;
|
||||||
|
case "dataDirectoryBasePath":
|
||||||
|
dataDirectoryBasePath = (String) value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Map<String, Object> toMap() {
|
||||||
|
Map<String, Object> settings = new HashMap<>();
|
||||||
|
settings.put("cacheDirectoryBasePath", cacheDirectoryBasePath);
|
||||||
|
settings.put("dataDirectoryBasePath", dataDirectoryBasePath);
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getRealSettings(@NonNull Object obj) {
|
||||||
|
Map<String, Object> realSettings = toMap();
|
||||||
|
return realSettings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.webkit.WebMessageCompat;
|
||||||
|
import androidx.webkit.WebViewFeature;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class WebMessageCompatExt {
|
||||||
|
@Nullable
|
||||||
|
private Object data;
|
||||||
|
private @WebMessageCompat.Type int type;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private List<WebMessagePortCompatExt> ports;
|
||||||
|
|
||||||
|
public WebMessageCompatExt(@Nullable Object data, int type, @Nullable List<WebMessagePortCompatExt> ports) {
|
||||||
|
this.data = data;
|
||||||
|
this.type = type;
|
||||||
|
this.ports = ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WebMessageCompatExt fromMapWebMessageCompat(@NonNull WebMessageCompat message) {
|
||||||
|
Object data;
|
||||||
|
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER) && message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) {
|
||||||
|
data = message.getArrayBuffer();
|
||||||
|
} else {
|
||||||
|
data = message.getData();
|
||||||
|
}
|
||||||
|
return new WebMessageCompatExt(data, message.getType(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static WebMessageCompatExt fromMap(@Nullable Map<String, Object> map) {
|
||||||
|
if (map == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Object data = map.get("data");
|
||||||
|
Integer type = (Integer) map.get("type");
|
||||||
|
List<Map<String, Object>> portMapList = (List<Map<String, Object>>) map.get("ports");
|
||||||
|
List<WebMessagePortCompatExt> ports = null;
|
||||||
|
if (portMapList != null && !portMapList.isEmpty()) {
|
||||||
|
ports = new ArrayList<>();
|
||||||
|
for (Map<String, Object> portMap : portMapList) {
|
||||||
|
ports.add(WebMessagePortCompatExt.fromMap(portMap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new WebMessageCompatExt(data, type, ports);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> toMap() {
|
||||||
|
Map<String, Object> proxyRuleMap = new HashMap<>();
|
||||||
|
proxyRuleMap.put("data", data);
|
||||||
|
proxyRuleMap.put("type", type);
|
||||||
|
return proxyRuleMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Object getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(@Nullable Object data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(int type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public List<WebMessagePortCompatExt> getPorts() {
|
||||||
|
return ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPorts(@Nullable List<WebMessagePortCompatExt> ports) {
|
||||||
|
this.ports = ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
WebMessageCompatExt that = (WebMessageCompatExt) o;
|
||||||
|
|
||||||
|
if (type != that.type) return false;
|
||||||
|
if (!Objects.equals(data, that.data)) return false;
|
||||||
|
return Objects.equals(ports, that.ports);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = data != null ? data.hashCode() : 0;
|
||||||
|
result = 31 * result + type;
|
||||||
|
result = 31 * result + (ports != null ? ports.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "WebMessageCompatExt{" +
|
||||||
|
"data=" + data +
|
||||||
|
", type=" + type +
|
||||||
|
", ports=" + ports +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
package com.pichillilorenzo.flutter_inappwebview.types;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class WebMessagePortCompatExt {
|
||||||
|
private int index;
|
||||||
|
@NonNull
|
||||||
|
private String webMessageChannelId;
|
||||||
|
|
||||||
|
public WebMessagePortCompatExt(int index, @NonNull String webMessageChannelId) {
|
||||||
|
this.index = index;
|
||||||
|
this.webMessageChannelId = webMessageChannelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static WebMessagePortCompatExt fromMap(@Nullable Map<String, Object> map) {
|
||||||
|
if (map == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Integer index = (Integer) map.get("index");
|
||||||
|
String webMessageChannelId = (String) map.get("webMessageChannelId");
|
||||||
|
return new WebMessagePortCompatExt(index, webMessageChannelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> toMap() {
|
||||||
|
Map<String, Object> proxyRuleMap = new HashMap<>();
|
||||||
|
proxyRuleMap.put("index", index);
|
||||||
|
proxyRuleMap.put("webMessageChannelId", webMessageChannelId);
|
||||||
|
return proxyRuleMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndex(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public String getWebMessageChannelId() {
|
||||||
|
return webMessageChannelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWebMessageChannelId(@NonNull String webMessageChannelId) {
|
||||||
|
this.webMessageChannelId = webMessageChannelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
WebMessagePortCompatExt that = (WebMessagePortCompatExt) o;
|
||||||
|
|
||||||
|
if (index != that.index) return false;
|
||||||
|
return webMessageChannelId.equals(that.webMessageChannelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = index;
|
||||||
|
result = 31 * result + webMessageChannelId.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "WebMessagePortCompatExt{" +
|
||||||
|
"index=" + index +
|
||||||
|
", webMessageChannelId='" + webMessageChannelId + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -133,6 +133,12 @@ public class InAppWebViewManager extends ChannelDelegateImpl {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "disableWebView":
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
WebView.disableWebView();
|
||||||
|
}
|
||||||
|
result.success(true);
|
||||||
|
break;
|
||||||
case "disposeKeepAlive":
|
case "disposeKeepAlive":
|
||||||
final String keepAliveId = (String) call.argument("keepAliveId");
|
final String keepAliveId = (String) call.argument("keepAliveId");
|
||||||
if (keepAliveId != null) {
|
if (keepAliveId != null) {
|
||||||
|
|
|
@ -43,7 +43,9 @@ import com.pichillilorenzo.flutter_inappwebview.types.SslCertificateExt;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.SyncBaseCallbackResultImpl;
|
import com.pichillilorenzo.flutter_inappwebview.types.SyncBaseCallbackResultImpl;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
|
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScript;
|
import com.pichillilorenzo.flutter_inappwebview.types.UserScript;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.types.WebMessageCompatExt;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.WebMessagePort;
|
import com.pichillilorenzo.flutter_inappwebview.types.WebMessagePort;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.types.WebMessagePortCompatExt;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceErrorExt;
|
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceErrorExt;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceRequestExt;
|
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceRequestExt;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceResponseExt;
|
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceResponseExt;
|
||||||
|
@ -141,8 +143,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(value);
|
result.success(value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -210,8 +211,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
Map<String, Object> screenshotConfiguration = (Map<String, Object>) call.argument("screenshotConfiguration");
|
Map<String, Object> screenshotConfiguration = (Map<String, Object>) call.argument("screenshotConfiguration");
|
||||||
webView.takeScreenshot(screenshotConfiguration, result);
|
webView.takeScreenshot(screenshotConfiguration, result);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
result.success(null);
|
result.success(null);
|
||||||
break;
|
break;
|
||||||
case setSettings:
|
case setSettings:
|
||||||
|
@ -282,8 +282,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(success);
|
result.success(success);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -568,8 +567,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(value);
|
result.success(value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -598,27 +596,33 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
break;
|
break;
|
||||||
case postWebMessage:
|
case postWebMessage:
|
||||||
if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.POST_WEB_MESSAGE)) {
|
if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.POST_WEB_MESSAGE)) {
|
||||||
Map<String, Object> message = (Map<String, Object>) call.argument("message");
|
WebMessageCompatExt message = WebMessageCompatExt.fromMap((Map<String, Object>) call.argument("message"));
|
||||||
String targetOrigin = (String) call.argument("targetOrigin");
|
String targetOrigin = (String) call.argument("targetOrigin");
|
||||||
List<WebMessagePortCompat> compatPorts = new ArrayList<>();
|
List<WebMessagePortCompat> compatPorts = new ArrayList<>();
|
||||||
List<WebMessagePort> ports = new ArrayList<>();
|
List<WebMessagePortCompatExt> portsExt = message.getPorts();
|
||||||
List<Map<String, Object>> portsMap = (List<Map<String, Object>>) message.get("ports");
|
if (portsExt != null) {
|
||||||
if (portsMap != null) {
|
for (WebMessagePortCompatExt portExt : portsExt) {
|
||||||
for (Map<String, Object> portMap : portsMap) {
|
WebMessageChannel webMessageChannel = webView.getWebMessageChannels().get(portExt.getWebMessageChannelId());
|
||||||
String webMessageChannelId = (String) portMap.get("webMessageChannelId");
|
|
||||||
Integer index = (Integer) portMap.get("index");
|
|
||||||
WebMessageChannel webMessageChannel = webView.getWebMessageChannels().get(webMessageChannelId);
|
|
||||||
if (webMessageChannel != null) {
|
if (webMessageChannel != null) {
|
||||||
if (webView instanceof InAppWebView) {
|
if (webView instanceof InAppWebView) {
|
||||||
compatPorts.add(webMessageChannel.compatPorts.get(index));
|
compatPorts.add(webMessageChannel.compatPorts.get(portExt.getIndex()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Object data = message.getData();
|
||||||
if (webView instanceof InAppWebView) {
|
if (webView instanceof InAppWebView) {
|
||||||
WebMessageCompat webMessage = new WebMessageCompat((String) message.get("data"), compatPorts.toArray(new WebMessagePortCompat[0]));
|
|
||||||
try {
|
try {
|
||||||
WebViewCompat.postWebMessage((WebView) webView, webMessage, Uri.parse(targetOrigin));
|
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER) && data != null &&
|
||||||
|
message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) {
|
||||||
|
WebViewCompat.postWebMessage((WebView) webView,
|
||||||
|
new WebMessageCompat((byte[]) data, compatPorts.toArray(new WebMessagePortCompat[0])),
|
||||||
|
Uri.parse(targetOrigin));
|
||||||
|
} else {
|
||||||
|
WebViewCompat.postWebMessage((WebView) webView,
|
||||||
|
new WebMessageCompat(data != null ? data.toString() : null, compatPorts.toArray(new WebMessagePortCompat[0])),
|
||||||
|
Uri.parse(targetOrigin));
|
||||||
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
result.error(LOG_TAG, e.getMessage(), null);
|
result.error(LOG_TAG, e.getMessage(), null);
|
||||||
|
@ -671,8 +675,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated Use {@link FindInteractionChannelDelegate#onFindResultReceived} instead.
|
||||||
* Use {@link FindInteractionChannelDelegate#onFindResultReceived} instead.
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) {
|
public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) {
|
||||||
|
|
|
@ -11,6 +11,8 @@ import androidx.webkit.WebViewFeature;
|
||||||
|
|
||||||
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
|
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
|
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.types.WebMessageCompatExt;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.types.WebMessagePortCompatExt;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewInterface;
|
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewInterface;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.WebMessagePort;
|
import com.pichillilorenzo.flutter_inappwebview.types.WebMessagePort;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
|
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
|
||||||
|
@ -77,7 +79,7 @@ public class WebMessageChannel implements Disposable {
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(@NonNull WebMessagePortCompat port, @Nullable WebMessageCompat message) {
|
public void onMessage(@NonNull WebMessagePortCompat port, @Nullable WebMessageCompat message) {
|
||||||
super.onMessage(port, message);
|
super.onMessage(port, message);
|
||||||
webMessageChannel.onMessage(index, message != null ? message.getData() : null);
|
webMessageChannel.onMessage(index, message != null ? WebMessageCompatExt.fromMapWebMessageCompat(message) : null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
result.success(true);
|
result.success(true);
|
||||||
|
@ -89,25 +91,28 @@ public class WebMessageChannel implements Disposable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void postMessageForInAppWebView(final Integer index, Map<String, Object> message, @NonNull MethodChannel.Result result) {
|
public void postMessageForInAppWebView(final Integer index, @NonNull WebMessageCompatExt message, @NonNull MethodChannel.Result result) {
|
||||||
if (webView != null && compatPorts.size() > 0 &&
|
if (webView != null && compatPorts.size() > 0 &&
|
||||||
WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE)) {
|
WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE)) {
|
||||||
WebMessagePortCompat port = compatPorts.get(index);
|
WebMessagePortCompat port = compatPorts.get(index);
|
||||||
List<WebMessagePortCompat> webMessagePorts = new ArrayList<>();
|
List<WebMessagePortCompat> webMessagePorts = new ArrayList<>();
|
||||||
List<Map<String, Object>> portsMap = (List<Map<String, Object>>) message.get("ports");
|
List<WebMessagePortCompatExt> portsExt = message.getPorts();
|
||||||
if (portsMap != null) {
|
if (portsExt != null) {
|
||||||
for (Map<String, Object> portMap : portsMap) {
|
for (WebMessagePortCompatExt portExt : portsExt) {
|
||||||
String webMessageChannelId = (String) portMap.get("webMessageChannelId");
|
WebMessageChannel webMessageChannel = webView.getWebMessageChannels().get(portExt.getWebMessageChannelId());
|
||||||
Integer portIndex = (Integer) portMap.get("index");
|
|
||||||
WebMessageChannel webMessageChannel = webView.getWebMessageChannels().get(webMessageChannelId);
|
|
||||||
if (webMessageChannel != null) {
|
if (webMessageChannel != null) {
|
||||||
webMessagePorts.add(webMessageChannel.compatPorts.get(portIndex));
|
webMessagePorts.add(webMessageChannel.compatPorts.get(portExt.getIndex()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WebMessageCompat webMessage = new WebMessageCompat((String) message.get("data"), webMessagePorts.toArray(new WebMessagePortCompat[0]));
|
Object data = message.getData();
|
||||||
try {
|
try {
|
||||||
port.postMessage(webMessage);
|
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER) && data != null &&
|
||||||
|
message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) {
|
||||||
|
port.postMessage(new WebMessageCompat((byte[]) data, webMessagePorts.toArray(new WebMessagePortCompat[0])));
|
||||||
|
} else {
|
||||||
|
port.postMessage(new WebMessageCompat(data != null ? data.toString() : null, webMessagePorts.toArray(new WebMessagePortCompat[0])));
|
||||||
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
result.error(LOG_TAG, e.getMessage(), null);
|
result.error(LOG_TAG, e.getMessage(), null);
|
||||||
|
@ -132,7 +137,7 @@ public class WebMessageChannel implements Disposable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onMessage(int index, String message) {
|
public void onMessage(int index, @Nullable WebMessageCompatExt message) {
|
||||||
if (channelDelegate != null) {
|
if (channelDelegate != null) {
|
||||||
channelDelegate.onMessage(index, message);
|
channelDelegate.onMessage(index, message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
|
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
|
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.types.WebMessageCompatExt;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
|
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -36,7 +37,7 @@ public class WebMessageChannelChannelDelegate extends ChannelDelegateImpl {
|
||||||
case "postMessage":
|
case "postMessage":
|
||||||
if (webMessageChannel != null && webMessageChannel.webView instanceof InAppWebView) {
|
if (webMessageChannel != null && webMessageChannel.webView instanceof InAppWebView) {
|
||||||
final Integer index = (Integer) call.argument("index");
|
final Integer index = (Integer) call.argument("index");
|
||||||
Map<String, Object> message = (Map<String, Object>) call.argument("message");
|
WebMessageCompatExt message = WebMessageCompatExt.fromMap((Map<String, Object>) call.argument("message"));
|
||||||
webMessageChannel.postMessageForInAppWebView(index, message, result);
|
webMessageChannel.postMessageForInAppWebView(index, message, result);
|
||||||
} else {
|
} else {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
|
@ -55,12 +56,12 @@ public class WebMessageChannelChannelDelegate extends ChannelDelegateImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onMessage(int index, String message) {
|
public void onMessage(int index, @Nullable WebMessageCompatExt message) {
|
||||||
MethodChannel channel = getChannel();
|
MethodChannel channel = getChannel();
|
||||||
if (channel == null) return;
|
if (channel == null) return;
|
||||||
Map<String, Object> obj = new HashMap<>();
|
Map<String, Object> obj = new HashMap<>();
|
||||||
obj.put("index", index);
|
obj.put("index", index);
|
||||||
obj.put("message", message );
|
obj.put("message", message != null ? message.toMap() : null);
|
||||||
channel.invokeMethod("onMessage", obj);
|
channel.invokeMethod("onMessage", obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import androidx.webkit.WebViewFeature;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
|
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
|
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.types.WebMessageCompatExt;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewInterface;
|
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewInterface;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
|
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.UserScriptInjectionTime;
|
import com.pichillilorenzo.flutter_inappwebview.types.UserScriptInjectionTime;
|
||||||
|
@ -61,7 +62,7 @@ public class WebMessageListener implements Disposable {
|
||||||
boolean isMainFrame, @NonNull JavaScriptReplyProxy javaScriptReplyProxy) {
|
boolean isMainFrame, @NonNull JavaScriptReplyProxy javaScriptReplyProxy) {
|
||||||
replyProxy = javaScriptReplyProxy;
|
replyProxy = javaScriptReplyProxy;
|
||||||
if (channelDelegate != null) {
|
if (channelDelegate != null) {
|
||||||
channelDelegate.onPostMessage(message.getData(),
|
channelDelegate.onPostMessage(WebMessageCompatExt.fromMapWebMessageCompat(message),
|
||||||
sourceOrigin.toString().equals("null") ? null : sourceOrigin.toString(),
|
sourceOrigin.toString().equals("null") ? null : sourceOrigin.toString(),
|
||||||
isMainFrame);
|
isMainFrame);
|
||||||
}
|
}
|
||||||
|
@ -171,9 +172,16 @@ public class WebMessageListener implements Disposable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void postMessageForInAppWebView(String message, @NonNull MethodChannel.Result result) {
|
public void postMessageForInAppWebView(WebMessageCompatExt message, @NonNull MethodChannel.Result result) {
|
||||||
if (replyProxy != null && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
|
if (replyProxy != null && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
|
||||||
replyProxy.postMessage(message);
|
Object data = message.getData();
|
||||||
|
if (data != null) {
|
||||||
|
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER) && message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) {
|
||||||
|
replyProxy.postMessage((byte[]) data);
|
||||||
|
} else {
|
||||||
|
replyProxy.postMessage(data.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
}
|
}
|
||||||
|
@ -196,12 +204,14 @@ public class WebMessageListener implements Disposable {
|
||||||
if (rule.getHost() != null && rule.getHost().startsWith("[")) {
|
if (rule.getHost() != null && rule.getHost().startsWith("[")) {
|
||||||
try {
|
try {
|
||||||
IPv6 = Util.normalizeIPv6(rule.getHost().substring(1, rule.getHost().length() - 1));
|
IPv6 = Util.normalizeIPv6(rule.getHost().substring(1, rule.getHost().length() - 1));
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
String hostIPv6 = null;
|
String hostIPv6 = null;
|
||||||
try {
|
try {
|
||||||
hostIPv6 = Util.normalizeIPv6(host);
|
hostIPv6 = Util.normalizeIPv6(host);
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
boolean schemeAllowed = rule.getScheme().equals(scheme);
|
boolean schemeAllowed = rule.getScheme().equals(scheme);
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,12 @@ package com.pichillilorenzo.flutter_inappwebview.webview.web_message;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.webkit.WebMessageCompat;
|
||||||
|
|
||||||
import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebView;
|
import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebView;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
|
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
|
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.types.WebMessageCompatExt;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
|
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -28,7 +30,7 @@ public class WebMessageListenerChannelDelegate extends ChannelDelegateImpl {
|
||||||
switch (call.method) {
|
switch (call.method) {
|
||||||
case "postMessage":
|
case "postMessage":
|
||||||
if (webMessageListener != null && webMessageListener.webView instanceof InAppWebView) {
|
if (webMessageListener != null && webMessageListener.webView instanceof InAppWebView) {
|
||||||
String message = (String) call.argument("message");
|
WebMessageCompatExt message = WebMessageCompatExt.fromMap((Map<String, Object>) call.argument("message"));
|
||||||
webMessageListener.postMessageForInAppWebView(message, result);
|
webMessageListener.postMessageForInAppWebView(message, result);
|
||||||
} else {
|
} else {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
|
@ -39,11 +41,11 @@ public class WebMessageListenerChannelDelegate extends ChannelDelegateImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPostMessage(String message, String sourceOrigin, boolean isMainFrame) {
|
public void onPostMessage(@Nullable WebMessageCompatExt message, String sourceOrigin, boolean isMainFrame) {
|
||||||
MethodChannel channel = getChannel();
|
MethodChannel channel = getChannel();
|
||||||
if (channel == null) return;
|
if (channel == null) return;
|
||||||
Map<String, Object> obj = new HashMap<>();
|
Map<String, Object> obj = new HashMap<>();
|
||||||
obj.put("message", message);
|
obj.put("message", message != null ? message.toMap() : null);
|
||||||
obj.put("sourceOrigin", sourceOrigin);
|
obj.put("sourceOrigin", sourceOrigin);
|
||||||
obj.put("isMainFrame", isMainFrame);
|
obj.put("isMainFrame", isMainFrame);
|
||||||
channel.invokeMethod("onPostMessage", obj);
|
channel.invokeMethod("onPostMessage", obj);
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
## 1.1.1
|
||||||
|
|
||||||
|
- Added `ExchangeableObject.fromMapForceAllInline`.
|
||||||
|
|
||||||
## 1.1.0
|
## 1.1.0
|
||||||
|
|
||||||
- Added `ExchangeableObject.copyMethod`.
|
- Added `ExchangeableObject.copyMethod`.
|
||||||
|
|
|
@ -2,6 +2,7 @@ class ExchangeableObject {
|
||||||
final bool toMapMethod;
|
final bool toMapMethod;
|
||||||
final bool toJsonMethod;
|
final bool toJsonMethod;
|
||||||
final bool fromMapFactory;
|
final bool fromMapFactory;
|
||||||
|
final bool fromMapForceAllInline;
|
||||||
final bool nullableFromMapFactory;
|
final bool nullableFromMapFactory;
|
||||||
final bool toStringMethod;
|
final bool toStringMethod;
|
||||||
final bool copyMethod;
|
final bool copyMethod;
|
||||||
|
@ -10,6 +11,7 @@ class ExchangeableObject {
|
||||||
this.toMapMethod = true,
|
this.toMapMethod = true,
|
||||||
this.toJsonMethod = true,
|
this.toJsonMethod = true,
|
||||||
this.fromMapFactory = true,
|
this.fromMapFactory = true,
|
||||||
|
this.fromMapForceAllInline = false,
|
||||||
this.nullableFromMapFactory = true,
|
this.nullableFromMapFactory = true,
|
||||||
this.toStringMethod = true,
|
this.toStringMethod = true,
|
||||||
this.copyMethod = false
|
this.copyMethod = false
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
name: flutter_inappwebview_internal_annotations
|
name: flutter_inappwebview_internal_annotations
|
||||||
description: Internal annotations used by the generator of flutter_inappwebview plugin
|
description: Internal annotations used by the generator of flutter_inappwebview plugin
|
||||||
version: 1.1.0
|
version: 1.1.1
|
||||||
homepage: https://github.com/pichillilorenzo/flutter_inappwebview
|
homepage: https://github.com/pichillilorenzo/flutter_inappwebview
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.14.0 <3.0.0"
|
sdk: ">=2.15.0 <4.0.0"
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
test: ^1.21.6
|
test: ^1.21.6
|
|
@ -358,7 +358,7 @@ class ExchangeableObjectGenerator
|
||||||
constructorParameter.isFinal || fieldElement.isFinal ||
|
constructorParameter.isFinal || fieldElement.isFinal ||
|
||||||
!Util.typeIsNullable(constructorParameter.type)) &&
|
!Util.typeIsNullable(constructorParameter.type)) &&
|
||||||
!constructorParameter.hasDefaultValue;
|
!constructorParameter.hasDefaultValue;
|
||||||
if (isRequiredParameter || fieldElement.isFinal) {
|
if (isRequiredParameter || fieldElement.isFinal || annotation.read("fromMapForceAllInline").boolValue) {
|
||||||
requiredFields.add('$fieldName: $value,');
|
requiredFields.add('$fieldName: $value,');
|
||||||
} else {
|
} else {
|
||||||
nonRequiredFields.add("instance.$fieldName = $value;");
|
nonRequiredFields.add("instance.$fieldName = $value;");
|
||||||
|
|
|
@ -209,11 +209,10 @@ packages:
|
||||||
flutter_inappwebview_internal_annotations:
|
flutter_inappwebview_internal_annotations:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_inappwebview_internal_annotations
|
path: "../flutter_inappwebview_internal_annotations"
|
||||||
sha256: "064a8ccbc76217dcd3b0fd6c6ea6f549e69b2849a0233b5bb46af9632c3ce2ff"
|
relative: true
|
||||||
url: "https://pub.dev"
|
source: path
|
||||||
source: hosted
|
version: "1.1.1"
|
||||||
version: "1.1.0"
|
|
||||||
frontend_server_client:
|
frontend_server_client:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -12,7 +12,7 @@ dependencies:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
build: ^2.4.0
|
build: ^2.4.0
|
||||||
source_gen: ^1.3.1
|
source_gen: ^1.3.1
|
||||||
flutter_inappwebview_internal_annotations: ^1.1.0
|
flutter_inappwebview_internal_annotations: ^1.1.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.2
|
build_runner: ^2.4.2
|
||||||
|
|
|
@ -10,7 +10,8 @@ void webMessage() {
|
||||||
].contains(defaultTargetPlatform);
|
].contains(defaultTargetPlatform);
|
||||||
|
|
||||||
skippableGroup('WebMessage', () {
|
skippableGroup('WebMessage', () {
|
||||||
skippableTestWidgets('WebMessageChannel', (WidgetTester tester) async {
|
skippableTestWidgets('WebMessageChannel post String',
|
||||||
|
(WidgetTester tester) async {
|
||||||
final Completer<InAppWebViewController> controllerCompleter =
|
final Completer<InAppWebViewController> controllerCompleter =
|
||||||
Completer<InAppWebViewController>();
|
Completer<InAppWebViewController>();
|
||||||
final Completer webMessageCompleter = Completer<String>();
|
final Completer webMessageCompleter = Completer<String>();
|
||||||
|
@ -61,7 +62,7 @@ void webMessage() {
|
||||||
|
|
||||||
await port1.setWebMessageCallback((message) async {
|
await port1.setWebMessageCallback((message) async {
|
||||||
await port1
|
await port1
|
||||||
.postMessage(WebMessage(data: message! + " and back"));
|
.postMessage(WebMessage(data: message!.data + " and back"));
|
||||||
});
|
});
|
||||||
await controller.postWebMessage(
|
await controller.postWebMessage(
|
||||||
message: WebMessage(data: "capturePort", ports: [port2]),
|
message: WebMessage(data: "capturePort", ports: [port2]),
|
||||||
|
@ -78,7 +79,94 @@ void webMessage() {
|
||||||
expect(message, 'JavaScript To Native and back');
|
expect(message, 'JavaScript To Native and back');
|
||||||
});
|
});
|
||||||
|
|
||||||
skippableTestWidgets('WebMessageListener', (WidgetTester tester) async {
|
skippableTestWidgets('WebMessageChannel post ArrayBuffer',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final Completer<InAppWebViewController> controllerCompleter =
|
||||||
|
Completer<InAppWebViewController>();
|
||||||
|
final Completer webMessageCompleter = Completer<String>();
|
||||||
|
await tester.pumpWidget(
|
||||||
|
Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: InAppWebView(
|
||||||
|
key: GlobalKey(),
|
||||||
|
initialData: InAppWebViewInitialData(data: """
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>WebMessageChannel Test</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<button id="button" onclick="port.postMessage(stringToBuffer(input.value));" />Send</button>
|
||||||
|
<br />
|
||||||
|
<input id="input" type="text" value="JavaScript To Native" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function bufferToString(buffer) {
|
||||||
|
return String.fromCharCode.apply(null, Array.from(new Uint8Array(buffer)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringToBuffer(value) {
|
||||||
|
var buffer = new ArrayBuffer(value.length);
|
||||||
|
var view = new Uint8Array(buffer);
|
||||||
|
for (var i = 0, length = value.length; i < length; i++) {
|
||||||
|
view[i] = value.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
var port;
|
||||||
|
window.addEventListener('message', function(event) {
|
||||||
|
if (bufferToString(event.data) == 'capturePort') {
|
||||||
|
if (event.ports[0] != null) {
|
||||||
|
port = event.ports[0];
|
||||||
|
port.onmessage = function (event) {
|
||||||
|
console.log(event.data);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""),
|
||||||
|
onWebViewCreated: (controller) {
|
||||||
|
controllerCompleter.complete(controller);
|
||||||
|
},
|
||||||
|
onConsoleMessage: (controller, consoleMessage) {
|
||||||
|
webMessageCompleter.complete(consoleMessage.message);
|
||||||
|
},
|
||||||
|
onLoadStop: (controller, url) async {
|
||||||
|
var webMessageChannel =
|
||||||
|
await controller.createWebMessageChannel();
|
||||||
|
var port1 = webMessageChannel!.port1;
|
||||||
|
var port2 = webMessageChannel.port2;
|
||||||
|
|
||||||
|
await port1.setWebMessageCallback((message) async {
|
||||||
|
await port1.postMessage(WebMessage(
|
||||||
|
data: utf8.encode(utf8.decode(message!.data) + " and back"),
|
||||||
|
type: WebMessageType.ARRAY_BUFFER));
|
||||||
|
});
|
||||||
|
await controller.postWebMessage(
|
||||||
|
message: WebMessage(
|
||||||
|
data: utf8.encode("capturePort"),
|
||||||
|
type: WebMessageType.ARRAY_BUFFER,
|
||||||
|
ports: [port2]),
|
||||||
|
targetOrigin: WebUri("*"));
|
||||||
|
await controller.evaluateJavascript(
|
||||||
|
source: "document.getElementById('button').click();");
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await controllerCompleter.future;
|
||||||
|
|
||||||
|
final String message = await webMessageCompleter.future;
|
||||||
|
expect(message, 'JavaScript To Native and back');
|
||||||
|
});
|
||||||
|
|
||||||
|
skippableTestWidgets('WebMessageListener post String',
|
||||||
|
(WidgetTester tester) async {
|
||||||
final Completer<InAppWebViewController> controllerCompleter =
|
final Completer<InAppWebViewController> controllerCompleter =
|
||||||
Completer<InAppWebViewController>();
|
Completer<InAppWebViewController>();
|
||||||
final Completer<void> pageLoaded = Completer<void>();
|
final Completer<void> pageLoaded = Completer<void>();
|
||||||
|
@ -97,9 +185,10 @@ void webMessage() {
|
||||||
if (isMainFrame &&
|
if (isMainFrame &&
|
||||||
(sourceOrigin.toString() + '/') ==
|
(sourceOrigin.toString() + '/') ==
|
||||||
TEST_URL_EXAMPLE.toString()) {
|
TEST_URL_EXAMPLE.toString()) {
|
||||||
replyProxy.postMessage(message! + " and back");
|
replyProxy.postMessage(
|
||||||
|
WebMessage(data: message!.data + " and back"));
|
||||||
} else {
|
} else {
|
||||||
replyProxy.postMessage("Nope");
|
replyProxy.postMessage(WebMessage(data: "Nope"));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
@ -130,5 +219,77 @@ void webMessage() {
|
||||||
final String message = await webMessageCompleter.future;
|
final String message = await webMessageCompleter.future;
|
||||||
expect(message, 'JavaScript To Native and back');
|
expect(message, 'JavaScript To Native and back');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
skippableTestWidgets('WebMessageListener post ArrayBuffer',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final Completer<InAppWebViewController> controllerCompleter =
|
||||||
|
Completer<InAppWebViewController>();
|
||||||
|
final Completer<void> pageLoaded = Completer<void>();
|
||||||
|
final Completer webMessageCompleter = Completer<String>();
|
||||||
|
await tester.pumpWidget(
|
||||||
|
Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: InAppWebView(
|
||||||
|
key: GlobalKey(),
|
||||||
|
onWebViewCreated: (controller) async {
|
||||||
|
await controller.addWebMessageListener(WebMessageListener(
|
||||||
|
jsObjectName: "myTestObj",
|
||||||
|
allowedOriginRules: Set.from(["https://*.example.com"]),
|
||||||
|
onPostMessage:
|
||||||
|
(message, sourceOrigin, isMainFrame, replyProxy) {
|
||||||
|
if (isMainFrame &&
|
||||||
|
(sourceOrigin.toString() + '/') ==
|
||||||
|
TEST_URL_EXAMPLE.toString()) {
|
||||||
|
replyProxy.postMessage(WebMessage(
|
||||||
|
data: utf8
|
||||||
|
.encode(utf8.decode(message!.data) + " and back"),
|
||||||
|
type: WebMessageType.ARRAY_BUFFER));
|
||||||
|
} else {
|
||||||
|
replyProxy.postMessage(WebMessage(
|
||||||
|
data: utf8.encode("Nope"),
|
||||||
|
type: WebMessageType.ARRAY_BUFFER));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
));
|
||||||
|
controllerCompleter.complete(controller);
|
||||||
|
},
|
||||||
|
onConsoleMessage: (controller, consoleMessage) {
|
||||||
|
webMessageCompleter.complete(consoleMessage.message);
|
||||||
|
},
|
||||||
|
onLoadStop: (controller, url) async {
|
||||||
|
if (url.toString() == TEST_URL_EXAMPLE.toString()) {
|
||||||
|
pageLoaded.complete();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final controller = await controllerCompleter.future;
|
||||||
|
await controller.loadUrl(urlRequest: URLRequest(url: TEST_URL_EXAMPLE));
|
||||||
|
await pageLoaded.future;
|
||||||
|
|
||||||
|
await controller.evaluateJavascript(source: """
|
||||||
|
function bufferToString(buffer) {
|
||||||
|
return String.fromCharCode.apply(null, Array.from(new Uint8Array(buffer)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringToBuffer(value) {
|
||||||
|
var buffer = new ArrayBuffer(value.length);
|
||||||
|
var view = new Uint8Array(buffer);
|
||||||
|
for (var i = 0, length = value.length; i < length; i++) {
|
||||||
|
view[i] = value.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
myTestObj.addEventListener('message', function(event) {
|
||||||
|
console.log(bufferToString(event.data));
|
||||||
|
});
|
||||||
|
myTestObj.postMessage(stringToBuffer('JavaScript To Native'));
|
||||||
|
""");
|
||||||
|
|
||||||
|
final String message = await webMessageCompleter.future;
|
||||||
|
expect(message, 'JavaScript To Native and back');
|
||||||
|
});
|
||||||
}, skip: shouldSkip);
|
}, skip: shouldSkip);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
part of 'main.dart';
|
||||||
|
|
||||||
|
void apply() {
|
||||||
|
final shouldSkip = kIsWeb
|
||||||
|
? true
|
||||||
|
: ![
|
||||||
|
TargetPlatform.android,
|
||||||
|
].contains(defaultTargetPlatform);
|
||||||
|
|
||||||
|
skippableTestWidgets('apply', (WidgetTester tester) async {
|
||||||
|
await expectLater(
|
||||||
|
ProcessGlobalConfig.instance().apply(
|
||||||
|
settings: ProcessGlobalConfigSettings(
|
||||||
|
dataDirectorySuffix:
|
||||||
|
(await WebViewFeature.isStartupFeatureSupported(
|
||||||
|
WebViewFeature
|
||||||
|
.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX))
|
||||||
|
? 'suffix_inappwebviewexample'
|
||||||
|
: null,
|
||||||
|
directoryBasePaths:
|
||||||
|
(await WebViewFeature.isStartupFeatureSupported(
|
||||||
|
WebViewFeature
|
||||||
|
.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS))
|
||||||
|
? ProcessGlobalConfigDirectoryBasePaths(
|
||||||
|
cacheDirectoryBasePath:
|
||||||
|
(await getApplicationDocumentsDirectory())
|
||||||
|
.absolute
|
||||||
|
.path +
|
||||||
|
'/inappwebviewexample/cache',
|
||||||
|
dataDirectoryBasePath:
|
||||||
|
(await getApplicationDocumentsDirectory())
|
||||||
|
.absolute
|
||||||
|
.path +
|
||||||
|
'/inappwebviewexample/data')
|
||||||
|
: null)),
|
||||||
|
completes);
|
||||||
|
}, skip: shouldSkip);
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import '../constants.dart';
|
||||||
|
import '../env.dart';
|
||||||
|
import '../util.dart';
|
||||||
|
|
||||||
|
part 'apply.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
final shouldSkip = kIsWeb;
|
||||||
|
|
||||||
|
skippableGroup('Process Global Config', () {
|
||||||
|
apply();
|
||||||
|
}, skip: shouldSkip);
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
|
import 'process_global_config/main.dart' as process_global_config_tests;
|
||||||
import 'in_app_webview/main.dart' as in_app_webview_tests;
|
import 'in_app_webview/main.dart' as in_app_webview_tests;
|
||||||
import 'find_interaction_controller/main.dart'
|
import 'find_interaction_controller/main.dart'
|
||||||
as find_interaction_controller_tests;
|
as find_interaction_controller_tests;
|
||||||
|
@ -34,6 +35,7 @@ void main() {
|
||||||
FindInteractionController.debugLoggingSettings.usePrint = true;
|
FindInteractionController.debugLoggingSettings.usePrint = true;
|
||||||
FindInteractionController.debugLoggingSettings.maxLogMessageLength = 7000;
|
FindInteractionController.debugLoggingSettings.maxLogMessageLength = 7000;
|
||||||
|
|
||||||
|
process_global_config_tests.main();
|
||||||
in_app_webview_tests.main();
|
in_app_webview_tests.main();
|
||||||
find_interaction_controller_tests.main();
|
find_interaction_controller_tests.main();
|
||||||
service_worker_controller_tests.main();
|
service_worker_controller_tests.main();
|
||||||
|
|
|
@ -2887,14 +2887,22 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
||||||
let body = message.body as! [String: Any?]
|
let body = message.body as! [String: Any?]
|
||||||
let webMessageChannelId = body["webMessageChannelId"] as! String
|
let webMessageChannelId = body["webMessageChannelId"] as! String
|
||||||
let index = body["index"] as! Int64
|
let index = body["index"] as! Int64
|
||||||
let webMessage = body["message"] as? String
|
var webMessage: WebMessage? = nil
|
||||||
|
if let webMessageMap = body["message"] as? [String : Any?] {
|
||||||
|
webMessage = WebMessage.fromMap(map: webMessageMap)
|
||||||
|
}
|
||||||
|
|
||||||
if let webMessageChannel = webMessageChannels[webMessageChannelId] {
|
if let webMessageChannel = webMessageChannels[webMessageChannelId] {
|
||||||
webMessageChannel.channelDelegate?.onMessage(index: index, message: webMessage)
|
webMessageChannel.channelDelegate?.onMessage(index: index, message: webMessage)
|
||||||
}
|
}
|
||||||
} else if message.name == "onWebMessageListenerPostMessageReceived" {
|
} else if message.name == "onWebMessageListenerPostMessageReceived" {
|
||||||
let body = message.body as! [String: Any?]
|
let body = message.body as! [String: Any?]
|
||||||
let jsObjectName = body["jsObjectName"] as! String
|
let jsObjectName = body["jsObjectName"] as! String
|
||||||
let messageData = body["message"] as? String
|
var webMessage: WebMessage? = nil
|
||||||
|
if let webMessageMap = body["message"] as? [String : Any?] {
|
||||||
|
webMessage = WebMessage.fromMap(map: webMessageMap)
|
||||||
|
}
|
||||||
|
|
||||||
if let webMessageListener = webMessageListeners.first(where: ({($0.jsObjectName == jsObjectName)})) {
|
if let webMessageListener = webMessageListeners.first(where: ({($0.jsObjectName == jsObjectName)})) {
|
||||||
let isMainFrame = message.frameInfo.isMainFrame
|
let isMainFrame = message.frameInfo.isMainFrame
|
||||||
|
|
||||||
|
@ -2920,7 +2928,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
||||||
if let scheme = scheme, !scheme.isEmpty, let host = host, !host.isEmpty {
|
if let scheme = scheme, !scheme.isEmpty, let host = host, !host.isEmpty {
|
||||||
sourceOrigin = URL(string: "\(scheme)://\(host)\(port != nil && port != 0 ? ":" + String(port!) : "")")
|
sourceOrigin = URL(string: "\(scheme)://\(host)\(port != nil && port != 0 ? ":" + String(port!) : "")")
|
||||||
}
|
}
|
||||||
webMessageListener.channelDelegate?.onPostMessage(message: messageData, sourceOrigin: sourceOrigin, isMainFrame: isMainFrame)
|
webMessageListener.channelDelegate?.onPostMessage(message: webMessage, sourceOrigin: sourceOrigin, isMainFrame: isMainFrame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3190,11 +3198,11 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
||||||
}
|
}
|
||||||
portsString = "[" + portArrayString.joined(separator: ", ") + "]"
|
portsString = "[" + portArrayString.joined(separator: ", ") + "]"
|
||||||
}
|
}
|
||||||
let data = message.data?.replacingOccurrences(of: "\'", with: "\\'") ?? "null"
|
|
||||||
let url = URL(string: targetOrigin)?.absoluteString ?? "*"
|
let url = URL(string: targetOrigin)?.absoluteString ?? "*"
|
||||||
let source = """
|
let source = """
|
||||||
(function() {
|
(function() {
|
||||||
window.postMessage('\(data)', '\(url)', \(portsString));
|
window.postMessage(\(message.jsData), '\(url)', \(portsString));
|
||||||
})();
|
})();
|
||||||
"""
|
"""
|
||||||
evaluateJavascript(source: source, completionHandler: completionHandler)
|
evaluateJavascript(source: source, completionHandler: completionHandler)
|
||||||
|
|
|
@ -25,8 +25,8 @@ public class WebMessageChannel : FlutterMethodCallDelegate {
|
||||||
self.channelDelegate = WebMessageChannelChannelDelegate(webMessageChannel: self, channel: channel)
|
self.channelDelegate = WebMessageChannelChannelDelegate(webMessageChannel: self, channel: channel)
|
||||||
}
|
}
|
||||||
self.ports = [
|
self.ports = [
|
||||||
WebMessagePort(name: "port1", webMessageChannel: self),
|
WebMessagePort(name: "port1", index: 0, webMessageChannelId: self.id, webMessageChannel: self),
|
||||||
WebMessagePort(name: "port2", webMessageChannel: self)
|
WebMessagePort(name: "port2", index: 1, webMessageChannelId: self.id, webMessageChannel: self)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,22 +39,20 @@ public class WebMessageChannelChannelDelegate : ChannelDelegate {
|
||||||
if let webView = webMessageChannel?.webView, let ports = webMessageChannel?.ports, ports.count > 0 {
|
if let webView = webMessageChannel?.webView, let ports = webMessageChannel?.ports, ports.count > 0 {
|
||||||
let index = arguments!["index"] as! Int
|
let index = arguments!["index"] as! Int
|
||||||
let port = ports[index]
|
let port = ports[index]
|
||||||
let message = arguments!["message"] as! [String: Any?]
|
var message = WebMessage.fromMap(map: arguments!["message"] as! [String: Any?])
|
||||||
|
|
||||||
var webMessagePorts: [WebMessagePort] = []
|
var ports: [WebMessagePort] = []
|
||||||
let portsMap = message["ports"] as? [[String: Any?]]
|
if let notConnectedPorts = message.ports {
|
||||||
if let portsMap = portsMap {
|
for notConnectedPort in notConnectedPorts {
|
||||||
for portMap in portsMap {
|
if let webMessageChannel = webView.webMessageChannels[notConnectedPort.webMessageChannelId] {
|
||||||
let webMessageChannelId = portMap["webMessageChannelId"] as! String
|
ports.append(webMessageChannel.ports[Int(notConnectedPort.index)])
|
||||||
let index = portMap["index"] as! Int
|
|
||||||
if let webMessageChannel = webView.webMessageChannels[webMessageChannelId] {
|
|
||||||
webMessagePorts.append(webMessageChannel.ports[index])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let webMessage = WebMessage(data: message["data"] as? String, ports: webMessagePorts)
|
message.ports = ports
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try port.postMessage(message: webMessage) { (_) in
|
try port.postMessage(message: message) { (_) in
|
||||||
result(true)
|
result(true)
|
||||||
}
|
}
|
||||||
} catch let error as NSError {
|
} catch let error as NSError {
|
||||||
|
@ -85,10 +83,10 @@ public class WebMessageChannelChannelDelegate : ChannelDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func onMessage(index: Int64, message: String?) {
|
public func onMessage(index: Int64, message: WebMessage?) {
|
||||||
let arguments: [String:Any?] = [
|
let arguments: [String:Any?] = [
|
||||||
"index": index,
|
"index": index,
|
||||||
"message": message
|
"message": message?.toMap()
|
||||||
]
|
]
|
||||||
channel?.invokeMethod("onMessage", arguments: arguments)
|
channel?.invokeMethod("onMessage", arguments: arguments)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,13 @@ public class WebMessageListenerChannelDelegate : ChannelDelegate {
|
||||||
case "postMessage":
|
case "postMessage":
|
||||||
if let webView = webMessageListener?.webView, let jsObjectName = webMessageListener?.jsObjectName {
|
if let webView = webMessageListener?.webView, let jsObjectName = webMessageListener?.jsObjectName {
|
||||||
let jsObjectNameEscaped = jsObjectName.replacingOccurrences(of: "\'", with: "\\'")
|
let jsObjectNameEscaped = jsObjectName.replacingOccurrences(of: "\'", with: "\\'")
|
||||||
let messageEscaped = (arguments!["message"] as! String).replacingOccurrences(of: "\'", with: "\\'")
|
let message = WebMessage.fromMap(map: arguments!["message"] as! [String: Any?])
|
||||||
|
|
||||||
let source = """
|
let source = """
|
||||||
(function() {
|
(function() {
|
||||||
var webMessageListener = window['\(jsObjectNameEscaped)'];
|
var webMessageListener = window['\(jsObjectNameEscaped)'];
|
||||||
if (webMessageListener != null) {
|
if (webMessageListener != null) {
|
||||||
var event = {data: '\(messageEscaped)'};
|
var event = {data: \(message.jsData)};
|
||||||
if (webMessageListener.onmessage != null) {
|
if (webMessageListener.onmessage != null) {
|
||||||
webMessageListener.onmessage(event);
|
webMessageListener.onmessage(event);
|
||||||
}
|
}
|
||||||
|
@ -50,9 +51,9 @@ public class WebMessageListenerChannelDelegate : ChannelDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func onPostMessage(message: String?, sourceOrigin: URL?, isMainFrame: Bool) {
|
public func onPostMessage(message: WebMessage?, sourceOrigin: URL?, isMainFrame: Bool) {
|
||||||
let arguments: [String:Any?] = [
|
let arguments: [String:Any?] = [
|
||||||
"message": message,
|
"message": message?.toMap(),
|
||||||
"sourceOrigin": sourceOrigin?.absoluteString,
|
"sourceOrigin": sourceOrigin?.absoluteString,
|
||||||
"isMainFrame": isMainFrame
|
"isMainFrame": isMainFrame
|
||||||
]
|
]
|
||||||
|
|
|
@ -509,23 +509,21 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
break
|
break
|
||||||
case .postWebMessage:
|
case .postWebMessage:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
let message = arguments!["message"] as! [String: Any?]
|
var message = WebMessage.fromMap(map: arguments!["message"] as! [String: Any?])
|
||||||
let targetOrigin = arguments!["targetOrigin"] as! String
|
let targetOrigin = arguments!["targetOrigin"] as! String
|
||||||
|
|
||||||
var ports: [WebMessagePort] = []
|
var ports: [WebMessagePort] = []
|
||||||
let portsMap = message["ports"] as? [[String: Any?]]
|
if let notConnectedPorts = message.ports {
|
||||||
if let portsMap = portsMap {
|
for notConnectedPort in notConnectedPorts {
|
||||||
for portMap in portsMap {
|
if let webMessageChannel = webView.webMessageChannels[notConnectedPort.webMessageChannelId] {
|
||||||
let webMessageChannelId = portMap["webMessageChannelId"] as! String
|
ports.append(webMessageChannel.ports[Int(notConnectedPort.index)])
|
||||||
let index = portMap["index"] as! Int
|
|
||||||
if let webMessageChannel = webView.webMessageChannels[webMessageChannelId] {
|
|
||||||
ports.append(webMessageChannel.ports[index])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let webMessage = WebMessage(data: message["data"] as? String, ports: ports)
|
message.ports = ports
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try webView.postWebMessage(message: webMessage, targetOrigin: targetOrigin) { (_) in
|
try webView.postWebMessage(message: message, targetOrigin: targetOrigin) { (_) in
|
||||||
result(true)
|
result(true)
|
||||||
}
|
}
|
||||||
} catch let error as NSError {
|
} catch let error as NSError {
|
||||||
|
|
|
@ -13,7 +13,11 @@ function FlutterInAppWebViewWebMessageListener(jsObjectName) {
|
||||||
this.listeners = [];
|
this.listeners = [];
|
||||||
this.onmessage = null;
|
this.onmessage = null;
|
||||||
}
|
}
|
||||||
FlutterInAppWebViewWebMessageListener.prototype.postMessage = function(message) {
|
FlutterInAppWebViewWebMessageListener.prototype.postMessage = function(data) {
|
||||||
|
var message = {
|
||||||
|
"data": window.ArrayBuffer != null && data instanceof ArrayBuffer ? Array.from(new Uint8Array(data)) : (data != null ? data.toString() : null),
|
||||||
|
"type": window.ArrayBuffer != null && data instanceof ArrayBuffer ? 1 : 0
|
||||||
|
};
|
||||||
window.webkit.messageHandlers['onWebMessageListenerPostMessageReceived'].postMessage({jsObjectName: this.jsObjectName, message: message});
|
window.webkit.messageHandlers['onWebMessageListenerPostMessageReceived'].postMessage({jsObjectName: this.jsObjectName, message: message});
|
||||||
};
|
};
|
||||||
FlutterInAppWebViewWebMessageListener.prototype.addEventListener = function(type, listener) {
|
FlutterInAppWebViewWebMessageListener.prototype.addEventListener = function(type, listener) {
|
||||||
|
|
|
@ -7,16 +7,53 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class WebMessage : NSObject {
|
public class WebMessage : NSObject, Disposable {
|
||||||
var data: String?
|
var data: Any?
|
||||||
|
var type: WebMessageType
|
||||||
var ports: [WebMessagePort]?
|
var ports: [WebMessagePort]?
|
||||||
|
|
||||||
public init(data: String?, ports: [WebMessagePort]?) {
|
var jsData: String {
|
||||||
|
var jsData: String = "null"
|
||||||
|
if let messageData = data {
|
||||||
|
if type == .arrayBuffer, let messageDataArrayBuffer = messageData as? FlutterStandardTypedData {
|
||||||
|
jsData = "new Uint8Array(\(Array(messageDataArrayBuffer.data))).buffer"
|
||||||
|
} else if let messageDataString = messageData as? String {
|
||||||
|
jsData = "'\(messageDataString.replacingOccurrences(of: "\'", with: "\\'"))'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jsData
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(data: Any?, type: WebMessageType, ports: [WebMessagePort]?) {
|
||||||
|
self.type = type
|
||||||
super.init()
|
super.init()
|
||||||
self.data = data
|
self.data = data
|
||||||
self.ports = ports
|
self.ports = ports
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func fromMap(map: [String: Any?]) -> WebMessage {
|
||||||
|
let portMapList = map["ports"] as? [[String: Any?]]
|
||||||
|
var ports: [WebMessagePort]? = nil
|
||||||
|
if let portMapList = portMapList, !portMapList.isEmpty {
|
||||||
|
ports = []
|
||||||
|
portMapList.forEach { (portMap) in
|
||||||
|
ports?.append(WebMessagePort.fromMap(map: portMap))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebMessage(
|
||||||
|
data: map["data"] as? Any,
|
||||||
|
type: WebMessageType.init(rawValue: map["type"] as! Int)!,
|
||||||
|
ports: ports)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func toMap () -> [String: Any?] {
|
||||||
|
return [
|
||||||
|
"data": type == .arrayBuffer && data is [UInt8] ? Data(data as! [UInt8]) : data,
|
||||||
|
"type": type.rawValue
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
public func dispose() {
|
public func dispose() {
|
||||||
ports?.removeAll()
|
ports?.removeAll()
|
||||||
}
|
}
|
||||||
|
@ -26,3 +63,8 @@ public class WebMessage : NSObject {
|
||||||
dispose()
|
dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum WebMessageType: Int {
|
||||||
|
case string = 0
|
||||||
|
case arrayBuffer = 1
|
||||||
|
}
|
||||||
|
|
|
@ -9,13 +9,17 @@ import Foundation
|
||||||
|
|
||||||
public class WebMessagePort : NSObject {
|
public class WebMessagePort : NSObject {
|
||||||
var name: String
|
var name: String
|
||||||
|
var index: Int64
|
||||||
|
var webMessageChannelId: String
|
||||||
var webMessageChannel: WebMessageChannel?
|
var webMessageChannel: WebMessageChannel?
|
||||||
var isClosed = false
|
var isClosed = false
|
||||||
var isTransferred = false
|
var isTransferred = false
|
||||||
var isStarted = false
|
var isStarted = false
|
||||||
|
|
||||||
public init(name: String, webMessageChannel: WebMessageChannel) {
|
public init(name: String, index: Int64, webMessageChannelId: String, webMessageChannel: WebMessageChannel?) {
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.index = index
|
||||||
|
self.webMessageChannelId = webMessageChannelId
|
||||||
super.init()
|
super.init()
|
||||||
self.webMessageChannel = webMessageChannel
|
self.webMessageChannel = webMessageChannel
|
||||||
}
|
}
|
||||||
|
@ -35,7 +39,10 @@ public class WebMessagePort : NSObject {
|
||||||
window.webkit.messageHandlers["onWebMessagePortMessageReceived"].postMessage({
|
window.webkit.messageHandlers["onWebMessagePortMessageReceived"].postMessage({
|
||||||
"webMessageChannelId": "\(webMessageChannel.id)",
|
"webMessageChannelId": "\(webMessageChannel.id)",
|
||||||
"index": \(String(index)),
|
"index": \(String(index)),
|
||||||
"message": event.data
|
"message": {
|
||||||
|
"data": window.ArrayBuffer != null && event.data instanceof ArrayBuffer ? Array.from(new Uint8Array(event.data)) : (event.data != null ? event.data.toString() : null),
|
||||||
|
"type": window.ArrayBuffer != null && event.data instanceof ArrayBuffer ? 1 : 0
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,12 +78,12 @@ public class WebMessagePort : NSObject {
|
||||||
}
|
}
|
||||||
portsString = "[" + portArrayString.joined(separator: ", ") + "]"
|
portsString = "[" + portArrayString.joined(separator: ", ") + "]"
|
||||||
}
|
}
|
||||||
let data = message.data?.replacingOccurrences(of: "\'", with: "\\'") ?? "null"
|
|
||||||
let source = """
|
let source = """
|
||||||
(function() {
|
(function() {
|
||||||
var webMessageChannel = \(WEB_MESSAGE_CHANNELS_VARIABLE_NAME)["\(webMessageChannel.id)"];
|
var webMessageChannel = \(WEB_MESSAGE_CHANNELS_VARIABLE_NAME)["\(webMessageChannel.id)"];
|
||||||
if (webMessageChannel != null) {
|
if (webMessageChannel != null) {
|
||||||
webMessageChannel.\(self.name).postMessage('\(data)', \(portsString));
|
webMessageChannel.\(self.name).postMessage(\(message.jsData), \(portsString));
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
"""
|
"""
|
||||||
|
@ -111,6 +118,23 @@ public class WebMessagePort : NSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func fromMap(map: [String: Any?]) -> WebMessagePort {
|
||||||
|
let index = map["index"] as! Int64
|
||||||
|
return WebMessagePort(
|
||||||
|
name: "port\(String(index + 1))",
|
||||||
|
index: index,
|
||||||
|
webMessageChannelId: map["webMessageChannelId"] as! String,
|
||||||
|
webMessageChannel: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func toMap () -> [String: Any?] {
|
||||||
|
return [
|
||||||
|
"name": name,
|
||||||
|
"index": index,
|
||||||
|
"webMessageChannelId": webMessageChannelId
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
public func dispose() {
|
public func dispose() {
|
||||||
isClosed = true
|
isClosed = true
|
||||||
webMessageChannel = nil
|
webMessageChannel = nil
|
||||||
|
|
|
@ -9,3 +9,8 @@ export 'webview_asset_loader.dart'
|
||||||
ResourcesPathHandler,
|
ResourcesPathHandler,
|
||||||
InternalStoragePathHandler;
|
InternalStoragePathHandler;
|
||||||
export 'tracing_controller.dart' show TracingController, TracingSettings;
|
export 'tracing_controller.dart' show TracingController, TracingSettings;
|
||||||
|
export 'process_global_config.dart'
|
||||||
|
show
|
||||||
|
ProcessGlobalConfig,
|
||||||
|
ProcessGlobalConfigSettings,
|
||||||
|
ProcessGlobalConfigDirectoryBasePaths;
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart';
|
||||||
|
import 'webview_feature.dart';
|
||||||
|
import '../in_app_webview/webview.dart';
|
||||||
|
import '../in_app_webview/in_app_webview_controller.dart';
|
||||||
|
import '../cookie_manager.dart';
|
||||||
|
|
||||||
|
part 'process_global_config.g.dart';
|
||||||
|
|
||||||
|
///Process Global Configuration for [WebView].
|
||||||
|
///WebView has some process-global configuration parameters
|
||||||
|
///that cannot be changed once WebView has been loaded.
|
||||||
|
///This class allows apps to set these parameters.
|
||||||
|
///
|
||||||
|
///If it is used, the configuration should be set and apply should
|
||||||
|
///be called prior to loading WebView into the calling process.
|
||||||
|
///Most of the methods in `android.webkit` and `androidx.webkit` packages load WebView,
|
||||||
|
///so the configuration should be applied before calling any of these methods.
|
||||||
|
///
|
||||||
|
///The following code configures the data directory suffix that WebView uses and
|
||||||
|
///then applies the configuration. WebView uses this configuration when it is loaded.
|
||||||
|
///
|
||||||
|
///[apply] can only be called once.
|
||||||
|
///
|
||||||
|
///Only a single thread should access this class at a given time.
|
||||||
|
///
|
||||||
|
///The configuration should be set up as early as possible during application startup,
|
||||||
|
///to ensure that it happens before any other thread can call a method that loads [WebView].
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView ([Official API - ProcessGlobalConfig](https://developer.android.com/reference/androidx/webkit/ProcessGlobalConfig))
|
||||||
|
class ProcessGlobalConfig {
|
||||||
|
static ProcessGlobalConfig? _instance;
|
||||||
|
static const MethodChannel _channel = const MethodChannel(
|
||||||
|
'com.pichillilorenzo/flutter_inappwebview_processglobalconfig');
|
||||||
|
|
||||||
|
ProcessGlobalConfig._();
|
||||||
|
|
||||||
|
///Gets the [ProcessGlobalConfig] shared instance.
|
||||||
|
static ProcessGlobalConfig instance() {
|
||||||
|
return (_instance != null) ? _instance! : _init();
|
||||||
|
}
|
||||||
|
|
||||||
|
static ProcessGlobalConfig _init() {
|
||||||
|
_channel.setMethodCallHandler((call) async {
|
||||||
|
try {
|
||||||
|
return await _handleMethod(call);
|
||||||
|
} on Error catch (e) {
|
||||||
|
print(e);
|
||||||
|
print(e.stackTrace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_instance = ProcessGlobalConfig._();
|
||||||
|
return _instance!;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<dynamic> _handleMethod(MethodCall call) async {
|
||||||
|
// ProcessGlobalConfig controller = ProcessGlobalConfig.instance();
|
||||||
|
switch (call.method) {
|
||||||
|
default:
|
||||||
|
throw UnimplementedError("Unimplemented ${call.method} method");
|
||||||
|
}
|
||||||
|
// return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Applies the configuration to be used by [WebView] on loading.
|
||||||
|
///This method can only be called once.
|
||||||
|
///
|
||||||
|
///Calling this method will not cause [WebView] to be loaded and will not block the calling thread.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView ([Official API - ProcessGlobalConfig.apply](https://developer.android.com/reference/androidx/webkit/ProcessGlobalConfig#apply(androidx.webkit.ProcessGlobalConfig)))
|
||||||
|
Future<void> apply({required ProcessGlobalConfigSettings settings}) async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
args.putIfAbsent("settings", () => settings.toMap());
|
||||||
|
return await _channel.invokeMethod('apply', args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///Class that represents the settings used to configure the [ProcessGlobalConfig].
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
@ExchangeableObject(copyMethod: true)
|
||||||
|
class ProcessGlobalConfigSettings_ {
|
||||||
|
///The directory name suffix to be used for the current process.
|
||||||
|
///Must not contain a path separator and should not be empty.
|
||||||
|
///
|
||||||
|
///Define the directory used to store WebView data for the current process.
|
||||||
|
///The provided suffix will be used when constructing data and cache directory paths.
|
||||||
|
///If this API is not called, no suffix will be used.
|
||||||
|
///Each directory can be used by only one process in the application.
|
||||||
|
///If more than one process in an app wishes to use WebView,
|
||||||
|
///only one process can use the default directory,
|
||||||
|
///and other processes must call this API to define a unique suffix.
|
||||||
|
///
|
||||||
|
///This means that different processes in the same application cannot directly share [WebView]-related data,
|
||||||
|
///since the data directories must be distinct.
|
||||||
|
///Applications that use this API may have to explicitly pass data between processes.
|
||||||
|
///For example, login cookies may have to be copied from one process's cookie jar to the other using [CookieManager] if both processes' WebViews are intended to be logged in.
|
||||||
|
///
|
||||||
|
///Most applications should simply ensure that all components of the app that rely
|
||||||
|
///on WebView are in the same process, to avoid needing multiple data directories.
|
||||||
|
///The [InAppWebViewController.disableWebView] method can be used to ensure that the other processes do not use WebView by accident in this case.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only if [WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX] feature is supported.
|
||||||
|
String? dataDirectorySuffix;
|
||||||
|
|
||||||
|
///Set the base directories that [WebView] will use for the current process.
|
||||||
|
///If this method is not used, [WebView] uses the default base paths defined by the Android framework.
|
||||||
|
///
|
||||||
|
///WebView will create and use a subdirectory under each of the base paths supplied to this method.
|
||||||
|
///
|
||||||
|
///This method can be used in conjunction with setDataDirectorySuffix.
|
||||||
|
///A different subdirectory is created for each suffix.
|
||||||
|
///
|
||||||
|
///The base paths must be absolute paths.
|
||||||
|
///
|
||||||
|
///The data directory must not be under the Android cache directory,
|
||||||
|
///as Android may delete cache files when disk space is low and WebView may not function properly if this occurs.
|
||||||
|
///Refer to [this link](https://developer.android.com/training/data-storage/app-specific#internal-remove-cache).
|
||||||
|
///
|
||||||
|
///If the specified directories already exist then they must be readable and writable by the current process.
|
||||||
|
///If they do not already exist, [WebView] will attempt to create them during initialization, along with any missing parent directories.
|
||||||
|
///In such a case, the directory in which [WebView] creates missing directories must be readable and writable by the current process.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only if [WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS] feature is supported.
|
||||||
|
ProcessGlobalConfigDirectoryBasePaths_? directoryBasePaths;
|
||||||
|
|
||||||
|
ProcessGlobalConfigSettings_(
|
||||||
|
{this.dataDirectorySuffix, this.directoryBasePaths});
|
||||||
|
}
|
||||||
|
|
||||||
|
///Class that represents the settings used to configure the [ProcessGlobalConfigSettings.directoryBasePaths].
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView ([Official API - ProxyConfig](https://developer.android.com/reference/androidx/webkit/ProxyConfig))
|
||||||
|
@ExchangeableObject()
|
||||||
|
class ProcessGlobalConfigDirectoryBasePaths_ {
|
||||||
|
///The absolute base path for the WebView data directory.
|
||||||
|
String dataDirectoryBasePath;
|
||||||
|
|
||||||
|
///The absolute base path for the WebView cache directory.
|
||||||
|
String cacheDirectoryBasePath;
|
||||||
|
|
||||||
|
ProcessGlobalConfigDirectoryBasePaths_(
|
||||||
|
{required this.dataDirectoryBasePath,
|
||||||
|
required this.cacheDirectoryBasePath});
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'process_global_config.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// ExchangeableObjectGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
///Class that represents the settings used to configure the [ProcessGlobalConfig].
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
class ProcessGlobalConfigSettings {
|
||||||
|
///The directory name suffix to be used for the current process.
|
||||||
|
///Must not contain a path separator and should not be empty.
|
||||||
|
///
|
||||||
|
///Define the directory used to store WebView data for the current process.
|
||||||
|
///The provided suffix will be used when constructing data and cache directory paths.
|
||||||
|
///If this API is not called, no suffix will be used.
|
||||||
|
///Each directory can be used by only one process in the application.
|
||||||
|
///If more than one process in an app wishes to use WebView,
|
||||||
|
///only one process can use the default directory,
|
||||||
|
///and other processes must call this API to define a unique suffix.
|
||||||
|
///
|
||||||
|
///This means that different processes in the same application cannot directly share [WebView]-related data,
|
||||||
|
///since the data directories must be distinct.
|
||||||
|
///Applications that use this API may have to explicitly pass data between processes.
|
||||||
|
///For example, login cookies may have to be copied from one process's cookie jar to the other using [CookieManager] if both processes' WebViews are intended to be logged in.
|
||||||
|
///
|
||||||
|
///Most applications should simply ensure that all components of the app that rely
|
||||||
|
///on WebView are in the same process, to avoid needing multiple data directories.
|
||||||
|
///The [InAppWebViewController.disableWebView] method can be used to ensure that the other processes do not use WebView by accident in this case.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only if [WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX] feature is supported.
|
||||||
|
String? dataDirectorySuffix;
|
||||||
|
|
||||||
|
///Set the base directories that [WebView] will use for the current process.
|
||||||
|
///If this method is not used, [WebView] uses the default base paths defined by the Android framework.
|
||||||
|
///
|
||||||
|
///WebView will create and use a subdirectory under each of the base paths supplied to this method.
|
||||||
|
///
|
||||||
|
///This method can be used in conjunction with setDataDirectorySuffix.
|
||||||
|
///A different subdirectory is created for each suffix.
|
||||||
|
///
|
||||||
|
///The base paths must be absolute paths.
|
||||||
|
///
|
||||||
|
///The data directory must not be under the Android cache directory,
|
||||||
|
///as Android may delete cache files when disk space is low and WebView may not function properly if this occurs.
|
||||||
|
///Refer to [this link](https://developer.android.com/training/data-storage/app-specific#internal-remove-cache).
|
||||||
|
///
|
||||||
|
///If the specified directories already exist then they must be readable and writable by the current process.
|
||||||
|
///If they do not already exist, [WebView] will attempt to create them during initialization, along with any missing parent directories.
|
||||||
|
///In such a case, the directory in which [WebView] creates missing directories must be readable and writable by the current process.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only if [WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS] feature is supported.
|
||||||
|
ProcessGlobalConfigDirectoryBasePaths? directoryBasePaths;
|
||||||
|
ProcessGlobalConfigSettings(
|
||||||
|
{this.dataDirectorySuffix, this.directoryBasePaths});
|
||||||
|
|
||||||
|
///Gets a possible [ProcessGlobalConfigSettings] instance from a [Map] value.
|
||||||
|
static ProcessGlobalConfigSettings? fromMap(Map<String, dynamic>? map) {
|
||||||
|
if (map == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final instance = ProcessGlobalConfigSettings(
|
||||||
|
dataDirectorySuffix: map['dataDirectorySuffix'],
|
||||||
|
directoryBasePaths: ProcessGlobalConfigDirectoryBasePaths.fromMap(
|
||||||
|
map['directoryBasePaths']?.cast<String, dynamic>()),
|
||||||
|
);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Converts instance to a map.
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return {
|
||||||
|
"dataDirectorySuffix": dataDirectorySuffix,
|
||||||
|
"directoryBasePaths": directoryBasePaths?.toMap(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
///Converts instance to a map.
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return toMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
///Returns a copy of ProcessGlobalConfigSettings.
|
||||||
|
ProcessGlobalConfigSettings copy() {
|
||||||
|
return ProcessGlobalConfigSettings.fromMap(toMap()) ??
|
||||||
|
ProcessGlobalConfigSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'ProcessGlobalConfigSettings{dataDirectorySuffix: $dataDirectorySuffix, directoryBasePaths: $directoryBasePaths}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///Class that represents the settings used to configure the [ProcessGlobalConfigSettings.directoryBasePaths].
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView ([Official API - ProxyConfig](https://developer.android.com/reference/androidx/webkit/ProxyConfig))
|
||||||
|
class ProcessGlobalConfigDirectoryBasePaths {
|
||||||
|
///The absolute base path for the WebView cache directory.
|
||||||
|
String cacheDirectoryBasePath;
|
||||||
|
|
||||||
|
///The absolute base path for the WebView data directory.
|
||||||
|
String dataDirectoryBasePath;
|
||||||
|
ProcessGlobalConfigDirectoryBasePaths(
|
||||||
|
{required this.cacheDirectoryBasePath,
|
||||||
|
required this.dataDirectoryBasePath});
|
||||||
|
|
||||||
|
///Gets a possible [ProcessGlobalConfigDirectoryBasePaths] instance from a [Map] value.
|
||||||
|
static ProcessGlobalConfigDirectoryBasePaths? fromMap(
|
||||||
|
Map<String, dynamic>? map) {
|
||||||
|
if (map == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final instance = ProcessGlobalConfigDirectoryBasePaths(
|
||||||
|
cacheDirectoryBasePath: map['cacheDirectoryBasePath'],
|
||||||
|
dataDirectoryBasePath: map['dataDirectoryBasePath'],
|
||||||
|
);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Converts instance to a map.
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return {
|
||||||
|
"cacheDirectoryBasePath": cacheDirectoryBasePath,
|
||||||
|
"dataDirectoryBasePath": dataDirectoryBasePath,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
///Converts instance to a map.
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return toMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'ProcessGlobalConfigDirectoryBasePaths{cacheDirectoryBasePath: $cacheDirectoryBasePath, dataDirectoryBasePath: $dataDirectoryBasePath}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -139,41 +139,4 @@ class ProxySettings_ {
|
||||||
this.bypassSimpleHostnames,
|
this.bypassSimpleHostnames,
|
||||||
this.removeImplicitRules,
|
this.removeImplicitRules,
|
||||||
this.reverseBypassEnabled = false});
|
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 'ProxySettings{bypassRules: $bypassRules, directs: $directs, proxyRules: $proxyRules, bypassSimpleHostnames: $bypassSimpleHostnames, removeImplicitRules: $removeImplicitRules, reverseBypassEnabled: $reverseBypassEnabled}';
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ProxySettings copy() {
|
|
||||||
// return ProxySettings.fromMap(this.toMap());
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_inappwebview/src/cookie_manager.dart';
|
|
||||||
import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart';
|
import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart';
|
||||||
|
import 'process_global_config.dart';
|
||||||
|
import '../cookie_manager.dart';
|
||||||
import '../in_app_webview/in_app_webview_controller.dart';
|
import '../in_app_webview/in_app_webview_controller.dart';
|
||||||
import '../in_app_webview/in_app_webview_settings.dart';
|
import '../in_app_webview/in_app_webview_settings.dart';
|
||||||
import 'proxy_controller.dart';
|
import 'proxy_controller.dart';
|
||||||
|
@ -29,18 +30,18 @@ class WebViewFeature_ {
|
||||||
@ExchangeableObjectMethod(ignore: true)
|
@ExchangeableObjectMethod(ignore: true)
|
||||||
String toNativeValue() => _value;
|
String toNativeValue() => _value;
|
||||||
|
|
||||||
///This feature covers [InAppWebViewController.createWebMessageChannel].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewController.createWebMessageChannel].
|
||||||
static const CREATE_WEB_MESSAGE_CHANNEL =
|
static const CREATE_WEB_MESSAGE_CHANNEL =
|
||||||
const WebViewFeature_._internal("CREATE_WEB_MESSAGE_CHANNEL");
|
const WebViewFeature_._internal("CREATE_WEB_MESSAGE_CHANNEL");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.disabledActionModeMenuItems].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.disabledActionModeMenuItems].
|
||||||
static const DISABLED_ACTION_MODE_MENU_ITEMS =
|
static const DISABLED_ACTION_MODE_MENU_ITEMS =
|
||||||
const WebViewFeature_._internal("DISABLED_ACTION_MODE_MENU_ITEMS");
|
const WebViewFeature_._internal("DISABLED_ACTION_MODE_MENU_ITEMS");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.forceDark].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.forceDark].
|
||||||
static const FORCE_DARK = const WebViewFeature_._internal("FORCE_DARK");
|
static const FORCE_DARK = const WebViewFeature_._internal("FORCE_DARK");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.forceDarkStrategy].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.forceDarkStrategy].
|
||||||
static const FORCE_DARK_STRATEGY =
|
static const FORCE_DARK_STRATEGY =
|
||||||
const WebViewFeature_._internal("FORCE_DARK_STRATEGY");
|
const WebViewFeature_._internal("FORCE_DARK_STRATEGY");
|
||||||
|
|
||||||
|
@ -59,19 +60,19 @@ class WebViewFeature_ {
|
||||||
///
|
///
|
||||||
static const MULTI_PROCESS = const WebViewFeature_._internal("MULTI_PROCESS");
|
static const MULTI_PROCESS = const WebViewFeature_._internal("MULTI_PROCESS");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.offscreenPreRaster].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.offscreenPreRaster].
|
||||||
static const OFF_SCREEN_PRERASTER =
|
static const OFF_SCREEN_PRERASTER =
|
||||||
const WebViewFeature_._internal("OFF_SCREEN_PRERASTER");
|
const WebViewFeature_._internal("OFF_SCREEN_PRERASTER");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewController.postWebMessage].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewController.postWebMessage].
|
||||||
static const POST_WEB_MESSAGE =
|
static const POST_WEB_MESSAGE =
|
||||||
const WebViewFeature_._internal("POST_WEB_MESSAGE");
|
const WebViewFeature_._internal("POST_WEB_MESSAGE");
|
||||||
|
|
||||||
///This feature covers [ProxyController.setProxyOverride] and [ProxyController.clearProxyOverride].
|
///Feature for [isFeatureSupported]. This feature covers [ProxyController.setProxyOverride] and [ProxyController.clearProxyOverride].
|
||||||
static const PROXY_OVERRIDE =
|
static const PROXY_OVERRIDE =
|
||||||
const WebViewFeature_._internal("PROXY_OVERRIDE");
|
const WebViewFeature_._internal("PROXY_OVERRIDE");
|
||||||
|
|
||||||
///This feature covers [ProxySettings.reverseBypassEnabled].
|
///Feature for [isFeatureSupported]. This feature covers [ProxySettings.reverseBypassEnabled].
|
||||||
static const PROXY_OVERRIDE_REVERSE_BYPASS =
|
static const PROXY_OVERRIDE_REVERSE_BYPASS =
|
||||||
const WebViewFeature_._internal("PROXY_OVERRIDE_REVERSE_BYPASS");
|
const WebViewFeature_._internal("PROXY_OVERRIDE_REVERSE_BYPASS");
|
||||||
|
|
||||||
|
@ -83,11 +84,11 @@ class WebViewFeature_ {
|
||||||
static const RECEIVE_WEB_RESOURCE_ERROR =
|
static const RECEIVE_WEB_RESOURCE_ERROR =
|
||||||
const WebViewFeature_._internal("RECEIVE_WEB_RESOURCE_ERROR");
|
const WebViewFeature_._internal("RECEIVE_WEB_RESOURCE_ERROR");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewController.setSafeBrowsingAllowlist].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewController.setSafeBrowsingAllowlist].
|
||||||
static const SAFE_BROWSING_ALLOWLIST =
|
static const SAFE_BROWSING_ALLOWLIST =
|
||||||
const WebViewFeature_._internal("SAFE_BROWSING_ALLOWLIST");
|
const WebViewFeature_._internal("SAFE_BROWSING_ALLOWLIST");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.safeBrowsingEnabled].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.safeBrowsingEnabled].
|
||||||
static const SAFE_BROWSING_ENABLE =
|
static const SAFE_BROWSING_ENABLE =
|
||||||
const WebViewFeature_._internal("SAFE_BROWSING_ENABLE");
|
const WebViewFeature_._internal("SAFE_BROWSING_ENABLE");
|
||||||
|
|
||||||
|
@ -95,7 +96,7 @@ class WebViewFeature_ {
|
||||||
static const SAFE_BROWSING_HIT =
|
static const SAFE_BROWSING_HIT =
|
||||||
const WebViewFeature_._internal("SAFE_BROWSING_HIT");
|
const WebViewFeature_._internal("SAFE_BROWSING_HIT");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewController.getSafeBrowsingPrivacyPolicyUrl].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewController.getSafeBrowsingPrivacyPolicyUrl].
|
||||||
static const SAFE_BROWSING_PRIVACY_POLICY_URL =
|
static const SAFE_BROWSING_PRIVACY_POLICY_URL =
|
||||||
const WebViewFeature_._internal("SAFE_BROWSING_PRIVACY_POLICY_URL");
|
const WebViewFeature_._internal("SAFE_BROWSING_PRIVACY_POLICY_URL");
|
||||||
|
|
||||||
|
@ -117,27 +118,27 @@ class WebViewFeature_ {
|
||||||
static const SAFE_BROWSING_WHITELIST =
|
static const SAFE_BROWSING_WHITELIST =
|
||||||
const WebViewFeature_._internal("SAFE_BROWSING_WHITELIST");
|
const WebViewFeature_._internal("SAFE_BROWSING_WHITELIST");
|
||||||
|
|
||||||
///This feature covers [ServiceWorkerController].
|
///Feature for [isFeatureSupported]. This feature covers [ServiceWorkerController].
|
||||||
static const SERVICE_WORKER_BASIC_USAGE =
|
static const SERVICE_WORKER_BASIC_USAGE =
|
||||||
const WebViewFeature_._internal("SERVICE_WORKER_BASIC_USAGE");
|
const WebViewFeature_._internal("SERVICE_WORKER_BASIC_USAGE");
|
||||||
|
|
||||||
///This feature covers [ServiceWorkerController.setBlockNetworkLoads] and [ServiceWorkerController.getBlockNetworkLoads].
|
///Feature for [isFeatureSupported]. This feature covers [ServiceWorkerController.setBlockNetworkLoads] and [ServiceWorkerController.getBlockNetworkLoads].
|
||||||
static const SERVICE_WORKER_BLOCK_NETWORK_LOADS =
|
static const SERVICE_WORKER_BLOCK_NETWORK_LOADS =
|
||||||
const WebViewFeature_._internal("SERVICE_WORKER_BLOCK_NETWORK_LOADS");
|
const WebViewFeature_._internal("SERVICE_WORKER_BLOCK_NETWORK_LOADS");
|
||||||
|
|
||||||
///This feature covers [ServiceWorkerController.setCacheMode] and [ServiceWorkerController.getCacheMode].
|
///Feature for [isFeatureSupported]. This feature covers [ServiceWorkerController.setCacheMode] and [ServiceWorkerController.getCacheMode].
|
||||||
static const SERVICE_WORKER_CACHE_MODE =
|
static const SERVICE_WORKER_CACHE_MODE =
|
||||||
const WebViewFeature_._internal("SERVICE_WORKER_CACHE_MODE");
|
const WebViewFeature_._internal("SERVICE_WORKER_CACHE_MODE");
|
||||||
|
|
||||||
///This feature covers [ServiceWorkerController.setAllowContentAccess] and [ServiceWorkerController.getAllowContentAccess].
|
///Feature for [isFeatureSupported]. This feature covers [ServiceWorkerController.setAllowContentAccess] and [ServiceWorkerController.getAllowContentAccess].
|
||||||
static const SERVICE_WORKER_CONTENT_ACCESS =
|
static const SERVICE_WORKER_CONTENT_ACCESS =
|
||||||
const WebViewFeature_._internal("SERVICE_WORKER_CONTENT_ACCESS");
|
const WebViewFeature_._internal("SERVICE_WORKER_CONTENT_ACCESS");
|
||||||
|
|
||||||
///This feature covers [ServiceWorkerController.setAllowFileAccess] and [ServiceWorkerController.getAllowFileAccess].
|
///Feature for [isFeatureSupported]. This feature covers [ServiceWorkerController.setAllowFileAccess] and [ServiceWorkerController.getAllowFileAccess].
|
||||||
static const SERVICE_WORKER_FILE_ACCESS =
|
static const SERVICE_WORKER_FILE_ACCESS =
|
||||||
const WebViewFeature_._internal("SERVICE_WORKER_FILE_ACCESS");
|
const WebViewFeature_._internal("SERVICE_WORKER_FILE_ACCESS");
|
||||||
|
|
||||||
///This feature covers [ServiceWorkerClient.shouldInterceptRequest].
|
///Feature for [isFeatureSupported]. This feature covers [ServiceWorkerClient.shouldInterceptRequest].
|
||||||
static const SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST =
|
static const SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST =
|
||||||
const WebViewFeature_._internal(
|
const WebViewFeature_._internal(
|
||||||
"SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST");
|
"SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST");
|
||||||
|
@ -146,7 +147,7 @@ class WebViewFeature_ {
|
||||||
static const SHOULD_OVERRIDE_WITH_REDIRECTS =
|
static const SHOULD_OVERRIDE_WITH_REDIRECTS =
|
||||||
const WebViewFeature_._internal("SHOULD_OVERRIDE_WITH_REDIRECTS");
|
const WebViewFeature_._internal("SHOULD_OVERRIDE_WITH_REDIRECTS");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewController.startSafeBrowsing].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewController.startSafeBrowsing].
|
||||||
static const START_SAFE_BROWSING =
|
static const START_SAFE_BROWSING =
|
||||||
const WebViewFeature_._internal("START_SAFE_BROWSING");
|
const WebViewFeature_._internal("START_SAFE_BROWSING");
|
||||||
|
|
||||||
|
@ -162,7 +163,7 @@ class WebViewFeature_ {
|
||||||
static const WEB_MESSAGE_CALLBACK_ON_MESSAGE =
|
static const WEB_MESSAGE_CALLBACK_ON_MESSAGE =
|
||||||
const WebViewFeature_._internal("WEB_MESSAGE_CALLBACK_ON_MESSAGE");
|
const WebViewFeature_._internal("WEB_MESSAGE_CALLBACK_ON_MESSAGE");
|
||||||
|
|
||||||
///This feature covers [WebMessageListener].
|
///Feature for [isFeatureSupported]. This feature covers [WebMessageListener].
|
||||||
static const WEB_MESSAGE_LISTENER =
|
static const WEB_MESSAGE_LISTENER =
|
||||||
const WebViewFeature_._internal("WEB_MESSAGE_LISTENER");
|
const WebViewFeature_._internal("WEB_MESSAGE_LISTENER");
|
||||||
|
|
||||||
|
@ -198,45 +199,90 @@ class WebViewFeature_ {
|
||||||
static const WEB_VIEW_RENDERER_TERMINATE =
|
static const WEB_VIEW_RENDERER_TERMINATE =
|
||||||
const WebViewFeature_._internal("WEB_VIEW_RENDERER_TERMINATE");
|
const WebViewFeature_._internal("WEB_VIEW_RENDERER_TERMINATE");
|
||||||
|
|
||||||
///This feature covers [UserScriptInjectionTime.AT_DOCUMENT_START].
|
///Feature for [isFeatureSupported]. This feature covers [UserScriptInjectionTime.AT_DOCUMENT_START].
|
||||||
static const DOCUMENT_START_SCRIPT =
|
static const DOCUMENT_START_SCRIPT =
|
||||||
const WebViewFeature_._internal("DOCUMENT_START_SCRIPT");
|
const WebViewFeature_._internal("DOCUMENT_START_SCRIPT");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.willSuppressErrorPage].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.willSuppressErrorPage].
|
||||||
static const SUPPRESS_ERROR_PAGE =
|
static const SUPPRESS_ERROR_PAGE =
|
||||||
const WebViewFeature_._internal("SUPPRESS_ERROR_PAGE");
|
const WebViewFeature_._internal("SUPPRESS_ERROR_PAGE");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.algorithmicDarkeningAllowed].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.algorithmicDarkeningAllowed].
|
||||||
static const ALGORITHMIC_DARKENING =
|
static const ALGORITHMIC_DARKENING =
|
||||||
const WebViewFeature_._internal("ALGORITHMIC_DARKENING");
|
const WebViewFeature_._internal("ALGORITHMIC_DARKENING");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.enterpriseAuthenticationAppLinkPolicyEnabled].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.enterpriseAuthenticationAppLinkPolicyEnabled].
|
||||||
static const ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY =
|
static const ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY =
|
||||||
const WebViewFeature_._internal(
|
const WebViewFeature_._internal(
|
||||||
"ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY");
|
"ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewController.getVariationsHeader].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewController.getVariationsHeader].
|
||||||
static const GET_VARIATIONS_HEADER =
|
static const GET_VARIATIONS_HEADER =
|
||||||
const WebViewFeature_._internal("GET_VARIATIONS_HEADER");
|
const WebViewFeature_._internal("GET_VARIATIONS_HEADER");
|
||||||
|
|
||||||
///This feature covers cookie attributes of [CookieManager.getCookie] and [CookieManager.getCookies] methods.
|
///Feature for [isFeatureSupported]. This feature covers cookie attributes of [CookieManager.getCookie] and [CookieManager.getCookies] methods.
|
||||||
static const GET_COOKIE_INFO =
|
static const GET_COOKIE_INFO =
|
||||||
const WebViewFeature_._internal("GET_COOKIE_INFO");
|
const WebViewFeature_._internal("GET_COOKIE_INFO");
|
||||||
|
|
||||||
///This feature covers cookie attributes of [CookieManager.getCookie] and [CookieManager.getCookies] methods.
|
///Feature for [isFeatureSupported]. This feature covers cookie attributes of [CookieManager.getCookie] and [CookieManager.getCookies] methods.
|
||||||
static const REQUESTED_WITH_HEADER_ALLOW_LIST =
|
static const REQUESTED_WITH_HEADER_ALLOW_LIST =
|
||||||
const WebViewFeature_._internal("REQUESTED_WITH_HEADER_ALLOW_LIST");
|
const WebViewFeature_._internal("REQUESTED_WITH_HEADER_ALLOW_LIST");
|
||||||
|
|
||||||
|
///Feature for [isFeatureSupported]. This feature covers [WebMessagePort.postMessage] with `ArrayBuffer` type,
|
||||||
|
///[InAppWebViewController.postWebMessage] with `ArrayBuffer` type, and [JavaScriptReplyProxy.postMessage] with `ArrayBuffer` type.
|
||||||
|
static const WEB_MESSAGE_ARRAY_BUFFER =
|
||||||
|
const WebViewFeature_._internal("WEB_MESSAGE_ARRAY_BUFFER");
|
||||||
|
|
||||||
|
///Feature for [isStartupFeatureSupported]. This feature covers [ProcessGlobalConfigSettings.dataDirectorySuffix].
|
||||||
|
static const STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX =
|
||||||
|
const WebViewFeature_._internal(
|
||||||
|
"STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX");
|
||||||
|
|
||||||
|
///Feature for [isStartupFeatureSupported]. This feature covers [ProcessGlobalConfigSettings.directoryBasePaths].
|
||||||
|
static const STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS =
|
||||||
|
const WebViewFeature_._internal(
|
||||||
|
"STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS");
|
||||||
|
|
||||||
///Return whether a feature is supported at run-time. On devices running Android version `Build.VERSION_CODES.LOLLIPOP` and higher,
|
///Return whether a feature is supported at run-time. On devices running Android version `Build.VERSION_CODES.LOLLIPOP` and higher,
|
||||||
///this will check whether a feature is supported, depending on the combination of the desired feature, the Android version of device,
|
///this will check whether a feature is supported, depending on the combination of the desired feature, the Android version of device,
|
||||||
///and the WebView APK on the device. If running on a device with a lower API level, this will always return `false`.
|
///and the WebView APK on the device. If running on a device with a lower API level, this will always return `false`.
|
||||||
///
|
///
|
||||||
|
///**Note**: This method is different from [isStartupFeatureSupported] and this
|
||||||
|
///method only accepts certain features.
|
||||||
|
///Please verify that the correct feature checking method is used for a particular feature.
|
||||||
|
///
|
||||||
|
///**Note**: If this method returns `false`, it is not safe to invoke the methods
|
||||||
|
///requiring the desired feature.
|
||||||
|
///Furthermore, if this method returns `false` for a particular feature, any callback guarded by that feature will not be invoked.
|
||||||
|
///
|
||||||
///**Official Android API**: https://developer.android.com/reference/androidx/webkit/WebViewFeature#isFeatureSupported(java.lang.String)
|
///**Official Android API**: https://developer.android.com/reference/androidx/webkit/WebViewFeature#isFeatureSupported(java.lang.String)
|
||||||
static Future<bool> isFeatureSupported(WebViewFeature_ feature) async {
|
static Future<bool> isFeatureSupported(WebViewFeature_ feature) async {
|
||||||
Map<String, dynamic> args = <String, dynamic>{};
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
args.putIfAbsent("feature", () => feature.toNativeValue());
|
args.putIfAbsent("feature", () => feature.toNativeValue());
|
||||||
return await _channel.invokeMethod('isFeatureSupported', args);
|
return await _channel.invokeMethod('isFeatureSupported', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///Return whether a startup feature is supported at run-time.
|
||||||
|
///On devices running Android version `Build.VERSION_CODES.LOLLIPOP` and higher,
|
||||||
|
///this will check whether a startup feature is supported,
|
||||||
|
///depending on the combination of the desired feature,
|
||||||
|
///the Android version of device, and the WebView APK on the device.
|
||||||
|
///If running on a device with a lower API level, this will always return `false`.
|
||||||
|
///
|
||||||
|
///**Note**: This method is different from [isFeatureSupported] and this method only accepts startup features.
|
||||||
|
///Please verify that the correct feature checking method is used for a particular feature.
|
||||||
|
///
|
||||||
|
///**Note**: If this method returns `false`, it is not safe to invoke the methods requiring the desired feature.
|
||||||
|
///Furthermore, if this method returns `false` for a particular feature,
|
||||||
|
///any callback guarded by that feature will not be invoked.
|
||||||
|
///
|
||||||
|
///**Official Android API**: https://developer.android.com/reference/androidx/webkit/WebViewFeature#isFeatureSupported(java.lang.String)
|
||||||
|
static Future<bool> isStartupFeatureSupported(
|
||||||
|
WebViewFeature_ startupFeature) async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
args.putIfAbsent("startupFeature", () => startupFeature.toNativeValue());
|
||||||
|
return await _channel.invokeMethod('isStartupFeatureSupported', args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///Class that represents an Android-specific utility class for checking which WebView Support Library features are supported on the device.
|
///Class that represents an Android-specific utility class for checking which WebView Support Library features are supported on the device.
|
||||||
|
@ -430,23 +476,23 @@ class AndroidWebViewFeature_ {
|
||||||
static const WEB_VIEW_RENDERER_TERMINATE =
|
static const WEB_VIEW_RENDERER_TERMINATE =
|
||||||
const AndroidWebViewFeature_._internal("WEB_VIEW_RENDERER_TERMINATE");
|
const AndroidWebViewFeature_._internal("WEB_VIEW_RENDERER_TERMINATE");
|
||||||
|
|
||||||
///This feature covers [UserScriptInjectionTime.AT_DOCUMENT_START].
|
///Feature for [isFeatureSupported]. This feature covers [UserScriptInjectionTime.AT_DOCUMENT_START].
|
||||||
static const DOCUMENT_START_SCRIPT =
|
static const DOCUMENT_START_SCRIPT =
|
||||||
const AndroidWebViewFeature_._internal("DOCUMENT_START_SCRIPT");
|
const AndroidWebViewFeature_._internal("DOCUMENT_START_SCRIPT");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.willSuppressErrorPage].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.willSuppressErrorPage].
|
||||||
static const SUPPRESS_ERROR_PAGE =
|
static const SUPPRESS_ERROR_PAGE =
|
||||||
const AndroidWebViewFeature_._internal("SUPPRESS_ERROR_PAGE");
|
const AndroidWebViewFeature_._internal("SUPPRESS_ERROR_PAGE");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.algorithmicDarkeningAllowed].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.algorithmicDarkeningAllowed].
|
||||||
static const ALGORITHMIC_DARKENING =
|
static const ALGORITHMIC_DARKENING =
|
||||||
const AndroidWebViewFeature_._internal("ALGORITHMIC_DARKENING");
|
const AndroidWebViewFeature_._internal("ALGORITHMIC_DARKENING");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.requestedWithHeaderMode].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.requestedWithHeaderMode].
|
||||||
static const REQUESTED_WITH_HEADER_CONTROL =
|
static const REQUESTED_WITH_HEADER_CONTROL =
|
||||||
const AndroidWebViewFeature_._internal("REQUESTED_WITH_HEADER_CONTROL");
|
const AndroidWebViewFeature_._internal("REQUESTED_WITH_HEADER_CONTROL");
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.enterpriseAuthenticationAppLinkPolicyEnabled].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.enterpriseAuthenticationAppLinkPolicyEnabled].
|
||||||
static const ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY =
|
static const ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY =
|
||||||
const AndroidWebViewFeature_._internal(
|
const AndroidWebViewFeature_._internal(
|
||||||
"ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY");
|
"ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY");
|
||||||
|
|
|
@ -19,40 +19,40 @@ class WebViewFeature {
|
||||||
String value, Function nativeValue) =>
|
String value, Function nativeValue) =>
|
||||||
WebViewFeature._internal(value, nativeValue());
|
WebViewFeature._internal(value, nativeValue());
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.algorithmicDarkeningAllowed].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.algorithmicDarkeningAllowed].
|
||||||
static const ALGORITHMIC_DARKENING = WebViewFeature._internal(
|
static const ALGORITHMIC_DARKENING = WebViewFeature._internal(
|
||||||
'ALGORITHMIC_DARKENING', 'ALGORITHMIC_DARKENING');
|
'ALGORITHMIC_DARKENING', 'ALGORITHMIC_DARKENING');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewController.createWebMessageChannel].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewController.createWebMessageChannel].
|
||||||
static const CREATE_WEB_MESSAGE_CHANNEL = WebViewFeature._internal(
|
static const CREATE_WEB_MESSAGE_CHANNEL = WebViewFeature._internal(
|
||||||
'CREATE_WEB_MESSAGE_CHANNEL', 'CREATE_WEB_MESSAGE_CHANNEL');
|
'CREATE_WEB_MESSAGE_CHANNEL', 'CREATE_WEB_MESSAGE_CHANNEL');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.disabledActionModeMenuItems].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.disabledActionModeMenuItems].
|
||||||
static const DISABLED_ACTION_MODE_MENU_ITEMS = WebViewFeature._internal(
|
static const DISABLED_ACTION_MODE_MENU_ITEMS = WebViewFeature._internal(
|
||||||
'DISABLED_ACTION_MODE_MENU_ITEMS', 'DISABLED_ACTION_MODE_MENU_ITEMS');
|
'DISABLED_ACTION_MODE_MENU_ITEMS', 'DISABLED_ACTION_MODE_MENU_ITEMS');
|
||||||
|
|
||||||
///This feature covers [UserScriptInjectionTime.AT_DOCUMENT_START].
|
///Feature for [isFeatureSupported]. This feature covers [UserScriptInjectionTime.AT_DOCUMENT_START].
|
||||||
static const DOCUMENT_START_SCRIPT = WebViewFeature._internal(
|
static const DOCUMENT_START_SCRIPT = WebViewFeature._internal(
|
||||||
'DOCUMENT_START_SCRIPT', 'DOCUMENT_START_SCRIPT');
|
'DOCUMENT_START_SCRIPT', 'DOCUMENT_START_SCRIPT');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.enterpriseAuthenticationAppLinkPolicyEnabled].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.enterpriseAuthenticationAppLinkPolicyEnabled].
|
||||||
static const ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY =
|
static const ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY =
|
||||||
WebViewFeature._internal('ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY',
|
WebViewFeature._internal('ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY',
|
||||||
'ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY');
|
'ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.forceDark].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.forceDark].
|
||||||
static const FORCE_DARK =
|
static const FORCE_DARK =
|
||||||
WebViewFeature._internal('FORCE_DARK', 'FORCE_DARK');
|
WebViewFeature._internal('FORCE_DARK', 'FORCE_DARK');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.forceDarkStrategy].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.forceDarkStrategy].
|
||||||
static const FORCE_DARK_STRATEGY =
|
static const FORCE_DARK_STRATEGY =
|
||||||
WebViewFeature._internal('FORCE_DARK_STRATEGY', 'FORCE_DARK_STRATEGY');
|
WebViewFeature._internal('FORCE_DARK_STRATEGY', 'FORCE_DARK_STRATEGY');
|
||||||
|
|
||||||
///This feature covers cookie attributes of [CookieManager.getCookie] and [CookieManager.getCookies] methods.
|
///Feature for [isFeatureSupported]. This feature covers cookie attributes of [CookieManager.getCookie] and [CookieManager.getCookies] methods.
|
||||||
static const GET_COOKIE_INFO =
|
static const GET_COOKIE_INFO =
|
||||||
WebViewFeature._internal('GET_COOKIE_INFO', 'GET_COOKIE_INFO');
|
WebViewFeature._internal('GET_COOKIE_INFO', 'GET_COOKIE_INFO');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewController.getVariationsHeader].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewController.getVariationsHeader].
|
||||||
static const GET_VARIATIONS_HEADER = WebViewFeature._internal(
|
static const GET_VARIATIONS_HEADER = WebViewFeature._internal(
|
||||||
'GET_VARIATIONS_HEADER', 'GET_VARIATIONS_HEADER');
|
'GET_VARIATIONS_HEADER', 'GET_VARIATIONS_HEADER');
|
||||||
|
|
||||||
|
@ -72,19 +72,19 @@ class WebViewFeature {
|
||||||
static const MULTI_PROCESS =
|
static const MULTI_PROCESS =
|
||||||
WebViewFeature._internal('MULTI_PROCESS', 'MULTI_PROCESS');
|
WebViewFeature._internal('MULTI_PROCESS', 'MULTI_PROCESS');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.offscreenPreRaster].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.offscreenPreRaster].
|
||||||
static const OFF_SCREEN_PRERASTER =
|
static const OFF_SCREEN_PRERASTER =
|
||||||
WebViewFeature._internal('OFF_SCREEN_PRERASTER', 'OFF_SCREEN_PRERASTER');
|
WebViewFeature._internal('OFF_SCREEN_PRERASTER', 'OFF_SCREEN_PRERASTER');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewController.postWebMessage].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewController.postWebMessage].
|
||||||
static const POST_WEB_MESSAGE =
|
static const POST_WEB_MESSAGE =
|
||||||
WebViewFeature._internal('POST_WEB_MESSAGE', 'POST_WEB_MESSAGE');
|
WebViewFeature._internal('POST_WEB_MESSAGE', 'POST_WEB_MESSAGE');
|
||||||
|
|
||||||
///This feature covers [ProxyController.setProxyOverride] and [ProxyController.clearProxyOverride].
|
///Feature for [isFeatureSupported]. This feature covers [ProxyController.setProxyOverride] and [ProxyController.clearProxyOverride].
|
||||||
static const PROXY_OVERRIDE =
|
static const PROXY_OVERRIDE =
|
||||||
WebViewFeature._internal('PROXY_OVERRIDE', 'PROXY_OVERRIDE');
|
WebViewFeature._internal('PROXY_OVERRIDE', 'PROXY_OVERRIDE');
|
||||||
|
|
||||||
///This feature covers [ProxySettings.reverseBypassEnabled].
|
///Feature for [isFeatureSupported]. This feature covers [ProxySettings.reverseBypassEnabled].
|
||||||
static const PROXY_OVERRIDE_REVERSE_BYPASS = WebViewFeature._internal(
|
static const PROXY_OVERRIDE_REVERSE_BYPASS = WebViewFeature._internal(
|
||||||
'PROXY_OVERRIDE_REVERSE_BYPASS', 'PROXY_OVERRIDE_REVERSE_BYPASS');
|
'PROXY_OVERRIDE_REVERSE_BYPASS', 'PROXY_OVERRIDE_REVERSE_BYPASS');
|
||||||
|
|
||||||
|
@ -96,15 +96,15 @@ class WebViewFeature {
|
||||||
static const RECEIVE_WEB_RESOURCE_ERROR = WebViewFeature._internal(
|
static const RECEIVE_WEB_RESOURCE_ERROR = WebViewFeature._internal(
|
||||||
'RECEIVE_WEB_RESOURCE_ERROR', 'RECEIVE_WEB_RESOURCE_ERROR');
|
'RECEIVE_WEB_RESOURCE_ERROR', 'RECEIVE_WEB_RESOURCE_ERROR');
|
||||||
|
|
||||||
///This feature covers cookie attributes of [CookieManager.getCookie] and [CookieManager.getCookies] methods.
|
///Feature for [isFeatureSupported]. This feature covers cookie attributes of [CookieManager.getCookie] and [CookieManager.getCookies] methods.
|
||||||
static const REQUESTED_WITH_HEADER_ALLOW_LIST = WebViewFeature._internal(
|
static const REQUESTED_WITH_HEADER_ALLOW_LIST = WebViewFeature._internal(
|
||||||
'REQUESTED_WITH_HEADER_ALLOW_LIST', 'REQUESTED_WITH_HEADER_ALLOW_LIST');
|
'REQUESTED_WITH_HEADER_ALLOW_LIST', 'REQUESTED_WITH_HEADER_ALLOW_LIST');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewController.setSafeBrowsingAllowlist].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewController.setSafeBrowsingAllowlist].
|
||||||
static const SAFE_BROWSING_ALLOWLIST = WebViewFeature._internal(
|
static const SAFE_BROWSING_ALLOWLIST = WebViewFeature._internal(
|
||||||
'SAFE_BROWSING_ALLOWLIST', 'SAFE_BROWSING_ALLOWLIST');
|
'SAFE_BROWSING_ALLOWLIST', 'SAFE_BROWSING_ALLOWLIST');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.safeBrowsingEnabled].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.safeBrowsingEnabled].
|
||||||
static const SAFE_BROWSING_ENABLE =
|
static const SAFE_BROWSING_ENABLE =
|
||||||
WebViewFeature._internal('SAFE_BROWSING_ENABLE', 'SAFE_BROWSING_ENABLE');
|
WebViewFeature._internal('SAFE_BROWSING_ENABLE', 'SAFE_BROWSING_ENABLE');
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ class WebViewFeature {
|
||||||
static const SAFE_BROWSING_HIT =
|
static const SAFE_BROWSING_HIT =
|
||||||
WebViewFeature._internal('SAFE_BROWSING_HIT', 'SAFE_BROWSING_HIT');
|
WebViewFeature._internal('SAFE_BROWSING_HIT', 'SAFE_BROWSING_HIT');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewController.getSafeBrowsingPrivacyPolicyUrl].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewController.getSafeBrowsingPrivacyPolicyUrl].
|
||||||
static const SAFE_BROWSING_PRIVACY_POLICY_URL = WebViewFeature._internal(
|
static const SAFE_BROWSING_PRIVACY_POLICY_URL = WebViewFeature._internal(
|
||||||
'SAFE_BROWSING_PRIVACY_POLICY_URL', 'SAFE_BROWSING_PRIVACY_POLICY_URL');
|
'SAFE_BROWSING_PRIVACY_POLICY_URL', 'SAFE_BROWSING_PRIVACY_POLICY_URL');
|
||||||
|
|
||||||
|
@ -134,28 +134,28 @@ class WebViewFeature {
|
||||||
static const SAFE_BROWSING_WHITELIST = WebViewFeature._internal(
|
static const SAFE_BROWSING_WHITELIST = WebViewFeature._internal(
|
||||||
'SAFE_BROWSING_WHITELIST', 'SAFE_BROWSING_WHITELIST');
|
'SAFE_BROWSING_WHITELIST', 'SAFE_BROWSING_WHITELIST');
|
||||||
|
|
||||||
///This feature covers [ServiceWorkerController].
|
///Feature for [isFeatureSupported]. This feature covers [ServiceWorkerController].
|
||||||
static const SERVICE_WORKER_BASIC_USAGE = WebViewFeature._internal(
|
static const SERVICE_WORKER_BASIC_USAGE = WebViewFeature._internal(
|
||||||
'SERVICE_WORKER_BASIC_USAGE', 'SERVICE_WORKER_BASIC_USAGE');
|
'SERVICE_WORKER_BASIC_USAGE', 'SERVICE_WORKER_BASIC_USAGE');
|
||||||
|
|
||||||
///This feature covers [ServiceWorkerController.setBlockNetworkLoads] and [ServiceWorkerController.getBlockNetworkLoads].
|
///Feature for [isFeatureSupported]. This feature covers [ServiceWorkerController.setBlockNetworkLoads] and [ServiceWorkerController.getBlockNetworkLoads].
|
||||||
static const SERVICE_WORKER_BLOCK_NETWORK_LOADS = WebViewFeature._internal(
|
static const SERVICE_WORKER_BLOCK_NETWORK_LOADS = WebViewFeature._internal(
|
||||||
'SERVICE_WORKER_BLOCK_NETWORK_LOADS',
|
'SERVICE_WORKER_BLOCK_NETWORK_LOADS',
|
||||||
'SERVICE_WORKER_BLOCK_NETWORK_LOADS');
|
'SERVICE_WORKER_BLOCK_NETWORK_LOADS');
|
||||||
|
|
||||||
///This feature covers [ServiceWorkerController.setCacheMode] and [ServiceWorkerController.getCacheMode].
|
///Feature for [isFeatureSupported]. This feature covers [ServiceWorkerController.setCacheMode] and [ServiceWorkerController.getCacheMode].
|
||||||
static const SERVICE_WORKER_CACHE_MODE = WebViewFeature._internal(
|
static const SERVICE_WORKER_CACHE_MODE = WebViewFeature._internal(
|
||||||
'SERVICE_WORKER_CACHE_MODE', 'SERVICE_WORKER_CACHE_MODE');
|
'SERVICE_WORKER_CACHE_MODE', 'SERVICE_WORKER_CACHE_MODE');
|
||||||
|
|
||||||
///This feature covers [ServiceWorkerController.setAllowContentAccess] and [ServiceWorkerController.getAllowContentAccess].
|
///Feature for [isFeatureSupported]. This feature covers [ServiceWorkerController.setAllowContentAccess] and [ServiceWorkerController.getAllowContentAccess].
|
||||||
static const SERVICE_WORKER_CONTENT_ACCESS = WebViewFeature._internal(
|
static const SERVICE_WORKER_CONTENT_ACCESS = WebViewFeature._internal(
|
||||||
'SERVICE_WORKER_CONTENT_ACCESS', 'SERVICE_WORKER_CONTENT_ACCESS');
|
'SERVICE_WORKER_CONTENT_ACCESS', 'SERVICE_WORKER_CONTENT_ACCESS');
|
||||||
|
|
||||||
///This feature covers [ServiceWorkerController.setAllowFileAccess] and [ServiceWorkerController.getAllowFileAccess].
|
///Feature for [isFeatureSupported]. This feature covers [ServiceWorkerController.setAllowFileAccess] and [ServiceWorkerController.getAllowFileAccess].
|
||||||
static const SERVICE_WORKER_FILE_ACCESS = WebViewFeature._internal(
|
static const SERVICE_WORKER_FILE_ACCESS = WebViewFeature._internal(
|
||||||
'SERVICE_WORKER_FILE_ACCESS', 'SERVICE_WORKER_FILE_ACCESS');
|
'SERVICE_WORKER_FILE_ACCESS', 'SERVICE_WORKER_FILE_ACCESS');
|
||||||
|
|
||||||
///This feature covers [ServiceWorkerClient.shouldInterceptRequest].
|
///Feature for [isFeatureSupported]. This feature covers [ServiceWorkerClient.shouldInterceptRequest].
|
||||||
static const SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST =
|
static const SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST =
|
||||||
WebViewFeature._internal('SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST',
|
WebViewFeature._internal('SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST',
|
||||||
'SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST');
|
'SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST');
|
||||||
|
@ -164,11 +164,21 @@ class WebViewFeature {
|
||||||
static const SHOULD_OVERRIDE_WITH_REDIRECTS = WebViewFeature._internal(
|
static const SHOULD_OVERRIDE_WITH_REDIRECTS = WebViewFeature._internal(
|
||||||
'SHOULD_OVERRIDE_WITH_REDIRECTS', 'SHOULD_OVERRIDE_WITH_REDIRECTS');
|
'SHOULD_OVERRIDE_WITH_REDIRECTS', 'SHOULD_OVERRIDE_WITH_REDIRECTS');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewController.startSafeBrowsing].
|
///Feature for [isStartupFeatureSupported]. This feature covers [ProcessGlobalConfigSettings.dataDirectorySuffix].
|
||||||
|
static const STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX =
|
||||||
|
WebViewFeature._internal('STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX',
|
||||||
|
'STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX');
|
||||||
|
|
||||||
|
///Feature for [isStartupFeatureSupported]. This feature covers [ProcessGlobalConfigSettings.directoryBasePaths].
|
||||||
|
static const STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS =
|
||||||
|
WebViewFeature._internal('STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS',
|
||||||
|
'STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS');
|
||||||
|
|
||||||
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewController.startSafeBrowsing].
|
||||||
static const START_SAFE_BROWSING =
|
static const START_SAFE_BROWSING =
|
||||||
WebViewFeature._internal('START_SAFE_BROWSING', 'START_SAFE_BROWSING');
|
WebViewFeature._internal('START_SAFE_BROWSING', 'START_SAFE_BROWSING');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.willSuppressErrorPage].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.willSuppressErrorPage].
|
||||||
static const SUPPRESS_ERROR_PAGE =
|
static const SUPPRESS_ERROR_PAGE =
|
||||||
WebViewFeature._internal('SUPPRESS_ERROR_PAGE', 'SUPPRESS_ERROR_PAGE');
|
WebViewFeature._internal('SUPPRESS_ERROR_PAGE', 'SUPPRESS_ERROR_PAGE');
|
||||||
|
|
||||||
|
@ -180,11 +190,16 @@ class WebViewFeature {
|
||||||
static const VISUAL_STATE_CALLBACK = WebViewFeature._internal(
|
static const VISUAL_STATE_CALLBACK = WebViewFeature._internal(
|
||||||
'VISUAL_STATE_CALLBACK', 'VISUAL_STATE_CALLBACK');
|
'VISUAL_STATE_CALLBACK', 'VISUAL_STATE_CALLBACK');
|
||||||
|
|
||||||
|
///Feature for [isFeatureSupported]. This feature covers [WebMessagePort.postMessage] with `ArrayBuffer` type,
|
||||||
|
///[InAppWebViewController.postWebMessage] with `ArrayBuffer` type, and [JavaScriptReplyProxy.postMessage] with `ArrayBuffer` type.
|
||||||
|
static const WEB_MESSAGE_ARRAY_BUFFER = WebViewFeature._internal(
|
||||||
|
'WEB_MESSAGE_ARRAY_BUFFER', 'WEB_MESSAGE_ARRAY_BUFFER');
|
||||||
|
|
||||||
///
|
///
|
||||||
static const WEB_MESSAGE_CALLBACK_ON_MESSAGE = WebViewFeature._internal(
|
static const WEB_MESSAGE_CALLBACK_ON_MESSAGE = WebViewFeature._internal(
|
||||||
'WEB_MESSAGE_CALLBACK_ON_MESSAGE', 'WEB_MESSAGE_CALLBACK_ON_MESSAGE');
|
'WEB_MESSAGE_CALLBACK_ON_MESSAGE', 'WEB_MESSAGE_CALLBACK_ON_MESSAGE');
|
||||||
|
|
||||||
///This feature covers [WebMessageListener].
|
///Feature for [isFeatureSupported]. This feature covers [WebMessageListener].
|
||||||
static const WEB_MESSAGE_LISTENER =
|
static const WEB_MESSAGE_LISTENER =
|
||||||
WebViewFeature._internal('WEB_MESSAGE_LISTENER', 'WEB_MESSAGE_LISTENER');
|
WebViewFeature._internal('WEB_MESSAGE_LISTENER', 'WEB_MESSAGE_LISTENER');
|
||||||
|
|
||||||
|
@ -262,10 +277,13 @@ class WebViewFeature {
|
||||||
WebViewFeature.SERVICE_WORKER_FILE_ACCESS,
|
WebViewFeature.SERVICE_WORKER_FILE_ACCESS,
|
||||||
WebViewFeature.SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST,
|
WebViewFeature.SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST,
|
||||||
WebViewFeature.SHOULD_OVERRIDE_WITH_REDIRECTS,
|
WebViewFeature.SHOULD_OVERRIDE_WITH_REDIRECTS,
|
||||||
|
WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX,
|
||||||
|
WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS,
|
||||||
WebViewFeature.START_SAFE_BROWSING,
|
WebViewFeature.START_SAFE_BROWSING,
|
||||||
WebViewFeature.SUPPRESS_ERROR_PAGE,
|
WebViewFeature.SUPPRESS_ERROR_PAGE,
|
||||||
WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE,
|
WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE,
|
||||||
WebViewFeature.VISUAL_STATE_CALLBACK,
|
WebViewFeature.VISUAL_STATE_CALLBACK,
|
||||||
|
WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER,
|
||||||
WebViewFeature.WEB_MESSAGE_CALLBACK_ON_MESSAGE,
|
WebViewFeature.WEB_MESSAGE_CALLBACK_ON_MESSAGE,
|
||||||
WebViewFeature.WEB_MESSAGE_LISTENER,
|
WebViewFeature.WEB_MESSAGE_LISTENER,
|
||||||
WebViewFeature.WEB_MESSAGE_PORT_CLOSE,
|
WebViewFeature.WEB_MESSAGE_PORT_CLOSE,
|
||||||
|
@ -308,6 +326,14 @@ class WebViewFeature {
|
||||||
///this will check whether a feature is supported, depending on the combination of the desired feature, the Android version of device,
|
///this will check whether a feature is supported, depending on the combination of the desired feature, the Android version of device,
|
||||||
///and the WebView APK on the device. If running on a device with a lower API level, this will always return `false`.
|
///and the WebView APK on the device. If running on a device with a lower API level, this will always return `false`.
|
||||||
///
|
///
|
||||||
|
///**Note**: This method is different from [isStartupFeatureSupported] and this
|
||||||
|
///method only accepts certain features.
|
||||||
|
///Please verify that the correct feature checking method is used for a particular feature.
|
||||||
|
///
|
||||||
|
///**Note**: If this method returns `false`, it is not safe to invoke the methods
|
||||||
|
///requiring the desired feature.
|
||||||
|
///Furthermore, if this method returns `false` for a particular feature, any callback guarded by that feature will not be invoked.
|
||||||
|
///
|
||||||
///**Official Android API**: https://developer.android.com/reference/androidx/webkit/WebViewFeature#isFeatureSupported(java.lang.String)
|
///**Official Android API**: https://developer.android.com/reference/androidx/webkit/WebViewFeature#isFeatureSupported(java.lang.String)
|
||||||
static Future<bool> isFeatureSupported(WebViewFeature feature) async {
|
static Future<bool> isFeatureSupported(WebViewFeature feature) async {
|
||||||
Map<String, dynamic> args = <String, dynamic>{};
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
@ -315,6 +341,28 @@ class WebViewFeature {
|
||||||
return await _channel.invokeMethod('isFeatureSupported', args);
|
return await _channel.invokeMethod('isFeatureSupported', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///Return whether a startup feature is supported at run-time.
|
||||||
|
///On devices running Android version `Build.VERSION_CODES.LOLLIPOP` and higher,
|
||||||
|
///this will check whether a startup feature is supported,
|
||||||
|
///depending on the combination of the desired feature,
|
||||||
|
///the Android version of device, and the WebView APK on the device.
|
||||||
|
///If running on a device with a lower API level, this will always return `false`.
|
||||||
|
///
|
||||||
|
///**Note**: This method is different from [isFeatureSupported] and this method only accepts startup features.
|
||||||
|
///Please verify that the correct feature checking method is used for a particular feature.
|
||||||
|
///
|
||||||
|
///**Note**: If this method returns `false`, it is not safe to invoke the methods requiring the desired feature.
|
||||||
|
///Furthermore, if this method returns `false` for a particular feature,
|
||||||
|
///any callback guarded by that feature will not be invoked.
|
||||||
|
///
|
||||||
|
///**Official Android API**: https://developer.android.com/reference/androidx/webkit/WebViewFeature#isFeatureSupported(java.lang.String)
|
||||||
|
static Future<bool> isStartupFeatureSupported(
|
||||||
|
WebViewFeature startupFeature) async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
args.putIfAbsent("startupFeature", () => startupFeature.toNativeValue());
|
||||||
|
return await _channel.invokeMethod('isStartupFeatureSupported', args);
|
||||||
|
}
|
||||||
|
|
||||||
///Gets [String] value.
|
///Gets [String] value.
|
||||||
String toValue() => _value;
|
String toValue() => _value;
|
||||||
|
|
||||||
|
@ -345,7 +393,7 @@ class AndroidWebViewFeature {
|
||||||
String value, Function nativeValue) =>
|
String value, Function nativeValue) =>
|
||||||
AndroidWebViewFeature._internal(value, nativeValue());
|
AndroidWebViewFeature._internal(value, nativeValue());
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.algorithmicDarkeningAllowed].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.algorithmicDarkeningAllowed].
|
||||||
static const ALGORITHMIC_DARKENING = AndroidWebViewFeature._internal(
|
static const ALGORITHMIC_DARKENING = AndroidWebViewFeature._internal(
|
||||||
'ALGORITHMIC_DARKENING', 'ALGORITHMIC_DARKENING');
|
'ALGORITHMIC_DARKENING', 'ALGORITHMIC_DARKENING');
|
||||||
|
|
||||||
|
@ -358,11 +406,11 @@ class AndroidWebViewFeature {
|
||||||
AndroidWebViewFeature._internal(
|
AndroidWebViewFeature._internal(
|
||||||
'DISABLED_ACTION_MODE_MENU_ITEMS', 'DISABLED_ACTION_MODE_MENU_ITEMS');
|
'DISABLED_ACTION_MODE_MENU_ITEMS', 'DISABLED_ACTION_MODE_MENU_ITEMS');
|
||||||
|
|
||||||
///This feature covers [UserScriptInjectionTime.AT_DOCUMENT_START].
|
///Feature for [isFeatureSupported]. This feature covers [UserScriptInjectionTime.AT_DOCUMENT_START].
|
||||||
static const DOCUMENT_START_SCRIPT = AndroidWebViewFeature._internal(
|
static const DOCUMENT_START_SCRIPT = AndroidWebViewFeature._internal(
|
||||||
'DOCUMENT_START_SCRIPT', 'DOCUMENT_START_SCRIPT');
|
'DOCUMENT_START_SCRIPT', 'DOCUMENT_START_SCRIPT');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.enterpriseAuthenticationAppLinkPolicyEnabled].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.enterpriseAuthenticationAppLinkPolicyEnabled].
|
||||||
static const ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY =
|
static const ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY =
|
||||||
AndroidWebViewFeature._internal(
|
AndroidWebViewFeature._internal(
|
||||||
'ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY',
|
'ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY',
|
||||||
|
@ -412,7 +460,7 @@ class AndroidWebViewFeature {
|
||||||
static const RECEIVE_WEB_RESOURCE_ERROR = AndroidWebViewFeature._internal(
|
static const RECEIVE_WEB_RESOURCE_ERROR = AndroidWebViewFeature._internal(
|
||||||
'RECEIVE_WEB_RESOURCE_ERROR', 'RECEIVE_WEB_RESOURCE_ERROR');
|
'RECEIVE_WEB_RESOURCE_ERROR', 'RECEIVE_WEB_RESOURCE_ERROR');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.requestedWithHeaderMode].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.requestedWithHeaderMode].
|
||||||
static const REQUESTED_WITH_HEADER_CONTROL = AndroidWebViewFeature._internal(
|
static const REQUESTED_WITH_HEADER_CONTROL = AndroidWebViewFeature._internal(
|
||||||
'REQUESTED_WITH_HEADER_CONTROL', 'REQUESTED_WITH_HEADER_CONTROL');
|
'REQUESTED_WITH_HEADER_CONTROL', 'REQUESTED_WITH_HEADER_CONTROL');
|
||||||
|
|
||||||
|
@ -486,7 +534,7 @@ class AndroidWebViewFeature {
|
||||||
static const START_SAFE_BROWSING = AndroidWebViewFeature._internal(
|
static const START_SAFE_BROWSING = AndroidWebViewFeature._internal(
|
||||||
'START_SAFE_BROWSING', 'START_SAFE_BROWSING');
|
'START_SAFE_BROWSING', 'START_SAFE_BROWSING');
|
||||||
|
|
||||||
///This feature covers [InAppWebViewSettings.willSuppressErrorPage].
|
///Feature for [isFeatureSupported]. This feature covers [InAppWebViewSettings.willSuppressErrorPage].
|
||||||
static const SUPPRESS_ERROR_PAGE = AndroidWebViewFeature._internal(
|
static const SUPPRESS_ERROR_PAGE = AndroidWebViewFeature._internal(
|
||||||
'SUPPRESS_ERROR_PAGE', 'SUPPRESS_ERROR_PAGE');
|
'SUPPRESS_ERROR_PAGE', 'SUPPRESS_ERROR_PAGE');
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import 'in_app_webview_keep_alive.dart';
|
||||||
|
|
||||||
import '../print_job/main.dart';
|
import '../print_job/main.dart';
|
||||||
import '../find_interaction/main.dart';
|
import '../find_interaction/main.dart';
|
||||||
|
import '../android/process_global_config.dart';
|
||||||
|
|
||||||
///List of forbidden names for JavaScript handlers.
|
///List of forbidden names for JavaScript handlers.
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
|
@ -3870,6 +3871,24 @@ class InAppWebViewController extends ChannelController {
|
||||||
false;
|
false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///Indicate that the current process does not intend to use WebView,
|
||||||
|
///and that an exception should be thrown if a WebView is created or any other
|
||||||
|
///methods in the `android.webkit` package are used.
|
||||||
|
///
|
||||||
|
///Applications with multiple processes may wish to call this in processes that
|
||||||
|
///are not intended to use WebView to avoid accidentally incurring the memory usage
|
||||||
|
///of initializing WebView in long-lived processes that have no need for it,
|
||||||
|
///and to prevent potential data directory conflicts (see [ProcessGlobalConfigSettings.dataDirectorySuffix]).
|
||||||
|
///
|
||||||
|
///**NOTE for Android**: available only on Android 28+.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView ([Official API - WebView.disableWebView](https://developer.android.com/reference/android/webkit/WebView.html#disableWebView()))
|
||||||
|
static Future<void> disableWebView() async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
await _staticChannel.invokeMethod('disableWebView', args);
|
||||||
|
}
|
||||||
|
|
||||||
///Returns a Boolean value that indicates whether WebKit natively supports resources with the specified URL scheme.
|
///Returns a Boolean value that indicates whether WebKit natively supports resources with the specified URL scheme.
|
||||||
///
|
///
|
||||||
///[urlScheme] represents the URL scheme associated with the resource.
|
///[urlScheme] represents the URL scheme associated with the resource.
|
||||||
|
|
|
@ -2,5 +2,5 @@ import '../web_message/main.dart';
|
||||||
import '../web_uri.dart';
|
import '../web_uri.dart';
|
||||||
|
|
||||||
///The listener for handling [WebMessageListener] events sent by a `postMessage()` on the injected JavaScript object.
|
///The listener for handling [WebMessageListener] events sent by a `postMessage()` on the injected JavaScript object.
|
||||||
typedef void OnPostMessageCallback(String? message, WebUri? sourceOrigin,
|
typedef void OnPostMessageCallback(WebMessage? message, WebUri? sourceOrigin,
|
||||||
bool isMainFrame, JavaScriptReplyProxy replyProxy);
|
bool isMainFrame, JavaScriptReplyProxy replyProxy);
|
||||||
|
|
|
@ -2,4 +2,4 @@ import '../web_message/main.dart';
|
||||||
|
|
||||||
///The listener for handling [WebMessagePort] events.
|
///The listener for handling [WebMessagePort] events.
|
||||||
///The message callback methods are called on the main thread.
|
///The message callback methods are called on the main thread.
|
||||||
typedef void WebMessageCallback(String? message);
|
typedef void WebMessageCallback(WebMessage? message);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export 'web_message.dart' show WebMessage;
|
export 'web_message.dart' show WebMessage, WebMessageType;
|
||||||
export 'web_message_port.dart' show WebMessagePort;
|
export 'web_message_port.dart' show WebMessagePort;
|
||||||
export 'web_message_channel.dart' show WebMessageChannel;
|
export 'web_message_channel.dart' show WebMessageChannel;
|
||||||
export 'web_message_listener.dart';
|
export 'web_message_listener.dart';
|
||||||
|
|
|
@ -1,18 +1,47 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart';
|
import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart';
|
||||||
|
|
||||||
|
import '../android/webview_feature.dart';
|
||||||
import 'web_message_port.dart';
|
import 'web_message_port.dart';
|
||||||
|
|
||||||
part 'web_message.g.dart';
|
part 'web_message.g.dart';
|
||||||
|
|
||||||
///The Dart representation of the HTML5 PostMessage event.
|
///The Dart representation of the HTML5 PostMessage event.
|
||||||
///See https://html.spec.whatwg.org/multipage/comms.html#the-messageevent-interfaces for definition of a MessageEvent in HTML5.
|
///See https://html.spec.whatwg.org/multipage/comms.html#the-messageevent-interfaces for definition of a MessageEvent in HTML5.
|
||||||
@ExchangeableObject()
|
@ExchangeableObject(fromMapForceAllInline: true)
|
||||||
class WebMessage_ {
|
class WebMessage_ {
|
||||||
///The data of the message.
|
///The data of the message.
|
||||||
String? data;
|
dynamic data;
|
||||||
|
|
||||||
|
///The payload type of the message.
|
||||||
|
WebMessageType_ type;
|
||||||
|
|
||||||
///The ports that are sent with the message.
|
///The ports that are sent with the message.
|
||||||
List<WebMessagePort>? ports;
|
List<WebMessagePort>? ports;
|
||||||
|
|
||||||
WebMessage_({this.data, this.ports});
|
@ExchangeableObjectConstructor()
|
||||||
|
WebMessage_({this.data, this.type = WebMessageType_.STRING, this.ports}) {
|
||||||
|
assert(((this.data == null || this.data is String) &&
|
||||||
|
this.type == WebMessageType_.STRING) ||
|
||||||
|
(this.data != null &&
|
||||||
|
this.data is Uint8List &&
|
||||||
|
this.type == WebMessageType_.ARRAY_BUFFER));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///The type corresponding to the [WebMessage].
|
||||||
|
@ExchangeableEnum()
|
||||||
|
class WebMessageType_ {
|
||||||
|
// ignore: unused_field
|
||||||
|
final int _value;
|
||||||
|
|
||||||
|
const WebMessageType_._internal(this._value);
|
||||||
|
|
||||||
|
///Indicates the payload of WebMessageCompat is String.
|
||||||
|
static const STRING = const WebMessageType_._internal(0);
|
||||||
|
|
||||||
|
///Indicates the payload of WebMessageCompat is JavaScript ArrayBuffer.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only if [WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER] feature is supported.
|
||||||
|
static const ARRAY_BUFFER = const WebMessageType_._internal(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,84 @@
|
||||||
|
|
||||||
part of 'web_message.dart';
|
part of 'web_message.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// ExchangeableEnumGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
///The type corresponding to the [WebMessage].
|
||||||
|
class WebMessageType {
|
||||||
|
final int _value;
|
||||||
|
final int _nativeValue;
|
||||||
|
const WebMessageType._internal(this._value, this._nativeValue);
|
||||||
|
// ignore: unused_element
|
||||||
|
factory WebMessageType._internalMultiPlatform(
|
||||||
|
int value, Function nativeValue) =>
|
||||||
|
WebMessageType._internal(value, nativeValue());
|
||||||
|
|
||||||
|
///Indicates the payload of WebMessageCompat is JavaScript ArrayBuffer.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only if [WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER] feature is supported.
|
||||||
|
static const ARRAY_BUFFER = WebMessageType._internal(1, 1);
|
||||||
|
|
||||||
|
///Indicates the payload of WebMessageCompat is String.
|
||||||
|
static const STRING = WebMessageType._internal(0, 0);
|
||||||
|
|
||||||
|
///Set of all values of [WebMessageType].
|
||||||
|
static final Set<WebMessageType> values = [
|
||||||
|
WebMessageType.ARRAY_BUFFER,
|
||||||
|
WebMessageType.STRING,
|
||||||
|
].toSet();
|
||||||
|
|
||||||
|
///Gets a possible [WebMessageType] instance from [int] value.
|
||||||
|
static WebMessageType? fromValue(int? value) {
|
||||||
|
if (value != null) {
|
||||||
|
try {
|
||||||
|
return WebMessageType.values
|
||||||
|
.firstWhere((element) => element.toValue() == value);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Gets a possible [WebMessageType] instance from a native value.
|
||||||
|
static WebMessageType? fromNativeValue(int? value) {
|
||||||
|
if (value != null) {
|
||||||
|
try {
|
||||||
|
return WebMessageType.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 1:
|
||||||
|
return 'ARRAY_BUFFER';
|
||||||
|
case 0:
|
||||||
|
return 'STRING';
|
||||||
|
}
|
||||||
|
return _value.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
// ExchangeableObjectGenerator
|
// ExchangeableObjectGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
@ -10,11 +88,20 @@ part of 'web_message.dart';
|
||||||
///See https://html.spec.whatwg.org/multipage/comms.html#the-messageevent-interfaces for definition of a MessageEvent in HTML5.
|
///See https://html.spec.whatwg.org/multipage/comms.html#the-messageevent-interfaces for definition of a MessageEvent in HTML5.
|
||||||
class WebMessage {
|
class WebMessage {
|
||||||
///The data of the message.
|
///The data of the message.
|
||||||
String? data;
|
dynamic data;
|
||||||
|
|
||||||
///The ports that are sent with the message.
|
///The ports that are sent with the message.
|
||||||
List<WebMessagePort>? ports;
|
List<WebMessagePort>? ports;
|
||||||
WebMessage({this.data, this.ports});
|
|
||||||
|
///The payload type of the message.
|
||||||
|
WebMessageType type;
|
||||||
|
WebMessage({this.data, this.type = WebMessageType.STRING, this.ports}) {
|
||||||
|
assert(((this.data == null || this.data is String) &&
|
||||||
|
this.type == WebMessageType.STRING) ||
|
||||||
|
(this.data != null &&
|
||||||
|
this.data is Uint8List &&
|
||||||
|
this.type == WebMessageType.ARRAY_BUFFER));
|
||||||
|
}
|
||||||
|
|
||||||
///Gets a possible [WebMessage] instance from a [Map] value.
|
///Gets a possible [WebMessage] instance from a [Map] value.
|
||||||
static WebMessage? fromMap(Map<String, dynamic>? map) {
|
static WebMessage? fromMap(Map<String, dynamic>? map) {
|
||||||
|
@ -26,6 +113,7 @@ class WebMessage {
|
||||||
ports: map['ports'] != null
|
ports: map['ports'] != null
|
||||||
? List<WebMessagePort>.from(map['ports'].map((e) => e))
|
? List<WebMessagePort>.from(map['ports'].map((e) => e))
|
||||||
: null,
|
: null,
|
||||||
|
type: WebMessageType.fromNativeValue(map['type'])!,
|
||||||
);
|
);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +123,7 @@ class WebMessage {
|
||||||
return {
|
return {
|
||||||
"data": data,
|
"data": data,
|
||||||
"ports": ports?.map((e) => e.toMap()).toList(),
|
"ports": ports?.map((e) => e.toMap()).toList(),
|
||||||
|
"type": type.toNativeValue(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +134,6 @@ class WebMessage {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'WebMessage{data: $data, ports: $ports}';
|
return 'WebMessage{data: $data, ports: $ports, type: $type}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_inappwebview/src/util.dart';
|
import 'package:flutter_inappwebview/src/util.dart';
|
||||||
import 'web_message_port.dart';
|
import 'web_message_port.dart';
|
||||||
|
import 'web_message.dart';
|
||||||
|
|
||||||
///The representation of the [HTML5 message channels](https://html.spec.whatwg.org/multipage/web-messaging.html#message-channels).
|
///The representation of the [HTML5 message channels](https://html.spec.whatwg.org/multipage/web-messaging.html#message-channels).
|
||||||
///
|
///
|
||||||
|
@ -45,7 +46,10 @@ class WebMessageChannel extends ChannelController {
|
||||||
int index = call.arguments["index"];
|
int index = call.arguments["index"];
|
||||||
var port = index == 0 ? this.port1 : this.port2;
|
var port = index == 0 ? this.port1 : this.port2;
|
||||||
if (port.onMessage != null) {
|
if (port.onMessage != null) {
|
||||||
String? message = call.arguments["message"];
|
WebMessage? message = call.arguments["message"] != null
|
||||||
|
? WebMessage.fromMap(
|
||||||
|
call.arguments["message"].cast<String, dynamic>())
|
||||||
|
: null;
|
||||||
port.onMessage!(message);
|
port.onMessage!(message);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -3,6 +3,7 @@ import '../in_app_webview/in_app_webview_controller.dart';
|
||||||
import '../types/main.dart';
|
import '../types/main.dart';
|
||||||
import '../util.dart';
|
import '../util.dart';
|
||||||
import '../web_uri.dart';
|
import '../web_uri.dart';
|
||||||
|
import 'web_message.dart';
|
||||||
|
|
||||||
///This listener receives messages sent on the JavaScript object which was injected by [InAppWebViewController.addWebMessageListener].
|
///This listener receives messages sent on the JavaScript object which was injected by [InAppWebViewController.addWebMessageListener].
|
||||||
///
|
///
|
||||||
|
@ -56,7 +57,10 @@ class WebMessageListener extends ChannelController {
|
||||||
_replyProxy = new JavaScriptReplyProxy(this);
|
_replyProxy = new JavaScriptReplyProxy(this);
|
||||||
}
|
}
|
||||||
if (onPostMessage != null) {
|
if (onPostMessage != null) {
|
||||||
String? message = call.arguments["message"];
|
WebMessage? message = call.arguments["message"] != null
|
||||||
|
? WebMessage.fromMap(
|
||||||
|
call.arguments["message"].cast<String, dynamic>())
|
||||||
|
: null;
|
||||||
WebUri? sourceOrigin = call.arguments["sourceOrigin"] != null
|
WebUri? sourceOrigin = call.arguments["sourceOrigin"] != null
|
||||||
? WebUri(call.arguments["sourceOrigin"])
|
? WebUri(call.arguments["sourceOrigin"])
|
||||||
: null;
|
: null;
|
||||||
|
@ -107,10 +111,12 @@ class JavaScriptReplyProxy {
|
||||||
|
|
||||||
///Post a [message] to the injected JavaScript object which sent this [JavaScriptReplyProxy].
|
///Post a [message] to the injected JavaScript object which sent this [JavaScriptReplyProxy].
|
||||||
///
|
///
|
||||||
|
///If [message] is of type [WebMessageType.ARRAY_BUFFER], be aware that large byte buffers can lead to out-of-memory crashes on low-end devices.
|
||||||
|
///
|
||||||
///**Official Android API**: https://developer.android.com/reference/androidx/webkit/JavaScriptReplyProxy#postMessage(java.lang.String)
|
///**Official Android API**: https://developer.android.com/reference/androidx/webkit/JavaScriptReplyProxy#postMessage(java.lang.String)
|
||||||
Future<void> postMessage(String message) async {
|
Future<void> postMessage(WebMessage message) async {
|
||||||
Map<String, dynamic> args = <String, dynamic>{};
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
args.putIfAbsent('message', () => message);
|
args.putIfAbsent('message', () => message.toMap());
|
||||||
await _webMessageListener.channel?.invokeMethod('postMessage', args);
|
await _webMessageListener.channel?.invokeMethod('postMessage', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2201,14 +2201,22 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
||||||
let body = message.body as! [String: Any?]
|
let body = message.body as! [String: Any?]
|
||||||
let webMessageChannelId = body["webMessageChannelId"] as! String
|
let webMessageChannelId = body["webMessageChannelId"] as! String
|
||||||
let index = body["index"] as! Int64
|
let index = body["index"] as! Int64
|
||||||
let webMessage = body["message"] as? String
|
var webMessage: WebMessage? = nil
|
||||||
|
if let webMessageMap = body["message"] as? [String : Any?] {
|
||||||
|
webMessage = WebMessage.fromMap(map: webMessageMap)
|
||||||
|
}
|
||||||
|
|
||||||
if let webMessageChannel = webMessageChannels[webMessageChannelId] {
|
if let webMessageChannel = webMessageChannels[webMessageChannelId] {
|
||||||
webMessageChannel.channelDelegate?.onMessage(index: index, message: webMessage)
|
webMessageChannel.channelDelegate?.onMessage(index: index, message: webMessage)
|
||||||
}
|
}
|
||||||
} else if message.name == "onWebMessageListenerPostMessageReceived" {
|
} else if message.name == "onWebMessageListenerPostMessageReceived" {
|
||||||
let body = message.body as! [String: Any?]
|
let body = message.body as! [String: Any?]
|
||||||
let jsObjectName = body["jsObjectName"] as! String
|
let jsObjectName = body["jsObjectName"] as! String
|
||||||
let messageData = body["message"] as? String
|
var webMessage: WebMessage? = nil
|
||||||
|
if let webMessageMap = body["message"] as? [String : Any?] {
|
||||||
|
webMessage = WebMessage.fromMap(map: webMessageMap)
|
||||||
|
}
|
||||||
|
|
||||||
if let webMessageListener = webMessageListeners.first(where: ({($0.jsObjectName == jsObjectName)})) {
|
if let webMessageListener = webMessageListeners.first(where: ({($0.jsObjectName == jsObjectName)})) {
|
||||||
let isMainFrame = message.frameInfo.isMainFrame
|
let isMainFrame = message.frameInfo.isMainFrame
|
||||||
|
|
||||||
|
@ -2225,7 +2233,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
||||||
if !scheme.isEmpty, !host.isEmpty {
|
if !scheme.isEmpty, !host.isEmpty {
|
||||||
sourceOrigin = URL(string: "\(scheme)://\(host)\(port != 0 ? ":" + String(port) : "")")
|
sourceOrigin = URL(string: "\(scheme)://\(host)\(port != 0 ? ":" + String(port) : "")")
|
||||||
}
|
}
|
||||||
webMessageListener.channelDelegate?.onPostMessage(message: messageData, sourceOrigin: sourceOrigin, isMainFrame: isMainFrame)
|
webMessageListener.channelDelegate?.onPostMessage(message: webMessage, sourceOrigin: sourceOrigin, isMainFrame: isMainFrame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2514,11 +2522,11 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
||||||
}
|
}
|
||||||
portsString = "[" + portArrayString.joined(separator: ", ") + "]"
|
portsString = "[" + portArrayString.joined(separator: ", ") + "]"
|
||||||
}
|
}
|
||||||
let data = message.data?.replacingOccurrences(of: "\'", with: "\\'") ?? "null"
|
|
||||||
let url = URL(string: targetOrigin)?.absoluteString ?? "*"
|
let url = URL(string: targetOrigin)?.absoluteString ?? "*"
|
||||||
let source = """
|
let source = """
|
||||||
(function() {
|
(function() {
|
||||||
window.postMessage('\(data)', '\(url)', \(portsString));
|
window.postMessage(\(message.jsData), '\(url)', \(portsString));
|
||||||
})();
|
})();
|
||||||
"""
|
"""
|
||||||
evaluateJavascript(source: source, completionHandler: completionHandler)
|
evaluateJavascript(source: source, completionHandler: completionHandler)
|
||||||
|
|
|
@ -26,8 +26,8 @@ public class WebMessageChannel : FlutterMethodCallDelegate {
|
||||||
self.channelDelegate = WebMessageChannelChannelDelegate(webMessageChannel: self, channel: channel)
|
self.channelDelegate = WebMessageChannelChannelDelegate(webMessageChannel: self, channel: channel)
|
||||||
}
|
}
|
||||||
self.ports = [
|
self.ports = [
|
||||||
WebMessagePort(name: "port1", webMessageChannel: self),
|
WebMessagePort(name: "port1", index: 0, webMessageChannelId: self.id, webMessageChannel: self),
|
||||||
WebMessagePort(name: "port2", webMessageChannel: self)
|
WebMessagePort(name: "port2", index: 1, webMessageChannelId: self.id, webMessageChannel: self)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,22 +40,20 @@ public class WebMessageChannelChannelDelegate : ChannelDelegate {
|
||||||
if let webView = webMessageChannel?.webView, let ports = webMessageChannel?.ports, ports.count > 0 {
|
if let webView = webMessageChannel?.webView, let ports = webMessageChannel?.ports, ports.count > 0 {
|
||||||
let index = arguments!["index"] as! Int
|
let index = arguments!["index"] as! Int
|
||||||
let port = ports[index]
|
let port = ports[index]
|
||||||
let message = arguments!["message"] as! [String: Any?]
|
var message = WebMessage.fromMap(map: arguments!["message"] as! [String: Any?])
|
||||||
|
|
||||||
var webMessagePorts: [WebMessagePort] = []
|
var ports: [WebMessagePort] = []
|
||||||
let portsMap = message["ports"] as? [[String: Any?]]
|
if let notConnectedPorts = message.ports {
|
||||||
if let portsMap = portsMap {
|
for notConnectedPort in notConnectedPorts {
|
||||||
for portMap in portsMap {
|
if let webMessageChannel = webView.webMessageChannels[notConnectedPort.webMessageChannelId] {
|
||||||
let webMessageChannelId = portMap["webMessageChannelId"] as! String
|
ports.append(webMessageChannel.ports[Int(notConnectedPort.index)])
|
||||||
let index = portMap["index"] as! Int
|
|
||||||
if let webMessageChannel = webView.webMessageChannels[webMessageChannelId] {
|
|
||||||
webMessagePorts.append(webMessageChannel.ports[index])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let webMessage = WebMessage(data: message["data"] as? String, ports: webMessagePorts)
|
message.ports = ports
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try port.postMessage(message: webMessage) { (_) in
|
try port.postMessage(message: message) { (_) in
|
||||||
result(true)
|
result(true)
|
||||||
}
|
}
|
||||||
} catch let error as NSError {
|
} catch let error as NSError {
|
||||||
|
@ -86,10 +84,10 @@ public class WebMessageChannelChannelDelegate : ChannelDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func onMessage(index: Int64, message: String?) {
|
public func onMessage(index: Int64, message: WebMessage?) {
|
||||||
let arguments: [String:Any?] = [
|
let arguments: [String:Any?] = [
|
||||||
"index": index,
|
"index": index,
|
||||||
"message": message
|
"message": message?.toMap()
|
||||||
]
|
]
|
||||||
channel?.invokeMethod("onMessage", arguments: arguments)
|
channel?.invokeMethod("onMessage", arguments: arguments)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,12 +23,13 @@ public class WebMessageListenerChannelDelegate : ChannelDelegate {
|
||||||
case "postMessage":
|
case "postMessage":
|
||||||
if let webView = webMessageListener?.webView, let jsObjectName = webMessageListener?.jsObjectName {
|
if let webView = webMessageListener?.webView, let jsObjectName = webMessageListener?.jsObjectName {
|
||||||
let jsObjectNameEscaped = jsObjectName.replacingOccurrences(of: "\'", with: "\\'")
|
let jsObjectNameEscaped = jsObjectName.replacingOccurrences(of: "\'", with: "\\'")
|
||||||
let messageEscaped = (arguments!["message"] as! String).replacingOccurrences(of: "\'", with: "\\'")
|
let message = WebMessage.fromMap(map: arguments!["message"] as! [String: Any?])
|
||||||
|
|
||||||
let source = """
|
let source = """
|
||||||
(function() {
|
(function() {
|
||||||
var webMessageListener = window['\(jsObjectNameEscaped)'];
|
var webMessageListener = window['\(jsObjectNameEscaped)'];
|
||||||
if (webMessageListener != null) {
|
if (webMessageListener != null) {
|
||||||
var event = {data: '\(messageEscaped)'};
|
var event = {data: \(message.jsData)};
|
||||||
if (webMessageListener.onmessage != null) {
|
if (webMessageListener.onmessage != null) {
|
||||||
webMessageListener.onmessage(event);
|
webMessageListener.onmessage(event);
|
||||||
}
|
}
|
||||||
|
@ -51,9 +52,9 @@ public class WebMessageListenerChannelDelegate : ChannelDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func onPostMessage(message: String?, sourceOrigin: URL?, isMainFrame: Bool) {
|
public func onPostMessage(message: WebMessage?, sourceOrigin: URL?, isMainFrame: Bool) {
|
||||||
let arguments: [String:Any?] = [
|
let arguments: [String:Any?] = [
|
||||||
"message": message,
|
"message": message?.toMap(),
|
||||||
"sourceOrigin": sourceOrigin?.absoluteString,
|
"sourceOrigin": sourceOrigin?.absoluteString,
|
||||||
"isMainFrame": isMainFrame
|
"isMainFrame": isMainFrame
|
||||||
]
|
]
|
||||||
|
|
|
@ -480,23 +480,21 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
break
|
break
|
||||||
case .postWebMessage:
|
case .postWebMessage:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
let message = arguments!["message"] as! [String: Any?]
|
var message = WebMessage.fromMap(map: arguments!["message"] as! [String: Any?])
|
||||||
let targetOrigin = arguments!["targetOrigin"] as! String
|
let targetOrigin = arguments!["targetOrigin"] as! String
|
||||||
|
|
||||||
var ports: [WebMessagePort] = []
|
var ports: [WebMessagePort] = []
|
||||||
let portsMap = message["ports"] as? [[String: Any?]]
|
if let notConnectedPorts = message.ports {
|
||||||
if let portsMap = portsMap {
|
for notConnectedPort in notConnectedPorts {
|
||||||
for portMap in portsMap {
|
if let webMessageChannel = webView.webMessageChannels[notConnectedPort.webMessageChannelId] {
|
||||||
let webMessageChannelId = portMap["webMessageChannelId"] as! String
|
ports.append(webMessageChannel.ports[Int(notConnectedPort.index)])
|
||||||
let index = portMap["index"] as! Int
|
|
||||||
if let webMessageChannel = webView.webMessageChannels[webMessageChannelId] {
|
|
||||||
ports.append(webMessageChannel.ports[index])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let webMessage = WebMessage(data: message["data"] as? String, ports: ports)
|
message.ports = ports
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try webView.postWebMessage(message: webMessage, targetOrigin: targetOrigin) { (_) in
|
try webView.postWebMessage(message: message, targetOrigin: targetOrigin) { (_) in
|
||||||
result(true)
|
result(true)
|
||||||
}
|
}
|
||||||
} catch let error as NSError {
|
} catch let error as NSError {
|
||||||
|
|
|
@ -13,7 +13,11 @@ function FlutterInAppWebViewWebMessageListener(jsObjectName) {
|
||||||
this.listeners = [];
|
this.listeners = [];
|
||||||
this.onmessage = null;
|
this.onmessage = null;
|
||||||
}
|
}
|
||||||
FlutterInAppWebViewWebMessageListener.prototype.postMessage = function(message) {
|
FlutterInAppWebViewWebMessageListener.prototype.postMessage = function(data) {
|
||||||
|
var message = {
|
||||||
|
"data": window.ArrayBuffer != null && data instanceof ArrayBuffer ? Array.from(new Uint8Array(data)) : (data != null ? data.toString() : null),
|
||||||
|
"type": window.ArrayBuffer != null && data instanceof ArrayBuffer ? 1 : 0
|
||||||
|
};
|
||||||
window.webkit.messageHandlers['onWebMessageListenerPostMessageReceived'].postMessage({jsObjectName: this.jsObjectName, message: message});
|
window.webkit.messageHandlers['onWebMessageListenerPostMessageReceived'].postMessage({jsObjectName: this.jsObjectName, message: message});
|
||||||
};
|
};
|
||||||
FlutterInAppWebViewWebMessageListener.prototype.addEventListener = function(type, listener) {
|
FlutterInAppWebViewWebMessageListener.prototype.addEventListener = function(type, listener) {
|
||||||
|
|
|
@ -6,17 +6,55 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import FlutterMacOS
|
||||||
|
|
||||||
public class WebMessage : NSObject {
|
public class WebMessage : NSObject, Disposable {
|
||||||
var data: String?
|
var data: Any?
|
||||||
|
var type: WebMessageType
|
||||||
var ports: [WebMessagePort]?
|
var ports: [WebMessagePort]?
|
||||||
|
|
||||||
public init(data: String?, ports: [WebMessagePort]?) {
|
var jsData: String {
|
||||||
|
var jsData: String = "null"
|
||||||
|
if let messageData = data {
|
||||||
|
if type == .arrayBuffer, let messageDataArrayBuffer = messageData as? FlutterStandardTypedData {
|
||||||
|
jsData = "new Uint8Array(\(Array(messageDataArrayBuffer.data))).buffer"
|
||||||
|
} else if let messageDataString = messageData as? String {
|
||||||
|
jsData = "'\(messageDataString.replacingOccurrences(of: "\'", with: "\\'"))'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jsData
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(data: Any?, type: WebMessageType, ports: [WebMessagePort]?) {
|
||||||
|
self.type = type
|
||||||
super.init()
|
super.init()
|
||||||
self.data = data
|
self.data = data
|
||||||
self.ports = ports
|
self.ports = ports
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func fromMap(map: [String: Any?]) -> WebMessage {
|
||||||
|
let portMapList = map["ports"] as? [[String: Any?]]
|
||||||
|
var ports: [WebMessagePort]? = nil
|
||||||
|
if let portMapList = portMapList, !portMapList.isEmpty {
|
||||||
|
ports = []
|
||||||
|
portMapList.forEach { (portMap) in
|
||||||
|
ports?.append(WebMessagePort.fromMap(map: portMap))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebMessage(
|
||||||
|
data: map["data"] as? Any,
|
||||||
|
type: WebMessageType.init(rawValue: map["type"] as! Int)!,
|
||||||
|
ports: ports)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func toMap () -> [String: Any?] {
|
||||||
|
return [
|
||||||
|
"data": type == .arrayBuffer && data is [UInt8] ? Data(data as! [UInt8]) : data,
|
||||||
|
"type": type.rawValue
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
public func dispose() {
|
public func dispose() {
|
||||||
ports?.removeAll()
|
ports?.removeAll()
|
||||||
}
|
}
|
||||||
|
@ -26,3 +64,8 @@ public class WebMessage : NSObject {
|
||||||
dispose()
|
dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum WebMessageType: Int {
|
||||||
|
case string = 0
|
||||||
|
case arrayBuffer = 1
|
||||||
|
}
|
||||||
|
|
|
@ -9,13 +9,17 @@ import Foundation
|
||||||
|
|
||||||
public class WebMessagePort : NSObject {
|
public class WebMessagePort : NSObject {
|
||||||
var name: String
|
var name: String
|
||||||
|
var index: Int64
|
||||||
|
var webMessageChannelId: String
|
||||||
var webMessageChannel: WebMessageChannel?
|
var webMessageChannel: WebMessageChannel?
|
||||||
var isClosed = false
|
var isClosed = false
|
||||||
var isTransferred = false
|
var isTransferred = false
|
||||||
var isStarted = false
|
var isStarted = false
|
||||||
|
|
||||||
public init(name: String, webMessageChannel: WebMessageChannel) {
|
public init(name: String, index: Int64, webMessageChannelId: String, webMessageChannel: WebMessageChannel?) {
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.index = index
|
||||||
|
self.webMessageChannelId = webMessageChannelId
|
||||||
super.init()
|
super.init()
|
||||||
self.webMessageChannel = webMessageChannel
|
self.webMessageChannel = webMessageChannel
|
||||||
}
|
}
|
||||||
|
@ -35,7 +39,10 @@ public class WebMessagePort : NSObject {
|
||||||
window.webkit.messageHandlers["onWebMessagePortMessageReceived"].postMessage({
|
window.webkit.messageHandlers["onWebMessagePortMessageReceived"].postMessage({
|
||||||
"webMessageChannelId": "\(webMessageChannel.id)",
|
"webMessageChannelId": "\(webMessageChannel.id)",
|
||||||
"index": \(String(index)),
|
"index": \(String(index)),
|
||||||
"message": event.data
|
"message": {
|
||||||
|
"data": window.ArrayBuffer != null && event.data instanceof ArrayBuffer ? Array.from(new Uint8Array(event.data)) : (event.data != null ? event.data.toString() : null),
|
||||||
|
"type": window.ArrayBuffer != null && event.data instanceof ArrayBuffer ? 1 : 0
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,12 +78,12 @@ public class WebMessagePort : NSObject {
|
||||||
}
|
}
|
||||||
portsString = "[" + portArrayString.joined(separator: ", ") + "]"
|
portsString = "[" + portArrayString.joined(separator: ", ") + "]"
|
||||||
}
|
}
|
||||||
let data = message.data?.replacingOccurrences(of: "\'", with: "\\'") ?? "null"
|
|
||||||
let source = """
|
let source = """
|
||||||
(function() {
|
(function() {
|
||||||
var webMessageChannel = \(WEB_MESSAGE_CHANNELS_VARIABLE_NAME)["\(webMessageChannel.id)"];
|
var webMessageChannel = \(WEB_MESSAGE_CHANNELS_VARIABLE_NAME)["\(webMessageChannel.id)"];
|
||||||
if (webMessageChannel != null) {
|
if (webMessageChannel != null) {
|
||||||
webMessageChannel.\(self.name).postMessage('\(data)', \(portsString));
|
webMessageChannel.\(self.name).postMessage(\(message.jsData), \(portsString));
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
"""
|
"""
|
||||||
|
@ -111,6 +118,23 @@ public class WebMessagePort : NSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func fromMap(map: [String: Any?]) -> WebMessagePort {
|
||||||
|
let index = map["index"] as! Int64
|
||||||
|
return WebMessagePort(
|
||||||
|
name: "port\(String(index + 1))",
|
||||||
|
index: index,
|
||||||
|
webMessageChannelId: map["webMessageChannelId"] as! String,
|
||||||
|
webMessageChannel: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func toMap () -> [String: Any?] {
|
||||||
|
return [
|
||||||
|
"name": name,
|
||||||
|
"index": index,
|
||||||
|
"webMessageChannelId": webMessageChannelId
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
public func dispose() {
|
public func dispose() {
|
||||||
isClosed = true
|
isClosed = true
|
||||||
webMessageChannel = nil
|
webMessageChannel = nil
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: flutter_inappwebview
|
name: flutter_inappwebview
|
||||||
description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window.
|
description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window.
|
||||||
version: 6.0.0-beta.27
|
version: 6.0.0-beta.28
|
||||||
homepage: https://inappwebview.dev/
|
homepage: https://inappwebview.dev/
|
||||||
repository: https://github.com/pichillilorenzo/flutter_inappwebview
|
repository: https://github.com/pichillilorenzo/flutter_inappwebview
|
||||||
issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues
|
issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues
|
||||||
|
@ -21,7 +21,7 @@ dependencies:
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
js: ^0.6.4
|
js: ^0.6.4
|
||||||
flutter_inappwebview_internal_annotations: ^1.1.0
|
flutter_inappwebview_internal_annotations: ^1.1.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in New Issue