• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 振动开发指导(ArkTS)
2<!--Kit: Sensor Service Kit-->
3<!--Subsystem: Sensors-->
4<!--Owner: @dilligencer-->
5<!--Designer: @butterls-->
6<!--Tester: @murphy84-->
7<!--Adviser: @hu-zhiqiong-->
8
9## 场景介绍
10
11当设备需要设置不同的振动效果时,可以调用Vibrator模块,例如:设备的按键可以设置不同强度和不同时长的振动,闹钟和来电可以设置不同强度和时长的单次或周期振动。
12
13详细的接口介绍请参考[Vibrator接口](../../reference/apis-sensor-service-kit/js-apis-vibrator.md)。
14
15
16## 接口说明
17
18| 名称                                                         | 描述                                                                          |
19| ------------------------------------------------------------ |-----------------------------------------------------------------------------|
20| startVibration(effect: VibrateEffect, attribute: VibrateAttribute): Promise&lt;void&gt; | 根据指定振动效果和振动属性触发马达振动,使用Promise异步回调。                                          |
21| startVibration(effect: VibrateEffect, attribute: VibrateAttribute, callback: AsyncCallback&lt;void&gt;): void | 根据指定振动效果和振动属性触发马达振动,使用Callback异步回调。                                         |
22| stopVibration(stopMode: VibratorStopMode): Promise&lt;void&gt; | 按照指定模式停止马达的振动,使用Promise异步回调。                                                |
23| stopVibration(stopMode: VibratorStopMode, callback: AsyncCallback&lt;void&gt;): void | 按照指定模式停止马达的振动,使用Callback异步回调。                                               |
24| stopVibration(): Promise&lt;void&gt;                         | 停止所有模式的马达振动,使用Promise异步回调。                                                  |
25| stopVibration(param?: VibratorInfoParam): Promise&lt;void&gt; | 不传参则停止本地设备所有马达的振动,也可传参停止指定马达振动,使用Promise异步回调。                                 |
26| stopVibration(callback: AsyncCallback&lt;void&gt;): void     | 停止所有模式的马达振动,使用Callback异步回调。                                                 |
27| isSupportEffect(effectId: string): Promise&lt;boolean&gt;    | 查询是否支持传入的参数effectId。返回true则表示支持,否则不支持,使用Promise异步回调。                        |
28| isSupportEffect(effectId: string, callback: AsyncCallback&lt;boolean&gt;): void | 查询是否支持传入的参数effectId。返回true则表示支持,否则不支持,使用Callback异步回调。                       |
29| getEffectInfoSync(effectId: string, param?: VibratorInfoParam): EffectInfo | 同步查询是否支持传入的参数effectId,param可指定具体马达。返回EffectInfo中isEffectSupported字段可判断是否支持。 |
30| getVibratorInfoSync(param?: VibratorInfoParam): Array&lt;VibratorInfo&gt; | 同步查询一个或所有设备的马达信息列表。返回VibratorInfo包含设备ID、马达ID、设备名称、是否支持高清振动、是否本地设备等信息。       |
31| on(type: 'vibratorStateChange', callback: Callback&lt;VibratorStatusEvent&gt;): void | 注册马达设备上线下状态变化的监听。callback参数VibratorStatusEvent可返回事件时间戳、设备ID、马达数量、上线或下线等信息。  |
32| off(type: 'vibratorStateChange', callback?: Callback&lt;VibratorStatusEvent&gt;): void | 注销马达设备上线下状态变化的监听。                                                           |
33
34
35## 振动效果说明
36
37目前支持三类振动效果,如下所示:
38
39| 名称         | 说明                                                         |
40| ------------ | ------------------------------------------------------------ |
41| 固定时长振动 | 传入一个固定时长,马达按照默认强度和频率触发振动,振动效果描述请参考[VibrateTime](../../reference/apis-sensor-service-kit/js-apis-vibrator.md#vibratetime9)。 |
42| 预置振动     | 系统中的[预置振动效果](../../reference/apis-sensor-service-kit/js-apis-vibrator.md#effectid),这些效果适用于某些固定场景,比如效果"haptic.clock.timer"通常用于用户调整计时器时的振感反馈,振动效果描述请参考[VibratePreset](../../reference/apis-sensor-service-kit/js-apis-vibrator.md#vibratepreset9)。 |
43| 自定义振动   | 自定义振动提供给用户设计自己所需振动效果的能力,用户可通过自定义振动配置文件,并遵循相应规则编排所需振动形式,使能更加开放的振感交互体验,效果描述请参考[VibrateFromFile](../../reference/apis-sensor-service-kit/js-apis-vibrator.md#vibratefromfile10)。 |
44
45自定义振动配置文件为Json格式,在形式上如下所示:
46
47```json
48{
49    "MetaData": {
50        "Create": "2023-01-09",
51        "Description": "a haptic case",
52        "Version": 1.0,
53        "ChannelNumber": 1
54    },
55    "Channels": [
56        {
57            "Parameters": {
58                "Index": 0
59            },
60            "Pattern": [
61                {
62                    "Event": {
63                        "Type": "transient",
64                        "StartTime": 0,
65                        "Parameters": {
66                            "Frequency": 31,
67                            "Intensity": 100
68                        }
69                    }
70                },
71                {
72                    "Event": {
73                        "Type": "continuous",
74                        "StartTime": 40,
75                        "Duration": 54,
76                        "Parameters": {
77                            "Frequency": 30,
78                            "Intensity": 38,
79                            "Curve": [
80                                {
81                                    "Time": 0,
82                                    "Frequency": 0,
83                                    "Intensity": 0
84                                },
85                                {
86                                    "Time": 1,
87                                    "Frequency": 15,
88                                    "Intensity": 0.5
89                                },
90                                {
91                                    "Time": 40,
92                                    "Frequency": -8,
93                                    "Intensity": 1.0
94                                },
95                                {
96                                    "Time": 54,
97                                    "Frequency": 0,
98                                    "Intensity": 0
99                                }
100                            ]
101                        }
102                    }
103                }
104            ]
105        }
106    ]
107}
108```
109
110Json文件共包含3个属性。
1111. "MetaData"属性中为文件头信息,可在如下属性中添加描述:
112
113     | 名称          | 必填项 | 说明                                          |
114     | ------------- | ------ | --------------------------------------------- |
115     | Version       | 是     | 文件格式的版本号,向前兼容,目前支持版本1.0。 |
116     | ChannelNumber | 是     | 表示马达振动的通道数,最大支持双马达通道。    |
117     | Create        | 否     | 可记录文件创作时间。                          |
118     | Description   | 否     | 可指明振动效果、创建信息等附加说明。          |
119
1202. "Channels"属性中为马达振动通道的相关信息。
121
122     "Channels"是Json数组,表示各个通道的信息,包含2个属性。
123
124     | 名称       | 必填项 | 说明                                                         |
125     | ---------- | ------ | ------------------------------------------------------------ |
126     | Parameters | 是     | 为通道参数。其中"Index"表示通道编号,0表示全通道发送,1、2分别对应左右马达。0不能与其他通道编号同时作为配置参数。 |
127     | Pattern    | 否     | 马达振动序列。                                               |
128
129     "Pattern"是Json数组,包含振动事件序列,每个"Event"属性代表1个振动事件,支持添加2种振动类型。
130
131     | 振动类型   | 说明                                           |
132     | ---------- | ---------------------------------------------- |
133     | transient  | 瞬态短振动,干脆有力。                         |
134     | continuous | 稳态长振动,具备长时间输出强劲有力振动的能力。 |
135
136     "Event"表示一个振动事件,包含如下属性:
137
138     | 名称      | 必填项 | 说明                                                         |
139     | --------- | ------ | ------------------------------------------------------------ |
140     | Type      | 是     | 振动事件类型,为"transient" 或"continuous"。                 |
141     | StartTime | 是     | 振动的起始时间,单位ms,有效范围为[0, 1800,000]。            |
142     | Duration  | 是     | 振动持续时间,仅当类型为"continuous"时有效,单位ms,有效范围为[0, 5000]。 |
143
1443. "Parameters"表示振动事件参数设置,必填项,可设置以下属性参数:
145
146     | 名称      | 必填项 | 说明                                                         |
147     | --------- | ------ | ------------------------------------------------------------ |
148     | Intensity | 是     | 振动事件强度,有效范围为[0, 100],数字大小代表最大振动量的xx%。 |
149     | Frequency | 是     | 振动事件频率,有效范围为[0, 100],一般支持频率调节的马达设置为55时为器件的谐振频率,此时振动量最大,越靠近谐振频率的振动,同强度设置的振动量越大。 |
150     | Curve     | 否     | 振动曲线,当振动事件类型为"continuous"时有效,为Json数组,支持设置一组调节点,调节点数量最大支持16个,最小为4个,每个调节点需包含如下属性:<br/>"Time":相对事件起始时间的偏移,最小为0,最大不能超过事件振动时长;<br/>"Intensity":相对事件振动强度的增益,范围为[0, 1],此值乘上振动事件强度为对应时间点调节后的强度;<br/>"Frequency":相对事件振动频率的变化,范围为[-100, 100],此值加上振动事件频率为对应时间点调节后的频率。 |
151
152其他要求:
153
154| 参数 | 要求                 |
155| -------- | ------------------------ |
156| 振动事件(event)的数量 | 不得超过128个。 |
157| 振动配置文件长度 | 不得超过64KB。 |
158
159
160## 开发步骤
161
1621. 控制设备上的振动器,需要申请权限ohos.permission.VIBRATE。具体配置方式请参考[声明权限](../../security/AccessToken/declare-permissions.md)。
163
1642. 振动器查询。
165
166  **情形一** 查询所有马达信息:
167
168  ```ts
169   import { vibrator } from '@kit.SensorServiceKit';
170   import { BusinessError } from '@kit.BasicServicesKit';
171
172  try {
173    const vibratorInfoList: vibrator.VibratorInfo[] = vibrator.getVibratorInfoSync();
174    console.log(`vibratorInfoList: ${JSON.stringify(vibratorInfoList)}`);
175  } catch (error) {
176    let e: BusinessError = error as BusinessError;
177    console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
178  }
179  ```
180
181  **情形二** 查询指定设备的一个或多个马达信息:
182
183  ```ts
184   import { vibrator } from '@kit.SensorServiceKit';
185   import { BusinessError } from '@kit.BasicServicesKit';
186
187  try {
188    const vibratorParam: vibrator.VibratorInfoParam = {
189      deviceId: 1    // deviceid 需要是查询出来真实存在的设备
190    }
191    const vibratorInfoList: vibrator.VibratorInfo[] = vibrator.getVibratorInfoSync(vibratorParam);
192    console.log(`vibratorInfoList: ${JSON.stringify(vibratorInfoList)}`);
193  } catch (error) {
194    let e: BusinessError = error as BusinessError;
195    console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
196  }
197  ```
198
1993. 根据指定振动效果和振动属性触发马达振动。
200
201   **情形一** 按照指定持续时间触发马达振动:
202
203   ```ts
204   import { vibrator } from '@kit.SensorServiceKit';
205   import { BusinessError } from '@kit.BasicServicesKit';
206
207   try {
208     // 触发马达振动
209     vibrator.startVibration({
210       type: 'time',
211       duration: 1000,
212     }, {
213       id: 0,
214       usage: 'alarm'
215     }, (error: BusinessError) => {
216       if (error) {
217         console.error(`Failed to start vibration. Code: ${error.code}, message: ${error.message}`);
218         return;
219       }
220       console.info('Succeed in starting vibration');
221     });
222   } catch (err) {
223     let e: BusinessError = err as BusinessError;
224     console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
225   }
226   ```
227
228   **情形二** 按照预置振动效果触发马达振动,可先查询振动效果是否被支持,再调用振动接口:
229
230   ```ts
231   import { vibrator } from '@kit.SensorServiceKit';
232   import { BusinessError } from '@kit.BasicServicesKit';
233
234   try {
235     // 查询是否支持'haptic.effect.soft'
236     vibrator.isSupportEffect('haptic.effect.soft', (err: BusinessError, state: boolean) => {
237       if (err) {
238         console.error(`Failed to query effect. Code: ${err.code}, message: ${err.message}`);
239         return;
240       }
241       console.info('Succeed in querying effect');
242       if (state) {
243         try {
244           // 触发马达振动
245           vibrator.startVibration({
246             type: 'preset',
247             effectId: 'haptic.effect.soft',
248             count: 1,
249             intensity: 50,
250           }, {
251             usage: 'unknown'
252           }, (error: BusinessError) => {
253             if (error) {
254               console.error(`Failed to start vibration. Code: ${error.code}, message: ${error.message}`);
255             } else {
256               console.info('Succeed in starting vibration');
257             }
258           });
259         } catch (error) {
260           let e: BusinessError = error as BusinessError;
261           console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
262         }
263       }
264     })
265   } catch (error) {
266     let e: BusinessError = error as BusinessError;
267     console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
268   }
269   ```
270
271   **情形三** 按照自定义振动配置文件触发马达振动:
272
273   ```ts
274   import { vibrator } from '@kit.SensorServiceKit';
275   import { resourceManager } from '@kit.LocalizationKit';
276   import { BusinessError } from '@kit.BasicServicesKit';
277
278   const fileName: string = 'xxx.json';
279
280   @Entry
281   @Component
282   struct Index {
283     uiContext = this.getUIContext();
284
285     build() {
286       Row() {
287         Column() {
288           Button('alarm-file')
289             .onClick(() => {
290               // 获取文件资源描述符
291               let rawFd: resourceManager.RawFileDescriptor | undefined = this.uiContext.getHostContext()?.resourceManager.getRawFdSync(fileName);
292               if (rawFd != undefined) {
293                 // 触发马达振动
294                 try {
295                   vibrator.startVibration({
296                     type: "file",
297                     hapticFd: { fd: rawFd.fd, offset: rawFd.offset, length: rawFd.length }
298                   }, {
299                     id: 0,
300                     usage: 'alarm' // 根据实际选择类型归属不同的开关管控
301                   }, (error: BusinessError) => {
302                     if (error) {
303                       console.error(`Failed to start vibration. Code: ${error.code}, message: ${error.message}`);
304                       return;
305                     }
306                     console.info('Succeed in starting vibration');
307                   });
308                 } catch (err) {
309                   let e: BusinessError = err as BusinessError;
310                   console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
311                 } finally {
312                   vibrator.stopVibration();
313                   this.uiContext.getHostContext()?.resourceManager.closeRawFdSync(fileName);
314                 }
315               }
316             })
317         }
318         .width('100%')
319       }
320       .height('100%')
321     }
322   }
323   ```
324
3254. 停止马达的振动。
326
327   **方式一** 按照指定模式停止对应的马达振动,自定义振动不支持此类停止方式:
328
329   ​	停止固定时长振动:
330
331   ```ts
332   import { vibrator } from '@kit.SensorServiceKit';
333   import { BusinessError } from '@kit.BasicServicesKit';
334
335   try {
336     // 按照VIBRATOR_STOP_MODE_TIME模式停止振动
337     vibrator.stopVibration(vibrator.VibratorStopMode.VIBRATOR_STOP_MODE_TIME, (error: BusinessError) => {
338       if (error) {
339         console.error(`Failed to stop vibration. Code: ${error.code}, message: ${error.message}`);
340         return;
341       }
342       console.info('Succeed in stopping vibration');
343     })
344   } catch (err) {
345     let e: BusinessError = err as BusinessError;
346     console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
347   }
348   ```
349
350   ​	停止预置振动:
351
352   ```ts
353   import { vibrator } from '@kit.SensorServiceKit';
354   import { BusinessError } from '@kit.BasicServicesKit';
355
356   try {
357     // 按照VIBRATOR_STOP_MODE_PRESET模式停止振动
358     vibrator.stopVibration(vibrator.VibratorStopMode.VIBRATOR_STOP_MODE_PRESET, (error: BusinessError) => {
359       if (error) {
360         console.error(`Failed to stop vibration. Code: ${error.code}, message: ${error.message}`);
361         return;
362       }
363       console.info('Succeed in stopping vibration');
364     })
365   } catch (err) {
366     let e: BusinessError = err as BusinessError;
367     console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
368   }
369   ```
370
371   **方式二** 停止所有模式的马达振动,包括自定义振动:
372
373   ```ts
374   import { vibrator } from '@kit.SensorServiceKit';
375   import { BusinessError } from '@kit.BasicServicesKit';
376
377   try {
378     // 停止所有模式的马达振动
379     vibrator.stopVibration((error: BusinessError) => {
380       if (error) {
381         console.error(`Failed to stop vibration. Code: ${error.code}, message: ${error.message}`);
382         return;
383       }
384       console.info('Succeed in stopping vibration');
385     })
386   } catch (error) {
387     let e: BusinessError = error as BusinessError;
388     console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
389   }
390   ```
391
392   **方式三** 停止指定设备的振动:
393
394   ```ts
395   import { vibrator } from '@kit.SensorServiceKit';
396   import { BusinessError } from '@kit.BasicServicesKit';
397
398   const vibratorInfoParam: vibrator.VibratorInfoParam = {
399     deviceId: 1   // deviceid 需要是查询出来真实存在的设备
400   }
401   try {
402     vibrator.stopVibration(vibratorInfoParam).then(() => {
403       console.info('Succeed in stopping vibration');
404     }, (error: BusinessError) => {
405       console.error(`Failed to stop vibration. Code: ${error.code}, message: ${error.message}`);
406     });
407   } catch (error) {
408     let e: BusinessError = error as BusinessError;
409     console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
410   }
411   ```
412
413
4145. 动态马达状态变化监听。
415
416   注册监听。
417   ```ts
418   import { vibrator } from '@kit.SensorServiceKit';
419   import { BusinessError } from '@kit.BasicServicesKit';
420
421   // 回调函数
422   const vibratorStateChangeCallback = (data: vibrator.VibratorStatusEvent) => {
423     console.log('vibrator state callback info:', JSON.stringify(data));
424   }
425
426   try {
427     // 订阅 vibratorStateChange事件
428     vibrator.on('vibratorStateChange', vibratorStateChangeCallback);
429   } catch (error) {
430     let e: BusinessError = error as BusinessError;
431     console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
432   }
433   ```
434
435   取消监听,取消传入的callback需与注册的一致。
436   ```ts
437   import { vibrator } from '@kit.SensorServiceKit';
438   import { BusinessError } from '@kit.BasicServicesKit';
439
440   // 回调函数
441   const vibratorStateChangeCallback = (data: vibrator.VibratorStatusEvent) => {
442     console.log('vibrator state callback info:', JSON.stringify(data));
443   }
444   try {
445     // 取消订阅 vibratorStateChange事件
446     vibrator.off('vibratorStateChange', vibratorStateChangeCallback);
447     // 取消订阅所有 vibratorStateChange事件
448     // vibrator.off('vibratorStateChange');
449   } catch (error) {
450     let e: BusinessError = error as BusinessError;
451     console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
452   }
453   ```
454
455## 相关实例
456
457针对振动开发,有以下相关实例可供参考:
458
459- [振动(ArkTS)(API9)](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/DeviceManagement/Vibrator/BasicVibration)
460
461- [自定义振动(ArkTS)(Full SDK)(API10)](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic)
462