修改多张照片时只有一个 iOS 权限对话框

Posted

技术标签:

【中文标题】修改多张照片时只有一个 iOS 权限对话框【英文标题】:Only one iOS permission dialog when modifying multiple photos 【发布时间】:2017-02-21 21:00:12 【问题描述】:

我的应用程序允许用户从相机胶卷中多选图像并将编辑应用到这些图像。但是,它会提示用户对每个图像编辑的权限。编辑用户图像时是否可以只显示一个权限对话框?如果是,我该如何将我的编辑分组到一个权限中?这是我的应用程序的屏幕截图。

我在应用商店中发现了另一个应用,它只需一个权限提示即可批量删除照片。这是该应用程序的屏幕截图。有谁知道这是否可以用于“修改”而不仅仅是“删除”?

这是我修改每个资产的代码。

  func selectImageFromCameraRoll() 
    let newImagePicker = BSImagePickerViewController()
    newImagePicker.doneButton = UIBarButtonItem(title: "Stamp", style: UIBarButtonItemStyle.done, target: self, action: nil)

    bs_presentImagePickerController(newImagePicker, animated: true,
                                    select:  (asset: PHAsset) -> Void in
                                      print("Selected")
    , deselect:  (asset: PHAsset) -> Void in
      print("Deselected")
    , cancel:  (assets: [PHAsset]) -> Void in
      print("Cancel")
    , finish:  (assets: [PHAsset]) -> Void in
      for asset in assets 
        self.saveUpdatedAsset(asset: asset)
      
      print("Finished")
    , completion: nil)


  func saveUpdatedAsset(asset: PHAsset) 
    let options = PHContentEditingInputRequestOptions()
    options.canHandleAdjustmentData =  adjustmentData in
      print("here")

      return adjustmentData.formatIdentifier == self.myIdentifier

    

    var id: PHContentEditingInputRequestID = 0
    id = asset.requestContentEditingInput(with: options) 
      input, info in
      guard let input = input else 
        asset.cancelContentEditingInputRequest(id)
        return
      

      let act = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
      act.backgroundColor = .darkGray
      act.layer.cornerRadius = 3
      act.center = self.view.center
      self.view.addSubview(act)
      act.startAnimating()

      DispatchQueue.global(qos: .userInitiated).async 
        let inurl = input.fullSizeImageURL!
        let inorient = input.fullSizeImageOrientation
        let output = PHContentEditingOutput(contentEditingInput: input)
        let outurl = output.renderedContentURL

        guard var ci = CIImage(contentsOf: inurl)?.applyingOrientation(inorient) else 
          act.removeFromSuperview()
          let ac = UIAlertController(title: "Save error", message: "Failed to edit image ????", preferredStyle: .alert)
          ac.addAction(UIAlertAction(title: "OK", style: .default))
          self.present(ac, animated: true)
          return
        
        let space = ci.colorSpace!
        let uim = UIImage(ciImage: ci)
        let width = uim.size.width
        let height = uim.size.height
        let location = Locations(rawValue: UserDefaults.standard.value(forKey: "location") as! String)!
        var point = CGPoint(x: 0, y: 0)
        switch location 
        case .topLeft:
          point = CGPoint(x: 30, y: 50)
        case .topRight:
          point = CGPoint(x: width - 30, y: 50)
        case .bottomLeft:
          point = CGPoint(x: 30, y: height - 50)
        case .bottomRight:
          point = CGPoint(x: width - 30, y: height - 50)
        case .center:
          point = CGPoint(x: width / 2, y: height / 2)
        case .topCenter:
          point = CGPoint(x: width / 2, y: 50)
        case .bottomCenter:
          point = CGPoint(x: width / 2, y: height - 50)
        
        let savedFormat = UserDefaults.standard.value(forKey: "format") as! String
        var date = Date()
        if !self.currentDateBool 
          date = UserDefaults.standard.value(forKey: "selectedDate") as! Date
        
        let timestampText = getFormattedDateFromFormatType(formatType: savedFormat, date: date) as NSString
        let timestampImage = self.textToImage(drawText: timestampText, inImage: uim, atPoint: point)
        ci = CIImage(image: timestampImage)!

        try! CIContext().writeJPEGRepresentation(of: ci, to: outurl, colorSpace: space)
        let data = NSKeyedArchiver.archivedData(withRootObject: timestampText)
        output.adjustmentData = PHAdjustmentData(
          formatIdentifier: self.myIdentifier, formatVersion: "1.0", data: data)

        phphotoLibrary.shared().performChanges(
          print("finishing")
          typealias Req = PHAssetChangeRequest
          let req = Req(for: asset)
          req.contentEditingOutput = output
        )  ok, err in
          DispatchQueue.main.async 
            act.removeFromSuperview()
            print("in completion handler")
            if ok 
              print("changed!")
             else 
              print("phasset change request error: \(err)")
            
          
        
      
    

【问题讨论】:

@rmaddy 这可能吗?从 Apple 的文档中可以看出:“如果您的应用编辑了照片库中已有资产的内容——包括您的应用最近添加的资产——照片会提示用户更改资产内容的权限。” 没关系。我想到了错误的权限对话框。你说的是删除确认。 您可能需要在一次调用 deleteAssets 时删除所有图像 @rmaddy 我正在尝试修改资产。我展示的示例删除屏幕截图是我发现的另一个应用程序,它能够通过一个权限请求删除所有资产。我想知道是否有一种方法可以通过一个权限要求修改多个资产。 一次调用performChanges即可完成所有更改请求。 【参考方案1】:

@dave-weston 是对的——您需要将这些请求合并到一个 PHPhotoLibrary.performChanges() 块中。

问题是如何 — 我自己也刚刚弄清楚了这一点。我是菜鸟,如果有更好的方法请告诉我。

// Create a dictionary with PHAsset as keys and PHContentEditingOutput as values.
var changeDict: [PHAsset: PHContentEditingOutput] = [:]

// Use two local variables to to the counting work
var _i = 0
let _n = <#YOUR_ARRAY_OF_ASSETS#>.count

// Get dict and perform changes
<#YOUR_ARRAY_OF_ASSETS#>.forEach  (asset) in
    asset.requestContentEditingInput(with: nil)  (optionalInput, info) in
        guard let input = optionalInput else return
        guard let url = input.fullSizeImageURL else return

        // perform the editing operation, which applies a noir filter in this case
        let ciImage = CIImage(contentsOf: url, options: nil)!
            .oriented(forExifOrientation: input.fullSizeImageOrientation)
        // write to output location
        let output = PHContentEditingOutput(contentEditingInput: input)
        let adjustmentData = PHAdjustmentData(formatIdentifier: "s",
                                              formatVersion: "1.2",
                                              data: "CIPhotoEffectTransfer".data(using: .utf8)!)
        output.adjustmentData = adjustmentData
        if let data = <#YOUR_CIIMAGE_TO_DATA_METHOD#> 
            do 
                try data.write(to: output.renderedContentURL, options: .atomic)
             catch 
                fatalError("Cannot write ciImage to disk.")
            
            changeDict[asset] = output
        

        // Count + 1
        _i += 1

        // Check if this is the last PHAsset to process. If so, we commit all the changes.
        if _i >= _n 
            // Commit the changes
            PHPhotoLibrary.shared().performChanges(
                for (asset, output) in changeDict 
                    let request = PHAssetChangeRequest(for: asset)
                    request.contentEditingOutput = output
                
            , completionHandler:  (success, error) in
                if success 
                 else 
                    print("Error Saving Edits:", error?.localizedDescription ?? "Unknown Error")
                
            )
        
    

这种方法存在一些问题,但目前它对我来说还可以。再次,请让我知道是否有更好的方法,可能会增加对 Grand Central Dispatch 处理流程的控制......目前它只计算所有处理的照片数量,没有任何控制照片的顺序得到处理。

【讨论】:

【参考方案2】:

来自PHPhotoLibrary的文档:

注意

对于performChanges:completionHandler:performChangesAndWait:error: 方法的每次调用,“照片”都会显示一条警报,询问用户是否允许编辑照片库的内容。如果您的应用需要一次提交多个更改,请将它们合并到一个更改块中。

...

要编辑多张现有照片的内容,请创建多个PHAssetChangeRequest 对象并将每个contentEditingOutput 属性设置为独立的PHContentEditingOutput 对象。

https://developer.apple.com/reference/photos/phphotolibrary

【讨论】:

感谢您的回复。我正在努力解决如何创建多个 PHAssetChangeRequest 对象并将每个对象的 contentEditingOutput 属性设置为独立的 PHContentEditingOutput 对象。对此有何建议?【参考方案3】:

比我想象的要容易得多,我也在找同样的问题:

    PHPhotoLibrary.shared().performChanges(
        PHAssetChangeRequest.deleteAssets(your_array_of_assets as NSFastEnumeration)
    )  (success, error) in 

【讨论】:

那是删除。我要做的是修改

以上是关于修改多张照片时只有一个 iOS 权限对话框的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 8 中编辑照片:允许“YourApp”修改这张照片?

IOS如何获取Facebook扩展权限对话框

如何在 Cordova 中显示照片库权限对话框?

iOs自动处理相机权限吗?

修改推送通知的权限请求对话框

iOS开发中的这些权限,你搞懂了吗?