setoya-blog

システム開発技術、データ分析関連でお勉強したことや、山奥生活を綴る、テンション低めなブログです。

iOSのUIActivityViewControllerにカスタムアクティビティを追加する

iOS6からFacebookなどへのシェアもiOSがサポートするようになりましたが、独自に開発しているアプリでもあのビューを使って、オリジナルのアクションを追加したいときがあります。

要するに以下の画像の「SoundCloud」ようなアクションを追加したい。

f:id:sessan:20121212170758p:plain

これには、iOS6で追加されたUIActivityを使います。

参考にした資料

WWDCの資料には殆ど有用な情報はなく、クラスリファレンスだけが頼りでした。

UIActivity Class Reference

手順

  1. UIActivityクラスのサブクラスを追加
  2. UIActivityクラスのサブクラスの各種メソッドを実装
  3. どこかでactivityDidFinish:を呼び出してアクティビティを終了させる
  4. UIActivityViewController起動時に、applicationActivitiesを初期化して渡す

1. UIActivityクラスのサブクラスを追加

UIActivityクラスのサブクラスを追加します。

  • APSoundCloudActivity.h
#import <UIKit/UIKit.h>

@interface APSoundCloudActivity : UIActivity

@end
  • APSoundCloudActivity.m
#import "APSoundCloudActivity.h"

@implementation APSoundCloudActivity

@end

2. UIActivityクラスのサブクラスの各種メソッドを実装

UIActivityViewControllerで表示されるビューに、画像や文字列の情報を渡すために、親クラスで定義されているメソッドを実装します。

  • APSoundCloudActivity.m
- (NSString *)activityType {
    return @"SoundCloud";
}

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

- (UIImage *)activityImage {
    UIImage *icon = [UIImage imageNamed:@"scshareicon.png"];
    return icon;
}

アイコンは、Appleが注意事項を書いているので、それに従って作ります。
iPhone用には43x43と86x86のアイコンが必要です。

The alpha channel of the image is used as a mask to generate the final image that is presented to the user. Any color data in the image itself is ignored. Opaque pixels have a gradient applied to them and this gradient is then laid on top of a standard background. Thus, a completely opaque image would yield a gradient filled rectangle. For iPhone and iPod touch, images should be no larger than 43 by 43 points (which equates to 86 by 86 pixels for devices with Retina displays.) For iPad, images should be no larger than 55 x 55 points (which equates to 110 by 110 pixels for iPads with Retina displays.)


次に、UIActivityViewControllerのビューでカスタムアイコンがクリックされたときにデータを渡す処理をprepareWithActivityItemsメソッドに書きます。中身は省略。

- (void)prepareWithActivityItems:(NSArray *)activityItems {
  //ここにデータ準備処理を書く
}

この後、カスタムアクションが呼ばれるのですが、この次に呼ばれるのは、以下の2つのメソッドのいずれかです。両方呼ばれることはありません。

  1. (void)performActivity
  2. (UIViewController *)activityViewController

入力画面が必要ない場合は、前者を実装し、後者は実装しません。
僕の場合は、入力が必要な画面だったので後者のactivityViewControllerを実装しました。
activityViewControllerメソッドの戻り値はUIViewControllerのサブクラスである必要があり、また、自分で画面を表示しては行けません。ただ、UIViewControllerのサブクラスのインスタンスを返すだけです。

3. どこかでactivityDidFinish:を呼び出してアクティビティを終了させる

UIActivityクラスのactivityDidFinishedメソッドを以下のように呼んでアクティビティが終了しないと、UIActivityViewControllerのアクションシートが閉じてくれません。

[self activityDidFinish:YES]; //注:ここのselfはUIActivityクラスのサブクラス

僕の場合は、activityViewControllerで表示したビューの処理が終わったときに、activityDidFinishを呼びました。

4. UIActivityViewController起動時に、applicationActivitiesを初期化して渡す

これで準備が終わったので、以下のようにUIActivityViewControllerを初期化して表示するときに、作ったカスタムアクティビティを登録すれば、冒頭の画像のように、カスタムアクションつきのUIActivityViewが表示されます。

    APSoundCloudActivity *scActivity =  [[APSoundCloudActivity alloc] init];
    NSArray *applicationActivities =  [NSArray arrayWithObject:scActivity];

    //注:itemsは別途定義済の想定
    UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:applicationActivities];

    [self presentViewController:activityVC animated:YES completion:nil];