parent
9b3ea1c6a2
commit
7c5931b0f9
|
@ -7,7 +7,8 @@
|
|||
- Added `IOSCookieManager` class and `CookieManager.instance().ios.getAllCookies` iOS-specific method
|
||||
- Added `UserScript`, `UserScriptInjectionTime`, `ContentWorld`, `AndroidWebViewFeature`, `AndroidServiceWorkerController`, `AndroidServiceWorkerClient` classes
|
||||
- Added `initialUserScripts` WebView option
|
||||
- Added `addUserScript`, `addUserScripts`, `removeUserScript`, `removeUserScripts`, `removeAllUserScripts` WebView methods
|
||||
- Added `addUserScript`, `addUserScripts`, `removeUserScript`, `removeUserScripts`, `removeAllUserScripts`, `callAsyncJavaScript` WebView methods
|
||||
- Added `contentWorld` argument to `evaluateJavascript` WebView method
|
||||
- Added `isDirectionalLockEnabled`, `mediaType`, `pageZoom`, `limitsNavigationsToAppBoundDomains` iOS-specific webview options
|
||||
- Added `handlesURLScheme` iOS-specific webview method
|
||||
- Updated integration tests
|
||||
|
@ -29,13 +30,16 @@
|
|||
- Fixed missing `clearHistory` webview method implementation on Android
|
||||
- Fixed iOS crash when using CookieManager getCookies for an URL and the host URL is `null`
|
||||
- Fixed "IOS does not support allowUniversalAccessFromFileURLs" [#654](https://github.com/pichillilorenzo/flutter_inappwebview/issues/654)
|
||||
- Fixed "Failed to load WebView provider: No WebView installed" [#642](https://github.com/pichillilorenzo/flutter_inappwebview/issues/642)
|
||||
- Fixed "java.net.MalformedURLException: unknown protocol: wss - Error using library sipml5 in flutter_inappwebview" [#614](https://github.com/pichillilorenzo/flutter_inappwebview/issues/614)
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
- Minimum Flutter version required is `1.22.0` and Dart SDK `>=2.12.0-0 <3.0.0`
|
||||
- iOS Xcode version `>= 12`
|
||||
- Removed `debuggingEnabled` WebView option; on Android you should use now the `AndroidInAppWebViewController.setWebContentsDebuggingEnabled(bool debuggingEnabled)` static method; on iOS, debugging is always enabled
|
||||
- `allowUniversalAccessFromFileURLs` and `allowFileAccessFromFileURLs` WebView options moved from Android-specific options to cross-platform options.
|
||||
- `allowUniversalAccessFromFileURLs` and `allowFileAccessFromFileURLs` WebView options moved from Android-specific options to cross-platform options
|
||||
- Added `callAsyncJavaScript` name to the list of javaScriptHandlerForbiddenNames
|
||||
|
||||
## 4.0.0+4
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import android.os.Message;
|
|||
import android.print.PrintAttributes;
|
||||
import android.print.PrintDocumentAdapter;
|
||||
import android.print.PrintManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.ActionMode;
|
||||
|
@ -42,6 +43,7 @@ import android.widget.HorizontalScrollView;
|
|||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.webkit.WebViewCompat;
|
||||
|
@ -67,9 +69,11 @@ import java.security.cert.X509Certificate;
|
|||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
|
@ -116,6 +120,8 @@ final public class InAppWebView extends InputAwareWebView {
|
|||
add("page");
|
||||
}};
|
||||
|
||||
public Map<String, MethodChannel.Result> callAsyncJavaScriptResults = new HashMap<>();
|
||||
|
||||
static final String pluginScriptsWrapperJS = "(function(){" +
|
||||
" if (window." + JavaScriptBridgeInterface.name + " == null || window." + JavaScriptBridgeInterface.name + "._pluginScriptsLoaded == null || !window." + JavaScriptBridgeInterface.name + "._pluginScriptsLoaded) {" +
|
||||
" $PLACEHOLDER_VALUE" +
|
||||
|
@ -659,11 +665,22 @@ final public class InAppWebView extends InputAwareWebView {
|
|||
" });" +
|
||||
"})();";
|
||||
|
||||
static final String onWindowBlurEventJS = "(function(){" +
|
||||
" window.addEventListener('blur', function(e) {" +
|
||||
" window." + JavaScriptBridgeInterface.name + ".callHandler('onWindowBlur');" +
|
||||
" });" +
|
||||
"})();";
|
||||
static final String onWindowBlurEventJS = "(function(){" +
|
||||
" window.addEventListener('blur', function(e) {" +
|
||||
" window." + JavaScriptBridgeInterface.name + ".callHandler('onWindowBlur');" +
|
||||
" });" +
|
||||
"})();";
|
||||
|
||||
static final String callAsyncJavaScriptWrapperJS = "(function(obj) {" +
|
||||
" (async function($FUNCTION_ARGUMENT_NAMES) {" +
|
||||
" $FUNCTION_BODY" +
|
||||
" })($FUNCTION_ARGUMENT_VALUES).then(function(value) {" +
|
||||
" window." + JavaScriptBridgeInterface.name + ".callHandler('callAsyncJavaScript', {'value': value, 'error': null, 'resultUuid': '$RESULT_UUID'});" +
|
||||
" }).catch(function(error) {" +
|
||||
" window." + JavaScriptBridgeInterface.name + ".callHandler('callAsyncJavaScript', {'value': null, 'error': error, 'resultUuid': '$RESULT_UUID'});" +
|
||||
" });" +
|
||||
" return null;" +
|
||||
"})($FUNCTION_ARGUMENTS_OBJ);";
|
||||
|
||||
public InAppWebView(Context context) {
|
||||
super(context);
|
||||
|
@ -1521,7 +1538,7 @@ final public class InAppWebView extends InputAwareWebView {
|
|||
});
|
||||
}
|
||||
|
||||
public void evaluateJavascript(String source, String contentWorldName, MethodChannel.Result result) {
|
||||
public void evaluateJavascript(String source, @Nullable String contentWorldName, MethodChannel.Result result) {
|
||||
injectDeferredObject(source, contentWorldName, null, result);
|
||||
}
|
||||
|
||||
|
@ -2093,6 +2110,47 @@ final public class InAppWebView extends InputAwareWebView {
|
|||
return sourceWrapped;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public void callAsyncJavaScript(String functionBody, Map<String, Object> arguments, @Nullable String contentWorldName, @NonNull MethodChannel.Result result) {
|
||||
String resultUuid = UUID.randomUUID().toString();
|
||||
callAsyncJavaScriptResults.put(resultUuid, result);
|
||||
|
||||
JSONObject functionArguments = new JSONObject(arguments);
|
||||
Iterator<String> keys = functionArguments.keys();
|
||||
|
||||
List<String> functionArgumentNamesList = new ArrayList<>();
|
||||
List<String> functionArgumentValuesList = new ArrayList<>();
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
functionArgumentNamesList.add(key);
|
||||
functionArgumentValuesList.add("obj." + key);
|
||||
}
|
||||
|
||||
String functionArgumentNames = TextUtils.join(", ", functionArgumentNamesList);
|
||||
String functionArgumentValues = TextUtils.join(", ", functionArgumentValuesList);
|
||||
String functionArgumentsObj = Util.JSONStringify(arguments);
|
||||
|
||||
String sourceToInject = InAppWebView.callAsyncJavaScriptWrapperJS
|
||||
.replace("$FUNCTION_ARGUMENT_NAMES", functionArgumentNames)
|
||||
.replace("$FUNCTION_ARGUMENT_VALUES", functionArgumentValues)
|
||||
.replace("$FUNCTION_ARGUMENTS_OBJ", functionArgumentsObj)
|
||||
.replace("$FUNCTION_BODY", functionBody)
|
||||
.replace("$RESULT_UUID", resultUuid);
|
||||
|
||||
if (contentWorldName != null && !contentWorldName.equals("page")) {
|
||||
if (!userScriptsContentWorlds.contains(contentWorldName)) {
|
||||
userScriptsContentWorlds.add(contentWorldName);
|
||||
// Add only the first time all the plugin scripts needed.
|
||||
String jsPluginScripts = prepareAndWrapPluginUserScripts();
|
||||
sourceToInject = jsPluginScripts + "\n" + sourceToInject;
|
||||
}
|
||||
sourceToInject = wrapSourceCodeInContentWorld(contentWorldName, sourceToInject);
|
||||
|
||||
}
|
||||
|
||||
evaluateJavascript(sourceToInject, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (windowId != null && InAppWebViewChromeClient.windowWebViewMessages.containsKey(windowId)) {
|
||||
|
@ -2106,6 +2164,7 @@ final public class InAppWebView extends InputAwareWebView {
|
|||
removeCallbacks(checkContextMenuShouldBeClosedTask);
|
||||
if (checkScrollStoppedTask != null)
|
||||
removeCallbacks(checkScrollStoppedTask);
|
||||
callAsyncJavaScriptResults.clear();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivit
|
|||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
@ -341,10 +340,10 @@ public class InAppWebViewClient extends WebViewClient {
|
|||
@Override
|
||||
public void onReceivedHttpAuthRequest(final WebView view, final HttpAuthHandler handler, final String host, final String realm) {
|
||||
|
||||
URL url;
|
||||
URI uri;
|
||||
try {
|
||||
url = new URL(view.getUrl());
|
||||
} catch (MalformedURLException e) {
|
||||
uri = new URI(view.getUrl());
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
credentialsProposed = null;
|
||||
|
@ -354,8 +353,8 @@ public class InAppWebViewClient extends WebViewClient {
|
|||
return;
|
||||
}
|
||||
|
||||
final String protocol = url.getProtocol();
|
||||
final int port = url.getPort();
|
||||
final String protocol = uri.getScheme();
|
||||
final int port = uri.getPort();
|
||||
|
||||
previousAuthRequestFailureCount++;
|
||||
|
||||
|
@ -422,19 +421,19 @@ public class InAppWebViewClient extends WebViewClient {
|
|||
|
||||
@Override
|
||||
public void onReceivedSslError(final WebView view, final SslErrorHandler handler, final SslError error) {
|
||||
URL url;
|
||||
URI uri;
|
||||
try {
|
||||
url = new URL(error.getUrl());
|
||||
} catch (MalformedURLException e) {
|
||||
uri = new URI(view.getUrl());
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
handler.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
final String host = url.getHost();
|
||||
final String protocol = url.getProtocol();
|
||||
final String host = uri.getHost();
|
||||
final String protocol = uri.getScheme();
|
||||
final String realm = null;
|
||||
final int port = url.getPort();
|
||||
final int port = uri.getPort();
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("host", host);
|
||||
|
@ -507,16 +506,16 @@ public class InAppWebViewClient extends WebViewClient {
|
|||
@Override
|
||||
public void onReceivedClientCertRequest(final WebView view, final ClientCertRequest request) {
|
||||
|
||||
URL url;
|
||||
URI uri;
|
||||
try {
|
||||
url = new URL(view.getUrl());
|
||||
} catch (MalformedURLException e) {
|
||||
uri = new URI(view.getUrl());
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
request.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
final String protocol = url.getProtocol();
|
||||
final String protocol = uri.getScheme();
|
||||
final String realm = null;
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
|
|
|
@ -438,6 +438,17 @@ public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandle
|
|||
}
|
||||
result.success(true);
|
||||
break;
|
||||
case "callAsyncJavaScript":
|
||||
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
String functionBody = (String) call.argument("functionBody");
|
||||
Map<String, Object> functionArguments = (Map<String, Object>) call.argument("arguments");
|
||||
String contentWorldName = (String) call.argument("contentWorld");
|
||||
webView.callAsyncJavaScript(functionBody, functionArguments, contentWorldName, result);
|
||||
}
|
||||
else {
|
||||
result.success(null);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
result.notImplemented();
|
||||
}
|
||||
|
|
|
@ -11,6 +11,10 @@ import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivit
|
|||
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.FlutterWebView;
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -96,6 +100,21 @@ public class JavaScriptBridgeInterface {
|
|||
|
||||
if (handlerName.equals("onPrint") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
webView.printCurrentPage();
|
||||
} else if (handlerName.equals("callAsyncJavaScript")) {
|
||||
try {
|
||||
JSONArray arguments = new JSONArray(args);
|
||||
JSONObject jsonObject = arguments.getJSONObject(0);
|
||||
String resultUuid = jsonObject.getString("resultUuid");
|
||||
if (webView.callAsyncJavaScriptResults.containsKey(resultUuid)) {
|
||||
MethodChannel.Result callAsyncJavaScriptResult = webView.callAsyncJavaScriptResults.get(resultUuid);
|
||||
callAsyncJavaScriptResult.success(jsonObject.toString());
|
||||
|
||||
webView.callAsyncJavaScriptResults.remove(resultUuid);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
channel.invokeMethod("onCallJsHandler", obj, new MethodChannel.Result() {
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
package com.pichillilorenzo.flutter_inappwebview;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.webkit.CookieManager;
|
||||
import android.webkit.CookieSyncManager;
|
||||
import android.webkit.ValueCallback;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
@ -16,6 +24,7 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import io.flutter.plugin.common.BinaryMessenger;
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
|
@ -29,10 +38,13 @@ public class MyCookieManager implements MethodChannel.MethodCallHandler {
|
|||
public static MethodChannel channel;
|
||||
public static CookieManager cookieManager;
|
||||
|
||||
// As CookieManager was synchronous before API 21 this class emulates the async behavior on <21.
|
||||
private static final boolean USES_LEGACY_STORE = Build.VERSION.SDK_INT < 21;
|
||||
|
||||
public MyCookieManager(BinaryMessenger messenger) {
|
||||
channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_inappwebview_cookiemanager");
|
||||
channel.setMethodCallHandler(this);
|
||||
cookieManager = CookieManager.getInstance();
|
||||
cookieManager = getCookieManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,6 +104,40 @@ public class MyCookieManager implements MethodChannel.MethodCallHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiating CookieManager will load the Chromium task taking a 100ish ms so we do it lazily
|
||||
* to make sure it's done on a background thread as needed.
|
||||
*
|
||||
* https://github.com/facebook/react-native/blob/1903f6680d9750e244d97c3cd4a9f755a9a47c61/ReactAndroid/src/main/java/com/facebook/react/modules/network/ForwardingCookieHandler.java#L132
|
||||
*/
|
||||
static private @Nullable CookieManager getCookieManager() {
|
||||
if (cookieManager == null) {
|
||||
try {
|
||||
cookieManager = CookieManager.getInstance();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=559720
|
||||
return null;
|
||||
} catch (Exception exception) {
|
||||
String message = exception.getMessage();
|
||||
// We cannot catch MissingWebViewPackageException as it is in a private / system API
|
||||
// class. This validates the exception's message to ensure we are only handling this
|
||||
// specific exception.
|
||||
// https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/webkit/WebViewFactory.java#348
|
||||
if (message != null
|
||||
&& exception
|
||||
.getClass()
|
||||
.getCanonicalName()
|
||||
.equals("android.webkit.WebViewFactory.MissingWebViewPackageException")) {
|
||||
return null;
|
||||
} else {
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cookieManager;
|
||||
}
|
||||
|
||||
public static void setCookie(String url,
|
||||
String name,
|
||||
String value,
|
||||
|
@ -103,6 +149,8 @@ public class MyCookieManager implements MethodChannel.MethodCallHandler {
|
|||
Boolean isHttpOnly,
|
||||
String sameSite,
|
||||
final MethodChannel.Result result) {
|
||||
cookieManager = getCookieManager();
|
||||
if (cookieManager == null) return;
|
||||
|
||||
String cookieValue = name + "=" + value + "; Domain=" + domain + "; Path=" + path;
|
||||
|
||||
|
@ -146,6 +194,9 @@ public class MyCookieManager implements MethodChannel.MethodCallHandler {
|
|||
|
||||
final List<Map<String, Object>> cookieListMap = new ArrayList<>();
|
||||
|
||||
cookieManager = getCookieManager();
|
||||
if (cookieManager == null) return cookieListMap;
|
||||
|
||||
String cookiesString = cookieManager.getCookie(url);
|
||||
|
||||
if (cookiesString != null) {
|
||||
|
@ -173,6 +224,8 @@ public class MyCookieManager implements MethodChannel.MethodCallHandler {
|
|||
}
|
||||
|
||||
public static void deleteCookie(String url, String name, String domain, String path, final MethodChannel.Result result) {
|
||||
cookieManager = getCookieManager();
|
||||
if (cookieManager == null) return;
|
||||
|
||||
String cookieValue = name + "=; Path=" + path + "; Domain=" + domain + "; Max-Age=-1;";
|
||||
|
||||
|
@ -196,6 +249,8 @@ public class MyCookieManager implements MethodChannel.MethodCallHandler {
|
|||
}
|
||||
|
||||
public static void deleteCookies(String url, String domain, String path, final MethodChannel.Result result) {
|
||||
cookieManager = getCookieManager();
|
||||
if (cookieManager == null) return;
|
||||
|
||||
CookieSyncManager cookieSyncMngr = null;
|
||||
|
||||
|
@ -228,6 +283,8 @@ public class MyCookieManager implements MethodChannel.MethodCallHandler {
|
|||
}
|
||||
|
||||
public static void deleteAllCookies(final MethodChannel.Result result) {
|
||||
cookieManager = getCookieManager();
|
||||
if (cookieManager == null) return;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
cookieManager.removeAllCookies(new ValueCallback<Boolean>() {
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.pichillilorenzo.flutter_inappwebview;
|
|||
|
||||
import android.content.res.AssetManager;
|
||||
import android.net.http.SslCertificate;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
|
@ -9,6 +10,12 @@ import android.os.Looper;
|
|||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -22,6 +29,7 @@ import java.security.cert.CertificateFactory;
|
|||
import java.security.cert.X509Certificate;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -234,4 +242,20 @@ public class Util {
|
|||
|
||||
return x509Certificate;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public static String JSONStringify(Object value) {
|
||||
if (value == null) {
|
||||
return "null";
|
||||
}
|
||||
if (value instanceof Map) {
|
||||
return new JSONObject((Map<String, Object>) value).toString();
|
||||
} else if (value instanceof List) {
|
||||
return new JSONArray((List<Object>) value).toString();
|
||||
} else if (value instanceof String) {
|
||||
return JSONObject.quote((String) value);
|
||||
} else {
|
||||
return JSONObject.wrap(value).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/.pub-cache/git/plugins-16f3281b04b0db12e609352b1c9544901392e428/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.27/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.1+1/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.4/","dependencies":[]}],"android":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/.pub-cache/git/plugins-16f3281b04b0db12e609352b1c9544901392e428/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.27/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.1+1/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.4/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.4+8/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.0.1+2/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.0.4+3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"device_info","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":["device_info"]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-02-06 02:03:14.260971","version":"1.26.0-18.0.pre.90"}
|
||||
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/.pub-cache/git/plugins-16f3281b04b0db12e609352b1c9544901392e428/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.27/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.1+1/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.4/","dependencies":[]}],"android":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/.pub-cache/git/plugins-16f3281b04b0db12e609352b1c9544901392e428/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.27/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.1+1/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.4/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.4+8/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.0.1+2/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.0.4+3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"device_info","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":["device_info"]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-02-07 16:00:15.712688","version":"1.26.0-18.0.pre.90"}
|
|
@ -18,10 +18,22 @@
|
|||
EDC1147F21735BC200D2247A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
6174FE1725CEB74E00A5020C /* Embed App Extensions */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
);
|
||||
name = "Embed App Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
26ADC1E5EAF404A509D528C5 /* Pods_Runner_copy.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner_copy.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
61FF72FF23634CA10069C557 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
|
||||
61FF730123634DD10069C557 /* flutter_downloader.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = flutter_downloader.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -59,7 +71,6 @@
|
|||
children = (
|
||||
61FF730123634DD10069C557 /* flutter_downloader.framework */,
|
||||
61FF72FF23634CA10069C557 /* libsqlite3.tbd */,
|
||||
26ADC1E5EAF404A509D528C5 /* Pods_Runner_copy.framework */,
|
||||
B0FC2CF7A6002799890B3102 /* Pods_Runner.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
|
@ -141,6 +152,7 @@
|
|||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
903A9F2558754FA70D0A7EA8 /* [CP] Embed Pods Frameworks */,
|
||||
6174FE1725CEB74E00A5020C /* Embed App Extensions */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -157,6 +169,7 @@
|
|||
97C146E61CF9000F007C117D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1240;
|
||||
LastUpgradeCheck = 1110;
|
||||
ORGANIZATIONNAME = "The Chromium Authors";
|
||||
TargetAttributes = {
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
</array>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string></string>
|
||||
<string>_dartobservatory._tcp</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
|
|
|
@ -827,6 +827,19 @@ let onWindowBlurEventJS = """
|
|||
})();
|
||||
"""
|
||||
|
||||
let callAsyncJavaScriptBelowIOS14WrapperJS = """
|
||||
(function(obj) {
|
||||
(async function($FUNCTION_ARGUMENT_NAMES) {
|
||||
$FUNCTION_BODY
|
||||
})($FUNCTION_ARGUMENT_VALUES).then(function(value) {
|
||||
window.webkit.messageHandlers['onCallAsyncJavaScriptResultBelowIOS14Received'].postMessage({'value': value, 'error': null, 'resultUuid': '$RESULT_UUID'});
|
||||
}).catch(function(error) {
|
||||
window.webkit.messageHandlers['onCallAsyncJavaScriptResultBelowIOS14Received'].postMessage({'value': null, 'error': error, 'resultUuid': '$RESULT_UUID'});
|
||||
});
|
||||
return null;
|
||||
})($FUNCTION_ARGUMENTS_OBJ);
|
||||
"""
|
||||
|
||||
var SharedLastTouchPointTimestamp: [InAppWebView: Int64] = [:]
|
||||
|
||||
public class WebViewTransport: NSObject {
|
||||
|
@ -879,6 +892,8 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
|||
|
||||
var userScriptsContentWorlds: [String] = ["page"]
|
||||
|
||||
var callAsyncJavaScriptBelowIOS14Results: [String:FlutterResult] = [:]
|
||||
|
||||
init(frame: CGRect, configuration: WKWebViewConfiguration, IABController: InAppBrowserWebViewController?, contextMenu: [String: Any]?, channel: FlutterMethodChannel?) {
|
||||
super.init(frame: frame, configuration: configuration)
|
||||
self.channel = channel
|
||||
|
@ -1333,6 +1348,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
|||
|
||||
let printJSScript = WKUserScript(source: printJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
||||
configuration.userContentController.addUserScript(printJSScript)
|
||||
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "onCallAsyncJavaScriptResultBelowIOS14Received")
|
||||
configuration.userContentController.add(self, name: "onCallAsyncJavaScriptResultBelowIOS14Received")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2113,10 +2131,79 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
|||
}
|
||||
}
|
||||
|
||||
public func evaluateJavascript(source: String, contentWorldName: String?, result: FlutterResult?) {
|
||||
public func evaluateJavascript(source: String, contentWorldName: String?, result: @escaping FlutterResult) {
|
||||
injectDeferredObject(source: source, contentWorldName: contentWorldName, withWrapper: nil, result: result)
|
||||
}
|
||||
|
||||
@available(iOS 10.3, *)
|
||||
public func callAsyncJavaScript(functionBody: String, arguments: [String:Any], contentWorldName: String?, result: @escaping FlutterResult) {
|
||||
var jsToInject = functionBody
|
||||
if #available(iOS 14.0, *) {
|
||||
var contentWorld = WKContentWorld.page
|
||||
if let contentWorldName = contentWorldName {
|
||||
contentWorld = getContentWorld(name: contentWorldName)
|
||||
if !userScriptsContentWorlds.contains(contentWorldName) {
|
||||
userScriptsContentWorlds.append(contentWorldName)
|
||||
addSharedPluginUserScriptsInContentWorld(contentWorldName: contentWorldName)
|
||||
// Add only the first time all the plugin user scripts needed.
|
||||
// In the next page load, it will use the WKUserScripts loaded
|
||||
jsToInject = getAllPluginUserScriptMergedJS() + "\n" + jsToInject
|
||||
}
|
||||
}
|
||||
callAsyncJavaScript(jsToInject, arguments: arguments, in: nil, in: contentWorld) { (evalResult) in
|
||||
var body: [String: Any?] = [
|
||||
"value": nil,
|
||||
"error": nil
|
||||
]
|
||||
|
||||
switch (evalResult) {
|
||||
case .success(let value):
|
||||
body["value"] = value
|
||||
break
|
||||
case .failure(let error):
|
||||
body["error"] = error
|
||||
break
|
||||
}
|
||||
|
||||
result(body)
|
||||
}
|
||||
} else {
|
||||
let resultUuid = NSUUID().uuidString
|
||||
callAsyncJavaScriptBelowIOS14Results[resultUuid] = result
|
||||
|
||||
var functionArgumentNamesList: [String] = []
|
||||
var functionArgumentValuesList: [String] = []
|
||||
let keys = arguments.keys
|
||||
keys.forEach { (key) in
|
||||
functionArgumentNamesList.append(key)
|
||||
functionArgumentValuesList.append("obj.\(key)")
|
||||
}
|
||||
|
||||
let functionArgumentNames = functionArgumentNamesList.joined(separator: ", ")
|
||||
let functionArgumentValues = functionArgumentValuesList.joined(separator: ", ")
|
||||
|
||||
jsToInject = callAsyncJavaScriptBelowIOS14WrapperJS
|
||||
.replacingOccurrences(of: "$FUNCTION_ARGUMENT_NAMES", with: functionArgumentNames)
|
||||
.replacingOccurrences(of: "$FUNCTION_ARGUMENT_VALUES", with: functionArgumentValues)
|
||||
.replacingOccurrences(of: "$FUNCTION_ARGUMENTS_OBJ", with: JSONStringify(value: arguments))
|
||||
.replacingOccurrences(of: "$FUNCTION_BODY", with: jsToInject)
|
||||
.replacingOccurrences(of: "$RESULT_UUID", with: resultUuid)
|
||||
|
||||
evaluateJavaScript(jsToInject) { (value, error) in
|
||||
if error != nil {
|
||||
let userInfo = (error! as NSError).userInfo
|
||||
self.onConsoleMessage(message:
|
||||
userInfo["WKJavaScriptExceptionMessage"] as? String ??
|
||||
userInfo["NSLocalizedDescription"] as? String ??
|
||||
"",
|
||||
messageLevel: 3)
|
||||
result(nil)
|
||||
self.callAsyncJavaScriptBelowIOS14Results.removeValue(forKey: resultUuid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func injectJavascriptFileFromUrl(urlFile: String) {
|
||||
let jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document);"
|
||||
injectDeferredObject(source: urlFile, contentWorldName: nil, withWrapper: jsWrapper, result: nil)
|
||||
|
@ -3270,6 +3357,16 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
webView = webViewTransport.webView
|
||||
}
|
||||
webView.onFindResultReceived(activeMatchOrdinal: activeMatchOrdinal, numberOfMatches: numberOfMatches, isDoneCounting: isDoneCounting)
|
||||
} else if message.name == "onCallAsyncJavaScriptResultBelowIOS14Received" {
|
||||
let body = message.body as! [String: Any?]
|
||||
let resultUuid = body["resultUuid"] as! String
|
||||
if let result = callAsyncJavaScriptBelowIOS14Results[resultUuid] {
|
||||
result([
|
||||
"value": body["value"],
|
||||
"error": body["error"]
|
||||
])
|
||||
callAsyncJavaScriptBelowIOS14Results.removeValue(forKey: resultUuid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3436,6 +3533,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
configuration.userContentController.removeScriptMessageHandler(forName: "consoleWarn")
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "callHandler")
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "onFindResultReceived")
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "onCallAsyncJavaScriptResultBelowIOS14Received")
|
||||
if #available(iOS 14.0, *) {
|
||||
configuration.userContentController.removeAllScriptMessageHandlers()
|
||||
for contentWorldName in userScriptsContentWorlds {
|
||||
|
@ -3469,6 +3567,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
|||
if let wId = windowId, InAppWebView.windowWebViews[wId] != nil {
|
||||
InAppWebView.windowWebViews.removeValue(forKey: wId)
|
||||
}
|
||||
callAsyncJavaScriptBelowIOS14Results.removeAll()
|
||||
super.removeFromSuperview()
|
||||
}
|
||||
|
||||
|
|
|
@ -384,6 +384,17 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
|
|||
webView?.removeAllUserScripts()
|
||||
result(true)
|
||||
break
|
||||
case "callAsyncJavaScript":
|
||||
if webView != nil, #available(iOS 10.3, *) {
|
||||
let functionBody = arguments!["functionBody"] as! String
|
||||
let functionArguments = arguments!["arguments"] as! [String:Any]
|
||||
let contentWorldName = arguments!["contentWorld"] as? String
|
||||
webView!.callAsyncJavaScript(functionBody: functionBody, arguments: functionArguments, contentWorldName: contentWorldName, result: result)
|
||||
}
|
||||
else {
|
||||
result(nil)
|
||||
}
|
||||
break
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
break
|
||||
|
|
|
@ -32,6 +32,7 @@ const javaScriptHandlerForbiddenNames = [
|
|||
"onPrint",
|
||||
"onWindowFocus",
|
||||
"onWindowBlur",
|
||||
"callAsyncJavaScript"
|
||||
];
|
||||
|
||||
///Controls a WebView, such as an [InAppWebView] widget instance, a [HeadlessInAppWebView] instance or [InAppBrowser] WebView instance.
|
||||
|
@ -2039,6 +2040,46 @@ class InAppWebViewController {
|
|||
await _channel.invokeMethod('removeAllUserScripts', args);
|
||||
}
|
||||
|
||||
///Executes the specified string as an asynchronous JavaScript function.
|
||||
///
|
||||
///[functionBody] is the JavaScript string to use as the function body.
|
||||
///This method treats the string as an anonymous JavaScript function body and calls it with the named arguments in the arguments parameter.
|
||||
///
|
||||
///[arguments] is a dictionary of the arguments to pass to the function call.
|
||||
///Each key in the dictionary corresponds to the name of an argument in the [functionBody] string,
|
||||
///and the value of that key is the value to use during the evaluation of the code.
|
||||
///Supported value types can be found in the official Flutter docs:
|
||||
///[Platform channel data types support and codecs](https://flutter.dev/docs/development/platform-integration/platform-channels#codec),
|
||||
///except for [Uint8List], [Int32List], [Int64List], and [Float64List] that should be converted into a [List].
|
||||
///All items in an array or dictionary must also be one of the supported types.
|
||||
///
|
||||
///[contentWorld], on iOS, it represents the namespace in which to evaluate the JavaScript [source] code.
|
||||
///Instead, on Android, it will run the [source] code into an iframe.
|
||||
///This parameter doesn’t apply to changes you make to the underlying web content, such as the document’s DOM structure.
|
||||
///Those changes remain visible to all scripts, regardless of which content world you specify.
|
||||
///For more information about content worlds, see [ContentWorld].
|
||||
///Available on iOS 14.0+.
|
||||
///
|
||||
///**NOTE for iOS**: available only on iOS 10.3+.
|
||||
///
|
||||
///**NOTE for Android**: available only on Android 21+.
|
||||
///
|
||||
///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/3656441-callasyncjavascript
|
||||
Future<CallAsyncJavaScriptResult?> callAsyncJavaScript({required String functionBody, Map<String, dynamic> arguments = const <String, dynamic>{}, ContentWorld? contentWorld}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('functionBody', () => functionBody);
|
||||
args.putIfAbsent('arguments', () => arguments);
|
||||
args.putIfAbsent('contentWorld', () => contentWorld?.name);
|
||||
var data = await _channel.invokeMethod('callAsyncJavaScript', args);
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||
data = json.decode(data);
|
||||
}
|
||||
return CallAsyncJavaScriptResult(value: data["value"], error: data["error"]);
|
||||
}
|
||||
|
||||
///Gets the default user agent.
|
||||
///
|
||||
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebSettings#getDefaultUserAgent(android.content.Context)
|
||||
|
|
|
@ -4623,4 +4623,41 @@ class ContentWorld {
|
|||
///Be careful when manipulating variables in this content world.
|
||||
///If you modify a variable with the same name as one the webpage uses, you may unintentionally disrupt the normal operation of that page.
|
||||
static ContentWorld page = ContentWorld.world(name: "page");
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {"name": name};
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return this.toMap();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
}
|
||||
|
||||
///Class that represents either a success or a failure, including an associated value in each case for [InAppWebViewController.callAsyncJavaScript].
|
||||
class CallAsyncJavaScriptResult {
|
||||
///It contains the success value.
|
||||
dynamic value;
|
||||
|
||||
///It contains the failure value.
|
||||
dynamic error;
|
||||
|
||||
CallAsyncJavaScriptResult({this.value, this.error});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {"value": value, "error": error};
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return this.toMap();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue