Mark Alldritt
Mark Alldritt

Reputation: 697

QLThumbnailProvider extension does not appear to be called

I'm developing a QLThumbnailProvider extension to display thumbnails for my document type. My extension does not appear to be being called - my thumbnails are not appearing and I'm not seeing the logging I've added appearing in any log files.

I have an UIDocumentBrowserViewController based app that defines a new document type. It exports an UTI (com.latenightsw.Eureka.form). My app is able to browse, create and open documents, but the thumbnails are blank.

I've added a Thumbnail Extension target to my project. The code looks like this:

class ThumbnailProvider: QLThumbnailProvider {
    override func provideThumbnail(for request: QLFileThumbnailRequest, _ handler: @escaping (QLThumbnailReply?, Error?) -> Void) {
        // Third way: Set an image file URL.
        print("provideThumbnail: \(request)")
        handler(QLThumbnailReply(imageFileURL: Bundle.main.url(forResource: "EurekaForm", withExtension: "png")!), nil)

    }
}

I've confirmed that EurekaForm.png is part of the target and being copied to the extension's bundle (as well as the host app's bundle).

And I've confirmed that my UTI is declared:

Thumbnail Extension PList

Does anyone have any suggestions?

Upvotes: 4

Views: 2102

Answers (3)

VojtaStavik
VojtaStavik

Reputation: 2482

In my case, the extension didn't work in the simulator (Xcode 11.1). Everything works as expected on a real device (iOS 13.1.2).

Upvotes: 0

Qbyte
Qbyte

Reputation: 13273

It appears that logging and breakpoints sometimes do not work inside app extension. Even fatalErrors occur silently.

In my project I could not get the initialiser QLThumbnailReply(imageFileURL:) to work. However the other initialisers seem to work better.

Drawing the image into a context

When using the context initialiser you have to use a context size which lies between request.minimumSize and request.maximumSize.

Below I've written some code which takes an image and draws it into the context while keeping the above conditions.

override func provideThumbnail(for request: QLFileThumbnailRequest, _ handler: @escaping (QLThumbnailReply?, Error?) -> Void) {

    let imageURL = // ... put your own code here

    let image = UIImage(contentsOfFile: imageURL.path)!


    // size calculations

    let maximumSize = request.maximumSize
    let imageSize = image.size

    // calculate `newImageSize` and `contextSize` such that the image fits perfectly and respects the constraints
    var newImageSize = maximumSize
    var contextSize = maximumSize
    let aspectRatio = imageSize.height / imageSize.width
    let proposedHeight = aspectRatio * maximumSize.width

    if proposedHeight <= maximumSize.height {
        newImageSize.height = proposedHeight
        contextSize.height = max(proposedHeight.rounded(.down), request.minimumSize.height)
    } else {
        newImageSize.width = maximumSize.height / aspectRatio
        contextSize.width = max(newImageSize.width.rounded(.down), request.minimumSize.width)
    }

    handler(QLThumbnailReply(contextSize: contextSize, currentContextDrawing: { () -> Bool in
        // Draw the thumbnail here.

        // draw the image in the upper left corner
        //image.draw(in: CGRect(origin: .zero, size: newImageSize))

        // draw the image centered
        image.draw(in: CGRect(x: contextSize.width/2 - newImageSize.width/2, 
                              y: contextSize.height/2 - newImageSize.height/2,
                              width: newImageSize.width,
                              height: newImageSize.height);)

        // Return true if the thumbnail was successfully drawn inside this block.
        return true
    }), nil)
}

Upvotes: 3

joshd
joshd

Reputation: 1726

I've gotten the Thumbnail Extension rendering but it only displays its renders in the Files app (others use the App Icon) as far as I can tell.

It is important to note this issue with debugging extensions in that print to console and breakpoints may not be called even though the extension is running.

I see that you have the QLSupportedContentTypes set with your UTI but you may also want to change your UTI to something new as this is when it started working for me. I think after some testing the UTI can get corrupted. While it was working, I had a breakpoint set and it was never called.

Upvotes: 1

Related Questions