Un tutorial sulle estensioni dell'app iOS 8

Pubblicato: 2022-03-11

Pochi avevano provato prima (dai un'occhiata a questo), ma è stata Apple con il primo iPhone a definire come dovrebbero apparire uno smartphone e un sistema operativo mobile. Apple ha fatto un'incredibile svolta nell'hardware e nell'esperienza utente. Tuttavia, spesso dimentichiamo che stabiliscono anche degli standard su come dovrebbe funzionare un sistema operativo mobile e come dovrebbero essere realizzate le applicazioni per smartphone.

Costruire muri di cemento tra le applicazioni, rendendole completamente isolate e inconsapevoli l'una dell'altra, era il metodo migliore per mantenerle al sicuro e proteggere i loro dati. Tutte le attività sono state monitorate da vicino da iOS e c'erano solo una manciata di azioni che un'app avrebbe potuto eseguire al di fuori del suo ambito.

"L'astinenza è la migliore protezione!" - ma dov'è il divertimento in questo?

Ci è voluto un po'; troppo lungo se me lo chiedi, ma con iOS 8 Apple ha deciso di divertirsi un po'. iOS 8 ha introdotto un nuovo concetto chiamato App Extensions. Questa nuova funzionalità non ha abbattuto i muri tra le applicazioni, ma ha aperto alcune porte fornendo un contatto delicato ma tangibile tra alcune app. L'ultimo aggiornamento ha offerto agli sviluppatori iOS un'opzione per personalizzare l'ecosistema iOS e siamo ansiosi di vedere anche questo percorso aprirsi.

estensioni dell'app ios 8

Cosa sono le estensioni dell'app iOS 8 e come funzionano?

In parole povere, iOS 8 App Extensions fornisce un nuovo metodo per interagire con la tua applicazione, senza avviarla o mostrarla sullo schermo.

Come previsto, Apple si è assicurata di essere sempre al passo con tutto, quindi ci sono solo una manciata di nuovi punti di ingresso che la tua applicazione può fornire:

  • Oggi (chiamato anche widget): un'estensione visualizzata nella vista Oggi del Centro notifiche mostra brevi informazioni e consente l'esecuzione di attività rapide.
  • Condividi: un'estensione che consente alla tua app di condividere contenuti con gli utenti sui social network e altri servizi di condivisione.
  • Azione: un'estensione che consente di creare pulsanti di azione personalizzati nel foglio Azione per consentire agli utenti di visualizzare o trasformare il contenuto originato in un'app host.
  • Modifica foto: un'estensione che consente agli utenti di modificare una foto o un video all'interno dell'app Foto.
  • Document Provider: un'estensione utilizzata per consentire ad altre app di accedere ai documenti gestiti dalla tua app.
  • Tastiera personalizzata: un'estensione che sostituisce la tastiera di sistema.

Le estensioni per app non sono app autonome. Stanno fornendo funzionalità estese dell'app (a cui è possibile accedere da altre app, chiamate app host) che è pensata per essere efficiente e focalizzata su una singola attività. Hanno il proprio codice binario, la propria firma del codice e il proprio set di elementi, ma vengono forniti tramite l'App Store come parte del binario dell'app contenitore. Un'app (contenente) può avere più di un'estensione. Una volta che l'utente installa un'app con estensioni, queste saranno disponibili su iOS.

Diamo un'occhiata a un esempio: un utente trova un'immagine utilizzando Safari, preme il pulsante di condivisione e sceglie l'estensione dell'applicazione per la condivisione. Safari "parla" con il framework iOS Social, che carica e presenta l'estensione. Il codice dell'estensione viene eseguito, trasmette i dati utilizzando i canali di comunicazione istanziati del sistema e, una volta completata l'attività, Safari interrompe la visualizzazione dell'estensione. Subito dopo, il sistema termina il processo e la tua applicazione non è mai stata visualizzata sullo schermo. Eppure ha completato una funzione di condivisione delle immagini.

iOS, utilizzando la comunicazione tra processi, è l'unico responsabile di garantire che l'app host e un'estensione dell'app possano funzionare insieme. Gli sviluppatori utilizzano API di alto livello fornite dal punto di estensione e dal sistema, quindi non devono mai preoccuparsi dei meccanismi di comunicazione sottostanti.

Ciclo vitale

Ciclo di vita dell'estensione dell'app

Le estensioni delle app hanno un ciclo di vita diverso rispetto alle app iOS. L'app host avvia il ciclo di vita dell'estensione in risposta all'azione di un utente. Quindi il sistema crea un'istanza dell'estensione dell'app e imposta un canale di comunicazione tra di loro. La visualizzazione dell'interno viene visualizzata nel contesto dell'app host utilizzando gli elementi ricevuti nella richiesta dell'app host. Una volta visualizzata la vista dell'estensione, l'utente può interagire con essa. In risposta all'azione dell'utente, l'estensione completa la richiesta dell'app host eseguendo/annullando immediatamente l'attività o, se necessario, avviando un processo in background per eseguirla. Subito dopo, l'app host interrompe la visualizzazione dell'estensione e l'utente torna al contesto precedente all'interno dell'app host. I risultati dell'esecuzione di questo processo potrebbero essere restituiti all'app host una volta completato il processo. L'estensione di solito viene terminata subito dopo aver completato la richiesta ricevuta dall'app host (o aver avviato un processo in background per eseguirla).

Il sistema apre l'estensione dell'azione di un utente dall'app host, l'estensione visualizza l'interfaccia utente, esegue alcune operazioni e restituisce i dati all'app host (se appropriato per il tipo di estensione). L'app contenitore non è nemmeno in esecuzione mentre la sua estensione è in esecuzione.

Creazione di un'estensione per app - Esempio pratico utilizzando l'estensione Today

Le estensioni Oggi, dette anche widget , si trovano nella vista Oggi del Centro notifiche. Sono un ottimo modo per presentare un contenuto aggiornato per l'utente (come mostrare le condizioni meteorologiche) o eseguire attività rapide (come contrassegnare le cose fatte nel widget di un'app per l'elenco delle cose da fare). Devo sottolineare qui che l' immissione da tastiera non è supportata .

come funzionano le estensioni per app

Creiamo un'estensione Today che visualizzerà le informazioni più aggiornate dalla nostra app (codice su GitHub). Per eseguire questo codice, assicurati di aver (ri)configurato il gruppo di app per il progetto (seleziona il tuo team di sviluppo, tieni presente che il nome del gruppo di app deve essere univoco e segui le istruzioni di Xcode).

Estensione dell'app ios 8

oggi estensioni dell'app

estensione dell'app in uso oggi

Creazione di un nuovo widget

Come abbiamo detto prima, le estensioni dell'app non sono app autonome. Abbiamo bisogno di un'app contenitore su cui costruiremo l'estensione dell'app. Una volta che abbiamo la nostra app che li contiene, scegliamo di aggiungere un nuovo target navigando su File -> New -> Target in Xcode. Da qui scegliamo il modello per il nostro nuovo target per aggiungere un'estensione Today.

creazione di un modello di widget

Nella fase successiva possiamo scegliere il nome del nostro prodotto. Questo è il nome che apparirà nella vista Oggi del Centro notifiche. C'è anche un'opzione per scegliere la lingua tra Swift e Objective-C in questo passaggio. Al termine di questi passaggi, Xcode crea un modello Today, che fornisce l'intestazione predefinita e i file di implementazione per la classe principale (denominata TodayViewController ) con il file Info.plist e un file di interfaccia (uno storyboard o un file .xib). Il file Info.plist , per impostazione predefinita, ha il seguente aspetto:

 <key>NSExtension</key> <dict> <key>NSExtensionMainStoryboard</key> <string>MainInterface</string> <key>NSExtensionPointIdentifier</key> <string>com.apple.widget-extension</string> </dict>

Se non vuoi usare lo storyboard fornito dal modello, rimuovi la chiave NSExtensionMainStoryboard e aggiungi la chiave NSExtensionPrincipalClass con il nome del controller di visualizzazione come valore.

Un widget Oggi dovrebbe:

  • assicurarsi che il contenuto sia sempre aggiornato
  • rispondere in modo appropriato alle interazioni dell'utente
  • funzionare bene (i widget iOS devono utilizzare la memoria con saggezza o verranno chiusi dal sistema)

Condivisione di dati e un contenitore condiviso

L'estensione dell'app e l'app che la contiene hanno entrambe accesso ai dati condivisi nel loro contenitore condiviso definito privatamente, che è un modo di comunicazione indiretta tra l'app che lo contiene e l'estensione.

Non ti piace il modo in cui Apple rende queste cose così "semplici"? :)

La condivisione dei dati tramite NSUserDefaults è semplice e un caso d'uso comune. Per impostazione predefinita, l'estensione e l'app che la contiene usano set di dati NSUserDefaults separati e non possono accedere ai contenitori dell'altro. Per modificare questo comportamento, iOS ha introdotto App Groups . Dopo aver abilitato i gruppi di app nell'app contenitore e nell'interno, invece di usare [NSUserDefaults standardUserDefaults] usa [[NSUserDefaults alloc] initWithSuiteName:@"group.yourAppGroupName"] per accedere allo stesso contenitore condiviso.

Aggiornamento del widget

Per garantire che il contenuto sia sempre aggiornato, l'estensione Today fornisce un'API per la gestione dello stato di un widget e la gestione degli aggiornamenti del contenuto. Il sistema acquisisce occasionalmente istantanee della vista del widget, quindi quando il widget diventa visibile, viene visualizzata l'istantanea più recente fino a quando non viene sostituita con una versione live della vista. Una conformazione al protocollo NCWidgetProviding è importante per aggiornare lo stato di un widget prima di acquisire uno snapshot. Una volta che il widget riceve la chiamata widgetPerformUpdateWithCompletionHandler: la vista del widget dovrebbe essere aggiornata con il contenuto più recente e il gestore di completamento dovrebbe essere chiamato con una delle seguenti costanti per descrivere il risultato dell'aggiornamento:

  • NCUpdateResultNewData : il nuovo contenuto richiede il ridisegno della vista
  • NCUpdateResultNoDate - Il widget non richiede l'aggiornamento
  • NCUpdateResultFailed - Si è verificato un errore durante il processo di aggiornamento
 - (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler { // Perform any setup necessary in order to update the view. // If an error is encountered, use NCUpdateResultFailed // If there's no update required, use NCUpdateResultNoData // If there's an update, use NCUpdateResultNewData [self updateTableView]; completionHandler(NCUpdateResultNewData); }

Controllare quando il widget è visualizzabile

Per controllare quando viene visualizzato un widget, utilizzare il setHasContent:forWidgetWithBundleIdentifier: dalla classe NCWidgetController . Questo metodo ti consentirà di specificare lo stato del contenuto del widget. Può essere chiamato dal widget o dall'app che lo contiene (se è attivo). Puoi passare un flag NO o YES a questo metodo, definendo che il contenuto del widget è pronto o meno. Se il contenuto non è pronto, iOS non visualizzerà il widget quando viene aperta la vista Oggi.

 NCWidgetController *widgetController = [[NCWidgetController alloc] init]; [widgetController setHasContent:YES forWidgetWithBundleIdentifier:@"com.your-company.your-app.your-widget"];

Apertura dell'app contenente dal widget

Il widget Oggi è l'unica estensione che può richiedere l'apertura dell'app che lo contiene chiamando il openURL:completionHandler: Per garantire che l'app contenitore si apra in un modo che abbia senso nel contesto dell'attività corrente dell'utente, è necessario definire uno schema URL personalizzato (che possono essere utilizzati sia dal widget che dall'app contenitore).

 [self.extensionContext openURL:[NSURL URLWithString:@"customURLsheme://URLpath"] completionHandler:nil];

Considerazioni sull'interfaccia utente

Quando progetti il ​​tuo widget, sfrutta la classe UIVisualEffectView , tenendo presente che le viste che dovrebbero essere sfocate/vibranti devono essere aggiunte a contentView e non direttamente a UIVisualEffectView . I widget (conformi al protocollo NCWidgetProviding ) dovrebbero caricare gli stati memorizzati nella cache in viewWillAppear: per far corrispondere lo stato della vista dall'ultima viewWillDisappear: e quindi passare senza problemi ai nuovi dati quando arrivano, cosa che non è un caso con una vista normale controller (l'interfaccia utente è impostata in viewDidLoad e gestisce le animazioni e il caricamento dei dati in viewWillAppear ). I widget devono essere progettati per eseguire un'attività o aprire l'app che li contiene con un solo tocco. La voce della tastiera non è disponibile all'interno di un widget. Ciò significa che qualsiasi interfaccia utente che richiede l'immissione di testo non deve essere utilizzata.

L'aggiunta di pergamene in un widget, sia verticale che orizzontale, non è possibile. O più precisamente, è possibile aggiungere una vista a scorrimento ma lo scorrimento non funzionerà. Il gesto di scorrimento orizzontale in una vista di scorrimento nell'estensione Oggi verrà intercettato dal centro notifiche che causerà lo scorrimento da Oggi al Centro notifiche. Lo scorrimento verticale di una visualizzazione di scorrimento all'interno di un'estensione Oggi verrà interrotto dallo scorrimento della Visualizzazione di oggi.

Note tecniche

Qui indicherò alcune cose importanti da tenere a mente quando crei un'estensione per app.

Funzionalità comuni a tutte le estensioni

I seguenti elementi sono validi per tutte le estensioni:

  • L'oggetto sharedApplication è off limits : le estensioni dell'app non possono accedere a un oggetto sharedApplication o utilizzare uno qualsiasi dei metodi relativi a tale oggetto.

  • Fotocamera e microfono sono off limits : le estensioni dell'app non possono accedere alla fotocamera o al microfono del dispositivo (ma questo non è un caso per tutti gli elementi hardware). Questo è il risultato dell'indisponibilità di alcune API. Per accedere ad alcuni elementi hardware nell'estensione dell'app, dovrai verificare se la sua API è disponibile o meno per le estensioni dell'app (con il controllo della disponibilità dell'API descritto sopra).

  • La maggior parte delle attività in background non sono consentite: le estensioni dell'app non possono eseguire attività in background di lunga durata, ad eccezione dell'avvio di caricamenti o download, come discusso di seguito.

  • AirDrop è off limits : le estensioni dell'app non possono ricevere (ma possono inviare) dati utilizzando AirDrop.

Caricamento/Download in background

L'unica attività che può essere eseguita in background è il caricamento/scaricamento, utilizzando l' NSURLSession object .

Dopo l'avvio dell'attività di caricamento/scaricamento, l'estensione può completare la richiesta dell'app host ed essere terminata senza alcun effetto sull'esito dell'attività. Se l'estensione non è in esecuzione al termine dell'attività in background, il sistema avvia l'app contenitore in background e viene chiamato il metodo delegato application:handleEventsForBackgroundURLSession:completionHandler:

L'app la cui estensione avvia un'attività NSURLSession in background deve avere un contenitore condiviso configurato a cui possono accedere sia l'app contenitore che la relativa estensione.

Assicurati di creare sessioni in background diverse per l'app che la contiene e ciascuna delle sue estensioni per app (ogni sessione in background deve avere un identificatore univoco). Questo è importante perché solo un processo alla volta può utilizzare una sessione in background.

Azione vs condivisione

Le differenze tra le estensioni Action e Share non sono del tutto chiare dal punto di vista di un programmatore, perché in pratica sono molto simili. Il modello di Xcode per la destinazione dell'estensione di condivisione utilizza SLComposeServiceViewController , che fornisce un'interfaccia utente di visualizzazione di composizione standard che puoi utilizzare per la condivisione sui social, ma non è richiesta. Un'estensione di condivisione può anche ereditare direttamente da UIViewController per una progettazione completamente personalizzata, nello stesso modo in cui un'estensione Action può ereditare da SLComposeServiceViewController .

Le differenze tra questi due tipi di estensioni sono nel modo in cui devono essere utilizzate. Con l'estensione Action, puoi creare un'estensione senza un'interfaccia utente propria (ad esempio, un'estensione utilizzata per tradurre il testo selezionato e restituire la traduzione all'app host). L'estensione Condividi ti consente di condividere commenti, foto, video, audio, collegamenti e altro direttamente dall'app host. UIActivityViewController guida sia le estensioni di Azione che quelle di Condivisione, dove le estensioni di Condivisione sono presentate come icone colorate nella riga superiore e le estensioni di azione sono presentate come icone monocromatiche nella riga inferiore (Immagine 2.1).

API proibite

Non è possibile utilizzare le API contrassegnate nei file di intestazione con la macro NS_EXTENSION_UNAVAILABLE o una macro simile per l'indisponibilità (ad esempio: i framework dell'interfaccia utente HealthKit ed EventKit in iOS 8 non sono disponibili per l'uso in nessuna estensione dell'app).

Se condividi il codice tra un'app e un'estensione, devi tenere presente che anche fare riferimento a un'API che non è consentita per l'estensione dell'app comporterà il rifiuto della tua app dall'App Store. Puoi scegliere di affrontare questo problema ri-fattorizzazione delle classi condivise in gerarchie, con un genitore comune e diverse sottoclassi per obiettivi diversi. Un altro modo è usare il preprocessore con i controlli #ifdef . Poiché non esiste ancora un condizionale target integrato, è necessario crearne uno personalizzato.

Un altro bel modo per farlo è creare il tuo framework incorporato. Assicurati solo che non contenga API non disponibili per le estensioni. Per configurare un'estensione dell'app per l'utilizzo di un framework incorporato, vai alle impostazioni di build della destinazione e imposta l'impostazione "Richiedi solo API sicura per le estensioni dell'app" su Sì. In fase di configurazione del progetto Xcode, nella fase di build Copy Files, deve essere scelto “Frameworks” come destinazione del framework embedded. Se scegli la destinazione "SharedFrameworks", il tuo invio verrà rifiutato dall'App Store.

Una nota sulla compatibilità con le versioni precedenti

Sebbene le estensioni dell'app siano disponibili solo da iOS 8, puoi rendere disponibile l'app contenitore alle versioni precedenti di iOS.

Conformità dell'interfaccia umana di Apple

Tieni a mente le linee guida dell'interfaccia umana iOS di Apple durante la progettazione di un'estensione per app. Devi assicurarti che l'estensione dell'app sia universale, indipendentemente dal dispositivo supportato dall'app che lo contiene. Per garantire che l'estensione dell'app sia universale, utilizza l'impostazione di build della famiglia di dispositivi di destinazione in Xcode specificando il valore "iPhone/iPad" (a volte chiamato universale).

Conclusione

Le estensioni dell'app hanno sicuramente l'impatto più visibile in iOS 8. Poiché il 79% dei dispositivi utilizza già iOS 8 (come misurato dall'App Store il 13 aprile 2015), le estensioni dell'app sono funzionalità incredibili di cui le app dovrebbero trarre vantaggio. Combinando le restrizioni dell'API e il modo di condividere i dati tra le estensioni e la loro app che li contiene, sembra che Apple sia riuscita a rispondere a uno dei maggiori reclami sulla piattaforma senza compromettere il suo modello di sicurezza. Non c'è ancora modo per le app di terze parti di condividere direttamente i propri dati tra loro. Anche se questo è un concetto molto nuovo, sembra molto promettente.