コンテンツ URI を使用してファイルを共有するようにアプリを設定したら、他のアプリの 作成できるようになります。このようなリクエストに対応する一つの方法は、ファイルの選択です。 他のアプリケーションが呼び出せるサーバーアプリからインターフェースを提供します。この方法では アプリケーションを使用して、ユーザーがサーバーアプリからファイルを選択し、選択したファイルの 指定します。
このレッスンでは、アプリでファイル選択 Activity
を作成する方法について説明します。
リクエストに応答する
Cloud Functions の関数を作成しました
ファイル リクエストを受信する
クライアント アプリからファイルのリクエストを受信し、コンテンツ URI を返すには、アプリで
ファイル選択 Activity
を指定します。クライアント アプリは、
アクションを含む Intent
を指定して startActivityForResult()
を呼び出すことで Activity
ACTION_PICK
。クライアント アプリが
startActivityForResult()
さん、アプリは次のことができます
ユーザーが選択したファイルのコンテンツ URI の形式で結果をクライアント アプリに返す。
クライアント アプリでファイルのリクエストを実装する方法については、レッスンをご覧ください。 共有ファイルのリクエスト
ファイル選択アクティビティを作成する
ファイル選択 Activity
を設定するには、まず
マニフェストで Activity
(インテント フィルタを指定)
アクション ACTION_PICK
、
カテゴリ: CATEGORY_DEFAULT
、
CATEGORY_OPENABLE
。MIME タイプのフィルタも追加する
アプリが他のアプリに配信するファイルの
詳細が表示されます次のスニペットは、Cloud Storage バケットを
新しい Activity
とインテント フィルタ:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> ... <application> ... <activity android:name=".FileSelectActivity" android:label="@File Selector" > <intent-filter> <action android:name="android.intent.action.PICK"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.OPENABLE"/> <data android:mimeType="text/plain"/> <data android:mimeType="image/*"/> </intent-filter> </activity>
コードでファイル選択アクティビティを定義する
次に、利用可能なファイルを表示する Activity
サブクラスを定義します。
内部ストレージにアプリの files/images/
ディレクトリに配置し、ユーザーが
クリックします。次のスニペットは、この変数を定義する方法を示しています。
Activity
を呼び出して、ユーザーの選択に応答します。
Kotlin
class MainActivity : Activity() { // The path to the root of this app's internal storage private lateinit var privateRootDir: File // The path to the "images" subdirectory private lateinit var imagesDir: File // Array of files in the images subdirectory private lateinit var imageFiles: Array<File> // Array of filenames corresponding to imageFiles private lateinit var imageFilenames: Array<String> // Initialize the Activity override fun onCreate(savedInstanceState: Bundle?) { ... // Set up an Intent to send back to apps that request a file resultIntent = Intent("com.example.myapp.ACTION_RETURN_FILE") // Get the files/ subdirectory of internal storage privateRootDir = filesDir // Get the files/images subdirectory; imagesDir = File(privateRootDir, "images") // Get the files in the images subdirectory imageFiles = imagesDir.listFiles() // Set the Activity's result to null to begin with setResult(Activity.RESULT_CANCELED, null) /* * Display the file names in the ListView fileListView. * Back the ListView with the array imageFilenames, which * you can create by iterating through imageFiles and * calling File.getAbsolutePath() for each File */ ... } ... }
Java
public class MainActivity extends Activity { // The path to the root of this app's internal storage private File privateRootDir; // The path to the "images" subdirectory private File imagesDir; // Array of files in the images subdirectory File[] imageFiles; // Array of filenames corresponding to imageFiles String[] imageFilenames; // Initialize the Activity @Override protected void onCreate(Bundle savedInstanceState) { ... // Set up an Intent to send back to apps that request a file resultIntent = new Intent("com.example.myapp.ACTION_RETURN_FILE"); // Get the files/ subdirectory of internal storage privateRootDir = getFilesDir(); // Get the files/images subdirectory; imagesDir = new File(privateRootDir, "images"); // Get the files in the images subdirectory imageFiles = imagesDir.listFiles(); // Set the Activity's result to null to begin with setResult(Activity.RESULT_CANCELED, null); /* * Display the file names in the ListView fileListView. * Back the ListView with the array imageFilenames, which * you can create by iterating through imageFiles and * calling File.getAbsolutePath() for each File */ ... } ... }
ファイル選択に応答する
ユーザーが共有ファイルを選択したら、アプリケーションは選択されたファイルを確認し、
ファイルのコンテンツ URI を生成します。Activity
には
ListView
内の使用可能なファイルのリスト(ユーザーがファイル名をクリックしたとき)
システムはメソッド onItemClick()
を呼び出します。これにより、選択されたファイルを取得できます。
インテントを使用して、あるアプリから別のアプリにファイルの URI を送信する場合、
他の Pod が使用している URI を
できます。Android 6.0(API レベル 23)以降を搭載しているデバイスの場合
特殊な
特に、Android のそのバージョンでは権限モデルが変更されたため、
READ_EXTERNAL_STORAGE
の
になる
危険な権限(受信側のアプリにはない可能性があります)
こうした考慮事項を念頭に置き、Terraform での使用は
Uri.fromFile()
、これは
これにはいくつかの欠点があります。このメソッドでは次の処理が行われます。
- プロファイル間でのファイル共有が許可されません。
- アプリに以下が必要です。
WRITE_EXTERNAL_STORAGE
Android 4.4(API レベル 19)以前を搭載しているデバイスでは、この権限が必要になります。 - 受信側のアプリに
READ_EXTERNAL_STORAGE
権限は、 その権限を持たない重要な共有ターゲット(Gmail など)では失敗します。
Uri.fromFile()
を使用する代わりに、
URI 権限を使用して、他のアプリ
アクセスを制御できます。URI 権限は file://
URI では機能しません。
Uri.fromFile()
によって生成された
コンテンツ プロバイダに関連付けられた URI に対して機能します。「
FileProvider
API は
作成すると便利です。この方法は、標準外のファイルにも適用できます。
外部ストレージに保存されますが、インテントを送信するアプリのローカル ストレージに保存されます。
onItemClick()
で、
選択したファイルのファイル名の File
オブジェクトを取得し、引数として
getUriForFile()
、および
権限のある認証情報で
FileProvider
の <provider>
要素。
結果として得られるコンテンツ URI には、認証局、ファイルのパス セグメント、
ディレクトリ(XML メタデータで指定)とそのファイルを含むファイル名(
あります。FileProvider
がディレクトリをパスにマッピングする方法
XML メタデータに基づくセグメントについては、セクションで
共有可能なディレクトリを指定する。
次のスニペットは、選択したファイルを検出して、そのコンテンツ URI を取得する方法を示しています。
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { ... // Define a listener that responds to clicks on a file in the ListView fileListView.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ -> /* * Get a File for the selected file name. * Assume that the file names are in the * imageFilename array. */ val requestFile = File(imageFilenames[position]) /* * Most file-related method calls need to be in * try-catch blocks. */ // Use the FileProvider to get a content URI val fileUri: Uri? = try { FileProvider.getUriForFile( this@MainActivity, "com.example.myapp.fileprovider", requestFile) } catch (e: IllegalArgumentException) { Log.e("File Selector", "The selected file can't be shared: $requestFile") null } ... } ... }
Java
protected void onCreate(Bundle savedInstanceState) { ... // Define a listener that responds to clicks on a file in the ListView fileListView.setOnItemClickListener( new AdapterView.OnItemClickListener() { @Override /* * When a filename in the ListView is clicked, get its * content URI and send it to the requesting app */ public void onItemClick(AdapterView<?> adapterView, View view, int position, long rowId) { /* * Get a File for the selected file name. * Assume that the file names are in the * imageFilename array. */ File requestFile = new File(imageFilename[position]); /* * Most file-related method calls need to be in * try-catch blocks. */ // Use the FileProvider to get a content URI try { fileUri = FileProvider.getUriForFile( MainActivity.this, "com.example.myapp.fileprovider", requestFile); } catch (IllegalArgumentException e) { Log.e("File Selector", "The selected file can't be shared: " + requestFile.toString()); } ... } }); ... }
コンテンツ URI は、ディレクトリ内に存在するファイルに対してのみ生成できます。
<paths>
要素を含むメタデータ ファイル内で指定した
共有可能なディレクトリを指定するをご覧ください。電話
getUriForFile()
:
指定していないパスで File
を指定すると、
IllegalArgumentException
。
ファイルの権限を付与する
他のアプリと共有するファイルのコンテンツ URI を取得できたら、次は
クライアント アプリにファイルへのアクセスを許可します。アクセスを許可するには、次の方法でクライアント アプリに権限を付与します。
コンテンツ URI を Intent
に追加し、次に権限フラグを
Intent
。付与する権限は一時的なものであり、期限切れになる
受信側のアプリのタスクスタックが完了すると自動的にトリガーされます。
次のコード スニペットは、ファイルの読み取り権限を設定する方法を示しています。
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { ... // Define a listener that responds to clicks on a file in the ListView fileListView.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ -> ... if (fileUri != null) { // Grant temporary read permission to the content URI resultIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) ... } ... } ... }
Java
protected void onCreate(Bundle savedInstanceState) { ... // Define a listener that responds to clicks in the ListView fileListView.setOnItemClickListener( new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long rowId) { ... if (fileUri != null) { // Grant temporary read permission to the content URI resultIntent.addFlags( Intent.FLAG_GRANT_READ_URI_PERMISSION); } ... } ... }); ... }
注意: setFlags()
の呼び出しは、
一時的なアクセス権限を使用してファイルへのアクセス権を安全に付与する、という方法があります。電話をかけない
Context.grantUriPermission()
メソッド(
付与します。このメソッドでは、権限を取り消すことができるのは、
Context.revokeUriPermission()
を呼び出しています。
Uri.fromFile()
は使用しないでください。受信するアプリを強制的に
READ_EXTERNAL_STORAGE
権限を付与する。
複数のユーザー間や複数のバージョン間で共有しようとすると、
Android 4.4(API レベル 19)よりも前のバージョンの Android
WRITE_EXTERNAL_STORAGE
が必要です。
また、Gmail アプリなどの非常に重要な共有ターゲットには、
READ_EXTERNAL_STORAGE
で発生し、
この呼び出しは失敗します。
代わりに、URI 権限を使用して、他のアプリに特定の URI へのアクセス権を付与できます。
一方、URI 権限は、
Uri.fromFile()
、彼らは
コンテンツ プロバイダに関連付けられた URI を処理します。そのために独自のルールを実装するのではなく
FileProvider
を使用できます。また、使用すべきです。
詳しくは、ファイル共有をご覧ください。
リクエスト元のアプリとファイルを共有する
ファイルをリクエストしたアプリとファイルを共有するには、Intent
を渡します。
コンテンツ URI と setResult()
への権限を含む。先ほど定義した Activity
が終了すると、
システムがコンテンツ URI を含む Intent
をクライアント アプリに送信する。
次のコード スニペットは、その方法を示しています。
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { ... // Define a listener that responds to clicks on a file in the ListView fileListView.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ -> ... if (fileUri != null) { ... // Put the Uri and MIME type in the result Intent resultIntent.setDataAndType(fileUri, contentResolver.getType(fileUri)) // Set the result setResult(Activity.RESULT_OK, resultIntent) } else { resultIntent.setDataAndType(null, "") setResult(RESULT_CANCELED, resultIntent) } } }
Java
protected void onCreate(Bundle savedInstanceState) { ... // Define a listener that responds to clicks on a file in the ListView fileListView.setOnItemClickListener( new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long rowId) { ... if (fileUri != null) { ... // Put the Uri and MIME type in the result Intent resultIntent.setDataAndType( fileUri, getContentResolver().getType(fileUri)); // Set the result MainActivity.this.setResult(Activity.RESULT_OK, resultIntent); } else { resultIntent.setDataAndType(null, ""); MainActivity.this.setResult(RESULT_CANCELED, resultIntent); } } });
ユーザーがファイルを選択したら、すぐにクライアント アプリに戻る方法を提供する。
たとえば、チェックマークまたは完了ボタンを提供します。メソッドを
ボタンの
android:onClick
属性。メソッドで、次を呼び出します。
finish()
。次に例を示します。
Kotlin
fun onDoneClick(v: View) { // Associate a method with the Done button finish() }
Java
public void onDoneClick(View v) { // Associate a method with the Done button finish(); }
その他の関連情報については、以下をご覧ください。