##主要功能介绍##
1、精简的库大小
2、方便简洁、易拓展、定制性强的API - 更快速开发
3、支持兼容多个手表系统 - android wear谷歌版和中国版、ticwear、duwear
4、连接及通信自适应适配 - 无需关心手表系统 只需关心业务逻辑
5、生命周期内部管理 - 无需关心生命周期 只需关心业务逻辑
6、声明一个监听服务即可兼容多个手表系统
7、丰富的工具类 - 更快速开发
8、手表无需联网 也可在手表端直接发起网络
9、可以以布局文件的形式 构建自定义表盘
10、支持多种数据形式的通信 - 字节流、字符串、图片、文件、键值对
11、支持全双工双向通信
涉及设备通信相关包含数据发送、数据监听、统计分析、自定义事件、错误日志、独立网络请求、云更新。
Mobile端uses-sdk配置
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="22" />
Wearable端uses-sdk配置
<uses-sdk
android:minSdkVersion="18"
android:targetSdkVersion="22" />
Mobile端及Wearable端的平台兼容性配置 创建res/values/wearable_service_version.xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- google play service版本号-->
<integer name="google_play_services_version">6587000</integer>
<!-- duwear连接服务版本号-->
<integer name="open_wearable_service_version">1000000</integer>
<!-- android wear中国版连接服务版本号-->
<integer name="android_wear_china_services_version">7887000</integer>
</resources>
Mobile端及Wearable端初始化代码
OpenWatchCommunication.init(context);
声明所需要兼容的Android Wear谷歌版、Android Wear中国版、DuWear连接服务的版本号(TicWear不需要)
兼容Android Wear谷歌版
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
兼容Android Wear中国版
<meta-data
android:name="com.google.android.wearable.version"
android:value="@integer/android_wear_china_services_version" />
兼容Duwear
<meta-data
android:name="org.owa.wear.ows.sdk.version"
android:value="@integer/open_wearable_service_version" />
可以自定义内部线程池
例如
OpenWatchCommunication.setTheadPool(Executors.newCachedThreadPool());
若不设置,则内部默认使用newCachedThreadPool创建的线程池,线程优先级为Process.THREAD_PRIORITY_BACKGROUND的非守护线程。
需要初始化设备通信相关,详见设备通信相关初始化一节。
提供多种手机与手表间的数据发送方式,不用手动管理连接,内部会在必要时自动断开或打开连接,不需要再关心设备连接、通信、数据层,且所发送的数据均没有大小限制,无论是手机端还是在手表端,代码写法及逻辑相同。
无需再导入其他第三方系统平台的开发jar包。
每种数据发送行为都由path和data组成:
- path:自定义的任意字符串,用于标识该数据发送行为的唯一性。
- data:所发送的任意类型数据,可以是基本数据类型、字节流、图片或者map类型,详见Demo。
1、数据存储和手机与手表间的自动同步,当配对设备未连接,数据并不会被丢失,会在下次连接上配对设备时接收到数据:
OpenWatchSender.sendData(context, "/send_data", "hello openwatch", new SendListener() {
@Override
public void onSuccess() {
// TODO Auto-generated method stub
//发送成功
}
@Override
public void onError(ErrorStatus error) {
// TODO Auto-generated method stub
//发送失败及失败原因
}
});
2、数据以消息的形式发送,当配对设备未连接,数据会被丢失,用于发送临时性或时效性数据:
OpenWatchSender.sendMsg(this, "/send_msg", "hello openwatch", new SendListener() {
@Override
public void onSuccess() {
// TODO Auto-generated method stub
//发送成功
}
@Override
public void onError(ErrorStatus error) {
// TODO Auto-generated method stub
//发送失败及失败原因
}
});
3、有时你的需求场景会需要类似网络请求,数据发送为请求/响应交流模型,可以等待配对设备的响应直到超时。当配对设备未连接,数据会被丢失:
OpenWatchBothWay.request(this, "/send_bothway", "hello openwatch", new BothWayCallback() {
@Override
public void onResponsed(byte[] rawData) {
// TODO Auto-generated method stub
//配对设备响应回来的数据
}
@Override
public void onError(ErrorStatus error) {
// TODO Auto-generated method stub
//数据请求错误及原因
}
});
配对设备接收到对应的请求并响应,同时传入接收到的path
if (path.equals("/send_bothway")) {
OpenWatchBothWay.response(this, path, "response bothway");
}
可设置数据发送的超时时间(默认10秒):
OpenWatchSender.setTimeOutMills(15000);
可设置请求响应的超时时间(默认10秒):
OpenWatchBothWay.setTimeOutMills(15000);
需要初始化设备通信相关,详见设备通信相关初始化一节。
数据接收与监听有两种方式,可任选其一或者两者结合使用,无论是手机端还是在手表端,代码写法及逻辑相同(详见Demo):
1、设置Listener,一般用于activity中,可根据应用具体业务和功能需求,添加不同层面的监听,并在监听的回调函数中接收到配对设备发送的数据:
// 添加设备连接的监听
OpenWatchRegister.addConnectListener(this);
// 添加接收数据的监听
OpenWatchRegister.addDataListener(this);
OpenWatchRegister.addMessageListener(this);
// 添加接收图片、map等特殊类型数据的监听
OpenWatchRegister.addSpecialTypeListener(this);
取消监听
OpenWatchRegister.removeDataListener(this);
OpenWatchRegister.removeConnectListener(this);
OpenWatchRegister.removeMessageListener(this);
OpenWatchRegister.removeSpecialTypeListener(this);
2、设置监听服务:
在配置文件注册监听服务 根据应用想要兼容的智能手表系统,可选择性配置不同的action,action name不可修改
<!-- 继承自OpenWatchListenerService的子类service 下面service name需要修改成自己的类名 -->
<!-- 根据自身业务需求和兼容性需求 可选择性添加不同的intent-filter 其中action name不可修改-->
<service android:name="cn.openwatch.mobile.demo.ListenerService" >
<intent-filter>
<!-- 兼容android wear谷歌版和中国版 -->
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
<!-- 兼容duwear-->
<action android:name="org.owa.wear.ows.BIND_LISTENER" />
<!-- 兼容ticwear -->
<action android:name="com.mobvoi.android.wearable.BIND_LISTENER" />
</intent-filter>
</service>
继承OpenWatchListenerService,内部会管理OpenWatchListenerService的生命周期,当有数据接收到时会启动service,当不需要再工作时销毁service,无需手动管理。
public class ListenerService extends OpenWatchListenerService {
@Override
public void onMessageReceived(String path, byte[] rawData) {
// TODO Auto-generated method stub
Toast.makeText(this, getClass().getSimpleName() + ":配对设备发来临时性数据", Toast.LENGTH_SHORT).show();
}
@Override
public void onDataReceived(String path, byte[] rawData) {
// TODO Auto-generated method stub
Toast.makeText(this, getClass().getSimpleName() + ":配对设备发来数据", Toast.LENGTH_SHORT).show();
}
@Override
public void onDataDeleted(String path, byte[] rawData) {
// TODO Auto-generated method stub
Toast.makeText(this, getClass().getSimpleName() + ":配对设备删除了一条数据", Toast.LENGTH_SHORT).show();
}
@Override
public void onDataMapReceived(String path, DataMap dataMap) {
// TODO Auto-generated method stub
Toast.makeText(this, getClass().getSimpleName() + ":配对设备发来键值对", Toast.LENGTH_SHORT).show();
}
@Override
public void onBitmapReceived(String path, Bitmap bitmap) {
// TODO Auto-generated method stub
Toast.makeText(this, getClass().getSimpleName() + ":配对设备发来图片", Toast.LENGTH_SHORT).show();
}
@Override
public void onFileReceived(SpecialData data) {
// TODO Auto-generated method stub
Toast.makeText(this, getClass().getSimpleName() + ":配对设备发来文件:" + new String(data.getData()), Toast.LENGTH_SHORT)
.show();
//保存成文件
data.receiveFile(getExternalCacheDir() + File.separator + "file.txt");
}
@Override
public void onStreamReceived(SpecialData data) {
// TODO Auto-generated method stub
Toast.makeText(this, getClass().getSimpleName() + ":配对设备发来数据流:" + new String(data.getData()), Toast.LENGTH_SHORT).show();
try {
FileOutputStream fileOutputStream = new FileOutputStream(new File(getExternalCacheDir(), "file.txt"));
//写入到输出流
data.receiveStream(fileOutputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
@Override
public void onInputClosed(String path) {
//在调用SpecialData的receiveStream或receiveFile后回调
Toast.makeText(this, getClass().getSimpleName() + ":保存配对设备发来的数据完成", Toast.LENGTH_SHORT).show();
}
@Override
public void onPeerConnected(String displayName, String nodeId) {
// TODO Auto-generated method stub
Toast.makeText(this, getClass().getSimpleName() + ":和配对设备连接上了 设备名:" + displayName + " 设备id:" + nodeId,
Toast.LENGTH_SHORT).show();
}
@Override
public void onPeerDisconnected(String displayName, String nodeId) {
// TODO Auto-generated method stub
Toast.makeText(this, getClass().getSimpleName() + ":和配对设备断开了连接 设备名:" + displayName + " 设备id:" + nodeId,
Toast.LENGTH_SHORT).show();
}
}
需要初始化设备通信相关,详见设备通信相关初始化一节。
大部分智能手表不可以独立联网,OpenWatch提供了在手表端应用中,可独立发起网络请求的方式,支持get和post请求。
OpenWatchHttp http = new OpenWatchHttp(context);
http.get("http://www.baidu.com", new HttpCallback() {
@Override
public void onResponse(String response) {
// TODO Auto-generated method stub
Log.d(WearListAdapter.class.getName(), response);
Toast.makeText(context, "网络请求响应成功", Toast.LENGTH_SHORT).show();
}
@Override
public void onError(byte[] data, int statusCode, Map<String, String> headers) {
// TODO Auto-generated method stub
Toast.makeText(context, "网络请求响应失败:" + statusCode, Toast.LENGTH_SHORT).show();
}
});
可以自定义网络请求的实现方式
OpenWatchHttp.setCustomHttpCaller(new IHttpCaller() {
@Override
public void setTimeOutMills(int timeOut) {
// TODO Auto-generated method stub
}
@Override
public void getWithHeaders(String url, Map<String, String> params, Map<String, String> headers,
HttpCallback callback) {
// TODO Auto-generated method stub
}
@Override
public void postWithHeaders(String url, byte[] body, Map<String, String> headers, HttpCallback callback) {
// TODO Auto-generated method stub
}
@Override
public void cancelAll() {
// TODO Auto-generated method stub
}
});
OpenWatch提供自定义View或者布局文件的方式创建表盘,并提供时间变化与时区变化回调等(详见Demo)。
public class DigitalWatchFace extends OpenWatchFace {
private TextView timeTextView, dateTextView;
// 构建表盘布局时回调
@Override
public View onCreateView() {
// TODO Auto-generated method stub
//设置表盘样式 指针样式等 此处略
......
View watchface = View.inflate(this, R.layout.digital_watchface_layout, null);
timeTextView = (TextView) watchface.findViewById(R.id.watchface_time_tv);
dateTextView = (TextView) watchface.findViewById(R.id.watchface_date_tv);
// 返回自定义view或者布局文件生成的view
return watchface;
}
// 时区发生改变时回调
@Override
public void onTimeZoneChanged() {
// TODO Auto-generated method stub
super.onTimeZoneChanged();
}
// 时间发生改变时回调
@Override
public void onTimeUpdate(Time time) {
// TODO Auto-generated method stub
super.onTimeUpdate(time);
// 刷新表盘
invalidate();
}
}
改变表盘上的日期和时间显示
@Override
protected void onWatchFaceDraw(Canvas canvas, Rect bounds) {
// TODO Auto-generated method stub
Time time = getTime();
setDate(time);
setTime(time);
super.onWatchFaceDraw(canvas, bounds);
}
private void setDate(Time time) {
String dateStr = (time.month + 1) + "." + time.monthDay + " " + (time.hour > 12 ? "下午" : "上午");
dateTextView.setText(dateStr);
}
private void setTime(Time time) {
String minStr = time.minute < 10 ? "0" + time.minute : String.valueOf(time.minute);
String timeStr = (time.hour > 12 ? time.hour - 12 : time.hour) + ":" + minStr;
timeTextView.setText(timeStr);
}
可设置秒针及相关样式,可设置长宽、纯色指针、图片指针等。
@Override
public View onCreateView() {
// TODO Auto-generated method stub
OpenWatchFaceStyle style = new OpenWatchFaceStyle(this);
// 如果需要的话 构建表盘秒针 否则不会绘制秒针
OpenWatchFaceHand secondHand = new OpenWatchFaceHand();
secondHand.setLength(DisplayUtil.dip2px(this, 10));
secondHand.setWidth(DisplayUtil.dip2px(this, 3));
// 秒针在表盘边界显示
secondHand.setDrawGravity(OpenWatchFaceHand.DRAW_GRAVITY_BORDER);
style.setSecondHand(secondHand);
setStyle(style);
//设置表盘样式 创建布局等 此处略
......
}
可设置onTimeUpdate函数的回调频率模式
//这里设置的模式 表现为交互模式下每秒回调一次 省电模式下每分钟回调一次
setTimeUpdateMode(TIME_UPDATE_PER_SECOND_MODE);
可设置表盘样式
@Override
public View onCreateView() {
// TODO Auto-generated method stub
OpenWatchFaceStyle style = new OpenWatchFaceStyle(this);
// 构建秒针及设置秒针样式等 此处略
......
// 表盘上的通知卡片以单行高度显示
style.setCardPeekMode(OpenWatchFaceStyle.PEEK_MODE_SHORT);
setStyle(style);
//创建布局等 此处略
......
}
声明权限
<uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
在工程中创建res/xml目录,并创建watch_face.xml文件,文件内容为
<?xml version="1.0" encoding="utf-8"?>
<wallpaper xmlns:android="http://schemas.android.com/apk/res/android" />
注册表盘Service,注意要替换name为自定义类,其中label属性为表盘名称。
<service
android:name="cn.openwatch.wearable.demo.DigitalWatchFace"
android:allowEmbedded="true"
android:label="@string/digital_watch_face_name"
android:permission="android.permission.BIND_WALLPAPER" >
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" />
<category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
</intent-filter>
<meta-data
android:name="android.service.wallpaper"
android:resource="@xml/watch_face" />
<!-- 表盘预览图 自行替换android:resource 对于圆形设备 预览图会被裁剪成圆形 -->
<meta-data
android:name="com.google.android.wearable.watchface.preview"
android:resource="@drawable/ic_launcher" />
</service>
若应用想构建多个表盘 则可以自定义多个OpenWatchFace子类,并分别注册多个表盘Service。
Eclipse或其他IDE打包
-keep class cn.openwatch.** {*; }
-dontwarn cn.openwatch.**
Android Studio或Gradle打包
-keep class cn.openwatch.** {*; }
-dontwarn cn.openwatch.**
当发布应用的时候,需要将手表端应用嵌入进手机端应用,因为用户不能直接在手表设备上查看或安装应用。
手机端与手表端应用包名、签名要保持一致,手机端应用声明的权限需要包含手表端应用的所有声明权限。
如果打包正确,当用户安装手机端应用后,系统会自动推送手表端应用到配对的手表设备上。如果应用正在开发或者是用debug签名,这个功能就没效果。
手机端应用模块中的权限声明,需要包含手表端应用模块中的所有权限,否则这个功能也会没有效果。
在开发的时候,需要用adb install命令或者直接用相应的IDE(比如Android studio)来安装。
创建一个res/xml/wearable_app_desc.xml文件,里面包含Android Wear应用的版本和路径信息。例如:
<wearableApp package="wearable.app.package.name">
<versionCode>1</versionCode>
<versionName>1.0</versionName>
<rawPathResId>android_wear_micro_apk</rawPathResId>
</wearableApp>
package, versionCode, 和versionName的值要和手表端应用的AndroidManifest.xml文件中的一样,rawPathResId的值不要改变。
用Android Studio打包
在手机端应用的AndroidManifest.xml文件中,在manifest根标签下添加
xmlns:tools="http://schemas.android.com/tools"
在application标签下添加meta-data 用于引用wearable_app_desc.xml描述文件(针对android wear谷歌版和中国版不需要手动添加手表端App的描述文件,打包的时候,studio会自动添加):
兼容DuWear
<!-- 引用同一个wearable_app_desc文件 需要添加tools:replace="android:resource" 否则打包会报错-->
<meta-data
android:name="org.owa.wear.app"
android:resource="@xml/wearable_app_desc"
tools:replace="android:resource" />
兼容TicWear
<meta-data
android:name="com.mobvoi.ticwear.app"
android:resource="@xml/wearable_app_desc" />
用Eclipse或其他IDE打包
如果你使用的是其他编译方式或者IDE,还可以手动打包。
1、拷贝已签名的手表端应用apk到手机端工程的res/raw目录下,apk重命名为android_wear_micro_apk.apk,文件名不要改变。
3、在手机端应用的AndroidManifest.xml文件中,在application标签下添加一个meta-data 用于引用wearable_app_desc.xml描述文件:
兼容Android Wear谷歌版及中国版
<meta-data android:name="com.google.android.wearable.beta.app"
android:resource="@xml/wearable_app_desc"/>
兼容DuWear
<meta-data
android:name="org.owa.wear.app"
android:resource="@xml/wearable_app_desc" />
兼容TicWear
<meta-data
android:name="com.mobvoi.ticwear.app"
android:resource="@xml/wearable_app_desc" />
##其他##
1、将原生gms谷歌版jar包从几兆精简到了300k
2、删除了原生gms谷歌版jar包中大量的log输出
3、gms谷歌版jar包基于版本6.5 以免用户手机端安装的版本过低 会弹出升级提示
4、gms中国版基于版本7.8
5、为避免gms谷歌版和中国版类名的冲突 用jarjar修改了各自的包名