이 클래스의 첫 번째 강의인 네트워크 서비스 사용 탐색: 로컬 네트워크에 연결된 서비스를 검색하는 방법 그러나 Wi-Fi Direct (P2P) 서비스 검색을 사용하면 근처 기기의 서비스를 검색할 수 있습니다. 네트워크 연결 없이 직접 통신할 수 있습니다 서비스를 광고할 수도 있습니다. 실행할 수 있습니다 이러한 기능은 앱 간의 커뮤니케이션에 도움이 되며, 로컬 네트워크나 핫스팟을 사용할 수 없는 경우에도 작동합니다
이 API 집합의 용도는 네트워크 서비스 검색(Network Service Discovery)과 유사하지만 API는 이전 과정에서 설명한 것처럼 코드로 구현하는 것은 매우 다릅니다. 이 강의에서는 다른 기기에서 사용할 수 있는 서비스를 검색하는 방법을 보여줍니다. Wi-Fi Direct를 사용. 이 강의에서는 Google Kubernetes Engine에만 Wi-Fi Direct API.
매니페스트 설정
Wi-Fi P2P를 사용하려면 CHANGE_WIFI_STATE
, ACCESS_WIFI_STATE
,
ACCESS_FINE_LOCATION
,
및 INTERNET
권한을 부여할 수 있습니다 앱이 Android 13 (API 수준 33) 이상을 타겟팅하는 경우
NEARBY_WIFI_DEVICES
,
권한을 부여할 수 있습니다. Wi-Fi Direct는
인터넷 연결, 표준 자바 소켓을 사용하며 Android에서 이를 사용합니다.
에는 요청된 권한이 필요합니다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.nsdchat" ... <uses-permission android:required="true" android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:required="true" android:name="android.permission.CHANGE_WIFI_STATE"/> <uses-permission android:required="true" android:name="android.permission.INTERNET"/> <!-- 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: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" /> ...
위의 권한 외에도 다음 API가 위치 모드 활성화를 요구합니다.
로컬 서비스 추가
지역 서비스를 제공하는 경우 사용할 수 있습니다 로컬 서비스가 등록되면 프레임워크는 피어의 서비스 검색 요청에 자동으로 응답합니다
로컬 서비스를 만들려면 다음 단계를 따르세요.
- 만들기
WifiP2pServiceInfo
객체. - 서비스에 관한 정보로 객체를 채웁니다.
addLocalService()
를 호출하여 로컬 등록 사용할 수 있습니다
Kotlin
private fun startRegistration() { // Create a string map containing information about your service. val record: Map<String, String> = mapOf( "listenport" to SERVER_PORT.toString(), "buddyname" to "John Doe${(Math.random() * 1000).toInt()}", "available" to "visible" ) // Service information. Pass it an instance name, service type // _protocol._transportlayer , and the map containing // information other devices will want once they connect to this one. val serviceInfo = WifiP2pDnsSdServiceInfo.newInstance("_test", "_presence._tcp", record) // Add the local service, sending the service info, network channel, // and listener that will be used to indicate success or failure of // the request. manager.addLocalService(channel, serviceInfo, object : WifiP2pManager.ActionListener { override fun onSuccess() { // Command successful! Code isn't necessarily needed here, // Unless you want to update the UI or add logging statements. } override fun onFailure(arg0: Int) { // Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY } }) }
자바
private void startRegistration() { // Create a string map containing information about your service. Map record = new HashMap(); record.put("listenport", String.valueOf(SERVER_PORT)); record.put("buddyname", "John Doe" + (int) (Math.random() * 1000)); record.put("available", "visible"); // Service information. Pass it an instance name, service type // _protocol._transportlayer , and the map containing // information other devices will want once they connect to this one. WifiP2pDnsSdServiceInfo serviceInfo = WifiP2pDnsSdServiceInfo.newInstance("_test", "_presence._tcp", record); // Add the local service, sending the service info, network channel, // and listener that will be used to indicate success or failure of // the request. manager.addLocalService(channel, serviceInfo, new ActionListener() { @Override public void onSuccess() { // Command successful! Code isn't necessarily needed here, // Unless you want to update the UI or add logging statements. } @Override public void onFailure(int arg0) { // Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY } }); }
주변 서비스 찾기
Android는 콜백 메서드를 사용하여 애플리케이션에 이용 가능한 서비스를 알리므로
가장 먼저 해야 할 일은 이를 설정하는 것입니다. 수신 대기할 WifiP2pManager.DnsSdTxtRecordListener
만들기
있습니다. 이 레코드는 원하는 경우 다른 사람이
기기에서 사용할 수 있습니다. 기기가 들어오면 기기 주소와 다른 주소 복사
현재 외부의 데이터 구조에 원하는 관련 정보를
나중에 액세스할 수 있습니다. 다음 예에서는
레코드에 'buddyname'이 포함되어 있음 필드가 사용자 ID로 채워져 있습니다.
Kotlin
private val buddies = mutableMapOf<String, String>() ... private fun discoverService() { /* Callback includes: * fullDomain: full domain name: e.g. "printer._ipp._tcp.local." * record: TXT record dta as a map of key/value pairs. * device: The device running the advertised service. */ val txtListener = DnsSdTxtRecordListener { fullDomain, record, device -> Log.d(TAG, "DnsSdTxtRecord available -$record") record["buddyname"]?.also { buddies[device.deviceAddress] = it } } }
자바
final HashMap<String, String> buddies = new HashMap<String, String>(); ... private void discoverService() { DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() { @Override /* Callback includes: * fullDomain: full domain name: e.g. "printer._ipp._tcp.local." * record: TXT record dta as a map of key/value pairs. * device: The device running the advertised service. */ public void onDnsSdTxtRecordAvailable( String fullDomain, Map record, WifiP2pDevice device) { Log.d(TAG, "DnsSdTxtRecord available -" + record.toString()); buddies.put(device.deviceAddress, record.get("buddyname")); } }; }
서비스 정보를 가져오려면 WifiP2pManager.DnsSdServiceResponseListener
를 만듭니다. 이
실제 설명과 연결 정보를 수신합니다. 이전 코드
스니펫은 기기 주소를 버디와 페어링하는 Map
객체를 구현했습니다.
있습니다. 서비스 응답 리스너는 이를 사용하여 DNS 레코드를
서비스 정보를 제공합니다 둘 다
리스너가 구현되면 setDnsSdResponseListeners()
메서드를 사용하여 WifiP2pManager
에 리스너를 추가합니다.
Kotlin
private fun discoverService() { ... val servListener = DnsSdServiceResponseListener { instanceName, registrationType, resourceType -> // Update the device name with the human-friendly version from // the DnsTxtRecord, assuming one arrived. resourceType.deviceName = buddies[resourceType.deviceAddress] ?: resourceType.deviceName // Add to the custom adapter defined specifically for showing // wifi devices. val fragment = fragmentManager .findFragmentById(R.id.frag_peerlist) as WiFiDirectServicesList (fragment.listAdapter as WiFiDevicesAdapter).apply { add(resourceType) notifyDataSetChanged() } Log.d(TAG, "onBonjourServiceAvailable $instanceName") } manager.setDnsSdResponseListeners(channel, servListener, txtListener) ... }
자바
private void discoverService() { ... DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() { @Override public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice resourceType) { // Update the device name with the human-friendly version from // the DnsTxtRecord, assuming one arrived. resourceType.deviceName = buddies .containsKey(resourceType.deviceAddress) ? buddies .get(resourceType.deviceAddress) : resourceType.deviceName; // Add to the custom adapter defined specifically for showing // wifi devices. WiFiDirectServicesList fragment = (WiFiDirectServicesList) getFragmentManager() .findFragmentById(R.id.frag_peerlist); WiFiDevicesAdapter adapter = ((WiFiDevicesAdapter) fragment .getListAdapter()); adapter.add(resourceType); adapter.notifyDataSetChanged(); Log.d(TAG, "onBonjourServiceAvailable " + instanceName); } }; manager.setDnsSdResponseListeners(channel, servListener, txtListener); ... }
이제 서비스 요청을 만들고 addServiceRequest()
를 호출합니다.
이 메서드는 리스너를 사용하여 성공 또는 실패도 보고합니다.
Kotlin
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance() manager.addServiceRequest( channel, serviceRequest, object : WifiP2pManager.ActionListener { override fun onSuccess() { // Success! } override fun onFailure(code: Int) { // Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY } } )
자바
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance(); manager.addServiceRequest(channel, serviceRequest, new ActionListener() { @Override public void onSuccess() { // Success! } @Override public void onFailure(int code) { // Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY } });
마지막으로 discoverServices()
를 호출합니다.
Kotlin
manager.discoverServices( channel, object : WifiP2pManager.ActionListener { override fun onSuccess() { // Success! } override fun onFailure(code: Int) { // Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY when (code) { WifiP2pManager.P2P_UNSUPPORTED -> { Log.d(TAG, "Wi-Fi Direct isn't supported on this device.") } } } } )
자바
manager.discoverServices(channel, new ActionListener() { @Override public void onSuccess() { // Success! } @Override public void onFailure(int code) { // Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY if (code == WifiP2pManager.P2P_UNSUPPORTED) { Log.d(TAG, "Wi-Fi Direct isn't supported on this device."); else if(...) ... } });
모두 잘 되면 과정을 잘 마친 것입니다. 문제가 발생하면
수행한 비동기 호출이
WifiP2pManager.ActionListener
를 인수로 사용합니다.
성공 또는 실패를 나타내는 콜백이 제공됩니다. 진단
문제가 발생하면 디버깅 코드를 onFailure()
에 넣습니다. 오류 코드
문제에 대한 힌트를 얻을 수 있습니다. 가능한 오류 값은 다음과 같습니다.
그 의미
-
P2P_UNSUPPORTED
- 앱을 실행하는 기기에서 Wi-Fi Direct가 지원되지 않습니다.
-
BUSY
- 시스템의 작업량이 많아 요청을 처리할 수 없습니다.
-
ERROR
- 작업이 내부 오류로 인해 실패했습니다.