A little background
Having built a few HTML spikes of Maavis features we satisfied ourselves that it is now perfectly feasible to replace the old XUL version with a mixture of HTML5, W3C widgets and a thin native code wrapper to provide access to platform features not yet available in the browser sandbox. Going for HTML has many advantages, including portability now, good future deployment options, and a potentially large community, something that is vital for a successful open development project.
And then, the Windows 8 release landed and we decide to seriously look at it as the first platform we targeted. I won’t go into all the reasons for this but it’s interesting to note that the simplified touch interface style that is a key feature of the Maavis UI has now appeared in consumer platforms, including Windows 8.
So we spent an OpenDirective week off-site hacking and exploring how we might implement features in HTML running in a Windows App Store app native wrapper. In other words we want the core application to be HTML code that will run on other platforms without change (AKA a hybrid app). I picked access to local image files which would be pretty straight forward, or so I thought.
At this point I became painfully aware that the MSDN documentation, my preferred first port of call, was early release and the quality was simply not what I was used to from previous experience. I spent many years delving into Win32 program and system development from the days of Windows 3.1 (well actually “Windows for Work Groups”) until Vista arrived. This had accustomed me to the excellent API documentation and articles that formed part of Microsoft’s formidable developer evangelism efforts. MSDN magazine, then later a handful of CDs, and then a huge raft of DVDs, contained all tools and information you could ever want as a developer. As time passed Code Project became a “go to”community resource and it’s good to still see it is still going strong (don’t miss their Azure competition).
At this point in time, however, while APIs were clearly defined by the objects, methods and properties, critical conceptual information providing context and defining the models just wasn’t there. Sure you can often work out the map of the forest from a study of all the trees but that leaves a lot of unknown ‘there be dragons’ areas, even after much trial and error. A couple of 3rd party blog posts gave vital clues but still with many gaps, caused largely by their being written for the preview releases of Windows 8. Plus heavy weight solutions like having a local webserver exclude running on Windows RT, and the background processing possibilities are restricted in App Store Apps.
To reiterate, the problem to be solved is to display an image in HTML in a web context iFrame where the image is a file in the “My Pictures” library on the local file system.
We need a URI referencing the image for src attribute of an image tag/element and while it could theoretically be defined declaratively in the HTML or set programatically by setting the src attribute, I’ll stick to the latter as that is more much flexible in terms of possible solutions, as well see.
WinRT provides a set of URI protocols for accessing resources in various locations (the protocol is the http: part of a web URI). However, the restrictions we hit in the App web context are:
- The file: protocol is completely blocked. This is the usual way to access local resources from HTML.
- There is no protocol for accessing the libraries like My Pictures. ms-appx: and ms-appx-web access content in the app package, while ms-appdata: looks in the app data storage area.
- While files in library locations can be programmatically accessed from the local context and accessed by dynamically created blob: URLs to be referenced in the HTML, such references are blocked from within the web context. This is no doubt due to cross domain restriction requirements.
But wait, the solution could be to use a local context iframe containing the image element that is nested inside the web context HTML. The nested local context will then be able to use the blob URI in an image element src attribute to access the image file. Result.
Except, that isn’t allowed either. Sigh.
But wait, the WinRT MSApp method addPublicLocalApplicationUri looks very interesting. It “exposes the provided local context URIs to arbitrary untrusted web content”. In other words we might be able to use it to allow a local context iframe to be embedded in a web context iframe.
And you know what? It works. In fact I subsequently found this solution is described at the end of a long runtime error message in Visual Studio that is easy to over look
APPHOST9605: Can’t navigate to <ms-appx:///nestedLocalContext.html> from <ms-appx-web://8f028944-29cc-4f85-8d13-c1ef987ea8f3/webContext.html> because the destination URI is in a higher security zone. You can’t navigate from a zone with lower security to a zone with higher security unless you’re navigating to a local context URI from a web context URI and you’ve registered the local context URI with the MSApp.addPublicLocalApplicationUri method.
So we can access the image file in the main app code, create a local blob URL to it and then pass that to the nested local context to be used in an image element. As we are crossing from local domain (context), to web domain domain and back to local domain we’ll need to use the official HTML cross domain communication “postMessage” twice. In theory it should be possible to access the inner local context directly from the outer one as they are both the same domain. However, in practice it’s not possible access an iframe’s content if it is from another domain (eg access to contentDocument etc is blocked).
To help make this all clear I’ve placed working code in an example VisualStudio project in GitHub SteveALee/Win8LocalResourceAccess.
A final note, obviously you need to tread a little carefully as addPublicLocalApplicationUri is overriding the security model which is there for good reasons. In particular watch out for untrusted code access in the web context. Being forced to restrict the cross domains interactions to postMessage is a security advantage.
Time for a quick sanity check. Is all this worth the effort? Is there really a use case or is it simply an academic exercise? Why not just remove the web context completely? Won’t other platforms have similar cross domain limitations for access local resources? Remember we want the core application to be HTML code that will run on other platforms without change. I can’t yet comment on other browser/platform combinations, but this is certainly a possible partial solution to having generic HTML code that works on various platforms. For now, I’m recording it so I can come back to it if required when we start to look at other platforms.