如何获取设备屏幕信息
今天我们来聊聊获取设备屏幕的分辨率,DPI,屏幕尺寸,缩放因子等信息。
在 OpenRTB 中,关于设备屏幕的信息有以下四个属性:
Attribute | Type | Definition |
---|---|---|
h | integer | Physical height of the screen in pixels. |
w | integer | Physical width of the screen in pixels. |
ppi | integer | Screen size as pixels per linear inch. |
pxratio | float | The ratio of physical pixels to device independent pixels. |
其中 w
, h
对应屏幕物理宽高的像素值。
ppi
是每英寸的像素个数,不过对于 Android 设备,通常它又被称作 dpi(Dots Per Inch,每英寸点数)。
pxratio
是物理像素与设备无关像素的比率,也被称为缩放因子(scale factor)。
下面我们来就 Android 和 iOS 设备来分别讨论如何获取这些信息。
获取 Android 设备的屏幕信息
对于 Android 设备来说,这些信息都可以通过 DisplayMetrics
类来获取。所有首先要获取一个有效的 DisplayMetrics
对象。
static DisplayMetrics getDisplayMetrics(Context context) { |
getRealMetrics
这个方法是在 Android 4.2 之后增加的,跟 getMetrics
相比,通过 getRealMetrics
获取到的屏幕分辨率是屏幕的真正分辨率,而 getMetrics
获取到的屏幕分辨率是去掉了屏幕底部虚拟按键高度的分辨率。在这之前的设备可能也不支持虚拟按键,所以,也就没有这个区分。
有了 DisplayMetrics
对象之后,我们就可以通过它来获取上面四个属性了,通常我们会这样来写:
DisplayMetrics dm = getDisplayMetrics(context); |
但是这样写真的对吗?对于 w
, h
和 pxratio
这三个的值来说,没什么问题,但是对于 dpi
来说,通过这种方式获取到的值其实是不对的。
在 Android 系统中,density
和 densityDpi
之间其实有一个固定的关系:
densityDpi == (int)(density * 160) |
所以,它俩相当于同一个概念的两种不同表示方法。而我们实际要获取的 dpi
应该按照如下方式来获取:
int w = dm.widthPixels; |
上面的计算中,width
是水平英寸数,height
是竖直英寸数,size
是对角线的长度,也就是通常我们说的手机尺寸。
然后通过对角线的像素个数除以手机尺寸,获得的才是 OpenRTB 中所说的 ppi
。
获取 iOS 设备的屏幕信息
对于 iOS 系统来说,w
, h
和 pxratio
这三个值跟 Android 一样,可以比较方便的直接获取。
CGSize size = [UIScreen mainScreen].nativeBounds.size; |
但需要注意,不要用 bounds
和 scale
这两个代替上面的 nativeBounds
和 nativeScale
。
因为 bounds
获取到的是设备无关像素(在 iOS 中被称为 Point
)的分辨率。而 scale
是渲染像素(Rendered Pixels
)跟设备无关像素(Point
)的比值。
在 iOS 上获取 ppi
就没有上面那么幸运了,因为 iOS 没有提供直接获取 ppi
的方法。但因为我们前面讲过 iOS 设备可以获取设备型号,所以我们可以通过做一张设备型号与 ppi
的对照表来返回对应设备的 ppi
,下面是到目前为止所有 iOS 设备的型号与 ppi
对照表:
static const NSDictionary *modelPPIs; |
接下来只要通过我们在第一篇中介绍的方法先获取设备型号,再来查这个表就可以了。
不过需要注意,如果是模拟器设备的话,获取到的设备型号是 x86_64
,并不在这张表中,所以在查表之前最好先判断一下。
另外,如果是采用 API 方式来进行广告对接的话,关于 iOS 设备 ppi
的获取,最好是在服务器端通过这种表格的方式来查询,因为如果苹果出了新设备,客户端来不及更新的话,在新设备上就无法获取到正确的 ppi
。但是在服务器端是可以做到及时更新生效的。