2017-08-02 1 views
2

Ich versuche, die iOS 11 Drag & Drop-Funktion in einer App von Xcode 9 Beta zu integrieren. Ich bin interessant beim Erstellen eines NSItemProvider, der von der Standard-Kalender-App verstanden werden kann. Mein Drag startet von einem UITableView, also nur eine DragDelegate-Methode implementiert.iOS 11 Drag & Drop: Drop auf Standard-Kalender App

Bisher habe ich versucht, die folgenden:

let text = "Rendez-vous at \(clientName)" 
    let data = text.data(using: .utf8) 

    let itemProvider = NSItemProvider() 
    itemProvider.registerDataRepresentation(forTypeIdentifier: kUTTypeCalendarEvent as String, visibility: .all) { completion in 
     completion(data, nil) 
     return nil 
    } 

    let dragItem = UIDragItem(itemProvider: itemProvider) 

Und auch versucht, durch die Typkennung kUTTypePlainText verwenden. Kein Glück, Kalender-App registriert den Tropfen nicht.

Ich kann keine offizielle Dokumentation darüber finden. Ich hoffe, dass die Kalender-App nach einigen Standard-Kalenderdaten sucht, und dies ist nicht auf Standard-Apps beschränkt, die miteinander kommunizieren. Sie können z. B. Text aus der Notizen-App ziehen und im Kalender ablegen, um ein Ereignis zu erstellen.

Wer weiß, was ich versuchen könnte?

Vielen Dank im Voraus.

Antwort

2

TL; DR: Die geheimen Zutaten, um den Standard-iOS Kalender-App, um Ihr benutzerdefiniertes Objekt konform mit dem NSItemProviderWriting Protokoll sind die "com.apple.ical.ics" Typkennung zu erkennen und Exportieren Ihres benutzerdefiniertes Objekts als iCalendar-String (vEvent).


Ich habe ein paar Tage damit gespielt und es endlich geschafft, es zur Arbeit zu bringen! Ich werde versuchen, meine Schritte so weit wie möglich zu durchbrechen.

  1. ein benutzerdefiniertes Objekt erstellen, die NSItemProviderWriting entspricht:
    • das Protokoll zu entsprechen, müssen Sie writableTypeIdentifiersForItemProvider und loadData(withTypeIdentifier:, forItemProviderCompletionHandler:) implementieren.
    • Das Array der Bezeichner ist eine Liste der Bezeichner, die Sie in der Reihenfolge der Wiedergabe mit höchster Genauigkeit zuerst exportieren können. Setzen Sie Ihre benutzerdefinierte Typkennung zuerst und schließen Sie danach "com.apple.ical.ics" ein.
    • Die oben genannte loadData-Funktion versucht, eine Kennung zu finden, die das Ziehziel (die Kalenderanwendung in diesem Szenario) unterstützt und die auch von Ihrer App unterstützt wird, um zuerst die höchste Wiedergabetreue zu erzielen.

Zum Beispiel:

public static var writableTypeIdentifiersForItemProvider: [String] { 
    return ["com.yourcompany.myEvent", "com.apple.ical.ics"] 
} 

public func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Void) -> Progress? { 
    switch typeIdentifier { 
    case "com.yourcompany.myEvent": // Your custom handling goes here 
    case "com.apple.ical.ics": completionHandler(createVEvent(), nil) 
    default: completionHandler(nil, YourAppError.someCustomError) 
    } 

    return nil 
} 
  1. Ein iCalendar vEvent Zeichenfolge mit Ihrer eigenen Ereignisinformation:
    • Dieser Schritt ist sehr ähnlich die Demo in Session 227 von WWDC 2017, wo sie eine vCard Zeichenfolge für einen benutzerdefinierten Kontakt erstellen. Überprüfen Sie das Demo-Projekt von dieser Sitzung.
    • Im Wesentlichen unterstützt die Kalender-App einige spezifische Arten von Typ-IDs und das iCal-Format ist eines davon.Daher müssen Sie nur eine Hilfsmethode erstellen, um den benutzerdefinierten Ereignistyp in eine iCalendar Zeichenfolge umzuwandeln.
    • Ich werde nicht in die Details auf vEvent s gehen, aber es gibt viele gute Informationen here und here.

Hier ist ein Vorschlag:

private func createVEvent() -> Data? { 
    let today = Date() 

    let dateFormatter = DateFormatter() 
    dateFormatter.dateFormat = "yyyyMMdd'T'HHmmss'Z'" 
    dateFormatter.timeZone = TimeZone(abbreviation: "UTC") 

    let startDateString = dateFormatter.string(from: startDate) 
    let endDateString = dateFormatter.string(from: endDate) 
    let todayString = dateFormatter.string(from: today) 

    var vCalendarText = "BEGIN:VCALENDAR\n" 
    vCalendarText += "VERSION:2.0\n" 
    vCalendarText += "PRODID:-//Your Company//App Name//EN\n" 
    vCalendarText += "BEGIN:VEVENT\n" 

    vCalendarText += "UID:\(identifier.uuidString)\n" 
    vCalendarText += "SUMMARY:\(name)\n" 
    vCalendarText += "DTSTAMP:\(todayString)\n" 
    vCalendarText += "DTSTART:\(startDateString)\n" 
    vCalendarText += "DTEND:\(endDateString)\n" 

    vCalendarText += "END:VEVENT\n" 
    vCalendarText += "END:VCALENDAR" 

    return vCalendarText.data(using: .utf8) 
} 

↑ Ähnlich wie bei der createVCard() Funktion aus dieser Sitzung Demo ich bereits erwähnt ...

Das ist es! Das ist alles, was Sie brauchen. Der schwierige Teil ist, zu wissen, welche Kennung die Kalender App unterstützt und wie man eine vEvent erstellt. Danke an quiker für das Finden der unterstützten Bezeichner.

Ein letzter Tipp: Sie können Ihre iCalendar-Zeichenfolge mit this nifty tool here validieren.

Beachten Sie, dass dies nur ermöglicht Drop Ihr benutzerdefiniertes Objekt. Das Ziehen einer Veranstaltung aus dem Kalender in Ihre App ist eine andere Geschichte, aber Sie können es aus meinen Tipps hier herausfinden. :)

Happy Codierung!

+0

Wow, was für eine tolle Antwort. Ich werde das heute testen und validieren. Vielen Dank für die Zeit, die Sie mit all diesen Details verbracht haben. –

+0

Hey Lucas, ich habe dein Beispiel getestet, und es funktioniert super. Aber es gibt eine Sache, die mich stört. Wenn ich keinen DTSTART-Wert einstelle, schlägt der Drop fehl. Wenn ich jedoch einen DTSTART-Wert einstelle, ist der Drop erfolgreich, ignoriert jedoch den Platz im Kalender, wenn das Element gelöscht wird. Dies verhindert den Zweck des visuellen Löschens des Elements zu dem Zeitpunkt, zu dem ich das Ereignis erstellen möchte. Irgendeine Idee ? –