読者です 読者をやめる 読者になる 読者になる

WonderPlanet DEVELOPER BLOG

ワンダープラネットの開発者ブログです。モバイルゲーム開発情報を発信。

Action Extensionsの実装について

今回エンジニアブログを担当する戸田です。

今回はiOS8で新たに追加されたApp Extensionsについて紹介したいと思います。App Extensionsは、アプリの一部機能を他のアプリから利用できる仕組みになります。iOSで使用できる主な機能は次の通りになります。

  • Today
  • Share
  • Action
  • Photo Editing
  • Document Provider
  • Custom Keyboard

今回はその中でも「Action」について紹介します。

Action Extensionの実装

1.前準備

前準備としてAction Extensionを追加する為のプロジェクトを作成します。

Xcodeを起動して、メニューの「File」>「New」>「Project...」を選択します。

ActionExtensions-01

テンプレートから作成するプロジェクトを選び、「Next」を選択ます。

ActionExtensions-02

次に以下のプロジェクト設定を行い「Next」を選択します。

  • Product Name
  • Organization Name
  • Organization Identifier
  • Languag
  • Devices

ActionExtensions-03

プロジェクトを保存する先を決めて、「Create」を選択します。

2.Action Extensionのターゲットを作成

作成したプロジェクトにApp Extensionsのターゲットを追加します。

メニューの「File」>「New」>「Terget...」を選択します。

ActionExtensions-05

テンプレートの「iOS」>「Application Extension」>「Action Extension」を選んで「Next」を選択ます。

ActionExtensions-06

次に以下のターゲット設定を行い「Next」を選択します。

  • Product Name
  • Organization Name
  • Languag
  • Action Type
  • Project
  • Embed in Application

ActionExtensions-07

Action Extensionのschemeを有効にするかを聞かれているので、「Active」を選択して有効にします。

ActionExtensions-08

3.Action Extensionの実装

デフォルトで作成されたコードを一部変更して説明していきます。

まず、「ActionViewController」の「viewDidLoad」メソッドを以下のように変更します。

- (void)viewDidLoad {  
    [super viewDidLoad];  
  
    __block UIImage *compositeImage = nil;  
    for (NSExtensionItem *item in self.extensionContext.inputItems) {  
        for (NSItemProvider *itemProvider in item.attachments) {  
            if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage]) {  
                __weak UIImageView *imageView = self.imageView;  
                [itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeImage options:nil completionHandler:^(UIImage *image, NSError *error) {  
                    if(image) {  
                        [[NSOperationQueue mainQueue] addOperationWithBlock:^{  
                            CGSize size = image.size;  
  
                            UIGraphicsBeginImageContextWithOptions(size, 0.0f, [[UIScreen mainScreen] scale]);  
  
                            [compositeImage drawInRect:CGRectMake(0, 0, size.width, size.height)];  
                            [image drawInRect:CGRectMake(0, 0, size.width, size.height)];  
  
                            compositeImage = UIGraphicsGetImageFromCurrentImageContext();  
  
                            UIGraphicsEndImageContext();  
  
                            [imageView setImage:compositeImage];  
  
                        }];  
                    }  
                }];  
            }  
        }  
    }  
}

Action Extensionがコールされる際に一緒に渡されるObjectの取得は、コードの5〜9行目で行っています。

続いて、「done」メソッドを以下のように変更します。

- (IBAction)done {  
    NSExtensionItem *extensionItem = [[NSExtensionItem alloc] init];  
    [extensionItem setAttachments:@[[[NSItemProvider alloc] initWithItem:[self.imageView image]  
                                                          typeIdentifier:(NSString*)kUTTypeImage]]];  
  
    [self.extensionContext completeRequestReturningItems:@[extensionItem] completionHandler:nil];  
}

コール元にObjectを返す時は、NSExtensionItemに格納する必要があるため、「done」メソッド内の1〜3行目で行っています。

4.info.plistの設定

Action Extensionの定義をinfo.plistで行います。また、デフォルト設定で以下のようになっています。

ActionExtensions-09

「NSExtensionActivationRule」内でAction Extensionへの受け渡しするオブジェクトの定義を行います。今回はKeyに「NSExtensionActivationSupportsImageWithMaxCount」、Valueに「2」を設定します。

※「NSExtensionActivationRule」のValueが「TRUEPREDICATE」になっていますが開発時専用になるため、Appleの審査でリジェクトの対象になります。

ActionExtensions-10

4.Action Extensionのコール元を実装

プロジェクトの「SampleAppExtensionHost」配下にある「Main.storyboard」と「ViewController.m」を以下のようにします。

Main.storyboard

ActionExtensions-11

ViewController.m

#import <MobileCoreServices/MobileCoreServices.h>  
@interface ViewController ()  
  
@property (strong, nonatomic) IBOutlet UIImageView *beforeImage;  
@property (strong, nonatomic) IBOutlet UIImageView *afterImage;  
@property (strong, nonatomic) IBOutlet UIImageView *overlayImage;  
  
@end
- (IBAction)actionTopButton:(UIButton *)sender {  
  
    UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[[self.beforeImage image], [self.overlayImage image]]  
                                                                                         applicationActivities:nil];  
  
    [activityViewController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError * error){  
  
        NSExtensionItem* extensionItem = [returnedItems firstObject];  
        NSItemProvider* itemProvider = [[extensionItem attachments] firstObject];  
  
        if([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage]){  
  
            [itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeImage  
                                            options:nil  
                                  completionHandler:^(UIImage *image, NSError *error) {  
  
                                          [[NSOperationQueue mainQueue] addOperationWithBlock:^{  
  
                                              [self.afterImage setImage:image];  
  
                                          }];  
                                  }];  
        }  
    }];  
  
    [self presentViewController:activityViewController animated:YES completion:nil];  
  
}

Action Extensionのコール及び引き渡すObjectの処理は、actionTopButtonメソッド内の3・4行目で行っています。
Action Extensionで合成されたObjectを受け取る処理は、actionTopButtonメソッド内の6〜24行目で行っています。

5.実行

Schemeの「SampleAppExtensionHost」を選択して、メニューの「Product」>「Run」を選択します。
アプリが起動後に「合成」をタップすると「ActivityViewController」が表示され、「SampleAppExtension」のアイコンをタップすると2つの画像が合成・表示されます。その後、「Done」をタップすると呼び元に合成画像が渡され表示されます。

ActionExtensions-12 ActionExtensions-13 ActionExtensions-14 ActionExtensions-15

以上が「Action Extensionの実装について」の紹介になります。