iOS 13 为从 UIImagePickController 中选择的文件添加 "trim." 前缀
iOS 13 adds "trim." prefix to files selected from UIImagePickController
iOS 13 从照片中选择文件时添加trim.
前缀:
file:///private/var/mobile/Containers/Data/PluginKitPlugin/FPDLKFHEQ-4T56-3456-HTE2-39EK2KDJUR/tmp/trim.DFLSPD0F-32RE-UYI8-DFHA-DPFLEOW098UH.MOV
之前iOS-13是这样的:
file:///private/var/mobile/Containers/Data/PluginKitPlugin/FPDLKFHEQ-4T56-3456-HTE2-39EK2KDJUR/tmp/DFLSPD0F-32RE-UYI8-DFHA-DPFLEOW098UH.MOV
这是将文件 URL 传递给 alamofire 以将文件上传到后端服务器时出现的问题。它会导致 "unknown error" 并且上传失败。也许 alamofire 在使用那个小前缀时遇到了麻烦?
有解决办法吗?
也许您现在应该重命名您的文件。
var lastPathComponent = yourFileURL.lastPathComponent
if lastPathComponent.lowercased().contains("trim") {
lastPathComponent = lastPathComponent.replacingOccurrences(of: "trim.", with: "")
try? yourFileURL.setResourceValue(lastPathComponent, forKey: URLResourceKey.nameKey)
// considering your fileURL is an nsurl
}
是的,这里有人遇到过。我会扩展答案。
您可能需要将该视频复制到临时文件夹中,因此在您的 UIImagePickerControllerDelegate
方法中:
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let mediaType = info[.mediaType] as? String,
mediaType == "public.movie",
let trimVideoURL = info[.mediaURL] as? URL {
if #available(iOS 13, *) {
// 1
let urlSlices = trimVideoURL.relativeString.split(separator: ".")
// 2
let tempDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
// 3
let targetFileURL = tempDirectoryURL.appendingPathComponent(String(urlSlices[1])).appendingPathExtension(String(urlSlices[2]))
do {
// 4
try FileManager.default.copyItem(at: trimVideoURL, to: targetFileURL)
} catch {
print(error.localizedDescription)
}
// use the video file via targetFileURL path
}
}
}
这里有 trimVideURL,需要按 .
进行切片
file:///private/var/mobile/Containers/Data/PluginKitPlugin/ECD6D7FD-35A8-47E2-8323-808454A32C37/tmp/trim.919BDBB7-E711-49AA-BB84-89E9B0416045.MOV
创建临时目录:
file:///private/var/mobile/Containers/Data/Application/FCD3E053-82DF-4EAE-86BA-4C65880D5B90/tmp/
在临时文件夹中编写目标文件名:file:///private/var/mobile/Containers/Data/Application/FCD3E053-82DF-4EAE-86BA-4C65880D5B90/tmp/919BDBB7-E711-49AA-BB84-89E9B0416045.MOV
最后使用 FileManager
将项目复制到您的临时文件夹
准备好后,您可以使用以下方法删除文件:
do {
try FileManager.default.removeItem(at: targetFileURL)
} catch {
print(error.localizedDescription)
}
Good article关于临时文件
此外,您可以将此测试项目作为参考,只需将其复制到新创建的项目中即可测试功能:
import UIKit
import WebKit
class ViewController: UIViewController, UINavigationControllerDelegate {
var imageView: UIImageView!
var videoView: WKWebView!
var selectButton: UIButton!
var deleteButton: UIButton!
var pickerController: UIImagePickerController?
var targetFileURL: URL?
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
setupPickerController()
}
func configureUI() {
imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
videoView = WKWebView()
videoView.translatesAutoresizingMaskIntoConstraints = false
selectButton = UIButton(type: .system)
selectButton.setTitle("Select", for: .normal)
selectButton.addTarget(self, action: #selector(showImagePicker), for: .touchUpInside)
selectButton.translatesAutoresizingMaskIntoConstraints = false
deleteButton = UIButton(type: .system)
deleteButton.setTitle("Delete", for: .normal)
deleteButton.addTarget(self, action: #selector(deleteCurrentTempFile), for: .touchUpInside)
deleteButton.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageView)
view.addSubview(videoView)
view.addSubview(selectButton)
view.addSubview(deleteButton)
imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 250.0).isActive = true
videoView.topAnchor.constraint(equalTo: imageView.bottomAnchor).isActive = true
videoView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
videoView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
videoView.heightAnchor.constraint(equalTo: imageView.heightAnchor).isActive = true
deleteButton.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
deleteButton.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
deleteButton.heightAnchor.constraint(equalToConstant: 60.0).isActive = true
deleteButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
selectButton.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
selectButton.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
selectButton.heightAnchor.constraint(equalTo: deleteButton.heightAnchor).isActive = true
selectButton.bottomAnchor.constraint(equalTo: deleteButton.topAnchor).isActive = true
view.layoutIfNeeded()
}
func setupPickerController() {
self.pickerController = UIImagePickerController()
self.pickerController?.delegate = self
if let mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary) {
self.pickerController?.mediaTypes = mediaTypes
}
}
private func action(for type: UIImagePickerController.SourceType, title: String) -> UIAlertAction? {
guard UIImagePickerController.isSourceTypeAvailable(type) else {
return nil
}
return UIAlertAction(title: title, style: .default) { [unowned self] _ in
self.pickerController?.sourceType = type
if let pickerController = self.pickerController {
self.present(pickerController, animated: true)
}
}
}
@IBAction func showImagePicker() {
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
if let action = self.action(for: .photoLibrary, title: "Photo library") {
alertController.addAction(action)
}
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alertController, animated: true)
}
@IBAction func deleteCurrentTempFile() {
if let url = targetFileURL,
FileManager.default.fileExists(atPath: url.path) {
removeTemporaryFile(at: url)
}
}
func didSelectMedia(image: UIImage?, videoURL: URL?) {
if let image = image {
imageView.image = image
} else if let videoURL = videoURL {
let request = URLRequest(url: videoURL)
videoView.load(request)
targetFileURL = videoURL
}
}
// remove it when you done
func removeTemporaryFile(at url: URL) {
do {
try FileManager.default.removeItem(at: url)
} catch {
print(error.localizedDescription)
}
targetFileURL = nil
}
}
extension ViewController: UIImagePickerControllerDelegate {
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let mediaType = info[.mediaType] as? String {
if mediaType == "public.movie", let trimVideoURL = info[.mediaURL] as? URL {
if #available(iOS 13, *) {
let urlSlices = trimVideoURL.relativeString.split(separator: ".")
let tempDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let targetFileURL = tempDirectoryURL.appendingPathComponent(String(urlSlices[1])).appendingPathExtension(String(urlSlices[2]))
do {
try FileManager.default.copyItem(at: trimVideoURL, to: targetFileURL)
} catch {
print(error.localizedDescription)
}
self.didSelectMedia(image: nil, videoURL: targetFileURL)
} else {
self.didSelectMedia(image: nil, videoURL: trimVideoURL)
}
} else if mediaType == "public.image", let image = info[.originalImage] as? UIImage {
self.didSelectMedia(image: image, videoURL: nil)
}
}
picker.dismiss(animated: true, completion: nil)
}
}
iOS 13 从照片中选择文件时添加trim.
前缀:
file:///private/var/mobile/Containers/Data/PluginKitPlugin/FPDLKFHEQ-4T56-3456-HTE2-39EK2KDJUR/tmp/trim.DFLSPD0F-32RE-UYI8-DFHA-DPFLEOW098UH.MOV
之前iOS-13是这样的:
file:///private/var/mobile/Containers/Data/PluginKitPlugin/FPDLKFHEQ-4T56-3456-HTE2-39EK2KDJUR/tmp/DFLSPD0F-32RE-UYI8-DFHA-DPFLEOW098UH.MOV
这是将文件 URL 传递给 alamofire 以将文件上传到后端服务器时出现的问题。它会导致 "unknown error" 并且上传失败。也许 alamofire 在使用那个小前缀时遇到了麻烦?
有解决办法吗?
也许您现在应该重命名您的文件。
var lastPathComponent = yourFileURL.lastPathComponent
if lastPathComponent.lowercased().contains("trim") {
lastPathComponent = lastPathComponent.replacingOccurrences(of: "trim.", with: "")
try? yourFileURL.setResourceValue(lastPathComponent, forKey: URLResourceKey.nameKey)
// considering your fileURL is an nsurl
}
是的,这里有人遇到过
您可能需要将该视频复制到临时文件夹中,因此在您的 UIImagePickerControllerDelegate
方法中:
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let mediaType = info[.mediaType] as? String,
mediaType == "public.movie",
let trimVideoURL = info[.mediaURL] as? URL {
if #available(iOS 13, *) {
// 1
let urlSlices = trimVideoURL.relativeString.split(separator: ".")
// 2
let tempDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
// 3
let targetFileURL = tempDirectoryURL.appendingPathComponent(String(urlSlices[1])).appendingPathExtension(String(urlSlices[2]))
do {
// 4
try FileManager.default.copyItem(at: trimVideoURL, to: targetFileURL)
} catch {
print(error.localizedDescription)
}
// use the video file via targetFileURL path
}
}
}
这里有 trimVideURL,需要按
.
进行切片file:///private/var/mobile/Containers/Data/PluginKitPlugin/ECD6D7FD-35A8-47E2-8323-808454A32C37/tmp/trim.919BDBB7-E711-49AA-BB84-89E9B0416045.MOV
创建临时目录:
file:///private/var/mobile/Containers/Data/Application/FCD3E053-82DF-4EAE-86BA-4C65880D5B90/tmp/
在临时文件夹中编写目标文件名:
file:///private/var/mobile/Containers/Data/Application/FCD3E053-82DF-4EAE-86BA-4C65880D5B90/tmp/919BDBB7-E711-49AA-BB84-89E9B0416045.MOV
最后使用
FileManager
将项目复制到您的临时文件夹
准备好后,您可以使用以下方法删除文件:
do {
try FileManager.default.removeItem(at: targetFileURL)
} catch {
print(error.localizedDescription)
}
Good article关于临时文件
此外,您可以将此测试项目作为参考,只需将其复制到新创建的项目中即可测试功能:
import UIKit
import WebKit
class ViewController: UIViewController, UINavigationControllerDelegate {
var imageView: UIImageView!
var videoView: WKWebView!
var selectButton: UIButton!
var deleteButton: UIButton!
var pickerController: UIImagePickerController?
var targetFileURL: URL?
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
setupPickerController()
}
func configureUI() {
imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
videoView = WKWebView()
videoView.translatesAutoresizingMaskIntoConstraints = false
selectButton = UIButton(type: .system)
selectButton.setTitle("Select", for: .normal)
selectButton.addTarget(self, action: #selector(showImagePicker), for: .touchUpInside)
selectButton.translatesAutoresizingMaskIntoConstraints = false
deleteButton = UIButton(type: .system)
deleteButton.setTitle("Delete", for: .normal)
deleteButton.addTarget(self, action: #selector(deleteCurrentTempFile), for: .touchUpInside)
deleteButton.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageView)
view.addSubview(videoView)
view.addSubview(selectButton)
view.addSubview(deleteButton)
imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 250.0).isActive = true
videoView.topAnchor.constraint(equalTo: imageView.bottomAnchor).isActive = true
videoView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
videoView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
videoView.heightAnchor.constraint(equalTo: imageView.heightAnchor).isActive = true
deleteButton.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
deleteButton.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
deleteButton.heightAnchor.constraint(equalToConstant: 60.0).isActive = true
deleteButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
selectButton.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
selectButton.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
selectButton.heightAnchor.constraint(equalTo: deleteButton.heightAnchor).isActive = true
selectButton.bottomAnchor.constraint(equalTo: deleteButton.topAnchor).isActive = true
view.layoutIfNeeded()
}
func setupPickerController() {
self.pickerController = UIImagePickerController()
self.pickerController?.delegate = self
if let mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary) {
self.pickerController?.mediaTypes = mediaTypes
}
}
private func action(for type: UIImagePickerController.SourceType, title: String) -> UIAlertAction? {
guard UIImagePickerController.isSourceTypeAvailable(type) else {
return nil
}
return UIAlertAction(title: title, style: .default) { [unowned self] _ in
self.pickerController?.sourceType = type
if let pickerController = self.pickerController {
self.present(pickerController, animated: true)
}
}
}
@IBAction func showImagePicker() {
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
if let action = self.action(for: .photoLibrary, title: "Photo library") {
alertController.addAction(action)
}
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alertController, animated: true)
}
@IBAction func deleteCurrentTempFile() {
if let url = targetFileURL,
FileManager.default.fileExists(atPath: url.path) {
removeTemporaryFile(at: url)
}
}
func didSelectMedia(image: UIImage?, videoURL: URL?) {
if let image = image {
imageView.image = image
} else if let videoURL = videoURL {
let request = URLRequest(url: videoURL)
videoView.load(request)
targetFileURL = videoURL
}
}
// remove it when you done
func removeTemporaryFile(at url: URL) {
do {
try FileManager.default.removeItem(at: url)
} catch {
print(error.localizedDescription)
}
targetFileURL = nil
}
}
extension ViewController: UIImagePickerControllerDelegate {
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let mediaType = info[.mediaType] as? String {
if mediaType == "public.movie", let trimVideoURL = info[.mediaURL] as? URL {
if #available(iOS 13, *) {
let urlSlices = trimVideoURL.relativeString.split(separator: ".")
let tempDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let targetFileURL = tempDirectoryURL.appendingPathComponent(String(urlSlices[1])).appendingPathExtension(String(urlSlices[2]))
do {
try FileManager.default.copyItem(at: trimVideoURL, to: targetFileURL)
} catch {
print(error.localizedDescription)
}
self.didSelectMedia(image: nil, videoURL: targetFileURL)
} else {
self.didSelectMedia(image: nil, videoURL: trimVideoURL)
}
} else if mediaType == "public.image", let image = info[.originalImage] as? UIImage {
self.didSelectMedia(image: image, videoURL: nil)
}
}
picker.dismiss(animated: true, completion: nil)
}
}