stylesheet

2014-07-31

Androidアプリの画像シェアインテントの扱いを調べた

シナリオ

インテント送信元のアプリはプライベート領域上にPNG画像ファイルを保有しており、これを独自に実装したContentProviderを使用して外部アプリへ共有する。

調査方法としてアプリ内で以下のようなインテントを生成し、ContentProviderへのメソッド呼び出しをデバッガで調べた。


Intent i = new Intent(Intent.ACTION_SEND);
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setType("image/png");
i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
i.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://__authority__/image/1"));

調査結果

<OK> ‐ Twitter公式クライアント 5.19.0

  1. #query projection={"_data"}
  2. #query projection={"_data"}
  3. #getType
  4. #openFile
  5. 読込成功

_dataはメディアストアに対してのクエリで使用できるカラムです。ファイルへの絶対パスが格納されています。
一旦、MediaStoreのコンテンツと仮定してアクセスを行い、失敗した場合はContentResolver経由でファイルオープンを行う実装でしょうか。
パッチ対応っぽい気配を感じる動作ですので、不具合報告を受けてのツギハギ修正でしょう。

<OK> ‐ Facebook公式クライアント 13.0.0.13.14

  1. #getType
  2. #openFile
  3. 読込成功

#getTypeでファイルタイプを調べてから、#openFileでデータを読み取りに来ます。
無駄のないシンプルな実装です。試しに#getTypeで出鱈目な文字列を返したら#openFileは呼ばれませんでした。

<OK> ‐ Google+ 4.4.3.69327528

  1. #getType
  2. #openFile
  3. #openFile
  4. #openFile
  5. #openFile
  6. 読込成功

手順としてはFacebookと変わりありません。#openFileが繰り返し呼ばれているのは、Exif読込、画像サイズ確認等を行っている為だと思います。
#openFileを繰り返し呼ぶ雑な作りと、ごちゃごちゃと細かい処理を組み合わせるのがAndroidのスタイルのようです。

<OK> ‐ Googleドライブ 2.0.222.39

  1. #query projection={"_display_name"}
  2. #query projection={"_id"}
  3. #openFile
  4. ダイアログ表示 OKボタン押下
  5. #openFile
  6. #openFile
  7. 成功

ダイアログが表示されてからOK後に再度#openFileが呼ばれます。
大きなファイルも扱いますし、メモリに確保せずに都度ファイルを読みに行く仕様なのでしょう。しばらく間が空いてからファイルを読みに来ることもあるので注意が必要かもしれません。

<OK> ‐ Gmail 4.9

  1. #getType
  2. #query projection={"_display_name,_size"}
  3. #openFile x 8
  4. 読込成功

なぜか#openFileが連続して8回も呼ばれます。ちょっと意味がわかりません。

<OK> ‐ Keep 2.3.02

  1. #getType
  2. #openFile
  3. #openFile
  4. 読込成功

#openFileの一回目で画像サイズを取得、二回目でリサンプルしながら画像読込だと思います。

<NG> ‐ Line 4.5.4

  1. #query projection={"orientation", "_data"}
  2. 失敗

orientaionと_dataはMediaStoreのカラムです。画像の向きと実ファイルのパスが入ります。
実装としては完全にMediaStoreコンテンツ専用で、Twitter公式のように失敗時にContentResolverからオープンすることもおこないません。
そのためアプリのプライベートデータをコンテンツプロバイダ経由で受け渡すことはできそうにありません。
データを共有するには一旦パブリックな領域へコピーして_dataカラムでパスを渡してやるか、MediaStoreへ書き出してからシェアしてやる必要がありそうです。


LINEへ共有できないので調べ始めましたが、結局うまく動作しないのはLINEだけという残念な結果に終わりました。
国内有数のユーザー数を誇るサービスでもあるので、対応させるかどうか悩ましいところではあります。

いや、むしろLINEが対応してくれないかと切に希望致します。

調査終わり。2014年7月某日。

参考