Android:周辺を使用したネットワーク通信(PlayServices API)

最近では、GoogleはAndroidモバイル開発者にネットワークデータ交換のための新しいテクノロジー、Nearbyを提供しています。 Androidデバイス間で問題なくローカル接続を確立できるので、すぐに興味深いものになりました! ユーザーにIPアドレスとポートの入力を強制する必要はありません。ユーザーは単に接続を開始し、クライアントは単純に接続します。 次の使用例がテクノロジーページに示されています

-個々の画面でのマルチプレイヤーゲーム-プレイヤーは、それぞれのデバイスからネットワークゲームをプレイします。これらはネットワーク化されています(このジャンルのクラシック)。

-共通画面でのマルチプレイヤーゲーム-この場合、GoogleTVはサーバーとして機能し、メインのゲームプロセスが実行され、接続されているすべてのユーザーがスマートフォン/タブレットをゲームコントローラーとして使用します(写真のように!)。

-もちろん、さまざまなAndroidデバイス間でのデータ交換用。







すでに、この技術をゲームBeach Buggy Racingで試すことができます:



主要な記事を準備した後、配信されたパッケージの順序をシステムがどのように制御しているか疑問に思いました。 特にこれらの目的のために、テキスト形式で写真を送信するための小さなアプリケーションを用意しました。 2048文字の数万のパケットが1つのデバイスから別のデバイスに送信されました。 シーケンスは壊れておらず、単一のパッケージも失われていません。 配送管理に費用がかかり、配送時間が長くなりました。



Neighborhoodでの作業の原則を考慮してください。

自転車を作らないようにするために、私はオリジナルの例を取り上げ、すべてのコメントの翻訳でそれを調べました。

まず、携帯電話に最新バージョンのGooglePlayサービス( https://play.google.com/store/apps/details?id=com.google.android.gms)がインストールされていることを確認してください

それでは、プロジェクトの主要なポイントに移りましょう。

PlayServicesライブラリがプロジェクト(「build.gradle」ファイル)に追加されました。Neighborhoodで作業できるようになります:

dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.0.0' compile 'com.google.android.gms:play-services:7.0.0' }
      
      





Neighborhoodでの作業は、次の段階に分けることができます。

1)メインアクセスオブジェクトの作成-GoogleApiClient。 クライアントの起動。 顧客停止

2)アクセスポイントになることを意図する苦情を申し立てる

3)接続するポイントの検索を開始する

4)ポイントに参加する

5)加入申請の処理

6)接続制御

7)相手からのメッセージを受信して​​処理する

8)メッセージを送信する

すべてを順番に考えてみましょう。



メインアクセスオブジェクト-GoogleApiClientの作成。 クライアントの起動。 顧客停止 ここではすべてが簡単です。 アクティビティコンストラクターで、Nearbyにアクセスするためのメインオブジェクトを作成します。 アクティビティが開始すると、それを開始し、アクティビティが停止すると、ネットワークから切断します。



 @Override protected void onCreate(Bundle savedInstanceState) { … mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(Nearby.CONNECTIONS_API) .build(); … } @Override public void onStart() { super.onStart(); Log.d(TAG, "onStart"); mGoogleApiClient.connect(); } @Override public void onStop() { super.onStop(); Log.d(TAG, "onStop"); if (mGoogleApiClient != null) { mGoogleApiClient.disconnect(); } }
      
      





次のステップは、アクセスポイントになる意図に関する苦情 、startAdvertisingメソッドを開始することです。

 private void startAdvertising() { debugLog("startAdvertising"); if (!isConnectedToNetwork()) { debugLog("startAdvertising: not connected to WiFi network."); return; } //           . List<AppIdentifier> appIdentifierList = new ArrayList<>(); appIdentifierList.add(new AppIdentifier(getPackageName())); AppMetadata appMetadata = new AppMetadata(appIdentifierList); //  .    .    ,       ,  "LGE Nexus 5" String name = null; Nearby.Connections.startAdvertising(mGoogleApiClient, name, appMetadata, TIMEOUT_ADVERTISE, this).setResultCallback(new ResultCallback<Connections.StartAdvertisingResult>() { @Override public void onResult(Connections.StartAdvertisingResult result) { Log.d(TAG, "startAdvertising:onResult:" + result); if (result.getStatus().isSuccess()) { debugLog("startAdvertising:onResult: SUCCESS"); updateViewVisibility(STATE_ADVERTISING); } else { debugLog("startAdvertising:onResult: FAILURE "); //      'Advertise'    ,    'STATUS_ALREADY_ADVERTISING' int statusCode = result.getStatus().getStatusCode(); if (statusCode == ConnectionsStatusCodes.STATUS_ALREADY_ADVERTISING) { debugLog("STATUS_ALREADY_ADVERTISING"); } else { updateViewVisibility(STATE_READY); } } } }); }
      
      





ユーザーが[広告]ボタンをクリックし続けると、すべてが正常に機能しているというメッセージが表示されます。リラックスしてください:)-STATUS_ALREADY_ADVERTISING



第3段階- 接続のポイントの検索の開始

 private void startDiscovery() { debugLog("startDiscovery"); if (!isConnectedToNetwork()) { debugLog("startDiscovery: not connected to WiFi network."); return; } //       Nearby    . String serviceId = getString(R.string.service_id); Nearby.Connections.startDiscovery(mGoogleApiClient, serviceId, TIMEOUT_DISCOVER, this) .setResultCallback(new ResultCallback<Status>() { @Override public void onResult(Status status) { if (status.isSuccess()) { debugLog("startDiscovery:onResult: SUCCESS"); updateViewVisibility(STATE_DISCOVERING); } else { debugLog("startDiscovery:onResult: FAILURE"); //      'Discover'    ,     'STATUS_ALREADY_DISCOVERING' int statusCode = status.getStatusCode(); if (statusCode == ConnectionsStatusCodes.STATUS_ALREADY_DISCOVERING) { debugLog("STATUS_ALREADY_DISCOVERING"); } else { updateViewVisibility(STATE_READY); } } } }); }
      
      





すべてが非常に透明で明確です。 アクセスポイントの検索を開始します。



次に、データ交換ポイントへの参加を検討します。 これを行うには、まず利用可能なアクセスポイントを見つけてから、目的のアクセスポイントに参加する必要があります。 onEndpointFoundメソッドは、新しく見つかったポイントを報告するように特別に設計されています。

  @Override public void onEndpointFound(final String endpointId, String deviceId, String serviceId, final String endpointName) { Log.d(TAG, "onEndpointFound:" + endpointId + ":" + endpointName); //    .    ,      . if (mMyListDialog == null) { // Configure the AlertDialog that the MyListDialog wraps AlertDialog.Builder builder = new AlertDialog.Builder(this) .setTitle("Endpoint(s) Found") .setCancelable(true) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mMyListDialog.dismiss(); } }); //     mMyListDialog = new MyListDialog(this, builder, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String selectedEndpointName = mMyListDialog.getItemKey(which); String selectedEndpointId = mMyListDialog.getItemValue(which); MainActivity.this.connectTo(selectedEndpointId, selectedEndpointName); mMyListDialog.dismiss(); } }); } mMyListDialog.addItem(endpointName, endpointId); mMyListDialog.show(); }
      
      





「connectTo」メソッドは、接続可能なポイントを選択するためダイアログを実装します。 オプションのいずれかを選択すると、直接接続に進みます。

  /** *       . * @param endpointId -       * @param endpointName -   ,    .       . * */ private void connectTo(String endpointId, final String endpointName) { debugLog("connectTo:" + endpointId + ":" + endpointName); //       . String myName = null; byte[] myPayload = null; Nearby.Connections.sendConnectionRequest(mGoogleApiClient, myName, endpointId, myPayload, new Connections.ConnectionResponseCallback() { @Override public void onConnectionResponse(String endpointId, Status status, byte[] bytes) { Log.d(TAG, "onConnectionResponse:" + endpointId + ":" + status); if (status.isSuccess()) { debugLog("onConnectionResponse: " + endpointName + " SUCCESS"); Toast.makeText(MainActivity.this, "Connected to " + endpointName, Toast.LENGTH_SHORT).show(); mOtherEndpointId = endpointId; updateViewVisibility(STATE_CONNECTED); } else { debugLog("onConnectionResponse: " + endpointName + " FAILURE"); } } }, this); }
      
      





すべてがうまくいけば、メッセージングを開始できます。



onConnectionRequestメソッドは、参加するアプリケーション処理するために使用されます

  @Override public void onConnectionRequest(final String endpointId, String deviceId, String endpointName, byte[] payload) { debugLog("onConnectionRequest:" + endpointId + ":" + endpointName); //          .            . mConnectionRequestDialog = new AlertDialog.Builder(this) .setTitle("Connection Request") .setMessage("Do you want to connect to " + endpointName + "?") .setCancelable(false) .setPositiveButton("Connect", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { byte[] payload = null; Nearby.Connections.acceptConnectionRequest(mGoogleApiClient, endpointId, payload, MainActivity.this) .setResultCallback(new ResultCallback<Status>() { @Override public void onResult(Status status) { if (status.isSuccess()) { debugLog("acceptConnectionRequest: SUCCESS"); mOtherEndpointId = endpointId; updateViewVisibility(STATE_CONNECTED); } else { debugLog("acceptConnectionRequest: FAILURE"); } } }); } }) .setNegativeButton("No", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Nearby.Connections.rejectConnectionRequest(mGoogleApiClient, endpointId); } }).create(); mConnectionRequestDialog.show(); }
      
      





接続を制御するためのいくつかのメソッドがあります。

onDisconnected-切断処理。

onConnected-接続処理。

onEndpointLost-切断処理。

onConnectionSuspended-接続終了処理。

onConnectionFailed-失敗した接続を処理します。

クライアントの再接続に対する制御(たとえば、ユーザーがWiFiカバレッジエリアを離れたときに接続が切断された場合)は、開発者に完全に委ねられています。



着信メッセージ処理するには、onMessageReceivedメソッドを書き換える必要があります

  @Override public void onMessageReceived(String endpointId, byte[] payload, boolean isReliable) { // ,     debugLog("onMessageReceived:" + endpointId + ":" + new String(payload)); }
      
      





メッセージは2つの方法を使用して送信されます。

1)Neighborhood.Connections.sendReliableMessage-信頼できるメッセージを送信します。

2)Neighborhood.Connections.sendUnreliableMessage-信頼できないメッセージの送信。

最初の方法を使用する場合、システム自体が配信されたメッセージのシーケンスの正確さを制御します。2番目の場合、制御がないため、シーケンスに違反する場合があります。 ただし、2番目の方法は高速であるため、画面上のカーソル位置を送信する場合など、大量のメッセージを送信する場合に使用することをお勧めします。



リソースでは、クライアントの検索と接続が発生するサービス識別子を指定する必要があります。

 <?xml version="1.0" encoding="utf-8"?> <resources> ... <string name="service_id"><!--   ,  ..--></string> ... </resources>
      
      





マニフェスト内のアプリケーションの苦情を解決するには、次のように記述します。

 <application> <meta-data android:name="com.google.android.gms.nearby.connection.SERVICE_ID" android:value="@string/service_id" /> <activity> ... </activity> </application>
      
      





このアプリケーションをビルドしてデバイスで実行すると、次のことを確認できます。



一見、Nearby APIの使用は複雑で扱いにくいように思えるかもしれませんが、これは一見しただけです。 その結果、開発者は、ネットワークデータ交換のための既製の信頼できる制御されたツールを入手できます。 個人的に、私はこのソリューションが本当に好きで、データパケットの到着順序を制御する必要はなく、ユーザーにIPアドレスとソケット番号の入力を求め、追加の設定を行う...美容!



コメント付きのソース

別途APK



イナテール素材の準備を手伝ってくれてありがとう!



All Articles