0

I am currently using an image picker for an iOS app to get a picture from the camera role, then trying to send it to a PHP Script on a web server to save the image at the other end.

When the the line of code task.resume() runs, however, this error is thrown:

[discovery] errors encountered while discovering extensions: Error Domain=PlugInKit Code=13 "query cancelled" UserInfo={NSLocalizedDescription=query cancelled}

The image does not save at the destination either, after this happens.

I've read several other posts about this error, and have tried exposing a the didFinishPickingMediaWithInfo to objective-c with @objc.

I've got the Privacy - Photo Library Usage Description assigned in the plist. I've also allowed Arbitrary Loads.

Through all this the error still occurs, so if anyone can spot anything wrong with my code it would help a lot. I'll also add the PHP Script so you can see where the data is sent to, thanks.

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegate {

    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var uploadButton: UIButton!
    @IBOutlet weak var progressView: UIProgressView!
    @IBOutlet weak var progressLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        checkPermission()
    }

    func checkPermission() {
        let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
        switch photoAuthorizationStatus {
        case .authorized:
            print("Access is granted by user")
        case .notDetermined:
            PHPhotoLibrary.requestAuthorization({
                (newStatus) in
                print("status is \(newStatus)")
                if newStatus ==  PHAuthorizationStatus.authorized {
                    /* do stuff here */
                    print("success")
                }
            })
            print("It is not determined until now")
        case .restricted:
            // same same
            print("User do not have access to photo album.")
        case .denied:
            // same same
            print("User has denied the permission.")
        }
    }

    @IBAction func uploadTapped(_ sender: UIButton) {
        let pickerController = UIImagePickerController()
        pickerController.delegate = self
        pickerController.sourceType = UIImagePickerController.SourceType.photoLibrary

        self.present(pickerController, animated: true, completion: nil)
    }

    @objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        imageView.image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage

        imageView.backgroundColor = UIColor.clear
        self.dismiss(animated: true, completion: nil)

        uploadImage()
    }

    func uploadImage() {
        let imageData = imageView.image!.jpegData(compressionQuality: 1)

        if imageData == nil {
            return
        }

        self.uploadButton.isEnabled = false

        let uploadScriptURL = NSURL(string: "I've removed the URL for this question, but a valid URL to the PHP goes here")
        var request = URLRequest(url: uploadScriptURL! as URL)
        request.httpMethod = "POST"
        request.setValue("Keep-Alive", forHTTPHeaderField: "Connection")

        let configuration = URLSessionConfiguration.default
        let session = URLSession(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main)

        let task = session.uploadTask(with: request, from: imageData!)
        print(imageData!)
        task.resume()
    }

    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        let alert = UIAlertController(title: "Alert", message: error?.localizedDescription, preferredStyle: .alert)
        self.present(alert, animated: true, completion: nil)
        self.uploadButton.isEnabled = true
    }

    func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
        let uploadProgress:Float = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
        progressView.progress = uploadProgress
        let progressPercent = Int(uploadProgress * 100)
        progressLabel.text = "\(progressPercent)%"
    }

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
        self.uploadButton.isEnabled = true
    }
}

PHP Script:

<?php
    $target_dir = "uploads";
    if(!file_exists($target_dir))
    {
        mkdir($target_dir, 0777, true);
    }
    $target_dir = $target_dir . "/" . basename($_FILES["file"]["name"]);
    if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_dir)) {
        echo json_encode([
            "Message" => "The file ". basename( $_FILES["file"]["name"]). " has been uploaded.",
            "Status" => "OK"
        ]);
    } else {
        echo json_encode([
            "Message" => "Sorry, there was an error uploading your file.",
            "Status" => "Error"
        ]);
    }
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
Ethan Humphries
  • 1,786
  • 3
  • 19
  • 28
  • Is the request actually being made from iOS, do you see `progressLabel` getting updated? – Dávid Pásztor Oct 12 '18 at 11:35
  • @DávidPásztor `progressLabel` gets updated, from 0% to 100%, whilst the `progressView` also updates correspondingly. – Ethan Humphries Oct 12 '18 at 11:39
  • 1
    I get it too, even though everything works properly. I wish I could explain what is happening, but I can't Instead, if you look at the second answer here: https://stackoverflow.com/questions/44465904/photopicker-discovery-error-error-domain-pluginkit-code-13#44907240 you'll find a way to squelch it in the console. (And a comment to this answer agrees with me, it doesn't explain what it is. I typically leave this variable enabled until I am finished and want to archive/upload to the App Store. I have two apps that were accepted - and I believe it was Xcode 9 where this started appearing. –  Oct 12 '18 at 12:01
  • @dfd So this error doesn't affect anything of the processes for you? If that's the case it may be unrelated to the issue where my image won't save. I'll double check everything on the server-side, thanks. – Ethan Humphries Oct 12 '18 at 12:15
  • To be specific, I'm using `UIImagePickerController` and everything works fine. I get this "error" when dismissing it. I'm currently going through *all* the answers in the link I posted and so far none have worked. –  Oct 12 '18 at 12:17
  • It's strange that there seems to be no real definition for what causes the error, but if it doesn't seem to affect anything, I'll try to debug the entire process and see if I can pick anything up that may disrupt the process. – Ethan Humphries Oct 12 '18 at 12:20

1 Answers1

0

So it turns out my issue was not caused by this error, and it seems that the error does not actually have any effect on the code - It seems it can be ignored.

In my case, the code wasn't working due to an oversight on my end. The image I was trying to send was 2.2MB, and I hadn't realised it was returning a HTML error code 413, due to the cap being 2MB on the server I was testing.

If you are having issues with a task like this failing make sure to print out response in the didReceive response function of the urlSession. That way you can check any HTML errors that get returned.

Ethan Humphries
  • 1,786
  • 3
  • 19
  • 28