Оптимизируйте свои подборки Сохраняйте и классифицируйте контент в соответствии со своими настройками.
Wi-Fi Direct (также известный как одноранговая сеть или P2P) позволяет вашему приложению быстро находить близлежащие устройства и взаимодействовать с ними на расстоянии, превышающем возможности Bluetooth.
API-интерфейсы Wi-Fi Direct (P2P) позволяют приложениям подключаться к близлежащим устройствам без необходимости подключения к сети или точке доступа. Если ваше приложение предназначено для работы в защищенной сети ближнего радиуса действия, Wi-Fi Direct является более подходящим вариантом, чем традиционная одноранговая сеть Wi-Fi, по следующим причинам:
В этом уроке показано, как найти устройства поблизости и подключиться к ним с помощью Wi-Fi P2P.
Чтобы использовать Wi-Fi Direct, добавьте разрешения ACCESS_FINE_LOCATION , CHANGE_WIFI_STATE , ACCESS_WIFI_STATE и INTERNET в свой манифест. Если ваше приложение предназначено для Android 13 (уровень API 33) или выше, также добавьте разрешение NEARBY_WIFI_DEVICES в свой манифест. Wi-Fi Direct не требует подключения к Интернету, но использует стандартные сокеты Java, для которых требуется разрешение INTERNET . Итак, для использования Wi-Fi Direct вам потребуются следующие разрешения:
xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.nsdchat" . If your app targets Android 13 (API level 33) or higher, you must declare the NEARBY_WIFI_DEVICES 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" /> android:required="true" 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" /> android:required="true" android:name="android.permission.ACCESS_WIFI_STATE"/> android:required="true" android:name="android.permission.CHANGE_WIFI_STATE"/> android:required="true" android:name="android.permission.INTERNET"/> .
Чтобы использовать Wi-Fi Direct, вам необходимо прослушивать широковещательные намерения, которые сообщают вашему приложению, когда произошли определенные события. В своем приложении создайте экземпляр IntentFilter и настройте его на прослушивание следующего:
WIFI_P2P_STATE_CHANGED_ACTION Указывает, включен ли Wi-Fi Direct WIFI_P2P_PEERS_CHANGED_ACTION Указывает, что список доступных одноранговых узлов изменился. WIFI_P2P_CONNECTION_CHANGED_ACTION Указывает, что состояние подключения Wi-Fi Direct изменилось. Начиная с Android 10, это не прилипает. Если ваше приложение полагалось на получение этих широковещательных рассылок при регистрации, поскольку они были закреплены, вместо этого используйте соответствующий метод get при инициализации, чтобы получить информацию. WIFI_P2P_THIS_DEVICE_CHANGED_ACTION Указывает, что сведения о конфигурации этого устройства изменились. Начиная с Android 10, это не прилипает. Если ваше приложение полагалось на получение этих широковещательных рассылок при регистрации, поскольку они были закреплены, вместо этого используйте соответствующий метод get при инициализации, чтобы получить информацию.
private val intentFilter = IntentFilter() . override fun onCreate(savedInstanceState: Bundle?) super.onCreate(savedInstanceState) setContentView(R.layout.main) // Indicates a change in the Wi-Fi Direct status. intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION) // Indicates a change in the list of available peers. intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION) // Indicates the state of Wi-Fi Direct connectivity has changed. intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION) // Indicates this device's details have changed. intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION) . >
private final IntentFilter intentFilter = new IntentFilter(); . @Override public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.main); // Indicates a change in the Wi-Fi Direct status. intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); // Indicates a change in the list of available peers. intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); // Indicates the state of Wi-Fi Direct connectivity has changed. intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); // Indicates this device's details have changed. intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); . >
В конце метода onCreate() получите экземпляр WifiP2pManager и вызовите его метод initialize() . Этот метод возвращает объект WifiP2pManager.Channel , который вы будете использовать позже для подключения вашего приложения к платформе Wi-Fi Direct.
private lateinit var channel: WifiP2pManager.Channel private lateinit var manager: WifiP2pManager override fun onCreate(savedInstanceState: Bundle?) . manager = getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager channel = manager.initialize(this, mainLooper, null) >
Channel channel; WifiP2pManager manager; @Override public void onCreate(Bundle savedInstanceState) . manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE); channel = manager.initialize(this, getMainLooper(), null); >
Теперь создайте новый класс BroadcastReceiver , который вы будете использовать для прослушивания изменений состояния Wi-Fi системы. В методе onReceive() добавьте условие для обработки каждого изменения состояния, указанного выше.
override fun onReceive(context: Context, intent: Intent) when(intent.action) WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> // Determine if Wi-Fi Direct mode is enabled or not, alert // the Activity. val state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1) activity.isWifiP2pEnabled = state == WifiP2pManager.WIFI_P2P_STATE_ENABLED > WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> // The peer list has changed! We should probably do something about // that. > WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> // Connection state changed! We should probably do something about // that. > WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION -> (activity.supportFragmentManager.findFragmentById(R.id.frag_list) as DeviceListFragment) .apply updateThisDevice( intent.getParcelableExtra( WifiP2pManager.EXTRA_WIFI_P2P_DEVICE) as WifiP2pDevice ) > > > >
@Override public void onReceive(Context context, Intent intent) String action = intent.getAction(); if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) // Determine if Wi-Fi Direct mode is enabled or not, alert // the Activity. int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1); if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) activity.setIsWifiP2pEnabled(true); > else activity.setIsWifiP2pEnabled(false); > > else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) // The peer list has changed! We should probably do something about // that. > else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) // Connection state changed! We should probably do something about // that. > else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) DeviceListFragment fragment = (DeviceListFragment) activity.getFragmentManager() .findFragmentById(R.id.frag_list); fragment.updateThisDevice((WifiP2pDevice) intent.getParcelableExtra( WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)); > >
Наконец, добавьте код для регистрации фильтра намерений и широковещательного приемника, когда ваше основное действие активно, и отменяйте их регистрацию, когда действие приостановлено. Лучшее место для этого — методы onResume() и onPause() .
/** register the BroadcastReceiver with the intent values to be matched */ public override fun onResume() super.onResume() receiver = WiFiDirectBroadcastReceiver(manager, channel, this) registerReceiver(receiver, intentFilter) > public override fun onPause() super.onPause() unregisterReceiver(receiver) >
/** register the BroadcastReceiver with the intent values to be matched */ @Override public void onResume() super.onResume(); receiver = new WiFiDirectBroadcastReceiver(manager, channel, this); registerReceiver(receiver, intentFilter); > @Override public void onPause() super.onPause(); unregisterReceiver(receiver); >
Чтобы начать поиск ближайших устройств с помощью Wi-Fi P2P, вызовите discoverPeers() . Этот метод принимает следующие аргументы:
manager.discoverPeers(channel, object : WifiP2pManager.ActionListener override fun onSuccess() // Code for when the discovery initiation is successful goes here. // No services have actually been discovered yet, so this method // can often be left blank. Code for peer discovery goes in the // onReceive method, detailed below. > override fun onFailure(reasonCode: Int) // Code for when the discovery initiation fails goes here. // Alert the user that something went wrong. > >)
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() @Override public void onSuccess() // Code for when the discovery initiation is successful goes here. // No services have actually been discovered yet, so this method // can often be left blank. Code for peer discovery goes in the // onReceive method, detailed below. > @Override public void onFailure(int reasonCode) // Code for when the discovery initiation fails goes here. // Alert the user that something went wrong. > >);
Имейте в виду, что это только инициирует обнаружение одноранговых узлов. Метод discoverPeers() запускает процесс обнаружения и затем немедленно завершает его. Система уведомляет вас, если процесс обнаружения одноранговых узлов успешно инициирован путем вызова методов в предоставленном прослушивателе действий. Кроме того, обнаружение остается активным до тех пор, пока не будет инициировано соединение или не сформирована группа P2P.
Теперь напишите код, который извлекает и обрабатывает список пиров. Сначала реализуйте интерфейс WifiP2pManager.PeerListListener , который предоставляет информацию об узлах, обнаруженных Wi-Fi Direct. Эта информация также позволяет вашему приложению определять, когда одноранговые узлы присоединяются к сети или покидают ее. Следующий фрагмент кода иллюстрирует эти операции, связанные с одноранговыми узлами:
private val peers = mutableListOf () . private val peerListListener = WifiP2pManager.PeerListListener peerList -> val refreshedPeers = peerList.deviceList if (refreshedPeers != peers) peers.clear() peers.addAll(refreshedPeers) // If an AdapterView is backed by this data, notify it // of the change. For instance, if you have a ListView of // available peers, trigger an update. (listAdapter as WiFiPeerListAdapter).notifyDataSetChanged() // Perform any other updates needed based on the new list of // peers connected to the Wi-Fi P2P network. > if (peers.isEmpty()) Log.d(TAG, "No devices found") return@PeerListListener > >
private List peers = new ArrayList (); . private PeerListListener peerListListener = new PeerListListener() @Override public void onPeersAvailable(WifiP2pDeviceList peerList) List refreshedPeers = peerList.getDeviceList(); if (!refreshedPeers.equals(peers)) peers.clear(); peers.addAll(refreshedPeers); // If an AdapterView is backed by this data, notify it // of the change. For instance, if you have a ListView of // available peers, trigger an update. ((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged(); // Perform any other updates needed based on the new list of // peers connected to the Wi-Fi P2P network. > if (peers.size() == 0) Log.d(WiFiDirectActivity.TAG, "No devices found"); return; > > >
Теперь измените метод onReceive() вашего приемника вещания, чтобы он вызывал requestPeers() при получении намерения с действием WIFI_P2P_PEERS_CHANGED_ACTION . Вам нужно как-то передать этот прослушиватель в приемник. Один из способов — отправить его в качестве аргумента конструктору приемника широковещательной передачи.
fun onReceive(context: Context, intent: Intent) when (intent.action) . WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> // Request available peers from the wifi p2p manager. This is an // asynchronous call and the calling activity is notified with a // callback on PeerListListener.onPeersAvailable() mManager?.requestPeers(channel, peerListListener) Log.d(TAG, "P2P peers changed") > . > >
public void onReceive(Context context, Intent intent) . else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) // Request available peers from the wifi p2p manager. This is an // asynchronous call and the calling activity is notified with a // callback on PeerListListener.onPeersAvailable() if (mManager != null) mManager.requestPeers(channel, peerListListener); > Log.d(WiFiDirectActivity.TAG, "P2P peers changed"); >. >
Теперь намерение с действием WIFI_P2P_PEERS_CHANGED_ACTION инициирует запрос обновленного списка пиров.
Чтобы подключиться к одноранговому узлу, создайте новый объект WifiP2pConfig и скопируйте в него данные из WifiP2pDevice представляющего устройство, к которому вы хотите подключиться. Затем вызовите метод connect() .
override fun connect() // Picking the first device found on the network. val device = peers[0] val config = WifiP2pConfig().apply deviceAddress = device.deviceAddress wps.setup = WpsInfo.PBC > manager.connect(channel, config, object : WifiP2pManager.ActionListener override fun onSuccess() // WiFiDirectBroadcastReceiver notifies us. Ignore for now. > override fun onFailure(reason: Int) Toast.makeText( this@WiFiDirectActivity, "Connect failed. Retry.", Toast.LENGTH_SHORT ).show() > >) >
@Override public void connect() // Picking the first device found on the network. WifiP2pDevice device = peers.get(0); WifiP2pConfig config = new WifiP2pConfig(); config.deviceAddress = device.deviceAddress; config.wps.setup = WpsInfo.PBC; manager.connect(channel, config, new ActionListener() @Override public void onSuccess() // WiFiDirectBroadcastReceiver notifies us. Ignore for now. > @Override public void onFailure(int reason) Toast.makeText(WiFiDirectActivity.this, "Connect failed. Retry.", Toast.LENGTH_SHORT).show(); > >); >
Если каждое из устройств в вашей группе поддерживает Wi-Fi Direct, вам не нужно явно запрашивать пароль группы при подключении. Однако, чтобы разрешить устройству, не поддерживающему Wi-Fi Direct, присоединиться к группе, вам необходимо получить этот пароль, вызвав requestGroupInfo() , как показано в следующем фрагменте кода:
manager.requestGroupInfo(channel) group -> val groupPassword = group.passphrase >
manager.requestGroupInfo(channel, new GroupInfoListener() @Override public void onGroupInfoAvailable(WifiP2pGroup group) String groupPassword = group.getPassphrase(); > >);
Обратите внимание, что WifiP2pManager.ActionListener , реализованный в методе connect() уведомляет вас только в случае успешного или неудачного запуска . Чтобы прослушивать изменения состояния соединения, реализуйте интерфейс WifiP2pManager.ConnectionInfoListener . Его обратный вызов onConnectionInfoAvailable() уведомляет вас об изменении состояния соединения. В тех случаях, когда к одному устройству будет подключено несколько устройств (например, игра с тремя или более игроками или приложение для чата), одно устройство назначается «владельцем группы». Вы можете назначить конкретное устройство владельцем группы сети, выполнив действия, описанные в разделе «Создание группы» .
private val connectionListener = WifiP2pManager.ConnectionInfoListener info -> // String from WifiP2pInfo struct val groupOwnerAddress: String = info.groupOwnerAddress.hostAddress // After the group negotiation, we can determine the group owner // (server). if (info.groupFormed && info.isGroupOwner) // Do whatever tasks are specific to the group owner. // One common case is creating a group owner thread and accepting // incoming connections. > else if (info.groupFormed) // The other device acts as the peer (client). In this case, // you'll want to create a peer thread that connects // to the group owner. > >
@Override public void onConnectionInfoAvailable(final WifiP2pInfo info) // String from WifiP2pInfo struct String groupOwnerAddress = info.groupOwnerAddress.getHostAddress(); // After the group negotiation, we can determine the group owner // (server). if (info.groupFormed && info.isGroupOwner) // Do whatever tasks are specific to the group owner. // One common case is creating a group owner thread and accepting // incoming connections. > else if (info.groupFormed) // The other device acts as the peer (client). In this case, // you'll want to create a peer thread that connects // to the group owner. > >
Теперь вернитесь к методу onReceive() приемника широковещательной передачи и измените раздел, который прослушивает намерение WIFI_P2P_CONNECTION_CHANGED_ACTION . Когда это намерение получено, вызовите requestConnectionInfo() . Это асинхронный вызов, поэтому результаты принимаются прослушивателем информации о соединении, который вы указываете в качестве параметра.
when (intent.action) . WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> // Connection state changed! We should probably do something about // that. mManager?.let manager -> val networkInfo: NetworkInfo? = intent .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO) as NetworkInfo if (networkInfo?.isConnected == true) // We are connected with the other device, request connection // info to find group owner IP manager.requestConnectionInfo(channel, connectionListener) > > > . >
. > else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) if (manager == null) return; > NetworkInfo networkInfo = (NetworkInfo) intent .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); if (networkInfo.isConnected()) // We are connected with the other device, request connection // info to find group owner IP manager.requestConnectionInfo(channel, connectionListener); > .
Если вы хотите, чтобы устройство, на котором работает ваше приложение, выступало в качестве владельца группы для сети, включающей устаревшие устройства, то есть устройства, не поддерживающие Wi-Fi Direct, выполните ту же последовательность шагов, что и в разделе «Подключение к равноправному узлу». раздел, за исключением того, что вы создаете новый WifiP2pManager.ActionListener используя createGroup() вместо connect() . Обработка обратного вызова в WifiP2pManager.ActionListener такая же, как показано в следующем фрагменте кода:
manager.createGroup(channel, object : WifiP2pManager.ActionListener override fun onSuccess() // Device is ready to accept incoming connections from peers. > override fun onFailure(reason: Int) Toast.makeText( this@WiFiDirectActivity, "P2P group creation failed. Retry.", Toast.LENGTH_SHORT ).show() > >)
manager.createGroup(channel, new WifiP2pManager.ActionListener() @Override public void onSuccess() // Device is ready to accept incoming connections from peers. > @Override public void onFailure(int reason) Toast.makeText(WiFiDirectActivity.this, "P2P group creation failed. Retry.", Toast.LENGTH_SHORT).show(); > >);
Примечание. Если все устройства в сети поддерживают Wi-Fi Direct, вы можете использовать метод connect() на каждом устройстве, поскольку этот метод затем создает группу и автоматически выбирает владельца группы.
После создания группы вы можете вызвать requestGroupInfo() , чтобы получить подробную информацию об узлах в сети, включая имена устройств и статусы подключения.
Контент и образцы кода на этой странице предоставлены по лицензиям. Java и OpenJDK – это зарегистрированные товарные знаки корпорации Oracle и ее аффилированных лиц.
Последнее обновление: 2024-09-10 UTC.