You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用UISaveVideoAtPathToSavedPhotosAlbum实现从URL保存视频到相册的简易Swift代码

如何用UISaveVideoAtPathToSavedPhotosAlbum实现从URL保存视频到相册的简易Swift代码

我完全懂你想要简洁代码的心情!你之前写的图片保存逻辑非常清晰,视频保存其实也可以沿用类似的思路,而且真的不用写一大堆@objc代码~

极简版代码(无回调,和存图片逻辑一致)

这个版本和你存图片的代码几乎一模一样,完全不用额外的@objc代码,直接就能跑:

func saveVideo() {
    // 替换成你的视频URL
    guard let videoURL = URL(string: "https://v16m-default.akamaized.net/fe144652a33b4df42aad6ac47ede1534/67277349/video/tos/useast2a/tos-useast2a-ve-0068c003/00a9393b3a6246b99081a11348575483/?a=0&bti=OUBzOTg7QGo6OjZAL3AjLTAzYCMxNDNg&ch=0&cr=0&dr=0&er=0&lr=all&net=0&cd=0%7C0%7C0%7C0&cv=1&br=5010&bt=2505&cs=0&ds=6&ft=XE5bCqT0m7jPD12iKoYJ3wU2Y3yKMeF~O5&mime_type=video_mp4&qs=0&rc=ZGRoOzloZzw0PGU3NDY1aUBpanlrNHN0OHdndjMzNTczM0BhLy1hXzIxXy0xLS1iMi0xYSMzL3NnNDI0NC9fLS0uMTZzcw%3D%3D&vvpl=1&l=202411030657353C428D976FE213CC387E&btag=e00088000") else { return }
    
    DispatchQueue.global().async {
        // 异步下载视频数据
        guard let videoData = try? Data(contentsOf: videoURL) else {
            print("视频下载失败")
            return
        }
        
        // 创建临时文件路径,用于存放下载的视频
        let tempDirectory = NSTemporaryDirectory()
        let tempFilePath = tempDirectory + "temp_video.mp4"
        let tempFileURL = URL(fileURLWithPath: tempFilePath)
        
        do {
            // 把视频数据写入临时文件
            try videoData.write(to: tempFileURL)
            
            DispatchQueue.main.async {
                // 调用系统方法保存视频到相册,target和selector传nil就不用写@objc回调
                UISaveVideoAtPathToSavedPhotosAlbum(tempFilePath, nil, nil, nil)
                
                // 可选:保存完成后删除临时文件,释放空间
                try? FileManager.default.removeItem(at: tempFileURL)
            }
        } catch {
            print("临时文件写入失败:\(error.localizedDescription)")
        }
    }
}

带保存结果回调的版本

要是你想在保存完成后给用户提示(比如成功弹框、失败报错),只需要加一个超简单的@objc回调方法就行,完全算不上“ tons of code”:

第一步:添加回调方法

在你的ViewController里添加这个方法:

@objc private func videoSaveCompleted(_ success: Bool, error: Error?, contextInfo: UnsafeMutableRawPointer?) {
    DispatchQueue.main.async {
        if success {
            print("视频已成功保存到相册!")
            // 这里可以加UIAlertController提示用户
        } else {
            print("保存失败:\(error?.localizedDescription ?? "未知错误")")
        }
    }
}

第二步:修改保存代码

把之前的保存行替换成:

UISaveVideoAtPathToSavedPhotosAlbum(tempFilePath, self, #selector(videoSaveCompleted(_:error:contextInfo:)), nil)

大视频优化版本

上面的Data(contentsOf:)适合小视频,要是保存长视频,建议用URLSession流式下载,避免内存暴涨,代码同样简洁:

func saveLargeVideo() {
    guard let videoURL = URL(string: "你的视频URL") else { return }
    
    // 用URLSession异步下载视频到临时文件
    let downloadTask = URLSession.shared.downloadTask(with: videoURL) { tempURL, _, error in
        guard let tempURL = tempURL, error == nil else {
            print("下载失败:\(error?.localizedDescription ?? "未知错误")")
            return
        }
        
        // 把系统生成的临时文件移到我们自己的路径(系统临时文件会被自动删除)
        let destDir = NSTemporaryDirectory()
        let uniqueFileName = UUID().uuidString + ".mp4"
        let destURL = URL(fileURLWithPath: destDir).appendingPathComponent(uniqueFileName)
        
        do {
            try FileManager.default.moveItem(at: tempURL, to: destURL)
            
            DispatchQueue.main.async {
                // 调用保存方法,这里用带回调的版本
                UISaveVideoAtPathToSavedPhotosAlbum(destURL.path, self, #selector(videoSaveCompleted(_:error:contextInfo:)), nil)
                // 保存后删除临时文件
                try? FileManager.default.removeItem(at: destURL)
            }
        } catch {
            print("文件移动失败:\(error.localizedDescription)")
        }
    }
    
    downloadTask.resume()
}

重要提醒

你已经添加了Privacy - Photo Library Additions Usage Description到Info.plist里,这一步非常关键,否则会出现权限问题或者崩溃哦~

这样就搞定啦,和你存图片的体验一样简单,希望能帮到你 😊


备注:内容来源于stack exchange,提问作者Антон Разгуляев

火山引擎 最新活动