[iOS 8] App Extension #1 – App Extension を実装するための基礎知識
App Extension
App Extension は、アプリの機能の一部を他のアプリからシームレスに利用できるようにするための仕組みを主とした新機能です。
iOS では、下記の6種類の Extension を作成することができます。
- Today
- Share
- Action
- Photo Editing
- Document Provider
- Custom Keyboard
この記事では、上記の各種 Extension の開発に共通する概念を説明します。
Extension と containing app
Extension はアプリの機能を拡張するためものですので、必ず特定の iOS アプリに紐づくことになります。Extension は単体で ipa を作成することはできません。リリースビルドする際には、紐づくアプリにバンドルされる形で ipa が生成されます。このため、Extension を App Store へリリースする際も、紐づくアプリとセットで申請することになります。
Extension を持っているアプリのことを containing app と言います。containing app は複数の Extension を持つことが可能です。
Extension の開発をサポートする機能
Embedded Framework
基本的に Extension は containing app の機能の一部を提供するため、共有したいコードが発生することになると思います。 Extension は、containing app のプロジェクト内に別のターゲットを作成して開発しますが、共通コードを双方のターゲットのコンパイル対象にいちいち追加するのは非常に面倒です。
このような場合に便利なのが、Embedded Framework です。Embedded Framework を利用すると、共通コードをライブラリ化して containing app と Extension の両方から利用することができます。
Embedded Framework については、こちらの記事を参照して下さい。
App Group
containing app と Extension は別のセキュリティサンドボックスが割り当てられます。このため、同じローカルディスク領域や UserDefaults を参照することができません。独立した2つのアプリと似た関係なので、データを共有する手段が限られてしまいます。
このような場合に App Group が便利です。App Group の仕組みを利用すると、containing app と Extension の間でデータの格納領域を共有することができます。
App Group については、こちらの記事を参照して下さい。
Extension と host app
基本的に、Extension はその containing app 以外のアプリから利用されることになります。Extension に対して処理をリクエストするアプリのことを host app と言います。
App Extension の制約
Apple の公式ドキュメントによれば、Extension には下記の制約があるとのことです。
sharedApplication にアクセスできない
UIApplication のインスタンスを保持する sharedApplication にアクセスができません。Extension のコード内から呼び出すと、コンパイルエラーになります。
一部の API が利用できない
iOS SDK で提供されている API のうち、NS_EXTENSION_UNAVAILABLE がついている API については利用することができません。これらについても Extension のコード内から呼び出すと、コンパイルエラーになります。
カメラ・マイクの利用ができない
Extension ではカメラ・マイクは利用できません。
バックグラウンドタスクの実行ができない
Extension からはバックグラウンドタスクを実行することができません。ただし、NSURLSession を利用してアップロード・ダウンロード処理をバックグラウンドで実行することは可能です。
AirDrop によるデータ受信ができない
Extension では AirDrop によるデータを受信することができません。ただし、UIActivityViewController を利用して AirDrop でデータを送信することは可能です。
arm64 アーキテクチャを含める必要がある
ビルド設定で、ビルド対象のアーキテクチャに arm64 を含める必要があります。これを含めない場合、App Store 申請時にリジェクト対象となるようです。また、Extension に対応した Embedded Framework をリンクしているアプリも同様に arm64 を含める必要があります。
メモリの上限が小さい
アプリに比べて、Extension の利用できるメモリの上限は小さい値に設定されているようです。Today Extension の Widget は特に小さく、Extension のプロセスはシステムによって終了させられやすいようです。
関連 API
Extension を実装するにあたって必要となる API のうち、主だったものを紹介します。
NSExtensionContext
host app が Extension を実行した際のコンテキストを表すクラスです。また、Extension による処理結果を host app に通知するためのメソッドもこのクラスに用意されています。
多くの Extension は UI を持っていますが、それらの Extension では UIViewController の extensionContext プロパティからこのクラスのインスタンスを取得することができます。
inputItems
host app から渡された情報を格納する NSExtensionItem の配列のプロパティです。
completeRequestReturningItems:completionHandler:
Extension での処理が正常に終了したことを host app に通知するメソッドです。パラメータに NSExtensionItem の配列を渡すことで、host app に処理結果のデータを返すことも可能です。
cancelRequestWithError:
Extension での処理に失敗したことを host app に通知するメソッドです。
NSExtensionItem
host app から渡された情報を表すクラスです。
attachments
host app から渡されたデータを格納する NSItemProvider の配列のプロパティです。
NSItemProvider
host app から渡された個々のデータを表すクラスです。
hasItemConformingToTypeIdentifier:
参照しているデータのタイプがパラメータで指定されたものと一致しているかをチェックするメソッドです。データタイプの指定は、UTI を利用して行います。UTI については Uniform Type Identifiers Reference を参照して下さい。
loadItemForTypeIdentifier:options:completionHandler:
パラメータで指定したデータタイプにマッチするデータをロードするメソッドです。このメソッドでもデータタイプの指定は UTI を利用します。
UIActivityViewController
UIActivityViewController は以前から提供されていた API で、OS の提供する機能などをサービスとしてアプリから利用するための UI を提供します。一部の Extension では、host app でこのクラスを利用して Activity View を表示し、Extension を呼び出すという流れになります。
setCompletionWithItemsHandler:
setCompletionWithItemsHandler: メソッドは Activity の完了時のハンドラをセットします。これは iOS 8 SDK で追加されたメソッドで、代わりに従来の setCompletionHandler: メソッドが非推奨となりました。
Extension の呼び出しの場合、ハンドラブロックの各パラメータに渡される値は下記の通りです。
activityType
アクティビティの種別を表す NSString 型のオブジェクトです。Extension を呼び出した場合には、その Extension の Bundle Identifier が渡されます。
completed
アクティビティの処理が正常に完了したかを表す BOOL 型の値です。Extension を呼び出した場合、Extension 側で host app に対してどういった通知を行ったかによって値が変化します。具体的には、ExtensionContext の completeRequestReturningItems:completionHandler: が実行された場合には YES、cancelRequestWithError: が実行された場合には NO が渡されます。
returnedItems
アクティビティの返却値です。Extension を呼び出した場合、Extension 側で completeRequestReturningItems:completionHandler: の第一パラメータに渡した NSArray 型のオブジェクトがセットされています。
activityError
アクティビティの処理が正常に終了しなかった場合に渡される NSError 型のオブジェクトです。Extension を呼び出した場合、Extension 側で cancelRequestWithError: のパラメータに渡したエラーオブジェクトがセットされています。