Android 暗黙的 Intent で Twitter や Evernote と連携する

暗黙的 Intent

Android では、Intent という実行すべき処理を抽象的に記述したクラスを利用して、他のアプリケーションと連携することが可能となっている。

例えば、Windows でも関連づけされていない拡張子を持ったファイルをダブルクリックしたりすると、ファイルを開くアプリケーションを選択するダイアログが開く。

file_choise

これと似たようなことが、アプリケーション間での情報の受け渡にて、もっと柔軟に行うことがというとわかりやすいか。

例えば、あるアプリケーションが、

「このテキストファイルを編集できるアプリケーション手を挙げて!」

と Intent を投げると、「テキストファイル編集可能」と AndroidManifest.xml に記述してあるアプリケーションの一覧から、処理するアプリケーションを選択することができる。

同じアプリケーション内の Activity (画面) から 別 Activity を起動するときにも Intent を使って情報を受け渡すが、この場合、起動する Activity を明示するため、明示的 Intent と呼ばれる。

対して前者は、Intent を送信する先を明示しないため、暗黙的 Intent と呼ばれる。

 

Intent が、すばらしいのは、このように、ゆるーい情報のやりとりのみで、他のアプリケーションと連携できる機構のおかげで、簡単に Twitter 対応だったり、Dropbox 対応だったり、Evernote 対応だったりというキャッチー(?) なアプリケーションが作れてしまうのだ!

 

で、今回は、そんなすばらしい、前者の暗黙的 Intent の利用法をメモ。

暗黙的 Intent を投げてデータを Twitter に送信

自作の テキストエディタ を例に、挙動を確認してみる。

まず、エディタから文章の一部分を選択する

intent01

共有ボタンを押すと、対応するアプリの一覧が表示される

intent02

TweetDeck を選択すると、見事に機能連携が果たされる

intent03

という機能を実現するのに、以下くらいの行数しか必要としない。しかもほとんどテキストの選択範囲を取得するコードで、Intent については、4、5行で自アプリとTwitter アプリとの連携ができてしまう。

いや、これだけで、Twitter だけではなく、Gmail や Evernote とも連携ができている。

すばらしい!

/**
 * 暗黙的 Intent でテキストを共有する
 */
public void share() {
    Intent intent = new Intent(android.content.Intent.ACTION_SEND);
    intent.setType("text/plain");

    // EditText から選択範囲を取得する。選択されていない場合、全体を対象とする
    String content = getEditor().getText().toString();
    int start = getEditor().getSelectionStart();
    int end   = getEditor().getSelectionEnd();

    if (start >= 0 && start != end) {
        if (start > end) {
            int tmp = start;
            start = end;
            end = tmp;
        }
        content = content.substring(start, end);
    }
    intent.putExtra(Intent.EXTRA_TEXT, content);
    startActivity(Intent.createChooser(
            intent, getString(R.string.msg_share_file)));
}

 

暗黙的 Intent を受信して、自アプリで利用する

では、逆に他のアプリが投げた、Intent を拾うにはどうするか。

アストロファイルマネージャー という高機能ファイルマネージャーからテキストファイルをタップする

intent04

様々な立派なアプリに混じって自作エディタが選択ダイアログに表示された!

intent05

自作エディタを選択するとファイルを編集できる

intent06

ということを行うためには、暗黙的 Intent の送信よりは少し多めにコーディングしなければいけないが、以下のような感じ。

AndroidManifest.xml の activity 要素に、intent-filter を記述し、どのようなアクションに応答するのかを記述する

 <activity android:label="@string/app_name" android:name="TypeapadActivity">
   <intent-filter>
     <action android:name="android.intent.action.MAIN" />
     <category android:name="android.intent.category.LAUNCHER" />
   </intent-filter>
   <intent-filter>
     <action android:name="android.intent.action.VIEW" />
     <action android:name="android.intent.action.EDIT" />
     <category android:name="android.intent.category.DEFAULT" />
     <data android:mimeType="text/plain" />
     <data android:mimeType="text/html" />
   </intent-filter>
 </activity>

Activity の onCreate で、暗黙的 Intent が渡された時の処理を記述する

下では省略してあるが、ファイルのURIが渡ってきたら、ファイルを開き、文字列が渡ってきたらEditTextに表示するということを行っているのみ。

 @Override
 public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
 
     // 暗黙的インテントで渡されたデータを処理
     if (!getIntent().getAction().equals(Intent.ACTION_MAIN)) {
         Uri uri = getIntent().getData();
 
         // スキーマの判定
         if ("file".equals(uri.getScheme())) {
             File file = new File(uri.getPath());
             
             // file に対する処理
             
         } else if 
             ("content".equals(uri.getScheme())){
             try {
                 StringBuffer buf = new StringBuffer();
                 ContentResolver cr = getContentResolver();
             
                 BufferedReader reader = new BufferedReader(
                     new InputStreamReader(cr.openInputStream(uri)));
                 
                 String line = null;
                 while((line = reader.readLine()) != null) {
                     buf.append(line).append("\n");
                 }
                 reader.close();
                 
                 // buf を利用した処理
                 
             } catch (Exception e) {
                 // エラー処理
             }
         }
     }

細かい話は、他のサイトやリファレンスを参照ください。

どんな Intent を投げたり受けたりすればよいのか

では、あのお気に入りのアプリに自作アプリの Intent を拾ってもらうには、どんな風に Intent を投げればいいのか?

結構悩んで、ググってもよくわからなかったりすることがあるかも。自分はあった。

LogCat をみるとヒントが得られるかも。

LogCat は、Eclipse メニュー Show View - Other から開く。

logcat

これね。

intent07

これを開いておいて、例えば、ブラウザでページを共有すると

intent08

ログにIntent の内容が以下のように出力される(改行してます)。

02-11 22:22:18.712: INFO/ActivityManager(95): Starting activity: 
Intent { 
  act=android.intent.action.CHOOSER 
  cmp=android/com.android.internal.app.ChooserActivity (has extras) 
}

これを確認すれば、どのような Intent を投げると、どんなアプリに拾ってもらえるのかつかめると思う。

ちなみに、LogCat の行を Ctrl + C すれば、内容がコピーされるので、テキストエディタに貼り付けて確認すれば、Eclipse上で無理に確認する必要はない。

 

いじょ。また一歩野望に近づいた!