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 do arquivo e abre o arquivo usando o URI de conteúdo.
Enviar uma solicitação de arquivo
Para solicitar um arquivo 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
a um app de servidor para iniciar o Activity
descrito 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
. Esse Intent
é transmitido ao app cliente
na substituição de 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 somente enquanto você analisa corretamente o URI de conteúdo que o app cliente recebe. Ao analisar o conteúdo, é necessário garantir que esse URI não aponte para nada fora do diretório pretendido, evitando que uma travessia de caminho seja tentada. Somente o app cliente pode ter acesso ao arquivo e apenas para as permissões concedidas pelo app do servidor. As permissões são temporárias. Assim, 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: