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/master/deviceorientationevent.html

<html>
    <head>
 	   <title>DeviceOrientationEvent</title>
	   <meta charset="UTF-8" />
	</head>
	<body>
		<p>左右:<span id="alpha">0</span></p>
		<p>前后:<span id="beta">0</span></p>
		<p>扭转:<span id="gamma">0</span></p>
		<p>指北针指向:<span id="heading">0</span>度</p>
		<p>指北针精度:<span id="accuracy">0</span>度</p>
		<script type="text/javascript">
		function orientationHandler(event) {
			document.getElementById("alpha").innerHTML = event.alpha;
			document.getElementById("beta").innerHTML = event.beta;
			document.getElementById("gamma").innerHTML = event.gamma;
			document.getElementById("heading").innerHTML = event.webkitCompassHeading;
			document.getElementById("accuracy").innerHTML = event.webkitCompassAccuracy;
		}

		if (window.DeviceOrientationEvent) {
		  window.addEventListener("deviceorientation", orientationHandler, false);
		} else {
		  document.body.innerHTML = "What user agent u r using???";
		}
   	 	</script>
	</body>
</html>

用MobileSafari或UIWebView打开以上网页,可以看到5个数值的实时变化。

(点击看大图)

在handler的event参数中可以获得5个属性,其中两个:

webkitCompassHeading:与正北方向的角度差值。正北为0度,正东为90度,正南为180度,正西为270度。因为0度是正北,所以叫指北针,不是指南针。

webkitCompassAccuracy:指北针的精确度,表示偏差为正负多少度。一般是10。

下面对另外三个属性的介绍引用一个转自http://www.tfan.org/wp-content/slides/deviceaccess.html的slides:

deviceorientation 事件对象
事件对象包含着每个轴相对于设备静止状态下发生变化的信息。

设备坐标系的概念:x 轴方向是从左往右,y 轴方向是从下往上,z 轴方向是从后往前。当设备静止放在水平桌面时,这三个值都是 0。

其中三个主要的属性:

alpha: 在围绕 z 轴旋转时(即左右旋转时),y 轴的度数差。
beta: 在围绕 x 轴旋转时(即前后旋转时),z 轴的度数差。
gamma: 在围绕 y 轴旋转时(即扭转设备时),z 轴的度数差。
围绕 z 轴旋转会引起 alpha 旋转角度发生变化。

当设备顶部指向地球正北方向时,alpha 角是 0 度,设备向左边旋转时增大,介于 0 - 360 度之间。

围绕 x 轴旋转,也就是前后翻转(朝着用户或者远离用户)时,会引起 beta 旋转角度变化。

设备水平放置时,beta 角度是 0 度;向上翻逐步增加到 180 度;向下翻减少到 -180 度。

注:我试了一下ipad safari,beta取值是-90到90,但用android chrome是-180到180。苹果的文档也表示beta是-90到90,参考https://developer.apple.com/library/safari/documentation/SafariDOMAdditions/Reference/DeviceOrientationEventClassRef/DeviceOrientationEvent/DeviceOrientationEvent.html#//apple_ref/javascript/instp/DeviceOrientationEvent/beta
,和我引用的文档说的不同。估计这是苹果自己的实现,觉得这样用户体验好,因为翻转后苹果自动旋转屏幕,故不存在倒转的操作。不能用beta值来判断屏幕是绝对地向天空还是向地面,因为那是基于初始位置的差值,即只要一刷新就归0。

围绕 y 轴旋转,会引起 gamma 角度值的变化。

水平放置角度是 0,向右拧增加到 90 度;向左拧减少到 -90 度。



在《Mac Safari VS Mobile Safari开启的宏》中已确认,DeviceOrientationEvent是iOS Safari特有的feature。

iOS Safari开源码的Document.h中,与DeviceOrientationEvent有关的是比Mac开源码多了这10行:

#if ENABLE(DEVICE_ORIENTATION)
    DeviceMotionController* deviceMotionController() const;
    DeviceOrientationController* deviceOrientationController() const;
#endif
#if ENABLE(DEVICE_ORIENTATION)
    OwnPtr<DeviceMotionClient> m_deviceMotionClient;
    OwnPtr<DeviceMotionController> m_deviceMotionController;
    OwnPtr<DeviceOrientationClient> m_deviceOrientationClient;
    OwnPtr<DeviceOrientationController> m_deviceOrientationController;
#endif

其中DeviceMotionXXX是重力感应相关的,既有联系又有区别,请查看《iOS Safari/WebKit对DeviceMotionEvent的实现》。

还有一个类叫DeviceOrientationClientMock,Mock是仿制品的意思。这个类只用在自动化测试,模拟设备的转动。

下图是相关类之间的关系概貌:

其中CMMotionManager是系统SDK,功能和使用方法请参见:

http://developer.apple.com/library/ios/#documentation/CoreMotion/Reference/CMMotionManager_Class/Reference/Reference.html

DeviceOrientationClient是个抽象类,在iOS由子类DeviceOrientationClientIOS(这是6.0的名字,在5.0叫做DeviceOrientationClientIPhone)来实现,直接与MotionManager交互。

与CMMotionManager的名字类似的CoreMotionManager是个C++类,在关系链中主要充当编程语言adapter的角色,即对外是C++接口,内部实现会使用Objective-C。

xcode文档里没看到必须在主线程操作CMMotionManager的字眼,但CoreMotionManager都是在主线程操作(包括创建、销毁、调用函数)CMMotionmanager的,收到回调后,通过GCD或performSelector在MainThread和WebThread间传递消息。

当执行JavaScript遇到addEventListener时,浏览器堆栈为:

Thread 5 WebThread, Queue : (null)
#0	0x389740f8 in -[CoreMotionManager checkClientStatus] ()
#1	0x38973fa0 in -[CoreMotionManager addOrientationClient:] ()
#2	0x389a9b04 in WebCore::DeviceOrientationClientIOS::startUpdating() ()
#3	0x389aa000 in WebCore::DeviceOrientationController::addListener(WebCore::DOMWindow*) ()
#4	0x3873df36 in WebCore::DOMWindow::addEventListener(WTF::AtomicString const&, WTF::PassRefPtr<WebCore::EventListener>, bool) ()
#5	0x3873dc26 in WebCore::JSDOMWindow::addEventListener(JSC::ExecState*) ()
#6	0x3873da78 in WebCore::jsDOMWindowPrototypeFunctionAddEventListener(JSC::ExecState*) ()

第0层函数如果检测到自身不在主线程执行,会使用performSelectorOnMainThread本Selector到主线程再继续,主要操作是创建一个repeat的NSTimer不断查询CMMotionManager的相关属性,然后通过

void orientationChanged(double, double, double, double, double);

函数,把文章开头提到的5个参数值封装成类WebCore::DeviceOrientation,

class DeviceOrientation : public RefCounted<DeviceOrientation> {
public:
    static PassRefPtr<DeviceOrientation> create();
    static PassRefPtr<DeviceOrientation> create(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma, bool canProvideCompassHeading, double compassHeading, bool canProvideCompassAccuracy, double compassAccuracy);

    double alpha() const;
    double beta() const;
    double gamma() const;
    bool absolute() const;
    bool canProvideAlpha() const;
    bool canProvideBeta() const;
    bool canProvideGamma() const;
    bool canProvideAbsolute() const;

    double compassHeading() const;
    double compassAccuracy() const;
    bool canProvideCompassHeading() const;
    bool canProvideCompassAccuracy() const;

private:
    DeviceOrientation();
    DeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma, bool canProvideCompassHeading, double compassHeading, bool canProvideCompassAccuracy, double compassAccuracy);

    bool m_canProvideAlpha;
    bool m_canProvideBeta;
    bool m_canProvideGamma;
    double m_alpha;
    double m_beta;
    double m_gamma;

    bool m_canProvideCompassHeading;
    bool m_canProvideCompassAccuracy;
    double m_compassHeading;
    double m_compassAccuracy;
};

最后通过WebCore::EventTarget的标准流程传递到JavaScript的函数。

Thread 5 WebThread, Queue : (null)
#0	0x387bec96 in WebCore::EventTarget::dispatchEvent(WTF::PassRefPtr<WebCore::Event>) ()
#1	0x389aa1d4 in WebCore::DeviceOrientationController::didChangeDeviceOrientation(WebCore::DeviceOrientation*) ()
#2	0x389a9b4c in WebCore::DeviceOrientationClientIOS::orientationChanged(double, double, double, double, double) ()
#3	0x38974b0a in __48-[CoreMotionManager sendMotionData:withHeading:]_block_invoke_0 ()

另外两个值得留意的地方是:

当Document需要suspend或resume时,会同时挂起或恢复 orientation或motion的监听。

void Document::suspendActiveDOMObjects(ActiveDOMObject::ReasonForSuspension why)
{
    ScriptExecutionContext::suspendActiveDOMObjects(why);

#if ENABLE(DEVICE_ORIENTATION)
    if (m_deviceMotionController)
        m_deviceMotionController->suspendUpdates();
    if (m_deviceOrientationController)
        m_deviceOrientationController->suspendUpdates();
#endif

    ...
}

void Document::resumeActiveDOMObjects()
{
    ScriptExecutionContext::resumeActiveDOMObjects();

#if ENABLE(DEVICE_ORIENTATION)
    if (m_deviceMotionController)
        m_deviceMotionController->resumeUpdates();
    if (m_deviceOrientationController)
        m_deviceOrientationController->resumeUpdates();
#endif

    ...
}

当网页正在监听orientation或motion时,这个Page不能Cache

bool PageCache::canCache(Page* page)
{
    ...

    return canCachePageContainingThisFrame(page->mainFrame())
        && page->backForward()->isActive()
        && page->settings()->usesPageCache()
#if ENABLE(DEVICE_ORIENTATION)
        && !(page->mainFrame()->document()->deviceMotionController() && page->mainFrame()->document()->deviceMotionController()->isActive())
        && !(page->mainFrame()->document()->deviceOrientationController() && page->mainFrame()->document()->deviceOrientationController()->isActive())
#endif
        && loadType != FrameLoadTypeReload
        && loadType != FrameLoadTypeReloadFromOrigin
        && loadType != FrameLoadTypeSame;
}

iOS Safari/WebKit对DeviceMotionEvent的实现》还会对本文有补充,请点击继续查看。

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

时间: 2024-08-18 06:41:35

iOS Safari/WebKit对DeviceOrientationEvent的实现的相关文章

iOS Safari/WebKit对DeviceMotionEvent的实现

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

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 打开网页白屏

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

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来实现:htt

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

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

iOS Safari阅读模式研究

这是一篇在2013年准备的资料,现在分享出来,供有需要的同学参考. 要点 (1) 阅读模式的检测 在frame加载完成后,触发一个timer来检测是否可以使用阅读模式.检测的方式是使用JavaScriptCore framework的接口执行一段JS脚本,然后取JS中属性值来判断是否可以进入阅读模式.如果当前页面可以进入阅读模式,将在地址栏显示阅读模式切换按钮. (2) 阅读模式的执行 当用户点击阅读模式切换按钮时,会依次执行: i. 执行阅读模式检查脚本,判断目前是否可以进入阅读模式. ii.

iOS9中的WebKit 与 Safari带来的惊喜_IOS

每个用过 UIWebView 的iOS开发者对其诸多的限制和有限的功能也深有感触.悻然,自iOS8推出 WebKit 框架后将改变这一窘境.在本文我将会深入WebKit来体验一下它给我们带来的好处,同时也看看在iOS9中新加入的 SFSafariViewController 有些什么新的惊喜. 通用的浏览行为 所谓的通用浏览行为主要可以归纳为以下的几种: 网页载入进度 前进 后退 刷新 如果每个用到 WebView 的 app都要做一个专用的Controller也挺麻烦的,我以前就直接采用其它第

谈谈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的重构优化是伴随着发布的,没做完的功能也

Webkit中HTML5 Video的实现分析(六) - Safari视频机制分析

Safari中的视频相关操作封装在QuickTime Plugin里面,存放于/Library/Internet Plugin目录下.   下图是相关类的class diagram: 其中的QuickTime Plugin是通过已淘汰的Apple之前定义的Webkit Plugin协议来实现的,而不是现在支持的Netscape API的机制. 可以参考以下文档:        Introduction to WebKit Plugin Programming Topic           We