こちらのページを参考に、メッセージ送信の部分だけを抜き出して作ってみました。
Android, Android Wear共通
両方のAndroidManifest.xmlのapplicationタグの下に以下の一行を追加します。こいつは通信につかうGoogleApiClientを使うのにいるっぽいです。
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
Android Wear メッセージ送信側
まず、画面でGoogleApiClientのインスタンスを作っておきます。Builderがあるのでさくっと作れます。接続の成否を見るために、addConnectionCallbacksとaddOnConnectionFailedのリスナーを追加しておくといいと思われます。そして、addApiでWearable.APIを追加しておきます。
// フィールドに定義しておく private GoogleApiClient client; // OnCreateとかそれに準ずるメソッドあたりで初期化 this.client = new GoogleApiClient.Builder(this.getActivity()) .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() { @Override public void onConnected(Bundle bundle) { Log.d("MyFragment", "onConnected"); } @Override public void onConnectionSuspended(int i) { Log.d("MyFragment", "onConnectionSuspended"); } }) .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() { @Override public void onConnectionFailed(ConnectionResult connectionResult) { Log.d("MyFragment", "onConnectionFailed"); } }) .addApi(Wearable.API) .build(); this.client.connect();
次にメッセージ送信処理です。これはボタンのクリックなど、送信したいタイミングのところに書くといいと思います。ポイントはUIスレッドでawait呼ぶと死ぬので別スレッドを立ててるところです。ただ、行儀がいいのかはちょっと個人的に疑問に残ったりするところです…。
Wearable.NodeApi.GetConnectionNodesメソッドで接続のノードを取得して、全ノードに対してsendMessageメソッドでメッセージを送っています。sendMessageは、GoogleClientApiと、ノードのIDと、メッセージ識別用のパスの文字列と、バイト列です。ここではHello worldをバイト配列にして渡してます。
結果に対してisSuccessで成否の判断ができます。到達確認までできてるのかは、未確認…。
new Thread(new Runnable() { @Override public void run() { Log.d("MyFragment", "onClick"); final String message = "Hello world"; NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(client).await(); for (Node node : nodes.getNodes()) { MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage( client, node.getId(), "/hello", message.getBytes()) .await(); if (result.getStatus().isSuccess()) { Log.d("onClick", "isSuccess is true"); } else { Log.d("onClick", "isSuccess is false"); } } } }).start();
Android wear側のコードはこんな感じになってます。
package com.example.kazuki.myapplication; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.os.Bundle; import android.support.wearable.view.CardFragment; import android.support.wearable.view.FragmentGridPagerAdapter; import android.support.wearable.view.GridViewPager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.wearable.MessageApi; import com.google.android.gms.wearable.Node; import com.google.android.gms.wearable.NodeApi; import com.google.android.gms.wearable.Wearable; public class MyActivity extends Activity { private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); final GridViewPager gvp = (GridViewPager) findViewById(R.id.gridPageView); gvp.setAdapter(new GridViewPagerAdapter(this.getFragmentManager())); } static class GridViewPagerAdapter extends FragmentGridPagerAdapter { public GridViewPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getFragment(int row, int col) { return MyFragment.newInstance(); } @Override public int getRowCount() { return 1; } @Override public int getColumnCount(int i) { return 1; } } static class MyFragment extends CardFragment { private GoogleApiClient client; @Override public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { this.client = new GoogleApiClient.Builder(this.getActivity()) .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() { @Override public void onConnected(Bundle bundle) { Log.d("MyFragment", "onConnected"); } @Override public void onConnectionSuspended(int i) { Log.d("MyFragment", "onConnectionSuspended"); } }) .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() { @Override public void onConnectionFailed(ConnectionResult connectionResult) { Log.d("MyFragment", "onConnectionFailed"); } }) .addApi(Wearable.API) .build(); this.client.connect(); Button button = new Button(this.getActivity()); button.setText("OK"); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { Log.d("MyFragment", "onClick"); final String message = "Hello world"; NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(client).await(); for (Node node : nodes.getNodes()) { MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage( client, node.getId(), "/hello", message.getBytes()) .await(); if (result.getStatus().isSuccess()) { Log.d("onClick", "isSuccess is true"); } else { Log.d("onClick", "isSuccess is false"); } } } }).start(); } }); return button; } public static MyFragment newInstance() { return new MyFragment(); } } }
ついでにレイアウトファイル
<?xml version="1.0" encoding="utf-8"?> <android.support.wearable.view.GridViewPager xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/gridPageView" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MyActivity" tools:deviceIds="wear"> </android.support.wearable.view.GridViewPager>
受信側のAndroidの処理
受信側も、何処かでGoogleApiClientのインスタンスを作っておきます。この例では、ActivityのOnCreateで作ってます。手抜きして各種リスナーは登録しないでやりました。すっきり!この処理いりませんでした。
package com.example.kazuki.myapplication; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.wearable.Wearable; public class MyActivity extends Activity { private GoogleApiClient client; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); this.client = new GoogleApiClient.Builder(this) .addApi(Wearable.API) .build(); this.client.connect(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.my, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
データの受信にはWearableListenerServiceを継承したサービスを作ります。こいつは、onMessageReceivedをオーバーライドすればOKです。メッセージがきたら呼ばれます。getPathとgetDataでsendMessageしたときのパスとデータがとれます。ここでは、受信結果をログに出しています。
package com.example.kazuki.myapplication; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; import com.google.android.gms.wearable.MessageEvent; import com.google.android.gms.wearable.WearableListenerService; public class MyService extends WearableListenerService { @Override public void onMessageReceived(MessageEvent messageEvent) { Log.d("MyService", "onMessageReceived"); Log.d("MyService", messageEvent.getPath()); Log.d("MyService", new String(messageEvent.getData())); } }
AndroidManifest.xmlには、以下のようなサービスの定義をしておきます。intent-filterのactionにcom.google.android.gms.wearable.BIND_LISTENERを追加しておくのがポイントです。
<service android:name=".MyService" > <intent-filter> <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> </intent-filter> </service>
これで、接続されているAndroidとAndroid Wearの両方でアプリを起動して、Android Wearでボタンを押すとAndroid側のログにメッセージが出ます。
おまけ
Android実機とAndroid Wearのエミュレータの接続方法は以下のページが参考になります。
Android Wear Previewの取得とかは今はいらないので後半の接続方法のところを参考にしてやればOKです。