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".
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)
}