updated management of Content Worlds, updated evaluateJavascript API
This commit is contained in:
parent
54e027bee0
commit
55242a35f9
|
@ -166,7 +166,7 @@ public class ContentBlockerHandler {
|
|||
@Override
|
||||
public void run() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webView.evaluateJavascript(jsScript, (MethodChannel.Result) null);
|
||||
webView.evaluateJavascript(jsScript, null);
|
||||
} else {
|
||||
webView.loadUrl("javascript:" + jsScript);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import android.os.Message;
|
|||
import android.print.PrintAttributes;
|
||||
import android.print.PrintDocumentAdapter;
|
||||
import android.print.PrintManager;
|
||||
import android.util.ArraySet;
|
||||
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.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.webkit.WebViewCompat;
|
||||
import androidx.webkit.WebViewFeature;
|
||||
|
@ -56,14 +58,19 @@ import com.pichillilorenzo.flutter_inappwebview.R;
|
|||
import com.pichillilorenzo.flutter_inappwebview.Shared;
|
||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
|
@ -106,8 +113,12 @@ final public class InAppWebView extends InputAwareWebView {
|
|||
public Runnable checkContextMenuShouldBeClosedTask;
|
||||
public int newCheckContextMenuShouldBeClosedTaskTask = 100; // ms
|
||||
|
||||
public Set<String> userScriptsContentWorlds = new HashSet<String>() {{
|
||||
add("page");
|
||||
}};
|
||||
|
||||
static final String pluginScriptsWrapperJS = "(function(){" +
|
||||
" if (window." + JavaScriptBridgeInterface.name + "._pluginScriptsLoaded == null || !window." + JavaScriptBridgeInterface.name + "._pluginScriptsLoaded) {" +
|
||||
" if (window." + JavaScriptBridgeInterface.name + " == null || window." + JavaScriptBridgeInterface.name + "._pluginScriptsLoaded == null || !window." + JavaScriptBridgeInterface.name + "._pluginScriptsLoaded) {" +
|
||||
" $PLACEHOLDER_VALUE" +
|
||||
" window." + JavaScriptBridgeInterface.name + "._pluginScriptsLoaded = true;" +
|
||||
" }" +
|
||||
|
@ -187,8 +198,8 @@ final public class InAppWebView extends InputAwareWebView {
|
|||
" }" +
|
||||
"})();";
|
||||
|
||||
static final String variableForOnLoadResourceJS = "window._flutter_inappwebview_useOnLoadResource";
|
||||
static final String enableVariableForOnLoadResourceJS = variableForOnLoadResourceJS + " = $PLACEHOLDER_VALUE;";
|
||||
static final String variableForOnLoadResourceJS = "_flutter_inappwebview_useOnLoadResource";
|
||||
static final String enableVariableForOnLoadResourceJS = "window." + variableForOnLoadResourceJS + " = $PLACEHOLDER_VALUE;";
|
||||
|
||||
static final String resourceObserverJS = "(function() {" +
|
||||
" var observer = new PerformanceObserver(function(list) {" +
|
||||
|
@ -1169,7 +1180,9 @@ final public class InAppWebView extends InputAwareWebView {
|
|||
String placeholderValue = newOptions.useShouldInterceptAjaxRequest ? "true" : "false";
|
||||
String sourceJs = InAppWebView.enableVariableForShouldInterceptAjaxRequestJS.replace("$PLACEHOLDER_VALUE", placeholderValue);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
evaluateJavascript(sourceJs, (ValueCallback<String>) null);
|
||||
for (String contentWorldName : userScriptsContentWorlds) {
|
||||
evaluateJavascript(sourceJs, contentWorldName, null);
|
||||
}
|
||||
} else {
|
||||
loadUrl("javascript:" + sourceJs);
|
||||
}
|
||||
|
@ -1179,7 +1192,9 @@ final public class InAppWebView extends InputAwareWebView {
|
|||
String placeholderValue = newOptions.useShouldInterceptFetchRequest ? "true" : "false";
|
||||
String sourceJs = InAppWebView.enableVariableForShouldInterceptFetchRequestsJS.replace("$PLACEHOLDER_VALUE", placeholderValue);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
evaluateJavascript(sourceJs, (ValueCallback<String>) null);
|
||||
for (String contentWorldName : userScriptsContentWorlds) {
|
||||
evaluateJavascript(sourceJs, contentWorldName, null);
|
||||
}
|
||||
} else {
|
||||
loadUrl("javascript:" + sourceJs);
|
||||
}
|
||||
|
@ -1457,7 +1472,7 @@ final public class InAppWebView extends InputAwareWebView {
|
|||
return (options != null) ? options.getRealOptions(this) : null;
|
||||
}
|
||||
|
||||
public void injectDeferredObject(String source, String jsWrapper, final MethodChannel.Result result) {
|
||||
public void injectDeferredObject(String source, @Nullable final String contentWorldName, String jsWrapper, final MethodChannel.Result result) {
|
||||
String scriptToInject = source;
|
||||
if (jsWrapper != null) {
|
||||
org.json.JSONArray jsonEsc = new org.json.JSONArray();
|
||||
|
@ -1472,39 +1487,58 @@ final public class InAppWebView extends InputAwareWebView {
|
|||
public void run() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
// This action will have the side-effect of blurring the currently focused element
|
||||
loadUrl("javascript:" + finalScriptToInject);
|
||||
loadUrl("javascript:" + finalScriptToInject.replaceAll("[\r\n]+", ""));
|
||||
result.success("");
|
||||
} else {
|
||||
evaluateJavascript(finalScriptToInject, new ValueCallback<String>() {
|
||||
@Override
|
||||
public void onReceiveValue(String s) {
|
||||
if (result == null)
|
||||
return;
|
||||
result.success(s);
|
||||
if (contentWorldName != null && !contentWorldName.equals("page")) {
|
||||
String sourceToInject = finalScriptToInject;
|
||||
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, new ValueCallback<String>() {
|
||||
@Override
|
||||
public void onReceiveValue(String s) {
|
||||
if (result == null)
|
||||
return;
|
||||
result.success(s);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
evaluateJavascript(finalScriptToInject, new ValueCallback<String>() {
|
||||
@Override
|
||||
public void onReceiveValue(String s) {
|
||||
if (result == null)
|
||||
return;
|
||||
result.success(s);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void evaluateJavascript(String source, MethodChannel.Result result) {
|
||||
injectDeferredObject(source, null, result);
|
||||
public void evaluateJavascript(String source, String contentWorldName, MethodChannel.Result result) {
|
||||
injectDeferredObject(source, contentWorldName, null, result);
|
||||
}
|
||||
|
||||
public void injectJavascriptFileFromUrl(String urlFile) {
|
||||
String jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document);";
|
||||
injectDeferredObject(urlFile, jsWrapper, null);
|
||||
injectDeferredObject(urlFile, null, jsWrapper, null);
|
||||
}
|
||||
|
||||
public void injectCSSCode(String source) {
|
||||
String jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document);";
|
||||
injectDeferredObject(source, jsWrapper, null);
|
||||
injectDeferredObject(source, null, jsWrapper, null);
|
||||
}
|
||||
|
||||
public void injectCSSFileFromUrl(String urlFile) {
|
||||
String jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document);";
|
||||
injectDeferredObject(urlFile, jsWrapper, null);
|
||||
injectDeferredObject(urlFile, null, jsWrapper, null);
|
||||
}
|
||||
|
||||
public HashMap<String, Object> getCopyBackForwardList() {
|
||||
|
@ -1999,6 +2033,10 @@ final public class InAppWebView extends InputAwareWebView {
|
|||
}
|
||||
|
||||
public boolean addUserScript(Map<String, Object> userScript) {
|
||||
String contentWorldName = (String) userScript.get("contentWorld");
|
||||
if (contentWorldName != null && !userScriptsContentWorlds.contains(contentWorldName)) {
|
||||
userScriptsContentWorlds.add(contentWorldName);
|
||||
}
|
||||
return userScripts.add(userScript);
|
||||
}
|
||||
|
||||
|
@ -2009,6 +2047,52 @@ final public class InAppWebView extends InputAwareWebView {
|
|||
public void removeAllUserScripts() {
|
||||
userScripts.clear();
|
||||
}
|
||||
|
||||
public void resetUserScriptsContentWorlds() {
|
||||
userScriptsContentWorlds.clear();
|
||||
userScriptsContentWorlds.add("page");
|
||||
}
|
||||
|
||||
public String prepareAndWrapPluginUserScripts() {
|
||||
String js = JavaScriptBridgeInterface.callHandlerScriptJS;
|
||||
js += InAppWebView.consoleLogJS;
|
||||
if (options.useShouldInterceptAjaxRequest) {
|
||||
js += InAppWebView.interceptAjaxRequestsJS;
|
||||
}
|
||||
if (options.useShouldInterceptFetchRequest) {
|
||||
js += InAppWebView.interceptFetchRequestsJS;
|
||||
}
|
||||
if (options.useOnLoadResource) {
|
||||
js += InAppWebView.resourceObserverJS;
|
||||
}
|
||||
if (!options.useHybridComposition) {
|
||||
js += InAppWebView.checkGlobalKeyDownEventToHideContextMenuJS;
|
||||
}
|
||||
js += InAppWebView.onWindowFocusEventJS;
|
||||
js += InAppWebView.onWindowBlurEventJS;
|
||||
js += InAppWebView.printJS;
|
||||
|
||||
String jsWrapped = InAppWebView.pluginScriptsWrapperJS
|
||||
.replace("$PLACEHOLDER_VALUE", js);
|
||||
|
||||
return jsWrapped;
|
||||
}
|
||||
|
||||
public String wrapSourceCodeInContentWorld(@Nullable String contentWorldName, String source) {
|
||||
JSONObject sourceEncoded = new JSONObject();
|
||||
try {
|
||||
// encode the javascript source in order to escape special chars and quotes
|
||||
sourceEncoded.put("source", source);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
String sourceWrapped = contentWorldName == null || contentWorldName.equals("page") ? source :
|
||||
InAppWebView.contentWorldWrapperJS.replace("$CONTENT_WORLD_NAME", contentWorldName)
|
||||
.replace("$JSON_SOURCE_ENCODED", sourceEncoded.toString());
|
||||
|
||||
return sourceWrapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
|
|
|
@ -26,12 +26,8 @@ import androidx.annotation.RequiresApi;
|
|||
import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.Credential;
|
||||
import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.CredentialDatabase;
|
||||
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
|
||||
import com.pichillilorenzo.flutter_inappwebview.JavaScriptBridgeInterface;
|
||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
|
@ -166,10 +162,10 @@ public class InAppWebViewClient extends WebViewClient {
|
|||
private void loadCustomJavaScriptOnPageStarted(WebView view) {
|
||||
InAppWebView webView = (InAppWebView) view;
|
||||
|
||||
String jsPluginScripts = preparePluginUserScripts(webView);
|
||||
String jsPluginScriptsWrapped = webView.prepareAndWrapPluginUserScripts();
|
||||
String jsUserScriptsAtDocumentStart = prepareUserScriptsAtDocumentStart(webView);
|
||||
|
||||
String js = wrapPluginAndUserScripts(jsPluginScripts, jsUserScriptsAtDocumentStart, null);
|
||||
String js = wrapPluginAndUserScripts(jsPluginScriptsWrapped, jsUserScriptsAtDocumentStart, null);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webView.evaluateJavascript(js, (ValueCallback<String>) null);
|
||||
|
@ -182,11 +178,11 @@ public class InAppWebViewClient extends WebViewClient {
|
|||
InAppWebView webView = (InAppWebView) view;
|
||||
|
||||
// try to reload also custom scripts if they were not loaded during the onPageStarted event
|
||||
String jsPluginScripts = preparePluginUserScripts(webView);
|
||||
String jsPluginScriptsWrapped = webView.prepareAndWrapPluginUserScripts();
|
||||
String jsUserScriptsAtDocumentStart = prepareUserScriptsAtDocumentStart(webView);
|
||||
String jsUserScriptsAtDocumentEnd = prepareUserScriptsAtDocumentEnd(webView);
|
||||
|
||||
String js = wrapPluginAndUserScripts(jsPluginScripts, jsUserScriptsAtDocumentStart, jsUserScriptsAtDocumentEnd);
|
||||
String js = wrapPluginAndUserScripts(jsPluginScriptsWrapped, jsUserScriptsAtDocumentStart, jsUserScriptsAtDocumentEnd);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webView.evaluateJavascript(js, (ValueCallback<String>) null);
|
||||
|
@ -194,57 +190,25 @@ public class InAppWebViewClient extends WebViewClient {
|
|||
webView.loadUrl("javascript:" + js.replaceAll("[\r\n]+", ""));
|
||||
}
|
||||
}
|
||||
|
||||
private String preparePluginUserScripts(InAppWebView webView) {
|
||||
String js = InAppWebView.consoleLogJS;
|
||||
js += JavaScriptBridgeInterface.callHandlerScriptJS;
|
||||
if (webView.options.useShouldInterceptAjaxRequest) {
|
||||
js += InAppWebView.interceptAjaxRequestsJS;
|
||||
}
|
||||
if (webView.options.useShouldInterceptFetchRequest) {
|
||||
js += InAppWebView.interceptFetchRequestsJS;
|
||||
}
|
||||
if (webView.options.useOnLoadResource) {
|
||||
js += InAppWebView.resourceObserverJS;
|
||||
}
|
||||
if (!webView.options.useHybridComposition) {
|
||||
js += InAppWebView.checkGlobalKeyDownEventToHideContextMenuJS;
|
||||
}
|
||||
js += InAppWebView.onWindowFocusEventJS;
|
||||
js += InAppWebView.onWindowBlurEventJS;
|
||||
js += InAppWebView.printJS;
|
||||
|
||||
return js;
|
||||
}
|
||||
|
||||
private String prepareUserScriptsAtDocumentStart(InAppWebView webView) {
|
||||
|
||||
private String prepareUserScripts(InAppWebView webView, int atDocumentInjectionTime) {
|
||||
StringBuilder js = new StringBuilder();
|
||||
|
||||
for (Map<String, Object> userScript : webView.userScripts) {
|
||||
Integer injectionTime = (Integer) userScript.get("injectionTime");
|
||||
if (injectionTime == null || injectionTime == 0) {
|
||||
if ((injectionTime == null && atDocumentInjectionTime == 0) || (injectionTime != null && injectionTime == atDocumentInjectionTime)) {
|
||||
String source = (String) userScript.get("source");
|
||||
String contentWorldName = (String) userScript.get("contentWorld");
|
||||
if (source != null) {
|
||||
if (contentWorldName != null && !contentWorldName.equals("page")) {
|
||||
String jsPluginScripts = preparePluginUserScripts(webView);
|
||||
String jsPluginScripts = webView.prepareAndWrapPluginUserScripts();
|
||||
source = jsPluginScripts + "\n" + source;
|
||||
}
|
||||
|
||||
JSONObject sourceEncoded = new JSONObject();
|
||||
try {
|
||||
// encode the javascript source in order to escape special chars and quotes
|
||||
sourceEncoded.put("source", source);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
if (contentWorldName != null && !webView.userScriptsContentWorlds.contains(contentWorldName)) {
|
||||
webView.userScriptsContentWorlds.add(contentWorldName);
|
||||
}
|
||||
|
||||
String sourceWrapped = contentWorldName == null || contentWorldName.equals("page") ? source :
|
||||
InAppWebView.contentWorldWrapperJS.replace("$CONTENT_WORLD_NAME", contentWorldName)
|
||||
.replace("$CONTENT_WORLD_NAME", contentWorldName)
|
||||
.replace("$JSON_SOURCE_ENCODED", sourceEncoded.toString());
|
||||
|
||||
if (contentWorldName != null && !contentWorldName.equals("page")) {
|
||||
String sourceWrapped = webView.wrapSourceCodeInContentWorld(contentWorldName, source);
|
||||
if (atDocumentInjectionTime == 0 && contentWorldName != null && !contentWorldName.equals("page")) {
|
||||
// adds another wrapper because sometimes document.body is not ready and it is undefined, causing an error and not adding the iframe element.
|
||||
sourceWrapped = InAppWebView.documentReadyWrapperJS.replace("$PLACEHOLDER_VALUE", sourceWrapped)
|
||||
.replace("$PLACEHOLDER_VALUE", sourceWrapped);
|
||||
|
@ -258,43 +222,15 @@ public class InAppWebViewClient extends WebViewClient {
|
|||
return js.toString();
|
||||
}
|
||||
|
||||
private String prepareUserScriptsAtDocumentStart(InAppWebView webView) {
|
||||
return prepareUserScripts(webView, 0);
|
||||
}
|
||||
|
||||
private String prepareUserScriptsAtDocumentEnd(InAppWebView webView) {
|
||||
StringBuilder js = new StringBuilder();
|
||||
|
||||
for (Map<String, Object> userScript : webView.userScripts) {
|
||||
Integer injectionTime = (Integer) userScript.get("injectionTime");
|
||||
if (injectionTime != null && injectionTime == 1) {
|
||||
String source = (String) userScript.get("source");
|
||||
String contentWorldName = (String) userScript.get("contentWorld");
|
||||
if (source != null) {
|
||||
if (contentWorldName != null && !contentWorldName.equals("page")) {
|
||||
String jsPluginScripts = preparePluginUserScripts(webView);
|
||||
source = jsPluginScripts + "\n" + source;
|
||||
}
|
||||
|
||||
JSONObject sourceEncoded = new JSONObject();
|
||||
try {
|
||||
// encode the javascript source in order to escape special chars and quotes
|
||||
sourceEncoded.put("source", source);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
String sourceWrapped = contentWorldName == null || contentWorldName.equals("page") ? source :
|
||||
InAppWebView.contentWorldWrapperJS.replace("$CONTENT_WORLD_NAME", contentWorldName)
|
||||
.replace("$CONTENT_WORLD_NAME", contentWorldName)
|
||||
.replace("$JSON_SOURCE_ENCODED", sourceEncoded.toString());
|
||||
js.append(sourceWrapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return js.toString();
|
||||
return prepareUserScripts(webView, 1);
|
||||
}
|
||||
|
||||
private String wrapPluginAndUserScripts(String jsPluginScripts, @Nullable String jsUserScriptsAtDocumentStart, @Nullable String jsUserScriptsAtDocumentEnd) {
|
||||
String jsPluginScriptsWrapped = InAppWebView.pluginScriptsWrapperJS
|
||||
.replace("$PLACEHOLDER_VALUE", jsPluginScripts);
|
||||
private String wrapPluginAndUserScripts(String jsPluginScriptsWrapped, @Nullable String jsUserScriptsAtDocumentStart, @Nullable String jsUserScriptsAtDocumentEnd) {
|
||||
String jsUserScriptsAtDocumentStartWrapped = jsUserScriptsAtDocumentStart == null || jsUserScriptsAtDocumentStart.isEmpty() ? "" :
|
||||
InAppWebView.userScriptsAtDocumentStartWrapperJS.replace("$PLACEHOLDER_VALUE", jsUserScriptsAtDocumentStart);
|
||||
String jsUserScriptsAtDocumentEndWrapped = jsUserScriptsAtDocumentEnd == null || jsUserScriptsAtDocumentEnd.isEmpty() ? "" :
|
||||
|
@ -305,6 +241,7 @@ public class InAppWebViewClient extends WebViewClient {
|
|||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
final InAppWebView webView = (InAppWebView) view;
|
||||
webView.resetUserScriptsContentWorlds();
|
||||
|
||||
loadCustomJavaScriptOnPageStarted(webView);
|
||||
|
||||
|
|
|
@ -74,7 +74,8 @@ public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandle
|
|||
case "evaluateJavascript":
|
||||
if (webView != null) {
|
||||
String source = (String) call.argument("source");
|
||||
webView.evaluateJavascript(source, result);
|
||||
String contentWorldName = (String) call.argument("contentWorld");
|
||||
webView.evaluateJavascript(source, contentWorldName, result);
|
||||
}
|
||||
else {
|
||||
result.success(null);
|
||||
|
|
|
@ -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-04 22:05:52.361400","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-06 02:03:14.260971","version":"1.26.0-18.0.pre.90"}
|
|
@ -58,7 +58,7 @@ window.\(JAVASCRIPT_BRIDGE_NAME).callHandler = function() {
|
|||
return new Promise(function(resolve, reject) {
|
||||
window.\(JAVASCRIPT_BRIDGE_NAME)[_callHandlerID] = resolve;
|
||||
});
|
||||
}
|
||||
};
|
||||
"""
|
||||
|
||||
// the message needs to be concatenated with '' in order to have the same behavior like on Android
|
||||
|
@ -269,8 +269,8 @@ function wkwebview_FindNext(forward) {
|
|||
}
|
||||
"""
|
||||
|
||||
let variableForOnLoadResourceJS = "window._flutter_inappwebview_useOnLoadResource"
|
||||
let enableVariableForOnLoadResourceJS = "\(variableForOnLoadResourceJS) = $PLACEHOLDER_VALUE;"
|
||||
let variableForOnLoadResourceJS = "_flutter_inappwebview_useOnLoadResource"
|
||||
let enableVariableForOnLoadResourceJS = "window.\(variableForOnLoadResourceJS) = $PLACEHOLDER_VALUE;"
|
||||
|
||||
let resourceObserverJS = """
|
||||
(function() {
|
||||
|
@ -877,7 +877,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
|||
static var windowWebViews: [Int64:WebViewTransport] = [:]
|
||||
static var windowAutoincrementId: Int64 = 0;
|
||||
|
||||
var userScriptsContentWorlds: [String] = ["defaultClient", "page"]
|
||||
var userScriptsContentWorlds: [String] = ["page"]
|
||||
|
||||
init(frame: CGRect, configuration: WKWebViewConfiguration, IABController: InAppBrowserWebViewController?, contextMenu: [String: Any]?, channel: FlutterMethodChannel?) {
|
||||
super.init(frame: frame, configuration: configuration)
|
||||
|
@ -1219,60 +1219,88 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
|||
configuration.userContentController.addUserScript(userScriptWindowId)
|
||||
}
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
func addSharedPluginUserScriptsBetweenContentWorlds(contentWorlds: [WKContentWorld]) -> Void {
|
||||
for contentWorld in contentWorlds {
|
||||
let promisePolyfillJSScript = WKUserScript(source: promisePolyfillJS, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: contentWorld)
|
||||
configuration.userContentController.addUserScript(promisePolyfillJSScript)
|
||||
func getAllPluginUserScriptMergedJS() -> String {
|
||||
var allPluginUserScriptMergedJS = promisePolyfillJS + "\n" +
|
||||
javaScriptBridgeJS + "\n" +
|
||||
consoleLogJS + "\n" +
|
||||
printJS + "\n"
|
||||
if let options = options {
|
||||
if options.useShouldInterceptAjaxRequest {
|
||||
allPluginUserScriptMergedJS += interceptAjaxRequestsJS + "\n"
|
||||
}
|
||||
|
||||
let javaScriptBridgeJSScript = WKUserScript(source: javaScriptBridgeJS, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: contentWorld)
|
||||
configuration.userContentController.addUserScript(javaScriptBridgeJSScript)
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "callHandler", contentWorld: contentWorld)
|
||||
configuration.userContentController.add(self, contentWorld: contentWorld, name: "callHandler")
|
||||
|
||||
let consoleLogJSScript = WKUserScript(source: consoleLogJS, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: contentWorld)
|
||||
configuration.userContentController.addUserScript(consoleLogJSScript)
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "consoleLog", contentWorld: contentWorld)
|
||||
configuration.userContentController.add(self, contentWorld: contentWorld, name: "consoleLog")
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "consoleDebug", contentWorld: contentWorld)
|
||||
configuration.userContentController.add(self, contentWorld: contentWorld, name: "consoleDebug")
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "consoleError", contentWorld: contentWorld)
|
||||
configuration.userContentController.add(self, contentWorld: contentWorld, name: "consoleError")
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "consoleInfo", contentWorld: contentWorld)
|
||||
configuration.userContentController.add(self, contentWorld: contentWorld, name: "consoleInfo")
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "consoleWarn", contentWorld: contentWorld)
|
||||
configuration.userContentController.add(self, contentWorld: contentWorld, name: "consoleWarn")
|
||||
|
||||
if let options = options {
|
||||
if options.useShouldInterceptAjaxRequest {
|
||||
let interceptAjaxRequestsJSScript = WKUserScript(source: interceptAjaxRequestsJS, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: contentWorld)
|
||||
configuration.userContentController.addUserScript(interceptAjaxRequestsJSScript)
|
||||
}
|
||||
|
||||
if options.useShouldInterceptFetchRequest {
|
||||
let interceptFetchRequestsJSScript = WKUserScript(source: interceptFetchRequestsJS, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: contentWorld)
|
||||
configuration.userContentController.addUserScript(interceptFetchRequestsJSScript)
|
||||
}
|
||||
if options.useShouldInterceptFetchRequest {
|
||||
allPluginUserScriptMergedJS += interceptFetchRequestsJS + "\n"
|
||||
}
|
||||
}
|
||||
return allPluginUserScriptMergedJS
|
||||
}
|
||||
|
||||
func addPluginUserScripts() -> Void {
|
||||
if #available(iOS 14.0, *) {
|
||||
let contentWorlds = userScriptsContentWorlds.map { (contentWorldName) -> WKContentWorld in
|
||||
return getContentWorld(name: contentWorldName)
|
||||
@available(iOS 14.0, *)
|
||||
func addSharedPluginUserScriptsInContentWorld(contentWorldName: String) -> Void {
|
||||
let contentWorld = getContentWorld(name: contentWorldName)
|
||||
|
||||
let promisePolyfillJSScript = WKUserScript(source: promisePolyfillJS, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: contentWorld)
|
||||
configuration.userContentController.addUserScript(promisePolyfillJSScript)
|
||||
|
||||
let javaScriptBridgeJSScript = WKUserScript(source: javaScriptBridgeJS, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: contentWorld)
|
||||
configuration.userContentController.addUserScript(javaScriptBridgeJSScript)
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "callHandler", contentWorld: contentWorld)
|
||||
configuration.userContentController.add(self, contentWorld: contentWorld, name: "callHandler")
|
||||
|
||||
let consoleLogJSScript = WKUserScript(source: consoleLogJS, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: contentWorld)
|
||||
configuration.userContentController.addUserScript(consoleLogJSScript)
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "consoleLog", contentWorld: contentWorld)
|
||||
configuration.userContentController.add(self, contentWorld: contentWorld, name: "consoleLog")
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "consoleDebug", contentWorld: contentWorld)
|
||||
configuration.userContentController.add(self, contentWorld: contentWorld, name: "consoleDebug")
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "consoleError", contentWorld: contentWorld)
|
||||
configuration.userContentController.add(self, contentWorld: contentWorld, name: "consoleError")
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "consoleInfo", contentWorld: contentWorld)
|
||||
configuration.userContentController.add(self, contentWorld: contentWorld, name: "consoleInfo")
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "consoleWarn", contentWorld: contentWorld)
|
||||
configuration.userContentController.add(self, contentWorld: contentWorld, name: "consoleWarn")
|
||||
|
||||
if let options = options {
|
||||
if options.useShouldInterceptAjaxRequest {
|
||||
let interceptAjaxRequestsJSScript = WKUserScript(source: interceptAjaxRequestsJS, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: contentWorld)
|
||||
configuration.userContentController.addUserScript(interceptAjaxRequestsJSScript)
|
||||
}
|
||||
|
||||
if options.useShouldInterceptFetchRequest {
|
||||
let interceptFetchRequestsJSScript = WKUserScript(source: interceptFetchRequestsJS, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: contentWorld)
|
||||
configuration.userContentController.addUserScript(interceptFetchRequestsJSScript)
|
||||
}
|
||||
}
|
||||
|
||||
let printJSScript = WKUserScript(source: printJS, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: contentWorld)
|
||||
configuration.userContentController.addUserScript(printJSScript)
|
||||
}
|
||||
|
||||
func addSharedPluginUserScriptsInContentWorlds() -> Void {
|
||||
if #available(iOS 14.0, *) {
|
||||
for contentWorldName in userScriptsContentWorlds {
|
||||
addSharedPluginUserScriptsInContentWorld(contentWorldName: contentWorldName)
|
||||
}
|
||||
addSharedPluginUserScriptsBetweenContentWorlds(contentWorlds: contentWorlds)
|
||||
} else {
|
||||
let promisePolyfillJSScript = WKUserScript(source: promisePolyfillJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
||||
let promisePolyfillJSScript = WKUserScript(
|
||||
source: promisePolyfillJS,
|
||||
injectionTime: .atDocumentStart,
|
||||
forMainFrameOnly: false)
|
||||
configuration.userContentController.addUserScript(promisePolyfillJSScript)
|
||||
|
||||
let javaScriptBridgeJSScript = WKUserScript(source: javaScriptBridgeJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
||||
let javaScriptBridgeJSScript = WKUserScript(
|
||||
source: javaScriptBridgeJS,
|
||||
injectionTime: .atDocumentStart,
|
||||
forMainFrameOnly: false)
|
||||
configuration.userContentController.addUserScript(javaScriptBridgeJSScript)
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "callHandler")
|
||||
configuration.userContentController.add(self, name: "callHandler")
|
||||
|
||||
let consoleLogJSScript = WKUserScript(source: consoleLogJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
||||
let consoleLogJSScript = WKUserScript(
|
||||
source: consoleLogJS,
|
||||
injectionTime: .atDocumentStart,
|
||||
forMainFrameOnly: false)
|
||||
configuration.userContentController.addUserScript(consoleLogJSScript)
|
||||
configuration.userContentController.removeScriptMessageHandler(forName: "consoleLog")
|
||||
configuration.userContentController.add(self, name: "consoleLog")
|
||||
|
@ -1287,23 +1315,33 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
|||
|
||||
if let options = options {
|
||||
if options.useShouldInterceptAjaxRequest {
|
||||
let interceptAjaxRequestsJSScript = WKUserScript(source: interceptAjaxRequestsJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
||||
let interceptAjaxRequestsJSScript = WKUserScript(
|
||||
source: interceptAjaxRequestsJS,
|
||||
injectionTime: .atDocumentStart,
|
||||
forMainFrameOnly: false)
|
||||
configuration.userContentController.addUserScript(interceptAjaxRequestsJSScript)
|
||||
}
|
||||
|
||||
if options.useShouldInterceptFetchRequest {
|
||||
let interceptFetchRequestsJSScript = WKUserScript(source: interceptFetchRequestsJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
||||
let interceptFetchRequestsJSScript = WKUserScript(
|
||||
source: interceptFetchRequestsJS,
|
||||
injectionTime: .atDocumentStart,
|
||||
forMainFrameOnly: false)
|
||||
configuration.userContentController.addUserScript(interceptFetchRequestsJSScript)
|
||||
}
|
||||
}
|
||||
|
||||
let printJSScript = WKUserScript(source: printJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
||||
configuration.userContentController.addUserScript(printJSScript)
|
||||
}
|
||||
}
|
||||
|
||||
func addPluginUserScripts() -> Void {
|
||||
addSharedPluginUserScriptsInContentWorlds()
|
||||
|
||||
let findElementsAtPointJSScript = WKUserScript(source: findElementsAtPointJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
||||
configuration.userContentController.addUserScript(findElementsAtPointJSScript)
|
||||
|
||||
let printJSScript = WKUserScript(source: printJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
||||
configuration.userContentController.addUserScript(printJSScript)
|
||||
|
||||
let lastTouchedAnchorOrImageJSScript = WKUserScript(source: lastTouchedAnchorOrImageJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
||||
configuration.userContentController.addUserScript(lastTouchedAnchorOrImageJSScript)
|
||||
|
||||
|
@ -1352,18 +1390,19 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
|||
|
||||
public func appendUserScript(userScript: [String: Any]) -> Void {
|
||||
var wkUserScript: WKUserScript?
|
||||
if #available(iOS 14.0, *), let contentWorldName = userScript["contentWorld"] as? String {
|
||||
if !userScriptsContentWorlds.contains(contentWorldName) {
|
||||
userScriptsContentWorlds.append(contentWorldName)
|
||||
}
|
||||
let contentWorldName = userScript["contentWorld"] as? String
|
||||
if contentWorldName != nil, !userScriptsContentWorlds.contains(contentWorldName!) {
|
||||
userScriptsContentWorlds.append(contentWorldName!)
|
||||
}
|
||||
if #available(iOS 14.0, *), let contentWorldName = contentWorldName {
|
||||
wkUserScript = WKUserScript(source: userScript["source"] as! String,
|
||||
injectionTime: WKUserScriptInjectionTime.init(rawValue: userScript["injectionTime"] as! Int) ?? .atDocumentStart,
|
||||
forMainFrameOnly: userScript["iosForMainFrameOnly"] as! Bool,
|
||||
in: getContentWorld(name: contentWorldName))
|
||||
} else {
|
||||
wkUserScript = WKUserScript(source: userScript["source"] as! String,
|
||||
injectionTime: WKUserScriptInjectionTime.init(rawValue: userScript["injectionTime"] as! Int) ?? .atDocumentStart,
|
||||
forMainFrameOnly: userScript["iosForMainFrameOnly"] as! Bool)
|
||||
injectionTime: WKUserScriptInjectionTime.init(rawValue: userScript["injectionTime"] as! Int) ?? .atDocumentStart,
|
||||
forMainFrameOnly: userScript["iosForMainFrameOnly"] as! Bool)
|
||||
}
|
||||
userScripts.append(wkUserScript!)
|
||||
}
|
||||
|
@ -1784,17 +1823,35 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
|||
|
||||
if newOptionsMap["useOnLoadResource"] != nil && options?.useOnLoadResource != newOptions.useOnLoadResource && newOptions.useOnLoadResource {
|
||||
let placeholderValue = newOptions.useOnLoadResource ? "true" : "false"
|
||||
evaluateJavaScript(enableVariableForOnLoadResourceJS.replacingOccurrences(of: "$PLACEHOLDER_VALUE", with: placeholderValue), completionHandler: nil)
|
||||
let source = enableVariableForOnLoadResourceJS.replacingOccurrences(of: "$PLACEHOLDER_VALUE", with: placeholderValue)
|
||||
evaluateJavaScript(source, completionHandler: nil)
|
||||
}
|
||||
|
||||
if newOptionsMap["useShouldInterceptAjaxRequest"] != nil && options?.useShouldInterceptAjaxRequest != newOptions.useShouldInterceptAjaxRequest && newOptions.useShouldInterceptAjaxRequest {
|
||||
let placeholderValue = newOptions.useShouldInterceptAjaxRequest ? "true" : "false"
|
||||
evaluateJavaScript(enableVariableForShouldInterceptAjaxRequestJS.replacingOccurrences(of: "$PLACEHOLDER_VALUE", with: placeholderValue), completionHandler: nil)
|
||||
let source = enableVariableForShouldInterceptAjaxRequestJS.replacingOccurrences(of: "$PLACEHOLDER_VALUE", with: placeholderValue)
|
||||
if #available(iOS 14.0, *) {
|
||||
for contentWorldName in userScriptsContentWorlds {
|
||||
let contentWorld = getContentWorld(name: contentWorldName)
|
||||
evaluateJavaScript(source, in: nil, in: contentWorld, completionHandler: nil)
|
||||
}
|
||||
} else {
|
||||
evaluateJavaScript(source, completionHandler: nil)
|
||||
}
|
||||
}
|
||||
|
||||
if newOptionsMap["useShouldInterceptFetchRequest"] != nil && options?.useShouldInterceptFetchRequest != newOptions.useShouldInterceptFetchRequest && newOptions.useShouldInterceptFetchRequest {
|
||||
let placeholderValue = newOptions.useShouldInterceptFetchRequest ? "true" : "false"
|
||||
evaluateJavaScript(enableVariableForShouldInterceptFetchRequestsJS.replacingOccurrences(of: "$PLACEHOLDER_VALUE", with: placeholderValue), completionHandler: nil)
|
||||
|
||||
let source = enableVariableForShouldInterceptAjaxRequestJS.replacingOccurrences(of: "$PLACEHOLDER_VALUE", with: placeholderValue)
|
||||
if #available(iOS 14.0, *) {
|
||||
for contentWorldName in userScriptsContentWorlds {
|
||||
let contentWorld = getContentWorld(name: contentWorldName)
|
||||
evaluateJavaScript(source, in: nil, in: contentWorld, completionHandler: nil)
|
||||
}
|
||||
} else {
|
||||
evaluateJavaScript(source, completionHandler: nil)
|
||||
}
|
||||
}
|
||||
|
||||
if newOptionsMap["mediaPlaybackRequiresUserGesture"] != nil && options?.mediaPlaybackRequiresUserGesture != newOptions.mediaPlaybackRequiresUserGesture {
|
||||
|
@ -2000,7 +2057,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
|||
}
|
||||
}
|
||||
|
||||
public func injectDeferredObject(source: String, withWrapper jsWrapper: String?, result: FlutterResult?) {
|
||||
public func injectDeferredObject(source: String, contentWorldName: String?, withWrapper jsWrapper: String?, result: FlutterResult?) {
|
||||
var jsToInject = source
|
||||
if let wrapper = jsWrapper {
|
||||
let jsonData: Data? = try? JSONSerialization.data(withJSONObject: [source], options: [])
|
||||
|
@ -2008,42 +2065,71 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
|||
let sourceString: String? = (sourceArrayString! as NSString).substring(with: NSRange(location: 1, length: (sourceArrayString?.count ?? 0) - 2))
|
||||
jsToInject = String(format: wrapper, sourceString!)
|
||||
}
|
||||
evaluateJavaScript(jsToInject, completionHandler: {(value, error) in
|
||||
if result == nil {
|
||||
return
|
||||
|
||||
if #available(iOS 14.0, *), let contentWorldName = 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
|
||||
}
|
||||
|
||||
if error != nil {
|
||||
let userInfo = (error! as NSError).userInfo
|
||||
self.onConsoleMessage(message: userInfo["WKJavaScriptExceptionMessage"] as? String ?? "", messageLevel: 3)
|
||||
let contentWorld = getContentWorld(name: contentWorldName)
|
||||
evaluateJavaScript(jsToInject, in: nil, in: contentWorld) { (evalResult) in
|
||||
guard let result = result else {
|
||||
return
|
||||
}
|
||||
|
||||
switch (evalResult) {
|
||||
case .success(let value):
|
||||
result(value)
|
||||
return
|
||||
case .failure(let error):
|
||||
let userInfo = (error as NSError).userInfo
|
||||
self.onConsoleMessage(message: userInfo["WKJavaScriptExceptionMessage"] as? String ?? "", messageLevel: 3)
|
||||
break
|
||||
}
|
||||
|
||||
result(nil)
|
||||
}
|
||||
|
||||
if value == nil {
|
||||
result!(nil)
|
||||
return
|
||||
} else {
|
||||
evaluateJavaScript(jsToInject) { (value, error) in
|
||||
guard let result = result else {
|
||||
return
|
||||
}
|
||||
|
||||
if error != nil {
|
||||
let userInfo = (error! as NSError).userInfo
|
||||
self.onConsoleMessage(message: userInfo["WKJavaScriptExceptionMessage"] as? String ?? "", messageLevel: 3)
|
||||
}
|
||||
|
||||
if value == nil {
|
||||
result(nil)
|
||||
return
|
||||
}
|
||||
|
||||
result(value)
|
||||
}
|
||||
|
||||
result!(value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public func evaluateJavascript(source: String, result: FlutterResult?) {
|
||||
injectDeferredObject(source: source, withWrapper: nil, result: result)
|
||||
public func evaluateJavascript(source: String, contentWorldName: String?, result: FlutterResult?) {
|
||||
injectDeferredObject(source: source, contentWorldName: contentWorldName, withWrapper: nil, result: result)
|
||||
}
|
||||
|
||||
public func injectJavascriptFileFromUrl(urlFile: String) {
|
||||
let jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document);"
|
||||
injectDeferredObject(source: urlFile, withWrapper: jsWrapper, result: nil)
|
||||
injectDeferredObject(source: urlFile, contentWorldName: nil, withWrapper: jsWrapper, result: nil)
|
||||
}
|
||||
|
||||
public func injectCSSCode(source: String) {
|
||||
let jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %@; d.body.appendChild(c); })(document);"
|
||||
injectDeferredObject(source: source, withWrapper: jsWrapper, result: nil)
|
||||
injectDeferredObject(source: source, contentWorldName: nil, withWrapper: jsWrapper, result: nil)
|
||||
}
|
||||
|
||||
public func injectCSSFileFromUrl(urlFile: String) {
|
||||
let jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet', c.type='text/css'; c.href = %@; d.body.appendChild(c); })(document);"
|
||||
injectDeferredObject(source: urlFile, withWrapper: jsWrapper, result: nil)
|
||||
injectDeferredObject(source: urlFile, contentWorldName: nil, withWrapper: jsWrapper, result: nil)
|
||||
}
|
||||
|
||||
public func getCopyBackForwardList() -> [String: Any] {
|
||||
|
@ -2181,6 +2267,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
|||
currentURL = url
|
||||
InAppWebView.credentialsProposed = []
|
||||
evaluateJavaScript(platformReadyJS, completionHandler: nil)
|
||||
|
||||
onLoadStop(url: url?.absoluteString)
|
||||
|
||||
if IABController != nil {
|
||||
|
|
|
@ -30,15 +30,15 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
|
|||
result( (webView != nil) ? Int(webView!.estimatedProgress * 100) : nil )
|
||||
break
|
||||
case "loadUrl":
|
||||
let url = (arguments!["url"] as? String)!
|
||||
let headers = (arguments!["headers"] as? [String: String])!
|
||||
let url = arguments!["url"] as! String
|
||||
let headers = arguments!["headers"] as! [String: String]
|
||||
webView?.loadUrl(url: URL(string: url)!, headers: headers)
|
||||
result(true)
|
||||
break
|
||||
case "postUrl":
|
||||
if webView != nil {
|
||||
let url = (arguments!["url"] as? String)!
|
||||
let postData = (arguments!["postData"] as? FlutterStandardTypedData)!
|
||||
let url = arguments!["url"] as! String
|
||||
let postData = arguments!["postData"] as! FlutterStandardTypedData
|
||||
webView!.postUrl(url: URL(string: url)!, postData: postData.data, completionHandler: { () -> Void in
|
||||
result(true)
|
||||
})
|
||||
|
@ -48,16 +48,16 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
|
|||
}
|
||||
break
|
||||
case "loadData":
|
||||
let data = (arguments!["data"] as? String)!
|
||||
let mimeType = (arguments!["mimeType"] as? String)!
|
||||
let encoding = (arguments!["encoding"] as? String)!
|
||||
let baseUrl = (arguments!["baseUrl"] as? String)!
|
||||
let data = arguments!["data"] as! String
|
||||
let mimeType = arguments!["mimeType"] as! String
|
||||
let encoding = arguments!["encoding"] as! String
|
||||
let baseUrl = arguments!["baseUrl"] as! String
|
||||
webView?.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
|
||||
result(true)
|
||||
break
|
||||
case "loadFile":
|
||||
let url = (arguments!["url"] as? String)!
|
||||
let headers = (arguments!["headers"] as? [String: String])!
|
||||
let url = arguments!["url"] as! String
|
||||
let headers = arguments!["headers"] as! [String: String]
|
||||
|
||||
do {
|
||||
try webView?.loadFile(url: url, headers: headers)
|
||||
|
@ -70,25 +70,26 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
|
|||
break
|
||||
case "evaluateJavascript":
|
||||
if webView != nil {
|
||||
let source = (arguments!["source"] as? String)!
|
||||
webView!.evaluateJavascript(source: source, result: result)
|
||||
let source = arguments!["source"] as! String
|
||||
let contentWorldName = arguments!["contentWorld"] as? String
|
||||
webView!.evaluateJavascript(source: source, contentWorldName: contentWorldName, result: result)
|
||||
}
|
||||
else {
|
||||
result(nil)
|
||||
}
|
||||
break
|
||||
case "injectJavascriptFileFromUrl":
|
||||
let urlFile = (arguments!["urlFile"] as? String)!
|
||||
let urlFile = arguments!["urlFile"] as! String
|
||||
webView?.injectJavascriptFileFromUrl(urlFile: urlFile)
|
||||
result(true)
|
||||
break
|
||||
case "injectCSSCode":
|
||||
let source = (arguments!["source"] as? String)!
|
||||
let source = arguments!["source"] as! String
|
||||
webView?.injectCSSCode(source: source)
|
||||
result(true)
|
||||
break
|
||||
case "injectCSSFileFromUrl":
|
||||
let urlFile = (arguments!["urlFile"] as? String)!
|
||||
let urlFile = arguments!["urlFile"] as! String
|
||||
webView?.injectCSSFileFromUrl(urlFile: urlFile)
|
||||
result(true)
|
||||
break
|
||||
|
@ -111,12 +112,12 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
|
|||
result(webView?.canGoForward ?? false)
|
||||
break
|
||||
case "goBackOrForward":
|
||||
let steps = (arguments!["steps"] as? Int)!
|
||||
let steps = arguments!["steps"] as! Int
|
||||
webView?.goBackOrForward(steps: steps)
|
||||
result(true)
|
||||
break
|
||||
case "canGoBackOrForward":
|
||||
let steps = (arguments!["steps"] as? Int)!
|
||||
let steps = arguments!["steps"] as! Int
|
||||
result(webView?.canGoBackOrForward(steps: steps) ?? false)
|
||||
break
|
||||
case "stopLoading":
|
||||
|
|
|
@ -1351,7 +1351,14 @@ class InAppWebViewController {
|
|||
await _channel.invokeMethod('stopLoading', args);
|
||||
}
|
||||
|
||||
///Evaluates JavaScript code into the WebView and returns the result of the evaluation.
|
||||
///Evaluates JavaScript [source] code into the WebView and returns the result of the evaluation.
|
||||
///
|
||||
///[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**: This method shouldn't be called in the [WebView.onWebViewCreated] or [WebView.onLoadStart] events,
|
||||
///because, in these events, the [WebView] is not ready to handle it yet.
|
||||
|
@ -1360,10 +1367,13 @@ class InAppWebViewController {
|
|||
///
|
||||
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#evaluateJavascript(java.lang.String,%20android.webkit.ValueCallback%3Cjava.lang.String%3E)
|
||||
///
|
||||
///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1415017-evaluatejavascript
|
||||
Future<dynamic> evaluateJavascript({required String source}) async {
|
||||
///**Official iOS API**:
|
||||
///- https://developer.apple.com/documentation/webkit/wkwebview/1415017-evaluatejavascript
|
||||
///- https://developer.apple.com/documentation/webkit/wkwebview/3656442-evaluatejavascript
|
||||
Future<dynamic> evaluateJavascript({required String source, ContentWorld? contentWorld}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('source', () => source);
|
||||
args.putIfAbsent('contentWorld', () => contentWorld?.name);
|
||||
var data = await _channel.invokeMethod('evaluateJavascript', args);
|
||||
if (data != null && defaultTargetPlatform == TargetPlatform.android) data = json.decode(data);
|
||||
return data;
|
||||
|
|
|
@ -4599,12 +4599,15 @@ class UserScript {
|
|||
|
||||
///Class that represents an object that defines a scope of execution for JavaScript code, and which you use to prevent conflicts between different scripts.
|
||||
///
|
||||
///**NOTE for iOS 14.0+**: this class represents the native [WKContentWorld](https://developer.apple.com/documentation/webkit/wkcontentworld) class.
|
||||
///**NOTE for iOS**: available on iOS 14.0+. This class represents the native [WKContentWorld](https://developer.apple.com/documentation/webkit/wkcontentworld) class.
|
||||
///
|
||||
///**NOTE for Android**: it will create and append an `<iframe>` HTML element with `id` equals to `flutter_inappwebview_[name]` to the webpage's content that contains only the scripts
|
||||
///in order to define a new scope of execution for JavaScript code. Unfortunately, there isn't any other way to do it.
|
||||
///For any [ContentWorld], except [ContentWorld.page], if you need to access to the `window` or `document` global Object,
|
||||
///you need to use `window.top` and `window.top.document` because the code runs inside an `<iframe>`.
|
||||
///**NOTE for Android**: it will create and append an `<iframe>` HTML element with `id` equals to `flutter_inappwebview_[name]`
|
||||
///to the webpage's content that contains only the inline `<script>` HTML elements in order to define a new scope of execution for JavaScript code.
|
||||
///Unfortunately, there isn't any other way to do it.
|
||||
///There are some limitations:
|
||||
///- for any [ContentWorld], except [ContentWorld.page] (that is the webpage itself), if you need to access to the `window` or `document` global Object,
|
||||
///you need to use `window.top` and `window.top.document` because the code runs inside an `<iframe>`;
|
||||
///- also, the execution of the inline `<script>` could be blocked by the `Content-Security-Policy` header.
|
||||
class ContentWorld {
|
||||
///The name of a custom content world.
|
||||
final String name;
|
||||
|
|
Loading…
Reference in New Issue