このクラスの最初のレッスン、ネットワーク サービスの使用 Discovery は、 ローカル ネットワークに接続されたサービスを検出する方法。ただし、 Wi-Fi Direct(P2P)Service Discovery を使用すると、付近のデバイスのサービスを検出できます ネットワークに直接接続できます。また、これらのサービスを 確認できます。これらの機能は、アプリ間のコミュニケーションに役立ちます。 アクセス ポイントを使用できます。
この API セットの目的は、ネットワーク サービス ディスカバリと 前のレッスンで概説した API をコードで実装する方法は大きく異なります。 このレッスンでは、他のデバイスから利用できるサービスを見つける方法について説明します。 接続することもできますこのレッスンは、 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 では接続の設定が
標準の Java ソケットを使用します。また、これらを 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 } }) }
Java
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 } } }
Java
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
を作成します。この
実際の説明と接続情報を受け取ります。上記のコード
スニペットは、デバイスのアドレスと buddy をペア設定するための 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) ... }
Java
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 } } )
Java
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.") } } } } )
Java
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
- : 内部エラーのため、オペレーションが失敗しました。