iOS:如何获取拍摄中/已拍摄照片经纬度(替代废弃Assets Library)
嘿,刚好碰到过类似的需求,我来给你梳理清楚!你说得没错,Assets Library早在iOS 9就被苹果废弃了,所以得针对不同系统版本用对应的框架,同时还要覆盖iOS 5+的兼容性。下面分两种场景给你写示例代码:
一、获取已拍摄照片的经纬度
根据系统版本不同,我们用两个不同的框架来实现:
1. iOS 9.0+ 使用 Photos 框架(推荐)
Photos框架是苹果现在主推的,API更简洁易用,直接通过PHAsset的location属性就能拿到照片的位置信息。
import Photos // 第一步:请求照片访问权限 PHPhotoLibrary.requestAuthorization { status in guard status == .authorized else { print("得先授予照片访问权限才能获取位置信息哦") return } // 这里以获取最近拍摄的一张照片为例,你可以根据需求调整筛选逻辑 let fetchOptions = PHFetchOptions() // 按拍摄时间倒序,取最新的一张 fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] fetchOptions.fetchLimit = 1 let photoFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions) if let targetAsset = photoFetchResult.firstObject { // 读取位置信息 if let photoLocation = targetAsset.location { let lat = photoLocation.coordinate.latitude let lng = photoLocation.coordinate.longitude print("这张照片的经纬度:lat = \(lat), lng = \(lng)") } else { print("这张照片没有标记位置哦") } } }
2. iOS 5.0 - iOS 8.x 使用 Assets Library 框架(兼容低版本)
虽然这个框架已经废弃,但为了支持iOS 5-8的设备,还是得用上它:
import AssetsLibrary // 直接遍历相册,取最新的照片 ALAssetsLibrary().enumerateGroupsWithTypes(ALAssetsGroupSavedPhotos, usingBlock: { group, stop in guard let validGroup = group else { print("无法访问相册分组") return } validGroup.setAssetsFilter(ALAssetsFilter.allPhotos()) // 倒序遍历,取最新的一张 validGroup.enumerateAssetsWithOptions(.Reverse) { asset, _, stopPointer in guard let validAsset = asset else { return } if let assetLocation = validAsset.location { let lat = assetLocation.coordinate.latitude let lng = assetLocation.coordinate.longitude print("这张照片的经纬度:lat = \(lat), lng = \(lng)") stopPointer.memory = true // 找到后停止遍历,节省资源 } else { print("这张照片没有位置标记") stopPointer.memory = true } } }, failureBlock: { error in print("访问相册失败:\(error.localizedDescription)") })
二、拍摄中获取经纬度(并写入照片元数据)
如果是你自己的相机功能,想要在拍摄时获取当前位置并写入照片,就得结合CoreLocation来获取实时位置,再根据系统版本保存带位置的照片:
import UIKit import CoreLocation import Photos // iOS9+ 用这个,低版本用AssetsLibrary class CameraDemoVC: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, CLLocationManagerDelegate { private let locationManager = CLLocationManager() private var currentUserLocation: CLLocation? override func viewDidLoad() { super.viewDidLoad() // 请求位置权限,拍摄时需要获取当前位置 if CLLocationManager.authorizationStatus() != .authorizedWhenInUse { locationManager.requestWhenInUseAuthorization() } locationManager.delegate = self locationManager.startUpdatingLocation() } // 打开系统相机的方法 @IBAction func openSystemCamera(_ sender: UIButton) { guard UIImagePickerController.isSourceTypeAvailable(.camera) else { print("当前设备不支持相机功能") return } let cameraPicker = UIImagePickerController() cameraPicker.sourceType = .camera cameraPicker.delegate = self present(cameraPicker, animated: true) } // CoreLocation获取位置更新的回调 func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { // 取最新的位置 currentUserLocation = locations.last // 获取到位置后就停止更新,节省电量 locationManager.stopUpdatingLocation() } // 拍摄完成的回调 func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { picker.dismiss(animated: true) guard let capturedImage = info[.originalImage] as? UIImage else { print("无法获取拍摄的照片") return } if let userLocation = currentUserLocation { // 保存带位置信息的照片 savePhotoWithLocation(image: capturedImage, location: userLocation) } else { // 没获取到位置,直接保存照片 savePhoto(image: capturedImage) } } // 兼容版本的保存带位置照片的方法 private func savePhotoWithLocation(image: UIImage, location: CLLocation) { if #available(iOS 9.0, *) { PHPhotoLibrary.shared().performChanges({ let creationRequest = PHAssetCreationRequest.forAsset() guard let imageData = image.jpegData(compressionQuality: 0.8) else { return } creationRequest.addResource(with: .photo, data: imageData, options: nil) // 设置照片的位置元数据 creationRequest.location = location }) { success, error in if success { print("带位置的照片保存成功啦") } else { print("保存失败:\(error?.localizedDescription ?? "未知错误")") } } } else { // iOS8及以下用AssetsLibrary处理 let assetsLibrary = ALAssetsLibrary() guard let imageData = image.jpegData(compressionQuality: 0.8) else { return } assetsLibrary.writeImageDataToSavedPhotosAlbum(imageData, metadata: nil) { assetURL, error in if let error = error { print("保存照片失败:\(error.localizedDescription)") return } // 给已保存的照片添加位置信息 assetsLibrary.asset(for: assetURL!) { asset in asset?.setLocation(location) { error in if error == nil { print("带位置的照片保存成功啦") } else { print("添加位置信息失败:\(error?.localizedDescription ?? "未知错误")") } } } failureBlock: { error in print("获取照片Asset失败:\(error?.localizedDescription ?? "未知错误")") } } } } // 兼容版本的普通保存照片方法 private func savePhoto(image: UIImage) { if #available(iOS 9.0, *) { PHPhotoLibrary.shared().performChanges({ guard let imageData = image.jpegData(compressionQuality: 0.8) else { return } PHAssetCreationRequest.forAsset().addResource(with: .photo, data: imageData, options: nil) }) { success, error in print(success ? "照片保存成功" : "保存失败:\(error?.localizedDescription ?? "未知错误")") } } else { ALAssetsLibrary().writeImageToSavedPhotosAlbum(image.cgImage!, orientation: ALAssetOrientation(rawValue: image.imageOrientation.rawValue)!) { _, error in print(error == nil ? "照片保存成功" : "保存失败:\(error?.localizedDescription ?? "未知错误")") } } } }
重要注意事项
- 权限配置:一定要在
Info.plist里添加对应的权限描述,不然App会崩溃:- 照片访问:
NSPhotoLibraryUsageDescription(iOS10+)、NSPhotoLibraryAddUsageDescription(如果只需要添加照片到相册) - 位置访问:
NSLocationWhenInUseUsageDescription(拍摄时获取位置需要)
- 照片访问:
- 版本判断:用
#available做运行时判断,避免在高版本系统调用废弃API的警告。 - 资源优化:获取到位置后记得停止CoreLocation的更新,避免不必要的电量消耗。
内容的提问来源于stack exchange,提问作者Louis Ferraiolo
相关产品推荐
相关产品推荐

