Quando um app quer acessar um arquivo compartilhado por outro app, 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 um Activity
no app do servidor que exibe os arquivos que ele pode compartilhar.
O usuário escolhe um arquivo. Depois, 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 do app do servidor 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
contendo a ação, como
ACTION_PICK
, e um tipo MIME que o app cliente
pode processar.
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 um
Intent
. Esse Intent
é transmitido para o 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 de arquivos é preservada nesse processo apenas quando você analisa corretamente o URI de conteúdo recebido pelo app cliente. Ao analisar conteúdo, você precisa garantir que esse URI não aponte para nada fora do diretório pretendido, garantindo que nenhuma travessia de caminho esteja sendo tentada. Somente o app cliente terá acesso ao arquivo e somente para as permissões concedidas pelo app do servidor. As permissões são temporárias. Portanto, quando a pilha de tarefas do app cliente for concluída, o arquivo não poderá mais ser acessado fora do app do servidor.
O próximo snippet demonstra como o app cliente processa a Intent
enviada do app do 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: