WWDC 20 過去已經(jīng)有好幾個月了, iOS 14 正式版也發(fā)布了,這篇文章寫的有點(diǎn)晚了,因?yàn)橛行?API 沒有徹底弄懂,所以一直拖到了現(xiàn)在(奇怪我怎么感覺去年也說過一樣的話: doge)其實(shí)過了這么多個月,大家應(yīng)該或多或少都看過一些別人寫文章,介紹相冊的變化,介紹 PHPicker,但是有一些點(diǎn)沒講清楚,比如怎么用 PHPicker 獲取視頻?PHPicker 有什么不足?那么下面讓我們一起看看什么是 PHPicker 以及 iOS 14 相冊有什么新的變化。
PHPicker
iOS 14 中系統(tǒng)新增了一個圖片選擇器 PHPicker
,官方建議使用 PHPicker
來替代原有的 API 進(jìn)行圖片選擇,下面我們來看看 PHPicker
的優(yōu)點(diǎn):
- 支持多選
- 支持搜索
- 獨(dú)立的進(jìn)程
- 內(nèi)置隱私
- 不需要直接訪問用戶相冊
- 不會彈出訪問相冊提示
- 僅提供用戶選擇的照片和視頻(App 無法獲取其他照片)
如何調(diào)用 PHPicker
我們先來看下 PHPicker
的流程圖,首先聲明 PHPickerConfiguration
,進(jìn)行配置,再傳給 PHPickerViewController
,完成調(diào)用環(huán)節(jié),代碼如下:
var config = PHPickerConfiguration()
// 可選擇的資源數(shù)量,0表示不設(shè)限制,默認(rèn)為1
config.selectionLimit = 0
// 可選擇的資源類型
// 只顯示圖片(注:images 包含 livePhotos)
config.filter = .images
// 顯示 Live Photos 和視頻(注:livePhotos 不包含 images)
config.filter = .any(of: [.livePhotos, .videos])
// 如果要獲取視頻,最好設(shè)置該屬性,避免系統(tǒng)對視頻進(jìn)行轉(zhuǎn)碼
config.preferredAssetRepresentationMode = .current
let picker = PHPickerViewController(configuration: config)
picker.delegate = self
present(picker, animated: true, completion: nil)
處理 PHPicker 的回調(diào)
PHPicker
的代理方法只有一個,聲明如下:
@available(iOS 14, *)
public protocol PHPickerViewControllerDelegate : AnyObject {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult])
}
注意: 取消選擇也會觸發(fā)代理方法,會返回空的 results
。
如何獲取照片
PHPicker
獲取圖片的方法還是比較簡單的,代碼如下:
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// 首先需要 dismiss picker
picker.dismiss(animated: true, completion: nil)
for result in results {
// 判斷類型是否為 UIImage
if result.itemProvider.canLoadObject(ofClass: UIImage.self) {
// 確認(rèn)類型后,調(diào)用 loadObject 方法獲取圖片
result.itemProvider.loadObject(ofClass: UIImage.self) { (data, error) in
// 回調(diào)結(jié)果是在異步線程,展示時需要切換到主線程
if let image = data as? UIImage {
DispatchQueue.main.async {
self.showImage(image)
}
}
}
}
}
}
如何獲取視頻
其他文章中都沒有介紹 PHPicker
如何獲取視頻,其實(shí)獲取視頻的方法在官方的 Demo 以及視頻中都沒有介紹,這也是我遲遲沒有寫文章的原因,因?yàn)橹拔乙膊恢涝趺传@取,那么下面讓我們一起來看下怎么獲取視頻。
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// 首先需要 dismiss picker
picker.dismiss(animated: true, completion: nil)
for result in results {
if result.itemProvider.canLoadObject(ofClass: UIImage.self) {
// 判斷類型是否為 UIImage
...
} else {
// 類型為 Video
// 調(diào)用 loadFileRepresentation 方法獲取視頻的 url
// 這里 Type Identifier 我們用 UTType.movie.identifier (“public.movie”) 這個 UTI 可以獲取所有格式的視頻
result.itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier) { (url, error) in
if let error = error {
print(error)
return
}
// 系統(tǒng)會將視頻文件存放到 tmp 文件夾下
// 我們必須在這個回調(diào)結(jié)束前,將視頻拷貝出去,一旦回調(diào)結(jié)束,系統(tǒng)就會把視頻刪掉
// 所以一定要確定拷貝結(jié)束后,再切換到主線程做 UI 操作
// 另外不用擔(dān)心視頻過大而導(dǎo)致拷貝的時間很久,系統(tǒng)將創(chuàng)建一個 APFS 的克隆項,因此拷貝的速度會非常快
guard let url = url else { return }
let fileName = "\(Int(Date().timeIntervalSince1970)).\(url.pathExtension)"
let newUrl = URL(fileURLWithPath: NSTemporaryDirectory() + fileName)
try? FileManager.default.copyItem(at: url, to: newUrl)
DispatchQueue.main.async {
self.playVideo(newUrl)
}
}
}
}
}
注意: 如果你遇到了部分資源可以加載,而部分資源無法加載的話,那么有可能是設(shè)備沒有連接到 iCloud,只能加載本地資源,而無法加載 iCould 上的資源。
被廢棄的 API
有新的 API 出現(xiàn),也會有一些 API 被廢棄,在 UIImagePickerController
中有三個 sourceType
,現(xiàn)在有兩個被廢棄,只留下 camera
。
public enum SourceType : Int {
@available(iOS, introduced: 2, deprecated: 100000, message: "Will be removed in a future release, use PHPicker.")
case photoLibrary = 0
case camera = 1
@available(iOS, introduced: 2, deprecated: 100000, message: "Will be removed in a future release, use PHPicker.")
case savedPhotosAlbum = 2
}
另外 AssetsLibrary
早在幾年前被廢棄,如果還在使用 AssetsLibrary
請盡快使用新的 API。
PHPicker 的缺點(diǎn)
為什么不推薦使用 PHPicker
,雖然說 PHPicker
有一些優(yōu)點(diǎn),但同時也有一些缺點(diǎn):
- 加載 iCloud 資源時沒有進(jìn)度回調(diào)
- 不支持圖片編輯(比如選擇頭像要將圖片裁剪成正方形)
有沒有其他的解決方案?
有的,如果你不能接受 PHPicker
的缺點(diǎn),同時又想保護(hù)用戶的隱私,那么可以考慮使用我和我的小伙伴做的第三方圖片選擇框架 AnyImageKit,目前有 Picker、Editor、Capture 三個模塊,支持圖片/視頻選擇、編輯、拍攝功能,支持 SPM、CocoaPods 方式引入。
接下來我會結(jié)合 AnyImageKit 中的案例一起來介紹 iOS 14 相冊的改動。
新增權(quán)限
iOS 14 中相冊新增了一個 “Limited Photos Library” 模式,在授權(quán)時多了一個 “選擇照片” 的選項。點(diǎn)擊之后系統(tǒng)會彈出 PHPickerController
用戶可以選擇指定的照片讓 App 讀取。
當(dāng)用戶選擇了 limited
模式后,系統(tǒng)將在 App 每次啟動后首次觸發(fā)相冊時彈出提示,允許用戶修改需要授權(quán)給 App 的照片。
當(dāng)然這個彈窗是可以關(guān)閉的,如果你希望手動控制 PHPickerController
彈出的時機(jī)也是有辦法的。
我們需要在 Info.plist 中添加 PHPhotoLibraryPreventAutomaticLimitedAccessAlert
字段,并設(shè)置為 YES,設(shè)置后系統(tǒng)將不再彈出訪問提示。
然后我們可以在合適的時機(jī)調(diào)用以下這個 API 來推出 PHPickerController
。
let viewController = self
PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: viewController)
我們可以看到,當(dāng)用戶選擇
limited
模式后,底部出現(xiàn)了一段提示:“無法查看相冊全部照片,點(diǎn)擊選擇更多照片”。當(dāng)點(diǎn)擊這個提示后,將會推出PHPickerController
,此時用戶可以修改授權(quán)給 App 的照片。同時我們會監(jiān)聽相冊的變化,當(dāng)用戶修改授權(quán)的照片后,會立即刷新相冊,用戶可以繼續(xù)進(jìn)行選擇照片的流程。
監(jiān)聽相冊變化
配合手動調(diào)用 PHPickerController
,我們還需要監(jiān)聽用戶添加/刪除了哪些照片。
注意: 這組 API 并不是新出的,從 iOS 8 開始就支持了。
let viewController = self
// 開始監(jiān)聽
PHPhotoLibrary.shared().register(viewController)
// 結(jié)束監(jiān)聽
PHPhotoLibrary.shared().unregisterChangeObserver(viewController)
處理監(jiān)聽回調(diào):
/// 回調(diào)方法
func photoLibraryDidChange(_ changeInstance: PHChange) {
// Your code
}
由于這是一組舊的 API,所以就不介紹細(xì)節(jié)了(比如判斷是新增還是刪除),感興趣的朋友可以去了解一下。
新增的 API
PHAccessLevel
在 iOS 14 中新增了權(quán)限等級枚舉 PHAccessLevel
,有兩個 case,分別是 “只讀” 和 “讀寫”。
public enum PHAccessLevel : Int {
case addOnly = 1
case readWrite = 2
}
對應(yīng)新增了一組獲取/查看權(quán)限的 API:
let level: PHAccessLevel = .readWrite
// 獲取權(quán)限
PHPhotoLibrary.requestAuthorization(for: level) { status in
// Your code
}
// 查看權(quán)限
let status: PHAuthorizationStatus = PHPhotoLibrary.authorizationStatus(for: level)
PHAuthorizationStatus
PHAuthorizationStatus
新增了一個 case limited
。
public enum PHAuthorizationStatus : Int {
case notDetermined = 0
case restricted = 1
case denied = 2
case authorized = 3
@available(iOS 14, *)
case limited = 4
}
當(dāng)用戶在授權(quán)時選擇了 “選擇照片” 的選項時:
- 使用新 API 將會返回
limited
case - 使用舊 API 將會返回
authorized
case
注意: limited
case 僅在 PHAccessLevel = .readWrite
時會返回。
總結(jié)
新出的 PHPicker
個人覺得一般,如果對 Picker
要求不多的朋友可以考慮使用。然后是新出的 “Limited Photos Library” 模式,這個非常棒,如果有自定義 Picker
的朋友建議跟進(jìn)一下。如果沒有自定義 Picker
的朋友可以考慮使用我們做的第三方圖片選擇框架 AnyImageKit。
以上就是 iOS 14 相冊的改動以及 PHPicker
的全部內(nèi)容,如有錯誤歡迎指出。