This post is focused on the AIR StageWebview class displaying assets including special handling required on Android.
Review of StageWebview
If you're familiar with basic StageWebview functionality you can skip this bit.
StageWebview is an AIR class that lets you display pretty much any HTML content you can display in a browser (basically StageWebView is a browser). Content can be remote (e.g., www.google.com) or local (e.g., file://appMainHelp.html).
It's important to note that StageWebView isn't really a Flex component, it doesn't even inherit from Sprite let alone UIComponent. On mobile it's essentially a chromeless system browser instance sitting on top of your app within a viewport you provide. The implementation for desktop apps is slightly different – you'll get an instance of HTMLLoader. This difference makes for different behavior and affects how you use StageWebview on mobile.
To display HTML content you can use StageWebView's loadURL or loadString methods. The loadURL method accepts a url that uses a standard URI scheme (e.g., https:). LoadString can process a string with HTML markup (e.g., "this has <b>bold</b> and <u>underline</u> with a link: <a href='http://www.google.com'> Google </a>").
The HTML you feed loadString() cannot load local resources – so the following is NOT allowed: var myHtmlContent:String = "<img src='localImage.png/>" // will NOT work! |
If you want more info on StageWebview you'll find this Adobe doc useful: "Displaying HTML content in mobile apps"
There's an enhanced StageWebView component called StageWebViewBridge. I haven't used it but it sounds like something to look at if you want to get around some of StageWebview's current limitations. |
StageWebview accessing application assets
In general, accessing local files with StageWebview is straightforward: just use File's url property to get the url to the file and then feed this url to StageWebview's loadurl method. However, this approach doesn't work when accessing assets packaged with your AIR app –- when you feed StageWebview the url it won't find your asset file. Why? The answer lies in the location of your assets and the url you get from AIR's File class.
Assets packaged with your app are stored under your app's application directory (i.e., File.applicationDirectory). For files stored in your app application directory the value of the url property begins with app://, which is AIR's addressing scheme for the application directory (more info here).
This app:// addressing scheme works great within your AIR application, but if you feed this address to an external browser you're out of luck – app:// has no meaning outside of AIR so if you use this address in a browser like Firefox you get an access error. As you'd expect, this is the same behavior you'll see when you pass that same url to StageWebview, since (as noted above) StageWebview is basically an external browser. Here's a relevant bit about StageWebview from the latest as3_devguide documentation:
"You can use any URI scheme supported by the system web browser control, including: data:, file:, http:, https:, and javascript:. The app: and app-storage: schemes are not supported."
So, the reason files residing in the application directory aren't found by external browsers is just that app:// url. Once you know this the workaround is straightforward.
For non-Android apps you can just use Mike Chambers workaround posted here. In this workaround you first obtain the native path to your file and then get the file:// URI for that nativePath. Here's Mike's example:
var fPath:String = new File(new File("app:/icon.png").nativePath).url;
Ok, that solves the problem of accessing files in the application directory… except for AIR apps on Android.
Why doesn't the above workaround work on Android ?
The short answer is that on Android the nativePath always returns blank for files residing in your application directory. Here's a bit from the doc:
"On Android, the nativePath property of a File object pointing to the application directory is an empty string. Use the url property to access application files."
Here's the slightly longer answer: on Android your application is contained in an .apk file, which is basically a .zip file. And that's why the nativePath value returns a blank for these files: there's no "real" file, there's just that compressed apk. If you want a file you can work with then you have to extract it from that apk.
Again, once you know the cause of the problem the workaround is simple. To access an asset on Android from StageWebview just do the following:
- copy your file out of the application "directory structure" (actually the compressed .apk) into a real directory as a real file
- create a File reference to your just-copied file using AIR's File class
- from this File instance retrieve the value of the url property
- now you can pass this url to StageWebview's loadURL method
Here's the code for copying a single file:
// This copies a single file into a subdir of appStorageDir var source:File = File.applicationDirectory.resolvePath("assets/docs/DEOverview.htm"); // create file(s) in a subdir of appStorageDir to simplify cleanup var destination:File = File.applicationStorageDirectory.resolvePath("docs/DEOverview.htm"); // now do the copy and create a ref to our HTML file that a browser will understand source.copyTo(destination, true); initialURL = "file://" + destination.nativePath ;
And if you want to copy all files in a directory you can use this:
source:File = File.applicationDirectory.resolvePath("assets/docs") ; var destination:File = File.applicationStorageDirectory; source.copyTo(destination, true); initialURL = "file://" + destination.resolvePath("DEOverview.htm").nativePath;
Once you have the url in a form that StageWebView can understand you just pass it to loadURL:
swv.loadURL(initialURL) ;
A reminder
On Android the above solution involves making a temp copy of your file, but don't forget to do your house cleaning -- files that you create in AIR are not automatically deleted by AIR when you app closes (this includes file you write to the File's createTempDirectory()) so if you copy assets into temporary directories then file clean up is your responsibility.
JavaScript
JavaScript appdev primers
General JavaScript
SPA Demo Application
Backbone Demo Application
Recommended sites
- Addy Osmani's blog
- Derick Bailey's Backbone posts
- Murphey's JQuery Fundamentals (original)
- Crockford's JS videos
- MSDN Project Silk
Flex/AIR
Flex/AIR primers
- Primer on Flex/AIR Multiscreen Development
- Primer on Mobile App Development w/Flex 4.5
- Primer on Flex 3 Component Lifecycle
- Primer on Flexlib MDI
Flex demo apps
all require Flash Player!
AIR mobile dev
- AIR mobile dev Tips
- AIR and Android Back key
- AIR, StageWebView, displaying local content
- AIR for Android memory issue w/large images