Quando um app quer acessar um arquivo compartilhado por outro app, o app solicitante (o cliente)
geralmente envia uma solicitação ao 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 pode ser compartilhado.
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, por exemplo,
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 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
FileDescriptor
.
A segurança do arquivo é preservada nesse processo, porque o URI de conteúdo é a única parte de dados 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. Somente o app cliente tem 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 o Intent
enviado pelo 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: