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
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
webView.evaluateJavascript(jsScript, (MethodChannel.Result) null);
|
webView.evaluateJavascript(jsScript, null);
|
||||||
} else {
|
} else {
|
||||||
webView.loadUrl("javascript:" + jsScript);
|
webView.loadUrl("javascript:" + jsScript);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import android.os.Message;
|
||||||
import android.print.PrintAttributes;
|
import android.print.PrintAttributes;
|
||||||
import android.print.PrintDocumentAdapter;
|
import android.print.PrintDocumentAdapter;
|
||||||
import android.print.PrintManager;
|
import android.print.PrintManager;
|
||||||
|
import android.util.ArraySet;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.ActionMode;
|
import android.view.ActionMode;
|
||||||
|
@ -42,6 +43,7 @@ import android.widget.HorizontalScrollView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
import androidx.webkit.WebViewCompat;
|
import androidx.webkit.WebViewCompat;
|
||||||
import androidx.webkit.WebViewFeature;
|
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.Shared;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.cert.CertificateEncodingException;
|
import java.security.cert.CertificateEncodingException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import io.flutter.plugin.common.MethodChannel;
|
import io.flutter.plugin.common.MethodChannel;
|
||||||
|
@ -106,8 +113,12 @@ final public class InAppWebView extends InputAwareWebView {
|
||||||
public Runnable checkContextMenuShouldBeClosedTask;
|
public Runnable checkContextMenuShouldBeClosedTask;
|
||||||
public int newCheckContextMenuShouldBeClosedTaskTask = 100; // ms
|
public int newCheckContextMenuShouldBeClosedTaskTask = 100; // ms
|
||||||
|
|
||||||
|
public Set<String> userScriptsContentWorlds = new HashSet<String>() {{
|
||||||
|
add("page");
|
||||||
|
}};
|
||||||
|
|
||||||
static final String pluginScriptsWrapperJS = "(function(){" +
|
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" +
|
" $PLACEHOLDER_VALUE" +
|
||||||
" window." + JavaScriptBridgeInterface.name + "._pluginScriptsLoaded = true;" +
|
" 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 variableForOnLoadResourceJS = "_flutter_inappwebview_useOnLoadResource";
|
||||||
static final String enableVariableForOnLoadResourceJS = variableForOnLoadResourceJS + " = $PLACEHOLDER_VALUE;";
|
static final String enableVariableForOnLoadResourceJS = "window." + variableForOnLoadResourceJS + " = $PLACEHOLDER_VALUE;";
|
||||||
|
|
||||||
static final String resourceObserverJS = "(function() {" +
|
static final String resourceObserverJS = "(function() {" +
|
||||||
" var observer = new PerformanceObserver(function(list) {" +
|
" var observer = new PerformanceObserver(function(list) {" +
|
||||||
|
@ -1169,7 +1180,9 @@ final public class InAppWebView extends InputAwareWebView {
|
||||||
String placeholderValue = newOptions.useShouldInterceptAjaxRequest ? "true" : "false";
|
String placeholderValue = newOptions.useShouldInterceptAjaxRequest ? "true" : "false";
|
||||||
String sourceJs = InAppWebView.enableVariableForShouldInterceptAjaxRequestJS.replace("$PLACEHOLDER_VALUE", placeholderValue);
|
String sourceJs = InAppWebView.enableVariableForShouldInterceptAjaxRequestJS.replace("$PLACEHOLDER_VALUE", placeholderValue);
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
evaluateJavascript(sourceJs, (ValueCallback<String>) null);
|
for (String contentWorldName : userScriptsContentWorlds) {
|
||||||
|
evaluateJavascript(sourceJs, contentWorldName, null);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
loadUrl("javascript:" + sourceJs);
|
loadUrl("javascript:" + sourceJs);
|
||||||
}
|
}
|
||||||
|
@ -1179,7 +1192,9 @@ final public class InAppWebView extends InputAwareWebView {
|
||||||
String placeholderValue = newOptions.useShouldInterceptFetchRequest ? "true" : "false";
|
String placeholderValue = newOptions.useShouldInterceptFetchRequest ? "true" : "false";
|
||||||
String sourceJs = InAppWebView.enableVariableForShouldInterceptFetchRequestsJS.replace("$PLACEHOLDER_VALUE", placeholderValue);
|
String sourceJs = InAppWebView.enableVariableForShouldInterceptFetchRequestsJS.replace("$PLACEHOLDER_VALUE", placeholderValue);
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
evaluateJavascript(sourceJs, (ValueCallback<String>) null);
|
for (String contentWorldName : userScriptsContentWorlds) {
|
||||||
|
evaluateJavascript(sourceJs, contentWorldName, null);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
loadUrl("javascript:" + sourceJs);
|
loadUrl("javascript:" + sourceJs);
|
||||||
}
|
}
|
||||||
|
@ -1457,7 +1472,7 @@ final public class InAppWebView extends InputAwareWebView {
|
||||||
return (options != null) ? options.getRealOptions(this) : null;
|
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;
|
String scriptToInject = source;
|
||||||
if (jsWrapper != null) {
|
if (jsWrapper != null) {
|
||||||
org.json.JSONArray jsonEsc = new org.json.JSONArray();
|
org.json.JSONArray jsonEsc = new org.json.JSONArray();
|
||||||
|
@ -1472,39 +1487,58 @@ final public class InAppWebView extends InputAwareWebView {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||||
// This action will have the side-effect of blurring the currently focused element
|
// This action will have the side-effect of blurring the currently focused element
|
||||||
loadUrl("javascript:" + finalScriptToInject);
|
loadUrl("javascript:" + finalScriptToInject.replaceAll("[\r\n]+", ""));
|
||||||
result.success("");
|
result.success("");
|
||||||
} else {
|
} else {
|
||||||
evaluateJavascript(finalScriptToInject, new ValueCallback<String>() {
|
if (contentWorldName != null && !contentWorldName.equals("page")) {
|
||||||
@Override
|
String sourceToInject = finalScriptToInject;
|
||||||
public void onReceiveValue(String s) {
|
if (!userScriptsContentWorlds.contains(contentWorldName)) {
|
||||||
if (result == null)
|
userScriptsContentWorlds.add(contentWorldName);
|
||||||
return;
|
// Add only the first time all the plugin scripts needed.
|
||||||
result.success(s);
|
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) {
|
public void evaluateJavascript(String source, String contentWorldName, MethodChannel.Result result) {
|
||||||
injectDeferredObject(source, null, result);
|
injectDeferredObject(source, contentWorldName, null, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void injectJavascriptFileFromUrl(String urlFile) {
|
public void injectJavascriptFileFromUrl(String urlFile) {
|
||||||
String jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document);";
|
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) {
|
public void injectCSSCode(String source) {
|
||||||
String jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document);";
|
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) {
|
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);";
|
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() {
|
public HashMap<String, Object> getCopyBackForwardList() {
|
||||||
|
@ -1999,6 +2033,10 @@ final public class InAppWebView extends InputAwareWebView {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addUserScript(Map<String, Object> userScript) {
|
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);
|
return userScripts.add(userScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2009,6 +2047,52 @@ final public class InAppWebView extends InputAwareWebView {
|
||||||
public void removeAllUserScripts() {
|
public void removeAllUserScripts() {
|
||||||
userScripts.clear();
|
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
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
|
|
|
@ -26,12 +26,8 @@ import androidx.annotation.RequiresApi;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.Credential;
|
import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.Credential;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.CredentialDatabase;
|
import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.CredentialDatabase;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
|
import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.JavaScriptBridgeInterface;
|
|
||||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
@ -166,10 +162,10 @@ public class InAppWebViewClient extends WebViewClient {
|
||||||
private void loadCustomJavaScriptOnPageStarted(WebView view) {
|
private void loadCustomJavaScriptOnPageStarted(WebView view) {
|
||||||
InAppWebView webView = (InAppWebView) view;
|
InAppWebView webView = (InAppWebView) view;
|
||||||
|
|
||||||
String jsPluginScripts = preparePluginUserScripts(webView);
|
String jsPluginScriptsWrapped = webView.prepareAndWrapPluginUserScripts();
|
||||||
String jsUserScriptsAtDocumentStart = prepareUserScriptsAtDocumentStart(webView);
|
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) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
webView.evaluateJavascript(js, (ValueCallback<String>) null);
|
webView.evaluateJavascript(js, (ValueCallback<String>) null);
|
||||||
|
@ -182,11 +178,11 @@ public class InAppWebViewClient extends WebViewClient {
|
||||||
InAppWebView webView = (InAppWebView) view;
|
InAppWebView webView = (InAppWebView) view;
|
||||||
|
|
||||||
// try to reload also custom scripts if they were not loaded during the onPageStarted event
|
// 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 jsUserScriptsAtDocumentStart = prepareUserScriptsAtDocumentStart(webView);
|
||||||
String jsUserScriptsAtDocumentEnd = prepareUserScriptsAtDocumentEnd(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) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
webView.evaluateJavascript(js, (ValueCallback<String>) null);
|
webView.evaluateJavascript(js, (ValueCallback<String>) null);
|
||||||
|
@ -194,57 +190,25 @@ public class InAppWebViewClient extends WebViewClient {
|
||||||
webView.loadUrl("javascript:" + js.replaceAll("[\r\n]+", ""));
|
webView.loadUrl("javascript:" + js.replaceAll("[\r\n]+", ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String preparePluginUserScripts(InAppWebView webView) {
|
private String prepareUserScripts(InAppWebView webView, int atDocumentInjectionTime) {
|
||||||
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) {
|
|
||||||
StringBuilder js = new StringBuilder();
|
StringBuilder js = new StringBuilder();
|
||||||
|
|
||||||
for (Map<String, Object> userScript : webView.userScripts) {
|
for (Map<String, Object> userScript : webView.userScripts) {
|
||||||
Integer injectionTime = (Integer) userScript.get("injectionTime");
|
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 source = (String) userScript.get("source");
|
||||||
String contentWorldName = (String) userScript.get("contentWorld");
|
String contentWorldName = (String) userScript.get("contentWorld");
|
||||||
if (source != null) {
|
if (source != null) {
|
||||||
if (contentWorldName != null && !contentWorldName.equals("page")) {
|
if (contentWorldName != null && !contentWorldName.equals("page")) {
|
||||||
String jsPluginScripts = preparePluginUserScripts(webView);
|
String jsPluginScripts = webView.prepareAndWrapPluginUserScripts();
|
||||||
source = jsPluginScripts + "\n" + source;
|
source = jsPluginScripts + "\n" + source;
|
||||||
}
|
}
|
||||||
|
if (contentWorldName != null && !webView.userScriptsContentWorlds.contains(contentWorldName)) {
|
||||||
JSONObject sourceEncoded = new JSONObject();
|
webView.userScriptsContentWorlds.add(contentWorldName);
|
||||||
try {
|
|
||||||
// encode the javascript source in order to escape special chars and quotes
|
|
||||||
sourceEncoded.put("source", source);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
String sourceWrapped = webView.wrapSourceCodeInContentWorld(contentWorldName, source);
|
||||||
String sourceWrapped = contentWorldName == null || contentWorldName.equals("page") ? source :
|
if (atDocumentInjectionTime == 0 && contentWorldName != null && !contentWorldName.equals("page")) {
|
||||||
InAppWebView.contentWorldWrapperJS.replace("$CONTENT_WORLD_NAME", contentWorldName)
|
|
||||||
.replace("$CONTENT_WORLD_NAME", contentWorldName)
|
|
||||||
.replace("$JSON_SOURCE_ENCODED", sourceEncoded.toString());
|
|
||||||
|
|
||||||
if (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.
|
// 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)
|
sourceWrapped = InAppWebView.documentReadyWrapperJS.replace("$PLACEHOLDER_VALUE", sourceWrapped)
|
||||||
.replace("$PLACEHOLDER_VALUE", sourceWrapped);
|
.replace("$PLACEHOLDER_VALUE", sourceWrapped);
|
||||||
|
@ -258,43 +222,15 @@ public class InAppWebViewClient extends WebViewClient {
|
||||||
return js.toString();
|
return js.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String prepareUserScriptsAtDocumentStart(InAppWebView webView) {
|
||||||
|
return prepareUserScripts(webView, 0);
|
||||||
|
}
|
||||||
|
|
||||||
private String prepareUserScriptsAtDocumentEnd(InAppWebView webView) {
|
private String prepareUserScriptsAtDocumentEnd(InAppWebView webView) {
|
||||||
StringBuilder js = new StringBuilder();
|
return prepareUserScripts(webView, 1);
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String wrapPluginAndUserScripts(String jsPluginScripts, @Nullable String jsUserScriptsAtDocumentStart, @Nullable String jsUserScriptsAtDocumentEnd) {
|
private String wrapPluginAndUserScripts(String jsPluginScriptsWrapped, @Nullable String jsUserScriptsAtDocumentStart, @Nullable String jsUserScriptsAtDocumentEnd) {
|
||||||
String jsPluginScriptsWrapped = InAppWebView.pluginScriptsWrapperJS
|
|
||||||
.replace("$PLACEHOLDER_VALUE", jsPluginScripts);
|
|
||||||
String jsUserScriptsAtDocumentStartWrapped = jsUserScriptsAtDocumentStart == null || jsUserScriptsAtDocumentStart.isEmpty() ? "" :
|
String jsUserScriptsAtDocumentStartWrapped = jsUserScriptsAtDocumentStart == null || jsUserScriptsAtDocumentStart.isEmpty() ? "" :
|
||||||
InAppWebView.userScriptsAtDocumentStartWrapperJS.replace("$PLACEHOLDER_VALUE", jsUserScriptsAtDocumentStart);
|
InAppWebView.userScriptsAtDocumentStartWrapperJS.replace("$PLACEHOLDER_VALUE", jsUserScriptsAtDocumentStart);
|
||||||
String jsUserScriptsAtDocumentEndWrapped = jsUserScriptsAtDocumentEnd == null || jsUserScriptsAtDocumentEnd.isEmpty() ? "" :
|
String jsUserScriptsAtDocumentEndWrapped = jsUserScriptsAtDocumentEnd == null || jsUserScriptsAtDocumentEnd.isEmpty() ? "" :
|
||||||
|
@ -305,6 +241,7 @@ public class InAppWebViewClient extends WebViewClient {
|
||||||
@Override
|
@Override
|
||||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||||
final InAppWebView webView = (InAppWebView) view;
|
final InAppWebView webView = (InAppWebView) view;
|
||||||
|
webView.resetUserScriptsContentWorlds();
|
||||||
|
|
||||||
loadCustomJavaScriptOnPageStarted(webView);
|
loadCustomJavaScriptOnPageStarted(webView);
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,8 @@ public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandle
|
||||||
case "evaluateJavascript":
|
case "evaluateJavascript":
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
String source = (String) call.argument("source");
|
String source = (String) call.argument("source");
|
||||||
webView.evaluateJavascript(source, result);
|
String contentWorldName = (String) call.argument("contentWorld");
|
||||||
|
webView.evaluateJavascript(source, contentWorldName, result);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result.success(null);
|
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) {
|
return new Promise(function(resolve, reject) {
|
||||||
window.\(JAVASCRIPT_BRIDGE_NAME)[_callHandlerID] = resolve;
|
window.\(JAVASCRIPT_BRIDGE_NAME)[_callHandlerID] = resolve;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
"""
|
"""
|
||||||
|
|
||||||
// the message needs to be concatenated with '' in order to have the same behavior like on Android
|
// 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 variableForOnLoadResourceJS = "_flutter_inappwebview_useOnLoadResource"
|
||||||
let enableVariableForOnLoadResourceJS = "\(variableForOnLoadResourceJS) = $PLACEHOLDER_VALUE;"
|
let enableVariableForOnLoadResourceJS = "window.\(variableForOnLoadResourceJS) = $PLACEHOLDER_VALUE;"
|
||||||
|
|
||||||
let resourceObserverJS = """
|
let resourceObserverJS = """
|
||||||
(function() {
|
(function() {
|
||||||
|
@ -877,7 +877,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
||||||
static var windowWebViews: [Int64:WebViewTransport] = [:]
|
static var windowWebViews: [Int64:WebViewTransport] = [:]
|
||||||
static var windowAutoincrementId: Int64 = 0;
|
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?) {
|
init(frame: CGRect, configuration: WKWebViewConfiguration, IABController: InAppBrowserWebViewController?, contextMenu: [String: Any]?, channel: FlutterMethodChannel?) {
|
||||||
super.init(frame: frame, configuration: configuration)
|
super.init(frame: frame, configuration: configuration)
|
||||||
|
@ -1219,60 +1219,88 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
||||||
configuration.userContentController.addUserScript(userScriptWindowId)
|
configuration.userContentController.addUserScript(userScriptWindowId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(iOS 14.0, *)
|
func getAllPluginUserScriptMergedJS() -> String {
|
||||||
func addSharedPluginUserScriptsBetweenContentWorlds(contentWorlds: [WKContentWorld]) -> Void {
|
var allPluginUserScriptMergedJS = promisePolyfillJS + "\n" +
|
||||||
for contentWorld in contentWorlds {
|
javaScriptBridgeJS + "\n" +
|
||||||
let promisePolyfillJSScript = WKUserScript(source: promisePolyfillJS, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: contentWorld)
|
consoleLogJS + "\n" +
|
||||||
configuration.userContentController.addUserScript(promisePolyfillJSScript)
|
printJS + "\n"
|
||||||
|
if let options = options {
|
||||||
|
if options.useShouldInterceptAjaxRequest {
|
||||||
|
allPluginUserScriptMergedJS += interceptAjaxRequestsJS + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
let javaScriptBridgeJSScript = WKUserScript(source: javaScriptBridgeJS, injectionTime: .atDocumentStart, forMainFrameOnly: false, in: contentWorld)
|
if options.useShouldInterceptFetchRequest {
|
||||||
configuration.userContentController.addUserScript(javaScriptBridgeJSScript)
|
allPluginUserScriptMergedJS += interceptFetchRequestsJS + "\n"
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return allPluginUserScriptMergedJS
|
||||||
}
|
}
|
||||||
|
|
||||||
func addPluginUserScripts() -> Void {
|
@available(iOS 14.0, *)
|
||||||
if #available(iOS 14.0, *) {
|
func addSharedPluginUserScriptsInContentWorld(contentWorldName: String) -> Void {
|
||||||
let contentWorlds = userScriptsContentWorlds.map { (contentWorldName) -> WKContentWorld in
|
let contentWorld = getContentWorld(name: contentWorldName)
|
||||||
return 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 {
|
} else {
|
||||||
let promisePolyfillJSScript = WKUserScript(source: promisePolyfillJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
let promisePolyfillJSScript = WKUserScript(
|
||||||
|
source: promisePolyfillJS,
|
||||||
|
injectionTime: .atDocumentStart,
|
||||||
|
forMainFrameOnly: false)
|
||||||
configuration.userContentController.addUserScript(promisePolyfillJSScript)
|
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.addUserScript(javaScriptBridgeJSScript)
|
||||||
configuration.userContentController.removeScriptMessageHandler(forName: "callHandler")
|
configuration.userContentController.removeScriptMessageHandler(forName: "callHandler")
|
||||||
configuration.userContentController.add(self, name: "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.addUserScript(consoleLogJSScript)
|
||||||
configuration.userContentController.removeScriptMessageHandler(forName: "consoleLog")
|
configuration.userContentController.removeScriptMessageHandler(forName: "consoleLog")
|
||||||
configuration.userContentController.add(self, name: "consoleLog")
|
configuration.userContentController.add(self, name: "consoleLog")
|
||||||
|
@ -1287,23 +1315,33 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
||||||
|
|
||||||
if let options = options {
|
if let options = options {
|
||||||
if options.useShouldInterceptAjaxRequest {
|
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)
|
configuration.userContentController.addUserScript(interceptAjaxRequestsJSScript)
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.useShouldInterceptFetchRequest {
|
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)
|
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)
|
let findElementsAtPointJSScript = WKUserScript(source: findElementsAtPointJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
||||||
configuration.userContentController.addUserScript(findElementsAtPointJSScript)
|
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)
|
let lastTouchedAnchorOrImageJSScript = WKUserScript(source: lastTouchedAnchorOrImageJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
||||||
configuration.userContentController.addUserScript(lastTouchedAnchorOrImageJSScript)
|
configuration.userContentController.addUserScript(lastTouchedAnchorOrImageJSScript)
|
||||||
|
|
||||||
|
@ -1352,18 +1390,19 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
||||||
|
|
||||||
public func appendUserScript(userScript: [String: Any]) -> Void {
|
public func appendUserScript(userScript: [String: Any]) -> Void {
|
||||||
var wkUserScript: WKUserScript?
|
var wkUserScript: WKUserScript?
|
||||||
if #available(iOS 14.0, *), let contentWorldName = userScript["contentWorld"] as? String {
|
let contentWorldName = userScript["contentWorld"] as? String
|
||||||
if !userScriptsContentWorlds.contains(contentWorldName) {
|
if contentWorldName != nil, !userScriptsContentWorlds.contains(contentWorldName!) {
|
||||||
userScriptsContentWorlds.append(contentWorldName)
|
userScriptsContentWorlds.append(contentWorldName!)
|
||||||
}
|
}
|
||||||
|
if #available(iOS 14.0, *), let contentWorldName = contentWorldName {
|
||||||
wkUserScript = WKUserScript(source: userScript["source"] as! String,
|
wkUserScript = WKUserScript(source: userScript["source"] as! String,
|
||||||
injectionTime: WKUserScriptInjectionTime.init(rawValue: userScript["injectionTime"] as! Int) ?? .atDocumentStart,
|
injectionTime: WKUserScriptInjectionTime.init(rawValue: userScript["injectionTime"] as! Int) ?? .atDocumentStart,
|
||||||
forMainFrameOnly: userScript["iosForMainFrameOnly"] as! Bool,
|
forMainFrameOnly: userScript["iosForMainFrameOnly"] as! Bool,
|
||||||
in: getContentWorld(name: contentWorldName))
|
in: getContentWorld(name: contentWorldName))
|
||||||
} else {
|
} else {
|
||||||
wkUserScript = WKUserScript(source: userScript["source"] as! String,
|
wkUserScript = WKUserScript(source: userScript["source"] as! String,
|
||||||
injectionTime: WKUserScriptInjectionTime.init(rawValue: userScript["injectionTime"] as! Int) ?? .atDocumentStart,
|
injectionTime: WKUserScriptInjectionTime.init(rawValue: userScript["injectionTime"] as! Int) ?? .atDocumentStart,
|
||||||
forMainFrameOnly: userScript["iosForMainFrameOnly"] as! Bool)
|
forMainFrameOnly: userScript["iosForMainFrameOnly"] as! Bool)
|
||||||
}
|
}
|
||||||
userScripts.append(wkUserScript!)
|
userScripts.append(wkUserScript!)
|
||||||
}
|
}
|
||||||
|
@ -1784,17 +1823,35 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
||||||
|
|
||||||
if newOptionsMap["useOnLoadResource"] != nil && options?.useOnLoadResource != newOptions.useOnLoadResource && newOptions.useOnLoadResource {
|
if newOptionsMap["useOnLoadResource"] != nil && options?.useOnLoadResource != newOptions.useOnLoadResource && newOptions.useOnLoadResource {
|
||||||
let placeholderValue = newOptions.useOnLoadResource ? "true" : "false"
|
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 {
|
if newOptionsMap["useShouldInterceptAjaxRequest"] != nil && options?.useShouldInterceptAjaxRequest != newOptions.useShouldInterceptAjaxRequest && newOptions.useShouldInterceptAjaxRequest {
|
||||||
let placeholderValue = newOptions.useShouldInterceptAjaxRequest ? "true" : "false"
|
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 {
|
if newOptionsMap["useShouldInterceptFetchRequest"] != nil && options?.useShouldInterceptFetchRequest != newOptions.useShouldInterceptFetchRequest && newOptions.useShouldInterceptFetchRequest {
|
||||||
let placeholderValue = newOptions.useShouldInterceptFetchRequest ? "true" : "false"
|
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 {
|
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
|
var jsToInject = source
|
||||||
if let wrapper = jsWrapper {
|
if let wrapper = jsWrapper {
|
||||||
let jsonData: Data? = try? JSONSerialization.data(withJSONObject: [source], options: [])
|
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))
|
let sourceString: String? = (sourceArrayString! as NSString).substring(with: NSRange(location: 1, length: (sourceArrayString?.count ?? 0) - 2))
|
||||||
jsToInject = String(format: wrapper, sourceString!)
|
jsToInject = String(format: wrapper, sourceString!)
|
||||||
}
|
}
|
||||||
evaluateJavaScript(jsToInject, completionHandler: {(value, error) in
|
|
||||||
if result == nil {
|
if #available(iOS 14.0, *), let contentWorldName = contentWorldName {
|
||||||
return
|
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
|
||||||
}
|
}
|
||||||
|
let contentWorld = getContentWorld(name: contentWorldName)
|
||||||
if error != nil {
|
evaluateJavaScript(jsToInject, in: nil, in: contentWorld) { (evalResult) in
|
||||||
let userInfo = (error! as NSError).userInfo
|
guard let result = result else {
|
||||||
self.onConsoleMessage(message: userInfo["WKJavaScriptExceptionMessage"] as? String ?? "", messageLevel: 3)
|
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)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if value == nil {
|
evaluateJavaScript(jsToInject) { (value, error) in
|
||||||
result!(nil)
|
guard let result = result else {
|
||||||
return
|
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?) {
|
public func evaluateJavascript(source: String, contentWorldName: String?, result: FlutterResult?) {
|
||||||
injectDeferredObject(source: source, withWrapper: nil, result: result)
|
injectDeferredObject(source: source, contentWorldName: contentWorldName, withWrapper: nil, result: result)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func injectJavascriptFileFromUrl(urlFile: String) {
|
public func injectJavascriptFileFromUrl(urlFile: String) {
|
||||||
let jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document);"
|
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) {
|
public func injectCSSCode(source: String) {
|
||||||
let jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %@; d.body.appendChild(c); })(document);"
|
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) {
|
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);"
|
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] {
|
public func getCopyBackForwardList() -> [String: Any] {
|
||||||
|
@ -2181,6 +2267,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
|
||||||
currentURL = url
|
currentURL = url
|
||||||
InAppWebView.credentialsProposed = []
|
InAppWebView.credentialsProposed = []
|
||||||
evaluateJavaScript(platformReadyJS, completionHandler: nil)
|
evaluateJavaScript(platformReadyJS, completionHandler: nil)
|
||||||
|
|
||||||
onLoadStop(url: url?.absoluteString)
|
onLoadStop(url: url?.absoluteString)
|
||||||
|
|
||||||
if IABController != nil {
|
if IABController != nil {
|
||||||
|
|
|
@ -30,15 +30,15 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
|
||||||
result( (webView != nil) ? Int(webView!.estimatedProgress * 100) : nil )
|
result( (webView != nil) ? Int(webView!.estimatedProgress * 100) : nil )
|
||||||
break
|
break
|
||||||
case "loadUrl":
|
case "loadUrl":
|
||||||
let url = (arguments!["url"] as? String)!
|
let url = arguments!["url"] as! String
|
||||||
let headers = (arguments!["headers"] as? [String: String])!
|
let headers = arguments!["headers"] as! [String: String]
|
||||||
webView?.loadUrl(url: URL(string: url)!, headers: headers)
|
webView?.loadUrl(url: URL(string: url)!, headers: headers)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "postUrl":
|
case "postUrl":
|
||||||
if webView != nil {
|
if webView != nil {
|
||||||
let url = (arguments!["url"] as? String)!
|
let url = arguments!["url"] as! String
|
||||||
let postData = (arguments!["postData"] as? FlutterStandardTypedData)!
|
let postData = arguments!["postData"] as! FlutterStandardTypedData
|
||||||
webView!.postUrl(url: URL(string: url)!, postData: postData.data, completionHandler: { () -> Void in
|
webView!.postUrl(url: URL(string: url)!, postData: postData.data, completionHandler: { () -> Void in
|
||||||
result(true)
|
result(true)
|
||||||
})
|
})
|
||||||
|
@ -48,16 +48,16 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "loadData":
|
case "loadData":
|
||||||
let data = (arguments!["data"] as? String)!
|
let data = arguments!["data"] as! String
|
||||||
let mimeType = (arguments!["mimeType"] as? String)!
|
let mimeType = arguments!["mimeType"] as! String
|
||||||
let encoding = (arguments!["encoding"] as? String)!
|
let encoding = arguments!["encoding"] as! String
|
||||||
let baseUrl = (arguments!["baseUrl"] as? String)!
|
let baseUrl = arguments!["baseUrl"] as! String
|
||||||
webView?.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
|
webView?.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "loadFile":
|
case "loadFile":
|
||||||
let url = (arguments!["url"] as? String)!
|
let url = arguments!["url"] as! String
|
||||||
let headers = (arguments!["headers"] as? [String: String])!
|
let headers = arguments!["headers"] as! [String: String]
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try webView?.loadFile(url: url, headers: headers)
|
try webView?.loadFile(url: url, headers: headers)
|
||||||
|
@ -70,25 +70,26 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
|
||||||
break
|
break
|
||||||
case "evaluateJavascript":
|
case "evaluateJavascript":
|
||||||
if webView != nil {
|
if webView != nil {
|
||||||
let source = (arguments!["source"] as? String)!
|
let source = arguments!["source"] as! String
|
||||||
webView!.evaluateJavascript(source: source, result: result)
|
let contentWorldName = arguments!["contentWorld"] as? String
|
||||||
|
webView!.evaluateJavascript(source: source, contentWorldName: contentWorldName, result: result)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "injectJavascriptFileFromUrl":
|
case "injectJavascriptFileFromUrl":
|
||||||
let urlFile = (arguments!["urlFile"] as? String)!
|
let urlFile = arguments!["urlFile"] as! String
|
||||||
webView?.injectJavascriptFileFromUrl(urlFile: urlFile)
|
webView?.injectJavascriptFileFromUrl(urlFile: urlFile)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "injectCSSCode":
|
case "injectCSSCode":
|
||||||
let source = (arguments!["source"] as? String)!
|
let source = arguments!["source"] as! String
|
||||||
webView?.injectCSSCode(source: source)
|
webView?.injectCSSCode(source: source)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "injectCSSFileFromUrl":
|
case "injectCSSFileFromUrl":
|
||||||
let urlFile = (arguments!["urlFile"] as? String)!
|
let urlFile = arguments!["urlFile"] as! String
|
||||||
webView?.injectCSSFileFromUrl(urlFile: urlFile)
|
webView?.injectCSSFileFromUrl(urlFile: urlFile)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
|
@ -111,12 +112,12 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
|
||||||
result(webView?.canGoForward ?? false)
|
result(webView?.canGoForward ?? false)
|
||||||
break
|
break
|
||||||
case "goBackOrForward":
|
case "goBackOrForward":
|
||||||
let steps = (arguments!["steps"] as? Int)!
|
let steps = arguments!["steps"] as! Int
|
||||||
webView?.goBackOrForward(steps: steps)
|
webView?.goBackOrForward(steps: steps)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "canGoBackOrForward":
|
case "canGoBackOrForward":
|
||||||
let steps = (arguments!["steps"] as? Int)!
|
let steps = arguments!["steps"] as! Int
|
||||||
result(webView?.canGoBackOrForward(steps: steps) ?? false)
|
result(webView?.canGoBackOrForward(steps: steps) ?? false)
|
||||||
break
|
break
|
||||||
case "stopLoading":
|
case "stopLoading":
|
||||||
|
|
|
@ -1351,7 +1351,14 @@ class InAppWebViewController {
|
||||||
await _channel.invokeMethod('stopLoading', args);
|
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,
|
///**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.
|
///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 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
|
///**Official iOS API**:
|
||||||
Future<dynamic> evaluateJavascript({required String source}) async {
|
///- 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>{};
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
args.putIfAbsent('source', () => source);
|
args.putIfAbsent('source', () => source);
|
||||||
|
args.putIfAbsent('contentWorld', () => contentWorld?.name);
|
||||||
var data = await _channel.invokeMethod('evaluateJavascript', args);
|
var data = await _channel.invokeMethod('evaluateJavascript', args);
|
||||||
if (data != null && defaultTargetPlatform == TargetPlatform.android) data = json.decode(data);
|
if (data != null && defaultTargetPlatform == TargetPlatform.android) data = json.decode(data);
|
||||||
return 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.
|
///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
|
///**NOTE for Android**: it will create and append an `<iframe>` HTML element with `id` equals to `flutter_inappwebview_[name]`
|
||||||
///in order to define a new scope of execution for JavaScript code. Unfortunately, there isn't any other way to do it.
|
///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.
|
||||||
///For any [ContentWorld], except [ContentWorld.page], if you need to access to the `window` or `document` global Object,
|
///Unfortunately, there isn't any other way to do it.
|
||||||
///you need to use `window.top` and `window.top.document` because the code runs inside an `<iframe>`.
|
///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 {
|
class ContentWorld {
|
||||||
///The name of a custom content world.
|
///The name of a custom content world.
|
||||||
final String name;
|
final String name;
|
||||||
|
|
Loading…
Reference in New Issue