Introduction

这篇文章是对小米手环7第三方小程序开发所作的复盘和教程。目前小米手环7只支持Zepp OS 1.0,米环8似乎还不知道什么时候会出,因此这篇文章可能还能用个一段时间。

准备工作

阅读这篇文章: https://blog.csdn.net/qq_34520882/article/details/127040418
Zepp OS的官方文档,大部分的信息都来自这里。
其他设备使用Zeus和模拟器会有更多功能/更兼容,但是小米手环所能用的功能基本只有:

  • zeus create 创建 Zepp OS 小程序或表盘项目
    • 命令行交互式问答的形式,体验更友好
    • 多种项目模版可以选择
  • zeus dev 编译预览
    • 连接模拟器,预览项目
    • 监听项目代码改动,自动刷新
  • zeus build 构建应用 zab 包

创建App

![[Pasted image 20230122152733.png]]
使用如上命令行创造新app
![[Pasted image 20230122153001.png]]
使用zeus dev来预览项目。

模拟器可以在官网下载,使用教程:
https://docs.zepp.com/zh-cn/docs/guides/tools/simulator/

安装教程:
https://docs.zepp.com/zh-cn/docs/guides/tools/simulator/setup/#windows-%E7%89%88%E6%9C%AC%E5%AE%89%E8%A3%85

开发

选择gtr3作为开发模板,主页面为index.page.js

常见代码

const globalData = getApp()._options.globalData;
可以获得全局变量,变量的初始value在app.js设定

1
2
3
4
5
App({
globalData: {
duration:0,
interval_list:[]
},

`const logger = DeviceRuntimeCore.HmLogger.getLogger(“helloworld”);``
没有他就没有办法debug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Page({
build() {
logger.debug('page build invoked')
hmUI.createWidget(hmUI.widget.TEXT, {
...TEXT_STYLE,
})
},
onInit() {
logger.debug('page onInit invoked')
},

onDestroy() {
logger.debug('page onDestroy invoked')
},
})

三个函数顾名思义,分别在打开,生成,退出三个阶段执行。我们大部分的代码会在build里写。

hmUI

hmUI的用法在官方文档里都能找到。在这里首先推荐使用以下代码生成一个小米手环7屏幕大小的长方形作为参考。因为模拟器的大小是gtr3的正方形屏幕大小。

1
2
3
4
5
6
7
8
// hmUI.createWidget(hmUI.widget.FILL_RECT, {
// x: 0,
// y: 0,
// w: 192,
// h: 490,
// radius: 20,
// color: 0x1f1f1f, //background color
// });
常见用法
生成多个按钮
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const dataList = [
{ name: "2min", value: 2 },
...
];

for (var i = 0; i < dataList.length; i++) {
let value = dataList1[i].value
hmUI.createWidget(hmUI.widget.BUTTON, {
...
text: dataList1[i].name,
...
normal_color: 0x999999,
press_color: 0xffffff,
click_func: () => {
globalData.duration = value;
});
}

使用一个array of objects来map名字和value到按钮上。
同样的做法可以生成一行行的Text或者其他hmUI控件。

在设定位置的时候注意

1
2
3
4
5
x: 30, //x不变
y: 20+i * 60, //高度每次多60px
text: dataList1[i].name,
w: 60,
h: 60, //长高60,和上面的高度变化保持大概一致

控件位置的计算为左上角是xy,往右往下分别形成w和h的宽高

跳转页面
1
2
3
click_func: () => {
hmApp.gotoPage({ url: "page/gtr3/home/aboutPage" })
},

注意,新页面必须在app.json里面注册(添加url)`

1
2
3
4
5
6
7
"gtr3": {
"module": {
"page": {
"pages": [
"page/gtr3/home/index.page",
"page/gtr3/home/aboutPage"
],

并且注意不要注册到其他设备了。

改变控件状态

在React.js里,我们使用setState来进行状态改变和重新render。在这里我们使用setProperty

1
2
3
4
5
6
7
8
9
10
click_func: () => {

startButton.setProperty(hmUI.prop.MORE, {
text: "Start " + globalData.duration + "m",
...
click_func: () => {
...
},
});
},

👆在一个button里使用onclick来改变另外一个button的样式。

index.style.js

基本等于外挂css,想用可以用:

1
2
3
4
5
6
export const TEXT_STYLE = {
...
}

//在index.page.js
import { TEXT_STYLE } from "./index.style";
更新全局变量

以按钮举例,在生成多个按钮的时候:

let value = dataList[i].value

click_func:
globalData.interval_list.push({value:value})

这个是当interval_list是个array时的用法。

返回
1
2
3
click_func: () => {
hmApp.goBack()
},
计时器
1
2
const timer1 = timer.createTimer(0, 1000, function () {
});

每过1秒,执行一次function ()的内容,开始没有延迟。

倒计时

1
2
3
4
5
6
7
8
let option = { minutes: minute - 1, second: 60 };
let index = 0
let timePassed = 0

const countdown = hmUI.createWidget(hmUI.widget.TEXT, {
text: option.minutes+':'+option.second,
...
});```

初始化一些counter和display text

初始化timer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const timer1 = timer.createTimer(0, 1000, function () {
option.second = option.second - 1; //秒数减一
if (option.second == 0 && option.minutes == 0) {
timer.stopTimer(timer1);
} //秒数和分钟数为零,结束timer

if (option.second == 0 && option.minutes!= 0) {
option.minutes -= 1;
option.second = 59;
} //秒数为零,分钟不为零,分钟-1,秒数回到59

if(option.second==0){
displaySec = "00" //如果秒数为0,显示00
}else if(option.second<=9){//如果秒数为单位数,显示0+数字
displaySec = "0"+parseInt(option.second)
}else{//其他情况,正常显示
displaySec = option.second
}

countdown.setProperty(hmUI.prop.MORE,{ //显示秒数
// text: gettext('appName'),
text: option.minutes+':'+ displaySec,
...
})
});

振动

const vibrate = hmSensor.createSensor(hmSensor.id.VIBRATE)

间隔振动

假设振动间隔先5后10,则使用array[5,10]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
timePassed+=1 //每次timer循环,记录累计时间
if(timePassed==globalData.interval_list[index].value){
//如果累计时间达到期待值,使用下面代码振动和调节强度
vibrate.stop()
vibrate.scene = 24
vibrate.start()
//--
//振动后重制累计时间
timePassed=0 //reset
index+=1 //跳到下一个间隔
if(index==globalData.interval_list.length){
index=0
} //如果下一个间隔没有了,跳回第一个
}
常亮
1
2
3
click_func: () => {
hmApp.startApp({ url: "Settings_displayBrightScreen", native: true });
},

跳到设置页面,注意跳回来的时候全局变量会清空。

发表

使用zeus build生成bin文件,具体操作可以看上面的外部教程。
bin文件可以用表盘自定义工具上传下载进行测试。如果你是ios,用安卓模拟器也可以。

下载蓝叠模拟器,下载表盘自定义工具的apk-注意版本要最新,把bin文件拖入模拟器就可以从模拟器文件系统使用了。

https://wwd.lanzoul.com/i0Mmc0dipc6f

好像这个可以下载。

Debug

因为![[Pasted image 20230122172549.png]]
模拟器的console不能显示具体错误信息,我们可以用大的try catch包住整个build里面的代码然后再print错误。