【问题标题】:Save image to documents folder using Share Extension使用共享扩展将图像保存到文档文件夹
【发布时间】:2019-02-25 05:22:32
【问题描述】:

我的目标(除了学习如何编写 iOS 应用程序扩展)是允许用户使用包括照片在内的各种应用程序的共享按钮共享图像并自动重命名它们。最后,我想将图像保存到应用程序的“文档”文件夹中以供进一步使用。

我在尝试使实际的 didSelectPost 部分正常工作时遇到了一些问题,因为与我见过的 Objective-C 示例不同,loadItem 操作返回 NSURL 而不是 UIImage .尝试将 NSUrl 复制到我的应用程序文档文件夹时出现错误:

错误域=NSCocoaErrorDomain Code=260 "文件“IMG_0941.JPG” 无法打开,因为没有这样的文件。” UserInfo={NSFilePath=file:///var/mobile/Media/PhotoData/OutgoingTemp/B79263E5-9512-4317-9C5D-817D7EBEFA9A/RenderedPhoto/IMG_0941.JPG, NSUnderlyingError=0x283f89080 {错误域=NSPOSIXErrorDomain 代码=2 "没有这样的文件或目录"}}

当我在“照片”应用中按下照片上的分享按钮,点击我的扩展程序,然后按下“发布”按钮时,就会发生这种情况。

无论是在模拟器还是真实设备上运行,我都会遇到同样的错误。

这是我迄今为止的整体进展:

    override func didSelectPost() {
        // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
        let inputItem = extensionContext?.inputItems.first as! NSExtensionItem
        let attachment = inputItem.attachments!.first!
        if attachment.hasItemConformingToTypeIdentifier(kUTTypeJPEG as String) {
            attachment.loadItem(forTypeIdentifier: kUTTypeJPEG as String, options: nil) { data, error in
                var image: UIImage?
                if let someUrl = data as? NSURL {
                    do {
                      // a ends up being nil in both of these cases
                      let a = NSData(contentsOfFile: someUrl.absoluteString!)
                      image = UIImage(data: a as! Data)
                      // let a = try Data(contentsOf: someUrl)
                      // image = UIImage(contentsOfFile: someUrl.absoluteString)
                    } catch {
                        print(error)
                    }
                } else if let someImage = data as? UIImage {
                    image = someImage
                }

                if let someImage = image {
                    guard let compressedImagePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first?.appendingPathComponent("theimage.jpg", isDirectory: false) else {
                        return
                    }

                    let compressedImageData = someImage.jpegData(compressionQuality: 1)
                    guard (try? compressedImageData?.write(to: compressedImagePath)) != nil else {
                        return
                    }
                } else {
                    print("Bad share data")
                }
            }
        }
        // Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
        self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
    }

请注意,我将img 变量转换为NSURL。我尝试将其转换为 UIImage 但这会引发异常。

我还想对图像做一些其他的事情,比如读取它的 EXIF 数据,但现在这就是我所拥有的。任何建议都会很棒,因为我真的很难集中精力学习这个环境。

我尝试过类似但不成功的帖子,请注意它们都是Objective-C:

iOS Share Extension issue when sharing images from Photo library

Share image using share extension in ios8

How to add my app to the share sheet action

[edit] 匹配其中一个更好答案的布局,但仍然没有运气。

【问题讨论】:

    标签: ios swift ios-extensions share-extension


    【解决方案1】:

    我已经查看了您的代码,但代码中有一些错误。我已经修好了。 用它替换你的代码

    func share() {
        let inputItem = extensionContext!.inputItems.first! as! NSExtensionItem
        let attachment = inputItem.attachments!.first as! NSItemProvider
        if attachment.hasItemConformingToTypeIdentifier( kUTTypeImage as String) {
            attachment.loadItem(forTypeIdentifier: kUTTypeImage as String, options: [:]) { (data, error) in
                var image: UIImage?
                if let someURl = data as? URL {
                    image = UIImage(contentsOfFile: someURl.path)
                }else if let someImage = data as? UIImage {
                    image = someImage
                }
    
    
                if let someImage = image {
                    guard let compressedImagePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first?.appendingPathComponent("shareImage.jpg", isDirectory: false) else {
                        return
                    }
    
                    let compressedImageData = UIImageJPEGRepresentation(someImage, 1)
                    guard (try? compressedImageData?.write(to: compressedImagePath)) != nil else {
                        return
                    }
    
                }else{
                    print("bad share data")
                }
            }
    
        }
    }
    

    【讨论】:

    • 谢谢!稍后我会看看这个。代码很清晰,我通常可以看到发生了什么。我认为当我打开 IDE 时,它会更有意义。
    • 不幸的是,这不起作用。 someUrl 总是有一个指向图像的直接路径,这很好,但 image 总是以 nil 结尾。我尝试了NSURL 和absoluteString,就像我一样。它们似乎都不起作用。我正在从照片应用中挑选图片。
    • @Chris 你有没有让这个工作?完全相同的情况发生在我身上,image 总是以 nil 结尾。
    【解决方案2】:

    我也有同样的问题。我能够实施的解决方案:

    1. 获取图像的 URL。这个 URL 没用,因为我在尝试使用这个 URL 加载图像时遇到 260 错误。有趣的是,这是在最近的一些更新之后出现的,因为它之前有效
    2. 从此 URL 获取带扩展名的文件名
    3. 遍历用户照片库中的所有图像,并从 ULR 中找到图像名称 == 名称
    4. 提取图像数据
    - (void)didSelectPost {
        
        for (NSItemProvider* itemProvider in ((NSExtensionItem*)self.extensionContext.inputItems[0]).attachments ) {
            // get type of file extention (jpeg, file, url, png ...)
            NSArray *registeredTypeIdentifiers = itemProvider.registeredTypeIdentifiers;
            if ([itemProvider hasItemConformingToTypeIdentifier:registeredTypeIdentifiers.firstObject]) {
               [itemProvider loadItemForTypeIdentifier:registeredTypeIdentifiers.firstObject options:nil completionHandler:^(id<NSSecureCoding> item, NSError *error) {
                    
                    NSData *imgData;
                    NSString* imgPath = ((NSURL*) item).absoluteString;
                    if(imgPath == nil)
                        imgPath = [NSString stringWithFormat:@"%@", item];
                    
                    NSCharacterSet* set = [NSCharacterSet URLHostAllowedCharacterSet];
                    NSString* imgPathEscaped = [imgPath stringByAddingPercentEncodingWithAllowedCharacters:set];
                    
                    NSString* fileName = [imgPath lastPathComponent];
                    
                    NSError* error2 = nil;
    //try load from file path
                    __block NSData* data2 = [NSData dataWithContentsOfFile:imgPath options: NSDataReadingUncached error:&error2];
                    if(data2 == nil) //try load as URL
                        data2 = [NSData dataWithContentsOfURL:[NSURL URLWithString:imgPath] options: NSDataReadingUncached error:&error2];
                   
                   if(data2 == nil) //all failed so try hacky way 
                   {
                       NSString* searchFilename = [fileName lowercaseString];
                       
                       PHFetchResult *results = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
                       
                       [results enumerateObjectsUsingBlock:^(PHAsset *obj, NSUInteger idx, BOOL * _Nonnull stop) {
                           
                           NSArray* resources = [PHAssetResource assetResourcesForAsset:obj];
                           NSString* fileName2 = [NSString stringWithFormat:@"%@", ((PHAssetResource*)resources[0]).originalFilename].lowercaseString;
                           
                           if ([fileName2 isEqual:searchFilename])
                           {
                               NSLog(@"found %@", fileName2);
                               
                               PHImageManager* mgr = [PHImageManager defaultManager];
                               PHImageRequestOptions * options = [PHImageRequestOptions alloc];
                               options.synchronous = YES;
                               [mgr requestImageDataForAsset:obj options:options resultHandler:^(NSData * _Nullable imageData33, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info)
                               {
                                   //imageData33 is your image
                                   data2 = imageData33;
                               }];
                           }
                       }];
                       
                   }
                }];
            }
        }
        
        // Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
        [self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
    }
    

    【讨论】:

      【解决方案3】:
      func getPhotofolder() -> String{
          let fileManager = FileManager.default
          let paths = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("hsafetyPhoto")
          if !fileManager.fileExists(atPath: paths){
              try! fileManager.createDirectory(atPath: paths, withIntermediateDirectories: true, attributes: nil)
      
          }else{
              print("Already dictionary created.")
          }
      
          return  paths
      }
      
      
      func saveImageDocumentDirectory(photo : UIImage, photoUrl : String) -> Bool{
          let fileManager = FileManager.default
          let paths =  Utility.getPhotofolder().stringByAppendingPathComponent(pathComponent: photoUrl)
          print("image's path \(paths)")
          if !fileManager.fileExists(atPath: paths){
              print("file already exits \(paths)")
              let imageData = UIImageJPEGRepresentation(photo, 0.5)
              fileManager.createFile(atPath: paths as String, contents: imageData, attributes: nil)
               if !fileManager.fileExists(atPath: paths){
                  return false
               }else{
                  return true
              }
           }else{
              print(paths)
              let imageData = UIImageJPEGRepresentation(photo, 0.5)
              fileManager.createFile(atPath: paths as String, contents: imageData, attributes: nil)
              if !fileManager.fileExists(atPath: paths){
                  return false
              }else{
                  return true
              }
          }
      }
      
       func showimage(image_name : String) {
       let documentsUrl = URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]) 
       let imgUrl =  documentsUrl.appendingPathComponent(image_name)
      
       if(FileManager.default.fileExists(atPath:imgUrl.path))
       {
      do {
           let data = try Data(contentsOf:imgUrl)
           self.imageView.image = UIImage(data:data)
          }catch {
         print(error)
         } } else{
        self.imageView.image = UIImage(named:"default.jpg") //Display any default image 
          }
        }
      

      【讨论】:

      • 我对这一切都很陌生,我很难阅读答案或知道它到底在做什么。你能评论一些事情来解释发生了什么吗?
      猜你喜欢
      • 1970-01-01
      • 2015-12-22
      • 1970-01-01
      • 1970-01-01
      • 2012-10-16
      • 2018-03-24
      • 2020-04-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多