iOS-Swift-AWSS3备份相册图片和视频

最近公司一个项目需要用到亚马逊AWS来做云存储功能,由于几个端的人员都不在同一个地方且网上AWSS3来做图片视频备份的资料几乎没有,只能是一点一点和后台人员沟通并在官网上摸索。
我这边只负责iOS端,由后台负责登录后提供OSS配置,所以关于亚马逊账号管理设置就不在下面描述了,这部分网上相关资料是蛮多的。

总结所有步骤

1.导入AWSS3
2.获取OSS配置后设置AWSServiceConfiguration
3.判断相册权限,获取相册所有照片或视频
4.将PHAsset转成Data(这一步一定要注意,要考虑上万张图片情况,具体会在下面描述)
5.使用AWSS3开始上传(上传成功后假如需要刷新页面显示时,一定不要把所有记录全部显示出来,会造成卡顿并内存暴涨崩溃)
6.通过本地存储的上传记录获取相册中的图片和视频用于UI显示
1.导入AWSS3
pod 'AWSCore'
pod 'AWSCognito'
pod 'AWSS3'
2.获取OSS配置后设置AWSServiceConfiguration
PD_appDelegate.bucketName = dataDic.dictionaryForKey("bucket").stringForKey("bucketName")
let accessKey = dataDic.stringForKey("accessKey")
let secretKey = dataDic.stringForKey("secretKey")
let endPointKey = dataDic.stringForKey("endpoint")
            
let credentialsProvider = AWSStaticCredentialsProvider(accessKey: accessKey, secretKey: secretKey)
let endPoint = AWSEndpoint(urlString: endPointKey)
let configuration = AWSServiceConfiguration(region: .USEast1, endpoint: endPoint, credentialsProvider: credentialsProvider)
            
AWSServiceManager.default().defaultServiceConfiguration = configuration
3.判断相册权限,获取相册所有照片或视频
class AuthorizationManager {
    /// 相机权限
    public static func camera(authorizedBlock: CustomNoParamTypealias?) {
        
        let authStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
        
        // .notDetermined  .authorized  .restricted  .denied
        if authStatus == .notDetermined {
            // 第一次触发授权 alert
            AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) in
                self.camera(authorizedBlock: authorizedBlock)
            })
            
        //打开相机
        } else if authStatus == .authorized {
            if authorizedBlock != nil {
                authorizedBlock!()
            }
            
        //没有权限使用相机
        } else {
            DispatchQueue.main.async {
                CommonUntils.showAlertController("权限未开启", "请在系统定位中开启相机权限", "去设置", "取消", { (alertAction) in
                    
                    let url = URL(string: UIApplication.openSettingsURLString)
                    UIApplication.shared.openURL(url!)
                })
            }
        }
    }
    
    /// 相册权限
    public static func photoAlbum(authorizedBlock: CustomNoParamTypealias?) {
        
        let authStatus = PHPhotoLibrary.authorizationStatus()
        
        // .notDetermined  .authorized  .restricted  .denied
        if authStatus == .notDetermined {
            // 第一次触发授权 alert
            PHPhotoLibrary.requestAuthorization { (status:PHAuthorizationStatus) -> Void in
                self.photoAlbum(authorizedBlock: authorizedBlock)
            }
            
        //打开相册
        } else if authStatus == .authorized  {
            if authorizedBlock != nil {
                authorizedBlock!()
            }
            
        //没有权限打开相册
        } else {
            DispatchQueue.main.async {
                CommonUntils.showAlertController("权限未开启", "请在系统定位中开启相册权限", "去设置", "取消", { (alertAction) in
                    
                    let url = URL(string: UIApplication.openSettingsURLString)
                    UIApplication.shared.openURL(url!)
                })
            }
        }
    }
}
//获取相册所有照片或视频
class AlbumManager {
    //单例
    static let shared = AlbumManager()
    
    //MARK:-获取相册所有图片
    func getAllPhoto(photoHandler: @escaping (_ assetArr: [PHAsset]) -> Void) {
        weak var weakSelf = self
        AuthorizationManager.photoAlbum {
            let assetArr: [PHAsset] = weakSelf!.getCameraRoll()
            photoHandler(assetArr)
        }
    }
    
    //MARK:-获取相册所有视频
    func getAllVideo(videoHandler: @escaping (_ assetArr: [PHAsset]) -> Void) {
        weak var weakSelf = self
        AuthorizationManager.photoAlbum {
            let assetArr: [PHAsset] = weakSelf!.getAlbumVideos()
            videoHandler(assetArr)
        }
    }
}

//MARK:*******************获取相册所有图片相关代码*******************
extension AlbumManager {
    //MARK:-先获取所有相册,然后获取相机胶卷
    private func getCameraRoll() -> [PHAsset] {
        // 所有智能相册集合(系统自动创建的相册)
        let smartAlbums: PHFetchResult = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .albumRegular, options: nil)
        
        //遍历得到每一个相册
        var photoAlbum: PHAssetCollection?
        for i in 0 ..< smartAlbums.count {
            //相册的名字是相机交卷,这里面包含了所有的资源,包括照片、视频、gif。 注意相册名字中英文
            if smartAlbums[i].localizedTitle == "相机胶卷" ||
                smartAlbums[i].localizedTitle == "Camera Roll" ||
                smartAlbums[i].localizedTitle == "最近项目" ||
                smartAlbums[i].localizedTitle == "Recents"{
                photoAlbum = smartAlbums[i]
            }
        }
        if photoAlbum == nil { return [PHAsset]() }
        
        return getPHAssetsFromAlbum(photoAlbum!)
    }
    
    //MARK:-获取相机胶卷的PHAsset集合(只选照片)
    private func getPHAssetsFromAlbum(_ collection: PHAssetCollection) -> [PHAsset] {
        // 存放所有图片对象
        var assetArr: [PHAsset] = []
        
        //时间排序、只选照片
        let options = PHFetchOptions.init()
        options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
        options.predicate = NSPredicate.init(format: "mediaType == %ld", PHAssetMediaType.image.rawValue)
        
        // 获取所有图片资源对象
        let results: PHFetchResult = PHAsset.fetchAssets(in: collection, options: options)
        
        // 遍历,得到每一个图片资源asset,然后放到集合中
        results.enumerateObjects { (asset, index, stop) in
            assetArr.append(asset)
        }
        
        return assetArr
    }
    
    //MARK:-根据PHAsset获取原图片信息
    func getImageDataFromPHAsset(_ asset: PHAsset, photoHandler: @escaping (_ imageData: Data?) -> Void) {
        
        let option: PHImageRequestOptions = PHImageRequestOptions.init()
        option.deliveryMode = PHImageRequestOptionsDeliveryMode.opportunistic
        option.resizeMode = PHImageRequestOptionsResizeMode.fast
        
        PHImageManager.default().requestImageData(for: asset, options: option) { (imageData, imageName, info, parameter) in
            photoHandler(imageData)
        }
    }
}

//MARK:*******************获取相册所有视频相关代码*******************
extension AlbumManager {
    //MARK:-先获取所有相册,然后获取视频相册
    private func getAlbumVideos() -> [PHAsset] {
        // 所有智能相册集合(系统自动创建的相册)
        let smartAlbums: PHFetchResult = PHAssetCollection.fetchAssetCollections(with: PHAssetCollectionType.smartAlbum, subtype: PHAssetCollectionSubtype.smartAlbumVideos, options: nil)
        
        //遍历得到每一个相册
        var photoAlbum: PHAssetCollection?
        for i in 0 ..< smartAlbums.count {
            //相册的名字是相机交卷,这里面包含了所有的资源,包括照片、视频、gif。 注意相册名字中英文
            if smartAlbums[i].localizedTitle == "视频" || smartAlbums[i].localizedTitle == "Videos" {
                photoAlbum = smartAlbums[i]
            }
        }
        if photoAlbum == nil { return [PHAsset]() }
        
        return getVideosFromAlbum(photoAlbum!)
    }
    
    //MARK:-获取视频相册的PHAsset集合(只选视频)
    private func getVideosFromAlbum(_ collection: PHAssetCollection) -> [PHAsset] {
        // 存放所有图片对象
        var assetArr: [PHAsset] = []
        
        //时间排序、只选照片
        let options = PHFetchOptions.init()
        options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
        options.predicate = NSPredicate.init(format: "mediaType == %ld", PHAssetMediaType.video.rawValue)
        
        // 获取所有图片资源对象
        let results: PHFetchResult = PHAsset.fetchAssets(in: collection, options: options)
        
        // 遍历,得到每一个图片资源asset,然后放到集合中
        results.enumerateObjects { (asset, index, stop) in
            assetArr.append(asset)
        }
        
        return assetArr
    }
    
    //MARK:-根据PHAsset获取视频信息
    func getVideoDataFromPHAsset(_ asset: PHAsset, videoHandler: @escaping (_ videoData: Data) -> Void) {
        
        let option: PHVideoRequestOptions = PHVideoRequestOptions.init()
        option.deliveryMode = .automatic
        option.isNetworkAccessAllowed = true
        
        PHImageManager.default().requestAVAsset(forVideo: asset, options: option) { (avasset, audioMix, info) in

            guard let avURLAsset = avasset as? AVURLAsset else {
                return
            }
            guard let data = try? Data.init(contentsOf: avURLAsset.url) else {
                return
            }
            videoHandler(data)
        }
    }
}
4.将上万的PHAsset转成Data(这一步我大概描述一下操作,需求不一样需要做的操作也不一样)

-获取已上传的文件名称或者图片localIdentifier也行(我这边是本地保存上传记录)

    //MARK:-获取相册所有图片并去除已上传的图片
    func getUploadPhotoAssetArr( _ customTypealias: @escaping (_ uploadAssetArr: [PHAsset]) -> Void) {
        
        //获取已上传的文件名称
        var alreadyUploadNameArr: [String] = []
        let dataArr = CommonValue.getHomeData()
        for i in 0 ..< dataArr.count {
            let name = dataArr.dictionaryWithIndex(i).stringForKey("titleStr")
            alreadyUploadNameArr.append(name)
        }
        
        AlbumManager.shared.getAllPhoto { (assetArr) in
            
            //用于统计真正需要上传的图片
            var uploadAssetArr: [PHAsset] = []
            
            for i in 0 ..< assetArr.count {
                
                //获取文件名称,并判断是否已上传
                guard let filename = assetArr[i].value(forKey: "filename") as? String , !alreadyUploadNameArr.contains(filename) else {
                    continue
                }
                uploadAssetArr.append(assetArr[i])
            }
            customTypealias(uploadAssetArr)
        }
    }

-获取到需要上传的图片后发通知刷新UI、开启队列、将要上传的文件数组分隔成等份的子数组(我这里设置成50,可以看情况来设置)

//获取相册所有需要上传的图片
getUploadPhotoAssetArr { (assetArr) in
    if assetArr.count == 0 {
        MBProgressHUD.showError("当前暂无可备份图片")
        return
    }
    weakSelf?.allUploadPhotoCount = assetArr.count
    
    //发送通知,开启任务页面的上传统计
    DispatchQueue.main.async {
        NotificationCenter.default.post(name: Notification.Name(StartUploadPhotoKey), object: nil)
    }

    //定义队列
    weakSelf?.uploadAllPhotoQueue = DispatchQueue.init(label: "uploadAllPhoto")
    
    //将要上传的文件数组分隔成等份的子数组
    var currentStart: Int = 0
    var currentEnd: Int = weakSelf!.groupPhotoAssetNum

    while currentStart < assetArr.count {
        currentEnd = min(currentStart + weakSelf!.groupPhotoAssetNum, assetArr.count)
        
        let subArr = Array(assetArr[currentStart ..< currentEnd]) as [PHAsset]
        weakSelf?.groupPhotoAssetArr.append(subArr)

        currentStart = currentEnd
    }
    weakSelf?.separatePhotoPHAsset()
}

-将分组后的PHAsset转成Data(每次转50张照片),然后分组用队列执行上传(这一步就不详细描述了)

5.使用AWSS3开始上传
    //MARK:-上传文件
    func uploadFile(_ fileData: Data?, _ key: String, _ contentType: String, _ asset: PHAsset? = nil, customTypealias: (() -> Void)? = nil) {
        if fileData == nil { return }
        
        let tempStr = "uploadingFile\(key.split(s: ".").first!)"
        //写入本地
        let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tempStr)
        try? fileData?.write(to: fileURL)
        
        let request = AWSS3TransferManagerUploadRequest()!
        request.bucket = PD_appDelegate.bucketName
        request.key = key
        request.body = fileURL
        request.contentType = contentType
        
        let transferManager = AWSS3TransferManager.default()
        transferManager.upload(request).continueWith(executor: AWSExecutor.mainThread()) { (task) -> Any? in

            if task.result != nil {
                DLog(message: "****\(key)上传成功****")
            }
            //删除本地文件
            FileManager.removeFile("\(NSTemporaryDirectory())/\(tempStr)")
            
            //上传数据记录本地
            let dataArr = NSMutableArray(array: CommonValue.getUploadFileData())
            let dic = NSMutableDictionary()
            dic.setValue(key, forKey: "titleStr")
            dic.setValue(Date().toString("yyyy-MM-dd HH:mm"), forKey: "timeStr")
            //图片才需要存储
            if contentType == "image/png" {
                dic.setValue(asset!.localIdentifier, forKey: "localIdentifier")
                if asset == nil {
                    dic.setValue(fileData, forKey: "imageData")
                }
            }
            dataArr.insert(dic, at: 0)
            CommonValue.setUploadFileData(dataArr)

            //发送通知,让首页和任务页刷新数据并显示
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: Notification.Name(RefreshUploadDataKey), object: dic)
            }
        
            if customTypealias != nil {
                customTypealias!()
            }
            return nil
        }
        sleep(1)
    }
6.通过本地存储的上传记录获取相册中的图片和视频用于UI显示(使用上面上传成功后存储本地的localIdentifier来获取)
if newValue!.localIdentifier == "" { return }

//通过localIdentifier从本地相册获取图片
guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [newValue!.localIdentifier], options: nil).firstObject else {
    return
}
weak var weakSelf = self
AlbumManager.shared.getImageDataFromPHAsset(asset) { (data) in
    if data == nil { return }
    
    newValue!.imageData = data!
    weakSelf?.imageB_1.setBackgroundImage(UIImage(data: newValue!.imageData), for: .normal)
}

你可能感兴趣的:(iOS-Swift-AWSS3备份相册图片和视频)