iOS Safari和UIWebView对orientationchange事件的实现

背景知识:

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
#0	0x0278f730 in -[WebFrame(WebPrivate) sendOrientationChangeEvent:] ()
#1	0x001f1d65 in -[UIWebDocumentView sendOrientationEventForOrientation:] ()
#2	0x00207a7c in -[UIWebView _didRotate:] ()
#3	0x00bae4f9 in __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 ()
#4	0x01dbc0c5 in ___CFXNotificationPost_block_invoke_0 ()
#5	0x01d16efa in _CFXNotificationPost ()
#6	0x00ae2bb2 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#7	0x0006a863 in -[UIWindow _finishedFullRotation:finished:context:skipNotification:] ()
#8	0x0006a959 in -[UIWindow _finishedFullRotation:finished:context:] ()
#9	0x0006fd66 in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] ()
#10	0x0006ff04 in -[UIViewAnimationState animationDidStop:finished:] ()
#11	0x0235a7d8 in CA::Layer::run_animation_callbacks(void*) ()
#12	0x04ad8014 in _dispatch_client_callout ()
#13	0x04ac87d5 in _dispatch_main_queue_callback_4CF ()
#14	0x01d08af5 in __CFRunLoopRun ()
#15	0x01d07f44 in CFRunLoopRunSpecific ()
#16	0x01d07e1b in CFRunLoopRunInMode ()
#17	0x01cbc7e3 in GSEventRunModal ()
#18	0x01cbc668 in GSEventRun ()
#19	0x00031ffc in UIApplicationMain ()
#20	0x00001eb2 in main at /Users/liuhx/Desktop/UIWebView_Research/WebViewResearch/main.mm:16
在0层函数里使用GCD技术,让一个block函数到WebThread里执行。随后WebThread的堆栈为:

Thread 5 WebThread, Queue : (null)
#0	0x02c46030 in WebCore::Frame::sendOrientationChangeEvent(int) ()
#1	0x0278f7cc in __51-[WebFrame(WebPrivate) sendOrientationChangeEvent:]_block_invoke_0 ()
#2	0x0363a548 in HandleRunSource ()
#3	0x01ce5f3f in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ()
#4	0x01ce596f in __CFRunLoopDoSources0 ()
#5	0x01d08734 in __CFRunLoopRun ()
#6	0x01d07f44 in CFRunLoopRunSpecific ()
#7	0x01d07e1b in CFRunLoopRunInMode ()
#8	0x03639c50 in RunWebThread(void*) ()
#9	0x9854aed9 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
#0	0x04487730 in -[WebFrame(WebPrivate) sendOrientationChangeEvent:] ()
#1	0x01e70d65 in -[UIWebDocumentView sendOrientationEventForOrientation:] ()
#2	0x0002d6f8 in ___lldb_unnamed_function816$$MobileSafari ()
#3	0x0002e006 in ___lldb_unnamed_function824$$MobileSafari ()
#4	0x01e681cf in -[UIWebDocumentView setFrame:] ()
#5	0x020741d0 in -[UIWebBrowserView setFrame:] ()
#6	0x01e69967 in -[UIWebDocumentView _updateSize] ()
#7	0x01e6b516 in -[UIWebDocumentView _WAKViewSizeDidChange:] ()
#8	0x00ba74f9 in __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 ()
#9	0x004e50c5 in ___CFXNotificationPost_block_invoke_0 ()
#10	0x0043fefa in _CFXNotificationPost ()
#11	0x00adbbb2 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#12	0x0047f1bd in __invoking___ ()
#13	0x0047f0d6 in -[NSInvocation invoke] ()
#14	0x03556dc3 in SendMessage(NSInvocation*) ()
#15	0x03555967 in SendDelegateMessage(NSInvocation*) ()
#16	0x0354cc51 in notificationCallback(WKView*, WKViewNotificationType, void*) ()
#17	0x035a0c49 in WKViewSetBoundsSize ()
#18	0x0354d8d5 in -[WAKView setBoundsSize:] ()
#19	0x033433c5 in WebCore::ScrollView::platformSetContentsSize() ()
#20	0x0333fd0e in WebCore::ScrollView::setContentsSize(WebCore::IntSize const&) ()
#21	0x02b98eb5 in WebCore::FrameView::setContentsSize(WebCore::IntSize const&) ()
#22	0x02b98fcc in WebCore::FrameView::adjustViewSize() ()
#23	0x02b9a56d in WebCore::FrameView::layout(bool) ()
#24	0x02ba0a8c in WebCore::FrameView::forceLayout(bool) ()
#25	0x044b77e7 in -[WebHTMLView layoutToMinimumPageWidth:height:originalPageWidth:originalPageHeight:maximumShrinkRatio:adjustingViewSize:] ()
#26	0x044b7851 in -[WebHTMLView layout] ()
#27	0x01e68ff6 in -[UIWebDocumentView viewportConfigurationsDidChange:] ()
#28	0x01e6b6ec in -[UIWebDocumentView setMinimumSize:updateCurrentViewportConfigurationSize:] ()
#29	0x01e6b5de in -[UIWebDocumentView setMinimumSize:] ()
#30	0x0002d6d6 in ___lldb_unnamed_function816$$MobileSafari ()
#31	0x0003b49b in ___lldb_unnamed_function1040$$MobileSafari ()
#32	0x0003b337 in ___lldb_unnamed_function1039$$MobileSafari ()
#33	0x00049b52 in ___lldb_unnamed_function1308$$MobileSafari ()
#34	0x01da06aa in -[UIViewController _didRotateFromInterfaceOrientation:forwardToChildControllers:skipSelf:] ()
#35	0x01da0bb7 in -[UIViewController window:didRotateFromInterfaceOrientation:] ()
#36	0x01ce96ee in -[UIWindow _finishedFullRotation:finished:context:skipNotification:] ()
#37	0x01ce9959 in -[UIWindow _finishedFullRotation:finished:context:] ()
#38	0x01ceed66 in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] ()
#39	0x01ceef04 in -[UIViewAnimationState animationDidStop:finished:] ()
#40	0x01b087d8 in CA::Layer::run_animation_callbacks(void*) ()
#41	0x04ce7014 in _dispatch_client_callout ()
#42	0x04cd77d5 in _dispatch_main_queue_callback_4CF ()
#43	0x00431af5 in __CFRunLoopRun ()
#44	0x00430f44 in CFRunLoopRunSpecific ()
#45	0x00430e1b in CFRunLoopRunInMode ()
#46	0x00ec07e3 in GSEventRunModal ()
#47	0x00ec0668 in GSEventRun ()
#48	0x01cb0ffc in UIApplicationMain ()
#49	0x0005be87 in ___lldb_unnamed_function1676$$MobileSafari ()

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

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


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

你可能感兴趣的:(ios,UIWebView,webkit,私有api)