如何在WKWebView中注入多份用户脚本以实现暗黑模式效果?
Let's break down your problem and fix it step by step:
First, a Key Clarification
You mentioned you don't see the injected scripts in the HTML source printed by chechHTML() — this is normal behavior. WKUserScript injects scripts directly into the WebKit JavaScript runtime, not by modifying the original HTML document structure. So using document.documentElement.outerHTML will never show these injected scripts, even if they're working correctly. That's not the root of your issue.
Step 1: Verify Your Local JS Files Are Loaded Correctly
First, make sure you're actually reading the full content of darkmode.min.js and darkmode-options.js into your jsLibrary and jsOptions variables. Add debug prints right before creating the user scripts to confirm:
print("Loaded darkmode library content:\n", jsLibrary) print("Loaded darkmode options content:\n", jsOptions)
- If the output is empty or truncated, check that the JS files are added to your Xcode project and their Target Membership is enabled for your app target.
- Ensure your file reading code (where you populate
darkModeLibraryJSanddarkModeOptionsJS) doesn't have errors (e.g., incorrect file paths).
Step 2: Adjust Script Execution Timing & Logic
Your injection timing (atDocumentStart for the library, atDocumentEnd for options) is correct, but you need to ensure the options script runs only after the DOM is ready (and the Darkmode class is fully available).
If your darkmode-options.js has code like this (immediate execution):
const darkmodeOptions = { bottom: "32px", right: "32px", label: "🌓" }; const darkmode = new Darkmode(darkmodeOptions); darkmode.showWidget();
Wrap it in a DOMContentLoaded listener to guarantee it runs after the DOM is built:
document.addEventListener("DOMContentLoaded", function() { const darkmodeOptions = { bottom: "32px", right: "32px", label: "🌓" }; const darkmode = new Darkmode(darkmodeOptions); darkmode.showWidget(); });
This matches how your working darkmode.html likely loads the scripts (waiting for the page to be ready before initializing the widget).
Step 3: Verify Scripts Are Actually Injecting & Working
Instead of checking the HTML source, validate the JavaScript environment directly. Update your didFinish navigation method to test if Darkmode is available:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { // Check if Darkmode library exists webView.evaluateJavaScript("typeof Darkmode !== 'undefined'") { (result, error) in if let exists = result as? Bool, exists { print("✅ Darkmode library loaded successfully!") // Try initializing the widget webView.evaluateJavaScript("new Darkmode({bottom: '32px', right: '32px'}).showWidget()") { (_, initError) in if let initError = initError { print("❌ Failed to initialize Darkmode widget:", initError.localizedDescription) } else { print("✅ Darkmode widget is active!") } } } else { print("❌ Darkmode library is NOT loaded. Check your script injection.") } } // self.chechHTML() // This won't show injected scripts, so you can remove it }
Step 4: Fix the loadHTMLString Base URL
When using loadHTMLString(_:baseURL:) with baseURL: nil, WebKit treats the document as "originless", which can break features like localStorage (if the Darkmode library relies on it). Set a valid base URL using your app's bundle:
let baseURL = Bundle.main.bundleURL self.webview!.loadHTMLString(html, baseURL: baseURL)
Step 5: Cross-Reference Your Working darkmode.html
Compare the script content in your working HTML file to the content you're injecting. Ensure:
- The injected
darkmode.min.jsis identical to the one referenced indarkmode.html - The options logic in
darkmode-options.jsmatches the initialization code in the working HTML (no typos or missing configs)
内容的提问来源于stack exchange,提问作者Cristi Ghinea

