App如何适应 iPhone 5s/6/6 Plus 三种屏幕的尺寸

本文深入探讨了iOS应用开发中如何应对不同屏幕尺寸和像素密度的挑战,详细介绍了从初代iPhone到iPhone6Plus的发展历程,重点阐述了如何通过使用点作为单位、AutoLayout技术、启动图片适配以及图片尺寸调整等方法实现应用的兼容性和优化。文章还提供了设计和开发过程中的一系列建议,旨在帮助开发者更好地应对多屏设备的适配问题。

55.jpg

初代 iPhone

2007 年,初代 iPhone 发布,屏幕的宽高是 320 x 480 像素。下文也是按照宽度,高度的顺序排列。这个分辨率一直到 iPhone 3GS 也保持不变。

那时编写 iOS 的 App(应用程序),只支持绝对定位。比如一个按钮(x, y, width, height) = (20, 30, 40, 50),就表示它的宽度是 40 像素,高度是 50 像素,放在(20, 20)像素的位置。

iPhone 4

2010 年,iPhone 4 发布,率先采用 Retina 显示屏,在屏幕的物理尺寸不变的情况下,像素成倍增加,达到 640 x 960 像素。

这样就出现一个问题,怎么让原有的 App 运行在新的手机上面?iPhone 手机一个优势,就是有众多优秀的 App,假如不兼容原有的 App,就相当于放弃这个得来不易的优势,是很不明智的。

每当 iPhone 的屏幕有所变化,比如 iPhone 3GS 过渡到 iPhone 4, iPhone 4 过渡到 iPhone 5, iPhone 5 过渡到 iPhone 6,苹果公司都需要想办法来解决上述的兼容问题。

为了运行之前的 App,引入一个新的概念 point(点)。点这个概念在 iOS 开发中十分重要,而实际用户很少关注。iPhone 4 屏幕尺寸继续保持 320 x 480,不过单位并非是像素,而是点。

  • 在 iPhone 3GS 中,1 个点等于 1 个像素。也就是说,点跟像素可以直接互换。

  • 在 iPhone 4 中,1 个点等于 2 个像素。

这篇文章中,我将点和像素当成一维的长度单位,而非二维的面积单位,这样对于我来说更自然些,因此 1 个点等于 2 个像素。别的文章中可能会说 1 个点等于 4 个像素,其实是指 1 个点占据了 4 个像素的面积,这样也没有说错,注意上下文语境。

iPhone 4 和 iPhone 3GS 的屏幕尺寸实际上是一样的,都是 3.5 英寸。同样一个点,实际尺寸看起来是一样的。只是 iPhone 4 在单位英寸上像素更多,看起来更细腻。

开发 iOS 的时候,使用点作为基本单位会更加方便,列表对比:

45.jpg

这里的屏幕模式可以初步理解成,一个点等于多少个像素。2x,就是 1 个点等于 2 个像素。

总结一下单位

  • 手机屏幕的物理长度,使用英寸作为单位。比如 iPhone 4 屏幕是 3.5 英寸,iPhone 5 是 4 英寸,iphone 6 是 4.7 英寸,这里的数字是指手机屏幕对角线的物理长度。

  • 屏幕像素,比如 iPhone 3GS 屏幕是 320 x 480 像素,iPhone 4 是 640 x 960 像素,这里的像素可以想象成屏幕上真正用来显示颜色的发光小点。

  • 点,开发 App 时候使用的单位,是一个虚拟的单位,并非实际存在的,因此点有时也叫虚拟点。点这个单位,用于屏蔽各个屏幕设备的不同,兼容以前的程序。

每英寸有多少个像素,称为 ppi(pixel per inch)。iPhone 4 的屏幕是 640 x 960 像素,3.5 英寸,我们没有宽高的实际尺寸,就按照对角线来粗略计算它的 ppi。将像素当做长度单位,根据勾股定理,对角线就是 1154 像素。屏幕对角线的实际长度为 3.5 英寸,也就是 1154 像素除以 3.5 英寸,得出 330ppi。而官方给出的数字是 326ppi。当像素太密,超过 300ppi 的时候,人眼也就不能区分出每个像素。因此 iPhone 4 的屏幕叫作 Retina 显示屏。Retina 在英文中,是视网膜的意思。

iPhone 4 之后(x, y, width, height) = (20, 30, 40, 50),就表示高度为 40 个点,宽度为 50 个点,放在(20, 20)个点的位置。这种处理方法,将之前以像素作为单位自动转换成以点作为单位,使得 iPhone 3GS 的应用程序,不用修改也可运行在 iPhone 4 上面。

文字,颜色等是矢量数据,放大不会失真。原有的 iPhone 3GS 程序,在 iPhone 4 上面运行,文字显示也十分清晰。

而图片并非矢量数据,处理方式有所不同。假设图片 example.png,大小为 30 x 40 像素(这里的单位是像素,数字图片的单位通常都为像素)。当这张 example.png 在 iPhone 3GS 和 iPhone 4 中使用时候,都占据屏幕上 30 x 40 个点。而因为 iPhone 4 中 1 个点等于 2 个像素,也就是 30 x 40 像素的图片,占据了 60 x 80 像素的屏幕,因此这图片在 iPhone 4 中看起来就会模糊。

开发的时候,为使得图片清晰,需要进行图片适配。这时需要准备两张内容相同的图片,放在同一目录下。

example.png      // 30 x 40 像素

example@2x.png   // 60 x 80 像素

当程序中使用 example.png 的时候,会根据屏幕模式自动选择对应的图片。屏幕 1x 模式,就会选择 example.png, 2x 模式就会优先选择 example@2x.png,假如 example@2x.png 不存在,就选择 example.png。

图片跟屏幕一样,也有 1x 模式,2x 模式。在 iPhone 6 Plus 中,还出现 3x 模式,原理是一样的。

当 iPhone 4 选中 example@2x.png 的图片,就会生成一张大小为 30 x 40 个点,2x 模式的图片。这个时候,图片看起来就会很清晰了。而没有适配的旧程序,example@2x.png 不存在,就选中 example.png,生成大小为 30 x 40 个点,1x 模式的图片,看起来比较模糊。但它们占据的屏幕点数是一样的。

iPhone 5

2012 年,苹果发布 iPhone 5。我们将所有机型对比,依然采用点作为单位。

22.jpg

跟 iPhone 4 做比较, iPhone 5 的宽度保持不变。高度增加 568 - 480 = 88 个点。

在 iOS 开发中,44 这个数字比较特殊。iOS 界面指南写着,人类的手指有一定大小,点击区域低于 44 个点的时候,就难以点中。44 的两倍就是 88。

当原有程序没有适配 iPhone 5 的时候,也可以正常运行,但多出来的 88 个点将会将会被自动均分为上下两部分,使得上下出现黑边。我找不到好看的图片。

46.jpg

那么怎样才能告诉 iOS 系统,应用程序已经适配了 iPhone 5 呢?在这里,我们先扯开一下,谈一下启动图片。

点击主屏幕的图标,进入 App 的时候,会立即显示一张图片,这张图片就是启动图片(Launch Image)。App 在正式启动的时需要做一些初始化处理,这通常比较费时。先出现启动图片,可以使用户觉得系统立即有响应,减少等待的焦虑感。

每个机型,比如同时支持 iPhone 和 iPad 的程序,需要分别为 iPhone 跟 iPad 指定启动图片。当旧的 iPhone 4 的程序,运行在 iPhone 5 上面,没有 iPhone 5 的启动图片,就采用兼容模式,上下留黑边。当为 iPhone 5 指定了新的启动图片,系统就认为这个应用程序是已经适配了 iPhone 5 的,上下就不会留黑边了。下面是微信启动图片,应该都很熟悉了。

47.jpg

微信启动图片中出现的那个地球,叫蓝色弹珠(The Blue Marble),是在 1972 年 12 月 7 日由阿波罗 17 号太空船的船员所拍摄的。这张照片当年很震撼,是普通人第一次可以通过照片直接看到地球的全貌。见问题为什么微信启动界面的地球图片没有转到中国这部分?这是否有损用户体验

微信的启动图,为适配 iPhone 5,相比与 iPhone 4, 很明显狭长了。

典型 iPhone 应用程序(游戏除外),很多是上面一个导航栏,下面一个工具栏或者标签栏, 中间一大块用于显示的内容区。iPhone 5 拉长了,对于程序的适配,也不算麻烦,内容区的内容基本是动态生成的。适配时候可以简单上下不变,中间的内容区拉长就行了。注意,导航栏和工具栏的高度也是 44 个点。下面是同一程序,在 iPhone 4 跟 iPhone 5 的对比。

AutoLayout

到了这个时候,传统绝对定位的弱点就显露出来了。这时 iPhone 按照点作为单位,已经出现了两种不同尺寸的屏幕,算上 iPad, 就有 3 种尺寸(有些 App 可以同时兼容 iPhone 和 iPad,称为 Universal)。

从iOS 6系统发布后,iOS开发中可以采用一种 AutoLayout 的技术。AutoLayout 就像网页一样,指定 View,Button,Text 之间的相对位置,比如靠左多少,靠右多少,居中多少等等。举个例子,像下面的简单布局。

26.jpg

假设左上角的区域为 view1, 右上角的区域为 view2, 下面的区域为 view3。AutoLayout 会说:

1
2
3
4
5
6
7
8
9
10
11
12
view1.left = 20                // View1 的左边距离边界 20 个点
view1.top = 20                 // View1 的上边距离边界 20 个点
view2.right = 20               // View2 的右边距离边界 20 个点
view2.top = 20                 // View2 的上边距离边界 20 个点
view2.left = view1.right + 20  // View2 的左边距离 View1 右边 20 个点
view2.width = view1.width      // View1 的宽度等于 View2 的宽度
view2.height = view1.height    // view1 高度等于 view2 高度
view3.left = view1.left        // view3 的跟 view1 左对齐
view3.right = view2.right      // view3 跟 view2 右对齐
view3.top = view1.bottom + 20  // view3 的上边距离 view1 下边 20 个点
view3.bottom = 20              // view3 下边距离边界 20 个点
view3.height = view1.height    // view3 高度等于 view1 高度

指定上面的约束条件后,AutoLayout 就会自动算出对应的布局。上面我写得比较繁琐,事实上很多操作都是可以使用鼠标拖拉来指定的,并不一定需要使用代码。但就算用代码,也有简写的方法。下面是在 xib 中,拖拉鼠标指定约束时的界面。

19.jpg

而绝对定位,会直接说

1
2
3
view1.frame = (x1, y1, width1, height1)
view2.frame = (x2, y2, width2, height2)
view3.frame = (x3, y3, width3, height3)

绝对定位并非指定约束条件,而是开发者自己来精确指定 View,Button, Text 等的实际坐标大小。

对于一个屏幕,绝对定位可能跟 AutoLayout 的区别不算大,甚至绝对定位会更方便些。但当需要同时适配多个屏幕,AutoLayout 根本不需要更改。而绝对定位就需要根据屏幕大小,一个个算出来。比如横屏,在 AutoLayout 下面,就自动变成:

18.jpg

这里不过是 3 个控件的布局,当出现的控件数越多,屏幕尺寸越多,AutoLayout 的优势就显露出来了。另外 AutoLayout 有个好处是容易支持多语言,不同语言下,同一个意思文字的长度是不同的,使用 AutoLayout 也可以自动适配。

在 iOS 6 的时候,AutoLayout 还比较少人使用,当时屏幕尺寸还比较少。iOS 7 的时候,就开始很多人使用了。而到现在 iOS 8 了, 更加上 iPhone 6, iPhone 6 Plus 需要适配,AutoLayout 大势所趋,不用不行了。

iPhone 6和iPhone 6 Plus

2014 年,iPhone 6和iPhone 6 Plus 发布后,情况又有新的变化。再次比较所有 iPhone 机型。

17.jpg

屏幕尺寸再度分裂。但是我们比较 iPhone 5 跟 iPhone 6 的宽高比例。

16.jpg

可以看出,iPhone 6 跟 iPhone 5 虽然屏幕尺寸改变了,但是它们的比例是不变的。都是 9 ÷ 16 = 0.5625 的屏幕。

当旧的 iPhone 5 程序运行在 iPhone 6 上面,假如没有经过适配,旧程序自动等比放大,铺满新手机,旧程序也可以正常运行。这种方案可算是自动适配。但因为旧程序拉伸了,整体看起来有点虚,也不能更好利用大屏空间。

当需要开发者手动适配的时候,跟 iPhone 4 过渡到 iPhone 5 一样,在新程序中,指定一张新的启动图片。当指定了启动图,屏幕分辨率就已经变成应有的大小,这时候利用 AutoLayout 进行布局,同一份代码,就可以支持多个机型。新手机的屏幕更大,有更多的虚拟点,可以显示更多的内容。

值得注意一点是,iPhone 6 Plus。它的宽高是 414 × 736 个点,3x 模式,理想上来说,应该有 1242 × 2208 像素。但 iPhone 6 Plus 的实际像素是 1080 × 1920,是比理想值要少一点的。iPhone 6 Plus 的处理方式是将程序整体稍微缩小一点。分辨率很高,这点区别,实际上也看不出来。

那为什么需要这样做呢?上面表格中 iPhone 6, iPhone 6 Plus 屏幕宽高的逻辑点的数字是怎么来的?下面我猜测一下原因,但不能证实。

先看 iPhone 6,这个比较简单。iPhone 6 的屏幕宽高比例跟 iPhone 5 一样,使用对角线来计算,就是放大了 4.7 ÷ 4 = 1.175 倍。用这个数字,乘以 iPhone 5 的 320 x 568 个点,忽略误差,差不多就是 iPhone 6 屏幕的 375 x 667 个点。这里需要注意,屏幕宽高比例一样,才能使用对角线来计算。

按照上面的方式来计算 iPhone 6 Plus, 应该是得到 440 x 781 个点,实际上却是 414 × 736 个点。这里我猜测是因为,iPhone 6 Plus 屏幕明显更大,相同尺寸的点放在大的屏幕上面,会使得人感觉尺寸变小,所以就将每个点的实际尺寸放大一些,从而得到更少的点数目。人眼看东西会有种错觉,并非是孤立的看的,而是跟周围的环境作比较。

确定了点数目之后,再确定了像素 1080 × 1920(很多高清电视就是这个尺寸),应该是 1080/414=2.6x,但 2.6x 这个数字开发就太麻烦了,就按照 3x 来处理。其实假如像素达到 1242 × 2208,3x 下也可以精确到 1:1, 这样会更好。但现今的技术在考虑电池,处理器,屏幕尺寸等综合因素下,很可能达不到这样的细腻程度。

上述只是猜测,我相信那些手机参数是经过反复考虑再确定的。iPhone 6 Plus 这个处于手机跟平板中间地带的产物经过不少特殊处理。

由分析可以看到,慢慢的为了适配多个机型,程序的启动图片也逐渐增多,为解决这个问题。iOS 8 之后,可以使用 xib 来搭建启动界面,这样就可以同一个启动界面,适配多个机型,减少启动图片占用的空间。

建议

  • 以后的应用程序,都使用 AutoLayout, 不要再用绝对定位。

  • 使用类似网页的方式来设计界面。

  • 设计师好,程序员也好,尽量使用点这个单位进行思考,而不要使用像素。比如,你需要做 44 x 66 个点的按钮,2x 模式,就乘以 2, 3x 模式就乘以 3。这样的思考方式可以大致估计到真实的物理长度。44 个点,就是手机上导航栏,工具栏的高度。假如用像素思考,容易使得做出的图片过大或者过小。

  • 非矢量素材,就可以做尺寸最大的,之后再进行缩小。比如你需要兼容 3x 的屏幕,就直接做最高那种图片。

  • 而当使用 Flash 之类的矢量工具来做素材的时候,应该直接做点那个尺寸。比如 44 x 66 个点的按钮。就建立一个 44 x 66 的场景。之后再导出成 2 倍图,3 倍图,因为矢量放大不失真。不要建立一个 3x 的场景,导出成大图片,再进行缩小,这样就容易失真。更理想的是直接使用矢量图。

  • 假如是那种导航栏,工具栏之类的背景图,需要横跨整个屏幕。可以只切一小块,让程序拉伸,拉伸方式是保持两边的像素不动,只拉伸最中间的一列像素。需要拉伸的话,横方向就不要出现一些渐变色。

  • 按钮的点击区域,不应该少于 44 像素,就算按钮的图片看起来比较小,也应该使得点按钮周围的透明区也有反应。

  • 可以按照你当前最方便测试机子的型号来做一些主要预览图,效果图。比如你手头有 iPhone 5,可以按照 iPhone 5 的尺寸,320 x 568 个点,需要兼容 iPhone 6 Plus,就使用 3x 的模式。这样方便将图片放进手机里面看实际的效果。有多个测试机,就选较大的,之后再进行一些细调。假如支持 iPhone 6 Plus 的横屏模式,需要另外处理。

  • 上面说的是应用的处理方式,游戏会有些特殊。现在很多游戏,按照 1136 x 768 的像素尺寸来设计场景,这样可以同时兼容 iPad 和 iPhone,并只使用一份图。iPad 1x 模式下尺寸是 1024 x 768 像素,iPhone 5 在 2x 模式下,是 1136 * 640 像素。这种尺寸,可以将场景居中显示,各自将场景拉伸到最大。

  • 转载地址:http://www.cocoachina.com/ios/20150130/11076.html
当应用中调用5+ API对应的模块在5+ Runtime中不包含时弹出标题为“HTML5+ Runtime”提示框:HBuilder|HBuilderX真机运行提示内容为打包时未添加push模块,请参考http://ask.dcloud.net.cn/article/283” 我怎么在manifest.json里配置push模块,下面是源码视图,我该怎么加push模块?这里拿来的后台运行模块?如果有请告诉我怎么添加或者打开{ "@platforms" : [ "android", "iPhone", "iPad" ], "id" : "H53710005", /*应用的标识*/ "name" : "巡检", /*应用名称,程序桌面图标名称*/ "version" : { "name" : "1.0", /*应用版本名称*/ "code" : "100" }, "description" : "", /*应用描述信息*/ "icons" : { "72" : "icon.png" }, "launch_path" : "index.html", /*应用的入口页面,默认为根目录下的index.html;支持网络地址,必须以http://或https://开头*/ "developer" : { "name" : "", /*开发者名称*/ "email" : "", /*开发者邮箱地址*/ "url" : "" /*开发者个人主页地址*/ }, "permissions" : { "NFC" : { "description" : "NFC读写权限" }, "Accelerometer" : { "description" : "访问加速度感应器" }, "Audio" : { "description" : "访问麦克风" }, "Messaging" : { "description" : "短彩邮件插件" }, "Cache" : { "description" : "管理应用缓存" }, "Camera" : { "description" : "访问摄像头" }, "Console" : { "description" : "跟踪调试输出日志" }, "Contacts" : { "description" : "访问系统联系人信息" }, "Device" : { "description" : "访问设备信息" }, "Downloader" : { "description" : "文件下载管理" }, "Events" : { "description" : "应用扩展事件" }, "File" : { "description" : "文件读写权限" }, "Gallery" : { "description" : "访问系统相册" }, "Geolocation" : { "description" : "访问位置信息" }, "Invocation" : { "description" : "使用Native.js能力" }, "Orientation" : { "description" : "访问方向感应器" }, "Proximity" : { "description" : "访问距离感应器" }, "Storage" : { "description" : "管理应用本地数据" }, "Uploader" : { "description" : "管理文件上传任务" }, "Runtime" : { "description" : "访问运行期环境" }, "XMLHttpRequest" : { "description" : "跨域网络访问" }, "Zip" : { "description" : "文件压缩与解压缩" }, "Barcode" : { "description" : "管理二维码扫描插件" }, "Maps" : { "description" : "管理地图插件" }, "Speech" : { "description" : "管理语音识别插件" }, "Webview" : { "description" : "窗口管理" }, "NativeUI" : { "description" : "原生UI控件" }, "Navigator" : { "description" : "浏览器信息" }, "NativeObj" : { "description" : "原生对象" }, "SQLite" : {} }, "plus" : { "userAgent" : "", "allowsInlineMediaPlayback" : false, "uniStatistics" : { "enable" : false }, "safearea" : { "background" : "#FFFFFF", "bottom" : { "offset" : "auto" } }, "launchwebview" : { "id" : "1", "kernel" : "WKWebView", "uniNView" : { "flexDirection" : "column" } }, "nfc" : { "description" : "NFC功能配置" }, "splashscreen" : { "autoclose" : true, /*是否自动关闭程序启动界面,true表示应用加载应用入口页面后自动关闭;false则需调plus.navigator.closeSplashscreen()关闭*/ "waiting" : true /*是否在程序启动界面显示等待雪花,true表示显示,false表示不显示。*/ }, "popGesture" : "close", /*设置应用默认侧滑返回关闭Webview窗口,"none"为无侧滑返回功能,"hide"为侧滑隐藏Webview窗口。参考http://ask.dcloud.net.cn/article/102*/ "runmode" : "liberate", /*应用的首次启动运行模式,可取liberate或normal,liberate模式在第一次启动时将解压应用资源(Android平台File API才可正常访问_www目录)*/ "signature" : "Sk9JTiBVUyBtYWlsdG86aHIyMDEzQGRjbG91ZC5pbw==", /*可选,保留给应用签名,暂不使用*/ "permissions" : [ "nfc" ], "distribute" : { "apple" : { "appid" : "", /*iOS应用标识,苹果开发网站申请的appid,如io.dcloud.HelloH5*/ "mobileprovision" : "", /*iOS应用打包配置文件*/ "password" : "", /*iOS应用打包个人证书导入密码*/ "p12" : "", /*iOS应用打包个人证书,打包配置文件关联的个人证书*/ "devices" : "universal", /*iOS应用支持的设备类型,可取值iphone/ipad/universal*/ "frameworks" : [] /*调用Native.js调用原生Objective-c API需要引用的FrameWork,如需调用GameCenter,则添加"GameKit.framework"*/ }, "google" : { "packagename" : "", /*Android应用包名,如io.dcloud.HelloH5*/ "keystore" : "", /*Android应用打包使用的密钥库文件*/ "password" : "", /*Android应用打包使用密钥库中证书的密码*/ "aliasname" : "", /*Android应用打包使用密钥库中证书的别名*/ "permissions" : [ "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>", "<uses-permission android:name=\"android.permission.NFC\" />", "<uses-permission android:name=\"android.permission.INTERNET\" />", "<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />", "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />", "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", "<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>", "<uses-permission android:name=\"android.permission.VIBRATE\"/>", "<uses-permission android:name=\"android.permission.READ_LOGS\"/>", "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", "<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>", "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.CAMERA\"/>", "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>", "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>", "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>", "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>", "<uses-feature android:name=\"android.hardware.camera\"/>", "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>" ], "intentFilters" : [ { "action" : [ "android.nfc.action.NDEF_DISCOVERED", "android.nfc.action.TAG_DISCOVERED", "android.nfc.action.TECH_DISCOVERED" ], "category" : [ "android.intent.category.DEFAULT" ] } ], "features" : [ "<uses-feature android:name=\"android.hardware.nfc\" android:required=\"true\" />" ], "schemes" : "" }, /*使用Native.js调用原生安卓API需要使用到的系统权限*/ "orientation" : [ "portrait-primary" ], /*应用支持的方向,portrait-primary:竖屏正方向;portrait-secondary:竖屏反方向;landscape-primary:横屏正方向;landscape-secondary:横屏反方向*/ "icons" : { "ios" : { "prerendered" : true, /*应用图标是否已经高亮处理,在iOS6及以下设备上有效*/ "auto" : "", /*应用图标,分辨率:512x512,用于自动生成各种尺寸程序图标*/ "iphone" : { "normal" : "", /*iPhone3/3GS程序图标,分辨率:57x57*/ "retina" : "", /*iPhone4程序图标,分辨率:114x114*/ "retina7" : "", /*iPhone4S/5/6程序图标,分辨率:120x120*/ "retina8" : "", /*iPhone6 Plus程序图标,分辨率:180x180*/ "spotlight-normal" : "", /*iPhone3/3GS Spotlight搜索程序图标,分辨率:29x29*/ "spotlight-retina" : "", /*iPhone4 Spotlight搜索程序图标,分辨率:58x58*/ "spotlight-retina7" : "", /*iPhone4S/5/6 Spotlight搜索程序图标,分辨率:80x80*/ "settings-normal" : "", /*iPhone4设置页面程序图标,分辨率:29x29*/ "settings-retina" : "", /*iPhone4S/5/6设置页面程序图标,分辨率:58x58*/ "settings-retina8" : "", /*iPhone6Plus设置页面程序图标,分辨率:87x87*/ "app@2x" : "unpackage/res/icons/120x120.png", "app@3x" : "unpackage/res/icons/180x180.png", "notification@2x" : "unpackage/res/icons/40x40.png", "notification@3x" : "unpackage/res/icons/60x60.png", "settings@2x" : "unpackage/res/icons/58x58.png", "settings@3x" : "unpackage/res/icons/87x87.png", "spotlight@2x" : "unpackage/res/icons/80x80.png", "spotlight@3x" : "unpackage/res/icons/120x120.png" }, "ipad" : { "normal" : "", /*iPad普通屏幕程序图标,分辨率:72x72*/ "retina" : "", /*iPad高分屏程序图标,分辨率:144x144*/ "normal7" : "", /*iPad iOS7程序图标,分辨率:76x76*/ "retina7" : "", /*iPad iOS7高分屏程序图标,分辨率:152x152*/ "spotlight-normal" : "", /*iPad Spotlight搜索程序图标,分辨率:50x50*/ "spotlight-retina" : "", /*iPad高分屏Spotlight搜索程序图标,分辨率:100x100*/ "spotlight-normal7" : "", /*iPad iOS7 Spotlight搜索程序图标,分辨率:40x40*/ "spotlight-retina7" : "", /*iPad iOS7高分屏Spotlight搜索程序图标,分辨率:80x80*/ "settings-normal" : "", /*iPad设置页面程序图标,分辨率:29x29*/ "settings-retina" : "", /*iPad高分屏设置页面程序图标,分辨率:58x58*/ "app" : "unpackage/res/icons/76x76.png", "app@2x" : "unpackage/res/icons/152x152.png", "notification" : "unpackage/res/icons/20x20.png", "notification@2x" : "unpackage/res/icons/40x40.png", "proapp@2x" : "unpackage/res/icons/167x167.png", "settings" : "unpackage/res/icons/29x29.png", "settings@2x" : "unpackage/res/icons/58x58.png", "spotlight" : "unpackage/res/icons/40x40.png", "spotlight@2x" : "unpackage/res/icons/80x80.png" }, "appstore" : "unpackage/res/icons/1024x1024.png" }, "android" : { "mdpi" : "", /*普通屏程序图标,分辨率:48x48*/ "ldpi" : "", /*大屏程序图标,分辨率:48x48*/ "hdpi" : "unpackage/res/icons/72x72.png", /*高分屏程序图标,分辨率:72x72*/ "xhdpi" : "unpackage/res/icons/96x96.png", /*720P高分屏程序图标,分辨率:96x96*/ "xxhdpi" : "unpackage/res/icons/144x144.png", /*1080P 高分屏程序图标,分辨率:144x144*/ "xxxhdpi" : "unpackage/res/icons/192x192.png" } }, "splashscreen" : { "ios" : { "iphone" : { "default" : "", /*iPhone3启动图片选,分辨率:320x480*/ "retina35" : "", /*3.5英寸设备(iPhone4)启动图片,分辨率:640x960*/ "retina40" : "", /*4.0 英寸设备(iPhone5/iPhone5s)启动图片,分辨率:640x1136*/ "retina47" : "", /*4.7 英寸设备(iPhone6)启动图片,分辨率:750x1334*/ "retina55" : "", /*5.5 英寸设备(iPhone6 Plus)启动图片,分辨率:1242x2208*/ "retina55l" : "" /*5.5 英寸设备(iPhone6 Plus)横屏启动图片,分辨率:2208x1242*/ }, "ipad" : { "portrait" : "", /*iPad竖屏启动图片,分辨率:768x1004*/ "portrait-retina" : "", /*iPad高分屏竖屏图片,分辨率:1536x2008*/ "landscape" : "", /*iPad横屏启动图片,分辨率:1024x748*/ "landscape-retina" : "", /*iPad高分屏横屏启动图片,分辨率:2048x1496*/ "portrait7" : "", /*iPad iOS7竖屏启动图片,分辨率:768x1024*/ "portrait-retina7" : "", /*iPad iOS7高分屏竖屏图片,分辨率:1536x2048*/ "landscape7" : "", /*iPad iOS7横屏启动图片,分辨率:1024x768*/ "landscape-retina7" : "" /*iPad iOS7高分屏横屏启动图片,分辨率:2048x1536*/ } }, "android" : { "mdpi" : "", /*普通屏启动图片,分辨率:240x282*/ "ldpi" : "", /*大屏启动图片,分辨率:320x442*/ "hdpi" : "", /*高分屏启动图片,分辨率:480x762*/ "xhdpi" : "", /*720P高分屏启动图片,分辨率:720x1242*/ "xxhdpi" : "" /*1080P高分屏启动图片,分辨率:1080x1882*/ } }, "ios" : { "dSYMs" : false }, "plugins" : { "push" : {} } } }, "screenOrientation" : [ "portrait-primary" ] }
最新发布
12-12
<think>根据提供的manifest.json源码视图,我们需要添加push模块。在DCloud的5+ Runtime中,要使用push模块,需要在manifest.json的"permissions"节点下添加"Push"权限,并且在"plus"->"distribute"->"plugins"节点下配置push插件的具体参数。 但是,从你提供的manifest.json中,我们可以看到: 1. 在"permissions"节点下已经有很多权限,但没有Push。 2. 在"plus"->"distribute"->"plugins"节点下已经有一个空的push插件配置("push": {}),这表示已经添加了push插件,但可能没有配置参数。 然而,根据错误提示“打包时未添加push模块”,可能是因为在"permissions"节点下没有添加Push权限。 所以,我们需要做以下两步: 步骤1:在"permissions"节点下添加Push权限。 步骤2:确保在"distribute"->"plugins"节点下配置了push插件(从提供的代码看已经存在,但可能需要根据具体需求配置参数,比如厂商推送配置等,但至少要有这个节点)。 修改"permissions"节点,添加Push权限: 在"permissions"节点内添加一个属性: "Push": { "description": "推送消息功能" } 另外,你提到的后台运行模块,如果是指Push模块的后台运行能力,通常Push模块在配置后,在真机运行时需要确保打包时勾选了Push模块。在manifest.json中配置了Push权限和插件后,在云打包时就会包含该模块。 但是,请注意:在真机运行调试时,如果本地没有配置push模块,也会出现此提示。因此,我们需要在manifest.json中正确配置。 修改后的manifest.json中permissions部分(添加Push): ```json "permissions": { ... // 原有的权限 "Push": { "description": "推送消息功能" } } ``` 同时,检查在"plus"->"distribute"->"plugins"节点下是否已经配置了push插件。从你提供的代码中已经存在: ```json "plugins": { "push": {} } ``` 这个空的配置表示使用默认配置。如果需要配置厂商推送(如小米、华为等),则需要在此处添加具体配置。但如果没有特殊要求,空配置也可以,表示使用DCloud的统一推送。 因此,我们只需要在permissions里添加Push权限即可。 修改后的manifest.json片段(只展示修改部分): 在permissions对象里添加: "Push": { "description": "推送消息功能" } 注意:因为你的manifest.json中已经有一个"permissions"对象,我们只需要在对象内添加一项。 另外,你提到是否有后台运行模块?在5+ Runtime中,Push模块在接收到推送消息时,会尝试唤醒应用(即使应用在后台或关闭),所以Push模块本身就包含了后台运行的能力。在Android平台上,为了确保推送服务在后台运行,通常需要在manifest.json的"plus"->"distribute"->"google"->"permissions"节点下添加必要的权限(比如唤醒锁、网络访问等),但通常这些权限已经在默认权限中包含了。你可以检查一下,如果没有,可能需要添加。 从你提供的代码中,google的permissions已经包含了很多权限,其中包括网络权限和唤醒锁等,所以应该没问题。 总结修改步骤: 1. 在manifest.json的"permissions"节点下添加Push权限。 2. 确保plugins中配置了push插件(已有,所以不用改)。 修改后的manifest.json(部分)如下: </think> 根据你的需求,需要在 manifest.json 中配置 push 模块来解决 "打包时未添加push模块" 的错误。以下是解决方案: ### 修改步骤: 1. **添加 Push 模块权限**:在 `permissions` 节点中添加 Push 模块 2. **启用 Push 插件**:在 `plus -> distribute -> plugins` 节点中配置 Push 插件 3. **添加后台运行权限**(可选):如需后台运行功能,添加 Background 权限 ### 修改后的 manifest.json 代码: ```json{4,9-11} { "@platforms": ["android", "iPhone", "iPad"], "id": "H53710005", "name": "巡检", // ... 其他原有配置保持不变 ... "permissions": { // ... 原有权限配置 ... "Push": { "description": "消息推送功能" }, "Background": { "description": "后台运行功能" } }, "plus": { // ... 其他配置 ... "distribute": { // ... 其他配置 ... "plugins": { "push": { // 可添加具体推送配置(如厂商通道配置) }, "background": { // 后台运行配置(可选) } } } }, // ... 其他配置 ... } ``` ### 关键修改说明: 1. **添加 Push 权限**: ```json "Push": { "description": "消息推送功能" } ``` 这向 5+ Runtime 声明需要使用推送功能 2. **配置 Push 插件**: ```json "plugins": { "push": {} } ``` 即使为空对象 `{}` 也必须存在,否则打包时不会包含推送模块 3. **后台运行模块**: ```json "Background": { "description": "后台运行功能" } ``` 这是后台运行所需的权限,在 `plugins` 中对应添加: ```json "background": {} ``` ### 验证方法: 1. 保存修改后的 manifest.json 2. 重新进行真机运行/云端打包 3. 检查应用启动时是否还会弹出模块缺失提示 ### 注意事项: 1. **厂商推送配置**:如需小米/华为等厂商推送,需在 `push` 配置中添加具体参数: ```json "push": { "xiaomi": { "appid": "小米推送APPID", "appkey": "小米推送APPKEY" } } ``` 2. **后台运行限制**:iOS 后台运行有严格限制,需在 `plus -> background` 中配置具体后台模式 ### 补充说明: 如果只需要解决当前报错,**只需添加 Push 权限和 push 插件配置**。后台运行模块(Background)是可选项,根据实际需求添加。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值