ActionBarの共有ボタンに共有履歴を表示する方法

ShareActionProvider

ICS以降、ActionBarに共有MenuItemを置く際、共有履歴を表示することができるようになった。 ShareActionProviderはその実装のための仕組みとして導入された。

実装

まず、menu定義に共有MenuItemを定義する。 このとき、android:actionProviderClass属性にandroid.widget.ShareActionProviderを定義する。 この属性を定義すると自動的に共有アイコンも設定される。 android:showAsActionneverでも正常に動作するが、最新履歴の表示がなくなってしまうためifroomalwaysが良いだろう。

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MyActivity">
    <item
        android:id="@+id/action_share_always"
        android:actionProviderClass="android.widget.ShareActionProvider"
        android:showAsAction="always"
        android:title="@string/action_share" />
</menu>

次に、ソースコード側でMenuItemの設定を行う。 ShareActionProviderを使用する場合、共有アクションで実行するIntentonCreateOptionsMenuで指定できてしまうため、onOptionsItemSelectedでの処理は特に必要なくなる。 また、下の例ではShareCompat.IntentBuilderを利用しているが、普通にIntentを生成してsetShareIntentしても問題なく動く。

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.my, menu);

        // ShareActionProvider の設定
        MenuItem actionItem = menu.findItem(R.id.action_share_always);
        ShareActionProvider actionProvider = (ShareActionProvider) actionItem.getActionProvider();
        // インテントの設定
        Intent shareIntent = ShareCompat.IntentBuilder.from(this)
                .setText("俺プリキュアで赤髪キャラの良さわかった!")
                .setType("text/plain")
                .getIntent();
        // ShareActionProviderにインテントの設定
        actionProvider.setShareIntent(shareIntent);

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // 何も書かなくてOK
        return super.onOptionsItemSelected(item);
    }

動作

はじめて共有アイコンをタップした場合、以下のようなポップアップが表示される。 共有動作実行前

すべてを表示→Twitterを選択し、Twitterから戻るとこのような画面になっている。 複数のアプリで共有を試すと左側の共有アイコンタップで表示されるポップアップも最新以前の履歴になっていることがわかる。 Twitterで共有後

ShareCompat

ShareActionProviderは便利だがICS以降でしか実装ができない。 ICS以前の端末に対応したアプリで同様の実装を行うためにはSupportLibraryShareCompatを利用する。 ただし、ShareCompatを使ってもICS以前の端末で履歴が表示されるわけではない。 この辺りはNotificationCompat等と一緒だ。

実装

ShareCompatで実装を行う場合、menu定義では特別な表記は必要ない。 ただし、デフォルトの共有アイコンが設定されないため、こちらは定義する必要がある。

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MyActivity">
    <item
        android:id="@+id/action_share_always"
        android:icon="@android:drawable/ic_menu_share"
        android:title="共有"
        app:showAsAction="always" />
</menu>

ソースコード側の処理はShareActionProviderを使用していた部分をShareCompatで書きなおすような形になる。 ShareActionProvider同様、onOptionsItemSelectedでの処理は特に必要ない。 ただし、IntentではなくShareCompat.IntentBuilderを渡すことになるため、若干の制限が生じる。 たとえば、ShareCompat.IntentBuilderではsetAction()ができないため、ACTION_SENDACTION_SEND_MULTIPLE以外のアクションが指定できないようだ(ちょっと自信がない…)。

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.my, menu);

        // IntentBuilderの生成
        ShareCompat.IntentBuilder builder = ShareCompat.IntentBuilder.from(this);
        builder.setText("俺プリキュアで赤髪キャラの良さわかった!")
                .setType("text/plain");
        // MenuItemにShareアクションの設定
        ShareCompat.configureMenuItem(menu, R.id.action_share_always, builder);

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        return super.onOptionsItemSelected(item);
    }

動作

ICS以降の端末での挙動はShareActionProviderと変わらない。 それ以前の端末ではmenuのxmlで指定したアイコンのみが表示され、タップ時にはIntentBuilderで生成したIntentが発行される。 物理メニューボタンのある機種でも同様。

まとめ

ActionBarに共有ボタンを置くAndroidアプリは多い。 ShareActionProviderShareCompatを使うと(ICS以降だけだが)非常に少ない手間で共有ボタンをリッチにできるため、かなり便利だと思う。 個人的にも便利なので、アプリ作成者はどんどん実装してほしい。