自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何使用PHPicker在iOS系統(tǒng)無授權(quán)下獲取資源

移動開發(fā) iOS
在本篇文章中,我將詳細(xì)介紹如何正確使用PHPicker以及何時應(yīng)該使用PHPicker。我撰寫這篇文章的原因是:在嘗試使用PHPicker訪問資源庫時遇到了一些問題?;ヂ?lián)網(wǎng)上的許多文章提供的方法都是錯誤的,從而導(dǎo)致了對PHPicker和iOS權(quán)限的一些核心問題的誤解。

自iOS14系統(tǒng)開始,蘋果加強了用戶隱私和安全功能。新增了“Limited Photo Library Access”模式,同時在授權(quán)彈窗中增加了“Select Photo”選項。這意味著用戶可以在應(yīng)用程序請求訪問相冊時選擇部分照片供應(yīng)用程序讀取。從應(yīng)用程序的角度來看,它只能訪問到用戶選擇的這幾張照片,無法得知其他照片的存在。然而,并非所有普通用戶都能夠正確理解這一機制,實際用戶反饋中也反映出了一些誤解。蘋果推薦使用新的PHPicke來解決這個問題。

在本篇文章中,我將詳細(xì)介紹如何正確使用PHPicker以及何時應(yīng)該使用PHPicker。我撰寫這篇文章的原因是:在嘗試使用PHPicker訪問資源庫時遇到了一些問題?;ヂ?lián)網(wǎng)上的許多文章提供的方法都是錯誤的,從而導(dǎo)致了對PHPicker和iOS權(quán)限的一些核心問題的誤解。

01PHPicker是什么?

從iOS14開始,PHPicker是系統(tǒng)提供的Picker ,它允許你從用戶的照片庫中訪問照片和視頻。新的PHPicker類不是在UIKit框架中的,而是位于PhotosUI框架中,包括:

  • PHPickerViewController
  • PHPickerConfiguration
  • PHPickerFilter
  • PHPickerResult

當(dāng)你展現(xiàn)一個PHPickerViewController,它有一個PHPickerConfiguration配置來告訴它要選擇多少個媒體項,以及需要選擇的媒體類型。通過 PHPickerConfiguration的filter屬性,配置可選擇的媒體類型,它的選項可以是任意組合:圖片、實況照片或視頻。通過PHPickerConfiguration的selectionLimit屬性來配置用戶可以選擇的媒體項數(shù)量。

let photoLibrary = PHPhotoLibrary.shared()
var config = PHPickerConfiguration(photoLibrary: photoLibrary)
                        
let selectedCount = self.albumViewModel.selectArray.count
let limited = min(4-selectedCount, 4)
config.selectionLimit = (type == .pic ? limited : 1)
config.filter = (type == .pic ? .images : .videos)
let pickerViewController = PHPickerViewController(configuration: config)
pickerViewController.delegate = self
self.viewController?.present(pickerViewController, ani

圖片圖片

02真的需要用戶授權(quán)嗎?

當(dāng)用戶給予受限訪問模式時,如果需要獲得未授權(quán)的額外資源,網(wǎng)絡(luò)上很多文章建議你使用PHAsset和PHPicker來獲取額外的數(shù)據(jù),這樣做的問題是,你必須具有訪問資源庫的權(quán)限,這違背了蘋果建議的使用PHPicker的初衷:在不請求權(quán)限的情況下使用的選擇器。

我們來模擬一下流程:你的的應(yīng)用程序請求訪問用戶資源庫的權(quán)限,用戶說:“我將只給這個應(yīng)用程序有限的訪問一些照片?!?此時,如果你的應(yīng)用程序打開PHPicker并顯示所有的照片;用戶說:“奇怪,我以為我只給有限的訪問權(quán)限,為什么所有照片都有?”;接下來,用戶選擇了一張他沒有給我們訪問權(quán)限的照片。應(yīng)用程序現(xiàn)在需要什么都不做,為了使用PHAsset獲得他選擇的照片的元數(shù)據(jù)(metadata),他們必須再次更新他們的權(quán)限。用戶感到困惑。

所以,如果你的目的非常明確,就是需要用戶給予額外的資源授權(quán)來獲得 PHAsset 對象,應(yīng)該使用iOS14的新API PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: vc),反之,使用 PHPicker不應(yīng)該申請獲得用戶授權(quán),正確的做法是使用 PHPickerViewControllerDelegate返回的NSItemProvider獲得元數(shù)據(jù)(metadata)信息,我將在稍后詳細(xì)介紹。

03使用PHPicker的方式

1、錯誤方式

下面這段代碼是網(wǎng)絡(luò)上廣泛被轉(zhuǎn)載的一段錯誤代碼:

import UIKit
import PhotosUI
class PhotoKitPickerViewController: UIViewController, PHPickerViewControllerDelegate {
    @IBAction func presentPicker(_ sender: Any) {
        let photoLibrary = PHPhotoLibrary.shared()
  let configuration = PHPickerConfiguration(photoLibrary: photoLibrary)
  let picker = PHPickerViewController(configuration: configuration)
  picker.delegate = self
  present(picker, animated: true)
 }
  
 func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
  picker.dismiss(animated: true)
  let identifiers = results.compactMap(\.assetIdentifier)
  let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: identifiers, options: nil)
    
  // TODO: Do something with the fetch result if you have Photos Library access
 }
}

在這段代碼中,你使用PHPickerViewController選擇了受限制的資源,但是在調(diào)用PHAsset.fetchAssets時返回了一個空結(jié)果。這是因為fetchAssets方法只能檢索用戶授權(quán)訪問的所有資源,而在受限制模式下,只有最近的受限制資源可供訪問,所以這種方式是錯誤的!

2、正確方式

PHAsset不應(yīng)該與PHPicker一起使用,這不是使用PHPickeri的正確方法!應(yīng)該使用NSItemProvider。NSItemProvider是一個項目提供程序,用于在拖放或復(fù)制/粘貼活動期間在進(jìn)程之間傳輸數(shù)據(jù)或文件,或者從主機應(yīng)用程序到應(yīng)用程序擴展。使用itemProvider,可以讀取對象的類型,并根據(jù)它是照片、視頻還是其他內(nèi)容來處理它。比較合適的方式如下所示:

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    picker.dismiss(animated: true)
    for result in results {
        let itemProvider: NSItemProvider = result.itemProvider;
        if(itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier)) {
            // 圖片處理
        } else  if(itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier)) {
            // 視頻處理
        } else {
            // 其他,暫時忽略
        }
    }
}

04獲得圖片與圖片元數(shù)據(jù)

通過前一步驟,我們已經(jīng)知道了資源的類型。接下來通過NSItemProvider的API加載圖片內(nèi)容和獲得元數(shù)據(jù)信息;查閱 NSItemProvider(1)文檔,可以看到加載數(shù)據(jù),主要提供了下面幾種API:

  • loadDataRepresentation:返回資源Data數(shù)據(jù)
  • loadFileRepresentation:返回資源URL
  • loadObject:指定資源類型返回

這里我推薦使用 loadDataRepresentation,返回Data數(shù)據(jù),方便下一步獲得元數(shù)據(jù)信息。

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    picker.dismiss(animated: true)
    for result in results {
        let itemProvider: NSItemProvider = result.itemProvider;
        if(itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier)) {
            // 圖片處理
            itemProvider.loadDataRepresentation(forTypeIdentifier: UTType.image.identifier) { data, error in
                    //處理業(yè)務(wù)model轉(zhuǎn)換
                    if let model = self.createPhotoResourcesModel(data: data, assetIdentifier: assetIdentifier){
                        self.albumViewModel.selectArrayAddObject(model)
                        
                        DispatchQueue.main.async {
                            //更新UI
                        }
                    }
              }
            
        } else  if(itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier)) {
            // 視頻處理
        } else {
            // 其他,暫時忽略
        }
    }
}

在處理業(yè)務(wù)model轉(zhuǎn)換函數(shù)中,由于Data類型很容易轉(zhuǎn)換成UIImage,并且通過將Data轉(zhuǎn)換為CFData 類型,可以通過系統(tǒng)預(yù)設(shè)的key/value鍵值對獲得元數(shù)據(jù)信息,

let imgSrc = CGImageSourceCreateWithData(data, options as CFDictionary)
let metadata = CGImageSourceCopyPropertiesAtIndex(imgSrc, 0, options as CFDictionary)
colorModel = metadata[kCGImagePropertyColorModel] as? String
pixelWidth = metadata[kCGImagePropertyPixelWidth] as? Double;
pixelHeight = metadata[kCGImagePropertyPixelHeight] as? Double;

這里我們使用了Github上開源的 ExifData(2) 代碼,完整實現(xiàn)了所有字段的獲取封裝,使用起來非常方便。

func createPhotoResourcesModel(data:Data?,
                            assetIdentifier:String?) -> SNSResourcesModel? {
        guard let imageData = data, let uiimage = UIImage(data: imageData) else {
            return nil
        }
        let model = SNSResourcesModel()
        model.assetLocalIdentifier = assetIdentifier
        model.assetType = .photo
        model.assetSource = .album
        model.originImage = uiimage
        model.bigPreviewImage = uiimage
        
        let exifData = ExifData(data: imageData)
        model.pixelWidth = Int(exifData.pixelWidth ?? 0)
        model.pixelHeight = Int(exifData.pixelHeight ?? 0)
        if imageData.imageType == .GIF{
            model.isGif = true
            model.gifData = imageData
        }
        return model
}

05處理特殊格式圖片

如果用戶在資源庫中選擇了一張WebP格式圖片或者GIF動圖,由于展示所需代碼和形式均不同,所以需要特別區(qū)分,那么如何來區(qū)別處理呢?

我們可以通過UTType來具體區(qū)分不同類型,UTType是Uniform Type Identifier的縮寫,用于標(biāo)識特定類型的文件或數(shù)據(jù)。在macOS和iOS等操作系統(tǒng)中,UTType通常用于識別文件類型、將文件分組到合適的應(yīng)用程序中、在不同應(yīng)用程序之間共享數(shù)據(jù)等。

UTType由兩部分組成:類型標(biāo)識符(type identifier)和類型標(biāo)簽(type tag)。類型標(biāo)識符是一串唯一的字符串,用于標(biāo)識特定類型的文件或數(shù)據(jù),通常采用反向DNS風(fēng)格的命名方式,如com.adobe.pdf、public.image等。類型標(biāo)簽是一個可選的字符串,用于描述特定類型的文件或數(shù)據(jù),例如"PDF document"或"JPEG image"等。

if(itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier)) {
    // 圖片處理
    // 判斷webp
    if itemProvider.hasItemConformingToTypeIdentifier(UTType.webP.identifier){
        //處理webp
    }
    //判斷GIF
    if itemProvider.hasItemConformingToTypeIdentifier(UTType.gif.identifier){
        //處理GIF
    }        
}

06獲得視頻

獲得視頻時,推薦使用loadFileRepresentation,返回URL,通過URL可以獲得 AVAsset。

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    picker.dismiss(animated: true)
    for result in results {
        let itemProvider: NSItemProvider = result.itemProvider;
        if(itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier)) {
            // 圖片處理
        } else  if(itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier)) {
            // 視頻處理
            itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier) { url, error in
                    //業(yè)務(wù)model轉(zhuǎn)換
                    if let model = self.createVideoResourcesModel(url: url, assetIdentifier: assetIdentifier){
                        self.albumViewModel.selectArrayAddObject(model)
                        
                        DispatchQueue.main.async {
                            //展示UI
                        }
                    }
            }
        } else {
            // 其他,暫時忽略
        }
    }
}

07獲取加載進(jìn)度

當(dāng)獲取的資源文件較大時,我們需要獲得加載數(shù)據(jù)的進(jìn)度,此時可以使用 NSItemProvider的加載數(shù)據(jù)函數(shù)提供的返回值NSProgress對象。

var progress:Progress?
progress = itemProvider.loadDataRepresentation(forTypeIdentifier: UTType.image.identifier) { data, error in
    //...
}
//添加觀察者
progress?.addObserver(self, forKeyPath: "fractionCompleted", options: [.new], context: nil)

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "fractionCompleted" {
        print("fractinotallow=\(self.progress?.fractionCompleted)")
    }
}

在上面的示例代碼中,我們首先創(chuàng)建了一個NSItemProvider對象和一個指定類型標(biāo)識符。然后,我們使用 loadDataRepresentation(forTypeIdentifier:completionHandler:) 方法加載數(shù)據(jù),并返回一個NSProgress對象。我們可以將該對象添加為觀察者,并在觀察者的回調(diào)方法中更新進(jìn)度條的值。

請注意,NSProgress對象是線程安全的,因此可以在不同的線程中使用。此外,如果你需要在多個地方使用同一個NSProgress對象;

NSProgress對象的fractionCompleted屬性,該屬性表示任務(wù)的完成度,其值在0.0和1.0之間。

06總結(jié)

本文要點包含以下:

  • PHPicker是iOS14開始引入的新組件,它允許在不需要用戶授權(quán)的情況下訪問照片庫的所有資源;
  • 使用PHPicker的正確方式是通過PHPickerViewControllerDelegate回調(diào)返回的NSItemProvider來獲取所選資源,而不是通過PHAsset來獲取,后者需要提前獲取用戶的相冊訪問授權(quán);
  • 通過NSItemProvider可以判斷資源類型,加載資源數(shù)據(jù)或文件URL,獲取圖片、視頻等多媒體資源;
  • 對于圖片,可以通過loadDataRepresentation獲取Data,并利用該Data獲取圖片元數(shù)據(jù)信息。對于視頻,可以通過loadFileRepresentation獲取URL,并利用URL獲取AVAsset;
  • 通過UTType可以進(jìn)一步判斷特殊格式資源如webp、gif等進(jìn)行不同處理;
  • 可以通過NSProgress監(jiān)聽資源加載進(jìn)度;
  • 正確使用PHPicker可以避免引起用戶疑惑,提高用戶體驗,是iOS14訪問多媒體資源的推薦方式。

總之,本文詳細(xì)介紹了在iOS14中如何正確使用PHPicker訪問用戶選擇的部分照片資源,其要點是不需要提前獲取授權(quán),通過NSItemProvider處理多媒體資源,這是一種更符合系統(tǒng)設(shè)計初衷和提高用戶體驗的方式。

標(biāo)注參考鏈接:

(1)https://developer.apple.com/documentation/foundation/nsitemprovider

(2)https://gist.github.com/lukebrandonfarrell/961a6dbc8367f0ac9cabc89b0052d1fe

責(zé)任編輯:武曉燕 來源: 搜狐技術(shù)產(chǎn)品
相關(guān)推薦

2009-12-10 09:42:07

2011-09-02 19:26:38

2011-08-30 15:19:23

2009-11-06 10:05:18

Linux系統(tǒng)環(huán)境GFS

2010-04-19 15:11:25

Unix操作系統(tǒng)

2011-09-06 16:30:32

iOS系統(tǒng)靜態(tài)鏈接庫

2011-09-09 18:16:18

WindowsLinux

2024-02-23 10:11:00

虛擬化技術(shù)

2022-11-16 13:23:51

2009-05-20 19:33:34

Vista虛擬機Linux

2011-09-15 17:01:25

ubuntu備份

2011-09-19 16:56:14

Vista秘密下載

2014-09-12 14:41:12

2011-09-05 13:19:42

UbuntuWebmin

2009-10-21 12:42:20

Linux系統(tǒng)資源操作系統(tǒng)

2011-07-06 15:06:46

Xcode Cocoa

2014-08-06 09:21:21

ubuntuPushbullet

2012-02-03 09:55:06

Delphi

2011-08-22 15:50:05

Linuxmailsendmail

2021-09-27 07:57:15

MEAT安全工具安全取證
點贊
收藏

51CTO技術(shù)棧公眾號