OpenHarmony开发者论坛

标题: 写一个简单的OpenHarmony蓝牙应用 [打印本页]

作者: 深开鸿_王石    时间: 2023-12-18 16:26
标题: 写一个简单的OpenHarmony蓝牙应用
[md]**此文件就是介绍OpenHarmony中的蓝牙接口和如何自己开发一个简单的蓝牙应用程序。**

### OpenHarmony蓝牙接口简介

| **接口名称**                | **参数**                                                                  | **返回值**               | **作用**             |
| --------------------------------- | ------------------------------------------------------------------------------- | ------------------------------ | -------------------------- |
| **enableBluetooth**         | **()**                                                                  | **boolean**              | **开启蓝牙**         |
| **disableBluetooth**        | **()**                                                                  | **boolean**              | **关闭蓝牙**         |
| **getState**                | **()**                                                                  | **BluetoothState:enum** | **获取蓝牙状态**     |
| **setLocalName**            | **(name: string)**                                                        | **boolean**              | **设置蓝牙名称**     |
| **getLocalName**            | **()**                                                                  | **string**               | **获取蓝牙名称**     |
| **setBluetoothScanMode**    | **(mode: ScanMode, duration: number)**                                    | **boolean**              | **设置蓝牙扫描模式** |
| **startBluetoothDiscovery** | **()**                                                                  | **boolean**              | **发现蓝牙**         |
| **pairDevice**              | **(deviceId: string)**                                                    | **boolean**              | **配对设备**         |
| **on.pinRequired**          | **(type: "pinRequired", callback: Callback<PinRequiredParam**>**)** | **void**                 | **侦听配对请求事件** |
| **disableBluetooth**        | **()**                                                                  | **boolean**              | **关闭蓝牙**         |

> * **getState**
>
> ```
> enum BluetoothState {
>    /** Indicates the local Bluetooth is off */
>    STATE_OFF = 0,
>    /** Indicates the local Bluetooth is turning on */
>    STATE_TURNING_ON = 1,
>    /** Indicates the local Bluetooth is on, and ready for use */
>    STATE_ON = 2,
>    /** Indicates the local Bluetooth is turning off */
>    STATE_TURNING_OFF = 3,
>    /** Indicates the local Bluetooth is turning LE mode on */
>    STATE_BLE_TURNING_ON = 4,
>    /** Indicates the local Bluetooth is in LE only mode */
>    STATE_BLE_ON = 5,
>    /** Indicates the local Bluetooth is turning off LE only mode */
>    STATE_BLE_TURNING_OFF = 6
> ```
>
> * **setBluetoothScanMode**
>
> ```
> enum ScanMode {
>    /** Indicates the scan mode is none */
>    SCAN_MODE_NONE = 0,
>    /** Indicates the scan mode is connectable */
>    SCAN_MODE_CONNECTABLE = 1,
>    /** Indicates the scan mode is general discoverable */
>    SCAN_MODE_GENERAL_DISCOVERABLE = 2,
>    /** Indicates the scan mode is limited discoverable */
>    SCAN_MODE_LIMITED_DISCOVERABLE = 3,
>    /** Indicates the scan mode is connectable and general discoverable */
>    SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE = 4,
>    /** Indicates the scan mode is connectable and limited discoverable */
>    SCAN_MODE_CONNECTABLE_LIMITED_DISCOVERABLE = 5
> }
> ```

### OpenHarmony典蓝牙配对流程

<pre class="md-fences md-end-block md-diagram md-fences-advanced ty-contain-cm modeLoaded" spellcheck="false" lang="mermaid" cid="n72" mdtype="fences" mermaid-type="graph"><div class="md-diagram-panel md-fences-adv-panel"><div class="md-diagram-panel-header"></div><div class="md-diagram-panel-preview"><svg id="mermaidChart0" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="61.59375" viewBox="0 0 587.921875 61.59375" class="in-text-selection"><g><g class="output"><g class="clusters"></g><g class="edgePaths"><g class="edgePath LS-开启蓝牙 LE-设置发现模式" id="L-开启蓝牙-设置发现模式"><path class="path" d="M92,30.796875L117,30.796875L142,30.796875" marker-end="url(#arrowhead17)"></path><defs><marker id="arrowhead17" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath"></path></marker></defs></g><g class="edgePath LS-设置发现模式 LE-注册pinRequest" id="L-设置发现模式-注册pinRequest"><path class="path" d="M258,30.796875L283,30.796875L308,30.796875" marker-end="url(#arrowhead18)"></path><defs><marker id="arrowhead18" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath"></path></marker></defs></g><g class="edgePath LS-注册pinRequest LE-配对设备" id="L-注册pinRequest-配对设备"><path class="path" d="M445.921875,30.796875L470.921875,30.796875L495.921875,30.796875" marker-end="url(#arrowhead19)"></path><defs><marker id="arrowhead19" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform=""><g transform="translate(0,0)" class="label"><rect rx="0" ry="0" width="0" height="0"></rect><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml"><span id="L-L-开启蓝牙-设置发现模式" class="edgeLabel L-LS-开启蓝牙' L-LE-设置发现模式"></span></div></foreignObject></g></g><g class="edgeLabel" transform=""><g transform="translate(0,0)" class="label"><rect rx="0" ry="0" width="0" height="0"></rect><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml"><span id="L-L-设置发现模式-注册pinRequest" class="edgeLabel L-LS-设置发现模式' L-LE-注册pinRequest"></span></div></foreignObject></g></g><g class="edgeLabel" transform=""><g transform="translate(0,0)" class="label"><rect rx="0" ry="0" width="0" height="0"></rect><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml"><span id="L-L-注册pinRequest-配对设备" class="edgeLabel L-LS-注册pinRequest' L-LE-配对设备"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="flowchart-开启蓝牙-4" transform="translate(50,30.796875)"><rect rx="0" ry="0" x="-42" y="-22.796875" width="84" height="45.59375" class="label-container"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-32,-12.796875)"><foreignObject width="64" height="25.59375"><div xmlns="http://www.w3.org/1999/xhtml">开启蓝牙</div></foreignObject></g></g></g><g class="node default" id="flowchart-设置发现模式-5" transform="translate(200,30.796875)"><rect rx="0" ry="0" x="-58" y="-22.796875" width="116" height="45.59375" class="label-container"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-48,-12.796875)"><foreignObject width="96" height="25.59375"><div xmlns="http://www.w3.org/1999/xhtml">设置发现模式</div></foreignObject></g></g></g><g class="node default" id="flowchart-注册pinRequest-6" transform="translate(376.9609375,30.796875)"><rect rx="0" ry="0" x="-68.9609375" y="-22.796875" width="137.921875" height="45.59375" class="label-container"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-58.9609375,-12.796875)"><foreignObject width="117.921875" height="25.59375"><div xmlns="http://www.w3.org/1999/xhtml">注册pinRequest</div></foreignObject></g></g></g><g class="node default" id="flowchart-配对设备-7" transform="translate(537.921875,30.796875)"><rect rx="0" ry="0" x="-42" y="-22.796875" width="84" height="45.59375" class="label-container"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-32,-12.796875)"><foreignObject width="64" height="25.59375"><div xmlns="http://www.w3.org/1999/xhtml">配对设备</div></foreignObject></g></g></g></g></g></g></svg></div><div class="md-diagram-panel-error"></div></div></pre>

1. **开启蓝牙**
   ```
   //开蓝牙
   ListItem() {
       TitleComponent({
           title: "enableBluetooth",                                                            //显示功能的名称
           bgColor: this.currentClick === 0 ? $r('app.color.font_color_007DFF') :  $r('app.color.white_bg_color')
       });                                                                                     //点击后颜色变化
   }
   .padding({ top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2') })   
       .onClick(() => {                                                                        //点击事件               
       if (this.btEnable) {                                                                    //判断蓝牙是否已经打开
           this.message = '蓝牙已经使能';                                                  
           return;
       }
       let ret = BluetoothModel.enableBluetooth();                                             //打开蓝牙
       this.btEnable = ret;                                                               //如果启用了蓝牙,则返回true,否则返回false
       AppStorage.SetOrCreate('bluetoothIsOn', this.btEnable);                                 //存储蓝牙打开的结果,方便调用
       AppStorage.SetOrCreate('currentClick', this.currentClick);
       this.message = "蓝牙使能执行结果:" + ret;                                                   //输出结果
   })
   ```
2. **设置发现模式**
   ```
   ListItem() {
       TitleComponent({
           title: "setBluetoothScanMode",                                                       //显示功能的名称
           bgColor: this.currentClick === 6 ? $r('app.color.font_color_007DFF') : $r('app.color.white_bg_color')
       });                                                                                      //点击后颜色变化
   }
   .padding({ top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2') })
       .onClick(() => {                                                                         //点击事件  
       this.currentClick = 6;
       if (this.btEnable) {                                                                     //判断蓝牙是否已经打开
           retObj = {mod: 0, duration: -1}                                  //mode表示要设置的蓝牙扫描模式{@link ScanMode}。                                                                                  //*@param duration指示主机可发现的持续时间(秒)。
           setLocalNameRet = BluetoothModel.setBluetoothScanMode(mode, dur);
           if (setLocalNameRet) {
               AppStorage.SetOrCreate('setScanModeRet', setLocalNameRet);
               retObj.mod = mode;
               retObj.duration = dur;
           } else {                                                          //如果设置了蓝牙扫描模式,返回true,否则返回false。
               console.info("BluetoothModel.setBluetoothScanMode failed!")
               onsole.info("BluetoothModel.setBluetoothScanMode success!", retObj)            
               this.message = "setBluetoothScanMode执行" + this.setLocalNameRet ? '成功' : '失败';
           }
       }else {
           this.message = "蓝牙未使能";
       }
   })
   ```
3. **注册pinRequest**
   ```
   ListItem() {
       TitleComponent({
           title: "btPinRequired"                                                                //显示功能的名称
           bgColor: this.currentClick === 18 ? $r('app.color.font_color_007DFF') : $r('app.color.white_bg_color')
       });                                                                                       //点击后颜色变化
   }
   .padding({ top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2') })
       .onClick(() => {                                                                            //点击事件
       if (!this.btEnable) {                                                                   //判断蓝牙是否已经打开
           this.message = "蓝牙未使能";
           return;
       }
       if (this.isPinRequiredClick) {                                                //判断监听是否开启,即为一个“开关”,并存储数据
           bluetooth.off('pinRequired', () => {                                  
           })
           this.message = 'on:pinRequired监听已关闭,再次点击将开启监听';
           this.isPinRequiredClick = false;
           AppStorage.SetOrCreate('on_pinRequired', this.btPinRequired);
           return;
       }
       this.isPinRequiredClick = true;
       AppStorage.SetOrCreate('on_pinRequired', this.btPinRequired);                //type要侦听的配对请求事件的类型为:pinRequired
       this.pinMessage = 'PIN: ';
       bluetooth.on('pinRequired', (data) => {                                           //callback回调用于侦听配对请求事件。
           this.pinMessage = 'PIN: ';
           this.pinMessage += data.pinCode;
       })
       this.message = 'on:pinRequired监听已启动,再次点击将关闭监听。';
   })
   ```
4. **配对设备**
   ```
   ListItem() {
       TitleComponent({
           title: "pairDevice",                                                                   //显示功能的名称  
           bgColor: this.currentClick === 10 ? $r('app.color.font_color_007DFF') : $r('app.color.white_bg_color')
       });                                                                                        //点击后颜色变化
   }
   .padding({ top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2') })
       .onClick(() => {                                                                         //点击事件
       if (!this.btEnable) {                                                                   //判断蓝牙是否已经打开
           this.message = '蓝牙未使能';
           return;
       }
       if (this.deviceId == '') {                                                      //deviceId为要配对的远程设备的地址
           this.message = "请输入目标设备的MAC";                                          //若为空,请输入目标MAC
           return;
       } else {
           this.pairDevice(this.deviceId);                                          //如果配对过程已启动,则返回true,否则返回false
       }
   })
   ```

### OpenHarmony经典蓝牙设备发现流程

<pre class="md-fences md-end-block md-diagram md-fences-advanced ty-contain-cm modeLoaded" spellcheck="false" lang="mermaid" cid="n87" mdtype="fences" mermaid-type="graph"><div class="md-diagram-panel md-fences-adv-panel"><div class="md-diagram-panel-header"></div><div class="md-diagram-panel-preview"><svg id="mermaidChart1" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="61.59375" viewBox="0 0 432 61.59375" class="in-text-selection"><g><g class="output"><g class="clusters"></g><g class="edgePaths"><g class="edgePath LS-开启蓝牙 LE-设置发现模式" id="L-开启蓝牙-设置发现模式"><path class="path" d="M92,30.796875L117,30.796875L142,30.796875" marker-end="url(#arrowhead31)"></path><defs><marker id="arrowhead31" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath"></path></marker></defs></g><g class="edgePath LS-设置发现模式 LE-开始蓝牙发现" id="L-设置发现模式-开始蓝牙发现"><path class="path" d="M258,30.796875L283,30.796875L308,30.796875" marker-end="url(#arrowhead32)"></path><defs><marker id="arrowhead32" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform=""><g transform="translate(0,0)" class="label"><rect rx="0" ry="0" width="0" height="0"></rect><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml"><span id="L-L-开启蓝牙-设置发现模式" class="edgeLabel L-LS-开启蓝牙' L-LE-设置发现模式"></span></div></foreignObject></g></g><g class="edgeLabel" transform=""><g transform="translate(0,0)" class="label"><rect rx="0" ry="0" width="0" height="0"></rect><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml"><span id="L-L-设置发现模式-开始蓝牙发现" class="edgeLabel L-LS-设置发现模式' L-LE-开始蓝牙发现"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="flowchart-开启蓝牙-11" transform="translate(50,30.796875)"><rect rx="0" ry="0" x="-42" y="-22.796875" width="84" height="45.59375" class="label-container"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-32,-12.796875)"><foreignObject width="64" height="25.59375"><div xmlns="http://www.w3.org/1999/xhtml">开启蓝牙</div></foreignObject></g></g></g><g class="node default" id="flowchart-设置发现模式-12" transform="translate(200,30.796875)"><rect rx="0" ry="0" x="-58" y="-22.796875" width="116" height="45.59375" class="label-container"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-48,-12.796875)"><foreignObject width="96" height="25.59375"><div xmlns="http://www.w3.org/1999/xhtml">设置发现模式</div></foreignObject></g></g></g><g class="node default" id="flowchart-开始蓝牙发现-13" transform="translate(366,30.796875)"><rect rx="0" ry="0" x="-58" y="-22.796875" width="116" height="45.59375" class="label-container"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-48,-12.796875)"><foreignObject width="96" height="25.59375"><div xmlns="http://www.w3.org/1999/xhtml">开始蓝牙发现</div></foreignObject></g></g></g></g></g></g></svg></div><div class="md-diagram-panel-error"></div></div></pre>

1. **开启蓝牙(同上)**
2. **设置发现模式(同上)**
3. **开始蓝牙发现**
   ```
   ListItem() {
       TitleComponent({
           title: "startBluetoothDiscovery",                                                              //显示功能的名称  
           bgColor: this.currentClick === 8 ? $r('app.color.font_color_007DFF') : $r('app.color.white_bg_color')
       });                                                                                                //点击后颜色变化
   }
   .padding({ top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2') })
       .onClick(() => {//点击事件
       LogUtil.info(this.TAG_PAGE + 'startBluetoothDiscovery 111');
       if (!this.btEnable) {                                                                   //判断蓝牙是否已经打开
           this.message = '蓝牙未使能';
           return;
       }
       Router.push({ uri: PAGE_URI_DEVICE_FOUND_MODE });                                      //搜索发现蓝牙的分界面
   })
   ```
4. **搜索发现蓝牙的分界面**
   ```
   Scroll() {
       Column() {
           if (this.isOn) {
               PairedDeviceComponent({                                                      //显示已配对的设备
                   controller: this.deviceController
               })
               AvailableDeviceComponent({                                                   //显示可被配对的设备                     
                   controller: this.deviceController
               })
           }
       }
       .width(ConfigData.WH_100_100)
   }


   //PairedDeviceComponent

   build() {
       Column() {
           if (this.pairedDevices && this.pairedDevices.length > 0) {
               // paired devices title
               Row() {
                   Text($r('app.string.bluetooth_paired_devices'))                          //已配对的设备
                       .fontSize($r('app.float.font_14'))
                       .fontColor($r('app.color.font_color_182431'))
               }
               .width(ConfigData.WH_100_100)
                   .padding({
                   left: $r('app.float.distance_24'),
                   top: $r('app.float.distance_19_5'),
                   bottom: $r('app.float.distance_9_5')
               })
               List() {
                   // paired devices list
                   ForEach(this.pairedDevices, (item: BluetoothDevice, index: number) => {
                       ListItem() {
                           Row() {
                               PairedItem({
                                   name: item.deviceName,
                                   type: item.deviceType,
                                   state: item.connectionState.toString(),
                                   mac: item.deviceId
                               })
                           }
                           .width(ConfigData.WH_100_100)
                               .borderRadius($r("app.float.radius_24"))
                               .padding($r('app.float.distance_4'))
                               .backgroundColor($r("app.color.white_bg_color"))
                               .onClick(() => {
                               this.itemClicked(item);
                           })
                       }
                   }, item => JSON.stringify(item));
               }
               .height(200)
                   .divider({
                   strokeWidth: 1,
                   color: $r('app.color.color_E3E3E3_grey'),
                   startMargin: $r('app.float.wh_value_52'),
                   endMargin: $r('app.float.wh_value_12')
               })
                   .backgroundColor($r("app.color.white_bg_color"))
                   .borderRadius($r("app.float.radius_24"))
           }
       }
   }

   //AvailableDeviceComponent

   build() {
       Column() {
           Row() {
               // available devices title
               Text($r('app.string.bluetooth_available_devices'))                            //可用设备
                   .fontSize($r('app.float.font_14'))
                   .fontColor($r('app.color.font_color_182431'))
                   .width(ConfigData.WH_100_100)
                   .padding({
                   left: $r('app.float.distance_24'),
                   top: $r('app.float.distance_19_5'),
                   bottom: $r('app.float.distance_9_5')
               })
               Blank()

               // bluetooth discovering
               if (this.isDeviceDiscovering) {
                   DiscoveringAnimatorComponent()
               }
           }
           .width(ConfigData.WH_100_100)

           if (this.availableDevices && this.availableDevices.length >= 1) {
               Scroll() {
                   List() {
                       // paired devices list
                       ForEach(this.availableDevices, (item: BluetoothDevice) => {
                           ListItem() {
                               Row() {
                                   AvailableItem({
                                       name: item.deviceName,
                                       type: item.deviceType,
                                       state: item.connectionState.toString(),
                                       mac: item.deviceId
                                   })
                               }
                               .width(ConfigData.WH_100_100)
                                   .borderRadius($r("app.float.radius_24"))
                                   .padding($r('app.float.distance_4'))
                                   .backgroundColor($r("app.color.white_bg_color"))
                                   .onClick(() => {
                                   LogUtil.info(this.TAG_PAGE + 'item on click : ' + JSON.stringify(item));
                                   AppStorage.SetOrCreate('pairedMac', item.deviceId);
                                   //                AppStorage.SetOrCreate('pairedName', item.deviceName);
                                   this.pairDevice(item)
                               })
                           }
                       }, item => JSON.stringify(item));
                   }
                   .backgroundColor($r("app.color.white_bg_color"))
                       .borderRadius($r("app.float.radius_24"))
                       .height("80%")
                       .divider({
                       strokeWidth: 1,
                       color: $r('app.color.color_E3E3E3_grey'),
                       startMargin: $r('app.float.wh_value_52'),
                       endMargin: $r('app.float.wh_value_12')
                   })
               }
               .scrollBar(BarState.Auto)
                   .scrollBarWidth(20)
           } else {
               Row() {
                   // Scanning...
                   Text($r('app.string.scanning'))
                       .fontSize($r('app.float.font_20'))
                       .textCase(TextCase.UpperCase);
               }
           }
       }
   }
   ```

### 整体代码

```
├─Component
│   │  └─controller
│   ├─pageTitle.ets
│   ├─headComponent.ets
│   └─titleComponent.ets
├─MainAbility
│  ├─controller
│  ├─model
│      ├─BluetoothDevice.ts
│      └─BluetoothModel.ts
│  └─pages
│      ├─homePage.ets
│      └─deviceFound.ets
└─Utils
```

**page**

```
//homePage
build() {
    Column() {
        GridContainer({
            columns: 12,
            sizeType: SizeType.Auto,
            gutter: vp2px(1) === 2 ? '12vp' : '0vp',
            margin: vp2px(1) === 2 ? '24vp' : '0vp'
        }) {
            Row({}) {
                Column() {
                }
                .width(ConfigData.WH_100_100)
                    .height(ConfigData.WH_100_100)
                    .useSizeType({
                    xs: { span: 0, offset: 0 }, sm: { span: 0, offset: 0 },
                    md: { span: 0, offset: 0 }, lg: { span: 2, offset: 0 }
                });
                Column() {
                    Text(this.message)
                        .fontSize($r("app.float.font_30"))
                        .lineHeight($r("app.float.lineHeight_41"))
                        .fontWeight(FontWeight.Bold)
                        .fontFamily('HarmonyHeiTi')
                        .textAlign(TextAlign.Start)
                        .width(ConfigData.WH_100_100)
                        .padding({
                        left: $r('app.float.distance_26'),
                        top: $r('app.float.distance_12'),
                        bottom: $r('app.float.distance_17')
                    })
                    Column() {
                        HeadComponent({ headName: $r('app.string.test1'), isActive: true })
                        Scroll() {
                            Column({ space: '12vp' }) {
                                List() {
                                    //开蓝牙
                                    ListItem() {
                                        TitleComponent({
                                            title: "enableBluetooth",
                                            bgColor: this.currentClick === 0 ? $r('app.color.font_color_007DFF') : $r('app.color.white_bg_color')
                                        });
                                    }
                                    .padding({ top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2') })
                                        .onClick(() => {
                                        this.currentClick = 0;
                                        if (this.btEnable) {
                                            this.message = '蓝牙已经使能';
                                            return;
                                        }
                                        let ret = BluetoothModel.enableBluetooth();
                                        this.btEnable = ret;
                                        AppStorage.SetOrCreate('bluetoothIsOn', this.btEnable);
                                        AppStorage.SetOrCreate('currentClick', this.currentClick);
                                        this.message = "蓝牙使能执行结果:" + ret;
                                    })
                                    //设置状态
                                    ListItem() {
                                        TitleComponent({
                                            title: "getState",
                                            bgColor: this.currentClick === 2 ? $r('app.color.font_color_007DFF') : $r('app.color.white_bg_color')
                                        });
                                    }
                                    .padding({ top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2') })
                                        .onClick(() => {
                                        this.currentClick = 2;
                                        let ret = BluetoothModel.getState();
                                        switch (ret) {
                                            case 0:
                                                this.stateBT = 'STATE_OFF';
                                                break;
                                            case 1:
                                                this.stateBT = 'STATE_TURNING_ON';
                                                break;
                                            case 2:
                                                this.stateBT = 'STATE_ON';
                                                break;
                                            case 3:
                                                this.stateBT = 'STATE_TURNING_OFF';
                                                break;
                                            case 4:
                                                this.stateBT = 'STATE_BLE_TURNING_ON';
                                                break;
                                            case 5:
                                                this.stateBT = 'STATE_BLE_ON';
                                                break;
                                            case 6:
                                                this.stateBT = 'STATE_BLE_TURNING_OFF';
                                                break;
                                            default:
                                                this.stateBT = '未知状态';
                                                break;
                                        }
                                        this.message = "当前蓝牙的状态是:" + this.stateBT;
                                    })
                                    //设置本地名称  
                                    ListItem() {
                                        TitleComponent({
                                            title: "setLocalName",
                                            bgColor: this.currentClick === 4 ? $r('app.color.font_color_007DFF') : $r('app.color.white_bg_color')
                                        });
                                    }
                                    .padding({ top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2') })
                                        .onClick(() => {
                                        this.currentClick = 4;
                                        if (this.btEnable) {
                                            Router.push({ uri: PAGE_URI_DEVICE_NAME });
                                            this.message = "设置SCAN MODE " + this.setScanModeRet ? '成功' : '失败';
                                        } else {
                                            this.message = "蓝牙未使能";
                                        }
                                    })
                                    //设置扫描模式   
                                    ListItem() {
                                        TitleComponent({
                                            title: "setBluetoothScanMode",
                                            bgColor: this.currentClick === 6 ? $r('app.color.font_color_007DFF') : $r('app.color.white_bg_color')
                                        });
                                    }
                                    .padding({ top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2') })
                                        .onClick(() => {
                                        this.currentClick = 6;
                                        if (!this.btEnable) {
                                            Router.push({ uri: PAGE_URI_SET_SCAN_MODE });
                                            this.message = "setBluetoothScanMode执行" + this.setLocalNameRet ? '成功' : '失败';
                                        } else {
                                            this.message = "蓝牙未使能";
                                        }
                                    })
                                    // 开始蓝牙发现
                                    ListItem() {
                                        TitleComponent({
                                            title: "startBluetoothDiscovery",
                                            bgColor: this.currentClick === 8 ? $r('app.color.font_color_007DFF') : $r('app.color.white_bg_color')
                                        });
                                    }
                                    .padding({ top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2') })
                                        .onClick(() => {
                                        LogUtil.info(this.TAG_PAGE + 'startBluetoothDiscovery 111');
                                        if (this.btEnable) {
                                            this.message = '蓝牙未使能';
                                            return;
                                        }
                                        this.currentClick = 8;
                                        Router.push({ uri: PAGE_URI_DEVICE_FOUND_MODE });
                                    })
                                    //监听PinRequired
                                    ListItem() {
                                        TitleComponent({
                                            title: this.btPinRequired,
                                            pinRequiredFlag: true,
                                            bgColor: this.currentClick === 18 ? $r('app.color.font_color_007DFF') : $r('app.color.white_bg_color')
                                        });
                                    }
                                    .padding({ top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2') })
                                        .onClick(() => {
                                        if (!this.btEnable) {
                                            this.message = "蓝牙未使能";
                                            return;
                                        }
                                        if (this.isPinRequiredClick) {
                                            bluetooth.off('pinRequired', () => {

                                            })
                                            this.message = 'on:pinRequired监听已关闭,再次点击将开启监听';
                                            this.isPinRequiredClick = false;
                                            this.btPinRequired = 'on:pinRequired';
                                            AppStorage.SetOrCreate('on_pinRequired', this.btPinRequired);
                                            return;
                                        }
                                        this.isPinRequiredClick = true;
                                        this.currentClick = 18;
                                        this.btPinRequired = 'off:pinRequired';
                                        AppStorage.SetOrCreate('on_pinRequired', this.btPinRequired);
                                        this.pinMessage = 'PIN: ';
                                        bluetooth.on('pinRequired', (data) => {
                                            this.pinMessage = 'PIN: ';
                                            this.pinMessage += data.pinCode;
                                        })
                                        this.message = 'on:pinRequired监听已启动,再次点击将关闭监听。';
                                    })
                                    //配对设备
                                    ListItem() {
                                        TitleComponent({
                                            title: "pairDevice",
                                            bgColor: this.currentClick === 10 ? $r('app.color.font_color_007DFF') : $r('app.color.white_bg_color')
                                        });
                                    }
                                    .padding({ top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2') })
                                        .onClick(() => {
                                        this.currentClick = 10;
                                        if (!this.btEnable) {
                                            this.message = '蓝牙未使能';
                                            return;
                                        }
                                        if (this.deviceId == '') {
                                            this.message = "请输入目标设备的MAC";
                                            return;
                                        } else {
                                            this.pairDevice(this.deviceId);
                                        }
                                    })
                                    //关蓝牙
                                    ListItem() {
                                        TitleComponent({
                                            title: "disableBluetooth",
                                            bgColor: this.currentClick === 1 ? $r('app.color.font_color_007DFF') : $r('app.color.white_bg_color')
                                        });
                                    }
                                    .padding({ top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2') })
                                        .onClick(() => {
                                        this.currentClick = 1;
                                        if (!this.btEnable) {
                                            this.message = '蓝牙还未使能';
                                            return;
                                        }
                                        let ret = BluetoothModel.disableBluetooth();
                                        this.btEnable = false;
                                        AppStorage.SetOrCreate('bluetoothIsOn', this.btEnable);
                                        this.message = "蓝牙去使能执行结果:" + ret;
                                    })
                                }
                            }
                            .width(ConfigData.WH_100_100)
                                .height(600)
                        }
                        .scrollable(ScrollDirection.Vertical).scrollBar(BarState.On)
                        .scrollBarColor(Color.Gray).scrollBarWidth(30)
                    }
                    .padding({ left: $r('app.float.distance_2'), right: $r('app.float.distance_2') })
                    .width(ConfigData.WH_100_100)
                    .height(ConfigData.WH_100_100)
                    .useSizeType({
                    xs: { span: 12, offset: 0 }, sm: { span: 12, offset: 0 },
                    md: { span: 12, offset: 0 }, lg: { span: 8, offset: 2 }
                    });
                }
                .padding({ left: $r('app.float.distance_2'), right: $r('app.float.distance_2') })
                .width(ConfigData.WH_100_100)
                .height(ConfigData.WH_100_100)
                .useSizeType({
                xs: { span: 12, offset: 0 }, sm: { span: 12, offset: 0 },
                md: { span: 12, offset: 0 }, lg: { span: 8, offset: 2 }
                });
            }
            .width(ConfigData.WH_100_100)
            .height(ConfigData.WH_100_100);
        }
        .backgroundColor($r("sys.color.ohos_id_color_sub_background"))
        .width(ConfigData.WH_100_100)
        .height(ConfigData.WH_100_100);
    }
}
```

**component:**

```
// titlecomoponent

import ConfigData from '../Utils/ConfigData';
@Component
export struct TitleComponent{
    private title:string | Resource;
    private fontSize:string ='35vp';
    private stateChangeFlag: boolean = false;
    private pinRequiredFlag: boolean = false;
    private bondStateChangeFlag: boolean = false;
    @State isTouched:boolean = false;
    @State bgColor: Resource = $r('app.color.font_color_007DFF');
    @StorageLink('on_stateChange') state: string = 'on:stateChange';
    @StorageLink('on_pinRequired') pin: string = 'on:pinRequired';
    @StorageLink('on_bondStateChange') bondState: string = 'on:bondStateChange';
    build(){
        Column(){
            Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems:ItemAlign.Center }) {
                Text(this.stateChangeFlag ? this.state : (this.pinRequiredFlag ? this.pin : (this.bondStateChangeFlag ? this.bondState : this.title)))
                    .textAlign(TextAlign.Center)
                    .width("100%")
                    .height(100)
                    .fontSize(this.fontSize)
                    .fontColor($r('app.color.font_color_182431'))
                    .fontWeight(FontWeight.Medium)
            }
            .height(ConfigData.WH_100_100)
                .width(ConfigData.WH_100_100)
                .backgroundColor(this.bgColor)
                .linearGradient(this.isTouched ? {
                angle: 90,
                direction: GradientDirection.Right,
                colors: [[$r("app.color.DCEAF9"), 0.0], [$r("app.color.FAFAFA"), 1.0]]
            } : {
                angle: 90, direction: GradientDirection.Right,
                colors: [[$r("sys.color.ohos_id_color_foreground_contrary"), 1], [$r("sys.color.ohos_id_color_foreground_contrary"), 1]]})
                .onTouch((event: TouchEvent) => {
                if (event.type === TouchType.Down) {
                    this.isTouched = true;
                }
                if (event.type === TouchType.Up) {
                    this.isTouched = false;
                }
            })
        }
        .padding($r('app.float.distance_4'))
        .height("100vp")
        .borderRadius($r('app.float.radius_12'))
    }
}
```

**model:**

```
import { DeviceState } from './BluetoothModel'
export class Profile {
    profileId: number = -1;
    profileConnectionState: number = -1
    constructor() {
    }
}
/**
* Bluetooth device class
*/
export default class BluetoothDevice {
    deviceId: string = '';
    deviceName: string = '';
    deviceType: string = '';
    connectionState: number = 0;
    profiles: Map<number, Profile> = new Map();
    constructor() {
    }
    setProfiles(data: Array<{
            profileId: number;
            profileConnectionState: number;
    }>): void{
                data.forEach((item: {
                profileId: number;
                profileConnectionState: number;
            }) => {
                this.setProfile({
                    profileId: item.profileId,
                    deviceId: this.deviceId,
                    profileConnectionState: item.profileConnectionState
                })
            })
        }
        setProfile(data: {
                profileId: number;
        deviceId: string;
        profileConnectionState: number;
    }): void{
            if (this.deviceId !== data.deviceId) {
                return;
            }
            this.profiles.set(data.profileId, data)
            let countStateDisconnect = 0;
                let countStateConnecting = 0;
                let countStateConnected = 0;
                let countStateDisconnecting = 0;
                this.profiles.forEach((profile, key) => {
                    if (profile.profileConnectionState == 0) {
                        // 0:the current profile is disconnected
                        countStateDisconnect++;
                    } else if (profile.profileConnectionState == 1) {
                        // 1:the current profile is being connected
                        countStateConnecting++;
                    } else if (profile.profileConnectionState == 2) {
                        // 2:the current profile is connected
                countStateConnected++;
                    } else if (profile.profileConnectionState == 3) {
                        // 3:the current profile is being disconnected
                        countStateDisconnecting++;
                    }
                });
                if (countStateConnected > 0 || countStateDisconnecting > 0) {
                    this.connectionState = DeviceState.STATE_CONNECTED;
                } else if (countStateConnecting > 0) {
                    this.connectionState = DeviceState.STATE_CONNECTING;
                } else {
                    this.connectionState = DeviceState.STATE_DISCONNECTED;
                }
        }
}
```

### 预览图

![image.png](https://forums-obs.openharmony.c ... gtoggfqt2jyveag.png "image.png")
[/md]
作者: liudongxjtu    时间: 2024-5-27 10:46
是否有该示例代码的下载?
作者: 深开鸿_王石    时间: 2024-5-28 10:42
回复 liudongxjtu: https://gitee.com/openharmony/co ... ample/bluetoothtest ,可以参考这里面的应用
作者: martin_hu    时间: 2024-7-22 17:30
demo要是有收发文件功能就更好了
作者: martin_hu    时间: 2024-7-30 13:43
回复 martin_hu: 蓝牙收发文件可用https://gitee.com/develop-phone-open-source/applications_app_samples/tree/OpenHarmony-4.0-Release/code/Solutions/OppTrans/BluetoothOpp
验证收发正常




欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/) Powered by Discuz! X3.5