Samouczek dotyczący rozszerzeń aplikacji iOS 8
Opublikowany: 2022-03-11Niewielu próbowało wcześniej (spójrz na to), ale to Apple z pierwszym iPhone'em zdefiniowało, jak powinien wyglądać smartfon i mobilny system operacyjny. Apple dokonał niesamowitego przełomu w sprzęcie i doświadczeniu użytkownika. Często jednak zapominamy, że wyznaczają one również standardy działania mobilnego systemu operacyjnego i tworzenia aplikacji na smartfony.
Budowanie betonowych ścian między aplikacjami, dzięki czemu są one całkowicie odizolowane i nieświadome siebie nawzajem, było najlepszym sposobem na zapewnienie im bezpieczeństwa i ochronę ich danych. Wszystkie działania były ściśle monitorowane przez iOS, a tylko kilka czynności, które aplikacja mogła wykonać poza jego zakresem, było tylko kilka.
„Abstynencja to najlepsza ochrona!” - ale gdzie jest w tym zabawa?
Zajęło im to trochę czasu; zbyt długo, jeśli mnie pytasz, ale z iOS 8 Apple postanowiło się zabawić. iOS 8 wprowadził nową koncepcję o nazwie Rozszerzenia aplikacji. Ta nowa funkcja nie zburzyła ścian między aplikacjami, ale otworzyła kilka drzwi, zapewniając delikatny, ale namacalny kontakt między niektórymi aplikacjami. Najnowsza aktualizacja dała programistom iOS możliwość dostosowania ekosystemu iOS i nie możemy się doczekać, aby ta ścieżka również się otworzyła.
Czym są rozszerzenia aplikacji na iOS 8 i jak one działają?
Mówiąc prościej, rozszerzenia aplikacji iOS 8 zapewniają nową metodę interakcji z Twoją aplikacją, bez jej uruchamiania lub wyświetlania na ekranie.
Zgodnie z oczekiwaniami Apple upewniło się, że wszystko jest na bieżąco, więc istnieje tylko kilka nowych punktów wejścia, które Twoja aplikacja może zapewnić:
- Dzisiaj (nazywane również widżetem) — rozszerzenie wyświetlane w widoku Dzisiaj Centrum powiadomień wyświetla krótkie informacje i umożliwia wykonywanie szybkich zadań.
- Udostępnij — rozszerzenie, które umożliwia Twojej aplikacji udostępnianie treści użytkownikom w sieciach społecznościowych i innych usługach udostępniania.
- Akcja — rozszerzenie, które umożliwia tworzenie niestandardowych przycisków akcji w arkuszu Akcja, aby umożliwić użytkownikom przeglądanie lub przekształcanie treści pochodzących z aplikacji hosta.
- Edycja zdjęć — rozszerzenie, które pozwala użytkownikom edytować zdjęcie lub wideo w aplikacji Zdjęcia.
- Dostawca dokumentów — rozszerzenie umożliwiające innym aplikacjom dostęp do dokumentów zarządzanych przez Twoją aplikację.
- Klawiatura niestandardowa — rozszerzenie, które zastępuje klawiaturę systemową.
Rozszerzenia aplikacji nie są samodzielnymi aplikacjami. Zapewniają rozszerzoną funkcjonalność aplikacji (do której można uzyskać dostęp z innych aplikacji, zwanych aplikacjami hosta), która ma być wydajna i skoncentrowana na jednym zadaniu. Mają własny plik binarny, własny podpis kodu i własny zestaw elementów, ale są dostarczane za pośrednictwem App Store jako część pliku binarnego aplikacji zawierającej. Jedna (zawierająca) aplikacja może mieć więcej niż jedno rozszerzenie. Gdy użytkownik zainstaluje aplikację, która ma rozszerzenia, będą one dostępne w systemie iOS.
Spójrzmy na przykład: użytkownik znajduje zdjęcie za pomocą przeglądarki Safari, klika przycisk udostępniania i wybiera rozszerzenie aplikacji do udostępnienia. Safari „rozmawia” z platformą iOS Social, która ładuje i prezentuje rozszerzenie. Kod rozszerzenia uruchamia się, przekazuje dane za pomocą skonkretyzowanych kanałów komunikacji systemu, a po wykonaniu zadania Safari wyłącza widok rozszerzenia. Niedługo po tym system kończy proces, a Twoja aplikacja nigdy nie była wyświetlana na ekranie. Jednak uzupełnił funkcję udostępniania zdjęć.
iOS, korzystający z komunikacji między procesami, jest odpowiedzialny za zapewnienie, że aplikacja hosta i rozszerzenie aplikacji mogą ze sobą współpracować. Deweloperzy używają wysokopoziomowych interfejsów API dostarczanych przez punkt rozszerzenia i system, dzięki czemu nigdy nie muszą się martwić o podstawowe mechanizmy komunikacji.
Koło życia
Rozszerzenia aplikacji mają inny cykl życia niż aplikacje na iOS. Aplikacja hosta rozpoczyna cykl życia rozszerzenia w odpowiedzi na działanie użytkownika. Następnie system tworzy instancję rozszerzenia aplikacji i konfiguruje kanał komunikacji między nimi. Widok rozszerzenia jest wyświetlany w kontekście aplikacji hosta przy użyciu elementów otrzymanych w żądaniu aplikacji hosta. Po wyświetleniu widoku rozszerzenia użytkownik może wchodzić z nim w interakcję. W odpowiedzi na działanie użytkownika rozszerzenie realizuje żądanie aplikacji hosta, natychmiast wykonując/anulując zadanie lub, jeśli to konieczne, inicjując proces w tle w celu jego wykonania. Zaraz po tym aplikacja hosta niszczy widok rozszerzenia, a użytkownik powraca do poprzedniego kontekstu w aplikacji hosta. Wyniki z wykonania tego procesu mogą zostać zwrócone do aplikacji hosta po zakończeniu procesu. Rozszerzenie zwykle zostaje zakończone wkrótce po zakończeniu żądania otrzymanego z aplikacji hosta (lub uruchomieniu procesu w tle w celu jego wykonania).
System otwiera rozszerzenie akcji użytkownika z aplikacji hosta, rozszerzenie wyświetla interfejs użytkownika, wykonuje pewną pracę i zwraca dane do aplikacji hosta (jeśli jest to odpowiednie dla typu rozszerzenia). Aplikacja zawierająca nie jest nawet uruchomiona, gdy jej rozszerzenie jest uruchomione.
Tworzenie rozszerzenia aplikacji — praktyczny przykład korzystania z rozszerzenia Today
Rozszerzenia Dzisiaj, zwane także widżetami , znajdują się w widoku Dzisiaj w Centrum powiadomień. To świetny sposób na prezentowanie użytkownikowi aktualnych treści (np. pokazywanie warunków pogodowych) lub wykonywanie szybkich zadań (takich jak zaznaczanie rzeczy zrobionych w widżecie aplikacji z listą rzeczy do zrobienia). Muszę tutaj zaznaczyć, że wpisywanie z klawiatury nie jest obsługiwane .
Stwórzmy rozszerzenie Today, które będzie wyświetlać najbardziej aktualne informacje z naszej aplikacji (kod na GitHub). Aby uruchomić ten kod, upewnij się, że (ponownie) skonfigurowałeś grupę aplikacji dla projektu (wybierz swój zespół programistów, pamiętaj, że nazwa grupy aplikacji musi być unikalna i postępuj zgodnie z instrukcjami Xcode).
Tworzenie nowego widżetu
Jak powiedzieliśmy wcześniej, rozszerzenia aplikacji nie są samodzielnymi aplikacjami. Potrzebujemy aplikacji zawierającej, na której zbudujemy rozszerzenie aplikacji. Gdy mamy już aplikację zawierającą, wybieramy dodanie nowego celu, przechodząc do Plik -> Nowy -> Cel w Xcode. Stąd wybieramy szablon dla naszego nowego celu, aby dodać rozszerzenie Today.
W kolejnym kroku możemy wybrać naszą Nazwę Produktu. Jest to nazwa, która pojawi się w widoku Dzisiaj w Centrum powiadomień. W tym kroku istnieje również możliwość wyboru języka między Swift a Objective-C. Po zakończeniu tych kroków Xcode tworzy szablon Today, który zapewnia domyślne pliki nagłówka i implementacji dla klasy głównej (o nazwie TodayViewController
) z plikiem Info.plist
i plikiem interfejsu (scenorysem lub plikiem .xib). Plik Info.plist
domyślnie wygląda tak:
<key>NSExtension</key> <dict> <key>NSExtensionMainStoryboard</key> <string>MainInterface</string> <key>NSExtensionPointIdentifier</key> <string>com.apple.widget-extension</string> </dict>
Jeśli nie chcesz używać scenorysu dostarczonego przez szablon, usuń klucz NSExtensionMainStoryboard
i dodaj klucz NSExtensionPrincipalClass
z nazwą kontrolera widoku jako wartością.
Widżet Dzisiaj powinien:
- upewnij się, że treść zawsze wygląda na aktualna
- odpowiednio reagować na interakcje użytkownika
- działają dobrze (widżety iOS muszą rozsądnie wykorzystywać pamięć, w przeciwnym razie zostaną zakończone przez system)
Udostępnianie danych i współdzielony kontener
Zarówno rozszerzenie aplikacji, jak i aplikacja zawierająca je, mają dostęp do udostępnionych danych w ich prywatnie zdefiniowanym udostępnionym kontenerze — co jest sposobem na pośrednią komunikację między aplikacją zawierającą a rozszerzeniem.
Czy nie podoba ci się, jak Apple sprawia, że te rzeczy są tak „proste”? :)
Udostępnianie danych przez NSUserDefaults
jest prostym i powszechnym przypadkiem użycia. Domyślnie rozszerzenie i zawierająca je aplikacja używają oddzielnych zestawów danych NSUserDefaults
i nie mogą uzyskiwać wzajemnego dostępu do kontenerów. Aby zmienić to zachowanie, iOS wprowadził App Groups . Po włączeniu grup aplikacji w aplikacji zawierającej i rozszerzeniu, zamiast używać [NSUserDefaults standardUserDefaults]
użyj [[NSUserDefaults alloc] initWithSuiteName:@"group.yourAppGroupName"]
aby uzyskać dostęp do tego samego udostępnionego kontenera.
Aktualizacja widżetu
Aby zapewnić, że zawartość jest zawsze aktualna, rozszerzenie Today udostępnia interfejs API do zarządzania stanem widżetu i obsługi aktualizacji zawartości. System od czasu do czasu przechwytuje migawki widoku widżetu, więc gdy widżet staje się widoczny, wyświetlana jest najnowsza migawka, dopóki nie zostanie zastąpiona aktywną wersją widoku. Zgodność z protokołem NCWidgetProviding
jest ważna dla aktualizowania stanu widżetu przed wykonaniem migawki. Gdy widżet otrzyma wywołanie widgetPerformUpdateWithCompletionHandler:
widok widżetu powinien zostać zaktualizowany o najnowszą zawartość, a procedura obsługi zakończenia powinna zostać wywołana z jedną z następujących stałych opisujących wynik aktualizacji:

-
NCUpdateResultNewData
- Nowa zawartość wymaga przerysowania widoku -
NCUpdateResultNoDate
- Widget nie wymaga aktualizacji -
NCUpdateResultFailed
— Wystąpił błąd podczas procesu aktualizacji
- (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); }
Kontrolowanie, kiedy widżet jest widoczny
Aby kontrolować, kiedy widżet jest wyświetlany, użyj metody setHasContent:forWidgetWithBundleIdentifier:
z klasy NCWidgetController
. Ta metoda pozwoli ci określić stan zawartości widżetu. Można go wywołać z widżetu lub z zawierającej go aplikacji (jeśli jest aktywny). Do tej metody można przekazać flagę NO
lub YES
, określając, czy zawartość widżetu jest gotowa lub nie. Jeśli zawartość nie jest gotowa, system iOS nie wyświetli widżetu po otwarciu widoku Dzisiaj.
NCWidgetController *widgetController = [[NCWidgetController alloc] init]; [widgetController setHasContent:YES forWidgetWithBundleIdentifier:@"com.your-company.your-app.your-widget"];
Otwieranie aplikacji zawierającej z widżetu
Widżet Dzisiaj jest jedynym rozszerzeniem, które może zażądać otwarcia swojej aplikacji, wywołując metodę openURL:completionHandler:
Aby mieć pewność, że zawierająca aplikacja otwiera się w sposób, który ma sens w kontekście bieżącego zadania użytkownika, należy zdefiniować niestandardowy schemat adresu URL (który może być używany zarówno dla widżetu, jak i aplikacji zawierającej).
[self.extensionContext openURL:[NSURL URLWithString:@"customURLsheme://URLpath"] completionHandler:nil];
Uwagi dotyczące interfejsu użytkownika
Podczas projektowania widżetu skorzystaj z klasy UIVisualEffectView
, pamiętając, że widoki, które powinny być rozmyte/wibrujące, należy dodać do contentView
, a nie bezpośrednio do UIVisualEffectView
. Widgety (zgodne z protokołem NCWidgetProviding
) powinny ładować stany zbuforowane w viewWillAppear:
w celu dopasowania stanu widoku z ostatniego viewWillDisappear:
a następnie płynnie przechodzić do nowych danych po ich nadejściu, co nie ma miejsca w przypadku normalnego widoku kontroler (UI jest konfigurowane w viewDidLoad
i obsługuje animacje oraz ładowanie danych w viewWillAppear
). Widgety powinny być zaprojektowane do wykonywania zadania lub otwierania aplikacji za pomocą jednego dotknięcia. Wpis z klawiatury nie jest dostępny w widżecie. Oznacza to, że nie należy używać żadnego interfejsu użytkownika wymagającego wprowadzania tekstu.
Dodanie zwojów do widżetu, zarówno w pionie, jak iw poziomie, nie jest możliwe. A dokładniej, dodanie widoku przewijania jest możliwe, ale przewijanie nie zadziała. Gest przewijania w poziomie w widoku przewijania w rozszerzeniu Dzisiaj zostanie przechwycony przez centrum powiadomień, co spowoduje przewijanie z Dzisiaj do Centrum powiadomień. Przewijanie w pionie widoku przewijania wewnątrz rozszerzenia Dzisiaj zostanie przerwane przez przewinięcie widoku Dzisiaj.
Uwagi techniczne
W tym miejscu wskażę kilka ważnych rzeczy, o których należy pamiętać podczas tworzenia rozszerzenia aplikacji.
Funkcje wspólne dla wszystkich rozszerzeń
Następujące punkty są prawdziwe dla wszystkich rozszerzeń:
Obiekt sharedApplication jest poza ograniczeniami : rozszerzenia aplikacji nie mogą uzyskać dostępu do obiektu sharedApplication ani używać żadnej z metod związanych z tym obiektem.
Kamera i mikrofon są niedostępne : rozszerzenia aplikacji nie mają dostępu do kamery ani mikrofonu na urządzeniu (ale nie dotyczy to wszystkich elementów sprzętowych). Wynika to z niedostępności niektórych interfejsów API. Aby uzyskać dostęp do niektórych elementów sprzętowych w rozszerzeniu aplikacji, musisz sprawdzić, czy jego interfejs API jest dostępny dla rozszerzeń aplikacji, czy nie (przy sprawdzaniu dostępności interfejsu API opisanym powyżej).
Większość zadań w tle jest niedostępna : rozszerzenia aplikacji nie mogą wykonywać długotrwałych zadań w tle, z wyjątkiem inicjowania przesyłania lub pobierania, co omówiono poniżej.
AirDrop jest niedostępny : rozszerzenia aplikacji nie mogą odbierać (ale mogą wysyłać) dane za pomocą AirDrop.
Przesyłanie/pobieranie w tle
Jedynym zadaniem, które można wykonać w tle, jest przesyłanie/pobieranie za pomocą NSURLSession object
.
Po zainicjowaniu zadania przesyłania/pobierania rozszerzenie może zakończyć żądanie aplikacji hosta i zostać zakończone bez żadnego wpływu na wynik zadania. Jeśli rozszerzenie nie jest uruchomione w momencie zakończenia zadania w tle, system uruchamia aplikację zawierającą w tle i wywoływana jest metoda delegata application:handleEventsForBackgroundURLSession:completionHandler:
.
Aplikacja, której rozszerzenie inicjuje zadanie NSURLSession
w tle, musi mieć skonfigurowany udostępniony kontener, do którego mają dostęp zarówno aplikacja zawierająca, jak i jej rozszerzenie.
Upewnij się, że tworzysz różne sesje w tle dla aplikacji zawierającej i każdego z jej rozszerzeń (każda sesja w tle powinna mieć unikalny identyfikator). Jest to ważne, ponieważ tylko jeden proces może jednocześnie korzystać z sesji w tle.
Akcja a udostępnianie
Różnice między rozszerzeniami Action i Share nie są do końca jasne z punktu widzenia kodera, ponieważ w praktyce są one bardzo podobne. Szablon Xcode dla celu rozszerzenia udziału używa SLComposeServiceViewController
, który zapewnia standardowy interfejs użytkownika widoku redagowania, którego można używać do udostępniania społecznościowego, ale nie jest to wymagane. Rozszerzenie udziału może również dziedziczyć bezpośrednio z UIViewController dla w pełni niestandardowego projektu, w ten sam sposób, w jaki rozszerzenie Action może dziedziczyć z SLComposeServiceViewController
.
Różnice między tymi dwoma typami rozszerzeń polegają na tym, jak mają być używane. Dzięki rozszerzeniu Action możesz zbudować rozszerzenie bez własnego interfejsu użytkownika (na przykład rozszerzenie używane do tłumaczenia wybranego tekstu i zwracania tłumaczenia do aplikacji hosta). Rozszerzenie udostępniania umożliwia udostępnianie komentarzy, zdjęć, filmów, plików audio, linków i nie tylko bezpośrednio z aplikacji hosta. UIActivityViewController
steruje rozszerzeniami Action i Share, gdzie rozszerzenia Share są prezentowane jako kolorowe ikony w górnym wierszu, a rozszerzenia akcji są prezentowane jako monochromatyczne ikony w dolnym wierszu (Obraz 2.1).
Zakazane API
Nie można używać interfejsów API oznaczonych w plikach nagłówkowych za pomocą makra NS_EXTENSION_UNAVAILABLE
lub podobnego makra niedostępności (na przykład: struktury UI HealthKit i EventKit w systemie iOS 8 nie są dostępne do użytku w żadnym rozszerzeniu aplikacji).
Jeśli udostępniasz kod między aplikacją a rozszerzeniem, musisz pamiętać, że nawet odwoływanie się do interfejsu API, który nie jest dozwolony dla rozszerzenia aplikacji, spowoduje odrzucenie Twojej aplikacji z App Store. Możesz sobie z tym poradzić, ponownie rozkładając współdzielone klasy na hierarchie, ze wspólnym rodzicem i różnymi podklasami dla różnych celów. Innym sposobem jest użycie preprocesora przez sprawdzenia #ifdef
. Ponieważ nadal nie ma wbudowanego warunkowego celu, musisz utworzyć własny.
Innym dobrym sposobem na to jest stworzenie własnego wbudowanego frameworka. Upewnij się tylko, że nie będzie zawierał żadnych interfejsów API niedostępnych dla rozszerzeń. Aby skonfigurować rozszerzenie aplikacji do korzystania z osadzonej platformy, przejdź do ustawień kompilacji obiektu docelowego i ustaw opcję „Wymagaj tylko bezpiecznego interfejsu API z rozszerzeniem aplikacji” na Tak. Podczas konfigurowania projektu Xcode w fazie kompilacji Kopiuj pliki należy wybrać „Frameworks” jako miejsce docelowe dla wbudowanej platformy. Jeśli wybierzesz miejsce docelowe „SharedFrameworks”, Twoje zgłoszenie zostanie odrzucone przez App Store.
Uwaga dotycząca wstecznej kompatybilności
Chociaż rozszerzenia aplikacji są dostępne dopiero od iOS 8, możesz udostępnić swoją aplikację w poprzednich wersjach iOS.
Zgodność z interfejsem ludzkim Apple
Podczas projektowania rozszerzenia aplikacji pamiętaj o wytycznych Apple dotyczących interfejsu użytkownika w systemie iOS. Musisz upewnić się, że rozszerzenie aplikacji jest uniwersalne, bez względu na to, jakie urządzenie obsługuje Twoja aplikacja. Aby upewnić się, że rozszerzenie aplikacji jest uniwersalne, użyj ustawienia kompilacji rodziny urządzeń docelowych w Xcode, określając wartość „iPhone/iPad” (czasami nazywaną uniwersalną).
Wniosek
Rozszerzenia aplikacji mają zdecydowanie najbardziej widoczny wpływ w systemie iOS 8. Ponieważ 79% urządzeń korzysta już z systemu iOS 8 (według pomiarów App Store z 13 kwietnia 2015 r.), rozszerzenia aplikacji to niesamowite funkcje, z których aplikacje powinny korzystać. Łącząc ograniczenia API i sposób udostępniania danych między rozszerzeniami i ich aplikacją, wydaje się, że Apple zdołało rozwiązać jedną z największych skarg na platformę bez naruszania jej modelu bezpieczeństwa. Nadal nie ma możliwości, aby aplikacje innych firm bezpośrednio udostępniały sobie swoje dane. Chociaż jest to bardzo nowa koncepcja, wygląda bardzo obiecująco.