Wysyłanie prośby o udostępnienie pliku

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: