App Extension とは?
App Extension (Extensions) は、iOS 8 から導入される、新しいアプリ間連携のしくみです。
iOS では、以下の 6種類の Extension point *1を利用することができます。
- Today
- Share
- Action
- Photo Editing
- Storage Provider
- Custom keyboard
大まかな仕組みは同じなのですが、見た目/機能は Extension point によって色々と違いがあり、実装方法も違ってくる(部分もある)ので、個別に説明していきたいと思います。
まずは一番説明しやすい "Action" から。
1. ターゲットを作成する
Xcode の [File] > [New] > [Target] から、[Application Extension] > [Action Extension] を選択します。
(※Xcode6のスクショではありません。App Extension Programming Guide の図3-1 です。)
ここでは [Action Type] は [View Controller] を選択します。
2. Extension の実装
Extension が起動されたときの見た目や挙動を実装します。
たとえば、ImageInverter サンプルでは、`viewDidLoad` で入力画像を反転して表示するように実装されています。
// extensionContextから入力アイテムを取得 NSExtensionItem *imageItem = [self.extensionContext.inputItems firstObject]; // NSItemProviderを取得 NSItemProvider *imageItemProvider = [[imageItem attachments] firstObject]; if([imageItemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage]){ // 入力画像を取得 [imageItemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeImage options:nil completionHandler:^(UIImage *image, NSError *error) { if(image){ dispatch_async(dispatch_get_main_queue(), ^{ // 画像を反転させる UIImage* invertedImage = [self invertedImage:image]; // 表示 [imageView setImage:invertedImage]; }); } }]; }
(説明用に簡略化しています。また `invertedImage` メソッドのソースは省略。)
そして、done ボタン押下で編集済みアイテムを返します。
-(void)done:(id)sender{ // 編集済みのNSExtensionItemオブジェクトを作成 NSExtensionItem *extensionItem = [[NSExtensionItem alloc] init]; [extensionItem setAttachments:@[[[NSItemProvider alloc] initWithItem:[self.imageView image] typeIdentifier:(NSString*)kUTTypeImage]]]; // Host appに返す [self.extensionContext completeRequestReturningItems:@[extensionItem] completionHandler:nil]; }
Host appの実装
Extension を呼び出す側のアプリの実装です。
ボタン押下時に UIActivityViewController を表示する、というのは従来と同じなのですが、完了ハンドラの引数で、Extention から返ってきたアイテムを受け取れるようになっています。
ImageInverter サンプルでは、下記のように画像を取り出して表示しています。
- (IBAction)share:(id)sender { UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems: @[[self.imageView image]] applicationActivities:nil]; [activityViewController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError * error){ // 返ってきたアイテムを取得 NSExtensionItem* extensionItem = [returnedItems firstObject]; NSItemProvider* imageItemProvider = [[extensionItem attachments] firstObject]; // 画像を取り出して表示 if([imageItemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage]){ [imageItemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeImage options:nil completionHandler:^(UIImage *item, NSError *error) { if(item && !error){ dispatch_async(dispatch_get_main_queue(), ^{ [self.imageView setImage:item]; }); } }]; } }]; [self presentViewController:activityViewController animated:YES completion:nil]; }
(説明用に簡略化しています。)
実行時の注意点
新しい機能なので、 UIActivityViewController が立ち上がってどうすればいいか一瞬戸惑うのですが、初回のみ [More] から今回追加した Extension を有効にして、UIActivityViewController を立ち上げ直す必要があります。
InvertImageサンプル自体は公開されているものの、Xcode6はNDA下にあるため、実行結果のスクショはここでは掲載を控えておきます。
参考資料
本記事は、以下のAppleによる公開リソースをもとに作成しています。
- App Extension Programming Guide: App Extensions Increase Your Impact
- ImageInverter: Creating Action Extensions
*1:OS X は4種類