Quando um app quer acessar um arquivo compartilhado por outro, o app solicitante (o cliente) geralmente envia uma solicitação para o app que compartilha os arquivos (o servidor). Na maioria dos casos, a solicitação inicia uma Activity
no app do servidor que exibe os arquivos que ele pode compartilhar.
O usuário escolhe um arquivo, e o app do servidor retorna o URI de conteúdo do arquivo para o app cliente.
Esta lição mostra como um app cliente solicita um arquivo de um app do servidor, recebe o URI de conteúdo e abre o arquivo.
Enviar uma solicitação de arquivo
Para solicitar um arquivo a partir do app do servidor, o app cliente chama startActivityForResult
com um Intent
que contém a ação, por exemplo, ACTION_PICK
e um tipo MIME que o app cliente pode gerenciar.
Por exemplo, o snippet de código a seguir demonstra como enviar um Intent
para um app de servidor, a fim de iniciar a Activity
descrita em Como compartilhar um arquivo:
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); ... } ... }
Acessar o arquivo solicitado
O app do servidor envia o URI de conteúdo do arquivo de volta ao app cliente em uma Intent
. Essa Intent
é transmitida ao app cliente em substituição a onActivityResult()
. Depois que o app cliente tem o URI de conteúdo do arquivo, ele pode acessar o arquivo, recebendo o FileDescriptor
.
A segurança do arquivo é preservada nesse processo, porque o URI de conteúdo é a única informação que o app cliente recebe. Como esse URI não contém um caminho de diretório, o app cliente não pode descobrir e abrir outros arquivos no app do servidor. Apenas o app cliente tem acesso ao arquivo e apenas de acordo com as permissões concedidas pelo app do servidor. As permissões são temporárias, ou seja, quando a pilha de tarefas do app cliente for concluída, o arquivo não estará mais acessível fora do app do servidor.
O próximo snippet demonstra como o app cliente gerencia a Intent
enviada a partir do app de servidor e como o app cliente recebe o FileDescriptor
usando o URI de conteúdo.
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(); ... } }
O método openFileDescriptor()
retorna um ParcelFileDescriptor
para o arquivo. A partir desse objeto, o app cliente recebe um objeto FileDescriptor
, que pode ser usado para ler o arquivo.
Para ver mais informações relacionadas, consulte: