Quando um aplicativo quer acessar um arquivo compartilhado por outro aplicativo, o aplicativo solicitante (o cliente)
geralmente envia uma solicitação para o aplicativo que compartilha os arquivos (o servidor). Na maioria dos casos, a solicitação
inicia uma Activity
no app do servidor que mostra 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 de servidor, recebe o arquivo URI de conteúdo 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
oferece.
Por exemplo, o snippet de código a seguir demonstra como enviar uma
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 aplicativo do servidor envia o URI de conteúdo do arquivo de volta ao aplicativo cliente em um
Intent
: Esse Intent
é transmitido ao cliente.
na substituição de onActivityResult()
. Uma vez
o app cliente tiver o URI de conteúdo do arquivo, poderá acessar o arquivo obtendo o
FileDescriptor
:
A segurança dos arquivos é preservada nesse processo somente se você analisar corretamente o URI de conteúdo. que o app cliente recebe. Ao analisar o conteúdo, você deve garantir que esse URI não aponte para qualquer item fora do diretório pretendido, garantindo que path traversal está em processo de tentativa. Somente o aplicativo cliente deve ter acesso ao arquivo e somente pelas permissões concedidas pelo do app do servidor de aplicativos. As permissões são temporárias, portanto, assim que a pilha de tarefas do aplicativo cliente for concluída, o não pode mais ser acessado fora do app do servidor.
O próximo snippet demonstra como o aplicativo cliente lida com
Intent
enviado pelo app do servidor e como o app cliente recebe a
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 cliente
app recebe um objeto FileDescriptor
, que pode ser usado para ler o arquivo.
Para ver mais informações relacionadas, consulte: