Wi-Fi Aware 개요

Wi-Fi Aware 기능은 Android 8.0 (API 수준 26) 및 더 높은 곳에서 다른 유형의 장치 없이 서로 직접 발견하고 연결성입니다 Wi-Fi Aware는 Neighbor Awareness라고도 합니다. 네트워킹 (NAN).

Wi-Fi Aware 네트워킹은 주변 장치와 클러스터를 형성하여 작동하거나 새로운 클러스터를 생성합니다. 이 클러스터링 동작이 전체 기기에 적용되며 Wi-Fi에 의해 관리됨 시스템 서비스를 인식합니다. 앱은 클러스터링 동작을 제어할 수 없습니다. 앱에서 사용하는 Wi-Fi Aware API를 이용하여 관리 서비스를 관리하는 Wi-Fi Aware 시스템 서비스와 통신합니다. Wi-Fi Aware 하드웨어에 액세스할 수 없습니다.

Wi-Fi Aware API를 통해 앱은 다음 작업을 할 수 있습니다.

  • 다른 기기 찾기: API에는 사용자가 소유한 다른 기기를 근처 기기. 한 기기가 기기를 게시하면 프로세스가 시작됩니다. 더 많은 검색 가능한 서비스를 제공할 수 있습니다 기기에서 하나 이상의 콘텐츠를 구독하면 게시자의 Wi-Fi 범위에 들어가면 일치하는 게시자가 발견되었다는 알림이 표시됩니다. 그런 다음 구독자가 게시자를 발견할 경우 구독자는 검색된 장치와의 네트워크 연결을 설정할 수 있습니다. 기기는 동시에 게시자와 구독자 모두가 될 수 있습니다.

  • 네트워크 연결 만들기: 두 대의 기기가 각각 다른 방법으로는 액세스 포인트 없이 양방향 Wi-Fi Aware 네트워크에 연결할 수 있습니다.

Wi-Fi Aware 네트워크 연결은 더 긴 시간 동안 더 높은 처리량 속도를 지원합니다 블루투스 대비 거리 연결을 설정할 수 있습니다 이러한 유형의 연결은 큰 데이터 세트를 공유하는 앱에 유용합니다. 대량의 데이터(예: 사진 공유 앱)

Android 13 (API 수준 33) 개선사항

인스턴트를 지원하는 Android 13 (API 수준 33) 이상을 실행하는 기기 앱은 PublishConfig.Builder.setInstantCommunicationModeEnabled()SubscribeConfig.Builder.setInstantCommunicationModeEnabled() 메서드를 사용하여 게시자 또는 구독자에 대한 인스턴트 커뮤니케이션 모드 사용 또는 사용 중지 탐색 세션입니다. 인스턴트 커뮤니케이션 모드는 메시지 교환을 가속화하고 서비스 검색, 그리고 게시자 또는 구독자의 일부로 설정된 모든 데이터 경로 탐색 세션입니다. 기기가 인스턴트 통신을 지원하는지 확인하기 위해 isInstantCommunicationModeSupported() 메서드를 사용합니다.

Android 12 (API 수준 31) 개선사항

Android 12 (API 수준 31)에서는 Wi-Fi Aware를 다음과 같이 개선했습니다.

  • Android 12 (API 수준 31) 이상을 실행하는 기기에서는 onServiceLost() 드림 콜백으로 인해 앱에서 발견된 서비스가 손실되었을 때 알림을 서비스 중단 또는 범위 외로 이동하지 않을 수 있습니다.
  • Wi-Fi Aware 데이터 경로의 설정이 유사했습니다. 이전 버전 L2 메시지를 사용하여 시작자의 MAC 주소를 제공하고, 지연 시간이 발생합니다 Android 12 이상을 실행하는 기기에서는 응답자가 모든 피어를 수락하도록 구성할 수 있습니다. 초기화자의 MAC 주소를 미리 알 수 있습니다 이렇게 하면 데이터 경로 속도가 빨라집니다. 하나의 네트워크로만 여러 지점 간 링크를 사용 설정할 수 있습니다. 합니다.
  • Android 12 이상에서 실행되는 앱은 WifiAwareManager.getAvailableAwareResources() 드림 메서드를 사용하여 현재 사용 가능한 데이터 경로의 수를 가져오고, 세션을 게시하고, 세션을 구독할 수 있습니다 이렇게 하면 앱에서 필요한 기능을 실행하기에 충분한 리소스를 확보할 수 있습니다

초기 설정

Wi-Fi Aware 검색 및 네트워킹을 사용하도록 앱을 설정하려면 다음을 수행합니다. 다음 단계를 따르세요.

  1. 앱 매니페스트에서 다음 권한을 요청합니다.

    <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" />
    <!-- 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" />
    
  2. 기기가 Wi-Fi Aware를 지원하는지 확인 PackageManager API를 사용할 수 있습니다.

    Kotlin

    context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)
    

    자바

    context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
    
  3. Wi-Fi Aware가 현재 사용 가능한지 확인합니다. Wi-Fi Aware가 사용자가 기기에서 비활성화 상태로 인해 현재 사용하지 못할 수 있음 Wi-Fi 또는 위치를 탭합니다. 일부 기기는 하드웨어 및 펌웨어 기능에 따라 Wi-Fi Direct, SoftAP 또는 테더링이 켜져 있으면 Wi-Fi Aware를 지원하지 않을 수 있습니다. 사용합니다 현재 Wi-Fi Aware를 사용할 수 있는지 확인하려면 isAvailable()

    Wi-Fi Aware의 사용 가능 여부는 언제든지 변경될 수 있습니다. 앱은 다음과 같아야 합니다. 수신할 BroadcastReceiver 등록 ACTION_WIFI_AWARE_STATE_CHANGED, 가용성이 변경될 때마다 전송됩니다 앱이 모든 기존 세션을 삭제해야 합니다( Wi-Fi Aware 서비스가 중단된 경우) 그에 따라 동작을 조정할 수 있습니다. 예를 들면 다음과 같습니다.

    Kotlin

    val wifiAwareManager = context.getSystemService(Context.WIFI_AWARE_SERVICE) as WifiAwareManager?
    val filter = IntentFilter(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED)
    val myReceiver = object : BroadcastReceiver() {
    
        override fun onReceive(context: Context, intent: Intent) {
            // discard current sessions
            if (wifiAwareManager?.isAvailable) {
                ...
            } else {
                ...
            }
        }
    }
    context.registerReceiver(myReceiver, filter)
    

    자바

    WifiAwareManager wifiAwareManager = 
            (WifiAwareManager)context.getSystemService(Context.WIFI_AWARE_SERVICE)
    IntentFilter filter =
            new IntentFilter(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED);
    BroadcastReceiver myReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // discard current sessions
            if (wifiAwareManager.isAvailable()) {
                ...
            } else {
                ...
            }
        }
    };
    context.registerReceiver(myReceiver, filter);
    

자세한 내용은 브로드캐스트를 참조하세요.

세션 가져오기

Wi-Fi Aware 사용을 시작하려면 앱에 Wi-Fi Aware 다음을 호출하여 WifiAwareSession attach()입니다. 이 방법 다음 작업을 수행합니다.

  • Wi-Fi Aware 하드웨어를 켭니다.
  • Wi-Fi Aware 클러스터에 참여하거나 클러스터를 형성합니다.
  • 네트워크 계층의 역할을 하는 고유한 네임스페이스를 사용하여 Wi-Fi Aware 세션을 생성합니다. 모든 탐색 세션을 위한 컨테이너를 실행합니다

앱이 성공적으로 연결되면 시스템은 onAttached() 콜백입니다. 이 콜백은 WifiAwareSession 객체를 제공합니다. 모든 추가 세션 작업에 사용해야 합니다. 앱은 서비스를 게시하기 위한 세션 또는 서비스를 구독할 수 있습니다

앱에서 attach()는 한 번만 사용할 수 있습니다. 만약 앱에서 attach() 호출 앱이 여러 번 호출될 때 앱은 각 호출에 대해 다른 세션을 수신합니다. 자체 네임스페이스가 있습니다 이 방법은 복잡한 시나리오에서 유용할 수 있지만 일반적으로 피하는 것이 좋습니다

서비스 게시

서비스를 검색 가능하게 만들려면 publish() 메서드 는 다음 매개변수를 사용합니다.

  • PublishConfig는 서비스 및 일치 필터와 같은 기타 구성 속성이 포함됩니다.
  • DiscoverySessionCallback는 이벤트가 발생할 때 실행할 작업(예: 구독자가 메시지를 보냅니다.

예를 들면 다음과 같습니다.

Kotlin

val config: PublishConfig = PublishConfig.Builder()
        .setServiceName(AWARE_FILE_SHARE_SERVICE_NAME)
        .build()
awareSession.publish(config, object : DiscoverySessionCallback() {

    override fun onPublishStarted(session: PublishDiscoverySession) {
        ...
    }

    override fun onMessageReceived(peerHandle: PeerHandle, message: ByteArray) {
        ...
    }
})

자바

PublishConfig config = new PublishConfig.Builder()
    .setServiceName(“Aware_File_Share_Service_Name”)
    .build();

awareSession.publish(config, new DiscoverySessionCallback() {
    @Override
    public void onPublishStarted(PublishDiscoverySession session) {
        ...
    }
    @Override
    public void onMessageReceived(PeerHandle peerHandle, byte[] message) {
        ...
    }
}, null);

게시에 성공하면 onPublishStarted() 콜백 메서드가 호출됩니다.

게시 후 일치하는 구독자 앱을 실행 중인 기기가 게시 기기의 Wi-Fi 범위, 구독자는 서비스를 검색합니다. 날짜 구독자가 게시자를 발견할 경우 게시자는 알림 구독자가 게시자에게 메시지를 보내면 게시자가 알림을 받게 됩니다. 이 경우 onMessageReceived() 콜백 메서드가 호출됩니다. 이 이 메서드에서 PeerHandle 인수를 다음 값으로 바꿉니다. 구독자에게 다시 메시지를 전송하거나 연결을 만듭니다.

서비스 게시를 중지하려면 다음을 호출합니다. DiscoverySession.close() 탐색 세션이 상위 요소와 연결됨 WifiAwareSession 상위 세션이 닫히면 연결된 탐색 세션도 닫힙니다. 삭제되는 동안 시스템도 범위를 벗어나면 닫히지 않을 수도 있고 세션이 종료되었으므로 close()를 명시적으로 호출하는 것이 좋습니다. 메서드를 참조하세요.

서비스 구독

서비스에 가입하려면 subscribe() 메서드 이 함수는 다음 매개변수를 사용합니다.

  • SubscribeConfig는 기타 구성 속성(예: 일치, 필터를 적용합니다.
  • DiscoverySessionCallback는 게시자가 검색될 때와 같이 이벤트가 발생할 때 실행할 작업입니다.

예를 들면 다음과 같습니다.

Kotlin

val config: SubscribeConfig = SubscribeConfig.Builder()
        .setServiceName(AWARE_FILE_SHARE_SERVICE_NAME)
        .build()
awareSession.subscribe(config, object : DiscoverySessionCallback() {

    override fun onSubscribeStarted(session: SubscribeDiscoverySession) {
        ...
    }

    override fun onServiceDiscovered(
            peerHandle: PeerHandle,
            serviceSpecificInfo: ByteArray,
            matchFilter: List<ByteArray>
    ) {
        ...
    }
}, null)

자바

SubscribeConfig config = new SubscribeConfig.Builder()
    .setServiceName("Aware_File_Share_Service_Name")
    .build();

awareSession.subscribe(config, new DiscoverySessionCallback() {
    @Override
    public void onSubscribeStarted(SubscribeDiscoverySession session) {
        ...
    }

    @Override
    public void onServiceDiscovered(PeerHandle peerHandle,
            byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
        ...
    }
}, null);

구독 작업이 성공하면 시스템은 onSubscribeStarted() 앱에 콜백을 추가할 수 있습니다. Cloud Shell에서 SubscribeDiscoverySession 인수 콜백을 사용하여 게시자와 통신할 수 있도록 합니다. 이 참조를 저장해야 합니다. 다음 방법으로 언제든지 구독 세션을 업데이트할 수 있습니다. 통화 updateSubscribe() 검색 세션으로 넘어갑니다

이 시점에서 구독은 일치하는 게시자가 들어올 때까지 대기합니다. Wi-Fi 신호 범위 이 경우 시스템은 onServiceDiscovered() 드림 콜백 메서드를 호출합니다. PeerHandle를 사용하면 됩니다. 인수를 사용하여 메시지를 전송하거나 해당 게시자와의 연결을 만듭니다.

서비스 구독을 중지하려면 다음을 호출합니다. DiscoverySession.close() 탐색 세션이 상위 요소와 연결됨 WifiAwareSession 상위 세션이 닫히면 연결된 탐색 세션도 닫힙니다. 삭제되는 동안 시스템도 범위를 벗어나면 닫히지 않을 수도 있고 세션이 종료되었으므로 close()를 명시적으로 호출하는 것이 좋습니다. 메서드를 참조하세요.

메시지 보내기

다른 기기에 메시지를 보내려면 다음 객체가 필요합니다.

메시지를 보내려면 sendMessage() 이 그러면 다음과 같은 콜백이 발생할 수 있습니다.

  • 메시지가 피어에 의해 성공적으로 수신되면 시스템은 onMessageSendSucceeded() 전송 앱에서 콜백을 수신합니다.
  • 피어가 메시지를 수신하면 시스템은 onMessageReceived() 수신 앱에서 콜백을 수신합니다.
를 통해 개인정보처리방침을 정의할 수 있습니다.

PeerHandle는 피어와 통신하는 데 필요하지만 피어의 영구 식별자로 사용됩니다 상위 수준 식별자는 애플리케이션에서 사용하거나 검색 서비스 자체에 삽입되어 있거나 확인할 수 있습니다. 다음을 사용하여 검색 서비스에 식별자를 삽입할 수 있습니다. setMatchFilter() 드림 또는 setServiceSpecificInfo() PublishConfig의 메서드 또는 SubscribeConfig. 이 setMatchFilter() 메서드는 검색에 영향을 주지만 setServiceSpecificInfo() 메서드는 검색에 영향을 미치지 않습니다.

메시지에 식별자를 삽입한다는 것은 메시지 바이트 배열을 식별자를 포함합니다 (예: 처음 몇 바이트로).

연결 생성

Wi-Fi Aware는 두 Wi-Fi Aware 기기 간의 클라이언트-서버 네트워킹을 지원합니다.

클라이언트-서버 연결을 설정하려면 다음 단계를 따르세요.

  1. Wi-Fi Aware 검색을 사용하여 서비스를 게시합니다( 서버)에서)하고 서비스에 가입 (서비스에 가입 있습니다.

  2. 구독자가 게시자를 검색하면 구독자에서 게시자에게 메시지를 전송하는 데 사용됩니다.

  3. 게시자에서 ServerSocket를 시작합니다. 기기를 사용하여 포트를 설정하거나 가져올 수 있습니다.

    Kotlin

    val ss = ServerSocket(0)
    val port = ss.localPort
    

    자바

    ServerSocket ss = new ServerSocket(0);
    int port = ss.getLocalPort();
    
  4. ConnectivityManager를 사용하여 다음을 수행합니다. Wi-Fi Aware 네트워크를 요청할 때 WifiAwareNetworkSpecifier, 검색 세션과 구독자의 PeerHandle, 다음과 같이 구독자가 전송한 메시지에서 얻은 값입니다.

    Kotlin

    val networkSpecifier = WifiAwareNetworkSpecifier.Builder(discoverySession, peerHandle)
        .setPskPassphrase("somePassword")
        .setPort(port)
        .build()
    val myNetworkRequest = NetworkRequest.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
        .setNetworkSpecifier(networkSpecifier)
        .build()
    val callback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) {
            ...
        }
    
        override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
            ...
        }
    
        override fun onLost(network: Network) {
            ...
        }
    }
    
    connMgr.requestNetwork(myNetworkRequest, callback);
    

    자바

    NetworkSpecifier networkSpecifier = new WifiAwareNetworkSpecifier.Builder(discoverySession, peerHandle)
        .setPskPassphrase("somePassword")
        .setPort(port)
        .build();
    NetworkRequest myNetworkRequest = new NetworkRequest.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
        .setNetworkSpecifier(networkSpecifier)
        .build();
    ConnectivityManager.NetworkCallback callback = new ConnectivityManager.NetworkCallback() {
        @Override
        public void onAvailable(Network network) {
            ...
        }
    
        @Override
        public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
            ...
        }
    
        @Override
        public void onLost(Network network) {
            ...
        }
    };
    
    ConnectivityManager connMgr.requestNetwork(myNetworkRequest, callback);
    
  5. 게시자가 네트워크를 요청하면 구독자에게 메시지를 전송합니다.

  6. 구독자가 게시자로부터 메시지를 수신하면 Wi-Fi를 요청합니다. 게시자와 동일한 방법을 사용하는 구독자의 인식 네트워크 올바른 예시 생성할 때 포트를 지정하지 않아야 함 NetworkSpecifier 이 네트워크 연결이 끊기면 적절한 콜백 메서드가 사용할 수 없게 됩니다.

  7. 구독자에서 onAvailable() 메서드가 호출되면 Network 객체는 다음과 함께 사용할 수 있습니다. Socket를 열어 게시자에 대한 ServerSocket과는 다릅니다. 하지만 ServerSocket의 IPv6 주소 및 포트입니다. 이 데이터는 NetworkCapabilities 객체 다음과 같이 onCapabilitiesChanged() 콜백에 제공됩니다.

    Kotlin

    val peerAwareInfo = networkCapabilities.transportInfo as WifiAwareNetworkInfo
    val peerIpv6 = peerAwareInfo.peerIpv6Addr
    val peerPort = peerAwareInfo.port
    ...
    val socket = network.getSocketFactory().createSocket(peerIpv6, peerPort)
    

    자바

    WifiAwareNetworkInfo peerAwareInfo = (WifiAwareNetworkInfo) networkCapabilities.getTransportInfo();
    Inet6Address peerIpv6 = peerAwareInfo.getPeerIpv6Addr();
    int peerPort = peerAwareInfo.getPort();
    ...
    Socket socket = network.getSocketFactory().createSocket(peerIpv6, peerPort);
    
  8. 네트워크 연결이 완료되면 unregisterNetworkCallback()

동종 기기 범위 지정 및 위치 인식 검색

Wi-Fi RTT 위치 기능이 있는 기기 기능은 동료와의 거리를 직접 측정하고 이 정보를 사용하여 Wi-Fi Aware 서비스 검색을 제한합니다.

Wi-Fi RTT API를 사용하면 MAC 주소 또는 PeerHandle.

Wi-Fi Aware 검색은 네트워크 내에서만 서비스를 검색하도록 제한될 수 있습니다 특정 지오펜싱을 사용하는 것이 좋습니다 예를 들어 사용자가 방문하는 곳을 찾을 수 있도록 지오펜싱을 설정할 수 있습니다. 현재 게시되어 있지 않은 "Aware_File_Share_Service_Name" 서비스를 3미터 이상 (3,000mm로 지정) 및 10미터 이하 (10,000mm로 지정)

지오펜싱을 사용하도록 설정하려면 게시자와 구독자 모두에서 다음 조치를 취해야 합니다.

  • 게시자는 setRangingEnabled(true):

    게시자가 범위 지정을 사용 설정하지 않으면 지오펜싱 제약 조건이 나머지는 무시되고 일반 검색이 수행되므로 거리가 무시됩니다.

  • 구독자는 setMinDistanceMmsetMaxDistanceMm.

    두 값 모두 지정하지 않으면 거리에 제한이 없음을 의미합니다. 지정 작업만 최대 거리는 최소 거리 0을 의미합니다. 포드의 상태를 최소 거리는 최댓값이 없음을 의미합니다.

지오펜싱 내에서 피어 서비스가 검색되면 onServiceDiscoveredWithinRange에 콜백이 트리거되어 동종 앱과의 측정된 거리를 제공합니다. 이 그런 다음 필요에 따라 Direct Wi-Fi RTT API를 호출하여 확인할 수 있습니다