fixed android user scripts

This commit is contained in:
Lorenzo Pichilli 2022-10-11 15:54:37 +02:00
parent bcbb8afaa4
commit e9c69c7f8b
2 changed files with 79 additions and 39 deletions

View File

@ -2,7 +2,6 @@ package com.pichillilorenzo.flutter_inappwebview.types;
import android.annotation.SuppressLint;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.WebView;
import androidx.annotation.NonNull;
@ -37,10 +36,13 @@ public class UserContentController implements Disposable {
private final Map<UserScript, ScriptHandler> scriptHandlerMap = new HashMap<>();
@Nullable
private ScriptHandler contentWorldsCreatorScript;
@NonNull
private final Map<UserScriptInjectionTime, LinkedHashSet<UserScript>> userOnlyScripts = new HashMap<UserScriptInjectionTime, LinkedHashSet<UserScript>>() {{
put(UserScriptInjectionTime.AT_DOCUMENT_START, new LinkedHashSet<UserScript>());
put(UserScriptInjectionTime.AT_DOCUMENT_END, new LinkedHashSet<UserScript>());
put(UserScriptInjectionTime.AT_DOCUMENT_START, new LinkedHashSet<UserScript>());
put(UserScriptInjectionTime.AT_DOCUMENT_END, new LinkedHashSet<UserScript>());
}};
@NonNull
private final Map<UserScriptInjectionTime, LinkedHashSet<PluginScript>> pluginScripts = new HashMap<UserScriptInjectionTime, LinkedHashSet<PluginScript>>() {{
@ -171,15 +173,35 @@ public class UserContentController implements Disposable {
return new LinkedHashSet<>(this.userOnlyScripts.get(injectionTime));
}
private void updateContentWorldsCreatorScript() {
String source = generateContentWorldsCreatorCode();
if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
if (contentWorldsCreatorScript != null) {
contentWorldsCreatorScript.remove();
}
if (!source.isEmpty() && webView != null) {
contentWorldsCreatorScript = WebViewCompat.addDocumentStartJavaScript(
webView,
source,
new HashSet<String>() {{
add("*");
}}
);
}
}
}
public boolean addUserOnlyScript(UserScript userOnlyScript) {
ContentWorld contentWorld = userOnlyScript.getContentWorld();
if (contentWorld != null) {
contentWorlds.add(contentWorld);
}
if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
this.updateContentWorldsCreatorScript();
if (webView != null && userOnlyScript.getInjectionTime() == UserScriptInjectionTime.AT_DOCUMENT_START
&& WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
ScriptHandler scriptHandler = WebViewCompat.addDocumentStartJavaScript(
webView,
userOnlyScript.getSource(),
wrapSourceCodeInContentWorld(userOnlyScript.getContentWorld(), userOnlyScript.getSource()),
userOnlyScript.getAllowedOriginRules()
);
this.scriptHandlerMap.put(userOnlyScript, scriptHandler);
@ -200,6 +222,7 @@ public class UserContentController implements Disposable {
scriptHandler.remove();
this.scriptHandlerMap.remove(userOnlyScript);
}
this.updateContentWorldsCreatorScript();
}
return this.userOnlyScripts.get(userOnlyScript.getInjectionTime()).remove(userOnlyScript);
}
@ -243,10 +266,12 @@ public class UserContentController implements Disposable {
if (contentWorld != null) {
contentWorlds.add(contentWorld);
}
if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
this.updateContentWorldsCreatorScript();
if (webView != null && pluginScript.getInjectionTime() == UserScriptInjectionTime.AT_DOCUMENT_START
&& WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
ScriptHandler scriptHandler = WebViewCompat.addDocumentStartJavaScript(
webView,
pluginScript.getSource(),
wrapSourceCodeInContentWorld(pluginScript.getContentWorld(), pluginScript.getSource()),
pluginScript.getAllowedOriginRules()
);
this.scriptHandlerMap.put(pluginScript, scriptHandler);
@ -267,6 +292,7 @@ public class UserContentController implements Disposable {
scriptHandler.remove();
this.scriptHandlerMap.remove(pluginScript);
}
this.updateContentWorldsCreatorScript();
}
return this.pluginScripts.get(pluginScript.getInjectionTime()).remove(pluginScript);
}
@ -383,9 +409,31 @@ public class UserContentController implements Disposable {
"}";
private static final String CONTENT_WORLDS_GENERATOR_JS_SOURCE = "(function() {" +
" var contentWorldNames = [" + PluginScriptsUtil.VAR_CONTENT_WORLD_NAME_ARRAY + "];" +
" for (var contentWorldName of contentWorldNames) {" +
" var iframeId = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_' + contentWorldName;" +
" var interval = setInterval(function() {" +
" if (document.body == null) {return;}" +
" var contentWorldNames = [" + PluginScriptsUtil.VAR_CONTENT_WORLD_NAME_ARRAY + "];" +
" for (var contentWorldName of contentWorldNames) {" +
" var iframeId = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_' + contentWorldName;" +
" var iframe = document.getElementById(iframeId);" +
" if (iframe == null) {" +
" iframe = document.createElement('iframe');" +
" iframe.id = iframeId;" +
" iframe.style = 'display: none; z-index: 0; position: absolute; width: 0px; height: 0px';" +
" document.body.append(iframe);" +
" }" +
" var script = iframe.contentWindow.document.createElement('script');" +
" script.id = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_plugin_scripts';" +
" script.innerHTML = " + PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED + ";" +
" iframe.contentWindow.document.body.append(script);" +
" }" +
" clearInterval(interval);" +
" });" +
"})();";
private static final String CONTENT_WORLD_WRAPPER_JS_SOURCE = "(function() {" +
" var interval = setInterval(function() {" +
" if (document.body == null) {return;}" +
" var iframeId = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_" + PluginScriptsUtil.VAR_CONTENT_WORLD_NAME + "';" +
" var iframe = document.getElementById(iframeId);" +
" if (iframe == null) {" +
" iframe = document.createElement('iframe');" +
@ -393,24 +441,14 @@ public class UserContentController implements Disposable {
" iframe.style = 'display: none; z-index: 0; position: absolute; width: 0px; height: 0px';" +
" document.body.append(iframe);" +
" }" +
" if (iframe.contentWindow.document.querySelector('#" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_plugin_scripts') == null) {" +
" return;" +
" }" +
" var script = iframe.contentWindow.document.createElement('script');" +
" script.innerHTML = "+ PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED + ";" +
" script.innerHTML = " + PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED + ";" +
" iframe.contentWindow.document.body.append(script);" +
" }" +
"})();";
private static final String CONTENT_WORLD_WRAPPER_JS_SOURCE = "(function() {" +
" var iframeId = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_" + PluginScriptsUtil.VAR_CONTENT_WORLD_NAME + "';" +
" var iframe = document.getElementById(iframeId);" +
" if (iframe == null) {" +
" iframe = document.createElement('iframe');" +
" iframe.id = iframeId;" +
" iframe.style = 'display: none; z-index: 0; position: absolute; width: 0px; height: 0px';" +
" document.body.append(iframe);" +
" }" +
" var script = iframe.contentWindow.document.createElement('script');" +
" script.innerHTML = "+ PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED + ";" +
" iframe.contentWindow.document.body.append(script);" +
" clearInterval(interval);" +
" });" +
"})();";
private static final String DOCUMENT_READY_WRAPPER_JS_SOURCE = "if (document.readyState === 'interactive' || document.readyState === 'complete') { " +
@ -419,6 +457,11 @@ public class UserContentController implements Disposable {
@Override
public void dispose() {
if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT) && contentWorldsCreatorScript != null) {
contentWorldsCreatorScript.remove();
}
removeAllUserOnlyScripts();
removeAllPluginScripts();
webView = null;
}
}

View File

@ -1,5 +1,8 @@
package com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview;
import static android.content.Context.INPUT_METHOD_SERVICE;
import static com.pichillilorenzo.flutter_inappwebview.types.PreferredContentModeOptionType.fromValue;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.annotation.SuppressLint;
@ -56,18 +59,13 @@ import androidx.webkit.WebViewCompat;
import androidx.webkit.WebViewFeature;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.find_interaction.FindInteractionController;
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobController;
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobManager;
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobSettings;
import com.pichillilorenzo.flutter_inappwebview.types.HitTestResult;
import com.pichillilorenzo.flutter_inappwebview.webview.JavaScriptBridgeInterface;
import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.Util;
import com.pichillilorenzo.flutter_inappwebview.content_blocker.ContentBlocker;
import com.pichillilorenzo.flutter_inappwebview.content_blocker.ContentBlockerAction;
import com.pichillilorenzo.flutter_inappwebview.content_blocker.ContentBlockerHandler;
import com.pichillilorenzo.flutter_inappwebview.content_blocker.ContentBlockerTrigger;
import com.pichillilorenzo.flutter_inappwebview.find_interaction.FindInteractionController;
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserDelegate;
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.ConsoleLogJS;
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.InterceptAjaxRequestJS;
@ -79,16 +77,20 @@ import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.OnWindowFocusE
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.PluginScriptsUtil;
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.PrintJS;
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.PromisePolyfillJS;
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobController;
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobManager;
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobSettings;
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshLayout;
import com.pichillilorenzo.flutter_inappwebview.types.ContentWorld;
import com.pichillilorenzo.flutter_inappwebview.types.DownloadStartRequest;
import com.pichillilorenzo.flutter_inappwebview.webview.ContextMenuSettings;
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewInterface;
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
import com.pichillilorenzo.flutter_inappwebview.types.PreferredContentModeOptionType;
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
import com.pichillilorenzo.flutter_inappwebview.types.UserContentController;
import com.pichillilorenzo.flutter_inappwebview.types.UserScript;
import com.pichillilorenzo.flutter_inappwebview.webview.ContextMenuSettings;
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewInterface;
import com.pichillilorenzo.flutter_inappwebview.webview.JavaScriptBridgeInterface;
import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;
import com.pichillilorenzo.flutter_inappwebview.webview.web_message.WebMessageChannel;
import com.pichillilorenzo.flutter_inappwebview.webview.web_message.WebMessageListener;
@ -99,20 +101,15 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;
import io.flutter.plugin.common.MethodChannel;
import okhttp3.OkHttpClient;
import static android.content.Context.INPUT_METHOD_SERVICE;
import static com.pichillilorenzo.flutter_inappwebview.types.PreferredContentModeOptionType.fromValue;
final public class InAppWebView extends InputAwareWebView implements InAppWebViewInterface {
protected static final String LOG_TAG = "InAppWebView";
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_";