-
Notifications
You must be signed in to change notification settings - Fork 2.9k
History Restoration in WKWebView (and Error Pages)
WKWebView has no native API to restore history in the web view.
History is restored by using injected JS, the sessionrestore.html
file in the bundle.
Overview:
- Tab history is queried from the
WKWebView.backForwardList
and stored on disk, along with the current position in the list. - On tab restore,
sessionrestore.html
is loaded, and arguments are passed to the page with the list of history URLs, and the current position -
sessionrestore.html
performswindow.history.pushState()
for each URL in the history, then sets the current position in the history usingwindow.history.go()
.
- WKURLScheme is used to provide single-origin URLs for manipulating
window.history
. The scheme and domain used isinternal://local/
; the same-origin-restricted JS APIs we use are satisfied by that root URL. -
internal://local/sessionrestore?history=<list of URLs and current index>
is the first URL loaded in a tab. Thehistory
param is parsed, and each item is pushed using an URL format ofinternal://local/sessionrestore?url=<actual URL>
to populate the browser history. - The
sessionrestore.html
is loaded usingWKWebView.load(request)
, and theload
API creates an entry on the history stack for the webview. Thus, the current page has to be replaced in-place to avoid further modifying the stack. This is done withlocation.replace(<actual URL>)
in JS. - Location replace also has to happen when going back/forward in the history, these urls will appear as
internal://local/sessionrestore?url=<actual URL>
. The WKURLScheme handler will load a placeholder page in the web view first, then replace the location to the actual URL. This appears to be the only method of redirection using WKURLScheme (and related) API.
- Not mentioned above is that internal:// URLs have a
uuidkey=<a uuid>
URL parameter. The UUID is generated once at app start, and internal history URLs must have a validuuidkey
param to be loaded. This ensures only the native history restoration can push these URLs.
WKWebView delegate didFailProvisionalNavigation
will be called when a page fails to load.
Note that the webview history will be unchanged at this point.
To provide a history entry for showing the error page in-content, WKWebView.load(request)
is used to load a HTML page which will show the internal error page; different HTML is shown depending on the type of error.
The error page urls are of the format internal://local/errorpage?<many params>
with URL parameters providing the original URL and details of the error.
The error page (i.e. the page with the URL internal://local/errorpage?...
) acts a placeholder in the history for back/forward navigation, and for history restoration. If the original page needs to be loaded, the original URL is extracted from the error page and is loaded in-place with location.replace
(any equivalent JS is acceptable that avoids doing a WKWebView.load
and blowing away the forward history).
To ensure only the app can request these, they are secured with the uuidkey
URL param as above.