更新记录

1.0.1(2026-07-07)

p2p 传输优化

1.0.0(2026-07-03)

首次提交


平台兼容性

uni-app(4.81)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android Android插件版本 iOS 鸿蒙
- - - - - - 8.0 1.0.1 - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

uni-app x(4.82)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - - - - -

hl-xsx-glass-sdk

XSX AI Glass SDK 的 UniApp UTS 原生插件封装,提供蓝牙扫描连接、设备控制、状态监听、AI 识别、WiFi P2P 媒体传输等能力。

平台支持:仅 Android(minSdkVersion 26)

安装引入

import * as XSX from '@/uni_modules/hl-xsx-glass-sdk'

生命周期

在页面 onMounted 中初始化 SDK 并注册监听,在 onUnmounted 中移除监听并释放资源:

import { onMounted, onUnmounted } from 'vue'

onMounted(() => {
  XSX.initSDK()
  XSX.setConnectionListener((state) => { /* ... */ })
  XSX.setBatteryListener((info) => { /* ... */ })
  XSX.setStorageSpaceListener((space) => { /* ... */ })
  XSX.setMediaDownloadListener((info) => { /* ... */ })
})

onUnmounted(() => {
  XSX.removeConnectionListener()
  XSX.removeBatteryListener()
  XSX.removeStorageSpaceListener()
  XSX.removeMediaDownloadListener()
  XSX.releaseSDK()
})

API 参考

一、权限管理

checkPermission

检查单个 Android 权限是否已授权。

const hasPermission = XSX.checkPermission('android.permission.BLUETOOTH_SCAN')
console.log(`蓝牙扫描权限: ${hasPermission}`)

requestPermissions

批量申请权限,回调返回每个权限的授权状态。

XSX.requestPermissions(
  ['android.permission.BLUETOOTH_SCAN', 'android.permission.ACCESS_FINE_LOCATION'],
  (result) => {
    console.log(`全部授权: ${result.allGranted}`)
    result.results.forEach((item) => {
      console.log(`${item.permission}: ${item.granted ? '已授权' : '未授权'}`)
    })
  }
)

requestBluetoothPermissions

一键申请蓝牙扫描、连接、定位所需的全部权限。

XSX.requestBluetoothPermissions((granted) => {
  if (granted) {
    console.log('蓝牙权限已就绪,可以开始扫描')
  } else {
    console.log('蓝牙权限被拒绝')
  }
})

requestWiFiPermissions

一键申请 WiFi P2P 相关权限。

  • Android 13+(API 33+):申请 NEARBY_WIFI_DEVICES
  • Android 12 及以下:申请 ACCESS_FINE_LOCATION / ACCESS_COARSE_LOCATION

⚠️ 这两个权限策略不能混合申请。Manifest 中 NEARBY_WIFI_DEVICES 必须声明 android:usesPermissionFlags="neverForLocation",否则在 Android 13+ 上会抛出 IllegalArgumentException

XSX.requestWiFiPermissions((granted) => {
  if (granted) {
    console.log('WiFi 权限已就绪,可以进行媒体传输')
  } else {
    console.log('WiFi 权限被拒绝')
  }
})

requestCameraStoragePermissions

一键申请相机与存储权限。

XSX.requestCameraStoragePermissions((granted) => {
  console.log(`相机存储权限: ${granted ? '已授权' : '未授权'}`)
})

requestPermissionGroup

按预定义场景分组申请权限。可选分组:'bluetooth' | 'wifi' | 'cameraStorage' | 'location' | 'recordAudio' | 'storage' | 'camera'

XSX.requestPermissionGroup('location', (granted) => {
  console.log(`定位权限: ${granted ? '已授权' : '未授权'}`)
})

Android 权限配置说明

插件已内置以下权限声明,一般无需额外配置。但如果你的宿主工程也声明了同名权限,注意避免 flags 冲突:

<!-- Android 13+ 必须加 neverForLocation -->
<uses-permission
    android:name="android.permission.NEARBY_WIFI_DEVICES"
    android:usesPermissionFlags="neverForLocation" />

<!-- Android 12 及以下 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<!-- 常规 WiFi / 网络权限 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />

注意事项:

  • usesPermissionFlags="neverForLocation" 要求 compileSdkVersion >= 33
  • CHANGE_WIFI_STATE / CHANGE_NETWORK_STATE / ACCESS_WIFI_STATE / ACCESS_NETWORK_STATE 属于 normal 权限,无需运行时申请。
  • WiFi P2P 扫描/连接还依赖系统定位服务总开关(GPS 或网络定位至少开启一个),请在调用前自行检查并引导用户开启。

二、系统设置

isBluetoothEnabled

检查设备蓝牙是否开启。

if (!XSX.isBluetoothEnabled()) {
  console.log('请先开启蓝牙')
}

isLocationEnabled

检查系统定位服务(GPS)是否开启。

if (!XSX.isLocationEnabled()) {
  console.log('请先开启定位服务')
}

requestBluetoothEnable

调起系统蓝牙开启弹窗,引导用户打开蓝牙。

XSX.requestBluetoothEnable()

openAppSettings

跳转到当前应用的系统权限设置页面。

XSX.openAppSettings()

openLocationSettings

跳转到系统定位服务设置页面。

XSX.openLocationSettings()

三、SDK 管理

initSDK

初始化 SDK,必须在所有其他 API 调用前执行。

XSX.initSDK()

releaseSDK

释放 SDK 资源,建议在页面卸载时调用。

XSX.releaseSDK()

setLog

设置 SDK 日志输出开关。

  • enableLog:是否在控制台打印日志
  • writeFile:是否将日志写入文件
// 开启控制台日志,不写文件
XSX.setLog(true, false)

// 关闭所有日志
XSX.setLog(false, false)

四、蓝牙扫描与连接

startScan

开始扫描周边蓝牙设备,每发现一个设备回调一次。

const devices = []
XSX.startScan((device) => {
  console.log(`发现设备: ${device.name} (${device.address}), 信号: ${device.rssi}dBm`)
  devices.push(device)
})

stopScan

停止蓝牙扫描。

XSX.stopScan()

connectDevice

连接到指定设备(通过名称和 MAC 地址)。连接结果通过 setConnectionListener 回调。

XSX.connectDevice('XSX-Glass-001', 'AA:BB:CC:DD:EE:FF')

disconnect

断开当前设备连接。

XSX.disconnect()

unbindDevice

解绑当前设备(解除绑定关系,断开连接)。

XSX.unbindDevice()

removeBtBond

移除系统蓝牙配对记录。

XSX.removeBtBond()

autoConnect

自动连接之前已绑定的设备(无需重新扫描)。

XSX.autoConnect()

isAuthenticated

检查当前是否已连接并完成认证。

if (XSX.isAuthenticated()) {
  console.log('设备已连接并认证,可以进行控制操作')
}

isDeviceBound

检查当前是否已绑定设备。

if (XSX.isDeviceBound()) {
  console.log('已绑定设备,可尝试自动连接')
}

getDeviceInfo

获取当前已连接设备的详细信息,未连接时返回 null

const info = XSX.getDeviceInfo()
if (info != null) {
  console.log(`当前设备: ${info.name}, MAC: ${info.address}, RSSI: ${info.rssi}`)
}

五、状态监听

setConnectionListener / removeConnectionListener

注册/移除连接状态监听。回调参数 XSXConnectionState 包含状态码、状态描述、关联设备和认证标志。

XSX.setConnectionListener((state) => {
  console.log(`状态: ${state.stateName} (code=${state.state})`)
  console.log(`已认证: ${state.isAuthenticated}`)
  if (state.device != null) {
    console.log(`设备: ${state.device.name} (${state.device.address})`)
  }
})

// 页面卸载时移除
XSX.removeConnectionListener()

setBatteryListener / removeBatteryListener

注册/移除电量监听。回调参数 XSXBatteryInfo 包含左右眼电量、充电状态和低电提醒。

XSX.setBatteryListener((info) => {
  console.log(`左眼: ${info.leftBattery}%, 右眼: ${info.rightBattery}%`)
  console.log(`左充电: ${info.isLeftCharging}, 右充电: ${info.isRightCharging}`)
  console.log(`总体: ${info.batteryLevel}%, 低电: ${info.isLowPower}`)
})

// 页面卸载时移除
XSX.removeBatteryListener()

setStorageSpaceListener / removeStorageSpaceListener

注册/移除设备存储空间变化监听。

XSX.setStorageSpaceListener((space) => {
  console.log(`已用: ${space.usedStorageSpace}, 可用: ${space.unuseStorageSpace}`)
})

// 页面卸载时移除
XSX.removeStorageSpaceListener()

getBatteryInfo

主动获取当前电量信息(非监听方式),未连接时返回 null

const info = XSX.getBatteryInfo()
if (info != null) {
  console.log(`电量: 左${info.leftBattery}% 右${info.rightBattery}%`)
}

getDeviceStatus

获取设备当前运行状态(是否正在录像/录音),未连接时返回 null

const status = XSX.getDeviceStatus()
if (status != null) {
  console.log(`正在录像: ${status.isVideoRecording}`)
  console.log(`正在录音: ${status.isAudioRecording}`)
}

六、设备控制

takePicture

控制设备拍照。返回 true 表示指令发送成功。

const ok = XSX.takePicture()
console.log(`拍照: ${ok ? '成功' : '失败'}`)

startRecordVideo

开始录像,可指定最长录制时长(秒)。

// 录制最长 15 秒
const ok = XSX.startRecordVideo(15)
console.log(`开始录像: ${ok ? '成功' : '失败'}`)

stopRecordVideo

手动停止录像(未到设定时长时提前结束)。

const ok = XSX.stopRecordVideo()
console.log(`停止录像: ${ok ? '成功' : '失败'}`)

startRecordAudio

开始录音,可指定最长录制时长(秒)。

// 录制最长 30 秒
const ok = XSX.startRecordAudio(30)
console.log(`开始录音: ${ok ? '成功' : '失败'}`)

stopRecordAudio

手动停止录音。

const ok = XSX.stopRecordAudio()
console.log(`停止录音: ${ok ? '成功' : '失败'}`)

shutDown

控制设备关机。

const ok = XSX.shutDown()
console.log(`关机: ${ok ? '成功' : '失败'}`)

restart

控制设备重启。

const ok = XSX.restart()
console.log(`重启: ${ok ? '成功' : '失败'}`)

restore

控制设备恢复出厂设置。

const ok = XSX.restore()
console.log(`恢复出厂: ${ok ? '成功' : '失败'}`)

syncTime

将手机当前时间同步到眼镜设备。

const ok = XSX.syncTime()
console.log(`同步时间: ${ok ? '成功' : '失败'}`)

七、设备参数

getDeviceParams

读取设备当前参数设置。

const ok = XSX.getDeviceParams()
console.log(`读取参数: ${ok ? '已发送' : '失败'}`)

setDeviceParams

设置设备参数。不修改的字段传 null 即可跳过。

XSXSetParams 字段说明:

字段 类型 说明
deviceName string \| null 设备名称
eqModel number \| null EQ 均衡模式
checkWear boolean \| null 佩戴检测开关
openPictureDateWaterMark boolean \| null 照片日期水印
openVideoDateWaterMark boolean \| null 视频日期水印
cameraRatio XSXCameraRatio \| null 相机分辨率(含 photo/video/AI 识别三项)
voiceAssistant boolean \| null 语音助手开关
languageCode number \| null 语言编码
videoDuration number \| null 默认录像时长(秒)
// 仅修改设备名称和佩戴检测,其余保持不变
XSX.setDeviceParams({
  deviceName: 'My Glass',
  eqModel: null,
  checkWear: true,
  openPictureDateWaterMark: null,
  openVideoDateWaterMark: null,
  cameraRatio: null,
  voiceAssistant: null,
  languageCode: null,
  videoDuration: null
})

八、AI 能力

initAI

初始化 AI 模块,回调返回 AI 类型:'domestic'(国内)或 'oversea'(海外)。

XSX.initAI((type) => {
  console.log(`AI 初始化完成,模式: ${type}`) // domestic / oversea
})

takePictureAndRecognize

拍照并使用 AI 识别图片内容,需传入识别提示词。需先调用 initAI

const ok = XSX.takePictureAndRecognize('描述一下这张图片的内容')
console.log(`拍照识别: ${ok ? '已发送' : '失败'}`)

九、WiFi P2P 媒体传输

startDownloadMedia

开始通过 WiFi P2P 从眼镜设备下载媒体文件。

调用前必须满足以下前置条件:

  1. 蓝牙设备已完成认证(isAuthenticated() === true
  2. 手机 WiFi 开关已开启
  3. 系统定位服务(GPS 或网络定位)已开启
  4. 已申请 WiFi P2P 相关权限(requestWiFiPermissions
  5. 已设置媒体下载监听(setMediaDownloadListener
XSX.requestWiFiPermissions((granted) => {
  if (!granted) return
  XSX.setMediaDownloadListener((info) => {
    // 根据 info.type 处理不同事件
  })
  XSX.startDownloadMedia()
})

setMediaDownloadListener / removeMediaDownloadListener

注册/移除媒体文件下载进度监听。详见下方 媒体下载回调详解

XSX.setMediaDownloadListener((info) => {
  switch (info.type) {
    case 'onDownloadStart':
    case 'onDownloadingMedia':
    case 'onDownloadProgress':
      if (info.totalBytes > 0) {
        const percent = Math.round((info.downloadedBytes / info.totalBytes) * 100)
        console.log(`[${info.type}] 文件 ${info.currentIndex}/${info.mediaNum} - ${percent}%`)
      }
      break
    case 'onDownloadSuccess':
      console.log(`文件已保存至: ${info.filePath}`)
      break
    case 'onDownloadComplete':
      console.log('全部文件下载完成')
      break
    case 'diagnostic':
      console.log(`[诊断] ${info.message}`)
      break
  }
})

// 页面卸载时移除
XSX.removeMediaDownloadListener()

restartP2P

重启 WiFi P2P 连接(连接异常时使用)。

const ok = XSX.restartP2P()
console.log(`重启 P2P: ${ok ? '成功' : '失败'}`)

disconnectWiFi

断开 WiFi P2P 连接。

XSX.disconnectWiFi()

getResourceInfoFilesTotal

获取眼镜设备上可导入的媒体文件总数。

const total = XSX.getResourceInfoFilesTotal()
console.log(`可导入文件数: ${total}`)

transferFileDone

通知眼镜设备当前文件传输已完成。

XSX.transferFileDone()

媒体下载回调详解

调用 setMediaDownloadListener 后,下载过程中会持续回调 XSXMediaDownloadInfo 对象。

回调字段说明

字段 类型 说明
type string 回调事件类型标识,详见 回调事件类型
hotspotType number 热点连接类型
serverIp string \| null 文件传输服务端 IP 地址
port number 文件传输服务端端口号
mediaNum number 本次传输的文件总数
currentIndex number 当前正在下载的文件序号(从 1 开始)
downloadedBytes number 当前文件已下载的字节数
totalBytes number 当前文件的总字节数
filePath string \| null 文件下载完成后的本地保存路径(仅 onDownloadSuccess 时有值)
message string \| null 附加消息(如错误信息、状态提示等)

回调事件类型

事件类型 说明
onMediaNum 获取到可导入文件总数,mediaNum 字段有效
hotspotStartSuccess 眼镜热点已启动成功,SDK 内部将自动连接手机到眼镜热点
onConnected 手机已成功连接到眼镜 WiFi 热点
onDownloadStart 开始下载单个文件
onDownloadingMedia 正在下载媒体数据
onDownloadProgress 下载进度更新
onDownloadSuccess 单个文件下载成功,filePath 字段有效
onDownloadComplete 全部文件下载完成
onDownloadFail 下载失败
discoverHotspotTimeout / discoverPeersTimeout / onConnectTimeout 热点发现 / 设备发现 / 连接超时
onDecodeOpus* 音频解码相关事件
diagnostic 诊断/调试日志消息,message 字段有效

进度计算

XSX.setMediaDownloadListener((info) => {
  switch (info.type) {
    case 'onMediaNum':
      console.log(`可导入文件总数: ${info.mediaNum}`)
      break

    case 'hotspotStartSuccess':
      console.log('眼镜热点已启动,等待手机连接...')
      break

    case 'onConnected':
      console.log('已连接到眼镜 WiFi 热点')
      break

    case 'onDownloadStart':
    case 'onDownloadingMedia':
    case 'onDownloadProgress':
      // 总体进度
      const fileProgress = `${info.currentIndex} / ${info.mediaNum}`
      // 单文件进度
      const filePercent = info.totalBytes > 0
        ? Math.round((info.downloadedBytes / info.totalBytes) * 100)
        : 0
      console.log(`文件 ${fileProgress},下载 ${filePercent}%`)
      break

    case 'onDownloadSuccess':
      console.log(`第 ${info.currentIndex} 个文件已保存: ${info.filePath}`)
      break

    case 'onDownloadComplete':
      console.log('全部文件下载完成')
      // 可选:通知设备传输完成
      // XSX.transferFileDone()
      break

    case 'onDownloadFail':
    case 'discoverHotspotTimeout':
    case 'discoverPeersTimeout':
    case 'onConnectTimeout':
      console.log(`传输异常/超时: ${info.message}`)
      break

    case 'diagnostic':
      console.log(`[诊断] ${info.message}`)
      break
  }
})

完整媒体导入流程

import * as XSX from '@/uni_modules/hl-xsx-glass-sdk'

// 前置检查
if (!XSX.isAuthenticated()) {
  console.log('设备未认证,请先连接并认证蓝牙设备')
  return
}

// 1. 检查系统定位服务(WiFi 扫描依赖定位开关)
//    若未开启,请引导用户跳转到系统设置页开启 GPS 或网络定位

// 2. 检查 WiFi 开关是否已开启
//    若未开启,请引导用户开启 WiFi

// 3. 申请 WiFi P2P 权限
XSX.requestWiFiPermissions((granted) => {
  if (!granted) {
    console.log('WiFi 权限未授权,无法传输')
    return
  }

  // 4. 注册下载监听(必须在 startDownloadMedia 之前设置)
  XSX.setMediaDownloadListener((info) => {
    switch (info.type) {
      case 'onMediaNum':
        console.log(`可导入文件总数: ${info.mediaNum}`)
        break
      case 'hotspotStartSuccess':
        console.log('热点启动成功')
        break
      case 'onConnected':
        console.log('已连接眼镜热点')
        break
      case 'onDownloadProgress':
      case 'onDownloadingMedia':
      case 'onDownloadStart':
        if (info.totalBytes > 0) {
          const percent = Math.round((info.downloadedBytes / info.totalBytes) * 100)
          console.log(`文件 ${info.currentIndex}/${info.mediaNum} - ${percent}%`)
        }
        break
      case 'onDownloadSuccess':
        console.log(`已保存: ${info.filePath}`)
        break
      case 'onDownloadComplete':
        console.log('全部下载完成')
        break
      case 'onDownloadFail':
      case 'discoverHotspotTimeout':
      case 'discoverPeersTimeout':
      case 'onConnectTimeout':
        console.log(`异常: ${info.message}`)
        break
      case 'diagnostic':
        console.log(`[诊断] ${info.message}`)
        break
    }
  })

  // 5. 查看可导入文件总数
  const total = XSX.getResourceInfoFilesTotal()
  console.log(`设备上有 ${total} 个媒体文件可导入`)

  // 6. 开始下载
  XSX.startDownloadMedia()
})

数据类型

XSXDevice — 蓝牙设备

type XSXDevice = {
  name: string          // 设备名称
  address: string       // MAC 地址
  rssi: number          // 信号强度(dBm)
  scanRecord: string | null
}

XSXConnectionState — 连接状态

type XSXConnectionState = {
  state: number             // 状态码
  stateName: string         // 状态描述(如"已连接"、"已断开"等)
  device: XSXDevice | null  // 关联设备信息
  isAuthenticated: boolean  // 是否已完成认证
}

XSXBatteryInfo — 电量信息

type XSXBatteryInfo = {
  leftBattery: number       // 左眼电量 %
  rightBattery: number      // 右眼电量 %
  isLeftCharging: boolean   // 左眼是否在充电
  isRightCharging: boolean  // 右眼是否在充电
  batteryLevel: number      // 总体电量 %
  isLowPower: boolean       // 是否低电量警告
}

XSXDeviceStatus — 设备运行状态

type XSXDeviceStatus = {
  isVideoRecording: boolean  // 是否正在录像
  isAudioRecording: boolean  // 是否正在录音
}

XSXStorageSpace — 存储空间

type XSXStorageSpace = {
  usedStorageSpace: number   // 已用空间(字节)
  unuseStorageSpace: number  // 可用空间(字节)
}

XSXCameraRatio — 相机分辨率

type XSXCameraRatio = {
  pictureRatio: number       // 拍照分辨率
  videoRatio: number         // 录像分辨率
  aiRecognizeRatio: number   // AI 识别分辨率
}

XSXMediaDownloadInfo — 媒体下载信息

详见 媒体下载回调详解

type XSXMediaDownloadInfo = {
  type: string               // 回调事件类型标识
  hotspotType: number        // 热点连接类型
  serverIp: string | null    // 服务端 IP
  port: number               // 服务端端口
  mediaNum: number           // 文件总数
  currentIndex: number       // 当前文件序号
  downloadedBytes: number    // 已下载字节数
  totalBytes: number         // 文件总字节数
  filePath: string | null    // 本地保存路径(onDownloadSuccess 时有值)
  message: string | null     // 附加消息
}

XSXPermissionResult — 权限申请结果

type XSXPermissionResult = {
  permission: string   // 权限常量名
  granted: boolean     // 是否已授权
}

type XSXPermissionRequestResult = {
  allGranted: boolean                // 是否全部授权
  results: XSXPermissionResult[]     // 每个权限的详细结果
}

注意事项

  1. 必须使用自定义基座运行,标准基座不包含原生 SDK
  2. 扫描前需确保蓝牙和定位均已开启,并申请对应权限
  3. setDeviceParams 中不修改的字段传 null 即可跳过
  4. 页面退出时务必调用 removeXxxListenerreleaseSDK 释放资源
  5. WiFi P2P 媒体传输前需确保:蓝牙设备已认证、WiFi 开关已开启、系统定位服务已开启,并已申请 WiFi 相关权限
  6. setMediaDownloadListener 必须在 startDownloadMedia 之前调用,否则会丢失进度回调
  7. AI 识别功能需先调用 initAI 完成初始化

隐私、权限声明

1. 本插件需要申请的系统权限列表:

需要蓝牙、定位、WiFi、存储等系统权限。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不主动采集业务数据;蓝牙设备数据仅在应用调用接口时透传给调用方。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。