Gdy aplikacja chce uzyskać dostęp do pliku udostępnionego przez inną aplikację, aplikacja wysyłająca żądanie (klient)
zwykle wysyła żądanie do aplikacji udostępniającej pliki (serwer). W większości przypadków
uruchamia w aplikacji serwerowej element Activity
, który wyświetla pliki, które umożliwia udostępnianie plików.
Użytkownik wybiera plik, po czym aplikacja serwerowa zwraca identyfikator URI treści pliku do funkcji
aplikacji klienckiej.
Z tej lekcji dowiesz się, jak aplikacja kliencka wysyła żądanie pliku od aplikacji serwerowej, odbiera żądanie pliku identyfikator URI treści z aplikacji serwera i otwiera plik za pomocą identyfikatora URI treści.
Wyślij prośbę o plik
Aby zażądać pliku z aplikacji serwera, aplikacja kliencka wywołuje
startActivityForResult
z
Intent
, na którym znajduje się działanie takie jak
ACTION_PICK
i typ MIME wybrany przez aplikację kliencką
który sobie radzi.
Na przykład ten fragment kodu pokazuje, jak wysłać
Intent
do aplikacji serwera, aby uruchomić
Activity
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
Intent
Parametr Intent
jest przekazywany do klienta
w przypadku aplikacji, które zastąpią onActivityResult()
. Jednorazowo
aplikacja kliencka ma identyfikator URI treści pliku, może uzyskać do niego dostęp, pobierając
FileDescriptor
Bezpieczeństwo plików jest w tym procesie zachowane tylko, o ile poprawnie przeanalizujesz identyfikator URI treści ponoszony przez aplikację kliencką. Analizując treść, upewnij się, że ten identyfikator URI nie wskazuje do czegokolwiek poza żądanym katalogiem, dzięki czemu żaden z nich podejmuje próbę pominięcia ścieżki. Tylko aplikacja kliencka powinna uzyskać dostęp do pliku i tylko w przypadku uprawnień przyznanych przez aplikacji serwera. Uprawnienia są tymczasowe, więc po zakończeniu stosu zadań aplikacji klienckiej nie jest już dostępny poza aplikacją serwera.
Następny fragment kodu pokazuje, jak aplikacja kliencka obsługuje
Intent
wysłane z aplikacji serwera oraz sposób, w jaki aplikacja kliencka
FileDescriptor
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 ParcelFileDescriptor
dla pliku. Z poziomu tego obiektu klient
pobiera obiekt FileDescriptor
, którego może użyć do odczytania pliku.
Dodatkowe informacje znajdziesz tutaj: