O Wi-Fi Direct (P2P) permite que dispositivos com o hardware adequado se conectem diretamente uns aos outros por Wi-Fi sem um ponto de acesso intermediário. Com essas APIs, é possível descobrir e se conectar a outros dispositivos quando cada um deles oferece suporte a P2P por Wi-Fi e, em seguida, se comunicar por uma conexão rápida em distâncias muito maiores do que uma conexão Bluetooth. Isso é útil para aplicativos que compartilham dados entre usuários, como um jogo multiplayer ou um aplicativo de compartilhamento de fotos.
As APIs Wi-Fi P2P consistem nas seguintes partes principais:
- Métodos que permitem descobrir, solicitar e se conectar a dispositivos semelhantes, que são
definidos na classe
WifiP2pManager. - Listeners que notificam você sobre o sucesso ou a falha das chamadas de método
WifiP2pManager. Ao chamar métodosWifiP2pManager, cada método pode receber um listener específico transmitido como um parâmetro. - Intents que notificam você sobre eventos específicos detectados pelo framework P2P do Wi-Fi, como uma conexão interrompida ou um par recém-descoberto.
Muitas vezes, você vai usar esses três componentes principais das APIs juntos. Por
exemplo, é possível fornecer um WifiP2pManager.ActionListener para uma chamada para
discoverPeers() para que os métodos ActionListener.onSuccess() e
ActionListener.onFailure() possam notificar você. Uma intent
WIFI_P2P_PEERS_CHANGED_ACTION também será transmitida se o método
discoverPeers() descobrir que a lista de pares foi alterada.
Visão geral da API
A classe WifiP2pManager oferece métodos para que você interaja com o
hardware de Wi-Fi no dispositivo para realizar ações como descobrir e se conectar a pares.
As seguintes ações estão disponíveis:
Tabela 1. Métodos de Wi-Fi P2P
| Método | Descrição |
initialize()
|
Registra o aplicativo no framework do Wi-Fi. Chame esse método antes de chamar qualquer outro método de Wi-Fi P2P. |
connect()
|
Inicia uma conexão ponto a ponto com um dispositivo com a configuração especificada. |
cancelConnect()
|
Cancela qualquer negociação de grupo de peering em andamento. |
requestConnectInfo()
|
Solicita as informações de conexão de um dispositivo. |
createGroup()
|
Cria um grupo de peering com o dispositivo atual como proprietário. |
removeGroup()
|
Remove o grupo de peering atual. |
requestGroupInfo()
|
Solicita informações do grupo de peering. |
discoverPeers()
|
Inicia a descoberta de semelhantes. |
requestPeers()
|
Solicita a lista atual de pares descobertos. |
Os métodos WifiP2pManager permitem
transmitir um listener para que o framework de P2P por Wi-Fi possa notificar sua atividade
sobre o status de uma chamada. As interfaces de listener disponíveis e as chamadas de método WifiP2pManager correspondentes que usam os listeners são descritas na tabela 2.
Tabela 2. Listeners de Wi-Fi P2P
| Interface do listener | Ações associadas |
WifiP2pManager.ActionListener
|
connect(), cancelConnect(),
createGroup(), removeGroup() e
discoverPeers()
|
WifiP2pManager.ChannelListener
|
initialize()
|
WifiP2pManager.ConnectionInfoListener
|
requestConnectInfo()
|
WifiP2pManager.GroupInfoListener
|
requestGroupInfo()
|
WifiP2pManager.PeerListListener
|
requestPeers()
|
As APIs Wi-Fi P2P definem intents que são transmitidas quando determinados eventos de Wi-Fi P2P acontecem, como quando um novo par é descoberto ou quando o estado de Wi-Fi de um dispositivo muda. Para receber essas intents no seu aplicativo, crie um broadcast receiver que as processe:
Tabela 3. Intents de Wi-Fi P2P
| Intent | Descrição |
WIFI_P2P_CONNECTION_CHANGED_ACTION
|
Transmissão quando o estado da conexão Wi-Fi do dispositivo muda. |
WIFI_P2P_PEERS_CHANGED_ACTION
|
Transmitir quando você chamar discoverPeers(). Normalmente, você
chama requestPeers() para receber uma lista atualizada de pares se
processar essa intent no seu aplicativo.
|
WIFI_P2P_STATE_CHANGED_ACTION
|
Transmitido quando o P2P por Wi-Fi é ativado ou desativado no dispositivo. |
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
|
Transmitido quando os detalhes de um dispositivo mudam, como o nome dele. |
Criar um broadcast receiver para intents de P2P por Wi-Fi
Um broadcast receiver permite que você receba intents transmitidas pelo sistema Android, para que seu aplicativo possa responder a eventos de seu interesse. As etapas básicas para criar um broadcast receiver que processe intents de Wi-Fi P2P são as seguintes:
Crie uma classe que estenda a classe
BroadcastReceiver. Para o construtor da classe, você vai usar parâmetros para oWifiP2pManager,WifiP2pManager.Channele a atividade em que esse broadcast receiver será registrado. Isso permite que o broadcast receiver envie atualizações para a atividade, além de ter acesso ao hardware de Wi-Fi e a um canal de comunicação, se necessário.No broadcast receiver, verifique as intents de seu interesse no método
onReceive(). Realize as ações necessárias dependendo da intent recebida. Por exemplo, se o broadcast receiver receber uma intentWIFI_P2P_PEERS_CHANGED_ACTION, você poderá chamar o métodorequestPeers()para receber uma lista dos pares descobertos no momento.
O código a seguir mostra como criar um broadcast receiver típico. O
broadcast receiver usa um objeto WifiP2pManager e uma atividade como argumentos
e usa essas duas classes para realizar as ações necessárias quando
o broadcast receiver recebe uma intent:
Kotlin
/**
* A BroadcastReceiver that notifies of important Wi-Fi P2P events.
*/
class WiFiDirectBroadcastReceiver(
private val manager: WifiP2pManager,
private val channel: WifiP2pManager.Channel,
private val activity: MyWifiActivity
) : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action: String = intent.action
when (action) {
WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> {
// Check to see if Wi-Fi is enabled and notify appropriate activity
}
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> {
// Call WifiP2pManager.requestPeers() to get a list of current peers
}
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> {
// Respond to new connection or disconnections
}
WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION -> {
// Respond to this device's Wi-Fi state changing
}
}
}
}
Java
/**
* A BroadcastReceiver that notifies of important Wi-Fi P2P events.
*/
public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {
private WifiP2pManager manager;
private Channel channel;
private MyWiFiActivity activity;
public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel,
MyWifiActivity activity) {
super();
this.manager = manager;
this.channel = channel;
this.activity = activity;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
// Check to see if Wi-Fi is enabled and notify appropriate activity
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// Call WifiP2pManager.requestPeers() to get a list of current peers
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
// Respond to new connection or disconnections
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
// Respond to this device's Wi-Fi state changing
}
}
}
Em dispositivos com o Android 10 e versões mais recentes, as seguintes intents de transmissão não são fixas:
WIFI_P2P_CONNECTION_CHANGED_ACTION- Os aplicativos podem usar
requestConnectionInfo(),requestNetworkInfo()ourequestGroupInfo()para recuperar as informações de conexão atuais. WIFI_P2P_THIS_DEVICE_CHANGED_ACTION- Os aplicativos podem usar
requestDeviceInfo()para recuperar as informações de conexão atuais.
Criar um aplicativo P2P de Wi-Fi
Para criar um aplicativo de Wi-Fi P2P, é preciso criar e registrar um broadcast receiver para o aplicativo, descobrir e se conectar a um par e transferir dados para ele. As seções a seguir descrevem como fazer isso.
Configuração inicial
Antes de usar as APIs Wi-Fi P2P, verifique se o aplicativo pode
acessar o hardware e se o dispositivo é compatível com o protocolo Wi-Fi P2P. Se
o Wi-Fi P2P for compatível, você poderá receber uma instância de WifiP2pManager, criar
e registrar seu broadcast receiver e começar a usar as APIs Wi-Fi P2P.
Solicite permissão para usar o hardware de Wi-Fi no dispositivo e declare que seu aplicativo tem a versão mínima correta do SDK no manifesto do Android:
<uses-sdk android:minSdkVersion="14" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- If your app targets Android 13 (API level 33) or higher, you must declare the NEARBY_WIFI_DEVICES permission. --> <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" <!-- If your app derives location information from Wi-Fi APIs, don't include the "usesPermissionFlags" attribute. --> android:usesPermissionFlags="neverForLocation" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" <!-- If any feature in your app relies on precise location information, don't include the "maxSdkVersion" attribute. --> android:maxSdkVersion="32" />Além das permissões anteriores, as APIs a seguir também exigem que o Modo de Localização esteja ativado:
Verifique se o Wi-Fi P2P está ativado e é compatível. Um bom lugar para verificar isso é no broadcast receiver quando ele recebe a intent
WIFI_P2P_STATE_CHANGED_ACTION. Notifique sua atividade sobre o estado do Wi-Fi P2P e reaja de acordo:Kotlin
override fun onReceive(context: Context, intent: Intent) { ... val action: String = intent.action when (action) { WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> { val state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1) when (state) { WifiP2pManager.WIFI_P2P_STATE_ENABLED -> { // Wi-Fi P2P is enabled } else -> { // Wi-Fi P2P is not enabled } } } } ... }Java
@Override public void onReceive(Context context, Intent intent) { ... String action = intent.getAction(); if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) { int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1); if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) { // Wi-Fi P2P is enabled } else { // Wi-Fi P2P is not enabled } } ... }No método
onCreate()da sua atividade, consiga uma instância deWifiP2pManagere registre o aplicativo no framework de Wi-Fi P2P chamandoinitialize(). Esse método retorna umWifiP2pManager.Channel, que é usado para conectar o aplicativo ao framework de Wi-Fi P2P. Você também precisa criar uma instância do broadcast receiver com os objetosWifiP2pManagereWifiP2pManager.Channel, além de uma referência à sua atividade. Essa configuração permite que o broadcast receiver notifique sua atividade sobre eventos interessantes e a atualize de acordo. Ele também permite manipular o estado do Wi-Fi do dispositivo, se necessário:Kotlin
val manager: WifiP2pManager? by lazy(LazyThreadSafetyMode.NONE) { getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager? } var channel: WifiP2pManager.Channel? = null var receiver: BroadcastReceiver? = null override fun onCreate(savedInstanceState: Bundle?) { ... channel = manager?.initialize(this, mainLooper, null) channel?.also { channel -> receiver = WiFiDirectBroadcastReceiver(manager, channel, this) } }Java
WifiP2pManager manager; Channel channel; BroadcastReceiver receiver; ... @Override protected void onCreate(Bundle savedInstanceState){ ... manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE); channel = manager.initialize(this, getMainLooper(), null); receiver = new WiFiDirectBroadcastReceiver(manager, channel, this); ... }Crie um filtro de intent e adicione as mesmas intents que o broadcast receiver verifica:
Kotlin
val intentFilter = IntentFilter().apply { addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION) addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION) addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION) addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION) }Java
IntentFilter intentFilter; ... @Override protected void onCreate(Bundle savedInstanceState){ ... intentFilter = new IntentFilter(); intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); ... }Registre o broadcast receiver no método
onResume()da atividade e cancele o registro no métodoonPause():Kotlin
/* register the broadcast receiver with the intent values to be matched */ override fun onResume() { super.onResume() receiver?.also { receiver -> registerReceiver(receiver, intentFilter) } } /* unregister the broadcast receiver */ override fun onPause() { super.onPause() receiver?.also { receiver -> unregisterReceiver(receiver) } }Java
/* register the broadcast receiver with the intent values to be matched */ @Override protected void onResume() { super.onResume(); registerReceiver(receiver, intentFilter); } /* unregister the broadcast receiver */ @Override protected void onPause() { super.onPause(); unregisterReceiver(receiver); }Depois de receber um
WifiP2pManager.Channele configurar um broadcast receiver, seu aplicativo poderá fazer chamadas de método de Wi-Fi P2P e receber intents de Wi-Fi P2P.Implemente o aplicativo usando os recursos de Wi-Fi P2P chamando os métodos em
WifiP2pManager.
As próximas seções descrevem como realizar ações comuns, como descobrir e se conectar a dispositivos semelhantes.
Descobrir semelhantes
Chame discoverPeers() para detectar os dispositivos disponíveis que estão ao alcance e disponíveis
para conexão. A chamada para essa função é assíncrona, e o sucesso ou a falha é comunicado ao aplicativo com onSuccess() e onFailure() se você tiver criado um WifiP2pManager.ActionListener. O método onSuccess() apenas
notifica que o processo de descoberta foi bem-sucedido e não fornece nenhuma
informação sobre os pares reais que ele descobriu, se houver. O exemplo de código a seguir mostra como configurar isso.
Kotlin
manager?.discoverPeers(channel, object : WifiP2pManager.ActionListener {
override fun onSuccess() {
...
}
override fun onFailure(reasonCode: Int) {
...
}
})
Java
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
...
}
@Override
public void onFailure(int reasonCode) {
...
}
});
Se o processo de descoberta for bem-sucedido e detectar pares, o sistema vai transmitir a
intent WIFI_P2P_PEERS_CHANGED_ACTION, que pode ser detectada em um broadcast
receiver para receber uma lista de pares. Quando o aplicativo recebe a intent
WIFI_P2P_PEERS_CHANGED_ACTION, é possível solicitar uma lista dos pares descobertos
com requestPeers(). O código a seguir mostra como fazer isso.
Kotlin
override fun onReceive(context: Context, intent: Intent) {
val action: String = intent.action
when (action) {
...
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> {
manager?.requestPeers(channel) { peers: WifiP2pDeviceList? ->
// Handle peers list
}
}
...
}
}
Java
PeerListListener myPeerListListener;
...
if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// request available peers from the Wi-Fi P2P manager. This is an
// asynchronous call and the calling activity is notified with a
// callback on PeerListListener.onPeersAvailable()
if (manager != null) {
manager.requestPeers(channel, myPeerListListener);
}
}
O método requestPeers() também é assíncrono e pode notificar sua atividade
quando uma lista de dispositivos semelhantes estiver disponível com onPeersAvailable(), que é definido
na interface WifiP2pManager.PeerListListener. O método onPeersAvailable()
fornece um WifiP2pDeviceList, que pode ser iterado
para encontrar o par ao qual se conectar.
Conectar-se a apps semelhantes
Depois de receber uma lista de possíveis pares e selecionar um dispositivo para se conectar, chame o método connect() para se conectar ao dispositivo. Essa chamada de método
requer um objeto WifiP2pConfig que contém informações sobre o dispositivo
ao qual se conectar. O WifiP2pManager.ActionListener pode notificar você sobre o sucesso ou a falha de uma conexão. O código a seguir mostra como criar uma conexão com um
dispositivo.
Kotlin
val device: WifiP2pDevice = ...
val config = WifiP2pConfig()
config.deviceAddress = device.deviceAddress
channel?.also { channel ->
manager?.connect(channel, config, object : WifiP2pManager.ActionListener {
override fun onSuccess() {
//success logic
}
override fun onFailure(reason: Int) {
//failure logic
}
}
)}
Java
//obtain a peer from the WifiP2pDeviceList
WifiP2pDevice device;
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
manager.connect(channel, config, new ActionListener() {
@Override
public void onSuccess() {
//success logic
}
@Override
public void onFailure(int reason) {
//failure logic
}
});
Transferir dados
Depois que uma conexão é estabelecida, é possível transferir dados entre os dispositivos com soquetes. As etapas básicas para transferir dados são as seguintes:
- Crie um
ServerSocket. Esse soquete aguarda uma conexão de um cliente em uma porta especificada e bloqueia até que isso aconteça. Portanto, faça isso em uma linha de execução em segundo plano. - Crie um cliente
Socket. O cliente usa o endereço IP e a porta do soquete de servidor para se conectar ao dispositivo do servidor. - Envie dados do cliente para o servidor. Quando o socket de cliente se conecta ao soquete de servidor, é possível enviar dados do cliente para o servidor com streams de bytes.
- O soquete de servidor aguarda uma conexão de cliente (com o método
accept()). Essa chamada é bloqueada até que um cliente se conecte. Portanto, chame-a em outra linha de execução. Quando uma conexão é estabelecida, o dispositivo do servidor pode receber os dados do cliente.
O exemplo a seguir, modificado da demonstração de Wi-Fi P2P, mostra como criar essa comunicação de soquete cliente-servidor e transferir imagens JPEG de um cliente para um servidor com um serviço. Para um exemplo completo, compile e execute a demonstração.
Kotlin
class FileServerAsyncTask(
private val context: Context,
private var statusText: TextView
) : AsyncTask<Void, Void, String?>() {
override fun doInBackground(vararg params: Void): String? {
/**
* Create a server socket.
*/
val serverSocket = ServerSocket(8888)
return serverSocket.use {
/**
* Wait for client connections. This call blocks until a
* connection is accepted from a client.
*/
val client = serverSocket.accept()
/**
* If this code is reached, a client has connected and transferred data
* Save the input stream from the client as a JPEG file
*/
val f = File(Environment.getExternalStorageDirectory().absolutePath +
"/${context.packageName}/wifip2pshared-${System.currentTimeMillis()}.jpg")
val dirs = File(f.parent)
dirs.takeIf { it.doesNotExist() }?.apply {
mkdirs()
}
f.createNewFile()
val inputstream = client.getInputStream()
copyFile(inputstream, FileOutputStream(f))
serverSocket.close()
f.absolutePath
}
}
private fun File.doesNotExist(): Boolean = !exists()
/**
* Start activity that can handle the JPEG image
*/
override fun onPostExecute(result: String?) {
result?.run {
statusText.text = "File copied - $result"
val intent = Intent(android.content.Intent.ACTION_VIEW).apply {
setDataAndType(Uri.parse("file://$result"), "image/*")
}
context.startActivity(intent)
}
}
}
Java
public static class FileServerAsyncTask extends AsyncTask {
private Context context;
private TextView statusText;
public FileServerAsyncTask(Context context, View statusText) {
this.context = context;
this.statusText = (TextView) statusText;
}
@Override
protected String doInBackground(Void... params) {
try {
/**
* Create a server socket and wait for client connections. This
* call blocks until a connection is accepted from a client
*/
ServerSocket serverSocket = new ServerSocket(8888);
Socket client = serverSocket.accept();
/**
* If this code is reached, a client has connected and transferred data
* Save the input stream from the client as a JPEG file
*/
final File f = new File(Environment.getExternalStorageDirectory() + "/"
+ context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis()
+ ".jpg");
File dirs = new File(f.getParent());
if (!dirs.exists())
dirs.mkdirs();
f.createNewFile();
InputStream inputstream = client.getInputStream();
copyFile(inputstream, new FileOutputStream(f));
serverSocket.close();
return f.getAbsolutePath();
} catch (IOException e) {
Log.e(WiFiDirectActivity.TAG, e.getMessage());
return null;
}
}
/**
* Start activity that can handle the JPEG image
*/
@Override
protected void onPostExecute(String result) {
if (result != null) {
statusText.setText("File copied - " + result);
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + result), "image/*");
context.startActivity(intent);
}
}
}
No cliente, conecte-se ao soquete de servidor com um socket de cliente e transfira dados. Este exemplo transfere um arquivo JPEG no sistema de arquivos do dispositivo cliente.
Kotlin
val context = applicationContext
val host: String
val port: Int
val len: Int
val socket = Socket()
val buf = ByteArray(1024)
...
try {
/**
* Create a client socket with the host,
* port, and timeout information.
*/
socket.bind(null)
socket.connect((InetSocketAddress(host, port)), 500)
/**
* Create a byte stream from a JPEG file and pipe it to the output stream
* of the socket. This data is retrieved by the server device.
*/
val outputStream = socket.getOutputStream()
val cr = context.contentResolver
val inputStream: InputStream = cr.openInputStream(Uri.parse("path/to/picture.jpg"))
while (inputStream.read(buf).also { len = it } != -1) {
outputStream.write(buf, 0, len)
}
outputStream.close()
inputStream.close()
} catch (e: FileNotFoundException) {
//catch logic
} catch (e: IOException) {
//catch logic
} finally {
/**
* Clean up any open sockets when done
* transferring or if an exception occurred.
*/
socket.takeIf { it.isConnected }?.apply {
close()
}
}
Java
Context context = this.getApplicationContext();
String host;
int port;
int len;
Socket socket = new Socket();
byte buf[] = new byte[1024];
...
try {
/**
* Create a client socket with the host,
* port, and timeout information.
*/
socket.bind(null);
socket.connect((new InetSocketAddress(host, port)), 500);
/**
* Create a byte stream from a JPEG file and pipe it to the output stream
* of the socket. This data is retrieved by the server device.
*/
OutputStream outputStream = socket.getOutputStream();
ContentResolver cr = context.getContentResolver();
InputStream inputStream = null;
inputStream = cr.openInputStream(Uri.parse("path/to/picture.jpg"));
while ((len = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, len);
}
outputStream.close();
inputStream.close();
} catch (FileNotFoundException e) {
//catch logic
} catch (IOException e) {
//catch logic
}
/**
* Clean up any open sockets when done
* transferring or if an exception occurred.
*/
finally {
if (socket != null) {
if (socket.isConnected()) {
try {
socket.close();
} catch (IOException e) {
//catch logic
}
}
}
}