A Tutorial on iOS 8 App Extensions

Few York Timesによると、スマートフォンとモバイルOSがどうあるべきかを定義したのは、最初のiPhoneを発表したAppleだったそうです。 Appleは、ハードウェアとユーザーエクスペリエンスにおいて、驚くべきブレークスルーを遂げました。 しかし、モバイルOSがどのように機能すべきか、スマートフォンのアプリケーションがどのように作られるべきかという基準も設定したことを、私たちは忘れがちです。

アプリケーションの間にコンクリートの壁を作り、完全に隔離してお互いを意識させないことが、アプリケーションを安全に保ちデータを保護するための最善の方法だったのです。 すべてのアクティビティは iOS によって厳密に監視され、アプリケーションがその範囲外で行うことができるアクションはほんの一握りしかありませんでした。 – iOS 8 では、App Extensions という新しいコンセプトが導入されました。 この新しい機能は、アプリケーション間の壁を壊すものではありませんが、いくつかのアプリケーション間の穏やかで具体的な接触を提供するいくつかのドアを開けました。 最新のアップデートでは、iOS 開発者に iOS エコシステムをカスタマイズするオプションを与え、私たちはこの道が開かれることを切望しています。

iOS 8 App Extensions とは何か、どのように機能するのか

簡単に言うと、iOS 8 App Extensions ではアプリケーションを起動したり画面上に表示せずに対話する新しい方法が提供されます。

  • Today (ウィジェット) – 通知センターの Today ビューに表示される拡張機能で、簡単な情報を表示し、迅速なタスクを実行できるようにします。
  • Share – ソーシャル ネットワークやその他の共有サービス上でユーザーとコンテンツを共有するための拡張機能。
  • Photo Editing – 写真アプリ内でユーザーが写真やビデオを編集できるようにする拡張機能。
  • Document Provider – アプリが管理するドキュメントに他のアプリがアクセスできるようにするための拡張機能。
  • Custom Keyboard – システム キーボードに代わる拡張機能。

App 拡張はスタンドアローン アプリではありません。 アプリの拡張機能 (ホスト アプリと呼ばれる他のアプリからアクセス可能) を提供するもので、効率的で単一のタスクに集中できるように意図されています。 拡張機能は、独自のバイナリ、独自のコード署名、および独自の要素セットを持ちますが、App Storeを通じて、内包するアプリのバイナリの一部として配信されます。 1つの(含む)アプリは、複数の拡張機能を持つことができます。 いったんユーザーが拡張機能を持つアプリをインストールすると、iOS 全体で利用できるようになります。 ユーザーは Safari を使用して画像を見つけ、共有ボタンを押し、共有するためにアプリケーションの拡張機能を選択します。 Safari は iOS Social フレームワークと「対話」し、フレームワークが拡張機能をロードして表示します。 拡張機能のコードが実行され、システムのインスタンス化された通信チャネルを使用してデータが渡され、タスクが完了すると、Safariは拡張機能のビューを縮小します。 この後すぐに、システムはプロセスを終了させ、あなたのアプリケーションは画面に表示されることはありませんでした。

iOS は、プロセス間通信を使用して、ホスト アプリとアプリ拡張が一緒に動作できるようにする役割を担っています。 開発者は、拡張ポイントとシステムが提供する高レベルの API を使用するため、根本的な通信メカニズムについて心配する必要はありません。 ホスト アプリは、ユーザーのアクションへの応答として拡張機能のライフ サイクルをキックオフします。 その後、システムはアプリの拡張機能をインスタンス化し、両者間の通信チャネルを設定します。 拡張機能のビューは、ホストアプリのリクエストで受け取ったアイテムを使用して、ホストアプリのコンテキスト内で表示されます。 拡張機能のビューが表示されると、ユーザはそのビューと対話することができます。 ユーザの操作に応じて、拡張機能は、タスクを直ちに実行/キャンセルするか、必要であれば、バックグラウンドプロセスを開始して、ホストアプリの要求を完了します。 その後、ホストアプリは拡張機能のビューを破棄し、ユーザはホストアプリ内の以前のコンテキストに戻ります。 この処理を実行した結果は、処理が完了した時点でホストアプリに返される可能性があります。 システムがホスト アプリからユーザーのアクションの拡張機能を開き、拡張機能は UI を表示し、何らかの作業を実行し、ホスト アプリにデータを返します (拡張機能のタイプに適している場合)。 拡張機能が実行されている間、含むアプリは実行されていません。

Creating an App Extension – Hands-on Example Using the Today Extension

Widget とも呼ばれる Today 拡張機能は、通知センターの Today ビューに配置されます。 これらは、ユーザーに最新のコンテンツを表示したり (天気の表示など)、迅速なタスクを実行したり (ToDo リスト アプリのウィジェットで完了した事柄に印を付けるなど) するための素晴らしい方法です。 キーボード入力はサポートされていません。

App から最新の情報を表示する Today 拡張を作成しましょう (コードは GitHub にあります)。 このコードを実行するには、プロジェクトの App グループを (再) 設定したことを確認してください (開発チームを選択し、App グループ名は一意でなければならないことを念頭に置き、Xcode の指示に従います)。

Creating a New Widget

前に述べたように、アプリ拡張は独立したアプリケーションではありません。 アプリ拡張を構築するための包含アプリが必要です。 インクルード アプリができたら、Xcode に File ->New ->Target と移動して、新しいターゲットを追加することを選択します。 ここから、Today Extension を追加する新しいターゲットのテンプレートを選択します。

次のステップでは、製品名を選択します。 これは、通知センターの [今日] ビューに表示される名前です。 このステップでは、Swift と Objective-C の間で言語を選択するオプションもあります。 このテンプレートには、プリンシパルクラス(TodayViewController という名前)用のデフォルトのヘッダーファイルと実装ファイル、Info.plist ファイル、およびインターフェイスファイル(ストーリーボードまたは .xib ファイル)が用意されています。 Info.plist ファイルは、デフォルトでは次のようになります。

テンプレートが提供するストーリーボードを使用しない場合は、NSExtensionMainStoryboardキーを削除し、NSExtensionPrincipalClassキーに自分のビューコントローラの名前を値として追加してください。

A Today ウィジェットでは、次のようにします。

  • コンテンツが常に最新に見えるようにする
  • ユーザーの操作に適切に対応する
  • うまく動作する (iOS ウィジェットはメモリを賢く使用しないとシステムにより終了させられる)

データの共有と共有コンテナー

アプリ拡張とその含むアプリは両方とも個人的に定義した共有コンテナーの共有データへのアクセスを持つ—。 これは、コンテナアプリとエクステンションの間で間接的に通信する方法です。

Apple がこのようなことを非常に「シンプル」にするのが好きではありませんか:)

NSUserDefaults によるデータの共有はシンプルで、一般的な使用例です。 デフォルトでは、拡張機能とそのアプリは別々の NSUserDefaults データセットを使用し、互いのコンテナーにアクセスすることはできません。 この動作を変更するために、iOS は App Groups を導入しました。 9625>

Updating the Widget

Widget が常に最新であることを保証するために、Today 拡張は、ウィジェットの状態を管理し、コンテンツの更新を処理する API を提供します。 システムは時折、ウィジェットのビューのスナップショットをキャプチャするので、ウィジェットが表示されると、ビューのライブ バージョンに置き換えられるまで、最新のスナップショットが表示されます。 スナップショットが取得される前にウィジェットの状態を更新するためには、NCWidgetProvidingプロトコルへのコンフォームが重要です。 ウィジェットがwidgetPerformUpdateWithCompletionHandler:コールを受信すると、ウィジェットのビューは最新のコンテンツで更新され、更新の結果を記述するために以下の定数のいずれかで完了ハンドラが呼び出されなければならない。

  • NCUpdateResultNewData – 新しいコンテンツはビューの再描画を必要とする
  • NCUpdateResultNoDate – ウィジェットは更新を必要としない
  • NCUpdateResultFailed – 更新処理中にエラーが発生した

Widget Is Viewable

ウィジェットをいつ表示するかコントロールするには、NCWidgetController クラスからsetHasContent:forWidgetWithBundleIdentifier:メソッドを使用します。 このメソッドでは、ウィジェットのコンテンツの状態を指定することができます。 このメソッドは、ウィジェットまたはそのアプリから呼び出すことができます(アプリがアクティブである場合)。 このメソッドにNOまたはYESフラグを渡すことで、ウィジェットのコンテンツが準備完了かどうかを定義することができます。 コンテンツが準備できていない場合、iOS は Today ビューが開かれたときにウィジェットを表示しません。

Opening the Containing App from the Widget

The Today ウィジェットは、openURL:completionHandler:メソッドをコールしてそのアプリを開くよう要求できる唯一の拡張機能です。

 completionHandler:nil];

UI Considerations

Widget を設計する場合、UIVisualEffectView クラスを活用し、ぼかし/鮮やかなビューを contentView に追加し、UIVisualEffectView に直接追加しないことを念頭に置いてください。 ウィジェット (NCWidgetProviding プロトコルに準拠) は、最後の viewWillDisappear: からのビューの状態と一致するように viewWillAppear: でキャッシュされた状態をロードし、新しいデータが到着したときにスムーズに移行する必要がありますが、これは通常のビューコントローラとは異なります (UI は viewDidLoad で設定し viewWillAppear でアニメーションとデータのロードを処理する)。 ウィジェットは、タスクを実行したり、ワンタップで含まれるアプリを開いたりするために設計されるべきです。 ウィジェット内ではキーボード入力はできません。 つまり、テキスト入力を必要とする UI は使用すべきではありません。

ウィジェットにスクロールを追加することは、垂直方向と水平方向の両方で不可能です。 より正確には、スクロール ビューの追加は可能ですが、スクロールは機能しません。 Today 拡張機能のスクロール ビューでの水平スクロール ジェスチャは、通知センターによって妨害され、Today から通知センターへのスクロールが発生します。

Technical Notes

App Extension を作成する際に留意すべき重要な点をいくつか指摘します。

Features Common to All Extensions

The following items are true for all extensions:

  • sharedApplication object is off limits.The shared application applicationは、すべての機能拡張に該当します。

  • Camera and microphone are off limits.App Extensions are not access a sharedApplication object, or use any of methods related to that object.

  • Camera and microphone are off limits.App Extensions are not available: App エクステンションは、デバイス上のカメラやマイクにアクセスできません (ただし、すべてのハードウェア要素についてそうではありません)。 これは、一部の API が使用できないことが原因です。 アプリ拡張で一部のハードウェア要素にアクセスするには、その API がアプリ拡張で利用可能かどうかを確認する必要があります (上記の API 利用可能性チェックで)。

  • Most background tasks are off limits: アップロードまたはダウンロードの開始を除き、アプリの拡張機能では長時間実行されるバックグラウンド タスクを実行できません。

Uploading/Downloading in the Background

バックグラウンドで実行できるタスクは、NSURLSession object を使用したアップロード/ダウンロードです。

アップロード/ダウンロードのタスクが開始された後、拡張機能はホスト アプリケーションの要求を完了し、タスクの結果には影響せずに終了させることができます。 バックグラウンド タスクが完了した時点で拡張機能が実行されていない場合、システムはバックグラウンドで含むアプリを起動し、アプリのデリゲート メソッド application:handleEventsForBackgroundURLSession:completionHandler: が呼び出されます。

バックグラウンド NSURLSession タスクを開始する拡張機能は、含むアプリとその拡張機能がアクセスできる共有コンテナが設定されている必要があります。 これは重要です。

Action vs. Share

Action と Share 拡張の違いは、コーダーの観点からは完全に明確ではありませんが、実際には非常によく似ているからです。 Xcode の Share エクステンション ターゲットのテンプレートは SLComposeServiceViewController を使用しており、ソーシャル共有に使用できる標準のコンポーズ ビュー UI を提供しますが、これは必須ではありません。 共有エクステンションは、Action エクステンションが SLComposeServiceViewController を継承するのと同じように、完全にカスタムな設計のために UIViewController を直接継承することもできます。

これら 2 種類の拡張機能の違いは、それらがどのように使用されることを意図しているかという点です。 Action 拡張を使用すると、それ自体の UI を持たない拡張を構築できます (たとえば、選択したテキストを翻訳してホスト アプリケーションに翻訳を返すために使用する拡張)。 Shareエクステンションでは、コメント、写真、ビデオ、オーディオ、リンクなどをホストアプリケーションから直接共有することができます。 UIActivityViewController は Action と Share エクステンションの両方を駆動し、Share エクステンションは上段にカラー アイコン、アクション エクステンションは下段にモノクロ アイコンで表示されます (画像 2.1).

Forbidden API

APIs mark in the header files with NS_EXTENSION_UNAVAILABLE macro, or similar macro for unavailability, cannot be used (for example.)(例:「利用できないAPIの利用」)。 iOS 8 の HealthKit および EventKit UI フレームワークは、どのアプリ拡張でも使用できません)。

アプリと拡張機能の間でコードを共有している場合、アプリ拡張機能で許可されていない API を参照しただけでも、App Store からの拒否につながることを念頭に置いておく必要があります。 別の方法としては、#ifdefチェックによるプリプロセッサを使用することです。 組み込みのターゲット条件はまだないので、自分で作成する必要があります。

これを行うもう 1 つの素晴らしい方法は、独自の組み込みフレームワークを作成することです。 ただ、拡張機能で利用できない API が含まれていないことを確認してください。 埋め込みフレームワークを使用するためにアプリの拡張機能を構成するには、ターゲットのビルド設定に移動し、[Require Only App-Extension-Safe API] 設定を [Yes] に設定します。 Xcode プロジェクトを構成するとき、Copy Files ビルドフェーズで、”Frameworks” を埋め込みフレームワークの保存先として選択する必要があります。 SharedFrameworks] を選択した場合、App Store によって投稿が拒否されます。

A Note on Backwards Compatibility

App Extensions は iOS 8 から利用可能になったが、含むアプリを以前の iOS バージョンで利用できるようにすることができます。 含むアプリがサポートするデバイスに関係なく、アプリの拡張機能がユニバーサルであることを確認する必要があります。 アプリの拡張機能がユニバーサルであることを確実にするために、Xcode で「iPhone/iPad」値 (ユニバーサルと呼ばれることもあります) を指定したターゲット デバイス ファミリ ビルド設定を使用します。 79% のデバイスがすでに iOS 8 を使用しているため (2015 年 4 月 13 日の App Store での測定値)、アプリ拡張はアプリが活用すべき信じられないような機能なのです。 API の制限と、拡張機能とそれを含むアプリ間のデータ共有の方法を組み合わせることで、Apple はセキュリティモデルを損なうことなく、プラットフォームに対する最大の不満の 1 つに対処できたようです。 サードパーティアプリが互いにデータを直接共有する方法はまだありません。 これは非常に新しいコンセプトですが、非常に有望です

コメントを残す

メールアドレスが公開されることはありません。