Alles, was Sie über iOS App Extensions wissen müssen



App-Erweiterungen wurden in iOS 8 veröffentlicht und machten das System für Benutzer flexibler, leistungsfähiger und erschwinglicher. Anwendungen können als Widget im Benachrichtigungscenter angezeigt werden, bieten ihre Filter für Fotos in Fotos an, zeigen eine neue Systemtastatur an und vieles mehr. Gleichzeitig wurde die Sicherheit der Benutzerdaten und des Systems gewahrt. Die Funktionen der Arbeit von App Extensions werden unten erläutert.

Apple hat immer versucht, Anwendungen sorgfältig voneinander zu isolieren. Dies ist der beste Weg, um die Sicherheit der Benutzer zu gewährleisten und ihre Daten zu schützen. Jede Anwendung erhält einen separaten Platz im Dateisystem mit eingeschränktem Zugriff. App-Erweiterungen ermöglichten die Interaktion mit der Anwendung, ohne sie zu starten oder auf dem Bildschirm anzuzeigen. Somit steht ein Teil seiner Funktionalität Benutzern zur Verfügung, wenn sie mit anderen Anwendungen oder dem System interagieren.

App-Erweiterungen sind ausführbare Dateien, die unabhängig von der enthaltenen Anwendung ausgeführt werden - Enthält App . Sie können nicht allein mit der enthaltenen App im App Store veröffentlicht werden. Alle App-Erweiterungen führen eine bestimmte Aufgabe aus und sind je nach Typ nur an einen Bereich von iOS gebunden. Beispiel: Benutzerdefinierte Tastaturerweiterungen dienen zum Ersetzen der Standardtastatur und Fotobearbeitungserweiterungen zum Bearbeiten von Fotos in Fotos. Derzeit gibt es 25 Arten von App-Erweiterungen.

Life Extension App Extension


Die Anwendung, mit der der Benutzer die App-Erweiterung startet, wird als Host-App bezeichnet . Die Host-App startet den Lebenszyklus der App-Erweiterung und sendet eine Anfrage als Antwort auf eine Benutzeraktion:



  • Der Benutzer wählt die App-Erweiterung über die Host-App aus.
  • Die Host-App sendet eine App-Erweiterungsanforderung.
  • iOS startet die App-Erweiterung im Kontext der Host-App und richtet einen Kommunikationskanal zwischen ihnen ein.
  • Der Benutzer führt eine Aktion in der App-Erweiterung aus.
  • Die App-Erweiterung schließt die Anforderung von der Host-App ab, führt eine Aufgabe aus oder startet einen Hintergrundprozess, um sie abzuschließen. Nach Abschluss der Aufgabe kann das Ergebnis an die Host-App zurückgegeben werden.
  • Sobald die App-Erweiterung ihren Code ausführt, beendet das System diese App-Erweiterung.

Wenn Sie beispielsweise ein Foto von Fotos mit der Facebook-Freigabeerweiterung freigeben, ist Facebook die enthaltende App und Fotos die Host-App. In diesem Fall startet Fotos den Lebenszyklus der Facebook-Freigabeerweiterung, wenn der Benutzer ihn im Freigabemenü auswählt:



Interaktion mit der App-Erweiterung




  • Enthält App - Host App
    Interagiere nicht miteinander.
  • App-Erweiterung - Host-App
    Interagiere mit IPC .
  • App-Erweiterung - Enthält App
    Indirekte Interaktion. App-Gruppen werden für den Datenaustausch verwendet, und Embedded Frameworks werden für allgemeinen Code verwendet. Sie können die enthaltende App über die App-Erweiterung mithilfe der URL-Schemata starten.

Generischer Code: dynamische Frameworks


Wenn die enthaltende App und die App-Erweiterung denselben Code verwenden, sollte dieser in einem dynamischen Framework platziert werden.

Beispielsweise kann eine Fotobearbeitungserweiterung einer benutzerdefinierten Fotobearbeitungsanwendung zugeordnet sein, die einige Filter aus der enthaltenen App verwendet. Eine gute Lösung wäre, ein dynamisches Framework für diese Filter zu erstellen.

Fügen Sie dazu ein neues Ziel hinzu und wählen Sie das Cocoa Touch Framework aus :



Geben Sie einen Namen an (z. B. ImageFilters ), und im Navigatorfenster wird ein neuer Ordner mit dem Namen des erstellten Frameworks angezeigt:

Sie müssen sicherstellen, dass das Framework keine APIs verwendet, die für App-Erweiterungen nicht verfügbar sind:

  • Geteilt von UIApplication.
  • Mit Unzugänglichkeitsmakros gekennzeichnete APIs.
  • Kamera und Mikrofon (außer iMessage Extension).
  • Ausführen langwieriger Hintergrundaufgaben (Funktionen dieser Einschränkung variieren je nach Art der App-Erweiterung).
  • Daten mit AirDrop empfangen.

Die Verwendung einer dieser Listen in App-Erweiterungen führt zu deren Ablehnung, wenn sie im App Store veröffentlicht werden.

In den Framework-Einstellungen unter Allgemein müssen Sie das Kontrollkästchen neben "Nur App-Erweiterungs-API zulassen" aktivieren :



Im Framework-Code müssen alle Klassen, Methoden und Eigenschaften, die in der Containing App und den App Extensions verwendet werden, public . Wo immer Sie das Framework verwenden müssen, import :

 import ImageFilters 

Datenaustausch: App-Gruppen


Die Containing App und die App Extension haben ihre eigenen begrenzten Abschnitte des Dateisystems und nur sie haben Zugriff darauf. Damit die enthaltende App und die App-Erweiterung einen gemeinsamen Container mit Lese- und Schreibzugriff haben, müssen Sie eine App-Gruppe für sie erstellen.

Die App-Gruppe wird im Apple Developer Portal erstellt :



Klicken Sie in der oberen rechten Ecke auf "+". Geben Sie im angezeigten Fenster die erforderlichen Daten ein:



Weiter Weiter -> Registrieren -> Fertig .

Wechseln Sie in den Einstellungen der enthaltenen App zur Registerkarte Funktionen, aktivieren Sie App-Gruppen und wählen Sie die erstellte Gruppe aus:



Ähnliches gilt für die App-Erweiterung:



Jetzt teilen sich die Containing App und die App Extension einen Container. Als nächstes werden wir darüber sprechen, wie man es liest und schreibt.

UserDefaults


Um eine kleine Datenmenge auszutauschen, ist es praktisch, UserDefaults zu verwenden. Sie müssen lediglich den Namen der App-Gruppe angeben:

 let sharedDefaults = UserDefaults(suiteName: "group.com.maxial.onemoreapp") 

NSFileCoordinator und NSFilePresenter


Für Big Data ist NSFileCoordinator besser geeignet, um die Lese- / Schreibkonsistenz sicherzustellen. Dadurch wird eine Beschädigung der Daten vermieden, da möglicherweise mehrere Prozesse gleichzeitig darauf zugreifen können.

Die URL des freigegebenen Containers wird wie folgt abgerufen:

 let sharedUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.maxial.onemoreapp") 

Aufzeichnung:

 fileCoordinator.coordinate(writingItemAt: sharedUrl, options: [], error: nil) { [unowned self] newUrl in do { let data = try NSKeyedArchiver.archivedData(withRootObject: self.object, requiringSecureCoding: false) try data.write(to: newUrl, options: .atomic) } catch { print(error) } } 

Lesen:

 fileCoordinator.coordinate(readingItemAt: sharedUrl, options: [], error: nil) { newUrl in do { let data = try Data(contentsOf: newUrl) if let object = try NSKeyedUnarchiver.unarchivedObject(ofClass: NSString.self, from: data) as String? { self.object = object } } catch { print(error) } } 

Es ist zu beachten, dass NSFileCoordinator synchron arbeitet. Während einige Dateien von einem Prozess belegt werden, müssen andere warten, bis sie freigegeben werden.

Wenn die App-Erweiterung wissen soll, wann die Containing App den Datenstatus ändert, wird NSFilePresenter verwendet. Dies ist ein Protokoll, dessen Implementierung folgendermaßen aussehen kann:

 extension TodayViewController: NSFilePresenter { var presentedItemURL: URL? { let sharedUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.maxial.onemoreapp") return sharedUrl?.appendingPathComponent("Items") } var presentedItemOperationQueue: OperationQueue { return .main } func presentedItemDidChange() { } } 

Die Eigenschaft presentItemOperationQueue gibt eine Warteschlange zurück, die für Rückrufe beim Ändern von Dateien verwendet wird. Die Methode presentedItemDidChange() wird aufgerufen, wenn ein Prozess, in diesem Fall die Containing App, den Inhalt der Daten ändert. Wenn Änderungen direkt mithilfe von Schreibaufrufen auf niedriger Ebene vorgenommen wurden, wird presentedItemDidChange() nicht aufgerufen. Es werden nur Änderungen gezählt, die den NSFileCoordinator .

Beim Initialisieren eines NSFileCoordinator Objekts NSFileCoordinator empfohlen, das NSFilePresenter Objekt zu übergeben, insbesondere wenn eine Dateioperation NSFilePresenter :

 let fileCoordinator = NSFileCoordinator(filePresenter: self) 

Andernfalls erhält das NSFilePresenter Objekt Benachrichtigungen über diese Vorgänge, die zu Deadlocks führen können, wenn Sie im selben Thread arbeiten.

Um den Status der Daten zu überwachen, müssen Sie die Methode addFilePresenter(_:) mit dem entsprechenden Objekt aufrufen:

 NSFileCoordinator.addFilePresenter(self) 

Alle später erstellten NSFileCoordinator Objekte kennen dieses NSFilePresenter Objekt automatisch und benachrichtigen über Änderungen in seinem Verzeichnis.

Verwenden Sie removeFilePresenter(_:) um die Überwachung des Datenstatus zu removeFilePresenter(_:) :

 NSFileCoordinator.removeFilePresenter(self) 

Kerndaten


Für die gemeinsame Nutzung von Daten können Sie SQLite und entsprechend Core Data verwenden. Sie können Prozesse verwalten, die mit gemeinsam genutzten Daten arbeiten. Um Core Data für die gemeinsame NSPersistentContainer zwischen der Containing App und der App Extension zu konfigurieren, erstellen Sie eine Unterklasse von NSPersistentContainer und überschreiben Sie die defaultDirectoryURL Methode, die die Datenspeicheradresse zurückgeben soll:

 class SharedPersistentContainer: NSPersistentContainer { override open class func defaultDirectoryURL() -> URL { var storeURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.maxial.onemoreapp") storeURL = storeURL?.appendingPathComponent("OneMoreApp.sqlite") return storeURL! } } 

AppDelegate in AppDelegate die Eigenschaft persistentContainer . Es wird automatisch erstellt, wenn beim Erstellen eines Projekts das Kontrollkästchen Kerndaten verwenden aktiviert ist. Jetzt geben wir ein Objekt der SharedPersistentContainer Klasse zurück:

 lazy var persistentContainer: NSPersistentContainer = { let container = SharedPersistentContainer(name: "OneMoreApp") container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) return container }() 

Sie müssen lediglich .xcdatamodeld zur App-Erweiterung hinzufügen. Wählen Sie im Navigatorbereich die Datei .xcdatamodeld aus. Aktivieren Sie im Dateiinspektor im Abschnitt Zielmitgliedschaft das Kontrollkästchen neben App-Erweiterung:



Somit können die enthaltende App und die App-Erweiterung Daten in denselben Speicher lesen und schreiben und dasselbe Modell verwenden.

Starten der enthaltenen App über die App-Erweiterung


Wenn die Host-App eine App-Erweiterungsanforderung sendet, stellt sie einen extensionContext bereit. Dieses Objekt verfügt über eine open(_:completionHandler:) -Methode, mit der Sie die Containing App öffnen können. Diese Methode ist jedoch nicht für alle Arten von App-Erweiterungen verfügbar. Unter iOS wird es von Today Extension und iMessage Extension unterstützt. iMessage Extension kann damit nur die Containing App öffnen. Wenn die Today Extension eine andere Anwendung damit öffnet, ist möglicherweise eine zusätzliche Überprüfung erforderlich, um sie an den App Store zu senden.

Um die Anwendung über die App-Erweiterung zu öffnen, müssen Sie das URL-Schema in der enthaltenen App definieren:



Rufen Sie als Nächstes die Methode open(_:completionHandler:) mit diesem Diagramm aus der App-Erweiterung auf:

 guard let url = URL(string: "OneMoreAppUrl://") else { return } extensionContext?.open(url, completionHandler: nil) 

Für die Arten von App-Erweiterungen, die die Methode open(_:completionHandler:) aufrufen, gibt es auch eine Möglichkeit. Es besteht jedoch die Möglichkeit, dass die Anwendung beim Einchecken im App Store abgelehnt wird. Das Wesentliche der Methode besteht darin UIResponder die Kette der UIResponder Objekte zu UIResponder , bis eine UIApplication UIResponder vorhanden ist, die den openURL Aufruf akzeptiert:

 guard let url = URL(string: "OneMoreAppUrl://") else { return } let selectorOpenURL = sel_registerName("openURL:") var responder: UIResponder? = self while responder != nil { if responder?.responds(to: selectorOpenURL) == true { responder?.perform(selectorOpenURL, with: url) } responder = responder?.next } 

Zukünftige App-Erweiterungen


App Extensions hat viel zur iOS-Entwicklung beigetragen. Allmählich erscheinen mehr Arten von App-Erweiterungen, deren Funktionen sich weiterentwickeln. Mit der Veröffentlichung des iOS 12 SDK können Sie jetzt beispielsweise mit dem Inhaltsbereich in Benachrichtigungen interagieren, der so lange fehlte.

Daher entwickelt Apple dieses Tool weiter, was Optimismus in Bezug auf seine Zukunft hervorruft.

Nützliche Links:

Offizielle Dokumentation
Daten zwischen iOS-Apps und App-Erweiterungen austauschen
Tipps zur Entwicklung von iOS 8-App-Erweiterungen

Source: https://habr.com/ru/post/de441890/


All Articles