Xcode Version 12.5.1
カメラロール内の動画をUIActivityViewControllerでシェアできるようにしました。
3日詰まりました。。

ImageはこんなかんじでactivityItemsにそのまま渡してやれば良いので、簡単です。
import SwiftUI
import PhotosUI //忘れずに
struct ImageShareSheet: UIViewControllerRepresentable {
@State var image: UIImage
func makeUIViewController(context: Context) -> UIActivityViewController {
let text = "Image"
let activityItems: [Any] = [image, text]
let controller = UIActivityViewController(
activityItems: activityItems,
applicationActivities: nil)
return controller
}
func updateUIViewController(_ vc: UIActivityViewController, context: Context) {
}
}
問題は動画です。
動画はURLで渡すのですが、そのまま渡すと「サンドボックス拡張機能の発行に失敗しました」というようなエラーが出ました。
私は元ファイルのURLを@StateでStringで受けとって使用していましたが、なんだろう、揮発するのかな?上手くいきませんでした。
正確に言うと、AirDropとMessageアプリでは送れるのに、メールやLINEで送れませんでした。(写真は送れたけど動画が送れず)
元になるPHAssetファイルのURLをstruct MovieShareSheet内で改めて取得し、fileManager.copyItemでTempディレクトリにコピーしてから、コピーしたファイルに対して操作を実行することで、うまく行くようになりました。やったー!
struct MovieShareSheet: UIViewControllerRepresentable {
@State var photo: PHAsset
func makeURLandCopy() -> URL {
let fileURL = photo.getURL(ofPhotoWith: photo)
print("fileURL(元): \(String(describing: fileURL))")
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let temporaryFileURL = temporaryDirectoryURL.appendingPathComponent(fileURL!.lastPathComponent)
print("temporaryFileURL(コピー先):\(temporaryFileURL)")
copyToTmp(fileURL: fileURL!, temporaryFileURL: temporaryFileURL)
return temporaryFileURL
}
func copyToTmp(fileURL: URL, temporaryFileURL: URL){
let fileManager = FileManager.default
do{try fileManager.copyItem(at: fileURL, to: temporaryFileURL)}
catch{}
return
}
func makeUIViewController(context: Context) -> UIActivityViewController {
let fileURL = makeURLandCopy()
let activityItems: [Any] = [fileURL]
let controller = UIActivityViewController(
activityItems: activityItems,
applicationActivities: nil)
return controller
}
func updateUIViewController(_ vc: UIActivityViewController, context: Context) {
}
}
extension PHAsset{
func getURL(ofPhotoWith mPhasset: PHAsset) -> URL?{
var url = URL(string:"test")
let semaphore = DispatchSemaphore(value: 0)
let options=PHVideoRequestOptions()
options.version = .current
options.isNetworkAccessAllowed = true
PHImageManager.default().requestAVAsset(forVideo: mPhasset, options: options)
{(asset:AVAsset?,audioMix, info:[AnyHashable:Any]?) -> Void in
if let urlAsset = asset as? AVURLAsset{
let localURL = urlAsset.url as URL
url = localURL
print(url!)
}else{
print("url asset nil")
}
do {semaphore.signal() }
}
if semaphore.wait(timeout: DispatchTime.distantFuture) == .success {
print("url success")
return url!
}else{
print("url timeout")
return url!
}
}
}
(Tmpファイルは自分で消さなくて大丈夫なのかな…?気になっています)
お役に立てれば幸いです!
もっと良い美しい方法があればぜひご教示ください!
参考
https://try2explore.com/questions/12413739
https://stackoverflow.com/questions/57798968/didfinishpickingmediawithinfo-returns-different-url-in-ios-13