news 2026/3/20 16:21:29

HarmonyOS 星闪快速实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HarmonyOS 星闪快速实战

一、什么是星闪?

星闪(NearLink)是华为研发的新一代短距离无线通信技术,可以理解为"华为版蓝牙"(仅限我们目前用的,有对标WiFi的版本),但比蓝牙更快、更稳、更省电。

星闪的优点:

  • 低延迟、高带宽、低功耗。

星闪的缺点:

  • 当前只能连接华为设备,不能连 iPhone 等其他设备
  • 设备还不多,在发展中

开发星闪应用需要什么?

  • 一台华为手机(运行 HarmonyOS 5.0+),星闪支持较好
  • 一个星闪设备(或另一台华为手机)
  • DevEco Studio 开发工具

二、第一步:导入需要的模块

// ====== common/NearLinkManager.ets ======// 这个文件放在 entry/src/main/ets/common/ 目录下// 星闪功能模块import{scan,advertising,ssap,constant}from'@kit.NearLinkKit';// scan: 扫描设备// advertising: 发送广播(可选)// ssap: 星闪应用层协议,类似蓝牙的 GATT// constant: 常量定义// 权限管理模块import{abilityAccessCtrl,Permissions,common}from'@kit.AbilityKit';// 错误处理模块import{BusinessError}from'@kit.BasicServicesKit';// 日志模块(可选)import{hilog}from'@kit.PerformanceAnalysisKit';

三、第二步:配置权限

星闪只需要一个权限,比蓝牙简单多了!

3.1 静态权限声明

// ====== entry/src/main/module.json5 ======// 只需要这一个权限,是不是超简单?{"module":{"requestPermissions":[{"name":"ohos.permission.ACCESS_NEARLINK",// 星闪权限(就这一个!)"reason":"$string:nearlink_permission_reason","usedScene":{"abilities":["EntryAbility"],"when":"inuse"}}]}}

3.2 权限说明字符串

// ====== entry/src/main/resources/base/element/string.json ======{"string":[{"name":"nearlink_permission_reason","value":"需要星闪权限以连接和控制星闪设备"}]}

3.3 动态权限申请(弹窗让用户确认)

// ====== common/PermissionManager.ets ======import{abilityAccessCtrl,Permissions,common}from'@kit.AbilityKit';exportclassPermissionManager{privatestaticinstance:PermissionManager;privatecontext?:common.UIAbilityContext;publicstaticgetInstance():PermissionManager{if(!PermissionManager.instance){PermissionManager.instance=newPermissionManager();}returnPermissionManager.instance;}publicsetContext(context:common.UIAbilityContext):void{this.context=context;}/** * 检查并申请星闪权限 * @returns 是否已授权 */publicasynccheckAndRequestNearLinkPermissions():Promise<boolean>{if(!this.context){console.error('Context not set');returnfalse;}constpermission:Permissions='ohos.permission.ACCESS_NEARLINK';try{constatManager=abilityAccessCtrl.createAtManager();// 检查权限constgrantStatus=awaitatManager.checkAccessToken(this.context.applicationInfo.accessTokenId,permission);if(grantStatus!==abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED){// 权限未授予,请求用户授权constrequestResult=awaitatManager.requestPermissionsFromUser(this.context,[permission]);if(requestResult.authResults[0]!==abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED){console.error('NearLink permission denied by user');returnfalse;}}console.info('NearLink permission granted');returntrue;}catch(error){console.error(`Permission request failed:${error}`);returnfalse;}}}

3.4 在 EntryAbility 中初始化(应用启动时设置)

// ====== EntryAbility.ets ======import{AbilityConstant,UIAbility,Want}from'@kit.AbilityKit';import{window}from'@kit.ArkUI';import{PermissionManager}from'../common/PermissionManager';import{NearLinkManager}from'../common/NearLinkManager';exportdefaultclassEntryAbilityextendsUIAbility{onCreate(want:Want,launchParam:AbilityConstant.LaunchParam):void{console.info('EntryAbility onCreate');}onWindowStageCreate(windowStage:window.WindowStage):void{// 设置上下文PermissionManager.getInstance().setContext(this.context);NearLinkManager.getInstance().setContext(this.context);windowStage.loadContent('pages/Index',(err)=>{if(err.code){console.error('Failed to load content');return;}});}}

四、第三步:SSAP 客户端实现(核心代码)

SSAP 是什么?星闪应用层协议(StarShine Application Protocol),类似蓝牙的 GATT,用来定义数据如何传输。

术语对照:

蓝牙星闪说明
GATTSSAP应用层协议
CharacteristicProperty数据容器
ServiceService服务分组

4.1 SSAP 客户端管理器

// ====== common/SSAPClient.ets ======// 这个文件放在 entry/src/main/ets/common/ 目录下import{ssap,constant}from'@kit.NearLinkKit';import{BusinessError}from'@kit.BasicServicesKit';// ========== 数据类型定义 ==========// 连接状态枚举exportenumConnectionState{DISCONNECTED=0,// 已断开CONNECTING=1,// 连接中...CONNECTED=2,// 已连接DISCONNECTING=3// 断开中...}// 属性权限枚举(这个属性能读/能写/能通知)exportenumPropertyPermission{READ=0x01,// 可读WRITE=0x02,// 可写NOTIFY=0x04// 可接收通知}// 连接状态变化信息exportinterfaceConnectionChangeState{address:string;state:ConnectionState;}// 属性通知信息exportinterfacePropertyNotification{address:string;serviceId:string;propertyId:string;value:ArrayBuffer;}// 发现的服务exportinterfaceDiscoveredService{serviceId:string;properties:DiscoveredProperty[];}// 发现的属性exportinterfaceDiscoveredProperty{propertyId:string;permissions:PropertyPermission[];}// 客户端信息interfaceClientInfo{address:string;client:ssap.Client;services:Array<ssap.Service>;connectionState:ConnectionState;}exportclassSSAPClient{privatestaticinstance:SSAPClient;privateclientMap:Map<string,ClientInfo>=newMap();// 回调函数privateconnectionStateCallbacks:((state:ConnectionChangeState)=>void)[]=[];privatepropertyNotificationCallbacks:((notification:PropertyNotification)=>void)[]=[];privateconstructor(){}publicstaticgetInstance():SSAPClient{if(!SSAPClient.instance){SSAPClient.instance=newSSAPClient();}returnSSAPClient.instance;}/** * 连接到 SSAP 服务端(连接星闪设备) * @param address 设备地址 * @returns 是否连接成功 */publicasyncconnectToServer(address:string):Promise<boolean>{try{// 检查是否已连接,防止重复连接if(this.clientMap.has(address)){constexisting=this.clientMap.get(address);if(existing?.connectionState===ConnectionState.CONNECTED){console.info(`已经连接了这个设备:${address}`);returntrue;}}console.info(`正在连接星闪设备:${address}`);// 创建 SSAP 客户端constclient:ssap.Client=ssap.createClient(address);constclientInfo:ClientInfo={address:address,client:client,services:[],connectionState:ConnectionState.CONNECTING};this.clientMap.set(address,clientInfo);// 注册连接状态变化回调client.on('connectionStateChange',(data:ssap.ConnectionChangeState)=>{this.handleConnectionStateChange(address,data);});// 注册属性变化回调client.on('propertyChange',(data:ssap.Property)=>{this.handlePropertyChange(address,data);});// 连接awaitclient.connect();console.info(`Connection request sent:${address}`);returntrue;}catch(error){console.error(`Connect failed:${error}`);this.clientMap.delete(address);returnfalse;}}/** * 处理连接状态变化 */privatehandleConnectionStateChange(address:string,data:ssap.ConnectionChangeState):void{constclientInfo=this.clientMap.get(address);if(!clientInfo)return;letnewState:ConnectionState;if(data.state===constant.ConnectionState.STATE_CONNECTED){newState=ConnectionState.CONNECTED;clientInfo.connectionState=newState;// 连接成功后获取服务列表this.getServices(address);}elseif(data.state===constant.ConnectionState.STATE_DISCONNECTED){newState=ConnectionState.DISCONNECTED;clientInfo.connectionState=newState;clientInfo.services=[];}elseif(data.state===constant.ConnectionState.STATE_CONNECTING){newState=ConnectionState.CONNECTING;clientInfo.connectionState=newState;}elseif(data.state===constant.ConnectionState.STATE_DISCONNECTING){newState=ConnectionState.DISCONNECTING;clientInfo.connectionState=newState;}else{newState=ConnectionState.DISCONNECTED;}// 通知所有订阅者constchangeState:ConnectionChangeState={address,state:newState};this.connectionStateCallbacks.forEach(callback=>callback(changeState));}/** * 处理属性变化 */privatehandlePropertyChange(address:string,data:ssap.Property):void{constnotification:PropertyNotification={address:address,serviceId:data.serviceUuid,propertyId:data.propertyUuid,value:data.value};this.propertyNotificationCallbacks.forEach(callback=>callback(notification));}/** * 获取服务列表 */privateasyncgetServices(address:string):Promise<void>{try{constclientInfo=this.clientMap.get(address);if(!clientInfo)return;constservices:Array<ssap.Service>=awaitclientInfo.client.getServices();clientInfo.services=services;console.info(`Discovered${services.length}services`);// 自动设置属性通知for(constserviceofservices){for(constpropofservice.properties){awaitthis.subscribePropertyNotification(address,service.serviceUuid,prop.propertyUuid);}}}catch(error){console.error(`Get services failed:${error}`);}}/** * 读取属性值 */publicasyncreadProperty(address:string,serviceId:string,propertyId:string):Promise<ArrayBuffer|null>{try{constclientInfo=this.clientMap.get(address);if(!clientInfo||clientInfo.services.length===0){console.error('Client not found or services not discovered');returnnull;}constproperty:ssap.Property={serviceUuid:serviceId,propertyUuid:propertyId,value:newArrayBuffer(1)};constresult:ssap.Property=awaitclientInfo.client.readProperty(property);returnresult.value;}catch(error){console.error(`Read property failed:${error}`);returnnull;}}/** * 写入属性值(双重写入策略) */publicasyncwriteProperty(address:string,serviceId:string,propertyId:string,value:ArrayBuffer):Promise<boolean>{try{constclientInfo=this.clientMap.get(address);if(!clientInfo||clientInfo.services.length===0){console.error('Client not found or services not discovered');returnfalse;}constproperty:ssap.Property={serviceUuid:serviceId,propertyUuid:propertyId,value:value};// 双重写入策略try{awaitclientInfo.client.writeProperty(property,ssap.PropertyWriteType.WRITE);console.info('Write property success (WRITE mode)');returntrue;}catch(writeError){console.warn('WRITE mode failed, trying WRITE_NO_RESPONSE');awaitclientInfo.client.writeProperty(property,ssap.PropertyWriteType.WRITE_NO_RESPONSE);console.info('Write property success (WRITE_NO_RESPONSE mode)');returntrue;}}catch(error){console.error(`Write property failed:${error}`);returnfalse;}}/** * 订阅属性通知 */publicasyncsubscribePropertyNotification(address:string,serviceId:string,propertyId:string):Promise<boolean>{try{constclientInfo=this.clientMap.get(address);if(!clientInfo)returnfalse;constproperty:ssap.Property={serviceUuid:serviceId,propertyUuid:propertyId,value:newArrayBuffer(1)};awaitclientInfo.client.setPropertyNotification(property,true);returntrue;}catch(error){console.error(`Subscribe notification failed:${error}`);returnfalse;}}/** * 断开连接 */publicasyncdisconnectFromServer(address:string):Promise<void>{try{constclientInfo=this.clientMap.get(address);if(!clientInfo)return;awaitclientInfo.client.disconnect();clientInfo.client.off('propertyChange');clientInfo.client.off('connectionStateChange');clientInfo.client.close();this.clientMap.delete(address);console.info(`Disconnected from:${address}`);}catch(error){console.error(`Disconnect failed:${error}`);}}/** * 获取发现的服务 */publicgetDiscoveredServices(address:string):DiscoveredService[]{constclientInfo=this.clientMap.get(address);if(!clientInfo)return[];returnclientInfo.services.map((service:ssap.Service):DiscoveredService=>({serviceId:service.serviceUuid,properties:service.properties.map((prop:ssap.Property):DiscoveredProperty=>({propertyId:prop.propertyUuid,permissions:[PropertyPermission.READ,PropertyPermission.WRITE,PropertyPermission.NOTIFY]}))}));}// 回调管理publiconConnectionStateChange(callback:(state:ConnectionChangeState)=>void):void{this.connectionStateCallbacks.push(callback);}publiconPropertyNotification(callback:(notification:PropertyNotification)=>void):void{this.propertyNotificationCallbacks.push(callback);}}

四、第三步:星闪管理器(核心代码)

这是整个星闪功能的核心,包含扫描、连接、收发数据等所有功能。

// ====== common/NearLinkManager.ets ======import{scan,advertising}from'@kit.NearLinkKit';import{common}from'@kit.AbilityKit';import{BusinessError}from'@kit.BasicServicesKit';import{SSAPClient,ConnectionState,DiscoveredService,ConnectionChangeState,PropertyNotification}from'./SSAPClient';// 扫描结果接口exportinterfaceScanResult{deviceId:string;deviceName:string;address:string;rssi:number;}// 扫描过滤器接口exportinterfaceScanFilter{deviceName?:string;address?:string;}exportclassNearLinkManager{privatestaticinstance:NearLinkManager;privatecontext?:common.UIAbilityContext;privateisScanning:boolean=false;privatescanResults:Map<string,ScanResult>=newMap();privateconnectedDevice?:ScanResult;// 回调函数privateonDeviceFoundCallback?:(device:ScanResult)=>void;privateconnectionStateCallbacks:((device:ScanResult,state:ConnectionState)=>void)[]=[];privateonDataReceivedCallback?:(data:ArrayBuffer)=>void;// SSAP客户端privatessapClient:SSAPClient=SSAPClient.getInstance();privateconstructor(){this.setupSSAPClientCallback();}publicstaticgetInstance():NearLinkManager{if(!NearLinkManager.instance){NearLinkManager.instance=newNearLinkManager();}returnNearLinkManager.instance;}publicsetContext(context:common.UIAbilityContext):void{this.context=context;}/** * 设置 SSAP 客户端回调 */privatesetupSSAPClientCallback():void{// 连接状态变化回调this.ssapClient.onConnectionStateChange((state:ConnectionChangeState)=>{if(this.connectedDevice&&this.connectionStateCallbacks.length>0){letconnectionState:ConnectionState;switch(state.state){case0:connectionState=ConnectionState.DISCONNECTED;break;case1:connectionState=ConnectionState.CONNECTING;break;case2:connectionState=ConnectionState.CONNECTED;break;case3:connectionState=ConnectionState.DISCONNECTING;break;default:connectionState=ConnectionState.DISCONNECTED;}this.connectionStateCallbacks.forEach(callback=>{callback(this.connectedDevice!,connectionState);});}});// 属性通知回调this.ssapClient.onPropertyNotification((notification:PropertyNotification)=>{if(this.onDataReceivedCallback){this.onDataReceivedCallback(notification.value);}});}/** * 开始扫描 */publicstartScan(filters?:ScanFilter[]):void{if(this.isScanning){console.warn('Already scanning');return;}try{this.isScanning=true;this.scanResults.clear();// 注册设备发现回调scan.on('deviceFound',(data:Array<scan.ScanResults>)=>{data.forEach((result:scan.ScanResults)=>{constdevice:ScanResult={deviceId:result.address,deviceName:result.deviceName||'未知设备',address:result.address,rssi:result.rssi||-100};// 去重if(!this.scanResults.has(device.address)){this.scanResults.set(device.address,device);if(this.onDeviceFoundCallback){this.onDeviceFoundCallback(device);}}});});// 配置扫描参数constscanOptions:scan.ScanOptions={scanMode:2// 平衡扫描模式};// 构建过滤器constscanFilters:scan.ScanFilters[]=[];if(filters&&filters.length>0){filters.forEach(filter=>{constnearLinkFilter:scan.ScanFilters={};if(filter.deviceName){nearLinkFilter.deviceName=filter.deviceName;}if(filter.address){nearLinkFilter.address=filter.address;}scanFilters.push(nearLinkFilter);});}constfiltersToUse=scanFilters.length>0?scanFilters:[({}asscan.ScanFilters)];scan.startScan(filtersToUse,scanOptions).then(()=>{console.info('NearLink scan started');}).catch((err:BusinessError)=>{console.error(`Start scan failed:${err.message}`);this.isScanning=false;});}catch(error){console.error(`Start scan exception:${error}`);this.isScanning=false;}}/** * 停止扫描 */publicstopScan():void{if(!this.isScanning)return;try{scan.stopScan().then(()=>console.info('NearLink scan stopped')).catch((err:BusinessError)=>console.error(`Stop scan failed:${err.message}`));scan.off('deviceFound');this.isScanning=false;}catch(error){console.error(`Stop scan exception:${error}`);}}/** * 连接设备 */publicasyncconnectDevice(device:ScanResult):Promise<boolean>{try{this.connectedDevice=device;constsuccess=awaitthis.ssapClient.connectToServer(device.address);returnsuccess;}catch(error){console.error(`Connect device failed:${error}`);this.connectedDevice=undefined;returnfalse;}}/** * 断开连接 */publicasyncdisconnectDevice():Promise<void>{if(!this.connectedDevice)return;try{awaitthis.ssapClient.disconnectFromServer(this.connectedDevice.address);this.connectedDevice=undefined;}catch(error){console.error(`Disconnect failed:${error}`);}}/** * 发送数据 */publicasyncsendData(serviceId:string,propertyId:string,data:ArrayBuffer):Promise<boolean>{if(!this.connectedDevice)returnfalse;returnawaitthis.ssapClient.writeProperty(this.connectedDevice.address,serviceId,propertyId,data);}// 回调设置publicsetOnDeviceFoundCallback(callback:(device:ScanResult)=>void):void{this.onDeviceFoundCallback=callback;}publicsetOnConnectionStateChangedCallback(callback:(device:ScanResult,state:ConnectionState)=>void):void{if(!this.connectionStateCallbacks.includes(callback)){this.connectionStateCallbacks.push(callback);}}publicsetOnDataReceivedCallback(callback:(data:ArrayBuffer)=>void):void{this.onDataReceivedCallback=callback;}// GetterpublicgetIsScanning():boolean{returnthis.isScanning;}publicgetConnectedDevice():ScanResult|undefined{returnthis.connectedDevice;}publicgetDiscoveredServices():DiscoveredService[]{if(!this.connectedDevice)return[];returnthis.ssapClient.getDiscoveredServices(this.connectedDevice.address);}}

六、UI 组件实现

6.1 设备卡片组件

// ====== pages/NearLinkConnectionPage.ets ======import{ScanResult,ConnectionState}from'../common/NearLinkManager';@Component struct NearLinkDeviceCard{@Prop device:ScanResult;@Prop isConnected:boolean=false;onConnect?:()=>void;privategetSignalColor(rssi:number):string{if(rssi>=-50)return'#4CAF50';if(rssi>=-70)return'#FF9800';return'#FF5722';}build(){Row(){// 左侧:设备信息Column(){Row(){Text(this.device.deviceName).fontSize(16).fontWeight(FontWeight.Medium).fontColor(this.isConnected?'#9C27B0':'#333333').layoutWeight(1)// 星闪标识Text('NearLink').fontSize(10).fontColor('#9C27B0').backgroundColor('rgba(156, 39, 176, 0.1)').padding({left:6,right:6,top:2,bottom:2}).borderRadius(4)}.width('100%')Row(){Text(this.device.address).fontSize(12).fontColor('#999999').layoutWeight(1)Text(`${this.device.rssi}dBm`).fontSize(12).fontColor(this.getSignalColor(this.device.rssi))}.width('100%').margin({top:4})}.layoutWeight(1).alignItems(HorizontalAlign.Start)// 连接按钮Button(this.isConnected?'断开':'连接').fontSize(14).backgroundColor(this.isConnected?'#FF5722':'#9C27B0').fontColor(Color.White).height(36).width(70).margin({left:12}).onClick(()=>{if(this.onConnect){this.onConnect();}})}.width('100%').padding(16).backgroundColor(Color.White).borderRadius(12).shadow({radius:4,color:'rgba(0,0,0,0.1)',offsetY:2})}}

6.2 设备列表页面

// ====== pages/NearLinkConnectionPage.ets ======import{NearLinkManager,ScanResult,ConnectionState}from'../common/NearLinkManager';import{PermissionManager}from'../common/PermissionManager';import{promptAction}from'@kit.ArkUI';@Entry @Component struct NearLinkConnectionPage{@State discoveredDevices:ScanResult[]=[];@State isScanning:boolean=false;@State connectedDevice:ScanResult|null=null;privatenearLinkManager:NearLinkManager=NearLinkManager.getInstance();aboutToAppear():void{// 设置设备发现回调this.nearLinkManager.setOnDeviceFoundCallback((device:ScanResult)=>{constexists=this.discoveredDevices.find(d=>d.address===device.address);if(!exists){this.discoveredDevices=[...this.discoveredDevices,device];}});// 设置连接状态回调this.nearLinkManager.setOnConnectionStateChangedCallback((device:ScanResult,state:ConnectionState)=>{if(state===ConnectionState.CONNECTED){this.connectedDevice=device;promptAction.showToast({message:`已连接:${device.deviceName}`});}elseif(state===ConnectionState.DISCONNECTED){this.connectedDevice=null;promptAction.showToast({message:'设备已断开'});}});}aboutToDisappear():void{this.nearLinkManager.stopScan();}privateasyncstartScan():Promise<void>{// 检查并申请权限consthasPermission=awaitPermissionManager.getInstance().checkAndRequestNearLinkPermissions();if(!hasPermission){promptAction.showToast({message:'请授予星闪权限后重试'});return;}this.discoveredDevices=[];this.nearLinkManager.startScan();this.isScanning=true;// 10秒后自动停止扫描setTimeout(()=>{this.stopScan();},10000);}privatestopScan():void{this.nearLinkManager.stopScan();this.isScanning=false;}privateasynconDeviceClick(device:ScanResult):Promise<void>{if(this.connectedDevice?.address===device.address){awaitthis.nearLinkManager.disconnectDevice();}else{this.stopScan();awaitthis.nearLinkManager.connectDevice(device);}}build(){Column(){// 标题栏Row(){Text('星闪设备').fontSize(20).fontWeight(FontWeight.Bold)Blank()Button(this.isScanning?'停止扫描':'开始扫描').fontSize(14).backgroundColor(this.isScanning?'#FF5722':'#9C27B0').onClick(()=>{if(this.isScanning){this.stopScan();}else{this.startScan();}})}.width('100%').padding(16)// 扫描状态if(this.isScanning){Row(){LoadingProgress().width(20).height(20).color('#9C27B0')Text('正在扫描星闪设备...').fontSize(14).fontColor('#666666').margin({left:8})}.width('100%').justifyContent(FlexAlign.Center).padding(16)}// 设备列表if(this.discoveredDevices.length===0){Column(){Text('⚡').fontSize(48).margin({bottom:16})Text(this.isScanning?'正在搜索星闪设备...':'未发现设备').fontSize(16).fontColor('#999999')}.width('100%').height(200).justifyContent(FlexAlign.Center)}else{List({space:12}){ForEach(this.discoveredDevices,(device:ScanResult)=>{ListItem(){NearLinkDeviceCard({device:device,isConnected:this.connectedDevice?.address===device.address,onConnect:()=>this.onDeviceClick(device)})}},(device:ScanResult)=>device.address)}.width('100%').layoutWeight(1).padding({left:16,right:16})}}.width('100%').height('100%').backgroundColor('#F5F5F5')}}

6.3 服务/属性卡片组件

// ====== pages/NearLinkDeviceDetailPage.ets ======import{NearLinkManager,DiscoveredService,DiscoveredProperty}from'../common/NearLinkManager';import{router}from'@kit.ArkUI';@Entry @Component struct NearLinkDeviceDetailPage{@State services:DiscoveredService[]=[];privatenearLinkManager:NearLinkManager=NearLinkManager.getInstance();aboutToAppear():void{this.services=this.nearLinkManager.getDiscoveredServices();}privateimportUUID(serviceId:string,propertyId:string):void{router.pushUrl({url:'pages/SettingsPage',params:{importServiceUUID:serviceId,importCharacteristicUUID:propertyId}});}@BuilderServiceCard(service:DiscoveredService,index:number){Column(){// 服务标题Row(){Text(`服务${index+1}`).fontSize(14).fontWeight(FontWeight.Medium).fontColor('#333333')Blank()Text('SSAP Service').fontSize(12).fontColor('#9C27B0').backgroundColor('rgba(156, 39, 176, 0.1)').padding({left:8,right:8,top:2,bottom:2}).borderRadius(4)}.width('100%').margin({bottom:8})// 服务 UUIDText(service.serviceId).fontSize(12).fontColor('#666666').width('100%').margin({bottom:12})// 属性列表if(service.properties.length>0){Text('属性列表').fontSize(13).fontColor('#999999').width('100%').margin({bottom:8})ForEach(service.properties,(prop:DiscoveredProperty,propIndex:number)=>{Row(){Column(){Text(`属性${propIndex+1}`).fontSize(12).fontColor('#333333')Text(prop.propertyId).fontSize(11).fontColor('#999999').maxLines(1).textOverflow({overflow:TextOverflow.Ellipsis})}.layoutWeight(1).alignItems(HorizontalAlign.Start)Button('导入').fontSize(12).height(28).backgroundColor('#9C27B0').fontColor(Color.White).onClick(()=>{this.importUUID(service.serviceId,prop.propertyId);})}.width('100%').padding(8).backgroundColor('#F5F5F5').borderRadius(4).margin({bottom:4})},(prop:DiscoveredProperty)=>prop.propertyId)}}.width('100%').padding(16).backgroundColor(Color.White).borderRadius(12).shadow({radius:2,color:'rgba(0,0,0,0.1)',offsetY:1})}build(){Column(){// 标题栏Row(){Button('返回').backgroundColor(Color.Transparent).fontColor('#9C27B0').onClick(()=>router.back())Text('设备详情').fontSize(18).fontWeight(FontWeight.Medium).layoutWeight(1).textAlign(TextAlign.Center)Text('').width(60)}.width('100%').padding(16)// 服务列表if(this.services.length===0){Column(){Text('未发现服务').fontSize(16).fontColor('#999999')}.width('100%').height(200).justifyContent(FlexAlign.Center)}else{Scroll(){Column({space:12}){ForEach(this.services,(service:DiscoveredService,index:number)=>{this.ServiceCard(service,index)},(service:DiscoveredService)=>service.serviceId)}.width('100%').padding(16)}.layoutWeight(1)}}.width('100%').height('100%').backgroundColor('#F5F5F5')}}

6.4 UUID 配置页面

// ====== pages/NearLinkSettingsPage.ets ======import{router}from'@kit.ArkUI';@Entry @Component struct NearLinkSettingsPage{@State serviceUUID:string='';@State propertyUUID:string='';@State filterEnabled:boolean=false;@State filterDeviceName:string='';aboutToAppear():void{constparams=router.getParams()asRecord<string,string>;if(params){if(params.importServiceUUID){this.serviceUUID=params.importServiceUUID;}if(params.importCharacteristicUUID){this.propertyUUID=params.importCharacteristicUUID;}}}@BuilderUUIDConfigSection(){Column(){Text('UUID 配置').fontSize(16).fontWeight(FontWeight.Medium).alignSelf(ItemAlign.Start).margin({bottom:16})// 服务 UUIDRow(){Text('服务UUID').fontSize(14).fontColor('#666666').width(80)TextInput({placeholder:'请输入服务UUID',text:this.serviceUUID}).layoutWeight(1).margin({left:12,right:12}).onChange((value:string)=>{this.serviceUUID=value;})Button('重置').fontSize(12).backgroundColor('#F5F5F5').fontColor('#9C27B0').width(60).height(32).onClick(()=>{this.serviceUUID='';})}.width('100%').margin({bottom:12})// 属性 UUIDRow(){Text('属性UUID').fontSize(14).fontColor('#666666').width(80)TextInput({placeholder:'请输入属性UUID',text:this.propertyUUID}).layoutWeight(1).margin({left:12,right:12}).onChange((value:string)=>{this.propertyUUID=value;})Button('重置').fontSize(12).backgroundColor('#F5F5F5').fontColor('#9C27B0').width(60).height(32).onClick(()=>{this.propertyUUID='';})}.width('100%').margin({bottom:8})Text('UUID格式:37bea880-fc70-11ea-b720-00000000fdee').fontSize(12).fontColor('#999999').alignSelf(ItemAlign.Start)}.width('100%').padding(16).backgroundColor(Color.White).borderRadius(12)}build(){Column(){// 标题栏Row(){Button('返回').backgroundColor(Color.Transparent).fontColor('#9C27B0').onClick(()=>router.back())Text('星闪设置').fontSize(18).fontWeight(FontWeight.Medium).layoutWeight(1).textAlign(TextAlign.Center)Button('保存').backgroundColor(Color.Transparent).fontColor('#9C27B0').onClick(()=>router.back())}.width('100%').padding(16)Scroll(){Column({space:16}){this.UUIDConfigSection()}.width('100%').padding(16)}.layoutWeight(1)}.width('100%').height('100%').backgroundColor('#F5F5F5')}}

七、广播发送(高级用法,可选)

什么是广播?让你的手机也能被其他星闪设备发现,类似于使你的手机变成一个星闪设备。

什么时候用?当你需要手机对手机通信,或者你在开发服务端功能时。

// ====== common/NearLinkManager.ets(补充)======/** * 开始广播 */publicstartAdvertising():void{try{constsetting:advertising.AdvertisingSettings={interval:160,power:2};constmanufactureData:advertising.ManufacturerData={manufacturerId:4567,manufacturerData:newUint8Array([1,2,3,4]).buffer};constserviceData:advertising.ServiceData={serviceUuid:'37bea880-fc70-11ea-b720-00000000fdee',serviceData:newUint8Array([5,6,7,8]).buffer};constadvData:advertising.AdvertisingData={serviceUuids:['37bea880-fc70-11ea-b720-00000000fdee'],manufacturerData:[manufactureData],serviceData:[serviceData],includeDeviceName:true};constadvertisingParams:advertising.AdvertisingParams={advertisingSettings:setting,advertisingData:advData};advertising.startAdvertising(advertisingParams).then((handle:number)=>{console.info(`Advertising started, handle:${handle}`);}).catch((err)=>{console.error(`Start advertising failed:${err.message}`);});}catch(error){console.error(`Start advertising exception:${error}`);}}/** * 停止广播 */publicstopAdvertising(handle:number):void{try{advertising.stopAdvertising(handle).then(()=>console.info('Advertising stopped')).catch((err)=>console.error(`Stop advertising failed:${err.message}`));}catch(error){console.error(`Stop advertising exception:${error}`);}}

八、最佳实践(踩坑总结)

8.1 必须遵守的规则

  1. 权限先行:扫描前必须检查并申请权限(只要1个!)
  2. 资源释放:页面销毁时停止扫描、断开连接
  3. 状态同步:使用回调机制同步 UI 状态
  4. 多设备管理:使用 Map 管理多个连接

8.2 常见问题排查

问题可能原因解决方法
扫描不到设备权限未授予检查应用设置里的权限
扫描不到设备设备不支持星闪确认是华为星闪设备
连接失败设备已被其他手机连接断开其他连接后重试
读写失败UUID 不对检查服务UUID和属性UUID

8.3 写入数据的技巧

// 双重写入策略:先尝试 WRITE,失败后尝试 WRITE_NO_RESPONSEpublicasyncsendData(serviceId:string,propId:string,data:ArrayBuffer):Promise<boolean>{try{// 第一次尝试:带响应的写入awaitthis.ssapClient?.writeProperty(prop,ssap.PropertyWriteType.WRITE);returntrue;}catch(error){try{// 第二次尝试:不带响应的写入awaitthis.ssapClient?.writeProperty(prop,ssap.PropertyWriteType.WRITE_NO_RESPONSE);returntrue;}catch(e){returnfalse;}}}

九、学习资源

  • ? 官方星闪开发指南
  • ? NearLink Kit API 文档
  • ? SSAP 客户端开发

十、常见问题 FAQ

Q1: 我的设备支持星闪吗?

如何确认:

  • HarmonyOS 6设备下拉控制中心,检查WLAN下方是不是有星闪标识

Q2: 星闪和蓝牙可以同时用吗?

可以!它们使用不同的无线频段,互不干扰。你可以同时连接一个蓝牙设备和一个星闪设备。

Q4: 星闪设备在哪买?

目前星闪设备还不太普及,可以购买WS63或者BS21E开发板作为初体验


作者声明:个人拙作,仅总结了本人开发经验,专业性指导请参考官方文档,欢迎各位大佬斧正。本文档不是最简星闪调试工具开发文档,代码截取自成熟应用,欢迎下载易管闪联(星闪端,蓝牙端正在突破3.5)体验。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/15 21:52:50

零成本搞定!2025 年免费降 AI 率实操指南:3款工具 + 5个有效方方法

论文降aigc现在绝对是大家写论文时遇到的最大拦路虎。别慌&#xff0c;只要掌握了正确的方法&#xff0c;把那些顽固的AI生成痕迹去掉&#xff0c;顺利通过检测其实并不难。 一、 AI检测原理 很多同学都在问&#xff1a;为什么我自己一个字一个字敲出来的论文&#xff0c;aig…

作者头像 李华
网站建设 2026/3/15 20:04:41

大模型如何赋能智能制造

大模型&#xff08;Large Models&#xff09;&#xff0c;特别是以大语言模型&#xff08;LLM&#xff09;和多模态大模型为代表的通用人工智能技术&#xff0c;正在深刻赋能智能制造&#xff08;Smart Manufacturing&#xff09;&#xff0c;推动制造业向更高效、柔性、智能和…

作者头像 李华
网站建设 2026/3/15 20:04:43

HunyuanVideo-Foley:AI自动生成音效的技术与应用

HunyuanVideo-Foley&#xff1a;AI自动生成音效的技术与应用 你有没有试过看一段没有声音的视频&#xff1f;画面清晰、动作流畅&#xff0c;但总觉得哪里不对劲——仿佛演员在演哑剧&#xff0c;世界被抽走了呼吸。可一旦加上脚步踩在石板上的回响、风吹树叶的沙沙声、杯子轻轻…

作者头像 李华
网站建设 2026/3/15 7:41:20

根据Excel数据自动生成Word文档:AI助力文档自动化的未来

随着大数据和AI技术的不断发展&#xff0c;文档生成的自动化逐渐成为提升办公效率的重要工具。尤其是在文档批量生成和格式统一方面&#xff0c;如何快速、准确地根据数据生成标准化的文档&#xff0c;已成为企业和开发者关注的焦点。在这个过程中&#xff0c;Excel数据的处理与…

作者头像 李华
网站建设 2026/3/20 23:03:15

LobeChat能否嵌入WordPress网站?网页集成方法探讨

LobeChat 能否嵌入 WordPress&#xff1f;网页集成方法深度解析 在今天的内容型网站中&#xff0c;用户早已不再满足于单向阅读。他们希望提问、互动、获得即时反馈——而传统的 WordPress 博客或企业官网&#xff0c;往往只能提供静态信息展示。如何让一个原本“沉默”的网站变…

作者头像 李华
网站建设 2026/3/16 8:04:56

YOLO推理速度瓶颈分析与GPU优化建议

YOLO推理速度瓶颈分析与GPU优化建议 在智能制造工厂的质检线上&#xff0c;每秒数十帧的高清图像正源源不断地涌向AI系统——任何一次检测延迟都可能导致缺陷产品流入下一环节。面对这种“零容忍”的实时性挑战&#xff0c;YOLO系列模型虽以高速著称&#xff0c;但在实际部署中…

作者头像 李华