iOS Safari和UIWebView对orientationchange事件的实现

来源:互联网 发布:龙腾世纪3 捏脸数据 编辑:程序博客网 时间:2024/05/17 07:34

背景知识:

Safari Web Content Guide中关于orientationchange的文档:

http://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html#//apple_ref/doc/uid/TP40006511-SW16

这里用addEventListener来实现:https://code.csdn.net/hursing/pagetest/blob/master/orientationchange.html

<html>    <head>    <title>orientationchange</title></head>    <body><p id="test">angle</p><script type="text/javascript">function orientationHandler() {var orientation = window.orientation;switch (orientation) {case 0:case 90:case -90:case 180:document.getElementById("test").innerHTML = orientation;break;default:document.getElementById("test").innerHTML = "oh my god~";break;}}window.addEventListener("orientationchange", orientationHandler, false);    </script></body></html>

可以用iOS Safari或UIWebView来访问这个网页,旋转设备,会看到角度的实时变化。


orientationchange相关的逻辑由宏ENABLE_ORIENTATION_EVENTS包着,代码里的例子

DOMWindow.h:

#if ENABLE(ORIENTATION_EVENTS)        // This is the interface orientation in degrees. Some examples are:        //  0 is straight up; -90 is when the device is rotated 90 clockwise;        //  90 is when rotated counter clockwise.        int orientation() const;        DEFINE_ATTRIBUTE_EVENT_LISTENER(orientationchange);#endif


UIWebView使用私有API来获取设备旋转的信息。利用NSNotificationCenter监听key为“UIWindowDidRotateNotification”的事件,此key的通知时机相当于RootViewController的
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
函数。(识别方法请参考《xcode反汇编调试iOS模拟器程序(四)自动断点应用之NSNotificationCenter》)

(lldb) po *(id*)($ebp+16)$1 = 0x0082877c UIWindowDidRotateNotification
触发时的主线程堆栈:

Thread 1, Queue : com.apple.main-thread#00x0278f730 in -[WebFrame(WebPrivate) sendOrientationChangeEvent:] ()#10x001f1d65 in -[UIWebDocumentView sendOrientationEventForOrientation:] ()#20x00207a7c in -[UIWebView _didRotate:] ()#30x00bae4f9 in __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 ()#40x01dbc0c5 in ___CFXNotificationPost_block_invoke_0 ()#50x01d16efa in _CFXNotificationPost ()#60x00ae2bb2 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()#70x0006a863 in -[UIWindow _finishedFullRotation:finished:context:skipNotification:] ()#80x0006a959 in -[UIWindow _finishedFullRotation:finished:context:] ()#90x0006fd66 in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] ()#100x0006ff04 in -[UIViewAnimationState animationDidStop:finished:] ()#110x0235a7d8 in CA::Layer::run_animation_callbacks(void*) ()#120x04ad8014 in _dispatch_client_callout ()#130x04ac87d5 in _dispatch_main_queue_callback_4CF ()#140x01d08af5 in __CFRunLoopRun ()#150x01d07f44 in CFRunLoopRunSpecific ()#160x01d07e1b in CFRunLoopRunInMode ()#170x01cbc7e3 in GSEventRunModal ()#180x01cbc668 in GSEventRun ()#190x00031ffc in UIApplicationMain ()#200x00001eb2 in main at /Users/liuhx/Desktop/UIWebView_Research/WebViewResearch/main.mm:16
在0层函数里使用GCD技术,让一个block函数到WebThread里执行。随后WebThread的堆栈为:

Thread 5 WebThread, Queue : (null)#00x02c46030 in WebCore::Frame::sendOrientationChangeEvent(int) ()#10x0278f7cc in __51-[WebFrame(WebPrivate) sendOrientationChangeEvent:]_block_invoke_0 ()#20x0363a548 in HandleRunSource ()#30x01ce5f3f in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ()#40x01ce596f in __CFRunLoopDoSources0 ()#50x01d08734 in __CFRunLoopRun ()#60x01d07f44 in CFRunLoopRunSpecific ()#70x01d07e1b in CFRunLoopRunInMode ()#80x03639c50 in RunWebThread(void*) ()#90x9854aed9 in _pthread_start ()
至此开始有开源码了:

#if ENABLE(ORIENTATION_EVENTS)void Frame::sendOrientationChangeEvent(int orientation){    m_orientation = orientation;    if (Document* doc = document())        doc->dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, false, false));}#endif // ENABLE(ORIENTATION_EVENTS)

总之,orientationchange事件的传递路径为:

UIKit::UIWebView->UIKit::UIWebDocumentView->WebKit::WebFrame--block函数跨线程-->WebCore::Frame

剩下的工作就是WebCore::EventTarget的标准流程了。


MobileSafari是不用UIWebView的,直接由UIViewController把事件传给UIWebDocumentView,但是路径并不同。堆栈如下:

Thread 1, Queue : com.apple.main-thread#00x04487730 in -[WebFrame(WebPrivate) sendOrientationChangeEvent:] ()#10x01e70d65 in -[UIWebDocumentView sendOrientationEventForOrientation:] ()#20x0002d6f8 in ___lldb_unnamed_function816$$MobileSafari ()#30x0002e006 in ___lldb_unnamed_function824$$MobileSafari ()#40x01e681cf in -[UIWebDocumentView setFrame:] ()#50x020741d0 in -[UIWebBrowserView setFrame:] ()#60x01e69967 in -[UIWebDocumentView _updateSize] ()#70x01e6b516 in -[UIWebDocumentView _WAKViewSizeDidChange:] ()#80x00ba74f9 in __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 ()#90x004e50c5 in ___CFXNotificationPost_block_invoke_0 ()#100x0043fefa in _CFXNotificationPost ()#110x00adbbb2 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()#120x0047f1bd in __invoking___ ()#130x0047f0d6 in -[NSInvocation invoke] ()#140x03556dc3 in SendMessage(NSInvocation*) ()#150x03555967 in SendDelegateMessage(NSInvocation*) ()#160x0354cc51 in notificationCallback(WKView*, WKViewNotificationType, void*) ()#170x035a0c49 in WKViewSetBoundsSize ()#180x0354d8d5 in -[WAKView setBoundsSize:] ()#190x033433c5 in WebCore::ScrollView::platformSetContentsSize() ()#200x0333fd0e in WebCore::ScrollView::setContentsSize(WebCore::IntSize const&) ()#210x02b98eb5 in WebCore::FrameView::setContentsSize(WebCore::IntSize const&) ()#220x02b98fcc in WebCore::FrameView::adjustViewSize() ()#230x02b9a56d in WebCore::FrameView::layout(bool) ()#240x02ba0a8c in WebCore::FrameView::forceLayout(bool) ()#250x044b77e7 in -[WebHTMLView layoutToMinimumPageWidth:height:originalPageWidth:originalPageHeight:maximumShrinkRatio:adjustingViewSize:] ()#260x044b7851 in -[WebHTMLView layout] ()#270x01e68ff6 in -[UIWebDocumentView viewportConfigurationsDidChange:] ()#280x01e6b6ec in -[UIWebDocumentView setMinimumSize:updateCurrentViewportConfigurationSize:] ()#290x01e6b5de in -[UIWebDocumentView setMinimumSize:] ()#300x0002d6d6 in ___lldb_unnamed_function816$$MobileSafari ()#310x0003b49b in ___lldb_unnamed_function1040$$MobileSafari ()#320x0003b337 in ___lldb_unnamed_function1039$$MobileSafari ()#330x00049b52 in ___lldb_unnamed_function1308$$MobileSafari ()#340x01da06aa in -[UIViewController _didRotateFromInterfaceOrientation:forwardToChildControllers:skipSelf:] ()#350x01da0bb7 in -[UIViewController window:didRotateFromInterfaceOrientation:] ()#360x01ce96ee in -[UIWindow _finishedFullRotation:finished:context:skipNotification:] ()#370x01ce9959 in -[UIWindow _finishedFullRotation:finished:context:] ()#380x01ceed66 in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] ()#390x01ceef04 in -[UIViewAnimationState animationDidStop:finished:] ()#400x01b087d8 in CA::Layer::run_animation_callbacks(void*) ()#410x04ce7014 in _dispatch_client_callout ()#420x04cd77d5 in _dispatch_main_queue_callback_4CF ()#430x00431af5 in __CFRunLoopRun ()#440x00430f44 in CFRunLoopRunSpecific ()#450x00430e1b in CFRunLoopRunInMode ()#460x00ec07e3 in GSEventRunModal ()#470x00ec0668 in GSEventRun ()#480x01cb0ffc in UIApplicationMain ()#490x0005be87 in ___lldb_unnamed_function1676$$MobileSafari ()

其中几行___lldb_unnamed_function应该是Safari的C++代码,去掉了符号表,不清楚是什么,还是不能肯定地说MobileSafari一定是viewport改变后才改变设备方向。

只好说,使用UIWebView的第三方浏览器想跟Safari比效率?还是算了吧。


转载请注明出处:http://blog.csdn.net/hursing