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

时间: 2024-09-10 18:15:40

iOS Safari和UIWebView对orientationchange事件的实现的相关文章

谈谈iOS的Safari和UIWebView

打开iOS4.3上的iPad Safari,再跟iOS6.1上的对比,也许你会觉得4.3没有标签栏,不够好用,但那个多窗口的设计却又非常酷. iPhone上的Safari 4.3也和iPad差不多.这个多窗口的设计,影响了那个年代的第三方浏览器,UC啊,QQ啊都这么学.可是后来呢,iPad上的诸多第三方浏览器都是有标签栏的,Safari估计是被骂多了,在iOS5开始也这么干. 可是其实,iOS4的Safari代码里就已经有关于Tab的代码,可见Safari的重构优化是伴随着发布的,没做完的功能也

iOS Safari/WebKit对DeviceOrientationEvent的实现

背景知识: Apple官方只发现一个文档: https://developer.apple.com/library/safari/#documentation/SafariDOMAdditions/Reference/DeviceOrientationEventClassRef/DeviceOrientationEvent/DeviceOrientationEvent.html 连个例子都没有,还是自己实践吧.https://code.csdn.net/hursing/pagetest/blob

iOS Safari阅读模式分析过程

本文为Safari阅读模式分析过程记录,没有做很好的整理.最终的输出见另一篇iOS Safari阅读模式研究. 1. Break on evaluate   b JSC::evaluate(JSC::ExecState*, JSC::ScopeChainNode*, JSC::SourceCode const&, JSC::JSValue, JSC::JSValue*)   dump the source content from JSC::SourceCode Printing descrip

iOS Safari/WebKit对DeviceMotionEvent的实现

请先阅读<iOS Safari/WebKit对DeviceOrientationEvent的实现>,本文是姐妹篇. 简单地描述一下区别,后面会更详细对比: DeviceOrientationEvent是获取方向,得到device静止时的绝对值: DeviceMotionEvent是获取移动速度,得到device移动时相对之前某个时间的差值比. 背景知识: Apple官方依然只发现一个文档: https://developer.apple.com/library/safari/#document

在线等,ios safari 打开网页白屏

问题描述 在线等,ios safari 打开网页白屏 在线等.http://www.dytj.com/pcebweb/PublicShare.do?ParentShareCode=6f655e7fba56a19040f2b9930204a117&adTemplateSeq=17&r=0.09126012772321701这是公司的分享到微信中的一个链接,打开经常出现白屏,想问下苹果对网页会有什么控制没?白屏不显示是网页的问题吗? 解决方案 本人打开多次,没有发现楼主说的白屏现象,可能是网络

IOS中使用UIWebView 加载网页、文件、 html的方法_IOS

 UIWebView 是用来加载加载网页数据的一个框.UIWebView可以用来加载pdf word doc 等等文件 生成webview 有两种方法: 1.通过storyboard 拖拽 2.通过alloc init 来初始化 创建webview,下列文本中 _webView.dataDetectorTypes = UIDataDetectorTypeAll; 是识别webview中的类型,例如 当webview中有电话号码,点击号码就能直接打电话 - (UIWebView *)webView

iOS开发中UIWebView的加载本地数据的三种方式_IOS

UIWebView是IOS内置的浏览器,可以浏览网页,打开文档 html/htm pdf docx txt等格式的文件. safari浏览器就是通过UIWebView做的. 服务器将MIME的标识符等放入传送的数据中告诉浏览器使用那种插件读取相关文件. uiwebview加载各种本地文件(通过loadData方法): UIWebView加载内容的三种方式: 1 加载本地数据文件 指定文件的MIMEType 编码格式使用@"UTF-8" 2加载html字符串(可以加载全部或者部分html

举例讲解iOS应用开发中hitTest触摸事件的编写方法_IOS

 hitTest:withEvet  调用过程 比如如果是当前的View A, 还有一个viewB 如果不重写 hitTest 方法,那么 系统默认是先调用viewA的hitest 方法,然后再调用viewB的htest方法. 系统的调用过程,跟下面的重写hitest的方法是一模一样的. 复制代码 代码如下: -(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event  {      if ([self pointInside:poin

iOS Safari支持浏览器内方向感应

日前有移动http://www.aliyun.com/zixun/aggregation/6434.html">软件开发者发现,虽然苹果从未宣传过这一功能,但实际上在上月底iOS 4.2升级后,iPhone.iPad.iPod touch上的Safari浏览器已经对一系列HTML5和W3C新标准提供了支持,其中最引人注目的要数浏览器内持握方向识别.该技术名为DeviceOrientation API,目前正处在W3C草案标准的阶段.通过这一编程接口,网页能够利用手机的加速度计.陀螺仪.电子