アプリケーション間通信

アプリケーションは、同じデバイス上であっても、他のアプリケーションと間接的にしか通信できません。他のアプリケーションとファイルやデータを共有するためにはAirDropを使います。また、独自のURLスキームを定義し、URLを使って他のアプリケーションに情報を送信することも可能です。

AirDropのサポート

AirDropを使えば、写真、文書、URLその他、各種のデータを、付近のデバイスと共有できます。AirDropには、ピアツーピアネットワークを活用して近くのデバイスを探索し、接続できるという利点があります。

ファイルやデータを他のアプリケーションに送信する

AirDropを利用してファイルやデータを送信するためには、UIActivityViewControllerオブジェクトを使って、画面上にアクティビティシートを表示する必要があります。このビューコントローラを作成する際、共有するデータオブジェクトを指定しなければなりません。ビューコントローラが表示するのは、指定されたデータを取り扱えるアクティビティに限ります。AirDropの場合、画像、文字列、URLなど、各種のデータ型を指定できます。UIActivityItemSourceプロトコルを実装した独自のオブジェクトを指定することも可能です。

アクティビティビューコントローラを表示するコード例をリスト6-1に示します。アクティビティビューコントローラは、指定されたオブジェクトの型に基づき自動的に、アクティビティシートにどのアクティビティを表示するか判断します。AirDropのアクティビティを明示的に指定する必要はありません。もっとも、特定の型がシートに表示されないよう、ビューコントローラのexcludedActivityTypesプロパティで指定することは可能です。iPad上にアクティビティビューコントローラを表示するためには、ポップオーバーを使う必要があります。

リスト6-1  iPhone上にアクティビティシートを表示する

- (void)displayActivityControllerWithDataObject:(id)obj {
   UIActivityViewController* vc = [[UIActivityViewController alloc]
                                initWithActivityItems:@[obj] applicationActivities:nil];
    [self presentViewController:vc animated:YES completion:nil];
}

アクティビティビューコントローラについて詳しくは、『UIActivityViewController Class Reference』を参照してください。サポート対象であるアクティビティおよびデータ型の一覧が『UIActivity Class Reference』に載っています。

アプリケーションに送信されたファイルやデータを受け取る

AirDropを使って、アプリケーションに送信されたファイルを受け取る手順を以下に示します。

  • Xcodeで、アプリケーションが開いて処理できる文書型のサポートを宣言します。

  • アプリケーションデリゲートにapplication:openURL:sourceApplication:annotation:メソッドを実装してください。このメソッドで、他のアプリケーションから送信されたデータを受け取ります。

  • アプリケーションのDocuments/Inboxディレクトリにファイルが追加されていないか監視し、必要ならばこのディレクトリ外に移動します。

Xcodeプロジェクトの「Info」タブには「Document Types」セクションがあり、アプリケーションがサポートする文書型を指定できます。最低限、文書型の名前と、データ型を表すUTIをいくつか指定しなければなりません。たとえばPNGファイルに対応する場合、UTI文字列として「public.png」と記述します。iOSは指定されたUTIに基づき、アプリケーションが文書を開けるかどうか判断します。

iOSは、該当する文書をアプリケーションのコンテナに転送した後、(必要ならば)当該アプリケーションを起動し、アプリケーションデリゲートのapplication:openURL:sourceApplication:annotation:メソッドを実行します。アプリケーションがフォアグラウンド状態であれば、このメソッドでファイルを開き、表示してください。バックグラウンド状態であれば、ファイルの存在のみ確認し、状態が切り替わってから、実際に開いて処理することになるでしょう。AirDrop経由で伝送されたファイルは暗号化されているので、デバイスがロック解除状態でなければ開いてみることはできません。

AirDrop経由で転送されたファイルは、アプリケーションのDocuments/Inboxディレクトリに保存されています。アプリケーションはファイルの読み取りと削除が可能です。書き替えはできません。ファイルを書き替える場合は、あらかじめInboxディレクトリ外に移動する必要があります。不要になったファイルはInboxディレクトリから削除するとよいでしょう。

アプリケーションがサポートする文書型について詳しくは、『Document-Based App Programming Guide for iOS』を参照してください。

URLスキームを使ってアプリケーションと通信する

URLスキームを利用すれば、独自に定義したプロトコルに従って他のアプリケーションと通信できます。当該スキームを実装したアプリケーションと通信する場合、適切な形式のURLを用意し、これを開くようシステムに要求することになります。独自のスキームをサポートする場合、当該スキームにもとづくURLを渡されたときに対処できる旨を宣言したうえで、実際の処理コードを実装しなければなりません。

URLを他のアプリケーションに送信する

独自のURLスキームを実装しているアプリケーションにデータを送信するためには、適切な形式のURLを用意した上で、アプリケーションオブジェクトのopenURL:メソッドを呼び出すことになります。openURL:メソッドは、当該スキームに対処できる旨が登録されているアプリケーションを起動し、URLを渡します。その時点で、制御は新しいアプリケーションに渡ります。

次のコード例では、あるアプリケーションが別のアプリケーションのサービスを要求する方法を示します(この例に示す「todolist」は、アプリケーションによって登録された架空のカスタムスキームです)。

NSURL *myURL = [NSURL URLWithString:@"todolist://www.acme.com?Quarterly%20Report#200806231300"]; 
[[UIApplication sharedApplication] openURL:myURL];

アプリケーションでカスタムURLスキームを定義する場合は、「カスタムURLスキームの実装」で説明するような、そのスキーム用のハンドラを実装する必要があります。システムがサポートするURLスキームの詳細(URLの書式化方法の情報を含む)については、『Apple URL Scheme Reference』を参照してください。

カスタムURLスキームの実装

アプリケーションが特殊な形式のURLを受け取る可能性がある場合は、それに対応するURLスキームをシステムに登録する必要があります。通常、アプリケーションはカスタムURLスキームを使用して、ほかのアプリケーションにサービスを提供します。たとえば、「マップ(Maps)」アプリケーションは地図上の特定の場所を表示するためのURLをサポートしています。

カスタムURLスキームの登録

アプリケーション用にURLタイプを登録するには、CFBundleURLTypesキーを、そのアプリケーションのInfo.plistファイルに含めます。CFBundleURLTypesキーには、辞書の配列が含まれており、各辞書にはアプリケーションがサポートするURLが定義されています。表6-1は、それぞれの辞書に含まれるキーと値の説明です。

表6-1  CFBundleURLTypesプロパティのキーと値

キー

CFBundleURLName

URLスキームの抽象名を含む文字列。一意性を確保するため、com.acme.myscheme.

ここで指定した文字列は、アプリケーションのInfoPlist.stringsファイル内のキーとしても使われます。このキーの値は、人が読める形式のスキーム名です。

CFBundleURLSchemes

URLスキームの名前(httpmailtotelsmsなど)を含む文字列の配列。

URLリクエストの処理

固有のURLスキームを持つアプリケーションは、渡されたURLを処理できなくてはなりません。すべてのURLは、起動時、アプリケーションの実行中、またはバックグラウンド状態のいずれかで、アプリケーションデリゲートに渡されます。渡されたURLを処理するために、デリゲートは以下のメソッドを実装しなければなりません。

URLリクエストが届いたときにアプリケーションが実行されていない場合は、アプリケーションが起動されて、URLを開くことができるようにフォアグラウンドに移されます。application:willFinishLaunchingWithOptions:メソッドまたはapplication:didFinishLaunchingWithOptions:メソッドの実装では、options辞書からURLを取得して、アプリケーションがそれを開けるかどうか決定しなければなりません。開ける場合は、YESを返し、application:openURL:sourceApplication:annotation:メソッド(またはapplication:handleOpenURL:メソッド)を利用して、実際にそのURLを開く処理を実行します。(両方のメソッドを実装した場合、どちらもYESを返さなければURLを開くことは不可)図6-1に、URLで指定されたリソースを開く、修正後の起動処理の流れを示します。

図6-1  アプリケーションを起動しURLを開く処理の流れ

URL要求が届いたときに、アプリケーションがバックグラウンドで実行中か一時停止している場合は、URLを開くためにアプリケーションがフォアグラウンドに移行されます。その直後に、システムはデリゲートの application:openURL:sourceApplication:annotation:を呼び出して、URLをチェックして開きます。図6-2に、フォアグラウンド状態に移行してURLを開く、修正後の流れを示します。

図6-2  バックグラウンドからフォアグラウンドに移行してURLを開く処理の流れ

URLはすべてNSURLオブジェクトでアプリケーションに渡されます。URLの形式を定義するのはデベロッパの仕事ですが、 NSURLクラスはRFC 1808仕様に準拠しているため、ほとんどのURLの表記法に対応しています。特に、RFC 1808仕様で定められている、ユーザ、パスワード、クエリ、コード、パラメータの文字列など、URLのさまざまな部分を返すメソッドがこのクラスにあります。カスタムスキームの「protocol」で、さまざまな種類の情報を伝えるためにURLのこうした部分を使用できます。

application:openURL:sourceApplication:annotation:メソッドの実装(リスト6-2を参照)では、渡されたURLオブジェクトが、クエリおよびコードの部分を使ってアプリケーション固有の情報を伝えます。デリゲートは、この情報(この例では、to-do項目の名前とその項目の締切日)を抽出し、それを使ってアプリケーションのモデルオブジェクトを作成します。この例では、ユーザはグレゴリオ暦を使用していることを前提としています。アプリケーションがグレゴリオ暦以外のカレンダーをサポートしている場合は、それに応じてURLスキームを設計して、コード内で別のタイプのカレンダーを処理できるように準備する必要があります。

リスト6-2  カスタムスキームに基づいたURLリクエストの処理

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
        sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    if ([[url scheme] isEqualToString:@"todolist"]) {
        ToDoItem *item = [[ToDoItem alloc] init];
        NSString *taskName = [url query];
        if (!taskName || ! [self isValidTaskString:taskName]) { // タスク名を持っている必要がある
            return NO;
        }
        taskName = [taskName stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
 
        item.toDoTask = taskName;
        NSString *dateString = [url fragment];
        if (!dateString || [dateString isEqualToString:@"today"]) {
            item.dateDue = [NSDate date];
        } else {
            if(! [self isValidDateString:dateString]) {
                return NO;
            }
            // 形式:yyyymmddhhmm(24時間)
            NSString *curStr = [dateString substringWithRange:NSMakeRange(0, 4)];
            NSInteger yeardigit = [curStr integerValue];
            curStr = [dateString substringWithRange:NSMakeRange(4, 2)];
            NSInteger monthdigit = [curStr integerValue];
            curStr = [dateString substringWithRange:NSMakeRange(6, 2)];
            NSInteger daydigit = [curStr integerValue];
            curStr = [dateString substringWithRange:NSMakeRange(8, 2)];
            NSInteger hourdigit = [curStr integerValue];
            curStr = [dateString substringWithRange:NSMakeRange(10, 2)];
            NSInteger minutedigit = [curStr integerValue];
 
            NSDateComponents *dateComps = [[NSDateComponents alloc] init];
            [dateComps setYear:yeardigit];
            [dateComps setMonth:monthdigit];
            [dateComps setDay:daydigit];
            [dateComps setHour:hourdigit];
            [dateComps setMinute:minutedigit];
            NSCalendar *calendar = [s[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
            NSDate *itemDate = [calendar dateFromComponents:dateComps];
            if (!itemDate) {
                return NO;
            }
            item.dateDue = itemDate;
        }
 
        [(NSMutableArray *)self.list addObject:item];
        return YES;
    }
    return NO;
}

アプリケーションに渡されたURLから取得した入力は必ず検証してください。URL処理に関連する問題を回避する方法については、『Secure Coding Guide』の「Validating Input and Interprocess Communication」を参照してください。Appleが定義したURLスキームについては、『Apple URL Scheme Reference』を参照してください。

URLで指定されたリソースを開く際に独自の起動画像を表示する

独自のURLスキームを取り扱うアプリケーションは、スキームに応じた独自の起動画像を用意することも可能です。システムがあるURLを渡して当該アプリケーションを起動する際、画面に表示する適当なスナップショットがなければ、この起動画像を表示することになります。起動画像として用いるのはPNG画像で、次の規約に従った名前にしておかなければなりません。

<basename>-<url_scheme><other_modifiers>.png

ここで「basename」は画像名のベースとなる文字列で、アプリケーションのInfo.plistファイルに、UILaunchImageFileキーの値として指定します。指定しなければ「Default」という名前になります。<url_scheme>の部分はURLのスキームを表します。たとえばmyappというURLスキームに対応する起動画像であれば、Default-myapp@2x.pngという名前で、アプリケーションバンドルに収容してください(修飾子「@2x」はRetinaディスプレイに表示することを表します。標準解像度のディスプレイにも表示する場合、Default-myapp.pngという画像も用意してください)。

起動画像ファイル名に指定できる他の修飾子については、『Information Property List Key Reference』の、UILaunchImageFileというキーに関する解説を参照してください。