npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fww_123/uni-ble-scanner

v2.0.0

Published

跨平台蓝牙低功耗扫描组件,支持安卓、鸿蒙、iOS

Readme

@fww_123/uni-ble-scanner

跨平台蓝牙低功耗(BLE)扫描组件,一套代码支持 AndroidiOS鸿蒙 三大原生平台,以及 UniAppAPICloudH5 WebView 等多种开发框架。

📖 目录

✨ 特性

  • 🚀 跨框架:支持 UniApp、APICloud、H5(WebView)、纯 H5
  • 📱 真原生:直接调用 Android/iOS/鸿蒙原生蓝牙 API,非 JS 模拟
  • 🔧 统一接口:所有框架使用相同的 JavaScript API
  • 自动降级:原生插件不可用时自动切换到标准 API
  • 🛡️ TypeScript:完整的类型定义和代码提示
  • 📦 开箱即用:npm 安装,引入即用

📦 安装

npm install @fww_123/uni-ble-scanner

🚀 快速开始

最简单的使用方式(推荐)

适用于:UniAppAPICloudH5 + WebView纯 H5

<!-- 1. 引入 Bridge 文件 -->
<script src="node_modules/@fww_123/uni-ble-scanner/native-plugins/bridge/universal-bridge.js"></script>

<script>
// 2. 初始化蓝牙
BLEScanner.init({}, function(ret, err) {
  if (err) {
    console.error('初始化失败:', err.message);
    return;
  }
  console.log('初始化成功:', ret.platform);
});

// 3. 开始扫描
BLEScanner.startScan({
  timeout: 10000,  // 扫描 10 秒
  services: []     // 可选:指定要扫描的服务 UUID
}, function(ret, err) {
  if (err) {
    console.error('扫描错误:', err.message);
    return;
  }
  
  // 处理扫描事件
  switch(ret.event) {
    case 'scanStart':
      console.log('扫描开始');
      break;
    case 'deviceFound':
      console.log('发现设备:', ret.device.name, ret.device.RSSI);
      break;
    case 'scanStop':
      console.log('扫描停止');
      break;
    case 'timeout':
      console.log('扫描超时');
      break;
  }
});
</script>

TypeScript / ES Module 方式

import { createScanner, createNativeScanner } from '@fww_123/uni-ble-scanner';

// 方式1:自动检测平台
const scanner = createScanner({ type: 'auto' });

// 方式2:强制使用原生
const scanner = createNativeScanner();

// 初始化
await scanner.init();

// 开始扫描
await scanner.startScan({
  timeout: 30000,
  allowDuplicates: false
}, {
  onDeviceFound: (device) => {
    console.log('发现设备:', device.name, device.RSSI);
  },
  onScanStart: () => console.log('扫描开始'),
  onScanStop: () => console.log('扫描停止')
});

🏗️ 架构说明

整体架构

┌─────────────────────────────────────────────────────────────┐
│                    你的 APP(任意框架)                       │
│         UniApp / APICloud / H5+原生壳 / 纯 H5               │
└───────────────────────────┬─────────────────────────────────┘
                            │
              ┌─────────────▼──────────────┐
              │   universal-bridge.js      │
              │   ├─ 自动检测运行环境       │
              │   ├─ 统一 API 封装          │
              │   └─ 自动降级处理           │
              └─────────────┬──────────────┘
                            │
        ┌───────────────────┼───────────────────┐
        │                   │                   │
┌───────▼───────┐  ┌────────▼────────┐  ┌──────▼──────┐
│    Android    │  │       iOS       │  │   鸿蒙      │
│  Java 原生    │  │   OC 原生        │  │  ArkTS 原生 │
│               │  │                 │  │             │
│ BluetoothLe   │  │ CoreBluetooth   │  │ @ohos.      │
│   Scanner     │  │                 │  │ bluetooth   │
└───────────────┘  └─────────────────┘  └─────────────┘

工作原理

  1. 环境检测universal-bridge.js 自动检测当前运行环境
  2. 适配层:根据环境选择最佳的实现方式
    • 有原生插件 → 使用原生插件(性能最好)
    • 无原生插件 → 使用框架标准 API
    • H5 环境 → 使用 Web Bluetooth API
  3. 统一接口:无论底层如何,对外提供一致的 API

各平台实现

| 平台 | 技术方案 | 原生 API | 最低版本 | |------|---------|---------|---------| | Android | UniApp 原生插件 / Native.js | BluetoothLeScanner | Android 5.0+ | | iOS | UniApp 原生插件 / Native.js | CoreBluetooth | iOS 7.0+ | | 鸿蒙 | 原生 ArkTS 模块 | @ohos.bluetooth.ble | HarmonyOS 2.0+ | | Web | Web Bluetooth API | navigator.bluetooth | Chrome/Edge |

📱 框架集成

UniApp

方案 A:使用原生插件(推荐,性能最佳)

  1. 复制原生插件到项目
# Android
mkdir -p nativeplugins/ble-scanner/android
mkdir -p nativeplugins/ble-scanner/ios

# 复制插件文件
cp -r node_modules/@fww_123/uni-ble-scanner/native-plugins/android/ble-scanner/* nativeplugins/ble-scanner/android/
cp -r node_modules/@fww_123/uni-ble-scanner/native-plugins/ios/ble-scanner/* nativeplugins/ble-scanner/ios/
  1. 配置 manifest.json
{
  "nativePlugins": {
    "ble-scanner": {
      "android": {
        "package": "com.blescanner",
        "class": "BLEScannerModule"
      },
      "ios": {
        "class": "BLEScannerModule"
      }
    }
  }
}
  1. 在页面中引入 Bridge
<template>
  <view>
    <!-- 你的页面内容 -->
  </view>
</template>

<script>
// 方式1:直接引入 Bridge(推荐)
// 在 index.html 的 head 中添加:
// <script src="static/js/universal-bridge.js"><\/script>

// 方式2:使用 npm 包
import { createScanner } from '@fww_123/uni-ble-scanner';

export default {
  methods: {
    async initBLE() {
      // 使用全局 BLEScanner 对象
      BLEScanner.init({}, (ret, err) => {
        if (ret) console.log('成功');
      });
      
      // 或使用 npm 包
      const scanner = createScanner({ type: 'native' });
      await scanner.init();
    }
  }
}
</script>

方案 B:使用标准 API(无需配置原生插件)

直接使用 universal-bridge.js,它会自动使用 UniApp 标准蓝牙 API。

<script src="path/to/universal-bridge.js"></script>
<script>
  // 自动降级到 uni.openBluetoothAdapter
  BLEScanner.init({}, callback);
</script>

APICloud

  1. 导入模块

    • 将 Android/iOS 模块编译后导入 APICloud 项目
    • config.xml 中添加模块配置
  2. 使用 Bridge

<!DOCTYPE html>
<html>
<head>
  <script src="path/to/universal-bridge.js"></script>
</head>
<body>
  <script>
    apiready = function() {
      BLEScanner.init({}, function(ret, err) {
        // 初始化完成
      });
    };
  </script>
</body>
</html>

H5 + 原生 WebView

如果你的 APP 是原生开发,内嵌 H5 页面:

Android 端(Java/Kotlin):

// 在 WebView 中注入 Bridge
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new BLEScannerBridge(this), "BLEScannerNative");

// BLEScannerBridge.java
public class BLEScannerBridge {
    @JavascriptInterface
    public void init(String options, String callbackId) {
        // 调用原生蓝牙 API
    }
}

iOS 端(Objective-C/Swift):

// 使用 WebViewJavascriptBridge
[bridge registerHandler:@"BLEScanner.init" handler:^(id data, WVJBResponseCallback responseCallback) {
    // 初始化蓝牙
    responseCallback(@{@"status": @YES});
}];

[bridge registerHandler:@"BLEScanner.startScan" handler:^(id data, WVJBResponseCallback responseCallback) {
    // 开始扫描
    // 扫描到设备后通过 callback 返回
}];

H5 页面:

<script src="path/to/universal-bridge.js"></script>
<script>
  // universal-bridge.js 会自动检测 WebViewJavascriptBridge
  BLEScanner.init({}, function(ret, err) {
    console.log('初始化结果:', ret);
  });
</script>

纯 H5(Web Bluetooth)

<script src="path/to/universal-bridge.js"></script>
<script>
  // 仅支持 Chrome、Edge、Opera 等浏览器
  // 必须在 HTTPS 环境下运行
  BLEScanner.init({}, function(ret, err) {
    if (err) {
      alert('浏览器不支持蓝牙或权限被拒绝');
      return;
    }
    
    BLEScanner.startScan({}, function(ret, err) {
      if (ret.event === 'deviceFound') {
        console.log(ret.device);
      }
    });
  });
</script>

� API 文档

统一 API(Bridge 模式)

BLEScanner.init(options, callback)

初始化蓝牙适配器。

参数:

  • options {Object} - 配置选项(可选)
    • restoreIdentifier {string} - iOS 后台恢复标识
  • callback {Function} - 回调函数 callback(ret, err)

回调结果:

// 成功
{
  status: true,
  platform: 'android' // 'android' | 'ios' | 'harmony' | 'web'
}

// 失败
{
  code: -1,           // 错误码
  message: '错误信息'  // 错误描述
}

错误码说明: | 错误码 | 说明 | |--------|------| | -1 | 缺少权限 | | -2 | 设备不支持蓝牙 | | -3 | 蓝牙未开启 | | -4 | 扫描已在进行中 | | -5 | 启动扫描失败 | | -10 | 用户取消 | | -99 | 其他错误 |

BLEScanner.startScan(options, callback)

开始扫描 BLE 设备。

参数:

  • options {Object} - 扫描选项
    • timeout {number} - 扫描超时时间(毫秒),默认 10000
    • services {string[]} - 要扫描的服务 UUID 数组
    • allowDuplicates {boolean} - 是否允许重复设备,默认 false
    • rssiThreshold {number} - RSSI 信号阈值(仅部分平台支持)
  • callback {Function} - 回调函数 callback(ret, err)

回调事件:

// 扫描开始
{ event: 'scanStart' }

// 发现设备
{
  event: 'deviceFound',
  device: {
    deviceId: 'xx:xx:xx:xx:xx:xx',  // 设备 MAC 地址或 UUID
    name: '设备名称',               // 蓝牙设备名称
    RSSI: -65,                     // 信号强度(dBm)
    advertisData: '...',           // 广播数据(十六进制字符串)
    serviceUuids: ['...']          // 服务 UUID 列表
  }
}

// 扫描停止
{ event: 'scanStop' }

// 扫描超时
{ event: 'timeout' }

BLEScanner.stopScan(callback)

停止扫描。

参数:

  • callback {Function} - 回调函数 callback(ret)

回调结果:

{ event: 'scanStop' }

BLEScanner.checkPermission(callback)

检查蓝牙权限。

参数:

  • callback {Function} - 回调函数 callback(ret)

回调结果:

{ granted: true }  // true: 有权限,false: 无权限

BLEScanner.requestPermission(callback)

请求蓝牙权限。

参数:

  • callback {Function} - 回调函数 callback(ret)

回调结果:

{
  requested: true,
  message: '提示信息'
}

BLEScanner.getDevices()

获取已发现的设备列表。

返回值:

[
  {
    deviceId: 'xx:xx:xx:xx:xx:xx',
    name: '设备名称',
    RSSI: -65
  }
]

TypeScript API

import { 
  createScanner, 
  createNativeScanner,
  BLEDevice,
  ScanOptions,
  ScanCallbacks 
} from '@fww_123/uni-ble-scanner';

// 创建设备
const scanner = createScanner({
  type: 'auto' // 'auto' | 'uniapp' | 'native' | 'web'
});

// 类型定义
interface BLEDevice {
  deviceId: string;
  name?: string;
  RSSI: number;
  advertisData?: string;
  serviceUuids?: string[];
}

interface ScanOptions {
  timeout?: number;
  services?: string[];
  allowDuplicates?: boolean;
  rssiThreshold?: number;
}

interface ScanCallbacks {
  onDeviceFound?: (device: BLEDevice) => void;
  onScanStart?: () => void;
  onScanStop?: () => void;
  onTimeout?: () => void;
  onError?: (error: BLEError) => void;
}

❓ 常见问题

Q1: 为什么扫描不到设备?

可能原因:

  1. 没有蓝牙权限 → 调用 BLEScanner.requestPermission()
  2. 蓝牙未开启 → 引导用户开启蓝牙
  3. Android 6.0+ 需要位置权限 → 检查定位权限
  4. iOS 需要在真机上测试 → 模拟器不支持蓝牙

Q2: 原生插件和 Bridge 有什么区别?

| 特性 | 原生插件 | Bridge | |------|---------|--------| | 性能 | 最好 | 好 | | 配置 | 需要配置 manifest | 引入即用 | | 兼容性 | 需要编译 | 纯 JS,无需编译 | | 适用场景 | 生产环境 | 开发/快速集成 |

Q3: 如何在 UniApp 中判断使用原生还是标准 API?

// universal-bridge.js 会自动判断
// 你也可以手动指定
const scanner = createScanner({ 
  type: 'native' // 强制使用原生
});

const scanner = createScanner({ 
  type: 'uniapp' // 强制使用标准 API
});

Q4: 支持后台扫描吗?

  • Android: 支持,需要后台定位权限
  • iOS: 支持,需要在 Info.plist 中配置 UIBackgroundModes
  • 鸿蒙: 支持
  • Web: 不支持

Q5: 如何打包发布?

# 1. 安装依赖
npm install

# 2. 编译 TypeScript
npm run build

# 3. 发布到 npm
npm publish --access public

� 目录结构

ble_test/
├── src/                          # TypeScript 源码
│   ├── core/
│   │   └── base-scanner.ts       # 扫描器基类
│   ├── platforms/
│   │   ├── android-native.ts     # Android 原生实现
│   │   ├── ios-native.ts         # iOS 原生实现
│   │   ├── harmony-native.ts     # 鸿蒙原生实现
│   │   ├── uniapp-scanner.ts     # UniApp 标准 API
│   │   └── web-scanner.ts        # Web Bluetooth
│   ├── utils/
│   │   ├── platform.ts           # 平台检测
│   │   ├── permissions.ts        # 权限管理
│   │   ├── errors.ts             # 错误处理
│   │   └── data-parser.ts        # 数据解析
│   ├── factory.ts                # 工厂函数
│   └── index.ts                  # 入口文件
├── native-plugins/               # 原生插件
│   ├── android/                  # Android 原生模块
│   │   └── ble-scanner/          # UniApp/APICloud 模块
│   ├── ios/                      # iOS 原生模块
│   │   └── ble-scanner/
│   ├── harmony/                  # 鸿蒙原生模块
│   │   └── entry/src/main/ets/components/ble/
│   └── bridge/
│       └── universal-bridge.js   # 跨框架 Bridge ⭐核心文件
├── examples/                     # 示例代码
│   ├── cross-framework-demo/     # 多框架集成示例
│   │   ├── uniapp/               # UniApp 示例
│   │   ├── apicloud/             # APICloud 示例
│   │   └── h5-webview/           # H5 WebView 示例
│   ├── native-app-demo/          # 原生 APP 示例
│   └── web-demo/                 # Web 示例
└── dist/                         # 编译输出

⚠️ 注意事项

Android

  • 权限配置AndroidManifest.xml):
<!-- Android 12+ -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

<!-- Android 11 及以下 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

<!-- 所有版本都需要 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  • 动态权限申请(Android 6.0+):
    • 需要动态申请位置和蓝牙权限

iOS

  • Info.plist 配置
<key>NSBluetoothAlwaysUsageDescription</key>
<string>需要使用蓝牙扫描设备</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>需要使用蓝牙扫描设备</string>
  • 必须使用真机测试,模拟器不支持蓝牙

鸿蒙

  • module.json5 配置
{
  "requestPermissions": [
    { "name": "ohos.permission.ACCESS_BLUETOOTH" },
    { "name": "ohos.permission.LOCATION" }
  ]
}

Web

  • 浏览器支持:仅 Chrome、Edge、Opera 支持 Web Bluetooth
  • HTTPS:必须在 HTTPS 环境下使用
  • 不支持后台扫描

� 支持与反馈

📄 许可证

MIT License


Made with ❤️ for cross-platform BLE scanning