Wi-Fi Aware の概要

Wi-Fi Aware の機能は、Android 8.0(API レベル 26)および 他の種類の API を使わずに互いに直接接続して、 内部 IP アドレスを使用して相互に通信できますWi-Fi Aware は Neighbor Awareness とも呼ばれます。 ネットワーキング(NAN)。

Wi-Fi Aware ネットワークは、隣接するデバイスとのクラスタを形成することで機能します。 そのデバイスがエリア内の最初のデバイスである場合は、新しいクラスタを作成します。この クラスタリング動作はデバイス全体に適用され、Wi-Fi によって管理されます。 Aware システム サービスアプリはクラスタリングの動作を制御できません。アプリの使用状況 Wi-Fi Aware API と通信し、Wi-Fi Aware システム サービスと通信します。 デバイスの Wi-Fi Aware ハードウェア。

Wi-Fi Aware API を使用すると、アプリで次のオペレーションを実施できます。

  • 他のデバイスの検出: この API には、他のデバイスを検出するメカニズムがあります。 付近のデバイスを探します。このプロセスは、1 つのデバイスが 1 つのデバイスをパブリッシュすると開始されます。 追加することもできますその後、デバイスが 1 つまたは複数の YouTube サービスを定期購入したとき ニュース メディアの Wi-Fi 範囲に入ると、加入者は 一致するパブリッシャーが検出されたという通知を受け取ります。 定期購読者がニュース メディアを見つけると、定期購読者は というメッセージが表示されるか、検出されたデバイスとのネットワーク接続が確立されます。 デバイスは、同時にパブリッシャーとサブスクライバーの両方になれます。

  • ネットワーク接続を作成する: 2 台のデバイスがそれぞれを検出した後 作成することも可能です。 双方向の Wi-Fi Aware ネットワーク接続(アクセス ポイントを使用しない場合)。

Wi-Fi Aware ネットワーク接続により、より長期間の Bluetooth と比較した場合の距離 接続しますこの種の接続は、大量のリソースを共有する ユーザー間で大量のデータを使用することが禁じられています。

Android 13(API レベル 33)の機能強化

Instant をサポートする 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 アドレスを事前に知る必要はありません。これによりデータパスが高速化されます 1 つのネットワークのみで複数のポイントツーポイント リンクを起動し、有効にする リクエストできます。
  • 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)
    

    Java

    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)
    

    Java

    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 の使用を開始するには、アプリで 呼び出しで WifiAwareSession attach()。この方法は 次の処理が行われます。

  • Wi-Fi Aware ハードウェアをオンにする。
  • Wi-Fi Aware クラスタに参加、または Wi-Fi Aware クラスタを形成する。
  • サービスとして機能する一意の名前空間を持つ Wi-Fi Aware セッションを作成します。 その中に作成されたすべての検出セッションが格納される

アプリが正常にアタッチされると、システムは onAttached() コールバック。 このコールバックは、WifiAwareSession オブジェクトを提供します。 以降のすべてのセッション オペレーションにアプリで使用する必要があります。アプリは サービスを公開する、または サービスに登録する

アプリは attach() は 1 回のみです。条件 アプリが attach() を呼び出す 呼び出しごとに異なるセッションを受信し、 Namespace があります。これは複雑なシナリオで役立ちますが、 おすすめしません。

サービスを公開する

サービスを検出可能にするには、 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) {
        ...
    }
})

Java

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)

Java

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() 実装する必要があります。kubectl の「get」コマンドや SubscribeDiscoverySession 引数を アプリがパブリッシャーを発見した後にパブリッシャーと通信するために、 この参照を保存しますサブスクライブ セッションは、いつでも更新できます。 通話中 updateSubscribe() 説明します。

この時点で、一致するパブリッシャーの参加をサブスクリプションが待機します Wi-Fi の範囲。この場合、システムは onServiceDiscovered() コールバック メソッドを指定します。PeerHandle を使用できます。 このコールバックから引数としてメッセージを送信するか、 そのパブリッシャーへの接続を作成します。

サービスへの登録を停止するには、次のコマンドを呼び出します。 DiscoverySession.close()。 検索セッションは親に関連付けられています WifiAwareSession。親セッションが 関連する調査セッションも終了します。破棄中 閉じられた場合でも、システムは対象範囲外であることを保証しません。 セッションは終了するため、close() を明示的に呼び出すことをおすすめします。 あります。

メッセージを送信する

別のデバイスにメッセージを送信するには、次のオブジェクトが必要です。

メッセージを送信するには、 sendMessage()。「 その後、次のコールバックが発生する可能性があります。

  • ピアがメッセージを正常に受信すると、システムは onMessageSendSucceeded() Sending アプリで呼び出します。
  • ピアがメッセージを受信すると、システムは onMessageReceived() 受信側のアプリでコールバックを行うかどうか。
で確認できます。

PeerHandle は同僚とのコミュニケーションに必要ですが、 ピアの永続的な識別子として信頼されます。上位レベルの識別子を 検出サービス自体またはインフラストラクチャに 後続のメッセージを取得します検出サービスに識別子を埋め込むには、 setMatchFilter() または setServiceSpecificInfo() PublishConfig または SubscribeConfig。「 setMatchFilter() メソッドは検出に影響しますが、 setServiceSpecificInfo() メソッドは検出に影響しません。

メッセージに識別子を埋め込むことは、メッセージ バイト配列を 識別子を含める(例: 最初の数バイト)。

接続を作成する

Wi-Fi Aware は、2 つの Wi-Fi Aware デバイス間のクライアント サーバー ネットワークをサポートします。

クライアント サーバー接続の設定手順は次のとおりです。

  1. Wi-Fi Aware 検出を使用してサービスを公開します( サブスクライブしたり、サービスに登録したり( できます。

  2. サブスクライバーがパブリッシャーを見つけると、 サブスクライバーからパブリッシャーにメッセージを送信します。

  3. パブリッシャーで ServerSocket を開始する ポートを設定または取得します。

    Kotlin

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

    Java

    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);
    

    Java

    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)
    

    Java

    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 m 未満(3,000 mm として指定)以内、10 m 以下 (10,000 mm として指定)。

ジオフェンスを有効にするには、パブリッシャーとサブスクライバーの両方で対応する必要があります。

  • ニュース メディアは、 setRangingEnabled(true)

    パブリッシャーが距離測定を有効にしていない場合、ジオフェンスの制約は 無視され、通常の検出が実行されます。 距離は無視します。

  • サブスクライバーは、以下の組み合わせを使用してジオフェンスを指定する必要があります。 setMinDistanceMm および setMaxDistanceMm

    どちらの値でも、距離が指定されていない場合は制限がないことを意味します。指定のみ 最大距離は最小距離が 0 であることを意味します。Pod の 最小距離は最大値がないことを意味します

ジオフェンス内でピアサービスが検出されると、 onServiceDiscoveredWithinRange コールバックがトリガーされ、ピアまでの距離が測定されます。「 Direct Wi-Fi RTT API を必要に応じて呼び出し、 後で説明します