在iOS中开启和使用WebGL

HiWebGL原创翻译整理
作者: Nathan de Vries
原文地址:http://atnan.com/blog/2011/11/03/enabling-and-using-webgl-on-ios/

背景

最近我对WebGL越来越感兴趣,我突然想起来曾经在Hacker News上看过一个新闻说iOS 5中将会在iAD框架中支持WebGL。

iOS 5不会开放对WebGL的普遍支持,而只会对iAD开发者开放。

—— Chris Marrin,WebKit工程师 (来源:Public WebGL Mailing List

在iOS 5释出GM版本时,我决定做一个简单的WebGL Demo来看看支持的情况和性能如何。

不幸的是这个Demo根本不能运行——当我尝试使用canvas的“getContext()”创建一个“webgl-experimental”的上下文时,失败了!

突破

我马上发了一条微博(其实是Tweet啦!)给 Antoine Quint(iAd JS/iOS软件工程师,就职于Apple),确认Chris Marrin的E-mail内容是否属实:

Chris Marrin暗示说iOS 5将会在iAd中支持WebGL。这是真的吗?

Nathan de Vries —— Twitter

他回复说:

iAd从iOS 4.2开始就支持WebGL啦!

Antoine Quint —— Twitter

这真是个比我预想的还要好的消息!然而,他还是没解释为什么我不能创建一个WebGL上下文。

我一点一点的慢慢尝试,我终于知道为什么当我调用getContext(“experimental-webgl”)的时候canvas总是返回null了。

你还需要把“uses-webgl”添加到你的ad的参数列表里。对不起,忘说了。

Antoine Quint —— Twitter

这个“uses-webgl”的参数设置从来没有被公布过,但是它真的管用!

iAd WebGL Demo

我制作了一个WebGL的iAD的工程,可以拖拽到模拟器中或者使用iTunes同步到设备上。

 

在GitHub上克隆WebGL.ad

把WebGL.ad目录拖拽到iOS模拟器中,然后会运行内置的iAd Tester应用。你会在底部看到一个条幅,点击这个条幅就会打开WebGL Demo。

如果你的iAd无法运行,可以去查看一下《iAd JS编程指南》中的《使用iOS模拟器测试》《使用设备测试》这两个章节。

标准的UIWebView暗中支持WebGL?

如果iAd框架使用了UIWebView,那我们是不是可以在浏览web时也会得到相同的效果?

在iOS模拟器中运行iAd Tester时检查ps的输出,你会发现运行着一个叫做AdSheet的应用。使用otool,我们看一下它连接到了哪个私有框架:

1
2
3
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看起来很有趣。让我们用class-dump看看与WebGL相关的函数。

1
class-dump /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/System/Library/PrivateFrameworks/iAdCore.framework/iAdCore

在输出中搜索一下,很容易就可以找到以下内容:

1
2
3
4
5
@interface ADWebView : UIWebView {
    BOOL _webGLEnabled;
}
@property(nonatomic) BOOL webGLEnabled; // @synthesize webGLEnabled=_webGLEnabled;
@end

反过来,我们可以简单的连接到iAdCore.framework,然后使用ADWebView来代替UIWebView。以下是一个实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@implementation WGLAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  Class ADWebView = NSClassFromString(@"ADWebView");
  UIWebView* webView = (UIWebView *)[[[ADWebView alloc] initWithFrame:self.window.bounds] autorelease];
  [webView setWebGLEnabled:YES];
 
  NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"WebGL" ofType:@"html"];
  NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:htmlPath]];
  [webView loadRequest:request];
 
  UIViewController* viewController = [[[UIViewController alloc] init] autorelease];
  viewController.view = webView;
 
  self.window.rootViewController = viewController;
  [self.window makeKeyAndVisible];
 
  return YES;
}
@end

ADWebView能行吗?

也许我们可以完全摆脱ADWebView,只是在自定义的UIWebView子类中加入“-[ADWebView setWebGLEnabled:]”。我们仍将继续调用私有API,但是至少我们不需要再连接私有框架了。

为了再生“-[ADWebView setWebGLEnabled:]”,我们需要反汇编一下,可以使用“otool -tVv”,或者通过Homebrew安装objdump,然后调用“gobjdump –d”。下面是我们感兴趣的一些东西:

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
0005aba3 <-[ADWebView setWebGLEnabled:]>:
   5aba3:       55                      push   %ebp
   5aba4:       89 e5                   mov    %esp,%ebp
   5aba6:       56                      push   %esi
   5aba7:       83 ec 24                sub    $0x24,%esp
   5abaa:       e8 00 00 00 00          call   5abaf <-[ADWebView setWebGLEnabled:]+0xc>
   5abaf:       59                      pop    %ecx
   5abb0:       8b b1 89 e4 04 00       mov    0x4e489(%ecx),%esi
   5abb6:       8a 45 10                mov    0x10(%ebp),%al
   5abb9:       8b 55 08                mov    0x8(%ebp),%edx
   5abbc:       88 04 32                mov    %al,(%edx,%esi,1)
   5abbf:       8b b1 d5 65 03 00       mov    0x365d5(%ecx),%esi
   5abc5:       89 75 e0                mov    %esi,-0x20(%ebp)
   5abc8:       c7 45 e4 00 00 00 42    movl   $0x42000000,-0x1c(%ebp)
   5abcf:       c7 45 e8 00 00 00 00    movl   $0x0,-0x18(%ebp)
   5abd6:       8d b1 50 00 00 00       lea    0x50(%ecx),%esi
   5abdc:       89 75 ec                mov    %esi,-0x14(%ebp)
   5abdf:       8d 89 c1 d9 04 00       lea    0x4d9c1(%ecx),%ecx
   5abe5:       89 4d f0                mov    %ecx,-0x10(%ebp)
   5abe8:       89 55 f4                mov    %edx,-0xc(%ebp)
   5abeb:       88 45 f8                mov    %al,-0x8(%ebp)
   5abee:       8d 45 e0                lea    -0x20(%ebp),%eax
   5abf1:       89 04 24                mov    %eax,(%esp)
   5abf4:       e8 d7 45 00 00          call   5f1d0 <_WebThreadRun$stub>
   5abf9:       83 c4 24                add    $0x24,%esp
   5abfc:       5e                      pop    %esi
   5abfd:       5d                      pop    %ebp
   5abfe:       c3                      ret    
 
0005abff <___29-[ADWebView setWebGLEnabled:]_block_invoke_0>:
   5abff:       55                      push   %ebp
   5ac00:       89 e5                   mov    %esp,%ebp
   5ac02:       57                      push   %edi
   5ac03:       56                      push   %esi
   5ac04:       83 ec 10                sub    $0x10,%esp
   5ac07:       e8 00 00 00 00          call   5ac0c <___29-[ADWebView setWebGLEnabled:]_block_invoke_0+0xd>
   5ac0c:       5e                      pop    %esi
   5ac0d:       8b 7d 08                mov    0x8(%ebp),%edi
   5ac10:       8b 47 14                mov    0x14(%edi),%eax
   5ac13:       8b 8e 54 66 04 00       mov    0x46654(%esi),%ecx
   5ac19:       89 4c 24 04             mov    %ecx,0x4(%esp)
   5ac1d:       89 04 24                mov    %eax,(%esp)
   5ac20:       e8 a7 46 00 00          call   5f2cc <_objc_msgSend$stub>
   5ac25:       8b 8e 50 66 04 00       mov    0x46650(%esi),%ecx
   5ac2b:       89 4c 24 04             mov    %ecx,0x4(%esp)
   5ac2f:       89 04 24                mov    %eax,(%esp)
   5ac32:       e8 95 46 00 00          call   5f2cc <_objc_msgSend$stub>
   5ac37:       0f be 57 18             movsbl 0x18(%edi),%edx
   5ac3b:       8b 8e 94 6a 04 00       mov    0x46a94(%esi),%ecx
   5ac41:       89 54 24 08             mov    %edx,0x8(%esp)
   5ac45:       89 4c 24 04             mov    %ecx,0x4(%esp)
   5ac49:       89 04 24                mov    %eax,(%esp)
   5ac4c:       e8 7b 46 00 00          call   5f2cc <_objc_msgSend$stub>
   5ac51:       83 c4 10                add    $0x10,%esp
   5ac54:       5e                      pop    %esi
   5ac55:       5f                      pop    %edi
   5ac56:       5d                      pop    %ebp
   5ac57:       c3                      ret    
   5ac58:       0f 1f 84 00 00 00 00    nopl   0x0(%eax,%eax,1)
   5ac5f:       00

我不会详细解释如何理解这些反汇编内容的细节,但是希望你们能够注意到在5abf4,我们正在运行一些看起来像是使用了UIWebView的web线程(_WebThreadRun$stub)的代码。这些代码好像用连续三次调用了Objective-C方法(_objc_msgSend$stub),分别在5ac20、5ac32和5ac4c。

在前面我们使用ADWebView并连接到私有框架iAdCore的代码中,我们可以在___29-[ADWebView setWebGLEnabled:]_block_invoke_0设置一个断点标识,然后检查暂存器$eax和$ecx的值,看看哪个优先调用了objc_msgSend。在i386 ABI for objc_msgSend()中,你会发现这两个暂存器对应于被调用的信息的接收者($eax)和选择者($ecx)。

继续下去,我们会发现:

  • 在5ac20,$eax是ADWebView的实例,$ecx是_browserView
  • 在5ac32,$eax是UIWebDocumentView的实例,$ecx是webView
  • 在5ac4c,$eax是WebView的实例,$ecx是_setWebGLEnabled:

这样,我们就可以拼凑出出的-[ADWebView setWebGLEnabled:]重实现

1
2
3
4
5
- (void)setWebGLEnabled:(BOOL)enableWebGL {
  UIWebDocumentView* webDocumentView = [self _browserView];
  WebView* backingWebView = [webDocumentView webView];
  [backingWebView _setWebGLEnabled:enableWebGL];
}

我把Xcode的工程都放到了GitHub。

 

在GitHub上克隆UIWebViewWebGL

总结

很明显,从对iAd支持WebGL中可以看出来,Apple正在致力于将WebGL的支持普及到更广泛的应用场合中。

与其抱怨为什么只在iAd中支持WebGL,我的实验证明了在标准嵌入式的web浏览中使用WebGL是可能的(尽管使用了私有API)。

这可以让开发者继续跟进Apple对WebGL的承诺,看看他们走到哪一步了。

欢迎和我一起讨论!

分享到: 更多
Posted in 博文精选. Bookmark the permalink.

3 trackbacks

WebGL新闻 | iOS 5 运行 WebGL 视频!HiWebGL | HiWebGL | 最好的HTML5 WebGL中文资讯站
2011 年 11 月 4 日 上午 3:07
WebGL新闻 | 支持 WebGL 的 iOS 5 浏览器 (附 WebGL 运行于 iPad 的视频)HiWebGL | HiWebGL | 最好的HTML5 WebGL中文资讯站
2011 年 11 月 6 日 下午 9:02
WebGL All in One 全傻瓜简介 | HiWebGL
2012 年 6 月 27 日 下午 1:59

Post a Comment

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>