Sandboxing issue: HTMLViewer and sandbox

Thanks a lot anyway, it was nice of you trying to help.

1 Like

I know very little about this

But

Try to compile with Xojo 2018 R2, if it works your issue is http:// vs https://
This version allows both, after only https://.

Make sure my Help Viewer works in the App Sandbox.

My first test was to the Sandbox the development project for the HelpViewer.

It uses a HTMLViewer to display the contents of an Apple compatible help book. Without any changes this works, so it is able to read and display static HTML content from the Application’s Resources folder.

When a user searches the help book, it dynamically generates a HTML page and uses the following line.

HTMLViewer1.loadPage page, _
new folderItem( localizedContent.nativePath + "/" + indexPageName, folderItem.pathModes.native, true )

Like I mentioned earlier, it uses an existing page as the base, I found the search didn’t work with a non-existent file.

Next, I’ll try to load pages from outside of my application.

Outside of the application bundle, things change.

By dragging the Apple help book into the application, this gives the application permission to access the content of the helpbook, however the HTMLViewer can only display HTML, images and CSS are lost.

My previous solution doesn’t appear to work in this case either.

However reading the notes I made, I see I was misusing the function, it isn’t designed to compliment the Xojo function, it’s designed to replace it.

Once modified and used correctly, instead of HTMLviewer1.loadPage <folderitem/> things appear to be working as expected. The second parameter is the root folder for all the HTML content that your application needs to display, your application MUST have access to this folder in order for it to work.

if anchorName <> "" then anchorToShow = anchorName

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

Note: book is the root folder, while localizedContent is the specific language folder.

Modified routine below.

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

When using this method my dynamically generated search pages also work, however they’re not loading and css or images, so that’s what I will test next.

1 Like

Lastly…

I modified the dynamically generated content to load a custom CSS (if present in the Help book) and it works, when the content is within the Application Resources folder or when the help book is dragged into the application (and I am assuming that I’ve loaded the first “home” page via the above mentioned function.

So what about content that’s generated without calling the above function, after all that’s the problem.

Dynamic content

For this test I split the CSS from a generated page (so two constants, pageHTML and testCSS.
I then made a method that took a folder and did the following.

Public Sub testLocation(inLocation as folderItem)
  Dim cssFile as folderItem   = inLocation.child( "test.css" )
  Dim tos as textoutputStream = textOutputStream.create( cssfile )
  tos.write testCSS
  tos.close
  
  HTMLViewer1.loadPage pageHTML, inlocation.child( "test.html" )
End Sub

inLocation = specialFolder.temporary

  • HTMLViewer1.loadPage( pageHTML, inlocation ) - Fails, error saying it needs to be a file.
  • HTMLViewer1.loadPage( pageHTML, inlocation.child( "test.html" ) ) - Fails, doesn’t load css.
  • HTMLViewer1.loadPage( pageHTML, cssFile ) - Works.

When looking at the Apple API, it doesn’t mention anything about having to use an existing file, so I translated the API and lo, I can simply pass a folder.

  • HTMLViewer1.loadHTMLStringWithAccessToFolder( pageHTML, inLocation ) - Works.

I’ve been able to display file based and dynamically generated HTML (with css and images) from a Sandboxed application. I found using the loadPageWithAccessToFolder function I created to be most reliable with existing content, while the loadHTMLStringWithAccessToFolder is more inline with this new function as I can pass it a folder that contains the resources.

Which now raises the question, whats the difference between this code and within your application?

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
1 Like

Even in a Sandboxed app the NSAllowsArbitraryLoads plist entry is enough to load html. The second argument for LoadPage can be nil. Please check that you use the correct plist entry.

Otherwise, my app would be dead.

1 Like

In summary…

  1. The application must have access to a root location where HTML resources will be loaded from and this folder must be passed through to the underlying WKWebView in order for it to have access to said resources.
  2. Xojo’s loadPage <folderitem> function does not appear to allow us to pass in a “root” folder for granting access to the page’s resources.
  3. Xojo’s loadPage <htmlcontent>, <folderitem> function does not appear to allow us to pass in a “root” folder for granting access to the page’s resources.
  4. No plist keys were harmed or used in the process.

Are you sure you mean the plist key “NSAllowsArbitraryLoads”…
https://developer.apple.com/documentation/bundleresources/information_property_list/nsapptransportsecurity/nsallowsarbitraryloads?language=objc

Documentation indicates this allows for HTTP access, not just HTTPS.

Is your application App Sandboxed?

Edit: I have tested this with the sample App Sandbox application, I reverted to pure Xojo functions, while having this key present in the plist and it didn’t help.

Sam, thank you a lot for the detailed description, you are really great.
But I must be doing something wrong, I tried to to do as you described and it does not work for me in the sandboxed application, HTMLViewer does not display anything (in the not sandboxed appplication it works). I tried both loadPageWithAccessToFolder and loadHTMLStringWithAccessToFolder. Here are both test applications (sandboxed and not sandboxed) and the source code: http://www.macmedianet.com/HTMLViewer.zip

Yes, I meant the key NSAllowsArbitraryLoadsInWebContent.
Yes, my application is sandboxed.

So, it works for me in the Xojo IDE (using App Wrapper to code sign the application).

However, the built application (also signed by App Wrapper) does not work.

Well… That was surprising…

I found an error message in bowels of the system and Googled for it.

In iOS 12 Apple made a change to WKWebView, which means it requires the entitlement to access the internet, even if it’s only displaying local content. I added the key (because macOS is now a sub OS of iOS) and lol, the compiled application can now also display local HTML content.

Screen Shot 2021-12-10 at 10.27.18 AM

That is 100% odd and IMHO most likely a bug in Monterey.

1 Like

I’m running BigSur, yet, like @Peter Koren, the sandboxed app does not show anything (even applying loadPageWithAccessToFolder and loadHTMLStringWithAccessToFolder.

So if it is a bug, it affects also BS.

On the other end, the Help files (loaded in AppWrapper) show the text but not the icons.

That’s sad.

Are you running the pre-release of App Wrapper 4.4? App Wrapper 4 - Prereleases

Not downloaded yet. I’ll try tomorrow and see what happens.

This is the version that contains my “new” Help Viewer to replace the broken Apple one on Monterey.

Fine. I’ll test and let you know.
Thanks.

Thanks

I snuck in a auto-entitlement into this weeks pre-release of App Wrapper, which will auto add the correct entitlement if App Wrapper finds the Xojo HTMLViewer and is wrapping a Sandboxed application.

https://ohanaware.com/appwrapper/prerelease.html

Sam, you are super… Thanks a lot… After adding the entitlement (required even for the local content - strange bug) HTMLViewer displays content correctly in the sandboxed application.

2 Likes