UIActivityViewControllerを使ったデータ共有

UIActivityViewControllerはiOS6で新しく追加されたクラスです。 Facebook、Twitterなど、システムで用意された複数のアイテムに加え、アプリ独自の機能を追加することができる使い勝手のよい新機能です。 iOS6でしか使えないのが難点ですが、是非使いこなしていきたいですね。

UIActivityViewControllerとは

UIActivityViewControllerは、指定したオブジェクトに応じて、ファイル共有やメール添付などの機能を自動的に表示してくれるViewControllerです。 UIDocumentInteractionControllerと違い、特定のファイルを指定するのではなく、複数のオブジェクトを指定します。 さらにアプリ独自の機能を追加することもできる、なかなか応用範囲の広いViewControllerです。

システムActivityを表示する

まず、システムで用意されているActivityを表示してみましょう。 ここでは文字列"Hello World!"を扱うことのできるActivityを表示しています。

NSString *text = @"Hello World!";
NSArray* actItems = [NSArray arrayWithObjects:text, nil];
        
UIActivityViewController *activityView = [[[UIActivityViewController alloc] initWithActivityItems:actItems applicationActivities:nil] autorelease];
            
[self presentViewController:activityView animated:YES completion:^{    
    }];

上のソースコードを実行すると、textに対応した5つのシステムActivityが表示されます

UIKIT_EXTERN NSString *const UIActivityTypePostToFacebook   NS_AVAILABLE_IOS(6_0); // text, images, URLs
UIKIT_EXTERN NSString *const UIActivityTypePostToTwitter    NS_AVAILABLE_IOS(6_0); // text, images, URLs
UIKIT_EXTERN NSString *const UIActivityTypePostToWeibo      NS_AVAILABLE_IOS(6_0); // text, images, URLs
UIKIT_EXTERN NSString *const UIActivityTypeMessage          NS_AVAILABLE_IOS(6_0); // text
UIKIT_EXTERN NSString *const UIActivityTypeMail             NS_AVAILABLE_IOS(6_0); // text, image, file:// URLs
UIKIT_EXTERN NSString *const UIActivityTypePrint            NS_AVAILABLE_IOS(6_0); // image, NSData, file:// URL, UIPrintPageRenderer, UIPrintFormatter, UIPrintInfo
UIKIT_EXTERN NSString *const UIActivityTypeCopyToPasteboard NS_AVAILABLE_IOS(6_0); // text, image, NSURL, UIColor, NSDictionary
UIKIT_EXTERN NSString *const UIActivityTypeAssignToContact  NS_AVAILABLE_IOS(6_0); // image
UIKIT_EXTERN NSString *const UIActivityTypeSaveToCameraRoll NS_AVAILABLE_IOS(6_0); // image, video

デフォルトのActivityは上記の9個。それぞれ対応することのできる機能が違います。 例えば、textに対応するシステムActivityはUIActivityTypePostToFacebookとUIActivityTypePostToTwitterとUIActivityTypePostToWeiboとUIActivityTypeMessageとUIActivityTypeMailとUIActivityTypeCopyToPasteboardになります。

ただし、UIActivityTypePostToWeiboはシステムのロケールが中国の場合のみ表示されるようです。

指定するオブジェクトによって表示される機能が異なるので、サンプルソース(最後にリンクをのせてます)で試してみてください。

オリジナルのActivity

次は自分のアプリ独自のActivityを表示してみます。 UIActivityViewControllerのinitWithActivityItemsをよぶときに、UIActivityクラスを拡張した独自Activityを設定します。

   // system activities
    NSString *text = @"Hello World!";
    UIImage* image1 = [UIImage imageNamed:@"book.jpg"];
    UIImage* image2 = [UIImage imageNamed:@"tree.png"];
    NSArray* actItems = [NSArray arrayWithObjects:text,image1,image2, nil];
    
    // 独自のActivityを作成する。
    CarActivity* a1 = [[[CarActivity alloc] init] autorelease];
    SnowActivity* a2 = [[[SnowActivity alloc] init] autorelease];
    NSArray* myItems = [NSArray arrayWithObjects:a1, a2, nil];
    
    UIActivityViewController *activityView = [[[UIActivityViewController alloc] initWithActivityItems:actItems applicationActivities:myItems] autorelease];
    
    [self presentViewController:activityView animated:YES completion:^{
        
    }];

このCarActivityはUIActivityを継承したクラスになっており、実装ファイルはこんな感じです。

@implementation CarActivity
- (NSString *)activityType {
    return @"Car";
}

- (NSString *)activityTitle {
    return @"Car";
}

- (UIImage *)activityImage {
    return [UIImage imageNamed:@"Car"];
}

- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems{
    return YES;

}

- (void)prepareWithActivityItems:(NSArray *)activityItems;{
    NSLog(@"prepare!!");

    [super prepareWithActivityItems:activityItems];

}

- (UIViewController *)activityViewController{
    return nil;
}

- (void)performActivity{

    NSLog(@"perform!!");

    // do something with activityItems

    [self activityDidFinish:YES];
}

- (void)activityDidFinish:(BOOL)completed{
    NSLog(@"finished!!");

    [super activityDidFinish:completed];
}
@end

UIActivityViewControllerで表示されるボタンのアイコン画像はactivityImageで指定します。 UITabViewControllerに使うものと同様に、アルファチャンネルのみが有効となります。 だいたい40x40くらいの大きさがちょうどいいようです。

オリジナルの「Snow」と「Car」のActivityを追加するとこんな感じの画面になります。

オリジナルの別画面つきActivity

さらに、オリジナルのViewControllerをつかって、別画面があるActivityも作成することができます。 下のSnowActivityは独自のViewControllerをもっていて、「Snow」ボタンを押すと、TwitterやFacebookの投稿と同じように別画面が表示されます。

@implementation SnowActivity
- (NSString *)activityType {
    return @"Snow";
}

- (NSString *)activityTitle {
    return @"Snow";
}

- (UIImage *)activityImage {
    return [UIImage imageNamed:@"Snow"];
}

- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems{
    return YES;

}

- (void)prepareWithActivityItems:(NSArray *)activityItems;{
    NSLog(@"prepare!!");

    [super prepareWithActivityItems:activityItems];

    if( self.snowViewController == nil){
        self.snowViewController = [[SnowViewController alloc] init];
        self.snowViewController.delegate = self;
    }

}

- (UIViewController *)activityViewController{
    return self.snowViewController;
}

- (void)performActivity{
// this is not called.
}

- (void)activityDidFinish:(BOOL)completed{
    NSLog(@"finished!!");

    [super activityDidFinish:completed];
}
@end

prepareWithActivityItemsでUIViewControllerを作成すると、UIActivityが自動的に表示を行ってくれます。 また、重要なのが、処理が終わってもdismissViewControllerAnimatedを呼ばないこと。 UIActivityのactivityDidFinishを呼べば、自動的にViewControllerを閉じてくれます。

ViewControllerがあるUIActivityの場合にはperformActivityは呼ばれないので、ViewControllerの適当な場所で処理を行ってください。

UUIActivityViewControllerの利点、欠点

独自機能拡張が簡単なUIActivityViewControllerはiOS6でしか使えないのが一番の欠点でしょう。

また、他のアプリを呼ぶ場合には、OpenURLを使うことになるため、よびだしたいアプリの「URLSchema」をあらかじめ知っておく必要があります。

UIDocumentInteractionControllerとは状況によって使い分けられるので、ユーザーの目的に応じてどちらかを使うかを検討してみてください。

サンプルソース

サンプルソースをGithubにおきました。 (OpenURL、UIDocumentInteractionController、UIActivityViewControllerを使ったファイル連携が実装されています。) SendDataDemo(情報を送る側) ReceiveDataDemo(情報を受け取る側)