绝大多数的 App 都要和相册打交道,选择照片或者视频,要么用来发个朋友圈,要么是放到什么地方做个背景。从 AssertLibrary 到 Photos 框架,苹果已经在多年之前就给相册相关的 API 做过一次大升级了。
通过 Photos 框架,只需要通过下面几步就可以从相册获取到内容了
1、获取相册权限 2、建立 UI 展示相册内容 3、响应用户操作,获取照片或视频的 PHAsset 对象 4、通过 PHImageManager 导出照片或者视频
作为一个合格的开发者,对上面这些步骤基本上都能驾轻就熟了。不过虽然看似简单的几步,其实依然存在着巨大的工作量,特别是建立 UI 并展示相册内容这一条,如果要做到细节完善、体验顺畅,基本上属于一个小型 App 的工作量了。所以很多时候我们会选择使用一些第三方的框架,目前可供选择的优秀作品也很多。看起来感觉岁月静好,可以结束工作去泡咖啡了 :)
然而,事情总是在变化的,一向在折腾之路上狂奔的苹果这次依然没有让我们失望,在相册相关的 API 上带来了两个重大变动:
Photos 框架提供了查询相册授权情况的 api,我们可以通过 PHPhotoLibrary 的 authorizationStatus 方法来查询当前的相册授权情况。查询结果 PHAuthorizationStatus 是个枚举,定义如下:
public enum PHAuthorizationStatus : Int {
@available(iOS 8, *)
case notDetermined = 0
@available(iOS 8, *)
case restricted = 1
@available(iOS 8, *)
case denied = 2
@available(iOS 8, *)
case authorized = 3
}
从 iOS 8 引入 Photos 框架一开始,相册权限就存在这几种状态:
状态不明确,用户还没有明确授权或拒绝访问,这时候我们一般通过调用 requestAuthorization 方法来显示权限询问弹窗,让用户授权访问。
没有访问权限,这个状态表示设备因为特殊原因被禁止访问相册,可能是基于家长控制设置的权限,也可能是当前设备隶属于某个组织,而组织在权限描述文件中禁止了这台设备的相册权限。
这个状态下,用户也无法主动开启相册权限,所以此时唯一能做的就是告诉用户无法获取相册内容。
禁止访问,这个状态表示用户在上一次询问相册权限时明确选择了禁止。这时候我们可以选择提示用户无法访问,或者提示用户主动去设置中开启权限。
允许访问,这个状态表示用户明确同意了相册的授权,此时我们就可以通过 PHAssetCollection 和 PHAsset 相关的 api 来获取相册和其中的照片了。
原本这一切可以很完美的运转,但是如果在 Xcode 12 中查看PHAuthorizationStatus 的定义,会看到从 iOS 14 开始,苹果引入了一个新的权限状态:limited
苹果在每一年的 WWDC 都特别强调用户隐私,到了今年,苹果终于对相册动手了。现有的方案虽然看起来很完美,但是存在一个重大的隐患:用户往往只需要从相册选一张照片上传,可此时 App 却获取了整个相册所有照片的数据!!
这时候如果开发者没有守住节操底线,那么用户的所有生活照片甚至是私密照片都存在严重的泄漏风险。
新引入的有限访问权限正是为了解决这个问题。在 iOS 14 下,当我们通过 requestAuthorization 向用户获取权限时,弹窗中多了一个选项:“选择部分照片”,此时系统会在 App 进程之外弹出相册让用户选择授权给当前 App 访问的照片。用户完成选择后,App 通过相册相关的 api 就只能获取到指定的这几张照片,这有效的保护了用户的隐私。
不过,这个设计虽然保护了用户的隐私,但是从 App 的角度来看却引入了新的问题:如果我们还是用原先的那一套流程来获取照片,那么在用户选择了部分权限的情况下,每次弹出相册后用户都无法选择其他的照片,解决办法是再次弹出权限询问,让用户选择或者更换指定的照片,然后再回到我们的相册 UI,继续之后的流程。。。
这一套流程明显变得更加复杂并且奇怪了。。。而且作为一个开发者,始终不能忘了用户是不了解技术细节的,在用户的角度来看,他可能会觉得很奇怪:“为什么我每次都只能选这两张照片?这 App 有什么毛病?” 而如果你选择每次都但窗询问权限,那么当用户耐心耗尽的那一天,就是你的 App 被卸载之时。。。
基于从 Beta 版就开始使用 iOS 14 的体验,升级之后所有 App 的第一次访问相册时都会弹窗询问权限,目测 iOS 14 应该是重置了所有 App 的相册授权状态。
好在苹果还是给开发者留了一扇窗的,那就是这篇文章要讲的主题,新成员:PHPicker。
其实上面在用户选择部分照片时,我们就已经接触到这玩意儿了:系统在 App 内部额外弹出的相册,本质上就是一个 PHPicker。
苹果在宣传中说它是基于系统的相册 App 的,具有与系统相册一致的 UI 和操作方式,可以保证用户体验的一致性。并且和相册 App 一样,支持通过人物、地点等关键信息来搜索照片。并且 PHPicker 是在独立进程中运行的,与宿主 App 无关,宿主 App 也无法通过截屏 api 来获取当前屏幕上的照片信息。为了保护用户隐私,苹果真的是在各种细节上严防死守。
既然在用户授权时可以在 App 中弹出这个选择器,那么我们的 App 是否可以主动发起这个弹窗呢?答案是:PHPickerViewController
PHPickerViewController 是整个 PHPicker 组件的核心,PHPicker 隶属于 PhothsUI 库,使用之前需要先导入:
import PhotosUI
先来查看这个类的定义:
@available(iOS 14, *)
public class PHPickerViewController : UIViewController {
}
@available(iOS 14, *)
extension PHPickerViewController {
/// The configuration passed in during initialization.
public var configuration: PHPickerConfiguration { get }
/// The delegate to be notified.
weak public var delegate: PHPickerViewControllerDelegate?
/// Initializes new picker with the `configuration` the picker should use.
public convenience init(configuration: PHPickerConfiguration)
}
太简单了!这个类的定义中居然没有任何声明,只是表示了一下自己继承自 UIViewControlelr,以及在扩展中暴露了两个属性和一个构造器。。。
PHPickerConfiguration
查看 PHPickerConfiguration 的定义,发现这里东西稍微多了一点:
presentationMode 用来指定导出结果的表示形式,默认值是 automatic, 此时系统会自动执行一些转码之类的操作,并且在注释中明确说了这个模式的实际表现会在之后的发布中修改。。。
果然这种表述就是坑的表现:目前官方论坛上有用户反馈,使用了缺省的 automatic 模式后,从相册导出视频的过程变得巨慢:
对此官方的回复是 automatic 模式可能会在导出时对视频进行转码处理,如果 App 本地能够处理 HEVC 格式的视频,可以指定为 current 模式来跳过转码的过程。
这一条是我在集成过程中遇到的最大的坑之一了,实际测试中,两分钟的原始视频(大约200到300M),使用 automatic 自动转码模式,导出过程耗时达到了难以置信的 5分钟!而改为 current 模式跳过转码之后,导出过程几乎无感(5s以内)。由于我们的 App 本身会将导出的视频压缩转码后再上传,因此果断选择了 current 模式
关于 compatible 模式,注释中用了充满玄学的说法: 尽量选择最合适的形式。由于 PHPicker 相关的资料目前还太少,这个模式的运作方式暂时还摸不清楚,欢迎掉过坑的同学来补充 :)
这个设置很好理解,限制用户最多可以选择的数量
filter 提供了有限的筛选模式设置,目前可以指定筛选照片、视频、LivePhoto 几种类型,或者任何他们的组合。这一点上目前还是比较欠缺的,比如说发送朋友圈时需要限制用户只能上传一分钟以内的视频,原来我们具有完全相册访问权限的时候,可以在展示的时候直接过滤掉超过一分钟的视频,或者将他们标志为不可选。目前 PHPicker 并没有提供更详细的筛选配置,所以应对这种需求折中的方法是将视频导出之后获取视频的时长,如果超过限制则提示用户。
弹出窗口其实没什么好说的,PHPickerViewController 本身还是一个 ViewController,设置好相应的属性和 delegate 后,简单的调用 present 就可以了。
PHPickerViewController 依然是通过 delegate 属性来向宿主 App 返回用户选择的结果。
看定义同样很简单,PHPickerViewControllerDelegate 只定义了一个方法:
public protocol PHPickerViewControllerDelegate : AnyObject {
/// Called when the user completes a selection or dismisses `PHPickerViewController` using the cancel button.
///
/// The picker won't be automatically dismissed when this method is called.
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult])
}
用户完成选择后,该方法会触发,用户选择的结果会以 PHPickerResult 数组的形式传入,每一个 PHPickerResult 都对应一个照片、视频或者 LivePhoto 的数据。
需要注意的是,注释中明确说明了 PHPickerViewController 不会自动关闭,用户需要在选择完毕后,自行调用 dismiss 方法来关闭选择器。
PHPickerResult 的定义一如既往的的“简洁”,只有 itemProvider 和 assetIdentifier 两个属性,剩下的是继承的 Equatable 和 Hashable 协议的实现。
NSItemProvider 是一个 iOS 8.0 就存在了的 api,上一次使用还是在 iOS 11 引入 Drag & Drop 的时候了。不过用法依然是一致的:故名思议,这个对象就是用来向我们提供另一个对象的(好像有点绕?) 通过 itemProvider 的 api,我们可以获取到最终的结果,不过这里有点小麻烦:针对照片、视频和 LivePhoto 三种媒体类型,分别要使用不同的 api 来获取
获取照片比较简单,通过 NSItemProvider 的 loadObject 方法,并且指定 Class 类型为 UIImage,就可以在回调中得到 UIImage 类型的照片了:
provider.loadObject(ofClass: UIImage.self) { (image, error) in
// do someting with results
}
获取 LivePhoto 与获取照片类似,只是需要将 UIImage 替换为 PHLivePhoto。之后你可以通过 PHLivePhotoView 来显示。或者通过 PHAssetResourceManager 获取 LivePhoto 的原始数据。
苹果在 WWDC 视频中只演示了如果使用 PHPickerViewController 获取相册照片,但对于如何获取视频只字未提,这就比较尴尬了。目前跟进 PHPicker 的开发者还不多,基本上都搜不到相关资料,一番折腾之后,终于在官方论坛零星找到了几条关于获取视频的讨论。
查看了相关对话之后,总算摸清了获取视频的套路,要稍微复杂一点:框架开发者明确指出需要使用 loadFileRepresentation 方法来加载大文件,例如视频:
provider.loadFileRepresentation(forTypeIdentifier: "public.movie") { url, error in
// do something with results
}
loadFileRepresentation 的使用方式与 UIImage 类似,但需要额外传入一个参数 forTypeIdentifier 来指定文件类型,指定为 public.movie 可以覆盖相册中的 .mov 和 .mp4 类型。
与照片不同的是,这个 api 返回的是一个 URL 类型的临时文件路径,苹果在这个 API 的说明中指出:系统会把请求的文件数据复制到这个路径对应的地址,并且在回调执行完毕后删除临时文件。
如果你需要在异步线程中对这个文件进行处理,那么需要再复制一次,将文件放到不会被系统自动删除的路径下,并且在处理完毕后自行删除。
iOS 相册提供了 iCloud 同步功能,如果用户开启了相册同步,那么相册中的照片、视频或者 LivePhoto 有可能会被上传到 iCloud,而本地只保存有缩略图,当请求某张照片时,相册会先从 iCloud 下载,然后再返回数据。
原先具有完整访问权限时,App 可以获得资源是否存在 iCloud 的状态,并且在下载时获得进度信息。由于 PHPicker 向 App 隐藏了所有隐私信息,因此我们无法再得知资源的 iCloud 同步状态,PHPicker 会自动从 iCloud 下载资源,并且完成之后通过 delegate 回调将数据返回。
不过这里有另外一个坑,不知道是因为工期问题还是苹果员工偷懒,目前宿主 App 是无法从 PHPicker 中获取到 iCloud 的下载进度信息的:
这是 PHPicker 的另一个大坑,这种情况下,如果用户选择了比较大的视频,或者是网络状态不好的话,视频导出依然需要耗费非常长的时间,并且没有进度信息!只能期待 iOS 的后续版本能够将将这一环补充完整了。
PHPicker 的集成本身很简单,但是存在一些坑需要注意。简单总结一下优缺点:
iOS 14 正式版刚上线不久,目前还没有看到适配的大厂 App,可能也是在权衡利弊之中。不过从长远来看,PHPicker 必然会将那些第三方的相册组件扫进历史的垃圾堆的 :)
本文由哈喽比特于4年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/TOL1Ut2Qmn00xPxJGBd9Gg
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。