如何在Xamarin Android中通过C#在Document Start阶段注入JavaScript
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:
- Tweak your JS to run at the earliest possible DOM-ready moment
- 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
OnPageCommitVisibletriggers right before the page renders (Android 7.0+), so your CSS is applied before the ad elements can be displayed.- For older Android versions,
OnPageStartedinjects the JS early, and our refined JS waits for the DOM to be ready if needed. - Enabling
DomStorageEnabledensures 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

