Thursday, December 9, 2021


Tags

Ohanaware site icon

WKWebKit, Xojo HTMLViewer and the App Sandbox

Like Inception - Its a Sandbox within a Sandbox.

Thursday, December 9, 2021 - Sam Rowlands



It appears to me that WKWebView uses its own Sandbox that is nested within the App Sandbox, Sandbox. As I haven't shipped any new apps on the Mac App Store that use the HTMLViewer (WKWebView) I've not noticed this, however in replacing the help viewer with our own to overcome bugs in Apple's Help Viewer, I needed to make it work, below is how I accomplished that.

  1. Decree a 'root' folder that is the base most folder, yet includes all the subfolders that the HTML content is going to access to load its resources.
  2. Make sure that the application has 'access' to this 'root' folder. If the app can't access the folder or it's content, neither can the HTMLViewer.
  3. Copy and Paste the below functions in a module within Xojo and use these functions to display content as they provide the ability to pass through the 'root' folder to the underlying WKWebView.
  4. There's a bug in iOS 12 (therefore the macOS also) whereby App Sandbox applications cannot display local HTML content until the "Client" entitlement is added to the application (giving the application access to the internet).

    App Wrapper 4.4 Alpha 4 or newer includes an auto-entitlement add for the Xojo HTMLViewer and App Sandbox. A pre-release version is available from https://ohanaware.com/appwrapper/prerelease.html

Existing HTML files on the disk

Public Sub loadPageWithAccessToFolder(extends h as HTMLViewer, inPage as folderItem, inRootFoolder as folderItem) #if targetMacOS and XojoVersion >= 2020.01 then // --- Originally created in July 2020. <--- Leave this info here so it's easier to track which version of the code. // First published Sep 1st 2020. // Updated Dec 9th 2021. // written by Sam Rowlands of Ohanaware.com // Apple documentation for this API: // https://developer.apple.com/documentation/webkit/wkwebview/1414973-loadfileurl?language=objc declare function NSClassFromString lib

"Foundation"

( inClassName as CFStringRef ) as integer declare Function NSURL_fileURLWithPathIsDirectory lib

"Foundation"

selector

"fileURLWithPath:isDirectory:"

( NSURLClass as integer, path as CFStringRef, directory as boolean) as integer declare function WKWebView_loadFileURL lib

"WebKit"

selector

"loadFileURL:allowingReadAccessToURL:"

( WKWebViewInstance as integer, URL as integer, readAccessURL as integer ) as integer dim NSURLClass as integer = NSClassFromString(

"NSURL"

) dim pageULR as integer = NSURL_fileURLWithPathIsDirectory( NSURLClass, inPage.nativePath, inPage.directory ) dim folderURL as integer = NSURL_fileURLWithPathIsDirectory( NSURLClass, inRootFoolder.nativePath, inRootFoolder.directory ) // --- Now that we have our page and folder, fire away! dim result as integer = WKWebView_loadFileURL( h.handle, pageULR, folderURL ) #else h.loadPage inPage #EndIf End Sub

Which is then used like below, with the folderitem 'book' being my root folder, failing that it uses the folder 'localizedContent' instead.

// HTMLViewer1.loadpage f HTMLViewer1.loadPageWithAccessToFolder f, if( book <> nil, book, localizedContent )

Dynamically Generated HTML

Public Sub loadHTMLStringWithAccessToFolder(extends h as HTMLViewer, inHTMLContent as string, inRootFoolder as folderItem) #if targetMacOS and XojoVersion >= 2020.01 then // --- Originally created Dec 9th 2020. <--- Leave this info here so it's easier to track which version of the code. // written by Sam Rowlands of Ohanaware.com // Apple documentation for this API: // https://developer.apple.com/documentation/webkit/wkwebview/1415004-loadhtmlstring?language=objc declare function NSClassFromString lib

"Foundation"

( inClassName as CFStringRef ) as integer declare Function NSURL_fileURLWithPathIsDirectory lib

"Foundation"

selector

"fileURLWithPath:isDirectory:"

( NSURLClass as integer, path as CFStringRef, directory as boolean) as integer declare function WKWebView_loadHTMLString lib

"WebKit"

selector

"loadHTMLString:baseURL:"

( WKWebViewInstance as integer, inString as CFStringRef, baseURL as integer ) as integer // --- Now that we have our page and folder, fire away! dim result as integer = WKWebView_loadHTMLString( h.handle, _ inHTMLContent, _ NSURL_fileURLWithPathIsDirectory( NSClassFromString(

"NSURL"

), _ inRootFoolder.nativePath, inRootFoolder.directory ) ) #else h.loadPage inHTMLContent, inRootFoolder.childAt( 0 ) #EndIf End Sub

Which is then used like below, with the folderitem 'inLocation' being my root folder.

// HTMLViewer1.loadPage pageHTML, inlocation.child( "test.html" ) HTMLViewer1.loadHTMLStringWithAccessToFolder pageHTML, inLocation