目前Android Wear分国际版本和中国版本,主要是因为GooglePlayService在国内无法使用。当然使用的库也不一样(国内版本其实就是国际版本的阉割版)。但这个库只是在手机侧不一样,在手表侧的库是一样的,使用标准的Android Wear 库就可以。
一、基础开发流程
手表应用主要有两种,一种为可以单独在手表上使用,比如表盘应用。这类应用与普通的Android 应用开发流程没有太大区别。另一种就是手表侧应用需要与手机侧应用进行数据交互,这个需要分别在手表和手机端开发,此时需要注意一点,手表端与手机端的应用必须是包名相同,并且签名也一样,手机端的应用权限需要包括手表端的权限,否则两个应有无法通讯。应该也是基于安全性考虑吧。
先看一下手表应用开发流程:
1.1、创建Wear工程
Android Studio本身就有一个创建手表应用的向导,菜单File->New->New Project 然后填好应用名称及包名,选择下一步,这里是选择目标设备,要选择Wear,如下图:
这里选择你要创建应用的类型.选择下一步,输入Activity及布局XML的名称,选择完成,Android Studio 的向导就会自动完成。
1.2、修改build.gralde
在应用模块的 build.gradle 文件中:
- 在 android 部分,确认 compileSdkVersion 设为 26。
- 在 android 部分,确认 targetSdkVersion 设为 26。
- 更新 dependencies 部分。第一个依赖关系针对的是 Wear 界面库,该库中包含体现了最佳做法的类。第二个依赖关系针对的是穿戴式设备支持库,该库包含其他类(包括适用于表盘主题的类):
dependencies {
implementation 'androidx.wear:wear:1.0.0'
implementation 'com.google.android.support:wearable:2.5.0'
compileOnly 'com.google.android.wearable:wearable:2.5.0'
}
1.3、配置AndroidManifest.xml
- 在应用的 Android 清单文件 (AndroidManifest.xml) 中,指明您的应用是独立应用。具体而言,添加 meta-data 标记,如下所示:
查找 <application> 标记。
使用一个名称为 com.google.android.wearable.standalone 且值为 true 的 meta-data 标记作为上述标记的子标记。
<application>
...
<meta-data
android:name="com.google.android.wearable.standalone"
android:value="true" />
...
</application>
- 在 Android 清单文件中,确保已定义 <uses-feature> 标记。至少必须使用 android:name="android.hardware.type.watch" 定义该标记,如下所示:
<manifest>
...
<uses-feature android:name="android.hardware.type.watch" />
...
</manifest>
二、手机应用和手表应用之间的差异
下面是手机应用和手表应用之间的一些差异:
- 手表除了能使用传统的控件库之外,还可以使用一些针对手表定制的界面库(例如,针对圆形布局、穿戴式设备抽屉式导航栏):
- android.support.wear.ambient
- android.support.wear.widget
- android.support.wear.widget.drawer
- 手表应用可以使用许多标准的 Android API,但不支持以下 API:
- android.webkit
- android.print
- android.app.backup
- android.appwidget
- android.hardware.usb
在使用某个 API 之前,您可以通过调用 hasSystemFeature() 来检查手表是否支持某项功能。
举个栗子
我们可以看下刚刚创建的Wear工程中的Activity和Layout:
Activity
使用WearableActivity
MainActivity继承WearableActivity,WearableActivity是专门适用于手表设备的Activity基类,它继承至Activity,它支持了手表的息屏模式(也算省电模式的一种),息屏模式主要是通过WearableActivity的onEnterAmbient、onUpdateAmbient、onExitAmbient三个函数来实现。分别为进入息屏模式,更新息屏模式和退出息屏模式。
使用普通的Activity
另外MainActivity也是可以继承手机那一套Activity,比如FragmentActivity,然后实现AmbientCallbackProvider接口。
实现该接口的getAmbientCallback方法,返回一个AmbientCallback实例。
实际上就是将WearableActivity中支持息屏模式的三个方法抽象到AmbientCallback接口中,方便开发者使用。
要使用息屏模式需要设置setAmbientEnabled()。正常与息屏模式界面对比如下图:
Layout
为 Wear OS 应用创建布局时,您需要考虑到设备会具有方形和圆形屏幕。在圆形 Wear OS 设备上,屏幕角落附近的内容可能会被剪裁掉。因此,为方形屏幕设计的布局在圆形设备上可能会出现显示问题。
例如,下图展示了以下布局在方形屏幕和圆形屏幕上的显示效果:
因此,为布局使用以下设置时,文本在具有圆形屏幕的设备上无法正确显示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_square" />
</LinearLayout>
可以通过两种方法解决此问题:
- 对方形设备和圆形设备都使用 Wear 界面库中的布局。
- BoxInsetLayout - 此布局根据设备屏幕的形状应用不同的窗口边衬区。如果您要对这两种屏幕形状使用相似的布局而又不希望圆形屏幕边缘附近的视图被剪裁掉,则可以使用此方法。
- 曲线布局 - 当您要显示和操作针对圆形屏幕优化过的垂直项目列表时,可使用此布局。
- 按照提供资源指南中所述,为方形设备和圆形设备提供备用布局资源。在运行时,Wear 会检测设备屏幕的形状并加载正确的布局。
使用 BoxInsetLayout
您可以使用 Wear 界面库中的 BoxInsetLayout 类,定义同时适用于方形和圆形屏幕的布局。此类会根据屏幕形状应用所需的窗口边衬区,并可让您轻松地在屏幕中心或边缘附近对齐视图。
效果如下:
上图中的灰色方形区域显示了在应用所需的窗口边衬区后,BoxInsetLayout 可在圆形屏幕上自动放置其子视图的区域。要使子视图显示在此区域内,需要为子视图的 boxedEdges 属性指定以下值:
- top、bottom、left 和 right 的组合。例如,"left|top" 值可将子视图的左侧边缘和顶部边缘定位在图 2 中的灰色方形内。
- "all" 值可将整个子视图定位在图 2 中的灰色方形内。
在方形屏幕上,窗口边衬区为零,并且会忽略 boxedEdges 属性。
上图中显示的布局使用了 <BoxInsetLayout> 元素,同时适用于方形屏幕和圆形屏幕:
<android.support.wear.widget.BoxInsetLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:padding="15dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp"
app:boxedEdges="all">
<TextView
android:gravity="center"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/sometext"
android:textColor="@color/black" />
<ImageButton
android:background="@null"
android:layout_gravity="bottom|left"
android:layout_height="50dp"
android:layout_width="50dp"
android:src="@drawable/ok" />
<ImageButton
android:background="@null"
android:layout_gravity="bottom|right"
android:layout_height="50dp"
android:layout_width="50dp"
android:src="@drawable/cancel" />
</FrameLayout>
</android.support.wear.widget.BoxInsetLayout>
使用曲线布局
您可以通过 Wear 界面库中的 WearableRecyclerView 类,选择使用针对圆形屏幕进行了优化的曲线布局。要为应用中的可滚动列表启用曲线布局,请参阅创建曲线布局。
对方形屏幕和圆形屏幕使用不同的布局
Wear 设备可能具有方形屏幕或圆形屏幕。您的应用需要能够支持任一设备配置。为此,您应提供备用资源。将 -round 和 -notround资源限定符应用于布局、尺寸或其他资源类型。
例如,考虑按如下方式组织布局:
- layout/ 目录包含同时适用于圆形和方形手表的布局。
- layout-round/ 和 layout-notround/ 目录包含特定于屏幕形状的布局。
您还可以使用 res/values、res/values-round 和 res/values-notround 资源目录。以这种方式组织资源,您可以共享一个布局,仅需根据设备类型更改特定属性即可。
三、手表与手机通讯原理及开发
Android Wear手表应用与手机应用通讯可以有多种方式,有传统的方式,也有新的方式。
传统方式:通知
新引入方式:MessageApi,DataItem
传统方式:通知
这个是与手机通知栏生成的消息是一样的,可以通过Notification.Builder来创建。考虑到手表屏幕的特殊性(比如:一个通知可以有多条信息,允许添加可访问的动作等),也可以使用Android Wear 的扩展类WearableExtender,使用实例如下:
NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender();
wearableExtender
.addAction(Action)
.addPage(Notificaton);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(“My first notification”)
.setContentText(“My first message”)
.extend(wearableExtender)
.build();
新方式:连接服务
连接到手机或者手表需要用到GoogleApiClient这个类,通过设置监听,调用connect来实现,具体如下:
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(Wearable.API)
.addConnectionCallbacks(GoogleApiClient.ConnectionCallbacks)
.addOnConnectionFailedListener(GoogleApiClient.OnConnectionFailedListener)
.build();
mGoogleApiClient.connect();
- 接口:GoogleApiClient.ConnectionCallbacks用来确认连接是否成功,分别有以下两个回调接口:
- Public void onConnected(Bundle bundle)-服务连接成功
- public void onConnectionSuspended(int i)-服务连接中断
- 接口:GoogleApiClient.OnConnectionFailedListener用来连接失败的回调:
- public void onConnectionFailed(ConnectionResult connectionResult)
新方式:连接设备
获取连接设备:
- Wearable.NodeApi.getConnectedNodes(GoogleApiClient);
或者通过实现NodeApi.NodeListener的两个接口:
- public void onPeerConnected(Node peer) –设备连接成功
- public void onPeerDisconnected(Node peer)-设备连接失败
再然后通过Wearable.NodeApi.addListener(GoogleApiClient, NodeApi.NodeListener)来设置
新方式:发送数据
发送数据有两种方式:
- Wearable.MessageApi.sendMessage(GoogleApiClient googleApiClient, String nodeId, String path, byte[] data)
- Wearable.DataApi.putDataItem(GoogleApiClient googleApiClient, PutDataRequest request)
sendMessage来发送少量数据(data不能大于100K。大数据,比如:图片、文件等需要通过第二种方式来发送),主要参数含义如下:
- Nodeid 这个是要发送数据的节点id
- Path 这个路径,实际可以看这消息的类型
- Data 你要发送的数据(不能大于100K)
putDataItem这个实际上是用来节点之间同步数据的。这里需要有个特别注意的地方,你相邻发送的两个数据一定要是变化的,对方才能接收到。所以在生成request时为了保证与之前数据不一样。通用常会request.getDataMap().putLong(KEY_DATA_ITEM_ID, new Date().getTime());参数request含义为要发送的数据,通常使用request.getDataMap().putXXX来加入数据
新方式:接收数据
对应发送数据,接收数据也有两种方式:
- public void onMessageReceived(MessageEvent messageEvent)
- public void onDataChanged(DataEventBuffer dataEventBuffer)
分别是通过继承:
- DataApi.DataListener
- MessageApi.MessageListener
再通过下面两个方法来设置:
- Wearable.DataApi.addListener(GoogleApiClient, DataListener);
- Wearable.MessageApi.addListener(GoogleApiClient, MessageListener);
另外新方式对设备连接的监控,数据的接收等也可以通过继承 WearableListenerService 来统一处理,它继承于Service,是一个服务。具体接口如下:
- public void onDataChanged(DataEventBuffer dataEvents)
- public void onMessageReceived(MessageEvent messageEvent)
- public void onPeerConnected(Node peer)
- public void onPeerDisconnected(Node peer)
四、Android Wear 2.0中主要新增的功能
增加Wifi及3G/4G通讯功能,完全摆脱依赖手机
五、Android Wear应用发布
Android Wear应用如果是手表端一个独立的应用,可以直接发布。如果这个应用包括了手表与手机端,通常手表端的应用发布是与主版本一起打包发布,安装到手机后,如果与手表连接,则系统会自动安装到手表,具体步骤如下:
- 手机侧应用权限需要包含手表侧应用权限
- 将手表侧应用放到res/raw目录下面,假设取名:qqmusic_for_android_wear.apk
- 在手机侧应用创建包括手表侧应用的版本和路径信息的res/xml/qqmusic_for_android_wear_desc.xml文件
<wearableApp package="wearable.app.package.name">
<versionCode>1</versionCode>
<versionName>1.0</versionName>
<rawPathResId> qqmusic_for_android_wear</rawPathResId>
</wearableApp>
其中,package、versionCode和versionName需要和手表侧应用的AndroidManifest.xml中的值相同。rawPathResId是手表侧应用的名字,例如:qqmusic_for_android_wear.apk的resPathResId为qqmusic_for_android_wear。
- 在手机侧应用的AndroidManifest文件中的标签中增加来指明qqmusic_for_android_wear_desc.xml文件,如下设置:
<meta-data android:name=”com.google.android.wearable.beta.app”
android:resource="@xml/ qqmusic_for_android_wear_desc"/>
这样编译并发布手机侧应用就可以了。