A Day In The Life

とあるプログラマの備忘録

iPhoneとAndroidのアプリケーション間連携方法を比較してみる

アプリAとアプリBがあり、アプリAでテキストボックスに文字を入力しボタンを押すとテキストボックスの内容をアプリBの画面に表示するサンプルを使って説明します。
アプリ間連携の図

iPhoneの場合

iPhone では UIApplication クラスの openURL メソッドを使うと他のアプリを起動することができます(Safariもこの方法で起動できます)。iPhone は単一アプリしか立ち上げることができないので openURL メソッドが呼びだされたときに呼び出し元アプリは終了してしまいます。そこでアプリを呼び出す際に呼び出し元アプリのURLを渡し、呼び出されたアプリの作業終了後に戻りURLを使って再び呼び出し元アプリを起動します。このようにすることであたかもアプリ間連携しているかのようにできます。
iPhoneのアプリ間連携をシーケンス図で表すとこのようになります。

呼び出される側の実装

  1. URLパターンを決める

    他のアプリから起動できるようにするためにまずは呼び出しに使うURLを決めます。スキーマ名はアプリ開発者が好きに決めることが出来ます。他のアプリとかぶらないようにアプリケーション名にしておくのが無難です。

    <スキーマ名>://<アクション名>?<パラメータ名>=<パラメータの値>#<呼び出し元のURL>
    例:linkedword://open?word=innovation#opener://open


  2. info.plistを編集
    URLが決まったらinfo.plistにURLの情報を記述します。画像のURL types以下を追加します。

    xcodeのスクリーンショット

  3. UIApplicationDelegateを修正
    他のアプリケーションから呼ばれた場合、applicationDidFinishLaunching:メソッドより先にapplication:handleOpenURL:メソッドが呼ばれます。application:handleOpenURL:メソッドで呼び出し側アプリのURLを解析しユーザデフォルトに保存します。

    @implementation XXXAppDelegate
    
    - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
      NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
      [defaults setObject:[[url query] stringByReplacingOccurrencesOfString:@"word=" withString:@""]
                   forKey:@"param"];
      [defaults setObject:[url fragment] forKey:@"callbackurl"];
      [defaults synchronize];	
      return YES;
    }
    @end
    


  4. 呼び出される側の終了条件を決める
    iPhoneAndroid のようにバックボタン(戻るボタン)がありません。なので他のアプリから起動された場合どのようにして呼び出し側のアプリに戻るか決める必要があります。もちろんホームを押して終了したときに戻るように実装しても良いのですが少し違和感があります(個人的主観です)。他のアプリから呼ばれた場合のみ終了ボタンなり戻るボタンを表示して戻れるようにするのが良いと思います。

  5. 終了時の実装
    起動時に保存したユーザデフォルトの戻りURLを使って呼び出し側アプリを起動します。

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *urlString = [defaults stringForKey:@"callbackurl"];
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
    


呼び出し側の実装

  1. URLを決める
    呼び出され側アプリから戻るときに UIApplication#openURL メソッドを使って戻るので、呼び出し側アプリもURLを決める必要があります。呼び出され側アプリと同様 info.plist を編集します。サンプルは opener:// にしています。
  2. UIApplication インスタンスの openURL メソッドを使ってアプリを呼び出す。
    URLのパラメータに1で設定したURL(opener://)を指定するのがポイントです。

    @implementation XXXViewController
    
    @synthesize textField;
    
    // ボタンクリックイベント
    - (IBAction)buttonClick:(id)sender {
      NSString *urlString = [NSString stringWithFormat:@"linkedword://open?word=%@#opener://", textField.text];
      [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
    }
    @end
    


アプリ連携時のデバック方法

Xcodeのメニューから「プロジェクト」→「アクティブな実行可能ファイル"xxx"を編集」→「デバック」タブを選択→「次の起動/プッシュ通知を待機」をチェックするとデバックできます。

万が一スキーマ名がかぶったら

未検証です。追記します。

Androidの場合

Android は Intent という仕組みを使ってアプリ間連携が出来ます。iPhone と違って複数アプリ立ち上げることができるので iPhone に比べて簡単です。
Androidのアプリ間連携をシーケンス図で表すとこのようになります。

呼び出される側の実装

  1. IntentFilterの設定

    AndroidManifest.xmlのactivityタグ以下に Intent Filter の設定を追加します。

    <activity android:name=".SampleActivity2"
              android:label="@string/app_name">
      <intent-filter>
        ...初期設定
      </intent-filter>
      <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
      </intent-filter>
    </activity>
    


  2. Activityクラスの実装

    呼び出し側から渡ってきたデータは Intent#getExtras() メソッドで取得できます。サンプルでは呼び出し側から渡ってきたデータを画面に出力しています。

    public class SampleActivity2 extends Activity {
      public void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.main);
        TextView text = (TextView)findViewById(R.id.text);
        Intent i = getIntent();
        if (Intent.ACTION_VIEW.equals(i.getAction())) {
          CharSequence cs = i.getExtras().getCharSequence(Intent.EXTRA_TEXT);
          text.setText(CS);
        }
      }
    }
    


呼び出し側の実装

呼び出される側の Intent Filter の設定に従って Intent クラスのインスタンスを生成し、startActivity メソッドに渡してやります。

public class SampleActivity extends Activity {
  EditText editText;
  public void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.main);
    editText = (EditText)findViewById(R.id.text);
    Button button = (Button)findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {
      public void onClick(View v) {
        String text = editText.getText().toString();
        Intent i = new Intent(Intent.ACTION_VIEW);
        i.setType("text/plain");
        i.putExtra(Intent.EXTRA_TEXT, text);
        startActivity(i);
      }
    });
  }
}

LinkedWordの連携機能

ちなみに私が開発した英英&類語辞書アプリ LinkedWord は他の iPhone/iPod Touch アプリとの連携機能を備えています。以下の URL で LinkedWord を呼び出すことができます。
linkedword://open?word=XXX#opener://

  • XXXに調べたい単語を指定します。
  • opener://に呼び出し元アプリケーションのURLを指定します。