Geteilte Datei anfordern

Wenn eine App auf eine Datei zugreifen möchte, die von einer anderen App freigegeben wurde, sendet die anfragende App (der Client) normalerweise eine Anfrage an die App, die die Dateien freigibt (den Server). In den meisten Fällen startet die Anfrage eine Activity in der Server-App, in der die freigegebenen Dateien angezeigt werden. Der Nutzer wählt eine Datei aus. Daraufhin gibt die Server-App den Inhalts-URI der Datei an die Client-App zurück.

In dieser Lektion erfahren Sie, wie eine Client-App eine Datei von einer Server-App anfordert, den Inhalts-URI der Datei von der Server-App empfängt und die Datei mit dem Inhalts-URI öffnet.

Anfrage für die Datei senden

Um eine Datei von der Serveranwendung anzufordern, ruft die Clientanwendung startActivityForResult mit einem Intent auf, der die Aktion enthält, z. B. ACTION_PICK, und einen MIME-Typ, den die Clientanwendung verarbeiten kann.

Das folgende Code-Snippet zeigt beispielsweise, wie eine Intent an eine Server-App gesendet wird, um die unter Datei freigeben beschriebene Activity zu starten:

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);
        ...
    }
    ...
}

Auf die angeforderte Datei zugreifen

Die Serveranwendung sendet den Inhalts-URI der Datei in einem Intent an die Clientanwendung zurück. Dieser Intent wird an die Client-App durch die Überschreibung von onActivityResult() übergeben. Sobald die Clientanwendung den Inhalts-URI der Datei hat, kann sie durch Abrufen des FileDescriptor auf die Datei zugreifen.

Die Dateisicherheit bleibt bei diesem Vorgang nur erhalten, wenn Sie den Inhalts-URI, den die Client-App empfängt, richtig parsen. Achten Sie beim Parsen von Inhalten darauf, dass dieser URI nicht auf etwas außerhalb des vorgesehenen Verzeichnisses verweist, damit kein Pfaddurchlauf ausgeführt wird. Nur die Client-App sollte Zugriff auf die Datei erhalten und nur für die Berechtigungen, die von der Server-App gewährt wurden. Berechtigungen sind temporär. Sobald der Aufgabenstapel der Client-App abgeschlossen ist, ist die Datei nicht mehr außerhalb der Server-App zugänglich.

Im nächsten Snippet wird gezeigt, wie die Client-App mit der von der Server-App gesendeten Intent umgeht und wie sie die FileDescriptor über den Inhalts-URI abrufen kann:

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();
            ...
        }
    }

Die Methode openFileDescriptor() gibt ein ParcelFileDescriptor für die Datei zurück. Von diesem Objekt erhält die Client-App ein FileDescriptor-Objekt, mit dem sie die Datei lesen kann.

Weitere Informationen finden Sie hier: