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: