振动开发指导(C/C++)
=============

#### 场景介绍

当设备需要设置不同的振动效果时，可以调用Vibrator模块，例如：设备的按键可以设置不同强度和不同时长的振动，闹钟和来电可以设置不同强度和时长的单次或周期振动。

详细的接口介绍请参考[Vibrator](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-vibrator)。

#### 函数说明

| 名称 | 描述 |
| :-- | :-- |
| OHOS::Sensors::OH\_Vibrator\_PlayVibration(int32\_t duration, Vibrator\_Attribute attribute) | 控制马达在指定时间内持续振动。 |
| OHOS::Sensors::OH\_Vibrator\_PlayVibrationCustom(Vibrator\_FileDescription fileDescription, Vibrator\_Attribute vibrateAttribute) | 播放自定义振动序列。 |
| OHOS::Sensors::OH\_Vibrator\_Cancel() | 停止马达振动。 |

#### 振动效果说明

目前支持两类振动效果，如下所示。

#### \[h2\]固定时长振动

传入一个固定时长，马达按照默认强度和频率触发振动。

#### \[h2\]自定义振动

自定义振动提供给用户设计自己所需振动效果的能力，用户可通过自定义振动配置文件，并遵循相应规则编排所需振动形式，使能更加开放的振感交互体验。

#### 开发步骤

1.  新建一个Native C++工程。
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/26/v3/ofljHFbqS_2oyWc5Z4wRAw/zh-cn_image_0000002625108249.png?HW-CC-KV=V1&HW-CC-Date=20260612T073449Z&HW-CC-Expire=86400&HW-CC-Sign=E97031CE081D75A5C1399B5ED84B7E53C392B0E1459C4242FF85BC9DACD981D7)
    
2.  控制设备上的振动器，需要申请权限ohos.permission.VIBRATE。具体配置方式请参考[声明权限](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/declare-permissions)。
    
    "requestPermissions": \[
      {
        "name": "ohos.permission.VIBRATE"
      }
    \]
    
3.  CMakeLists.txt文件中引入动态依赖库。
    
    target\_link\_libraries(entry PUBLIC libace\_napi.z.so)
    target\_link\_libraries(entry PUBLIC libhilog\_ndk.z.so)
    target\_link\_libraries(entry PUBLIC libohvibrator.z.so)
    target\_link\_libraries(entry PUBLIC librawfile.z.so)
    
4.  导入模块。
    
    #include <sensors/vibrator.h>
    #include "napi/native\_api.h"
    #include "hilog/log.h"
    #include <thread>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <rawfile/raw\_file\_manager.h>
    
5.  定义常量。
    
    const int VIBRATOR\_LOG\_DOMAIN = 0xD002701;
    const char \*TAG = "\[NativeVibratorTest\]";
    constexpr int32\_t TIME\_WAIT\_FOR\_OP = 2;
    
6.  控制马达在指定时间内持续振动和停止马达振动。
    
    static napi\_value PlayVibrationInDuration(napi\_env env, napi\_callback\_info info)
    {
        Vibrator\_Attribute vibrateAttribute;
        vibrateAttribute.usage = VIBRATOR\_USAGE\_ALARM;
        // 控制马达在指定时间内持续振动。
        int32\_t ret = OH\_Vibrator\_PlayVibration(2000, vibrateAttribute);
        if (ret != 0) {
            OH\_LOG\_Print(LOG\_APP, LOG\_ERROR, VIBRATOR\_LOG\_DOMAIN, TAG, "vibration fail");
            return nullptr;
        }
        OH\_LOG\_Print(LOG\_APP, LOG\_INFO, VIBRATOR\_LOG\_DOMAIN, TAG, "vibration successful");
        std::this\_thread::sleep\_for(std::chrono::milliseconds(TIME\_WAIT\_FOR\_OP));
        // 停止马达振动。
        ret = OH\_Vibrator\_Cancel();
        if (ret != 0) {
            OH\_LOG\_Print(LOG\_APP, LOG\_ERROR, VIBRATOR\_LOG\_DOMAIN, TAG, "cancel vibration fail");
            return nullptr;
        }
        return nullptr;
    }
    
7.  播放自定义振动序列。
    
    static napi\_value PlayVibrationCustom(napi\_env env, napi\_callback\_info info)
    {
        size\_t argc = 1;
        napi\_value argv\[1\] = { nullptr };
        // 获取参数信息
        napi\_get\_cb\_info(env, info, &argc, argv, nullptr, nullptr);
    
        // argv\[0\]即为函数第一个参数Js资源对象，OH\_ResourceManager\_InitNativeResourceManager转为Native对象
        NativeResourceManager \*mNativeResMgr = OH\_ResourceManager\_InitNativeResourceManager(env, argv\[0\]);
        if (mNativeResMgr == nullptr) {
            OH\_LOG\_Print(LOG\_APP, LOG\_ERROR, VIBRATOR\_LOG\_DOMAIN, TAG, "Get native resource manager failed");
            return nullptr;
        }
        // 获取rawfile指针对象
        std::string fileName = "coin\_drop.json";
        RawFile \*rawFile = OH\_ResourceManager\_OpenRawFile(mNativeResMgr, fileName.c\_str());
        if (rawFile == nullptr) {
            OH\_ResourceManager\_ReleaseNativeResourceManager(mNativeResMgr);
            OH\_LOG\_Print(LOG\_APP, LOG\_ERROR, VIBRATOR\_LOG\_DOMAIN, TAG, "Get native rawFile failed");
            return nullptr;
        }
        // 获取rawfile的描述符RawFileDescriptor {fd, offset, length}
        RawFileDescriptor descriptor;
        OH\_ResourceManager\_GetRawFileDescriptor(rawFile, descriptor);
        Vibrator\_FileDescription fileDescription = {
            .fd = descriptor.fd,
            .offset = descriptor.start,
            .length = descriptor.length
        };
        Vibrator\_Attribute vibrateAttribute = {
            .usage = VIBRATOR\_USAGE\_RING
        };
        // 播放自定义振动序列。
        int32\_t ret = OH\_Vibrator\_PlayVibrationCustom(fileDescription, vibrateAttribute);
        bool isSuccess = ((ret == 0) || (ret == UNSUPPORTED));
        if (!isSuccess) {
            OH\_LOG\_Print(LOG\_APP, LOG\_INFO, VIBRATOR\_LOG\_DOMAIN, TAG, "Vibratecustom fail");
        } else {
            OH\_LOG\_Print(LOG\_APP, LOG\_INFO, VIBRATOR\_LOG\_DOMAIN, TAG, "Vibratecustom successful");
        }
        std::this\_thread::sleep\_for(std::chrono::milliseconds(TIME\_WAIT\_FOR\_OP));
        // 停止马达振动。
        OH\_Vibrator\_Cancel();
        // 关闭打开的指针对象
        OH\_ResourceManager\_CloseRawFile(rawFile);
        OH\_ResourceManager\_ReleaseNativeResourceManager(mNativeResMgr);
        return nullptr;
    }
    
8.  在Init函数中补充接口。
    
    EXTERN\_C\_START
    static napi\_value Init(napi\_env env, napi\_value exports)
    {
        napi\_property\_descriptor desc\[\] = {
            {"playVibrationInDuration", nullptr, PlayVibrationInDuration, nullptr, nullptr, nullptr, napi\_default, nullptr},
            {"playVibrationCustom", nullptr, PlayVibrationCustom, nullptr, nullptr, nullptr, napi\_default, nullptr}
        };
        napi\_define\_properties(env, exports, sizeof(desc) / sizeof(desc\[0\]), desc);
        return exports;
    }
    EXTERN\_C\_END
    
9.  在types/libentry路径下index.d.ts文件中引入Napi接口。
    
    export const playVibrationInDuration: () => object;
    export const playVibrationCustom: (resmgr: object) => object;
    
10.  编写程序入口调用代码。
     
     import { BusinessError } from '@kit.BasicServicesKit';
     import { hilog } from '@kit.PerformanceAnalysisKit';
     import { resourceManager } from '@kit.LocalizationKit';
     import vibratorCapi from 'libentry.so';
     
     const DOMAIN = 0xD002701;
     // ...
               try {
                 vibratorCapi.playVibrationInDuration();
                 // ...
               } catch (error) {
                 let e: BusinessError = error as BusinessError;
                 hilog.error(DOMAIN, 'testTag', \`Failed to invoke playVibrationInDuration. Code: ${e.code}, message: ${e.message}\`);
               }
               // ...
               try {
                 vibratorCapi.playVibrationCustom(this.getUIContext().getHostContext()?.resourceManager);
                 // ...
               } catch (error) {
                 let e: BusinessError = error as BusinessError;
                 hilog.error(DOMAIN, 'testTag', \`Failed to invoke playVibrationCustom. Code: ${e.code}, message: ${e.message}\`);
               }