Сохранить изображение в папку с документами, используя Share Extension

Моя цель (помимо изучения того, как написать расширение приложения для 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=0x283fr = NoSense = NoSense = код ошибки 2x283f89080 файл или каталог "}}

Это происходит, когда я нажимаю кнопку "Поделиться" на фотографии в приложении "фото", нажимаю на расширение и затем нажимаю кнопку "опубликовать".

Я получаю одну и ту же ошибку независимо от того, работает она на симуляторе или на реальном устройстве.

Вот мой прогресс в этой области:

    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 при обмене изображениями из библиотеки фотографий

Поделиться изображением с помощью расширения поделиться в ios8

Как добавить мое приложение к акции

[править] Подберите макет одного из лучших ответов, но безуспешно.

3 ответа

Я просмотрел ваш код, и в нем есть какая-то ошибка. Я исправил это. Замени свой код этим

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")
            }
        }

    }
}

У меня такая же проблема. Решение, которое мне удалось реализовать:

  1. Получить URL-адрес изображения. Этот URL-адрес бесполезен, потому что я получил ошибку 260 при попытке загрузить изображение с помощью этого URL-адреса. Интересно, что это происходит после некоторых недавних обновлений, потому что это работает до
  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];
}
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 
    }
  }
Другие вопросы по тегам