質問編集履歴

2 他アプリから参照可能な場所にファイルをコピーする方法では共有に成功

rtamura

rtamura score 34

2016/06/16 09:17  投稿

AndroidのContent ProviderでGmailアプリにファイルを受け渡すことができない
###前提・実現したいこと
Androidアプリケーションの開発を行っています。
アプリで実現したいことは
・自身のアプリから他のアプリを起動し、起動先アプリへ画像ファイルを渡す。
・画像ファイルはアプリ内の`asset`フォルダに含まれる
です。
私が調べた範囲では、外部アプリとファイルの連携を行う方法として以下の二つがあるようです。
0. `assets`内のファイルを他のアプリから参照できる共有ディレクトリにコピーし、そのパス(URI)をIntentで送る。
0. `Content Provider`の仕組みを利用し、他のアプリから`asset`内のデータを参照できるようにして、そのパス(URI)をIntentで送る。
今回はなるべく外部にファイルを残したくないので、まず上記の方法2で実装を行いました。
現状、
Twitterアプリでは画像を参照できるのですが、
Gmailアプリの場合は参照同様の方法でファイルが参照できない状態です。
###発生している問題・エラーメッセージ
Twitterアプリには画像の受け渡しができることを確認したのですが、
Gmailの場合は
```
空のファイルを添付することはできません。
```
と表示されてしまい、添付することができない状態です。
###該当のソースコード
- マニフェストファイル(AndroidManifest.xml)
``` xml
... provider設定の部分のみ抜粋 ...
<provider android:name="com.example.r_tamura.app.AssetFileProvider"
   android:authorities="com.example.r_tamura.app.provider.Asset"
   android:exported="true"
   android:grantUriPermissions="true"
   android:multiprocess="true">
</provider>
...
```
- AssetFileProvider.java
```java
// Content Providerを継承したProviderクラス
public class AssetFileProvider extends ContentProvider {
   public static final String PROVIDER_AUTHORITY = "com.example.r_tamura.app.provider.Asset";
   public static final String URL = "content://" + PROVIDER_AUTHORITY;
   public static final Uri CONTENT_URI = Uri.parse(URL);
   ... 実装が必要なメソッドはオーバーライドしたデフォルトの処理のままですので省略 ...
   @Nullable
   @Override
   public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
       AssetManager am = getContext().getAssets();
       AssetFileDescriptor afd = null;
       String path = uri.getLastPathSegment();
       try {
           afd = am.openFd(path);
       } catch (IOException e) {
           e.printStackTrace();
           Log.e(Const.LOGTAG, "Error: " + e);
           throw new FileNotFoundException(e.getMessage());
       }
       return afd;
   }
}
```
- MainActivity.java
メインアクティビティクラスです。画面内のボタンを押すとIntentを発行するイベントを登録しています。
```java
// メインアクティビティのボタンにIntent発行すイベントを登録する
public class MainActivity extends Activity {
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
   Button btn = (Button) findViewById(R.id.btn); // ボタンを取得
       btn.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v){
               // "sample.png"が共有したい画像で,ファイルは`asset`ディレクトリの直下に配置しております。
               Uri theUri = Uri.parse("content://com.example.r_tamura.app.provider.Asset/sample.png");
               Intent shareIntent = new Intent(Intent.ACTION_SEND);
               shareIntent.setType("image/*");
               shareIntent.putExtra(Intent.EXTRA_STREAM, theUri);
               shareIntent.putExtra(Intent.EXTRA_SUBJECT, "サンプルタイトル");
               shareIntent.putExtra(Intent.EXTRA_TEXT, "サンプルメッセージ"));
               shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
               startActivity(Intent.createChooser(i, "Chooserタイトル"));
           }
   }
 
```
###試したこと
上記のコードで方法2を実装しました。
現在は方法1でGmailに対応できるかを検証するため、方法1を実装中です。
2016/06/16追記
方法1で実装することでGmail,Twitterに画像を渡すことが一応できました。
###補足情報(言語/FW/ツール等のバージョンなど)
■ 事象を確認した実機データ
- モデル番号:Nexus 7
- Androidバージョン: 5.1.1
■ 開発環境
- OS: Windows 10
- IDE: Android Studio 2.1.2
対応方法をご存知でしたらご教授いただけますと幸いです。よろしくお願いいたします。
ContentProviderを使用した対応方法をご存知でしたらご教授いただけますと幸いです。よろしくお願いいたします。
  • Android

    10190 questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

1 質問に不要なソースコード部分を削除

rtamura

rtamura score 34

2016/06/15 10:44  投稿

AndroidのContent ProviderでGmailアプリにファイルを受け渡すことができない
###前提・実現したいこと
Androidアプリケーションの開発を行っています。
アプリで実現したいことは
・自身のアプリから他のアプリを起動し、起動先アプリへ画像ファイルを渡す。
・画像ファイルはアプリ内の`asset`フォルダに含まれる
です。
私が調べた範囲では、外部アプリとファイルの連携を行う方法として以下の二つがあるようです。
0. `assets`内のファイルを他のアプリから参照できる共有ディレクトリにコピーし、そのパス(URI)をIntentで送る。
0. `Content Provider`の仕組みを利用し、他のアプリから`asset`内のデータを参照できるようにして、そのパス(URI)をIntentで送る。
今回はなるべく外部にファイルを残したくないので、まず上記の方法2で実装を行いました。
現状、
Twitterアプリでは画像を参照できるのですが、
Gmailアプリの場合は参照同様の方法でファイルが参照できない状態です。
###発生している問題・エラーメッセージ
Twitterアプリには画像の受け渡しができることを確認したのですが、
Gmailの場合は
```
空のファイルを添付することはできません。
```
と表示されてしまい、添付することができない状態です。
###該当のソースコード
- マニフェストファイル(AndroidManifest.xml)
``` xml
... provider設定の部分のみ抜粋 ...
<provider android:name="com.example.r_tamura.app.AssetFileProvider"
   android:authorities="com.example.r_tamura.app.provider.Asset"
   android:exported="true"
   android:grantUriPermissions="true"
   android:multiprocess="true">
</provider>
...
```
- AssetFileProvider.java
```java
// Content Providerを継承したProviderクラス
public class AssetFileProvider extends ContentProvider {
   public static final String PROVIDER_AUTHORITY = "com.example.r_tamura.app.provider.Asset";
   public static final String URL = "content://" + PROVIDER_AUTHORITY;
   public static final Uri CONTENT_URI = Uri.parse(URL);
   ... 実装が必要なメソッドはオーバーライドしたデフォルトの処理のままですので省略 ...
   @Nullable
   @Override
   public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
       AssetManager am = getContext().getAssets();
       AssetFileDescriptor afd = null;
       String path = uri.getLastPathSegment();
       try {
           afd = am.openFd(path);
       } catch (IOException e) {
           e.printStackTrace();
           Log.e(Const.LOGTAG, "Error: " + e);
           throw new FileNotFoundException(e.getMessage());
       }
       return afd;
   }
 
   /**  
    * asset内のパスをURIへ変換した文字列を取得します  
    * @param name asset内のパス  
    * @return 変換後のURI  
    */  
   public static Uri getContentUri(String name) {  
       return Uri.parse(URL + "/" + name);  
   }  
}
```
- MainActivity.java
メインアクティビティクラスです。画面内のボタンを押すとIntentを発行するイベントを登録しています。
```java
// メインアクティビティのボタンにIntent発行すイベントを登録する
public class MainActivity extends Activity {
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
   Button btn = (Button) findViewById(R.id.btn); // ボタンを取得
       btn.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v){
               // "sample.png"が共有したい画像で,ファイルは`asset`ディレクトリの直下に配置しております。
               Uri theUri = Uri.parse("content://com.example.r_tamura.app.provider.Asset/sample.png");
               Intent shareIntent = new Intent(Intent.ACTION_SEND);
               shareIntent.setType("image/*");
               shareIntent.putExtra(Intent.EXTRA_STREAM, theUri);
               shareIntent.putExtra(Intent.EXTRA_SUBJECT, "サンプルタイトル");
               shareIntent.putExtra(Intent.EXTRA_TEXT, "サンプルメッセージ"));
               shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
               startActivity(Intent.createChooser(i, "Chooserタイトル"));
           }
   }
 
```
###試したこと
上記のコードで方法2を実装しました。
現在は方法1でGmailに対応できるかを検証するため、方法1を実装中です。
###補足情報(言語/FW/ツール等のバージョンなど)
■ 事象を確認した実機データ
- モデル番号:Nexus 7
- Androidバージョン: 5.1.1
■ 開発環境
- OS: Windows 10
- IDE: Android Studio 2.1.2
対応方法をご存知でしたらご教授いただけますと幸いです。よろしくお願いいたします。
  • Android

    10190 questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る