blue
blue

Reputation: 7375

MessageAppExtension: how to load sticker images from assets to MSStickerBrowserView?

Alright, I know this is new for everybody but I would think it'd be a simple concept - I am following this here to make a custom sticker message app extension:

https://code.tutsplus.com/tutorials/create-an-imessage-app-in-ios-10--cms-26870

Ive copied everything exactly and am trying to create a basic MSStickerBrowserView displaying (then later filtering using logic, but haven't attempted that yet) sticker pngs I have in my assets folder here:

enter image description here

The tutorial did not load from assets it seems but rather just from their project, regardless their code is old as here:

var stickers = [MSSticker]()

    func loadStickers() {
        for i in 1...2 {
            if let url = Bundle.main.urlForResource("Sticker \(i)",  withExtension: "png") { //ERROR!!
                do {
                    let sticker = try MSSticker(contentsOfFileURL: url, localizedDescription: "")
                    stickers.append(sticker)
                } catch {
                    print(error)
                }
            }
        }
    }

I get the error

Bundle has no member URLforResource

I can't find anything on this. How can I just display my stickers programmatically in the app?

Error:

enter image description here

These are the images Im trying to load regardless of their name:

enter image description here

Upvotes: 4

Views: 2549

Answers (3)

Pastel Poop
Pastel Poop

Reputation: 1

You can put the images in a folder like so (XCODE Viewport):

enter image description here

It make things more organised but doesnt need as much code as if you would put them in a .xcasset.

It can be put done by creating a new group instead of creating an .xcasset by (Right Clicking Message Extension and clicking New Group):

enter image description here

The following code for the StickerBrowserView can be called like so:

import UIKit
import Messages

class StickerBrowserViewController: MSStickerBrowserViewController {

  var stickers = [MSSticker]()

  func changeBrowserViewBackgroundColor(color: UIColor){
    stickerBrowserView.backgroundColor = color
  }

  func loadStickers(){

    createSticker(asset: "1", localizedDescription:"grinning face")
    createSticker(asset: "2", localizedDescription:"grimacing face")
    createSticker(asset: "3", localizedDescription:"grinning face with smiling eyes")
    createSticker(asset: "4", localizedDescription:"face with tears of joy")
    createSticker(asset: "5", localizedDescription:"smiling face with open mouth")
    createSticker(asset: "6", localizedDescription:"smiling face with open mouth and smiling eyes")

  }

  func createSticker(asset: String, localizedDescription: String){

    guard let stickerPath = Bundle.main.path(forResource:asset, ofType:"png") else {
      print("couldn't create the sticker path for", asset)
      return
    }

    // we use URL so, it's possible to use image from network
    let stickerURL = URL(fileURLWithPath:stickerPath)

    let sticker: MSSticker
    do {

      try sticker = MSSticker(contentsOfFileURL: stickerURL, localizedDescription: localizedDescription)
      // localizedDescription for accessibility

      stickers.append(sticker)
    }catch {
      print(error)
      return
    }

  }

  override func numberOfStickers(in stickerBrowserView: MSStickerBrowserView) -> Int{
    return stickers.count
  }

  override func stickerBrowserView(_ stickerBrowserView: MSStickerBrowserView, stickerAt index: Int) -> MSSticker{

    return stickers[index] as MSSticker

  }

}

(Ps. Not my blog, but found it on google and it has been very useful)

Upvotes: 0

fAiSaL
fAiSaL

Reputation: 774

Just replace "resourceUrl" with:

let url = Bundle.main.url(forResource: "Sticker \(i)", withExtension: "png")

The code got replaced in Swift 3.

Upvotes: 1

JAB
JAB

Reputation: 3235

The reason that tutorial doesn't use asset catalogs is that you cannot get a valid fileURL for images placed in an .xcassets folder when calling the urlForResource method on the bundle.

You need to add your assets individually like you would other files you are bringing in to the app. Calling pathForResource or urlForResource on the bundle at that point will no longer return nil.

EDIT: Here is a function that will take a folder name, loop through it's contents and return [MSSticker]? based on what it finds

func createStickers(from folderName: String) -> [MSSticker]? {

    guard
        let path = Bundle.main.resourcePath
        else { return nil }

    var stickers = [MSSticker]()
    let folderPath = "\(path)/\(folderName)"
    let folderURL = URL(fileURLWithPath: folderPath)

    //get a list of urls in the chosen directory
    do {
        let imageURLs = try FileManager.default.contentsOfDirectory(at: folderURL,
                                                                    includingPropertiesForKeys: nil,
                                                                    options: .skipsHiddenFiles)
        //loop through the found urls
        for url in imageURLs {
            //create the sticker and add it, or handle error
            do {
                let sticker = try MSSticker(contentsOfFileURL: url, localizedDescription: "yourDescription")
                stickers.append(sticker)
            } catch let error {
                print(error.localizedDescription)
            }
        }

    } catch let error {
        print(error.localizedDescription)
    }

    //return nil if stickers array is empty
    return stickers.isEmpty ? nil : stickers
}

This should let you just call this and get what you are after:

let stickers = createStickers(from: "YourFolderName")

Please note not to include the forward slash ('/') at the beginning of the folder name.

Upvotes: 5

Related Questions