iOS照片库读取访问

4

在用户授权我们访问他的相机胶卷后,我们希望能够从我们的应用程序内获取数据并上传到我们的服务。

是否有一种方法可以从文件中访问视频数据?唯一打开视频文件的方法是创建AVAsset。但这对我来说还不够。

我知道

func requestExportSessionForVideo(_ asset: PHAsset!,
                      options options: PHVideoRequestOptions!,
                 exportPreset exportPreset: String!,
                resultHandler resultHandler: ((AVAssetExportSession!,
                    [NSObject : AnyObject]!) -> Void)!) -> PHImageRequestID

但在我的情况下,我只想将视频上传到我们的服务中,不想执行以下操作:

  1. 首先通过导出到本地应用程序数据来复制视频。
  2. 然后将该数据发送到我们的服务。
  3. 删除数据。

上述方法会使用大量额外的空间和时间,并且对拥有完整16GB iPhone的用户不起作用。

好的,这是我尝试过的使用URL的方法。

var anAcces = sourceURL?.startAccessingSecurityScopedResource

if !NSFileManager.defaultManager().fileExistsAtPath(sourceURL!.path!) {
    NSLog("not exist")
}

var aFileCoordinator = NSFileCoordinator(filePresenter:nil)
var anError: NSError?

aFileCoordinator.coordinateReadingItemAtURL(sourceURL!, options:.ForUploading, error:&anError, byAccessor:  { (newURL: NSURL!) -> Void in
    var data = NSData(contentsOfURL: newURL)
    })
if let unError = anError {
    NSLog("Error \(unError)")
}

sourceURL?.stopAccessingSecurityScopedResource

此功能记录以下内容:
2015-02-08 16:20:01.947 Cameo[15706:2288691] not exist
2015-02-08 16:20:01.991 Cameo[15706:2288691] Error Error Domain=NSCocoaErrorDomain Code=257 "The operation couldn’t be completed. (Cocoa error 257.)" UserInfo=0x170876480 {NSURL=file:///var/mobile/Media/DCIM/100APPLE/IMG_0155.MOV, NSFilePath=/var/mobile/Media/DCIM/100APPLE/IMG_0155.MOV, NSUnderlyingError=0x17005a9a0 "The operation couldn’t be completed. Operation not permitted"}

你应该能够从AVAsset获取URL,然后将其传递给上传器。我已经有一段时间没有看过这个了。看看我的问题/答案。我想有人建议过一些可能适合你的东西。 - Paul Cezanne
我更新了我的问题,并附上了我尝试访问URL的代码。我尝试了两种技术:NSFileManager和NSFileCoordinator。 - mvo
1
请参见https://dev59.com/-18e5IYBdhLWcg3wJnyl#26144019 - Paul Cezanne
3
据我所知,这并不能解决问题。我可以从PHAsset检索AVURLAsset并从结果URL中读取(例如,读入NSData对象)。但是,尝试从该URL创建NSURLSessionUploadTask会抛出错误:“无法为文件file:///var/mobile/Media/DCIM/100APPLE/IMG_0730.MOV发出沙盒扩展,errno = 1”。这是问题的核心。@mvo是否可以将此详细信息添加到问题中?有人有解决此问题的方法吗?我的共享应用程序组已正确设置... - Alfie Hanssen
2个回答

2

感谢Paul的建议,我找到了解决方法:

你需要在此区块中创建一个PHImageManager requestAVAssetForVideo会话,这样你就可以访问该文件并从URL读取它的数据。

    let imageManager = PHImageManager.defaultManager()
    let videoRequestOptions = PHVideoRequestOptions()

    videoRequestOptions.deliveryMode = .HighQualityFormat
    videoRequestOptions.version = .Current
    videoRequestOptions.networkAccessAllowed = true
    videoRequestOptions.progressHandler = { (progress: Double, error: NSError!, stop: UnsafeMutablePointer<ObjCBool>, [NSObject : AnyObject]!) -> Void in

        NSLog("Progress: %@", progress.description)
    }

    videoRequestOptions.progressHandler = { (progress: Double, error: NSError!, stop: UnsafeMutablePointer<ObjCBool>, [NSObject : AnyObject]!) -> Void in

        NSLog("Progress: %@", progress.description)
    }

    imageManager.requestAVAssetForVideo(nextAsset, options: videoRequestOptions, resultHandler: { (avAsset: AVAsset!, avAudioMix: AVAudioMix!, info: [NSObject : AnyObject]!) -> Void in

        if let nextURLAsset = avAsset as? AVURLAsset {

            let sourceURL = nextURLAsset.URL

            if NSFileManager.defaultManager().fileExistsAtPath(sourceURL.path!) {
                NSLog("exist file")
            }

            var data = NSData(contentsOfURL: sourceURL)

            if let aData = data {
                NSLog("length : <\(aData.length)")
            }
            else {
                NSLog("no data read.")
            }
        }
    }

1
阅读到NSData对象中是可行的,但尝试从AVURLAsset的URL创建NSURLSessionUploadTask时会抛出错误:Failed to issue sandbox extension for file file:///var/mobile/Media/DCIM/100APPLE/IMG_0730.MOV, errno = 1。有什么想法可以解决这个问题或者为什么会发生这种情况? - Alfie Hanssen
Tumblr遇到类似的错误,尽管来源URL构造不同:https://github.com/tumblr/ios-extension-issues/blob/master/samples/BackgroundSessionErrors/ShareExtension/ShareViewController.m - Alfie Hanssen
1
我遇到了和 Alfie 一样的错误信息:“无法为文件发出沙盒扩展”。有解决方法吗? - Alyoshak

1
关于这个问题:
Failed to issue sandbox extension for file file:///var/mobile/Media/DCIM/100APPLE/IMG_0730.MOV, errno = 1

我针对这个问题的解决方法是创建一个临时路径,从而能够访问媒体文件:

  Future<void> loadAssets() async {
    List<Asset> resultList = <Asset>[];
    String error = 'No Error Detected';
    final temp = await Directory.systemTemp.create();
    List<File> imagesFileList = [];

    try {
      resultList = await MultiImagePicker.pickImages(
        maxImages: 300,
        enableCamera: true,
        selectedAssets: imagesAssetsList,
        cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
        materialOptions: MaterialOptions(
          actionBarColor: "#abcdef",
          actionBarTitle: "Example App",
          allViewTitle: "All Photos",
          useDetailsView: false,
          selectCircleStrokeColor: "#000000",
        ),
      );
    } on Exception catch (e) {
      error = e.toString();
    }
    if (!mounted) return;

    for (int i = 0; i < resultList.length; i++) {
      final data = await resultList[i].getByteData();
      imagesFileList.add(await File('${temp.path}/img$i').writeAsBytes(
          data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes)));
      print('pathnew: ${imagesFileList[i].path}');
      await uploadFileToStorage(imagesFileList[i].path);
    }

    setState(() {
      imagesAssetsList = resultList;

      _error = error;
    });
  }

我希望它能够正常工作!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接