Search code examples
iosswiftanimated-gifimessage-extension

How to create GIF stickers from Messages extension


I build a messages app extension, inspired from the Ice Cream Builder (Apple sample code): https://developer.apple.com/library/content/samplecode/IceCreamBuilder/Introduction/Intro.html

Instead using "png" image for my stickers, I want to use animated gif. Because gif are more fun for stickers!

In the sample code, stickers are created from file URL in xcassets folder, with PNG format.

func sticker(for mySticker: MySticker, completion: @escaping (_ sticker: MSSticker) -> Void) {

     // Determine the URL for the sticker.
    let fileName = mySticker.name! + ".png" 
    let url = cacheURL.appendingPathComponent(fileName)

    // Create an operation to process the request.
    let operation = BlockOperation {
        // Check if the sticker already exists at the URL.
        let fileManager = FileManager.default
        guard !fileManager.fileExists(atPath: url.absoluteString) else { return }

        // Create the sticker image and write it to disk.
        guard let image = UIImage(named:mySticker.name!), let imageData = UIImagePNGRepresentation(image) else { fatalError("Unable to build image for stickers") }

        do {
            try imageData.write(to: url, options: [.atomicWrite])
        } catch {
            fatalError("Failed to write sticker image to cache: \(error)")
        }
    }

    // Set the operation's completion block to call the request's completion handler.
    operation.completionBlock = {
        do {
            let sticker = try MSSticker(contentsOfFileURL: url, localizedDescription: "My Sticker")
            completion(sticker)
        } catch {
            print("Failed to write image to cache, error: \(error)")
        }
    }

    // Add the operation to the queue to start the work.
    queue.addOperation(operation)
}

I tried to edit filename:

let fileName = mySticker.name! + ".gif" 

...but of course it doesn't work

I noticed animated GIF format works in Xcode only if I create a "Sticker pack" in the xcassets folder.

enter image description here

But my code doesn't work with it, error to this line :

 guard let image = UIImage(named:mySticker.name!), let imageData = UIImagePNGRepresentation(image) else { fatalError("Unable to build image for stickers") }

It seems logical, but I don't find a workaround.


Solution

  • The solution was quite simple. Use directly the path .gif. Be careful, if your gif are in a specific folder, this folder must not be a folder reference.

    func sticker(for mySticker: MySticker, completion: @escaping (_ sticker: MSSticker) -> Void) {
    
        let fileName = mySticker.name + ".gif"
    
        let url = cacheURL.appendingPathComponent(fileName)
    
        // Create an operation to process the request.
        let operation = BlockOperation {
    
        // Check if the sticker already exists at the URL.
         let fileManager = FileManager.default
         guard !fileManager.fileExists(atPath: url.absoluteString) else { return }
    
        // Create the sticker image and write it to disk.
        guard let image = UIImage(named:mySticker.name), let imageData = UIImagePNGRepresentation(image) else { fatalError("Unable to build image \(mySticker.name)") }
    
            do {
                try imageData.write(to: url, options: [.atomicWrite])
    
            } catch {
                fatalError("Failed to write sticker image \(mySticker.name) to cache: \(error)")
            }
        }
    
    
        // Set the operation's completion block to call the request's completion handler.
        operation.completionBlock = {
            do {
                let sticker = try MSSticker(contentsOfFileURL: url, localizedDescription: "My Sticker")
                completion(sticker)
            } catch {
                print("Failed to write image to cache, error: \(error)")
            }
        }
    }
    

    with

    struct MySticker {
       var name: String
       var num: Int
    }