A Tutorial on iOS 8 App Extensions

Niewielu próbowało wcześniej (spójrz na to), ale to Apple z pierwszym iPhonem zdefiniowało, jak powinien wyglądać smartfon i mobilny system operacyjny. Apple dokonało niesamowitego przełomu w sprzęcie i doświadczeniach użytkownika. Jednak często zapominamy, że oni również ustanowił standardy w jak mobilny OS powinien działać, i jak aplikacje Smartphone powinny być wykonane.

Budując betonowe ściany między aplikacjami, co czyni je całkowicie odizolowane i nieświadomi siebie, była najlepsza metoda, aby utrzymać je bezpieczne i chronić swoje dane. Wszystkie działania były ściśle monitorowane przez iOS, i nie było tylko garstka działań aplikacja mogła zrobić poza jego zakres.

„Abstynencja jest najlepszą ochroną!” – ale gdzie jest zabawa w tym?

Zajęło im to trochę czasu; zbyt długo, jeśli mnie pytasz, ale z iOS 8 Apple postanowił mieć trochę zabawy. iOS 8 wprowadził nową koncepcję o nazwie App Extensions. 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. Ostatnia aktualizacja dała programistom iOS możliwość dostosowania ekosystemu iOS, a my z niecierpliwością czekamy na otwarcie tej ścieżki.

Czym są rozszerzenia aplikacji iOS 8 i jak działają?

W uproszczeniu, rozszerzenia aplikacji iOS 8 zapewniają nową metodę interakcji z aplikacją, bez uruchamiania jej lub pokazywania na ekranie.

Jak można się było spodziewać, Apple zadbało o to, aby pozostać na szczycie wszystkiego, więc istnieje tylko garść nowych punktów wejścia, które Twoja aplikacja może zapewnić:

  • Dzisiaj (zwane również widżetem) – rozszerzenie wyświetlane w widoku Dzisiaj w Centrum Powiadomień pokazuje krótkie informacje i umożliwia wykonywanie szybkich zadań.
  • Share – rozszerzenie, które umożliwia Twojej aplikacji udostępnianie treści użytkownikom w sieciach społecznościowych i innych usługach udostępniania.
  • Action – rozszerzenie, które umożliwia tworzenie niestandardowych przycisków akcji w arkuszu Action, aby umożliwić użytkownikom wyświetlanie lub przekształcanie treści pochodzących z aplikacji hosta.
  • Photo Editing – rozszerzenie, które pozwala użytkownikom edytować zdjęcie lub wideo w aplikacji Photos.
  • Document Provider – rozszerzenie używane do umożliwienia innym aplikacjom dostępu do dokumentów zarządzanych przez Twoją aplikację.
  • Custom Keyboard – rozszerzenie, które zastępuje klawiaturę systemową.

Rozszerzenia aplikacji nie są samodzielnymi aplikacjami. Zapewniają one rozszerzoną funkcjonalność aplikacji (do której można uzyskać dostęp z innych aplikacji, zwanych aplikacjami macierzystymi), która ma być wydajna i skoncentrowana na jednym zadaniu. Mają własną binarkę, własną sygnaturę kodu i własny zestaw elementów, ale są dostarczane przez App Store jako część binarki aplikacji zawierającej. Jedna aplikacja (zawierająca) może mieć więcej niż jedno rozszerzenie. Po zainstalowaniu przez użytkownika aplikacji, która ma rozszerzenia, będą one dostępne w całym systemie iOS.

Patrzmy na przykład: Użytkownik znajduje zdjęcie za pomocą Safari, uderza w przycisk udostępniania i wybiera rozszerzenie Twojej aplikacji do udostępniania. Safari „rozmawia” z iOS Social framework, który ładuje i prezentuje rozszerzenie. Kod rozszerzenia uruchamia się, przekazuje dane za pomocą instancjonowanych kanałów komunikacyjnych systemu, a gdy zadanie zostanie wykonane – Safari zamyka widok rozszerzenia. Wkrótce potem system kończy proces, a Twoja aplikacja nigdy nie została wyświetlona na ekranie. Mimo to ukończyła funkcję udostępniania zdjęć.

iOS, używając komunikacji międzyprocesowej, jest odpowiedzialny za zapewnienie, że aplikacja hosta i rozszerzenie aplikacji mogą współpracować. Programiści używają wysokopoziomowych API dostarczanych przez punkt rozszerzeń i system, więc nie muszą się martwić o podstawowe mechanizmy komunikacji.

Cykl życia

Rozszerzenia aplikacji mają inny cykl życia niż aplikacje iOS. Aplikacja hosta rozpoczyna cykl życia rozszerzenia jako odpowiedź na działanie użytkownika. Następnie system tworzy instancję rozszerzenia aplikacji i ustanawia kanał komunikacyjny między nimi. Widok rozszerzenia jest wyświetlany w kontekście aplikacji nadrzędnej przy użyciu elementów otrzymanych w żądaniu aplikacji nadrzędnej. Gdy widok rozszerzenia zostanie wyświetlony, użytkownik może wejść z nim w interakcję. W odpowiedzi na działanie użytkownika, rozszerzenie kończy żądanie aplikacji hosta poprzez natychmiastowe wykonanie/anulowanie zadania lub, jeśli to konieczne, zainicjowanie procesu w tle w celu jego wykonania. Zaraz po tym, aplikacja hosta niszczy widok rozszerzenia, a użytkownik powraca do swojego poprzedniego kontekstu w aplikacji hosta. Wyniki z wykonania tego procesu mogą zostać zwrócone do aplikacji głównej po jego zakończeniu. Rozszerzenie zazwyczaj zostaje zakończone wkrótce po zakończeniu żądania otrzymanego od aplikacji hosta (lub uruchamia proces w tle, aby je wykonać).

System otwiera rozszerzenie działania użytkownika z aplikacji hosta, rozszerzenie wyświetla UI, 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 działa jej rozszerzenie.

Tworzenie rozszerzenia aplikacji – przykład praktyczny Używanie rozszerzenia Today

Rozszerzenia Today, zwane również widżetami, znajdują się w widoku Today centrum powiadomień. Są one świetnym sposobem na prezentowanie aktualnej zawartości dla użytkownika (np. pokazując warunki pogodowe) lub wykonywanie szybkich zadań (np. zaznaczanie rzeczy zrobionych w widżecie aplikacji listy rzeczy do zrobienia). Muszę tutaj zaznaczyć, że wprowadzanie danych z klawiatury nie jest obsługiwane.

Stwórzmy rozszerzenie Today, które będzie wyświetlało najbardziej aktualne informacje z naszej aplikacji (kod na GitHubie). Aby uruchomić ten kod, upewnij się, że (ponownie) skonfigurowałeś App Group dla projektu (wybierz swój Development Team, pamiętaj, że nazwa App Group musi być unikalna i postępuj zgodnie z instrukcjami Xcode).

Tworzenie nowego widgetu

Jak już mówiliśmy, rozszerzenia aplikacji nie są samodzielnymi aplikacjami. Potrzebujemy aplikacji zawierającej, na której będziemy budować rozszerzenie aplikacji. Kiedy mamy już naszą aplikację zawierającą, wybieramy nowy cel poprzez przejście do Plik -> Nowy -> Cel w Xcode. Stąd wybieramy szablon dla naszego nowego celu, aby dodać Rozszerzenie Today.

W następnym kroku możemy wybrać naszą Nazwę Produktu. Jest to nazwa, która będzie wyświetlana w widoku Today w Centrum Powiadomień. Istnieje opcja wyboru języka pomiędzy Swift i Objective-C w tym kroku również. Kończąc te kroki, Xcode tworzy szablon Today, który dostarcza domyślne pliki nagłówkowe i implementacyjne dla klasy głównej (o nazwie TodayViewController) z plikiem Info.plist i plikiem interfejsu (storyboard lub plik .xib). Plik Info.plist domyślnie wygląda tak:

Jeśli nie chcesz używać storyboardu dostarczonego przez szablon, usuń klucz NSExtensionMainStoryboard i dodaj klucz NSExtensionPrincipalClass z nazwą swojego kontrolera widoku jako wartością.

Widżet Today powinien:

  • zapewnić, że zawartość zawsze wygląda na aktualną
  • odpowiednio reagować na interakcje użytkownika
  • wykonywać dobrze (widżety iOS muszą mądrze korzystać z pamięci, w przeciwnym razie zostaną zakończone przez system)

Współdzielenie danych i współdzielony kontener

Rozszerzenie aplikacji i jego aplikacja zawierająca zarówno mają dostęp do współdzielonych danych w swoim prywatnie zdefiniowanym współdzielonym kontenerze -… co jest sposobem na pośrednią komunikację między aplikacją zawierającą a rozszerzeniem.

Czy po prostu nie kochasz jak Apple robi te rzeczy tak „proste”? 🙂

Współdzielenie danych poprzez NSUserDefaults jest proste i jest częstym przypadkiem użycia. Domyślnie rozszerzenie i jego aplikacja zawierająca używają oddzielnych zestawów danych NSUserDefaults i nie mają dostępu do swoich kontenerów. Aby zmienić to zachowanie, iOS wprowadził App Groups. Po włączeniu grup aplikacji na aplikacji zawierającej i rozszerzeniu, zamiast używać użyj initWithSuiteName:@"group.yourAppGroupName"], aby uzyskać dostęp do tego samego współdzielonego 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 kiedy widżet staje się widoczny, wyświetlana jest najnowsza migawka, dopóki nie zostanie zastąpiona wersją widoku na żywo. Konformacja do protokołu NCWidgetProviding jest ważna dla aktualizacji stanu widżetu przed wykonaniem zrzutu. Gdy widżet odbierze wywołanie widgetPerformUpdateWithCompletionHandler:, widok widżetu powinien zostać zaktualizowany o najnowszą zawartość, a handler zakończenia powinien zostać wywołany z jedną z następujących stałych opisujących wynik aktualizacji:

  • NCUpdateResultNewData – Nowa zawartość wymaga przerysowania widoku
  • NCUpdateResultNoDate – Widżet nie wymaga aktualizacji
  • NCUpdateResultFailed – Podczas procesu aktualizacji wystąpił błąd

Controlling When the Widget Is Viewable

Aby kontrolować, kiedy widżet jest wyświetlany, należy użyć metody setHasContent:forWidgetWithBundleIdentifier: z klasy NCWidgetController. Ta metoda pozwoli ci określić stan zawartości widżetu. Może być wywołana z widżetu lub z aplikacji zawierającej widżet (jeśli jest ona aktywna). Możesz przekazać NO lub YES flagę do tej metody, określając, że zawartość widżetu jest gotowa lub nie. Jeśli zawartość nie jest gotowa, iOS nie wyświetli Twojego widżetu po otwarciu widoku Today.

Otwarcie aplikacji zawierającej z widżetu

Widżet Today jest jedynym rozszerzeniem, które może zażądać otwarcia swojej aplikacji zawierającej przez wywołanie metody openURL:completionHandler:. Aby zapewnić, ż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 URL (który może być używany zarówno przez widżet, jak i zawierającą go aplikację).

 completionHandler:nil];

UI Considerations

Podczas projektowania widżetu skorzystaj z klasy UIVisualEffectView, pamiętając, że widoki, które powinny być rozmyte/wibrujące, muszą być dodane do contentView, a nie bezpośrednio do UIVisualEffectView. Widżety (zgodne z protokołem NCWidgetProviding) powinny ładować zbuforowane stany w viewWillAppear: w celu dopasowania do stanu widoku z ostatniego viewWillDisappear:, a następnie płynnie przechodzić do nowych danych, gdy te nadejdą, co nie ma miejsca w przypadku zwykłego kontrolera widoku (UI jest skonfigurowane w viewDidLoad i obsługuje animacje i ładowanie danych w viewWillAppear). Widżety powinny być zaprojektowane do wykonywania zadań lub otwierania aplikacji zawierającej za pomocą jednego dotknięcia. Wprowadzanie tekstu za pomocą klawiatury nie jest dostępne wewnątrz widgetu. Oznacza to, że wszelkie UI wymagające wprowadzania tekstu nie powinny być używane.

Dodawanie przewijania do widżetu, zarówno pionowego jak i poziomego, nie jest możliwe. Lub bardziej precyzyjnie, dodanie widoku przewijania jest możliwe, ale przewijanie nie będzie działać. Gest przewijania w poziomie w widoku przewijania w rozszerzeniu Today zostanie przechwycony przez centrum powiadomień, co spowoduje przewijanie z Today do centrum powiadomień. Przewijanie w pionie widoku przewijania wewnątrz rozszerzenia Today zostanie przerwane przez przewijanie widoku Today.

Uwagi techniczne

W tym miejscu wskażę kilka ważnych rzeczy, o których należy pamiętać podczas tworzenia rozszerzenia App Extension.

Właściwości wspólne dla wszystkich rozszerzeń

Następujące elementy są prawdziwe dla wszystkich rozszerzeń:

  • obiektsharedApplication jest poza ograniczeniami: Rozszerzenia aplikacji nie mogą uzyskać dostępu do obiektu sharedApplication ani użyć żadnej z metod związanych z tym obiektem.

  • Camera i mikrofon są wyłączone: Rozszerzenia aplikacji nie mogą uzyskać dostępu do kamery lub mikrofonu na urządzeniu (ale nie jest to przypadek dla wszystkich elementów sprzętowych). Wynika to z niedostępności niektórych API. Aby uzyskać dostęp do niektórych elementów sprzętowych w rozszerzeniu aplikacji, będziesz musiał sprawdzić, czy jego API jest dostępne dla rozszerzeń aplikacji, czy nie (z sprawdzaniem dostępności API opisanym powyżej).

  • Większość zadań w tle jest niedostępna: Rozszerzenia aplikacji nie mogą wykonywać długo trwających zadań w tle, z wyjątkiem inicjowania wysyłania lub pobierania, co zostało omówione poniżej.

  • AirDrop jest poza ograniczeniami: Rozszerzenia aplikacji nie mogą odbierać (ale mogą wysyłać) danych przy użyciu AirDrop.

Uploading/Downloading in the Background

Jednym zadaniem, które może być wykonywane w tle, jest wysyłanie/pobieranie danych, przy użyciu NSURLSession object.

Po zainicjowaniu zadania wysyłania/pobierania rozszerzenie może zakończyć żądanie aplikacji hosta i zostać zakończone bez wpływu na wynik zadania. Jeśli rozszerzenie nie jest uruchomione w momencie zakończenia zadania tła, system uruchamia aplikację zawierającą w tle i wywoływana jest metoda delegata aplikacji application:handleEventsForBackgroundURLSession:completionHandler:.

Aplikacja, której rozszerzenie inicjuje zadanie tła NSURLSession musi mieć ustawiony współdzielony kontener, do którego dostęp ma zarówno aplikacja zawierająca, jak i jej rozszerzenie.

Upewnij się, że tworzysz różne sesje tła dla aplikacji zawierającej i każdego z jej rozszerzeń (każda sesja tła powinna mieć unikalny identyfikator). Jest to ważne, ponieważ tylko jeden proces może korzystać z sesji tła w tym samym czasie.

Action vs. Share

Różnice pomiędzy rozszerzeniami Action i Share nie są całkowicie jasne z perspektywy kodera, ponieważ w praktyce są one bardzo podobne. Szablon Xcode dla celu rozszerzenia share używa SLComposeServiceViewController, który zapewnia standardowy widok compose view UI, który można wykorzystać do udostępniania społecznościowego, ale nie jest to wymagane. Rozszerzenie akcji 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ń są w tym, jak mają być używane. Z rozszerzeniem Action, możesz zbudować rozszerzenie bez własnego UI (na przykład, rozszerzenie używane do tłumaczenia wybranego tekstu i zwracania tłumaczenia do aplikacji głównej). Rozszerzenie Share pozwala udostępniać komentarze, zdjęcia, wideo, audio, linki i inne elementy bezpośrednio z aplikacji głównej. Rozszerzenie UIActivityViewController napędza zarówno rozszerzenia akcji, jak i udostępniania, przy czym rozszerzenia akcji są prezentowane jako kolorowe ikony w górnym rzędzie, a rozszerzenia akcji jako monochromatyczne ikony w dolnym rzędzie (obraz 2.1).

Zabronione interfejsy API

API oznaczone w plikach nagłówkowych makrem NS_EXTENSION_UNAVAILABLE lub podobnym makrem oznaczającym niedostępność, nie mogą być używane (na przykład: HealthKit i EventKit UI frameworks w iOS 8 nie są dostępne do użycia w żadnym rozszerzeniu aplikacji).

Jeśli współdzielisz kod między aplikacją a rozszerzeniem, musisz pamiętać, że nawet odwołanie się do API, które nie jest dozwolone dla rozszerzenia aplikacji, spowoduje odrzucenie Twojej aplikacji z App Store. Możesz wybrać, jak sobie z tym poradzić poprzez refaktoryzację wspólnych klas w hierarchie, ze wspólnym rodzicem i różnymi podklasami dla różnych celów.Innym sposobem jest użycie preprocesora przez #ifdef kontrole. Ponieważ wciąż nie ma wbudowanego warunkowego celu, musisz stworzyć własny.

Innym miłym sposobem na zrobienie tego jest stworzenie własnego wbudowanego frameworka. Upewnij się tylko, że nie będzie on zawierał żadnych API niedostępnych dla rozszerzeń. Aby skonfigurować rozszerzenie aplikacji do korzystania z wbudowanego frameworka, przejdź do ustawień budowania celu i ustaw ustawienie „Wymagaj tylko API bezpiecznego dla aplikacji” na Tak. Podczas konfigurowania projektu Xcode, w fazie budowania Kopiuj pliki, „Frameworks” musi być wybrany jako miejsce docelowe dla wbudowanego frameworka. Jeśli wybierzesz miejsce docelowe „SharedFrameworks”, zgłoszenie zostanie odrzucone przez App Store.

A Note on Backwards Compatibility

Although app extensions have only been available since iOS 8, you can make your containing app available to the prior iOS versions.

Apple Human Interface Compliance

Keep in mind Apple’s iOS Human Interface Guidelines when designing an app extension. Musisz upewnić się, że Twoje rozszerzenie aplikacji jest uniwersalne, bez względu na to, jakie urządzenie obsługuje Twoja aplikacja zawierająca. Aby zapewnić, że rozszerzenie aplikacji jest uniwersalne, użyj ustawienia budowy rodziny urządzeń docelowych w Xcode, określając wartość „iPhone/iPad” (czasami nazywaną uniwersalną).

Wniosek

Rozszerzenia aplikacji zdecydowanie mają najbardziej widoczny wpływ w iOS 8. Ponieważ 79% urządzeń korzysta już z iOS 8 (według pomiarów App Store z 13 kwietnia 2015 r.), rozszerzenia aplikacji są niesamowitymi funkcjami, z których aplikacje powinny korzystać. Dzięki połączeniu ograniczeń API i sposobu udostępniania danych między rozszerzeniami a ich aplikacją zawierającą, wydaje się, że Apple udało się rozwiązać jeden z największych zarzutów dotyczących platformy bez naruszania jej modelu bezpieczeństwa. Nadal nie ma sposobu, aby aplikacje firm trzecich mogły bezpośrednio dzielić się swoimi danymi między sobą. Chociaż jest to bardzo nowa koncepcja, wygląda to bardzo obiecująco.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.