3

I am creating an iOS application through which users can print the files on their device. From my application, I can access the files on the device though the DocumentPicker provided by other apps such as iCloud Drive, Dropbox, etc.

Now, I want to add a functionality where user can share the file with my application through an other application. I created an Action Extension for that. For example, if I select an Image in the Photos application and select Share I get my extension in the Share sheet and when I select it, I also get the URL of the file. Next, I am creating a zip file of this file to send it to my server. But the issue is, the zip file is always empty. The code I am using is as below:

In Action Extension's viewDidLoad()

if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
    itemProvider.loadItemForTypeIdentifier(kUTTypeImage as String, options: nil, 
        completionHandler: { (image, error) in
            NSOperationQueue.mainQueue().addOperationWithBlock {
                print("Image: \(image.debugDescription)")
                //Image: Optional(file:///Users/guestUser/Library/Developer/CoreSimulator/Devices/00B81632-041E-47B1-BACD-2F15F114AA2D/data/Media/DCIM/100APPLE/IMG_0004.JPG)
                print("Image class: \(image.dynamicType)")
                //Image class: Optional<NSSecureCoding>
                self.filePaths.append(image.debugDescription)
                let zipPath = self.createZip(filePaths)
                print("Zip: \(zipPath)")
            }
         })
}

And my createZip function is as follows:

func createZipWithFiles(filePaths: [AnyObject]) -> String {
    let zipPath = createZipPath()  //Creates an unique zip file name

    let success = SSZipArchive.createZipFileAtPath(zipPath, withFilesAtPaths: filePaths)

    if success {
        return zipPath
    }
    else {
        return "zip prepation failed"
    }
}

Is there a way that I can create a zip of the shared files?

Prerak Sola
  • 9,517
  • 7
  • 36
  • 67
  • Is `SSZipArchive` returning an error? Are you sure you have write access to the `zipPath` and read access to all of the paths in `filePaths`? – JAL Apr 20 '16 at 13:26
  • No it does not give any error. It creates a zip file at `zipPath`, hence I have write access at `zipPath`. And, the files in `filePaths` are image files coming from the default Photos application. In the logs it says that the file does not exist at the mentioned position but I can see the file if I navigate through the terminal (for simulator). – Prerak Sola Apr 20 '16 at 13:31
  • Using `image.debugDescription` is not the way to get a file path to the image. First, what is the actual type of `image` in the completion handler? What is the output of `image.debugDescription`? – rmaddy Apr 22 '16 at 16:26
  • @rmaddy: image is of type `NSSecureCoding` and the output of `image.debugDescription` is somethings like`fie:///Users/xxx/Library/Developer/CoreSimulator/Devices/---xx-xx-xx/data/Media/DCIM/100APPLE/IMG_0004.jpg` – Prerak Sola Apr 25 '16 at 07:44
  • You have post 2 func. In the first you use self.createZip(filePaths), and in the second you post func createZipWithFiles, but i dont see any createZip method.. – Alessandro Ornano Apr 25 '16 at 10:48
  • @AlessandroOrnano: As I have mentioned in the comments, `createZip()` function just creates a unique file name. So it returns a string like `xxx-yy-zzz.zip`. – Prerak Sola Apr 25 '16 at 13:35
  • @PrerakSola Update your question with the actual and complete output of the line `print("Image: \(image.debugDescription)")`. – rmaddy Apr 25 '16 at 14:35
  • @rmaddy: Added the complete output in the comment below the print statement. – Prerak Sola Apr 25 '16 at 14:42
  • OK, now add the output of `print("Image class: \(image.dynamicType)")`. – rmaddy Apr 25 '16 at 14:48
  • @rmaddy added that too. – Prerak Sola Apr 25 '16 at 14:51

1 Answers1

3

Your primary issue is that you are blindly adding image.debugDescription to an array that is expecting a file path. The output of image.debugDescription isn't at all a valid file path. You need to use a proper function on the image to obtain the actual file path.

But image is declared to have a type of NSSecureCoding. Based on the output of image.debugDescription, it seems that image is really of type NSURL. So you need to convert image to an NSURL using a line like:

if let photoURL = image as? NSURL {
}

Once you have the NSURL, you can use the path property to get the actual needed path.

So your code becomes:

if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
    itemProvider.loadItemForTypeIdentifier(kUTTypeImage as String, options: nil, 
        completionHandler: { (image, error) in
            if let photoURL = image as? NSURL {
                NSOperationQueue.mainQueue().addOperationWithBlock {
                    let photoPath = photoURL.path
                    print("photoPath: \(photoPath)")
                    self.filePaths.append(photoPath)
                    let zipPath = self.createZip(filePaths)
                    print("Zip: \(zipPath)")
                }
            }
    })
}

Hint: Never use debugDescription for anything other than a print statement. Its output is just some string that could contain just about any information and that output can change from one iOS version to the next.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • Thank you for the answer. Before this, as a workaround, I was creating a temporary image using `NSData` in my app's sandbox and than copying that image to the zip file to upload to the server. But your way saves the processing and memory overhead of creating an extra image. – Prerak Sola Apr 25 '16 at 15:52
  • @rmaddy, I implemented shared extension in my app, In iOS 13, my share extension app can not open main app to receive shared file/image because UIApplication.shared is unavailable now. Previous all version works fine. So, how could developer receive/import data from different sources ? Suppose i want to open a file to my app from gmail or drive, any workaround ? – Jamshed Alam Feb 23 '20 at 02:48