iOS:从分享扩展向应用传输视频时画质降低问题求助
iOS分享扩展传输视频画质降低问题排查与解决
从iOS分享扩展向主应用传输视频时,视频画质会出现降低,但直接通过主应用选择并上传视频时无此问题。相关加载视频文件的代码如下:
func handleSharedFile() async { loader.startAnimating() let attachments = (self.extensionContext?.inputItems.first as? NSExtensionItem)?.attachments ?? [] let contentTypes = [UTType.data, .url] for provider in attachments { for contentType in contentTypes { guard let loadedItem = await provider.load(type: contentType) else { continue } if let url = loadedItem as? URL { await MainActor.run { if let uti = UTType(tag: url.pathExtension, tagClass: .filenameExtension, conformingTo: nil) { let videoTypes = [UTType.movie, .video, .mpeg4Movie, .movie, .quickTimeMovie] if videoTypes.contains(uti) { if UIVideoEditorController.canEditVideo(atPath: url.path) { let editorController = UIVideoEditorController() editorController.videoMaximumDuration = 90 editorController.videoPath = url.path editorController.delegate = self present(editorController, animated: true) } else { Task { let convertedUrl = await VideoConverterHelper().convertVideo(at: url, isShare: true) if let convertedUrl { // Here Upload video on server // For sample example here I'm playing video with AVPlayer self.playVideo(for: convertedUrl) } else { self.didTapCancelButton() } } } } } } return } } } loader.stopAnimating() } extension NSItemProvider { func load(type: UTType) async -> Any? { guard self.hasItemConformingToTypeIdentifier(type.identifier) else { return nil } do { let item = try await self.loadItem(forTypeIdentifier: type.identifier) if type == .data || type == .image { print("Type ", type.identifier) switch item { case let image as UIImage: return image case let data as Data: return UIImage(data: data) case let url as URL: _ = url.startAccessingSecurityScopedResource() if let image = UIImage(contentsOfFile: url.path) { return image } url.stopAccessingSecurityScopedResource() return url default: return nil } } else if let url = item as? URL { return url } } catch { print(error.localizedDescription) } return nil } }
问题原因
- 资源加载顺序不合理:当前代码优先加载
.data类型,系统通过NSItemProvider返回视频数据时,会自动对视频进行压缩,导致画质下降;而直接从应用选择视频时,获取的是原始文件URL,无压缩操作。 - UTType匹配泛化:未优先请求视频专属的UTType,而是用通用的
.data/.url类型,无法确保获取到原始视频资源。
修复方案
1. 调整资源加载顺序与UTType优先级
优先请求视频专属的UTType(如.movie、.mpeg4Movie),再回退到.url和.data,确保优先获取原始视频文件URL。
2. 优化代码实现
修改后的核心代码如下:
func handleSharedFile() async { loader.startAnimating() let attachments = (self.extensionContext?.inputItems.first as? NSExtensionItem)?.attachments ?? [] // 优先请求视频专属UTType let videoUTTypes: [UTType] = [.movie, .mpeg4Movie, .quickTimeMovie] for provider in attachments { // 尝试加载视频类型资源 for videoUTType in videoUTTypes { guard let loadedItem = await provider.load(type: videoUTType) else { continue } if let url = loadedItem as? URL { await MainActor.run { self.processVideoURL(url) } return } } // 视频类型加载失败,回退到URL和Data类型 let fallbackTypes = [UTType.url, .data] for contentType in fallbackTypes { guard let loadedItem = await provider.load(type: contentType) else { continue } if let url = loadedItem as? URL { await MainActor.run { self.processVideoURL(url) } return } } } loader.stopAnimating() } // 提取视频处理逻辑,简化代码结构 private func processVideoURL(_ url: URL) { if UIVideoEditorController.canEditVideo(atPath: url.path) { let editorController = UIVideoEditorController() editorController.videoMaximumDuration = 90 editorController.videoPath = url.path editorController.delegate = self present(editorController, animated: true) } else { Task { guard let convertedUrl = await VideoConverterHelper().convertVideo(at: url, isShare: true) else { self.didTapCancelButton() return } self.playVideo(for: convertedUrl) } } }
同时优化NSItemProvider扩展,针对视频类型做专门处理:
extension NSItemProvider { func load(type: UTType) async -> Any? { guard self.hasItemConformingToTypeIdentifier(type.identifier) else { return nil } do { let item = try await self.loadItem(forTypeIdentifier: type.identifier) // 视频类型资源直接返回URL if type.conforms(to: .video) { if let url = item as? URL { _ = url.startAccessingSecurityScopedResource() defer { url.stopAccessingSecurityScopedResource() } return url } } // 图片和数据类型处理逻辑保持不变 else if type == .data || type == .image { switch item { case let image as UIImage: return image case let data as Data: return UIImage(data: data) case let url as URL: _ = url.startAccessingSecurityScopedResource() defer { url.stopAccessingSecurityScopedResource() } return UIImage(contentsOfFile: url.path) ?? url default: return nil } } else if let url = item as? URL { return url } } catch { print(error.localizedDescription) } return nil } }
说明
- 优先请求视频专属UTType,能让系统直接返回未压缩的原始视频文件URL,避免自动压缩导致的画质损失。
- 调整加载顺序后,分享扩展将优先获取原始视频资源,与主应用直接选择视频的逻辑保持一致,解决画质差异问题。
- 使用安全作用域URL时,需确保正确调用
startAccessingSecurityScopedResource()和stopAccessingSecurityScopedResource(),保证资源可正常访问。
内容的提问来源于stack exchange,提问作者Nirav D
相关产品推荐
相关产品推荐

