iOS 12Mattt Henry Lee 🚩🌱

如果你去看今年的 WWDC Keynote 演讲,你就知道 iOS 12 的这些比较重大的的新特性: Siri Shortcuts, ARKit 2, and Core ML 2 — 更不用提风传很久的炸弹:代号为 “Marzipan” 的 iOS/Mac 桥接件终于提前透露了出来。

另外如果你看了今年的这一期 Platforms State of the Union session, 你会发现一些虽然没那么光芒四射但依旧很令人兴奋技术: 像自定义用户通知 UI, 和更新了的 Network自然语言(Natural Language) 框架。

但在 NSHipster , 我们感兴趣的是那些最详细最细微的变化 (我们可以说, 晦涩的?) 也是最终加起来却又能给我们每天的工作带来很大影响的变化。

今年的 iOS 12 版本说明Foundation 版本说明涵盖了很多这样的变化,但是它们还没有展开故事的全貌。 正因如此,你还需要深入挖掘。

为了庆祝 iOS 12 在这周的发布, 我们把通过iOS 11.4 到 12 的 API 的一些差异 分享给大家(尽管 API 已经列出来了,但是他们还没有正式文档的说明,所以记得小心使用)。


为更重要的请求在网络流量里排出优先级

你听过 iOS 里的 Fast Lane(快车道)么? 并不是 Google 的 fastlane。 也不是 Cisco 的 IOS

Fast Lane (或者写成 Fastlane?) 是一种能根据网络请求的类型(例如音频、视频或后台数据)来优化无线网络流量的一个机制。

它原本是只有 Cisco 路由器(Cisco 路由器承载了互联网一半的流量)专有的一个技术,里面包含了一些 Wi-Fi 的标准, 例如快速漫游的 802.11r、 辅助漫游的 802.11k 和无线配置的 802.11v

多亏了 2015 年 Apple 和 Cisco 的合作, iOS 开发者可以通过给网络连接提供一个服务类型(QoS 标记) 来用到这个技术 (很多高层的 API 可以自动地帮你实现这个工作)。

在 iOS 12 的新 API 里,你可以把 URLRequest 对象networkServiceType 设置为 NSURLNetworkServiceTypeResponsiveData,从而让一些时间敏感的操作优先请求。

import Foundation

let url = URL(string: "https://example.com/checkout")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.networkServiceType = .responsiveData // Prioritize

URLSession.shared.dataTask(with: request) {
    (data, response, error) in
    // ...
}

这个选项还没有文档说明, 但是在 WWDC 2018 Session 714: “Optimizing Your App for Today’s Internet” 的向导里,苹果工程师已经提到了。 不过只有最需要极力减少请求时间的时候才能谨慎地使用这个特性, 例如他们提到了一个场景就是一些购物应用的收银台页面可以使用, 当然你也可以推断出一些其他的使用案例。

在后台读取 NFC 标签

在 WWDC 2018 里被排着队问到的最多的一个问题是 NSUserActivity 加入的 ndefMessagePayload 属性, 而彼时苹果工程师在 Lab Session 回答的最多的也是“无可奉告”。

但是重重迷雾终于在上周的 iPhone XS, iPhone XS Max 和 iPhone XR 的发布会上被揭开。 这些设备支持在后台读取 NFC 标签, 而且如果你在最新的设备上跑着 iOS 12, 你将可以 — 干这些 — 可以不需要别的设置, 就通过扫到的标签来启动 App、打电话或打开链接。 为了防止误激活, 这个只在 iPhone 是解锁状态下才工作, 处于飞行模式、使用 Apple Pay 中和使用相机的时候不能工作。

有了 NFC 集成,通过提供一个更顺畅与真实世界连接的途径,而不是堕落到去扫二维码(在中国非常流行,但是被世界其他地方被忽视), Apple 终于可以完全实现 2013 对于 BLE 的承诺了。

可能 NFC 和 iBeacon 最适用场景还是你在博物馆参观, 站在展品面前想了解更多信息的时候, 只需要把 iPhone 放到信息牌上就能实现。

实现类似功能需要 App 有个特别的 entitlements, 设置相关的域和其他一些相关配置 — 还有一些你需要实际实现的 API。 好在,Apple 还提供了一些过程中的扩展文档, 包括一个示例项目这篇文章.

根据电话号码和邮件地址匹配联系人

Contacts framework 是在 iOS 9 和 macOS El Capitan 作为 AddressBook framework 的更现代的替代版本出现的。

截止目前, 你只能通过姓名或者唯一编码(identifier)搜索联系人, 但是在 iOS 12 里, 你能用CNContact 类的 predicateForContacts(matching:)predicateForContacts(matchingEmailAddress:) 来构造谓词(predicate)用以匹配手机号码与邮件地址。

例如, 如果我们想要依照一组手机号和邮件地址取出所有匹配到的姓与名, 你可以创建一个 CNContactFetchRequest, 用 “AND” 来把连个子谓词(subpredicate)组合一个复合谓词,而后传给当前 CNContactStore 对象的 enumerateContacts(with:) 方法。

import Contacts

let phoneNumber = CNPhoneNumber(stringValue: "+1 555 555 1234")
let phoneNumberPredicate = CNContact.predicateForContacts(matching: phoneNumber)

let emailPredicate = CNContact.predicateForContacts(matchingEmailAddress: "johnny@example.com")

var fetchRequest = CNContactFetchRequest(keysToFetch: [
    CNContactGivenNameKey as CNKeyDescriptor,
    CNContactFamilyNameKey as CNKeyDescriptor
])

fetchRequest.predicate =
  NSCompoundPredicate(andPredicateWithSubpredicates: [
    phoneNumberPredicate,
    emailPredicate
])

let store = CNContactStore()
try store.enumerateContacts(with: fetchRequest) { (contact, _) in
    // ...
}

在空中更新位置信息

很多飞行员很喜欢用 iPad 来导航和制定飞行计划。 如果你的 App 是用来装备给在天上驾驶员座舱里的老兄们的话, 你就会对 iOS 12 里 CLLocationManager 的新特性感到兴奋。

activityType 属性 已经出来有一段时间了,但是针对于 CLLocationManager 的配置却鲜有人知。 如果你用这个 CLLocationManager 在一段时间内追踪位置的变化, 通过一些唾手可得的优化, 你就能知道用户在以什么行为模式运动。 但目前,运动变化的种类被严格限制在正在 驾驶类走路/跑步/骑行类其他类这三个领域。 但是在 iOS 12 里,你可以指定飞行活动类来让你的运动追踪算法飞起来!

import CoreLocation

let manager = CLLocationManager()
manager.activityType = .airborne // ✈️

检测平放设备朝向

你是否想检测设备是否平放在一个表面上, 但是只能勉强地使用 两个条件 来检测? 好消息是,在 iOS 12 里, 新增了一个 isFlat 的方便属性。

import UIKit

// iOS 12+
UIDevice.current.orientation.isFlat

// iOS <= 11.4
UIDevice.current.orientation == .faceUp ||
  UIDevice.current.orientation == .faceDown

新密码的自动输入与一次性验证码在文本框里的输入

尽管 Apple 为了在让用户在设备上愉悦地输入做了长期的英雄般卓越的工作, 但是有一些事实还是不能改变: 在一个毫无触感的光滑玻璃上输入总是比在一个合适的硬件键盘上输入要苍白 (尽管依然要吐槽新 MacBook 的键盘)。

为了减少文本输入之类的苦差事, iOS 10 为一些服从 UITextInputTraits 协议的控件(分别是 UITextFieldUITextView) 提供了 textContentType 属性。 只要提供一个具体的枚举类型,你就指定了这个控件的语义类型, 就可以依据当前用户的信息,自动填入名字或者地址类的信息。

iOS 12 和 tvOS 12 拓展了这个枚举,增加了 UITextContentTypeNewPasswordUITextContentTypeOneTimeCode 类型。

当你同时指定 .newPasswordpasswordRules 属性的时候, 密码自动填写功能(Password AutoFill)就能根据系统登录密码的要求自动生成一个新的密码。

textField.textContentType = .newPassword
textField.passwordRules = .init(descriptor:
    "allowed: ascii-printable; minlength: 8;"
)

当你指定了 .oneTimeCode 内容类型的时候, 文本框能够自动地转发短信的二次验证码。

textField.textContentType = .oneTimeCode

我们这一期的 iOS 12 代码 diff 探险就在这里结束了。 当然,这是一次庞大的更新, 我们期待在接下来的几周再讲解更多更深的新 API。

对之后的内容有任何建议? 来 Twitter 联系我们!


除非另有声明,本文采用知识共享「署名-非商业性使用 3.0 中国大陆」许可协议授权。