Gdy aplikacja chce uzyskać dostęp do pliku udostępnionego przez inną aplikację, zwykle wysyłająca żądanie (klient) wysyła żądanie do aplikacji (czyli do serwera). W większości przypadków żądanie powoduje uruchomienie w aplikacji serwera polecenia Activity
, które wyświetla pliki, które może udostępnić.
Użytkownik wybiera plik, a aplikacja serwera zwraca URI treści pliku do aplikacji klienckiej.
Z tej lekcji dowiesz się, jak aplikacja kliencka wysyła żądanie pliku do aplikacji serwera, odbiera z aplikacji serwera identyfikator URI treści pliku i otwiera plik za pomocą identyfikatora URI treści.
Wyślij prośbę o plik
Aby poprosić aplikację serwera o plik, aplikacja klienta wywołuje funkcję startActivityForResult
z argumentem Intent
zawierającym działanie takie jak ACTION_PICK
oraz typ MIME, który może obsłużyć aplikacja klienta.
Na przykład poniższy fragment kodu pokazuje, jak wysłać Intent
do aplikacji serwera, aby uruchomić Activity
, jak opisano w sekcji Udostępnianie pliku.
Kotlin
class MainActivity : Activity() { private lateinit var requestFileIntent: Intent private lateinit var inputPFD: ParcelFileDescriptor ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) requestFileIntent = Intent(Intent.ACTION_PICK).apply { type = "image/jpg" } ... } ... private fun requestFile() { /** * When the user requests a file, send an Intent to the * server app. * files. */ startActivityForResult(requestFileIntent, 0) ... } ... }
Java
public class MainActivity extends Activity { private Intent requestFileIntent; private ParcelFileDescriptor inputPFD; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); requestFileIntent = new Intent(Intent.ACTION_PICK); requestFileIntent.setType("image/jpg"); ... } ... protected void requestFile() { /** * When the user requests a file, send an Intent to the * server app. * files. */ startActivityForResult(requestFileIntent, 0); ... } ... }
Dostęp do żądanego pliku
Aplikacja serwera wysyła identyfikator URI treści pliku z powrotem do aplikacji klienckiej w Intent
. Wartość Intent
jest przekazywana do aplikacji klienckiej w ramach zastąpienia wartości onActivityResult()
. Gdy aplikacja klienta ma URI treści pliku, może uzyskać dostęp do pliku, uzyskując jego FileDescriptor
.
Bezpieczeństwo plików jest zachowane w ramach tego procesu tylko wtedy, gdy prawidłowo zanalizujesz URI treści, które otrzymuje aplikacja kliencka. Podczas analizowania treści musisz się upewnić, że ten identyfikator URI nie wskazuje niczego poza właściwym katalogiem. Upewnij się też, że nie jest wykonywana żadna próba przemierzania ścieżki. Dostęp do pliku powinien mieć tylko aplikacja klienta i tylko w zakresie uprawnień przyznanych przez aplikację serwera. Uprawnienia są tymczasowe, więc po zakończeniu wykonywania stosu zadań przez aplikację klienta plik nie jest już dostępny poza aplikacją serwera.
Ten fragment kodu pokazuje, jak aplikacja kliencka obsługuje daneIntent
wysłane z aplikacji serwera, oraz jak uzyskuje daneFileDescriptor
za pomocą identyfikatora URI treści:
Kotlin
/* * When the Activity of the app that hosts files sets a result and calls * finish(), this method is invoked. The returned Intent contains the * content URI of a selected file. The result code indicates if the * selection worked or not. */ public override fun onActivityResult(requestCode: Int, resultCode: Int, returnIntent: Intent) { // If the selection didn't work if (resultCode != Activity.RESULT_OK) { // Exit without doing anything else return } // Get the file's content URI from the incoming Intent returnIntent.data?.also { returnUri -> /* * Try to open the file for "read" access using the * returned URI. If the file isn't found, write to the * error log and return. */ inputPFD = try { /* * Get the content resolver instance for this context, and use it * to get a ParcelFileDescriptor for the file. */ contentResolver.openFileDescriptor(returnUri, "r") } catch (e: FileNotFoundException) { e.printStackTrace() Log.e("MainActivity", "File not found.") return } // Get a regular file descriptor for the file val fd = inputPFD.fileDescriptor ... } }
Java
/* * When the Activity of the app that hosts files sets a result and calls * finish(), this method is invoked. The returned Intent contains the * content URI of a selected file. The result code indicates if the * selection worked or not. */ @Override public void onActivityResult(int requestCode, int resultCode, Intent returnIntent) { // If the selection didn't work if (resultCode != RESULT_OK) { // Exit without doing anything else return; } else { // Get the file's content URI from the incoming Intent Uri returnUri = returnIntent.getData(); /* * Try to open the file for "read" access using the * returned URI. If the file isn't found, write to the * error log and return. */ try { /* * Get the content resolver instance for this context, and use it * to get a ParcelFileDescriptor for the file. */ inputPFD = getContentResolver().openFileDescriptor(returnUri, "r"); } catch (FileNotFoundException e) { e.printStackTrace(); Log.e("MainActivity", "File not found."); return; } // Get a regular file descriptor for the file FileDescriptor fd = inputPFD.getFileDescriptor(); ... } }
Metoda openFileDescriptor()
zwraca wartość ParcelFileDescriptor
dla pliku. Z tego obiektu aplikacja kliencka pobiera obiekt FileDescriptor
, za pomocą którego może odczytać plik.
Więcej informacji znajdziesz w tych artykułach: