You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Xamarin Android中通过C#在Document Start阶段注入JavaScript

Fixing Android WebView JS Injection Timing to Avoid Ad Flash

I get it—porting from Xamarin.iOS to Xamarin.Android can feel like navigating a whole new ecosystem, especially when WebView behaviors don't line up perfectly. The core issue here is that Android doesn't have a direct equivalent to iOS's WKUserScriptInjectionTime.AtDocumentStart, but we can work around it to get your ad-hiding JS running early enough to eliminate that flash.

Here's the Plan

We'll adjust two key parts:

  1. Tweak your JS to run at the earliest possible DOM-ready moment
  2. Update your Android WebView code to inject the JS much earlier than OnPageFinished

Step 1: Refine the JavaScript

Wrap your ad-hiding logic to handle different DOM states, so it works whether injected early or slightly later:

(function() {
    function hideAppStoreAds() {
        var styleTag = document.createElement("style");
        styleTag.textContent = '.mobile-apps {display:none;}';
        document.documentElement.appendChild(styleTag);
    }

    // Run immediately if DOM is already ready; wait for DOMContentLoaded if not
    if (document.readyState === "complete" || document.readyState === "interactive") {
        hideAppStoreAds();
    } else {
        document.addEventListener("DOMContentLoaded", hideAppStoreAds);
    }
})();

Step 2: Update the Android WebView Code

We'll use OnPageCommitVisible (for Android 7.0+) to inject JS right before the page renders, with a fallback to OnPageStarted for older versions. This mimics iOS's early injection behavior as closely as possible.

First, update the JavascriptWebViewClient:

public class JavascriptWebViewClient : WebViewClient
{
    private readonly string _javascript;

    public JavascriptWebViewClient(string javascript)
    {
        _javascript = javascript;
    }

    // Android 7.0+ (API 24): Inject right before page content becomes visible
    public override void OnPageCommitVisible(WebView view, string url)
    {
        base.OnPageCommitVisible(view, url);
        InjectJavascript(view);
    }

    // Fallback for older Android versions: Inject as soon as page starts loading
    public override void OnPageStarted(WebView view, string url, Bitmap favicon)
    {
        base.OnPageStarted(view, url, favicon);
        if (Build.VERSION.SdkInt < BuildVersionCodes.N)
        {
            InjectJavascript(view);
        }
    }

    private void InjectJavascript(WebView view)
    {
        if (!string.IsNullOrEmpty(_javascript))
        {
            view.EvaluateJavascript($"({_javascript})();", null);
        }
    }

    // Optional: Keep this as a safety net if early injection fails for some reason
    public override void OnPageFinished(WebView view, string url)
    {
        base.OnPageFinished(view, url);
        // InjectJavascript(view);
    }
}

Then update the PortalViewRenderer to enable critical WebView settings and clean up the initialization:

public class PortalViewRenderer : ViewRenderer<PortalView, Android.Webkit.WebView>
{
    private readonly Context _context;

    public PortalViewRenderer(Context context) : base(context)
    {
        _context = context;
    }

    protected override void OnElementChanged(ElementChangedEventArgs<PortalView> e)
    {
        base.OnElementChanged(e);

        string javascriptFunction = null;
        // Load the JS file from assets
        using (var sr = new StreamReader(_context.Assets.Open("Common/HideAppStoreAds.js")))
        {
            javascriptFunction = sr.ReadToEnd();
        }

        if (Control == null)
        {
            var webView = new Android.Webkit.WebView(_context);
            var settings = webView.Settings;

            // Enable essential WebView features
            settings.JavaScriptEnabled = true;
            settings.DomStorageEnabled = true; // Ensures DOM operations work reliably
            settings.UserAgentString = "headbanger.davylamp.android"; // Match iOS user agent if needed
            settings.SetSupportZoom(false);
            settings.BuiltInZoomControls = false;

            // Match your iOS background color
            webView.SetBackgroundColor(Android.Graphics.Color.Argb(255, 0x11, 0x25, 0x43));

            // Attach our custom WebViewClient for early JS injection
            webView.SetWebViewClient(new JavascriptWebViewClient(javascriptFunction));

            SetNativeControl(webView);
        }

        if (e.OldElement != null)
        {
            Control.RemoveJavascriptInterface("jsBridge");
            var portalView = e.OldElement as PortalView;
            portalView?.Cleanup();
        }

        if (e.NewElement != null)
        {
            Control.LoadUrl(Element.Uri);
        }
    }
}

Why This Works

  • OnPageCommitVisible triggers right before the page renders (Android 7.0+), so your CSS is applied before the ad elements can be displayed.
  • For older Android versions, OnPageStarted injects the JS early, and our refined JS waits for the DOM to be ready if needed.
  • Enabling DomStorageEnabled ensures your JS can interact with the DOM reliably, avoiding silent failures.

If you still see a tiny flash, try enabling hardware acceleration for the WebView with webView.SetLayerType(Android.Views.LayerType.Hardware, null)—this can speed up rendering and eliminate the last traces of the flash.

内容的提问来源于stack exchange,提问作者headbanger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:06:21