Added WebViewFeature.DOCUMENT_START_SCRIPT Android feature support
This commit is contained in:
parent
1791b8202b
commit
80b8bde10a
|
@ -10,6 +10,7 @@
|
|||
- Added `onCameraCaptureStateChanged`, `onMicrophoneCaptureStateChanged` WebView events
|
||||
- Added support for `onPermissionRequest` event on iOS 15.0+
|
||||
- Added `debugLoggingSettings` static property for WebView and ChromeSafariBrowser
|
||||
- Added `WebViewFeature.DOCUMENT_START_SCRIPT` Android feature support
|
||||
- Updated `getMetaThemeColor` on iOS 15.0+
|
||||
- Deprecated `onLoadError` for `onReceivedError`. `onReceivedError` will be called also for subframes
|
||||
- Deprecated `onLoadHttpError` for `onReceivedError`. `onReceivedHttpError` will be called also for subframes
|
||||
|
|
|
@ -10,7 +10,8 @@ public class ConsoleLogJS {
|
|||
ConsoleLogJS.CONSOLE_LOG_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
true
|
||||
true,
|
||||
null
|
||||
);
|
||||
|
||||
public static final String CONSOLE_LOG_JS_SOURCE = "(function(console) {" +
|
||||
|
|
|
@ -12,7 +12,8 @@ public class InterceptAjaxRequestJS {
|
|||
InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
true
|
||||
true,
|
||||
null
|
||||
);
|
||||
|
||||
public static final String INTERCEPT_AJAX_REQUEST_JS_SOURCE = "(function(ajax) {" +
|
||||
|
|
|
@ -12,7 +12,8 @@ public class InterceptFetchRequestJS {
|
|||
InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
true
|
||||
true,
|
||||
null
|
||||
);
|
||||
|
||||
public static final String INTERCEPT_FETCH_REQUEST_JS_SOURCE = "(function(fetch) {" +
|
||||
|
|
|
@ -11,7 +11,8 @@ public class JavaScriptBridgeJS {
|
|||
JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
true
|
||||
true,
|
||||
null
|
||||
);
|
||||
|
||||
public static final String JAVASCRIPT_UTIL_VAR_NAME = "window." + JAVASCRIPT_BRIDGE_NAME + "._Util";
|
||||
|
|
|
@ -11,7 +11,8 @@ public class OnLoadResourceJS {
|
|||
OnLoadResourceJS.ON_LOAD_RESOURCE_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
false
|
||||
false,
|
||||
null
|
||||
);
|
||||
|
||||
public static final String ON_LOAD_RESOURCE_JS_SOURCE = "window." + FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE + " = true;" +
|
||||
|
|
|
@ -10,7 +10,8 @@ public class OnWindowBlurEventJS {
|
|||
OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
false
|
||||
false,
|
||||
null
|
||||
);
|
||||
|
||||
public static final String ON_WINDOW_BLUR_EVENT_JS_SOURCE = "(function(){" +
|
||||
|
|
|
@ -10,7 +10,8 @@ public class OnWindowFocusEventJS {
|
|||
OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
false
|
||||
false,
|
||||
null
|
||||
);
|
||||
|
||||
public static final String ON_WINDOW_FOCUS_EVENT_JS_SOURCE = "(function(){" +
|
||||
|
|
|
@ -77,7 +77,8 @@ public class PluginScriptsUtil {
|
|||
PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
false
|
||||
false,
|
||||
null
|
||||
);
|
||||
|
||||
// android Workaround to hide context menu when user emit a keydown event
|
||||
|
|
|
@ -10,7 +10,8 @@ public class PrintJS {
|
|||
PrintJS.PRINT_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
false
|
||||
false,
|
||||
null
|
||||
);
|
||||
|
||||
public static final String PRINT_JS_SOURCE = "window.print = function() {" +
|
||||
|
|
|
@ -10,7 +10,8 @@ public class PromisePolyfillJS {
|
|||
PromisePolyfillJS.PROMISE_POLYFILL_JS_SOURCE,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
true
|
||||
true,
|
||||
null
|
||||
);
|
||||
|
||||
// https://github.com/tildeio/rsvp.js
|
||||
|
|
|
@ -3,11 +3,13 @@ package com.pichillilorenzo.flutter_inappwebview.types;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class PluginScript extends UserScript {
|
||||
private boolean requiredInAllContentWorlds;
|
||||
|
||||
public PluginScript(@Nullable String groupName, @NonNull String source, @NonNull UserScriptInjectionTime injectionTime, @Nullable ContentWorld contentWorld, boolean requiredInAllContentWorlds) {
|
||||
super(groupName, source, injectionTime, contentWorld);
|
||||
public PluginScript(@Nullable String groupName, @NonNull String source, @NonNull UserScriptInjectionTime injectionTime, @Nullable ContentWorld contentWorld, boolean requiredInAllContentWorlds, @Nullable Set<String> allowedOriginRules) {
|
||||
super(groupName, source, injectionTime, contentWorld, allowedOriginRules);
|
||||
this.requiredInAllContentWorlds = requiredInAllContentWorlds;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
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;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.webkit.ScriptHandler;
|
||||
import androidx.webkit.WebViewCompat;
|
||||
import androidx.webkit.WebViewFeature;
|
||||
|
||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
|
||||
|
@ -21,7 +26,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class UserContentController {
|
||||
@SuppressLint("RestrictedApi")
|
||||
public class UserContentController implements Disposable {
|
||||
protected static final String LOG_TAG = "UserContentController";
|
||||
|
||||
@NonNull
|
||||
|
@ -29,6 +35,8 @@ public class UserContentController {
|
|||
add(ContentWorld.PAGE);
|
||||
}};
|
||||
|
||||
private final Map<UserScript, ScriptHandler> scriptHandlerMap = new HashMap<>();
|
||||
|
||||
@NonNull
|
||||
private final Map<UserScriptInjectionTime, LinkedHashSet<UserScript>> userOnlyScripts = new HashMap<UserScriptInjectionTime, LinkedHashSet<UserScript>>() {{
|
||||
put(UserScriptInjectionTime.AT_DOCUMENT_START, new LinkedHashSet<UserScript>());
|
||||
|
@ -40,7 +48,11 @@ public class UserContentController {
|
|||
put(UserScriptInjectionTime.AT_DOCUMENT_END, new LinkedHashSet<PluginScript>());
|
||||
}};
|
||||
|
||||
public UserContentController() {
|
||||
@Nullable
|
||||
public WebView webView;
|
||||
|
||||
public UserContentController(WebView webView) {
|
||||
this.webView = webView;
|
||||
}
|
||||
|
||||
public String generateWrappedCodeForDocumentStart() {
|
||||
|
@ -52,8 +64,11 @@ public class UserContentController {
|
|||
|
||||
public String generateWrappedCodeForDocumentEnd() {
|
||||
UserScriptInjectionTime injectionTime = UserScriptInjectionTime.AT_DOCUMENT_END;
|
||||
// try to reload scripts if they were not loaded during the AT_DOCUMENT_START event
|
||||
String js = generateCodeForDocumentStart();
|
||||
String js = "";
|
||||
if (!WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
|
||||
// try to reload scripts if they were not loaded during the AT_DOCUMENT_START event
|
||||
js += generateCodeForDocumentStart();
|
||||
}
|
||||
js += generatePluginScriptsCodeAt(injectionTime);
|
||||
js += generateUserOnlyScriptsCodeAt(injectionTime);
|
||||
js = USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE.replace(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, js);
|
||||
|
@ -161,6 +176,14 @@ public class UserContentController {
|
|||
if (contentWorld != null) {
|
||||
contentWorlds.add(contentWorld);
|
||||
}
|
||||
if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
|
||||
ScriptHandler scriptHandler = WebViewCompat.addDocumentStartJavaScript(
|
||||
webView,
|
||||
userOnlyScript.getSource(),
|
||||
userOnlyScript.getAllowedOriginRules()
|
||||
);
|
||||
this.scriptHandlerMap.put(userOnlyScript, scriptHandler);
|
||||
}
|
||||
return this.userOnlyScripts.get(userOnlyScript.getInjectionTime()).add(userOnlyScript);
|
||||
}
|
||||
|
||||
|
@ -171,6 +194,13 @@ public class UserContentController {
|
|||
}
|
||||
|
||||
public boolean removeUserOnlyScript(UserScript userOnlyScript) {
|
||||
if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
|
||||
ScriptHandler scriptHandler = this.scriptHandlerMap.get(userOnlyScript);
|
||||
if (scriptHandler != null) {
|
||||
scriptHandler.remove();
|
||||
this.scriptHandlerMap.remove(userOnlyScript);
|
||||
}
|
||||
}
|
||||
return this.userOnlyScripts.get(userOnlyScript.getInjectionTime()).remove(userOnlyScript);
|
||||
}
|
||||
|
||||
|
@ -180,6 +210,15 @@ public class UserContentController {
|
|||
}
|
||||
|
||||
public void removeAllUserOnlyScripts() {
|
||||
if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
|
||||
for (UserScript userOnlyScript : this.userOnlyScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START)) {
|
||||
ScriptHandler scriptHandler = this.scriptHandlerMap.get(userOnlyScript);
|
||||
if (scriptHandler != null) {
|
||||
scriptHandler.remove();
|
||||
this.scriptHandlerMap.remove(userOnlyScript);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.userOnlyScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START).clear();
|
||||
this.userOnlyScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END).clear();
|
||||
}
|
||||
|
@ -204,6 +243,14 @@ public class UserContentController {
|
|||
if (contentWorld != null) {
|
||||
contentWorlds.add(contentWorld);
|
||||
}
|
||||
if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
|
||||
ScriptHandler scriptHandler = WebViewCompat.addDocumentStartJavaScript(
|
||||
webView,
|
||||
pluginScript.getSource(),
|
||||
pluginScript.getAllowedOriginRules()
|
||||
);
|
||||
this.scriptHandlerMap.put(pluginScript, scriptHandler);
|
||||
}
|
||||
return this.pluginScripts.get(pluginScript.getInjectionTime()).add(pluginScript);
|
||||
}
|
||||
|
||||
|
@ -214,10 +261,26 @@ public class UserContentController {
|
|||
}
|
||||
|
||||
public boolean removePluginScript(PluginScript pluginScript) {
|
||||
if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
|
||||
ScriptHandler scriptHandler = this.scriptHandlerMap.get(pluginScript);
|
||||
if (scriptHandler != null) {
|
||||
scriptHandler.remove();
|
||||
this.scriptHandlerMap.remove(pluginScript);
|
||||
}
|
||||
}
|
||||
return this.pluginScripts.get(pluginScript.getInjectionTime()).remove(pluginScript);
|
||||
}
|
||||
|
||||
public void removeAllPluginScripts() {
|
||||
if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
|
||||
for (PluginScript pluginScript : this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START)) {
|
||||
ScriptHandler scriptHandler = this.scriptHandlerMap.get(pluginScript);
|
||||
if (scriptHandler != null) {
|
||||
scriptHandler.remove();
|
||||
this.scriptHandlerMap.remove(pluginScript);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START).clear();
|
||||
this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END).clear();
|
||||
}
|
||||
|
@ -353,4 +416,9 @@ public class UserContentController {
|
|||
private static final String DOCUMENT_READY_WRAPPER_JS_SOURCE = "if (document.readyState === 'interactive' || document.readyState === 'complete') { " +
|
||||
" " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE +
|
||||
"}";
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
webView = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,10 @@ package com.pichillilorenzo.flutter_inappwebview.types;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class UserScript {
|
||||
@Nullable
|
||||
|
@ -14,12 +17,19 @@ public class UserScript {
|
|||
private UserScriptInjectionTime injectionTime;
|
||||
@NonNull
|
||||
private ContentWorld contentWorld;
|
||||
@NonNull
|
||||
private Set<String> allowedOriginRules = new HashSet<>();
|
||||
|
||||
public UserScript(@Nullable String groupName, @NonNull String source, @NonNull UserScriptInjectionTime injectionTime, @Nullable ContentWorld contentWorld) {
|
||||
public UserScript(@Nullable String groupName, @NonNull String source,
|
||||
@NonNull UserScriptInjectionTime injectionTime, @Nullable ContentWorld contentWorld,
|
||||
@Nullable Set<String> allowedOriginRules) {
|
||||
this.groupName = groupName;
|
||||
this.source = source;
|
||||
this.injectionTime = injectionTime;
|
||||
this.contentWorld = contentWorld == null ? ContentWorld.PAGE : contentWorld;
|
||||
this.allowedOriginRules = allowedOriginRules == null ? new HashSet<String>() {{
|
||||
add("*");
|
||||
}} : allowedOriginRules;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -31,8 +41,9 @@ public class UserScript {
|
|||
String source = (String) map.get("source");
|
||||
UserScriptInjectionTime injectionTime = UserScriptInjectionTime.fromValue((int) map.get("injectionTime"));
|
||||
ContentWorld contentWorld = ContentWorld.fromMap((Map<String, Object>) map.get("contentWorld"));
|
||||
Set<String> allowedOriginRules = new HashSet<>((List<String>) map.get("allowedOriginRules"));
|
||||
assert source != null;
|
||||
return new UserScript(groupName, source, injectionTime, contentWorld);
|
||||
return new UserScript(groupName, source, injectionTime, contentWorld, allowedOriginRules);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -71,6 +82,15 @@ public class UserScript {
|
|||
this.contentWorld = contentWorld == null ? ContentWorld.PAGE : contentWorld;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Set<String> getAllowedOriginRules() {
|
||||
return allowedOriginRules;
|
||||
}
|
||||
|
||||
public void setAllowedOriginRules(@NonNull Set<String> allowedOriginRules) {
|
||||
this.allowedOriginRules = allowedOriginRules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -78,10 +98,12 @@ public class UserScript {
|
|||
|
||||
UserScript that = (UserScript) o;
|
||||
|
||||
if (groupName != null ? !groupName.equals(that.groupName) : that.groupName != null) return false;
|
||||
if (groupName != null ? !groupName.equals(that.groupName) : that.groupName != null)
|
||||
return false;
|
||||
if (!source.equals(that.source)) return false;
|
||||
if (injectionTime != that.injectionTime) return false;
|
||||
return contentWorld.equals(that.contentWorld);
|
||||
if (!contentWorld.equals(that.contentWorld)) return false;
|
||||
return allowedOriginRules.equals(that.allowedOriginRules);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -90,6 +112,7 @@ public class UserScript {
|
|||
result = 31 * result + source.hashCode();
|
||||
result = 31 * result + injectionTime.hashCode();
|
||||
result = 31 * result + contentWorld.hashCode();
|
||||
result = 31 * result + allowedOriginRules.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -100,6 +123,7 @@ public class UserScript {
|
|||
", source='" + source + '\'' +
|
||||
", injectionTime=" + injectionTime +
|
||||
", contentWorld=" + contentWorld +
|
||||
", allowedOriginRules=" + allowedOriginRules +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview;
|
|||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
|
@ -96,9 +97,11 @@ 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;
|
||||
|
||||
|
@ -153,7 +156,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
|
|||
public Runnable checkContextMenuShouldBeClosedTask;
|
||||
public int newCheckContextMenuShouldBeClosedTaskTask = 100; // ms
|
||||
|
||||
public UserContentController userContentController = new UserContentController();
|
||||
public UserContentController userContentController = new UserContentController(this);
|
||||
|
||||
public Map<String, ValueCallback<String>> callAsyncJavaScriptCallbacks = new HashMap<>();
|
||||
public Map<String, ValueCallback<String>> evaluateJavaScriptContentWorldCallbacks = new HashMap<>();
|
||||
|
@ -161,6 +164,8 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
|
|||
public Map<String, WebMessageChannel> webMessageChannels = new HashMap<>();
|
||||
public List<WebMessageListener> webMessageListeners = new ArrayList<>();
|
||||
|
||||
private List<UserScript> initialUserOnlyScript = new ArrayList<>();
|
||||
|
||||
public InAppWebView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
@ -185,7 +190,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
|
|||
this.windowId = windowId;
|
||||
this.customSettings = customSettings;
|
||||
this.contextMenu = contextMenu;
|
||||
this.userContentController.addUserOnlyScripts(userScripts);
|
||||
this.initialUserOnlyScript = userScripts;
|
||||
if (plugin != null && plugin.activity != null) {
|
||||
plugin.activity.registerForContextMenu(this);
|
||||
}
|
||||
|
@ -208,24 +213,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
|
|||
WebViewCompat.setWebViewRenderProcessClient(this, inAppWebViewRenderProcessClient);
|
||||
}
|
||||
|
||||
userContentController.addPluginScript(PromisePolyfillJS.PROMISE_POLYFILL_JS_PLUGIN_SCRIPT);
|
||||
userContentController.addPluginScript(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT);
|
||||
userContentController.addPluginScript(ConsoleLogJS.CONSOLE_LOG_JS_PLUGIN_SCRIPT);
|
||||
userContentController.addPluginScript(PrintJS.PRINT_JS_PLUGIN_SCRIPT);
|
||||
userContentController.addPluginScript(OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT);
|
||||
userContentController.addPluginScript(OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT);
|
||||
if (customSettings.useShouldInterceptAjaxRequest) {
|
||||
userContentController.addPluginScript(InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT);
|
||||
}
|
||||
if (customSettings.useShouldInterceptFetchRequest) {
|
||||
userContentController.addPluginScript(InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT);
|
||||
}
|
||||
if (customSettings.useOnLoadResource) {
|
||||
userContentController.addPluginScript(OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT);
|
||||
}
|
||||
if (!customSettings.useHybridComposition) {
|
||||
userContentController.addPluginScript(PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT);
|
||||
}
|
||||
prepareAndAddUserScripts();
|
||||
|
||||
if (customSettings.useOnDownloadStart)
|
||||
setDownloadListener(new DownloadStartListener());
|
||||
|
@ -504,6 +492,28 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
|
|||
});
|
||||
}
|
||||
|
||||
private void prepareAndAddUserScripts() {
|
||||
userContentController.addPluginScript(PromisePolyfillJS.PROMISE_POLYFILL_JS_PLUGIN_SCRIPT);
|
||||
userContentController.addPluginScript(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT);
|
||||
userContentController.addPluginScript(ConsoleLogJS.CONSOLE_LOG_JS_PLUGIN_SCRIPT);
|
||||
userContentController.addPluginScript(PrintJS.PRINT_JS_PLUGIN_SCRIPT);
|
||||
userContentController.addPluginScript(OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT);
|
||||
userContentController.addPluginScript(OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT);
|
||||
if (customSettings.useShouldInterceptAjaxRequest) {
|
||||
userContentController.addPluginScript(InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT);
|
||||
}
|
||||
if (customSettings.useShouldInterceptFetchRequest) {
|
||||
userContentController.addPluginScript(InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT);
|
||||
}
|
||||
if (customSettings.useOnLoadResource) {
|
||||
userContentController.addPluginScript(OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT);
|
||||
}
|
||||
if (!customSettings.useHybridComposition) {
|
||||
userContentController.addPluginScript(PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT);
|
||||
}
|
||||
this.userContentController.addUserOnlyScripts(this.initialUserOnlyScript);
|
||||
}
|
||||
|
||||
public void setIncognito(boolean enabled) {
|
||||
WebSettings settings = getSettings();
|
||||
if (enabled) {
|
||||
|
@ -1879,6 +1889,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
|
|||
|
||||
@Override
|
||||
public void dispose() {
|
||||
userContentController.dispose();
|
||||
if (windowId != null) {
|
||||
InAppWebViewChromeClient.windowWebViewMessages.remove(windowId);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
|
@ -166,15 +167,17 @@ public class InAppWebViewClient extends WebViewClient {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
public void loadCustomJavaScriptOnPageStarted(WebView view) {
|
||||
InAppWebView webView = (InAppWebView) view;
|
||||
|
||||
String source = webView.userContentController.generateWrappedCodeForDocumentStart();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webView.evaluateJavascript(source, (ValueCallback<String>) null);
|
||||
} else {
|
||||
webView.loadUrl("javascript:" + source.replaceAll("[\r\n]+", ""));
|
||||
if (!WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
|
||||
String source = webView.userContentController.generateWrappedCodeForDocumentStart();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webView.evaluateJavascript(source, (ValueCallback<String>) null);
|
||||
} else {
|
||||
webView.loadUrl("javascript:" + source.replaceAll("[\r\n]+", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -96,7 +96,8 @@ public class WebMessageListener implements Disposable {
|
|||
source,
|
||||
UserScriptInjectionTime.AT_DOCUMENT_START,
|
||||
null,
|
||||
false
|
||||
false,
|
||||
null
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -586,7 +586,7 @@ class ExchangeableObjectGenerator
|
|||
getToMapValue('$genericTypeFieldName', genericType) +
|
||||
').toList()';
|
||||
} else {
|
||||
return fieldName;
|
||||
return elementType.isDartCoreSet ? "$fieldName${(isNullable ? '?' : '')}.toList()" : fieldName;
|
||||
}
|
||||
} else if (fieldTypeElement != null && hasToMapMethod(fieldTypeElement)) {
|
||||
return fieldName +
|
||||
|
|
|
@ -6,6 +6,7 @@ import '../in_app_webview/in_app_webview_settings.dart';
|
|||
import 'proxy_controller.dart';
|
||||
import 'service_worker_controller.dart';
|
||||
import '../web_message/main.dart';
|
||||
import '../types/user_script_injection_time.dart';
|
||||
|
||||
part 'webview_feature.g.dart';
|
||||
|
||||
|
@ -187,6 +188,10 @@ class WebViewFeature_ {
|
|||
static const WEB_VIEW_RENDERER_TERMINATE =
|
||||
const WebViewFeature_._internal("WEB_VIEW_RENDERER_TERMINATE");
|
||||
|
||||
///This feature covers [UserScriptInjectionTime.AT_DOCUMENT_START].
|
||||
static const DOCUMENT_START_SCRIPT =
|
||||
const AndroidWebViewFeature_._internal("DOCUMENT_START_SCRIPT");
|
||||
|
||||
///Return whether a feature is supported at run-time. On devices running Android version `Build.VERSION_CODES.LOLLIPOP` and higher,
|
||||
///this will check whether a feature is supported, depending on the combination of the desired feature, the Android version of device,
|
||||
///and the WebView APK on the device. If running on a device with a lower API level, this will always return `false`.
|
||||
|
@ -386,6 +391,10 @@ class AndroidWebViewFeature_ {
|
|||
static const WEB_VIEW_RENDERER_TERMINATE =
|
||||
const AndroidWebViewFeature_._internal("WEB_VIEW_RENDERER_TERMINATE");
|
||||
|
||||
///This feature covers [UserScriptInjectionTime.AT_DOCUMENT_START].
|
||||
static const DOCUMENT_START_SCRIPT =
|
||||
const AndroidWebViewFeature_._internal("DOCUMENT_START_SCRIPT");
|
||||
|
||||
///Return whether a feature is supported at run-time. On devices running Android version `Build.VERSION_CODES.LOLLIPOP` and higher,
|
||||
///this will check whether a feature is supported, depending on the combination of the desired feature, the Android version of device,
|
||||
///and the WebView APK on the device. If running on a device with a lower API level, this will always return `false`.
|
||||
|
|
|
@ -189,6 +189,10 @@ class WebViewFeature {
|
|||
static const WEB_VIEW_RENDERER_TERMINATE = WebViewFeature._internal(
|
||||
'WEB_VIEW_RENDERER_TERMINATE', 'WEB_VIEW_RENDERER_TERMINATE');
|
||||
|
||||
///This feature covers [UserScriptInjectionTime.AT_DOCUMENT_START].
|
||||
static const DOCUMENT_START_SCRIPT = WebViewFeature._internal(
|
||||
'DOCUMENT_START_SCRIPT', 'DOCUMENT_START_SCRIPT');
|
||||
|
||||
///Set of all values of [WebViewFeature].
|
||||
static final Set<WebViewFeature> values = [
|
||||
WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL,
|
||||
|
@ -232,6 +236,7 @@ class WebViewFeature {
|
|||
WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT,
|
||||
WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE,
|
||||
WebViewFeature.WEB_VIEW_RENDERER_TERMINATE,
|
||||
WebViewFeature.DOCUMENT_START_SCRIPT,
|
||||
].toSet();
|
||||
|
||||
///Gets a possible [WebViewFeature] instance from [String] value.
|
||||
|
@ -479,6 +484,10 @@ class AndroidWebViewFeature {
|
|||
static const WEB_VIEW_RENDERER_TERMINATE = AndroidWebViewFeature._internal(
|
||||
'WEB_VIEW_RENDERER_TERMINATE', 'WEB_VIEW_RENDERER_TERMINATE');
|
||||
|
||||
///This feature covers [UserScriptInjectionTime.AT_DOCUMENT_START].
|
||||
static const DOCUMENT_START_SCRIPT = AndroidWebViewFeature._internal(
|
||||
'DOCUMENT_START_SCRIPT', 'DOCUMENT_START_SCRIPT');
|
||||
|
||||
///Set of all values of [AndroidWebViewFeature].
|
||||
static final Set<AndroidWebViewFeature> values = [
|
||||
AndroidWebViewFeature.CREATE_WEB_MESSAGE_CHANNEL,
|
||||
|
@ -522,6 +531,7 @@ class AndroidWebViewFeature {
|
|||
AndroidWebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT,
|
||||
AndroidWebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE,
|
||||
AndroidWebViewFeature.WEB_VIEW_RENDERER_TERMINATE,
|
||||
AndroidWebViewFeature.DOCUMENT_START_SCRIPT,
|
||||
].toSet();
|
||||
|
||||
///Gets a possible [AndroidWebViewFeature] instance from [String] value.
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i
|
|||
import '../in_app_webview/webview.dart';
|
||||
import 'user_script_injection_time.dart';
|
||||
import 'content_world.dart';
|
||||
import '../android/webview_feature.dart';
|
||||
|
||||
part 'user_script.g.dart';
|
||||
|
||||
|
@ -29,6 +30,11 @@ class UserScript_ {
|
|||
///**NOTE**: available only on iOS.
|
||||
bool forMainFrameOnly;
|
||||
|
||||
///A set of matching rules for the allowed origins.
|
||||
///
|
||||
///**NOTE**: available only on Android and only if [WebViewFeature.DOCUMENT_START_SCRIPT] feature is supported.
|
||||
late Set<String> allowedOriginRules;
|
||||
|
||||
///A scope of execution in which to evaluate the script to prevent conflicts between different scripts.
|
||||
///For more information about content worlds, see [ContentWorld].
|
||||
late ContentWorld contentWorld;
|
||||
|
@ -40,7 +46,10 @@ class UserScript_ {
|
|||
required this.injectionTime,
|
||||
@Deprecated("Use forMainFrameOnly instead") this.iosForMainFrameOnly,
|
||||
this.forMainFrameOnly = true,
|
||||
Set<String>? allowedOriginRules,
|
||||
ContentWorld? contentWorld}) {
|
||||
this.allowedOriginRules = allowedOriginRules != null ?
|
||||
allowedOriginRules : Set.from(["*"]);
|
||||
this.contentWorld = contentWorld ?? ContentWorld.PAGE;
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
this.forMainFrameOnly = this.iosForMainFrameOnly != null
|
||||
|
|
|
@ -28,6 +28,11 @@ class UserScript {
|
|||
///**NOTE**: available only on iOS.
|
||||
bool forMainFrameOnly;
|
||||
|
||||
///A set of matching rules for the allowed origins.
|
||||
///
|
||||
///**NOTE**: available only on Android and only if [WebViewFeature.DOCUMENT_START_SCRIPT] feature is supported.
|
||||
late Set<String> allowedOriginRules;
|
||||
|
||||
///A scope of execution in which to evaluate the script to prevent conflicts between different scripts.
|
||||
///For more information about content worlds, see [ContentWorld].
|
||||
late ContentWorld contentWorld;
|
||||
|
@ -37,7 +42,10 @@ class UserScript {
|
|||
required this.injectionTime,
|
||||
@Deprecated("Use forMainFrameOnly instead") this.iosForMainFrameOnly,
|
||||
this.forMainFrameOnly = true,
|
||||
Set<String>? allowedOriginRules,
|
||||
ContentWorld? contentWorld}) {
|
||||
this.allowedOriginRules =
|
||||
allowedOriginRules != null ? allowedOriginRules : Set.from(["*"]);
|
||||
this.contentWorld = contentWorld ?? ContentWorld.PAGE;
|
||||
this.forMainFrameOnly = this.iosForMainFrameOnly != null
|
||||
? this.iosForMainFrameOnly!
|
||||
|
@ -57,6 +65,7 @@ class UserScript {
|
|||
iosForMainFrameOnly: map['forMainFrameOnly'],
|
||||
);
|
||||
instance.forMainFrameOnly = map['forMainFrameOnly'];
|
||||
instance.allowedOriginRules = map['allowedOriginRules'].cast<String>();
|
||||
instance.contentWorld = map['contentWorld'];
|
||||
return instance;
|
||||
}
|
||||
|
@ -68,6 +77,7 @@ class UserScript {
|
|||
"source": source,
|
||||
"injectionTime": injectionTime.toNativeValue(),
|
||||
"forMainFrameOnly": forMainFrameOnly,
|
||||
"allowedOriginRules": allowedOriginRules.toList(),
|
||||
"contentWorld": contentWorld.toMap(),
|
||||
};
|
||||
}
|
||||
|
@ -79,6 +89,6 @@ class UserScript {
|
|||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UserScript{groupName: $groupName, source: $source, injectionTime: $injectionTime, forMainFrameOnly: $forMainFrameOnly, contentWorld: $contentWorld}';
|
||||
return 'UserScript{groupName: $groupName, source: $source, injectionTime: $injectionTime, forMainFrameOnly: $forMainFrameOnly, allowedOriginRules: $allowedOriginRules, contentWorld: $contentWorld}';
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue