[iOS 8] App Extension #5 – Embedded Framework と App Group を利用して Action Extension を実装する [前編]

Embedded Framework と App Group を利用した App Extension の開発

前回の記事で Action Extension のサンプルを作成しましたが、実際に App Extension を作成する際には Embedded Framework と App Group の利用は必須になると思います。

そこで、今回は Embedded Framework と App Group を利用して App Extension を作成していきたいと思います。作成する Extension は Action Extension ですが、通常の Action Extension は前回作っているので、今回は UI を持たない Action Extension を作成したいと思います。

UI を持たない Action Extension

Action Extension は App Extension の中で唯一 UI を持つものと持たないものの双方を実装することができます。UI を持たない Action Extension によって、host app から遷移することなくバックグラウンドで処理を行い、その処理が完了したタイミングで host app に任意のデータを返却する Extension を提供することができます。

利用方法は他の Extension と同じで、host app から UIActivityViewController によって提供される Activity View 上で Extension を選択して呼び出します。

UI を持たない Action Extension は、ターゲットを作成した際に生成される雛形が Safari 内の Web ページに対する Extension を提供するためのものとなっています。このため、ネイティブアプリに対して UI のない Action Extension を提供することは Apple が意図した利用方法ではない可能性もあります。Apple の公式ドキュメントには UI を持たない Action Extension の利用用途についての記述はないようなので、何とも言えないところです。

NSExtensionRequestHandling プロトコル

host app からの Extension に対する呼び出しをハンドリングする役割を持つプロトコルです。UI を持っている Extension の場合には、ViewController でハンドリングを行いますが、UI を持たない Action Extension の場合には、このプロトコルに適合したクラスでハンドリングを行います。

beginRequestWithExtensionContext:

Extension の Info.plist で NSExtensionPrincipalClass に指定されたクラスが NSExtensionRequestHandling プロトコルに適合している場合、host app からの Extension の呼び出しがあった際にプロトコルで定義されている beginRequestWithExtensionContext: メソッドが呼び出されます。

UI を持たない Action Extension では、このメソッドにハンドリング後の処理を実装することになります。メソッドの引数として NSExtensionContext のインスタンスが渡されてくるので、ここから NSExtensionItemNSItemProvider を取り出して host app から渡されたデータを参照することができます。

サンプル Extension の作成

今回は、host app からイメージを受け取ってローカルストレージに保存する Extension のサンプルを作成したいと思います。さらに、Extension で保存したイメージのうち最新のものを表示する containing app も作成します。ソースコードは GitHub に公開してあるので参考にして下さい。

containing app, Extension プロジェクトの作成

Xcode から Single View Application でプロジェクトを作成します。

通常の Action Extension 同様、Extension の Target を追加します。 Project navigator で作成したプロジェクトを選択すると、Editor ペインにプロジェクトの設定が表示されますので、その左下にある + ボタンをクリックします。

ios-actionextension-noui_001

ターゲットのテンプレートを選択するダイアログが表示されますので、左側のカテゴリで iOS > Application Extension 選択します。選択すると右側に Extension のテンプレート一覧が表示されますので、Action Extension を選択して Next をクリックしてください。

ios-actionextension-noui_002

続いて、オプションを入力する画面が表示されます。Product Name に Extension の名前を入力します。また、今回は UI を持たない Extension を作成するので、Action Type を No User Interface に設定します。Finish をクリックすると、Extension のターゲットが作成されます。

ios-actionextension-noui_003

作成したターゲットのアクティベーションダイアログが表示された場合には、Activate を選択します。

ios-actionextension-noui_004

以上で、Action Extension のターゲット作成が完了しました。

ios-actionextension-noui_005

プロジェクトの構成

Extension のターゲット作成後に Project navigator を確認すると、ターゲットのフォルダと下記のファイルが作成されています。

  • ActionRequestHandler.h
  • ActionRequestHandler.m
  • Action.js
  • Info.plist

ios-actionextension-noui_006

Extension のターゲット作成時に Action Type を No User Interface とすると、host app が Safari の場合に Web ページに対して処理を行う実装のひな形が作成されます。しかし、これらは今回作成する Extension の実装には不要なものですので利用しません。

ActionRequestHandler.h, .m

NSExtensionRequestHandling プロトコルに適合したクラスです。host app からの Extension の呼び出しに対する処理が記述されています。 host app からの呼び出しをこのクラスでハンドリングするため、Info.plist の中の NSExtensionPrincipalClass キーの値としてクラス名が指定されています。

生成された .m の実装のひな形のうち、beginRequestWithExtensionContext: メソッド以外は関係ないので削除します。beginRequestWithExtensionContext: メソッドについても、中の実装は関係がないので削除しておきます。

Action.js

Extension の呼び出し時に host app の Web ページで実行するスクリプトを記述するファイルです。今回の実装には全く関係ないのでこのファイルは削除します。

Info.plist

Extension の設定が定義されている Info.plist です。通常の Action Extension と同じく、NSExtension キーの値として Extension 固有の設定が定義されています。

ios-actionextension-noui_007

NSExtensionActivationRule

UI のない Action Extension のターゲットを作成した場合、いくつかの項目が既に設定された状態になっています。今回作成する Extension はイメージを受け取って処理を行うため、NSExtensionActivationSupportsImageWithMaxCount を 1 に設定しておきます。一方、URL に対する処理は行いませんので、NSExtensionActivationSupportsWebURLWithMaxCount は 0 に設定します。

また、NSExtensionJavaScriptPreprocessingFile キーで Action.js が指定されていますが、今回は利用しないためこの項目は削除します。

最終的なファイル構成と Info.plist の内容は下図のようになります。

ios-actionextension-noui_008

App Group の設定

containing app と Extension の間でイメージを共有するために、App Group の shared container が提供する UserDefaults 及びローカルストレージの共有領域を利用できるようにします。App Group の設定は、containing app と Extension のそれぞれに対して行います。

ios-actionextension-noui_009

ios-actionextension-noui_010

App Group やその設定方法については、こちらの記事を参照して下さい。

Embedded Framework の作成

containing app と Extension の間でソースコードを共有するために Embedded Framework を作成します。

ios-actionextension-noui_011

Embedded Framework のターゲットを作成して、Extension のターゲットでリンクの設定をします。

ios-actionextension-noui_012

Embedded Framework やその作成方法については、こちらの記事を参照して下さい。

プロジェクトの設定が終わったので続いて実装に入りたいと思います。記事が長くなってしまいますので、続きは後編に分割します。