Swift中如何从UIImagePickerController获取媒体文件的拍摄创建日期
Swift中从UIImagePickerController回调获取媒体拍摄日期的实现方案
前置依赖
- 导入
Photos框架,所有资源日期都通过PHAsset对象获取,适配图片、视频两类媒体 - 提前在Info.plist中配置对应权限描述:
- 相册读取:
NSPhotoLibraryUsageDescription - 相机权限:
NSCameraUsageDescription - 相册写入(相机拍摄后存入场景需要):
NSPhotoLibraryAddUsageDescription
- 相册读取:
- 调用功能前先通过
PHPhotoLibrary.requestAuthorization(for:handler:)申请对应相册权限
核心实现逻辑
在UIImagePickerControllerDelegate的imagePickerController(_:didFinishPickingMediaWithInfo:)回调中,根据sourceType分两种场景处理:
1. sourceType为.photoLibrary(从相册选择)
从系统返回的info字典中可直接拿到对应资源的PHAsset对象,其creationDate属性就是媒体的拍摄日期,示例代码如下:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { picker.dismiss(animated: true) guard picker.sourceType == .photoLibrary else { return } // 直接取系统返回的PHAsset guard let asset = info[.phAsset] as? PHAsset else { print("获取相册资源失败") return } // 读取拍摄日期 if let shootDate = asset.creationDate { // 后续业务逻辑处理shootDate即可 print("媒体拍摄日期:\(shootDate)") } }
2. sourceType为.camera(相机实时拍摄)
相机刚拍摄的媒体默认不会存入相册,info字典中没有直接返回PHAsset,可以选择两种方式获取日期:
方式A:拍摄后先存入相册再读取日期(推荐,适配图片/视频,逻辑简单)
import MobileCoreServices // 需要引入该框架判断媒体类型 func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { picker.dismiss(animated: true) guard picker.sourceType == .camera else { return } let mediaType = info[.mediaType] as! String PHPhotoLibrary.shared().performChanges { let createRequest = PHAssetCreationRequest.forAsset() // 区分图片和视频写入 if mediaType == kUTTypeImage as String, let image = info[.originalImage] as? UIImage { createRequest.addResource(with: .photo, image: image, options: nil) } else if mediaType == kUTTypeMovie as String, let videoUrl = info[.mediaURL] as? URL { createRequest.addResource(with: .video, fileURL: videoUrl, options: nil) } } completionHandler: { success, error in guard success, error == nil else { return } // 拉取最新存入的资源 let fetchOpt = PHFetchOptions() fetchOpt.sortDescriptors = [.init(key: "creationDate", ascending: false)] fetchOpt.fetchLimit = 1 let fetchResult = PHAsset.fetchAssets(with: fetchOpt) guard let asset = fetchResult.firstObject, let shootDate = asset.creationDate else { return } DispatchQueue.main.async { // 回到主线程处理业务逻辑 print("拍摄日期:\(shootDate)") } } }
方式B:不存入相册,直接从媒体元数据提取
如果不需要保留拍摄的媒体到相册,可以直接读取EXIF(图片)或视频元数据中的拍摄日期,以图片为例:
if let imageUrl = info[.imageURL] as? URL, let imageSource = CGImageSourceCreateWithURL(imageUrl as CFURL, nil), let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [String: Any], let exif = properties[kCGImagePropertyExifDictionary as String] as? [String: Any], let dateStr = exif[kCGImagePropertyExifDateTimeOriginal as String] as? String { let formatter = DateFormatter() formatter.dateFormat = "yyyy:MM:dd HH:mm:ss" if let shootDate = formatter.date(from: dateStr) { print("EXIF提取的拍摄日期:\(shootDate)") } }
注意事项
- iOS版本适配:
UIImagePickerController.InfoKey.phAsset仅支持iOS 11及以上版本,如需兼容更低版本,可通过info[.referenceURL]获取资源链接后调用PHAsset.fetchAssets(withALAssetURLs:options:)获取PHAsset - 时区处理:
PHAsset.creationDate返回的是UTC时区的Date对象,展示给用户时需要转换为当地时区 - 空值处理:部分截图、网络保存的图片可能没有拍摄日期,需要做好
creationDate为空的兜底逻辑
内容的提问来源于stack exchange,提问作者Ahmad
相关产品推荐
相关产品推荐

