13

I want to set local storage before making request to WKWebView is that possible in any iOS version?

Can't find a way to do it, the only class seem to relevant is WKWebsiteDataStore https://developer.apple.com/documentation/webkit/wkwebsitedatastore which only have method to read and delete.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
sarunw
  • 8,036
  • 11
  • 48
  • 84
  • Does the value need to be set in local storage before the page is loaded? In that case, you could load an empty web view, implement the navigation delegate, and in `didFinishLoad` callback, inject a line of JavaScript setting your value in local storage. Now, load the page you originally wished to load. – paulvs Jul 04 '17 at 04:17
  • Yes, it use to determine the language of the page. – sarunw Jul 05 '17 at 04:26

2 Answers2

21

From @paulvs comment here is what I do.

Set navigation delegate to listen to finished callback.

webView.navigationDelegate = self

Then in the callback, check for value in localStorage and set if needed.

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {

    webView.evaluateJavaScript("localStorage.getItem(\"key\")") { (result, error) in

        // check if result is what I want
        // if it is what I want, do nothing
        // if not set it
        webView.evaluateJavaScript("localStorage.setItem(\"key\", \"value\")") { (result, error) in

            webView.reload()

        }            
    }
}
sarunw
  • 8,036
  • 11
  • 48
  • 84
  • 11
    This work after the `WKWebView` has been loaded once, right? What if, I want to set the local storage item before making the very first request on `viewDidLoad`? – Vaibhav Jhaveri Aug 09 '18 at 10:25
  • How to set multiple key and values in local storage – Prateek kumar Mar 26 '19 at 11:36
  • @Prateekkumar I assume that you just need to separate them with semicolons inside the Javascript like they were more than one line – Julio Bailon Oct 04 '19 at 19:38
  • @VaibhavJhaveri did you solved your problem? I have the same issue. I do not want the `WKWebView` to first load and then reload. I need to set the local storage before first request of the `WKWebView`. – Neneil Jul 05 '20 at 16:41
  • 2
    Koshub's answer (https://stackoverflow.com/a/63485081/178280) should be the accepted one, its more elegant than reloading the webview. – grassyburrito Nov 30 '20 at 11:25
7

You do not need to reload the page - just inject the local storage data using WKUserScript at .atDocumentStart

// Restore local storage

// Instantiate the configuration before instantiating `WKWebView`

let configuration = WKWebViewConfiguration()

// Clear existed local storage just after document element is created

let script = WKUserScript(
    source: "window.localStorage.clear();",
    injectionTime: .atDocumentStart,
    forMainFrameOnly: true
)
configuration.userContentController.addUserScript(script)

// Preare your local storage data

let localStorageData: [AnyHashable : Any] = [:]

if JSONSerialization.isValidJSONObject(localStorageData),
    let data = try? JSONSerialization.data(withJSONObject: localStorageData, options: []),
    let value = String(data: data, encoding: .utf8) {
    // Inject valid local storage data just after document element is created
    let script = WKUserScript(
        source: "Object.assign(window.localStorage, \(value));",
        injectionTime: .atDocumentStart,
        forMainFrameOnly: true
    )
    configuration.userContentController.addUserScript(script)
}

// Instantiate WebView with the configuration

let webView = WKWebView(frame: .zero, configuration: configuration)
        
// Later you may save the updated local storage
webView.evaluateJavaScript("Object.assign({}, window.localStorage);") { (result, error) in
    // let updatedlocalStorageData = (result as? [AnyHashable : Any]) ?? [:]
}
Koshub
  • 131
  • 1
  • 4