Brandon Stillitano
Brandon Stillitano

Reputation: 1736

Generating QR Code for vEvent gives error "No usable data found"

I am trying to generate a QR code, that when scanned, will prompt the user to add an event to their calendar. I know that this is possible as I've used services like qrmonkey to generate codes that my iOS device will prompt me to do this.

I've created a function that successfully generates a QR code and is scannable. The function is below.

func generateCalendarEvent(summary: String, location: String?, url: String?, description: String?, startDate: Date, endDate: Date) -> UIImage? {
        //Generate Event String
        var eventString: String = "BEGIN:VEVENT"
        eventString.append("\nSUMMARY:\(summary)")
        if let locationString: String = location {
            eventString.append("\nLOCATION:\(locationString)")
        }
        if let urlString: String = url {
            eventString.append("\nURL:\(urlString)")
        }
        if let descriptionString: String = description {
            eventString.append("\nDESCRIPTION:\(descriptionString)")
        }
        eventString.append("\nDTSTART:\(startDate.formatted(format: "yyyymmdd'T'hhmmss"))")
        eventString.append("\nDTEND:\(endDate.formatted(format: "yyyymmdd'T'hhmmss"))")
        eventString.append("\nEND:VEVENT")

        //Setup Filter
        guard let filter = CIFilter(name: "CIQRCodeGenerator") else {
            return nil
        }
        filter.setValue(eventString.data(using: .utf8), forKey: "inputMessage")
        
        //Setup Transform
        let transform = CGAffineTransform(scaleX: 3, y: 3)
        
        guard let output = filter.outputImage?.transformed(by: transform) else {
            return nil
        }
        return UIImage(ciImage: output)
    }

When I scan the generated QR code though, it gives me an error on the iOS device saying "No usable data found".

Upvotes: 0

Views: 781

Answers (1)

DonMag
DonMag

Reputation: 77690

You didn't show what you're using for .formatted(format: "yyyymmdd'T'hhmmss")...

But, assuming it produces the string you're expecting, the problem appears to be the format of DTSTART AND DTEND.

You are using ":" where you should be using ";":

DTSTART:
DTEND:

should be:

DTSTART;
DTEND;

Try this... if it works, try it with your .formatted(...) extension:

func generateCalendarEvent(summary: String, location: String?, url: String?, description: String?, startDate: Date, endDate: Date) -> UIImage? {
    //Generate Event String
    var eventString: String = "BEGIN:VEVENT"
    eventString.append("\nSUMMARY:\(summary)")
    if let locationString: String = location {
        eventString.append("\nLOCATION:\(locationString)")
    }
    if let urlString: String = url {
        eventString.append("\nURL:\(urlString)")
    }
    if let descriptionString: String = description {
        eventString.append("\nDESCRIPTION:\(descriptionString)")
    }
    
    let df = DateFormatter()
    df.dateFormat = "yyyymmdd'T'hhmmss"

    eventString.append("\nDTSTART;VALUE=DATE:\(df.string(from: startDate))")
    eventString.append("\nDTEND;VALUE=DATE:\(df.string(from: startDate))")
    
    eventString.append("\nEND:VEVENT")
    
    //Setup Filter
    guard let filter = CIFilter(name: "CIQRCodeGenerator") else {
        return nil
    }
    filter.setValue(eventString.data(using: .utf8), forKey: "inputMessage")
    
    //Setup Transform
    let transform = CGAffineTransform(scaleX: 3, y: 3)
    
    guard let output = filter.outputImage?.transformed(by: transform) else {
        return nil
    }
    return UIImage(ciImage: output)
}

Upvotes: 1

Related Questions