Esta lição mostra como projetar seu app para enviar arquivos grandes para outro dispositivo usando a transferência de arquivos do "Android Beam". Para enviar arquivos, você solicita permissão para usar NFC e armazenamento externo, testa para garantir que seu dispositivo é compatível com NFC e fornece URIs para a transferência de arquivos do "Android Beam".
O recurso de transferência de arquivos do "Android Beam" tem os seguintes requisitos:
- A transferência de arquivos grandes do "Android Beam" está disponível apenas no Android 4.1 (API de nível 16) e versões mais recentes.
- Os arquivos que você quer transferir precisam residir no armazenamento externo. Para saber mais sobre o uso do armazenamento externo, leia Como usar o armazenamento externo.
-
Cada arquivo que você quer transferir precisa ser legível para todos. Você pode definir essa permissão chamando o método
File.setReadable(true,false)
. -
Você precisa fornecer um URI de arquivo para os arquivos que quer transferir. A transferência de arquivos do "Android Beam" não consegue processar URIs de conteúdo gerados por
FileProvider.getUriForFile
.
Declarar recursos no manifesto
Primeiro, edite o manifesto do aplicativo para declarar as permissões e os recursos necessários.
Solicitar permissões
Para permitir que seu app use a transferência de arquivos do "Android Beam" para enviar arquivos de armazenamento externo usando NFC, você precisa solicitar as seguintes permissões no manifesto do aplicativo:
-
NFC
- Permite que seu app envie dados por NFC. Para especificar essa permissão, adicione o seguinte elemento como filho do elemento
<manifest>
:<uses-permission android:name="android.permission.NFC" />
-
READ_EXTERNAL_STORAGE
-
Permite que seu app leia a partir do armazenamento externo. Para especificar essa permissão, adicione o seguinte elemento como um filho do elemento
<manifest>
:<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Observação: a partir do Android 4.2.2 (API de nível 17), essa permissão não é aplicada. Versões futuras da plataforma podem exigi-la para apps que querem ler a partir do armazenamento externo. Para garantir a compatibilidade direta, solicite a permissão agora, antes que ela se torne obrigatória.
Especificar o recurso NFC
Especifique que seu app usa NFC adicionando um elemento <uses-feature>
como filho do elemento <manifest>
. Defina o atributo android:required
como true
para indicar que seu app só funcionará se houver NFC presente.
O snippet a seguir mostra como especificar o elemento <uses-feature>
:
<uses-feature android:name="android.hardware.nfc" android:required="true" />
Observe que se seu app usar NFC apenas como uma opção, mas ainda funcionar se esse recurso não estiver presente, você precisa definir android:required
como false
e testar a NFC no código.
Especificar a transferência de arquivos do "Android Beam"
Como a transferência de arquivos do "Android Beam" está disponível apenas no Android 4.1 (API de nível 16) e versões mais recentes, se seu app depender da transferência de arquivos do "Android Beam" para uma parte essencial da funcionalidade, você precisará especificar o elemento <uses-sdk>
com o atributo android:minSdkVersion="16"
. Caso contrário, você pode definir android:minSdkVersion
como outro valor, conforme necessário, e testar a versão da plataforma no código, conforme descrito na seção a seguir.
Testar suporte de transferência de arquivos do "Android Beam"
Para especificar no manifesto do aplicativo que a NFC é opcional, use o seguinte elemento:
<uses-feature android:name="android.hardware.nfc" android:required="false" />
Se você definir o atributo android:required="false"
, precisará testar a compatibilidade com NFC e com a transferência de arquivos do "Android Beam" no código.
Para testar a compatibilidade com a transferência de arquivos do "Android Beam" no código, comece testando se o dispositivo é compatível com NFC chamando PackageManager.hasSystemFeature()
com o argumento FEATURE_NFC
. Em seguida, verifique se a versão do Android é compatível com a transferência de arquivos do Android Beam testando o valor de SDK_INT
. Se a transferência de arquivos do Android Beam for compatível, acesse uma instância do controlador de NFC, que permite a comunicação com o hardware NFC.
Exemplo:
Kotlin
class MainActivity : Activity() { ... private lateinit var nfcAdapter: NfcAdapter // Flag to indicate that Android Beam is available private var androidBeamAvailable = false ... override fun onCreate(savedInstanceState: Bundle?) { ... androidBeamAvailable = if (!packageManager.hasSystemFeature(PackageManager.FEATURE_NFC)) { // NFC isn't available on the device /* * Disable NFC features here. * For example, disable menu items or buttons that activate * NFC-related features */ false // Android Beam file transfer isn't supported } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { // If Android Beam isn't available, don't continue. androidBeamAvailable = false /* * Disable Android Beam file transfer features here. */ ... false } else { // Android Beam file transfer is available, continue nfcAdapter = NfcAdapter.getDefaultAdapter(this) ... true } } ... }
Java
public class MainActivity extends Activity { ... NfcAdapter nfcAdapter; // Flag to indicate that Android Beam is available boolean androidBeamAvailable = false; ... @Override protected void onCreate(Bundle savedInstanceState) { ... // NFC isn't available on the device if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) { /* * Disable NFC features here. * For example, disable menu items or buttons that activate * NFC-related features */ ... // Android Beam file transfer isn't supported } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { // If Android Beam isn't available, don't continue. androidBeamAvailable = false; /* * Disable Android Beam file transfer features here. */ ... // Android Beam file transfer is available, continue } else { androidBeamAvailable = true; nfcAdapter = NfcAdapter.getDefaultAdapter(this); ... } } ... }
Criar um método de callback que fornece arquivos
Depois de verificar se o dispositivo é compatível com a transferência de arquivos do "Android Beam", adicione um método de callback que o sistema invoque quando a transferência de arquivos do "Android Beam" detectar que o usuário quer enviar arquivos para outro dispositivo compatível com NFC. Nesse método de callback, retorne uma matriz de objetos Uri
. A transferência de arquivos do "Android Beam" copia os arquivos representados por esses URIs para o dispositivo receptor.
Para adicionar o método de callback, implemente a interface NfcAdapter.CreateBeamUrisCallback
e o método de callback createBeamUris()
. O snippet a seguir mostra como fazer isso:
Kotlin
public class MainActivity : Activity() { ... // List of URIs to provide to Android Beam private val fileUris = mutableListOf<Uri>() ... /** * Callback that Android Beam file transfer calls to get * files to share */ private inner class FileUriCallback : NfcAdapter.CreateBeamUrisCallback { /** * Create content URIs as needed to share with another device */ override fun createBeamUris(event: NfcEvent): Array<Uri> { return fileUris.toTypedArray() } } ... }
Java
public class MainActivity extends Activity { ... // List of URIs to provide to Android Beam private Uri[] fileUris = new Uri[10]; ... /** * Callback that Android Beam file transfer calls to get * files to share */ private class FileUriCallback implements NfcAdapter.CreateBeamUrisCallback { public FileUriCallback() { } /** * Create content URIs as needed to share with another device */ @Override public Uri[] createBeamUris(NfcEvent event) { return fileUris; } } ... }
Depois de implementar a interface, forneça o callback para a transferência de arquivos do "Android Beam" chamando setBeamPushUrisCallback()
. O snippet a seguir mostra como fazer isso:
Kotlin
class MainActivity : Activity() { ... private lateinit var nfcAdapter: NfcAdapter // Flag to indicate that Android Beam is available private var androidBeamAvailable = false ... override fun onCreate(savedInstanceState: Bundle?) { ... // Android Beam file transfer is available, continue nfcAdapter = NfcAdapter.getDefaultAdapter(this).apply { /* * Instantiate a new FileUriCallback to handle requests for * URIs */ fileUriCallback = FileUriCallback() // Set the dynamic callback for URI requests. nfcAdapter.setBeamPushUrisCallback(fileUriCallback, this@MainActivity) } ... } ... }
Java
public class MainActivity extends Activity { ... // Instance that returns available files from this app private FileUriCallback fileUriCallback; ... @Override protected void onCreate(Bundle savedInstanceState) { ... // Android Beam file transfer is available, continue ... nfcAdapter = NfcAdapter.getDefaultAdapter(this); /* * Instantiate a new FileUriCallback to handle requests for * URIs */ fileUriCallback = new FileUriCallback(); // Set the dynamic callback for URI requests. nfcAdapter.setBeamPushUrisCallback(fileUriCallback,this); ... } ... }
Observação: você também pode fornecer a matriz de objetos Uri
diretamente para o framework de NFC por meio da instância NfcAdapter
do seu app. Escolha essa abordagem se você puder definir os URIs a serem transferidos antes que o evento de toque de NFC ocorra.
Para saber mais sobre essa abordagem, consulte NfcAdapter.setBeamPushUris()
.
Especificar os arquivos a serem enviados
Para transferir um ou mais arquivos para outro dispositivo compatível com NFC, consiga um URI de arquivo (um URI com um esquema file
) para cada arquivo e adicione o URI a uma matriz de objetos Uri
. Para transferir um arquivo, você também precisa ter acesso de leitura permanente ao arquivo. Por exemplo, o snippet a seguir mostra como conseguir um URI de arquivo a partir de um nome de arquivo e, em seguida, adicionar o URI à matriz:
Kotlin
/* * Create a list of URIs, get a File, * and set its permissions */ val fileUris = mutableListOf<Uri>() val transferFile = "transferimage.jpg" val extDir = getExternalFilesDir(null) val requestFile = File(extDir, transferFile).apply { setReadable(true, false) } // Get a URI for the File and add it to the list of URIs Uri.fromFile(requestFile)?.also { fileUri -> fileUris += fileUri } ?: Log.e("My Activity", "No File URI available for file.")
Java
/* * Create a list of URIs, get a File, * and set its permissions */ private Uri[] fileUris = new Uri[10]; String transferFile = "transferimage.jpg"; File extDir = getExternalFilesDir(null); File requestFile = new File(extDir, transferFile); requestFile.setReadable(true, false); // Get a URI for the File and add it to the list of URIs fileUri = Uri.fromFile(requestFile); if (fileUri != null) { fileUris[0] = fileUri; } else { Log.e("My Activity", "No File URI available for file."); }
Para mais informações relacionadas, consulte Opções de armazenamento
Para ver um código de amostra relacionado a esta página, consulte a Amostra Android BeamLargeFiles (link em inglês)