Background
I’ve become a lot more interested in WebGL lately, and remembered reading on Hacker News a while back that WebGL would be available in iOS 5 as part of the iAd framework.
WebGL will not be publicly available in iOS 5. It will only be available to iAd developers.
When iOS 5.0 went GM, I decided to knock up a quick WebGL demo to see what was involved & how well it performed.
Unfortunately it didn’t run at all — creating a webgl-experimental context via the canvas element’s getContext() API would fail.
Breakthrough
I shot through a tweet to Antoine Quint (iAd JS/iOS software engineer at Apple), asking for confirmation of Chris Marrin’s email:
Chris Marrin suggested that WebGL would be available in iAds as of iOS 5.0. Is that actually the case?
To which he replied:
WebGL has been supported for iAds since iOS 4.2.
That’s even better news than I had anticipated! However, it still doesn’t explain why I’m unable to create a WebGL context.
With a little bit more prompting, I got to the bottom of why HTMLCanvasElement was returning null when I called getContext("experimental-webgl"):
You also need to have “uses-webgl” in your ad’s plist. Sorry, forgot about that.
The uses-webgl setting is completely undocumented, but it certainly works!
Demo iAd WebGL Project
I’ve put together a demo WebGL iAd project that can simply be dragged into the Simulator or synced to your device via iTunes.
Drag the WebGL.ad directory into the iOS Simulator & the built-in iAd Tester app will launch. You’ll see a banner at the bottom, which when tapped will bring up the WebGL demo:

If you’re having difficulties getting the iAd running, take a look at the Testing on the iOS Simulator and Testing on the Device sections of the iAd JS Programming Guide.
Do standard UIWebViews (secretly) support WebGL?
So if the iAd framework is using a UIWebView, perhaps we can get the same behaviour in our own web views?
Looking at the output of ps while running iAd Tester in the iOS Simulator, you’ll notice an app called AdSheet running. Using otool, we can see what private frameworks it’s linked against:
otool -L /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk//Applications/AdSheet.app/AdSheet | grep PrivateFrameworks
/System/Library/PrivateFrameworks/iAdCore.framework/iAdCore (compatibility version 1.0.0, current version 1.0.0)
/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices (compatibility version 1.0.0, current version 1.0.0)
iAdCore.framework looks interesting. Let’s take a look for WebGL-related functionality using class-dump:
class-dump /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/System/Library/PrivateFrameworks/iAdCore.framework/iAdCore
Searching through the output, it’s pretty clear that we’ve found what we’re after:
1 2 3 4 5 | |
Turns out we can simply link against the private iAdCore.framework, and use ADWebViews instead of UIWebViews. Here’s an implementation which does just that:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Is ADWebView really doing that much?
Perhaps we can get rid of ADWebView altogether & just implement whatever -[ADWebView setWebGLEnabled:] is doing in our own custom UIWebView subclass. We’re still going to be calling private APIs, but at least we won’t need to link against private frameworks.
To reproduce -[ADWebView setWebGLEnabled:], we’ll need to disassemble it using otool -tVv, or install objdump via Homebrew & use gobjdump -d. Here’s the bit we’re interested in:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | |
I won’t go into detail about how to read the disassembly, but hopefully you’ll be able to see that at 5abf4 we’re running a block of code on what seems to be the UIWebView’s dedicated web thread (_WebThreadRun$stub). The block itself seems to be making 3 consecutive Objective-C method calls (_objc_msgSend$stub) at 5ac20, 5ac32 & 5ac4c.
By running the previous snippet where we were linking against the private iAdCore framework and using ADWebView, we can set a symbolic breakpoint on ___29-[ADWebView setWebGLEnabled:]_block_invoke_0 and see what the values of the $eax & $ecx registers are prior to calling objc_msgSend. Look at the i386 ABI for objc_msgSend(), and you’ll note that these registers correspond to the receiver ($eax) of the message and the selector ($ecx) being called.
Stepping through, we see:
- At
5ac20,$eaxis an instance ofADWebView, and$ecxis_browserView. - At
5ac32,$eaxis an instance ofUIWebDocumentViewand$ecxiswebView. - At
5ac4c,$eaxis an instance ofWebViewand$ecxis_setWebGLEnabled:.
From this, we can piece together our re-implementation of -[ADWebView setWebGLEnabled:]:
1 2 3 4 5 | |
I’ve put together an Xcode project demoing the results of this:
Summing Up
Apple are clearly working towards supporting WebGL in a more general sense, as can be seen in their support for it in iAds.
Instead of whinging about it only being available in iAds, I’ve demonstrated that it’s possible to take advantage of WebGL using standard embedded web views (albeit using private APIs).
This will let developers track the progress of Apple’s commitment to WebGL, and skate to where the puck is going to be.
I’m really looking forward to seeing what you all come up with!
