ストレージにあるファイルを別アプリで表示、メール添付する [FileProviderの使い方]
Android7以降ではインテント(Intent)で内部ストレージにあるファイルを別アプリに投げると「FileUriExposedException」の例外が発生します。
その例外を回避するにはFileProviderクラスを使用します。
STEP1 | AndroidManifest.xmlに「ストレージ権限」と「プロバイダ」を定義する。 |
STEP2 | my_provider.xmlに「プロバイダで使用するpath」を定義する。 |
STEP3 | FileProviderクラスを使用してファイルをインテントで投げます。 |
目次
1. 作るもの
2. ストレージ権限とプロバイダを定義する
3. プロバイダで使用するpathを定義する
4. コーディング
1. 作るもの
Buttonを2個、配置します。
「表示」ボタンでPDFファイルを別アプリで表示します。
「添付」ボタンでPDFファイルをメールやLINEに添付します。
※MIMEタイプを変更すればどのタイプのファイルでもOKです。
2. ストレージ権限とプロバイダを定義する
manifestsフォルダの「AndroidManifest.xml」にストレージ権限(5-6行目)とプロバイダ(23-31行目)を追加します。
[AndroidManifest.xml]
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.petitmonte.android.myapplication"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/my_provider" /> </provider> </application> </manifest>
3. プロバイダで使用するpathを定義する
resフォルダの上で右クリックで[新規][ディレクトリ]でxmlフォルダを作成します。
xmlフォルダの上で右クリックで[新規][XMLリソースファイル]を選択して「my_provider.xml」を作成します。
[my_provider.xml]
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="share" path="." /> </paths>
3行目でpath="."として定義しているので、内部ストレージの最階層からサブフォルダも含む全てのファイルがインテントで使用できるようになります。
<root-path name="sdcard" path="." />
を<paths></paths>内に追加します。
4. コーディング
内部ストレージの最階層にtest.pdfファイルを設置してください。
import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Environment; import android.support.v4.app.ActivityCompat; import android.support.v4.content.FileProvider; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import java.io.File; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 内部ストレージの最階層にあるtest.pdfファイル // ※ファイルは各自で用意してください。 final String pathName = Environment.getExternalStorageDirectory()+"/" + "test.pdf"; // ストレージの権限の確認 if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { // ストレージの権限の許可を求めるダイアログを表示する ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1000); } // 表示 findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_VIEW); Uri uri = FileProvider.getUriForFile(MainActivity.this, MainActivity.this.getApplicationContext().getPackageName() + ".provider", new File(pathName)); intent.setDataAndType(uri,"application/pdf"); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); try { startActivity(intent); } catch (Exception e) { e.printStackTrace(); } } }); // 添付 findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Uri uri = FileProvider.getUriForFile(MainActivity.this, MainActivity.this.getApplicationContext().getPackageName() + ".provider", new File(pathName)); Intent it = new Intent(Intent.ACTION_SEND); it.putExtra(Intent.EXTRA_EMAIL, ""); it.putExtra(Intent.EXTRA_SUBJECT, ""); it.putExtra(Intent.EXTRA_STREAM, uri); it.setType("application/pdf"); try { startActivity(Intent.createChooser(it, "選択")); }catch (Exception e) { e.printStackTrace(); } } }); } }