uni-app 跑上鸿蒙,发现蓝牙全瞎:我把 BLE 补齐的实战(一)基建篇 – 码间留白

uni-app 跑上鸿蒙,发现蓝牙全瞎:我把 BLE 补齐的实战(一)基建篇 – 码间留白


The Bluetooth API family of uni-app is marked as not supported on HarmonyOS Next: no error is reported, no callback is given, the page is stuck in initialization, and the button looks “no response when clicked”. Our complementary solution is three-layered: the UTS plug-in encapsulates @kit.ConnectivityKit, the front-end gasket is disguised as a Bluetooth API with the same name and signature as uni, and then it is used as an injection host to be handed over to the pure JS manufacturer SDK – not a single line of protocol logic is transplanted. What really takes time is three things: There are 4 copies of the same plug-in logic in the project and are out of sync; the native event listener registration and annotation are not paired, causing random ghost failures of “the connection is successful but the connection fails”; the persistent deviceId is the broadcast address derived during the scanning period, which will become invalid when the device is restarted. Attached is the ArkTS compilation error comparison table, cross-bridge ArrayBuffer processing, write queue, hilog collection, and 9-item self-check list before using it on a real machine.

Targeted at: Developers who want to use uni-app to adjust BLE on HarmonyOS Next.
This article only talks aboutPlatform infrastructure(Plug-ins, gaskets, compilation chains, life cycle defects), does not involve any specific device protocols; device side docking (handshake, data analysis, reading storage), see the second part of the series.
All package names, AppIDs, plug-in names, and paths in this article are placeholders or proxies.

TL;DR

  • The Bluetooth API family of uni-app is listed in the official compatibility table of HarmonyOS Next. x(not supported), callNever call backthe performance is “no response when clicking the button”, and it is not a permission issue.
  • We use UTS plug-in package layer @kit.ConnectivityKitand then use one with uni BluetoothAPI Same name and signatureThe shim is injected into the manufacturer’s SDK, so that not a single line of protocol code is ported.
  • The real pitfall is not that “API does not exist”, but in three places:There are 4 copies of the product that are out of sync.、Native listener registration/annotation is not paired、Persistent deviceId will rot。
  • The whole process has been run and returned on a real machine. All ArkTS compilation errors encountered have definite solutions. This article provides a comparison table.

1. Phenomenon: three illusions “like permission issues”

When I click “Start Search” on the device list page, there is no response on the Hongmeng terminal; on the Android terminal, it is normal. The three hypotheses in my mind at that time were all falsified:

hypothesis Evidence collection method in conclusion
Changes are not synchronized into the package Compare on device www/app-service.js Build fingerprint + build intermediates Already included in the package
Conditional compilation strips the code Check the corresponding product #ifdef branch string count branch correct
Bluetooth permission not declared Check inside the bag module.json Does it contain ACCESS_BLUETOOTH Declared

And the click did reach JS – the page popped up with the “Bluetooth initialization timeout” tip we added ourselves.

Troubleshooting experience:when await When an API never returns and your code link has been proven to be in the package, be suspicious firstLack of platform capabilitiesrather than a bridging bug.

2. Root cause: lack of platform capabilities, not a bug

In the uni-app compatibility table of HarmonyOS Next, the following APIs are all marked as not supported:

openBluetoothAdapter / getBluetoothAdapterState
startBluetoothDevicesDiscovery / stopBluetoothDevicesDiscovery / onBluetoothDeviceFound
createBLEConnection / closeBLEConnection
getBLEDeviceServices / getBLEDeviceCharacteristics
writeBLECharacteristicValue / notifyBLECharacteristicValueChange / onBLECharacteristicValueChange

The failure pattern is quiet:No error reporting, no callback,success/fail/complete None of the three families came. then await Hangs, the page is stuck on initialization, and the buttons look “unresponsive”. Complementing abilities must be done natively.

3. Selection: Three options, choose the most economical one

plan practice cost
A. Migrate the protocol to native Rewriting device protocols and state machines in ArkTS The workload is the largest, and the logic of the two protocols at both ends has been bifurcated for a long time.
B. Waiting for official support none Uncontrollable
C. Add a layer of API with the same name UTS plugin provides native primitives + frontend shim disguised as uni BluetoothAPI A one-time investment, the business code is almost unchanged

The key prerequisite for choosing C is to first read the implementation of the manufacturer’s SDK:

// node_modules/-bluetooth-sdk/package.json
"dependencies": {}        // 无原生依赖
// 内部调用形态
uni.createBLEConnection(...)  // 蓝牙能力全部来自「注入进来的宿主对象」

SDK isPure JSand the Bluetooth API host isParameter injectionof:

adapter.createBLEConnection(deviceId, callback, host, timeout, authParams)
//                                              ^^^^ 原来传 uni,现在可以传任何东西

Just provide a and uni For objects with the same name and signature of the Bluetooth subset, the protocol logic (handshake, instructions, unpacking) is reused as it is.This is the foundation of the entire plan。

4. Structure: three layers, each responsible for one thing

业务层   useXxxScan.ts / useBluetoothDevice.ts
            │  bleApi(条件编译赋值)
            │    #ifdef APP-HARMONY → bleApi = harmonyBle
            │    #ifndef            → bleApi = uni
            ▼
垫片层   utils/bluetooth/harmonyBle.ts
            与 uni 蓝牙 API 同名、同签名({ success, fail, complete } + errCode)
            负责:桥接语义归一(广播数据、二进制)+ 插件缺失时显式 fail
            │  uni.hbXxx(...)  扁平属性访问
            ▼
原生层   uni_modules/harmony-ble/utssdk/app-harmony/index.uts
            @kit.ConnectivityKit:access.getState / ble.startBLEScan /
            ble.createGattClientDevice / device.writeCharacteristicValue ...
4.1 Platform indirection layer: two const Will compile and report an error

conditionally compiledoriginalwill be seen together by tsc/IDE, and the two branches will const bleApi “Cannot redeclare block scope variable” will appear. The correct way to write it is to declare it once and assign the value in the branch:

let bleApi: any;
// #ifdef APP-HARMONY
import { harmonyBle } from '@/utils/bluetooth/harmonyBle';
bleApi = harmonyBle;
// #endif
// #ifndef APP-HARMONY
bleApi = uni;
// #endif

Two other small pits:

  • APP-HARMONY and APP-PLUS yesjuxtaposeRelationship, not inclusion. Originally written in #ifdef APP-PLUS The authorization logic in Hongmeng will be completely stripped off.
  • from @/uni_modules/ Name the path to import the UTS plug-in in our offline build projectNot confirmed to be available(See §6 for details), and finally changed to flat attribute access.
4.2 Shims: Better to fail explicitly than to timeout silently

The most important thing about gaskets is not forwarding;Total failure: When the native plug-in is not included in the package, attribute access will be obtained undefinedif called directly, it will be “stuck without callback”. So detect first and then call back:

const ERR_PLUGIN_MISSING = 10002;

function call(flatName: string, opts: any) {
  const f = (uni as any)[flatName];
  if (typeof f !== 'function') {
    const errMsg = `harmonyBle.${flatName}:fail native plugin not installed`;
    console.log('[BLE]', errMsg);
    opts?.fail?.({ errMsg, errCode: ERR_PLUGIN_MISSING });
    opts?.complete?.({ errMsg, errCode: ERR_PLUGIN_MISSING });
    return;
  }
  f(opts);
}

What this code gets is:The fault changed from “metaphysical timeout” to “a readable reason in the log”. The entire troubleshooting cycle was thus shortened by half.

5. ArkTS will teach you how to be a good person: Compilation error comparison table

.uts It needs to be compiled into ArkTS on the Hongmeng side, and ArkTS is TypeScript.restricted subset. The causes and solutions of the first 12 compilation errors:

Report an error root cause solution
Indexed signatures are not supported(arkts-no-indexed-signatures) ArkTS disables index signatures,[key: string]: any The ____ does not work In the interfaceExplicit declaration one by oneTransparent transmission fields:deviceId?/serviceId?/characteristicId?/value?: ArrayBuffer
not assignable to string index type 'Object' Same as above Same as above
Property 'advData' does not exist on type 'ScanResult' The field name was guessed wrong and the original broadcast was called data advertisData: r.data
Property 'createBLEDevice' does not exist on type 'typeof ble' Wrong memory of factory function name ble.createGattClientDevice(deviceId)
Use explicit types instead of "any"(arkts-no-any-unknown) The previous API does not exist, causing the return value to be pushed to any ofjointly wrong It will automatically disappear after modifying the real API name; it will be empty if entered. undefined guard rather than as string
Namespace 'ble' has no exported member 'ConnectionState' Event callback type names are different (state: ble.BLEConnectionChangeState) => ...
Property 'STATE_CONNECTED' does not exist on type 'typeof BluetoothState' BundleAdapter switch enumerationTake it asConnection status enum state.state === constant.ProfileConnectionState.STATE_CONNECTED

Three methodologies:

  1. All signatures must be checked on this machine .d.tsdon’t write based on impressions. Location:/sdk/default/openharmony/ets/api/@ohos.bluetooth.*.d.tsbucket file ets/kits/@kit.ConnectivityKit.d.ts。
  2. any Error reports are often a chain reaction of incorrectly written upstream API names.first fix the “member does not exist” at the top level.
  3. .uts Files usuallyNo native lint supportgrammatical legitimacy can only rely on assembleHar Exposed – so the first step is to run the compilation chain.

By the way, there is an ArkTS closure restriction:device.off('BLEConnectionStateChange', listener) quoted here listener itself will run into self-reference problems, and off(type)(Without callback) will remove all listeners for the event – as long as the only registered party for the event in the process is the plug-in itself, it is cleaner to use the callback-free form.

6. How to turn front-end functions into native functions: four registrations + two forms

The UTS plug-in is not finished yet .uts can be uni. Tune in. Offline (without HBuilderX cloud packaging) requiredCollaborate everywhere:

1) 把插件编成 har        →  <原生工程>/libs/uni_modules__harmony_ble.har
2) 声明依赖              →  entry/oh-package.json5
     "@uni_modules/harmony-ble": "../libs/uni_modules__harmony_ble.har"
3) 注册挂载              →  entry/src/main/ets/uni_modules/index.generated.ets
     import { openAdapter, ... } from '@uni_modules/harmony-ble'
     Reflect.set(uni, 'hbOpenAdapter', openAdapter)   // ×14
4) 构建期登记            →  standalone-ext-apis.json
     { "type": "extapi", "plugin": "harmony-ble", "apis": [14 个 hbXxx], "version": "..." }

Two points that must be remembered:

  • index.generated.ets In many projects it isManually maintained superset(Registered verify/push/payment/share…).publish The generated version only contains the plug-ins that participated in the compilation this time.Full coverage will silently drop other pluginsbe sure to add them one by one.
  • Step 3 has two forms, depending on how the front-end consumes:
    • flat mount:Reflect.set(uni, 'hbOpenAdapter', fn),front end uni.hbOpenAdapter(...) Pure attribute access. ArkTS friendly (avoids anonymous object literal restrictions), and the front end can detect when the plug-in is missing undefined。
    • Plug-in registration:uni.registerUTSPlugin('uni_modules/harmony-ble', ns)cooperate with the front-end import from '@/uni_modules/harmony-ble'. The dev project follows this path, but it is different from the running model of our offline main project——dev running through does not mean that your call can pass。

our api 数量一致性 Relying on a constraint:standalone-ext-apis.json The number of entries must equal Reflect.set number of rows (currently 14 each). When adding the API, all the changes were made at the same time, and the one thing missing was “Compiled and run 10002”.

7. ArrayBuffer cross-bridge: byteLength will be lost

ArkTS ArrayBuffer Throw it directly to JS, and it often becomes {}(byteLength lost). The plan isJust walk across the bridge Array:

// 原生侧:ArrayBuffer → Array
function ab2arrForJs(ab: ArrayBuffer): Array {
  const u8 = new Uint8Array(ab);
  const out: Array = [];
  for (let k = 0; k < u8.length; k++) out.push(u8[k]);
  return out;
}

// JS 侧垫片:Array → ArrayBuffer,并做语义对齐
function normalizeIncomingValue(v: any): ArrayBuffer | null {
  if (v instanceof ArrayBuffer) return v;
  if (Array.isArray(v)) { /* 逐字节 & 0xff 重建 */ }
  // TypedArray/DataView 兜底:v 只是底层 buffer 上的一个窗口视图,
  // 直接返回 v.buffer 会把整段内存写出去(长度、内容全错),必须按视图范围切片
  if (typeof v.byteLength === 'number' && v.buffer != null) {
    return v.buffer.slice(v.byteOffset, v.byteOffset + v.byteLength);
  }
  return null;
}

The last branch is the easiest to miss:View is not equal to its underlying buffer. The symptom of this bug is “the write command occasionally contains a few extra tail bytes”, which is extremely difficult to attribute.

8. Product consistency red line: 4 copies of the same piece of logic

There is no technical difficulty in this section, butIt cost us two rounds of real machine verification in vain. The same piece of plug-in logic exists in 4 copies on the machine at the same time:

① src/uni_modules/harmony-ble/utssdk/app-harmony/index.uts       ← 你在这里改代码
② dist/dev/app-harmony/.../app-harmony/index.ets                 ← har 的真实编译源
③ <原生工程>/libs/uni_modules__harmony_ble.har                    ← 打进包的东西
④ 设备上的 www / hap                                              ← 实际运行的东西

② It is UTS→ArkTS translation + manual correction version(object literal to UTSJSONObjectMap value conversion UTS.mapGet wait). If you only change ①, the har will always have the old logic; conversely, the IDE’s “Run to Hongmeng” will use ① to re-translate and overwrite ②, and manual corrections may be lost after overwriting.Changes must be semantically synchronized on both sides ①②.

besides www double source trap: GUI package export and CLI export appResource fell into two different directories respectively, and brought /MIR The sync script uses one of these as a source – running it in the wrong direction willPut the new bag back into the old bag. Our approach is to hard-code a dedicated script for each product chain and do not allow manual combination of commands.

Verify that compressed products cannot be searched by text:.har is a compressed archive, on a har file grep/findstr The key identifier must have zero hits – zero hits only means “no decompression”, not “no such logic”.

tar -xzf uni_modules__harmony_ble.har -C tmp_verify
# 在解出的 modules.abc(字节码)里做字符串计数

The same is true for front-end JS products: compression will rename variables, so pressSemantic fingerprintJudgment (string constant, calling form), not variable name.

General Lesson: Yes har/jar/aar/zip This type of compressed product is used to verify “whether the content contains my changes”. It must be unpacked first and then the bytecode is checked.

9. Three real flaws: from “ability to run” to “dare to use”

After the link was established, three random failures occurred. What they have in common is:The semantic level of packaging native events is wrong。

9.1 Ghost failure: The connection is successful, but “Connection failed” pops up

The initial implementationcalled this time success and fail Together, the closure enters the connection status monitoring:

// ❌ 初版
device.on('BLEConnectionStateChange', (state) => {
  if (state.state === CONNECTED) options.success(...);
  else if (state.state === DISCONNECTED) options.fail(...);   // 监听从不解除
});

After the connection is established, the deviceAutomatically shut down after testingor the upper level takes the initiative disconnect()will be derived again DISCONNECTED ——So it triggeredThe original call that returned successfully fail. The upper layer resets the connection status and pops up “Connection Failed”. The symptoms are random and difficult to reproduce, and in the log, “success comes first and failure comes last.”

Repair mode issingle final state semantics:

// ✅ 只认首个终态,到终态立即解注
let settled = false;
const listener = (state: ble.BLEConnectionChangeState) => {
  if (settled) return;
  const connected = state.state === constant.ProfileConnectionState.STATE_CONNECTED;
  const disconnected = state.state === constant.ProfileConnectionState.STATE_DISCONNECTED;
  if (!connected && !disconnected) return;   // CONNECTING 等中间态只记日志
  settled = true;
  clearConnTimer(deviceId);
  device.off('BLEConnectionStateChange');    // 无 callback 形式,移除该事件全部监听
  if (connected) {
    options.success?.({ errMsg: 'createBLEConnection:ok' });
  } else {
    gattDevices.delete(deviceId);            // 建连以断连收尾 → 回收实例,重连走全新流程
    charListenerDevices.delete(deviceId);
    clearWriteState(deviceId);
    try { device.close(); } catch (e) { /* ignore */ }
    options.fail?.({ errMsg: 'createBLEConnection:fail disconnected', errCode: 10003 });
  }
};

at the same time:closeConnection insideAnnotate first and then disconnect();same deviceId Repeat the connection establishment and annotate and merge close() Old GattClient (otherwise the GATT connection leaks).

Transferable rules: Do not put request-level success/fail The callback is hung on a long-lived device event that will be triggered multiple times – subsequent legitimate events will backfire on the completed call. All gaskets/plug-ins (Bluetooth, serial port, socket) that encapsulate “connection class native events → Promise style callback” are applicable. In turn, the state callback API, which itself has continuous subscription semantics, should retain monitoring, but must be annotated in pairs.

By the way, there is a log interpretation pit:constant.ProfileConnectionState yes DISCONNECTED=0 / CONNECTING=1 / CONNECTED=2. When only printing the original enumeration value,state=1 It is very easy to read as “connected”, so we once looked the other way.

9.2 Listener registration is not paired: each broadcast/notification is dispatched K times

onDeviceFound / notifyCharacteristic Used for every JS callnew closureGo to register native onand the JS side callback is a single slot coverage. In ArkTS on Pass in different function referencesNot idempotentso each broadcast and each notification is dispatched multiple times – in addition to log flooding, there are alsoReport measurement values ​​repeatedlybusiness risks.

Repair uses two types of guards:

// 扫描监听:模块级布尔,原生 on 只注册一次;off 时复位
let scanListenerRegistered = false;
export function onDeviceFound(callback: (res: any) => void) {
  deviceFoundCb = callback;                    // 单槽派发
  if (scanListenerRegistered) return;
  scanListenerRegistered = true;
  ble.on('BLEDeviceFind', (results) => { deviceFoundCb?.({ devices: /* 归一 */ }); });
}

// 特征监听:deviceId → boolean,同设备多特征(notify + indicate)共用一个原生监听
const charListenerDevices = new Map();

// off 系列必须做真正的原生 off,不能只把回调置 null
export function offDeviceFound() {
  deviceFoundCb = null;
  scanListenerRegistered = false;
  try { ble.off('BLEDeviceFind'); } catch (e) { /* ignore */ }
}

offCharacteristicChange To iterate through registered devices one by one device.off back clear()——Only clearing JS side references is the most common false release.

9.3 Concurrent write rejected:The operation is busy

The manufacturer’s SDK will launch twice concurrently within a few milliseconds after the subscription is successful. writeBLECharacteristicValue(Handshake command + setting time), with 1200ms self-resend. Hongmeng GATT only allows one pending write at the same time, and concurrency is directly rejected by the native The operation is busy。

The solution is to add it at the plug-in layerSerial write queue by deviceIdand put the “CCCD write for subscription” into the same queue (the same GATT write channel):

type BleWriteTask = (next: () => void) => void;
const writeQueues = new Map>();
const writeBusy = new Map();
const WRITE_TIMEOUT_MS = 5000;

function flushWrite(deviceId: string) {
  if (writeBusy.get(deviceId) === true) return;
  const q = writeQueues.get(deviceId);
  if (q == null || q.length === 0) return;
  const task = q[0]; q.shift();
  writeBusy.set(deviceId, true);
  task(() => { writeBusy.set(deviceId, false); flushWrite(deviceId); });   // 结算后放行下一个
}

function enqueueWrite(deviceId: string, task: BleWriteTask) {
  let q = writeQueues.get(deviceId);
  if (q == null) { q = []; writeQueues.set(deviceId, q); }
  q.push(task);
  flushWrite(deviceId);
}

Two details:

  • A single write must have a timeout. If the native Promise is not resolved, it will permanently occupy the queue of the device.
  • In the timeout branch next() to be placed finally. upper layer fail The queue must also be released even if the callback throws an exception, otherwise subsequent write tasks to the device will be permanently queued.

give at the same time createConnection Plus input parameters timeout respect (SDK transfer 20000no time limit by default):

const timeoutMs: number = options.timeout == null ? 0 : options.timeout as number;
if (timeoutMs > 0) {
  const timer = setTimeout(() => {
    if (settled) return;
    settled = true;
    connTimers.delete(deviceId);
    try { device.off('BLEConnectionStateChange'); } catch (e) { /* ignore */ }
    gattDevices.delete(deviceId); charListenerDevices.delete(deviceId); clearWriteState(deviceId);
    try { device.disconnect(); device.close(); } catch (e) { /* ignore */ }
    options.fail?.({ errMsg: `createBLEConnection:fail timeout ${timeoutMs}ms`, errCode: 10003 });
  }, timeoutMs);
  connTimers.set(deviceId, timer);   // 终态 / closeConnection / 重复建连 三处都要 clearConnTimer
}

connTimers The three cleanups are not defensive redundancies –The timer goes back and triggers fail, which is the second entrance to the ghost failure in 9.1。

The real machine returns after repair:The operation is busy 0 times,connect fail 0 times, 0 late callbacks, and no repeated notifications.

10. deviceId is perishable data

This is the most hidden pit, becauseThe symptoms are exactly the same as “device not turning on”。

Hongmeng side ble.createGattClientDevice(deviceId) Used deviceId yesBroadcast address derived during scan periodafter the device is restarted or the address is rotated, the old value stored will become invalid immediately. The reconnection code often looks like this:

// ❌ 只 openAdapter + 取本地存储的 deviceId 直连,从不扫描
const ok = await connectDevice(storedDevice);

After the failure, GATT has been stuck at CONNECTINGwill not reply until the system times out in ~30s createBLEConnection:fail disconnected(The 4 actual measurements were all between 30.05~30.14s). If the failure prompt is commented out again, all the user will see is “no response after clicking”. Android the same path is available because the system holds the bond/address cache –This is a platform difference, not a code difference。

We observed 4 address patterns on one device within a day:

form type
FE:79:xx:xx:xx:29 Random static address
0C:35:xx:xx:xx:FC public address
5E:F1:xx:xx:xx:20 Resolvable Private Address (RPA)
02:1E:xx:xx:xx:5B Another rotation value

Conclusion: Never assume that a persistent deviceId will be available long-term.

Repair three-piece set (front end side, immobile har):

const HARMONY_CONNECT_WATCHDOG_MS = 12000;   // 不等系统 30s,主动收敛
const HARMONY_REFRESH_SCAN_MS = 10000;

// 1) 看门狗:超时即 closeBLEConnection 并 resolve(false),配 settled 忽略迟到回调
const watchdog = setTimeout(() => {
  if (settled) return;
  settled = true;
  bleApi.closeBLEConnection({ deviceId: device.deviceId });
  resolve(false);
}, HARMONY_CONNECT_WATCHDOG_MS);

// 2) 直连失败后扫一轮拿新鲜地址,再重连一次;成功后由 saveBoundDevice 写回存储
const fresh = await scanForFreshDevice((name) => prefixInName(deviceType.bleNamePrefix, name));
if (fresh && fresh.deviceId !== boundDevice.deviceId) {
  return connectDevice({ ...device, deviceId: fresh.deviceId }, deviceType);
}

// 3) 页面 onShow 的自动重连走 silent 分支:不扫描、不打扰用户

Two other lessons:

  • Failure prompt must be visible,butOnly pop up once at the page level–according to productCode When connecting in a loop, the toasts in the composable will be played several times in succession.
  • Determining “whether the failure reason is due to an expired address” depends on the scan results: if the scanned deviceId It is consistent with the binding record, indicating that there is another reason for the failure.Don’t blindly retry。

Actual measured timing: watchdog triggers in 11.8s → scans for 384ms and hits new address → establishes connection state=2 Only 0.4~1s → SDK connect success, the new address is written back to the storage, and the subsequent 7 connection establishments use the new address directly and succeed. When the device is really shut down, the scan will time out after 10 seconds and the message “Device not scanned” will be returned and only prompted once.

11. Permissions: Statement + Active application, two things

Native module.json5 Three permanent posts:

Permissions type Remark
ohos.permission.USE_BLUETOOTH system_grant Just declare
ohos.permission.DISCOVER_BLUETOOTH system_grant Just declare
ohos.permission.ACCESS_BLUETOOTH user_grant need reason + usedScene,andMust be applied at runtime

uni.openBluetoothAdapter Hongmeng will not open the authorization box for you, so the plug-in openAdapter Apply proactively before:

export function requestBluetoothPermission(success: (granted: boolean) => void) {
  const atManager = abilityAccessCtrl.createAtManager();
  const perms: Array = ['ohos.permission.ACCESS_BLUETOOTH'];
  atManager.requestPermissionsFromUser(getContext(), perms)
    .then((r) => success(r.authResults.length > 0 && r.authResults[0] === 0))
    .catch(() => success(false));
}

getContext() Get the host context of the current window:

function getContext(): common.UIAbilityContext {
  return UTSHarmony.getCurrentWindow()!.getUIContext().getHostContext() as common.UIAbilityContext;
}

By the way, there is a pitfall in building baselines: the API version in which har is compiled in the project will have that minimum version requirement. If the main project compatibleSdkVersion below it,assembleHap Will be reported in the MergeProfile stage 00306004 Specification Limit Violation. Either upgrade the main project baseline in a unified manner (need to check at the same time compatibleSdkVersionStage (with signing certificate), or drop the plug-in to the target API and reprogram——Pick one, don’t mix them。

12. Real machine logs: tags, encoding and lost logs

hdc tconn <设备IP:端口>          # 无线连接,掉线需重连并授权
hdc shell hilog -T JSAPP          # 前端 console.log 落在 JSAPP tag
hdc shell hilog -Q pidoff         # 需要时关闭流控

Three details that will waste you half a day:

  1. tag is not chromium Neither EntryAbility,yes JSAPP. Before applying your own log prefix grep, press JSAPP Filtering – “Not a single front-end log could be found” before, because there was no filtering + buffer rotation.
  2. PowerShell *> Redirects will be encoded twice(UTF-8 is read by GBK and then written into UTF-8). To search Chinese, you must first UTF8 读 → GetEncoding(936).GetBytes → UTF8.GetString Restore; used when the file is occupied by the collection process FileStream(..., 'ReadWrite') Shared reading.Counts are based on ASCII keywordsfull-width punctuation restoration may lose bytes.
  3. hilog has rate limithigh-frequency application logs will beDiscard the entire section. Don’t think “it’s not in the log” as “it didn’t happen”;Start-Process -RedirectStandardOutput The collection child process started may also be recycled along with the parent process, leaving a 0-byte file.

13. Impact area and rollback

To Fei Hongmeng Endzero impact:bleApi = uni Branching makes the behavior of Android / iOS / H5 / applet exactly the same as before the change.

To temporarily disable Hongmeng Connect, just change #ifdef APP-HARMONY inside bleApi = harmonyBle Change back bleApi = uni(Return to the old behavior of “API not supported, card initialization”).

Rollback scope operate Notice
front end bleApi one line Hot update (only change www) will take effect
plug-in Roll back old har → delete oh_modules with two oh-package-lock.json5 → ohpm install --all → assembleHap has 与 standalone-ext-apis.json、index.generated.ets Must roll back to the same version
whole pack Reinstall hap Overwrite the installation and retain login status and device binding records;hdc uninstall It will be lost, please pay attention when scheduling

Another thing: WGT/hot update can only carry www.Unable to host new UTS plug-ins. Changes to the plug-in layer must be made in the entire package.

14. Self-check list before using the real machine

15. Summary

The really difficult part of this matter is not “finding out that Hongmeng does not support the uni Bluetooth API” – the conclusion can be reached in five minutes by looking up the table. The hard part is the next three steps:

  1. Let the matter of supplementing capabilities not affect the existing business: Same name and same signature shim + injection point replacement, protocol logic zero migration.
  2. Let the changes really be included: Consistency of four copies, and meta-rules such as “compression products cannot be text verified”.
  3. Make the link stable enough to be handed over to users: Single final state semantics, paired annotations, write queues, and address refreshes – the four repairs are not complicated, but their absence manifests itself as random failures, and random failures are the most costly in real machine troubleshooting.

The second article will write about the device itself: why the authentication of the manufacturer’s SDK only responds with “Authentication failed”, why Hongmeng’s broadcast data requires manual parsing of the AD structure, and the process data from package to package to the three numbers of blood pressure and pulse in the form.


Attached: Desensitization instructions for this article (delete this section before publishing)

true value In-text treatment
The real plug-in name and its uni. Mount prefix, har file name Uniformly change to neutral pronouns harmony-ble / hbXxx / uni_modules__harmony_ble.har(There is no real identification in the text)
Front-end project name, native project name, package name com.*、DCloud AppID、bundleName delete or change <原生工程> / / <设备IP:端口> placeholder
Manufacturer SDK package name, device model,appKey / appIdentifier and its background error code This article only writes “Manufacturer SDK (Pure JS)”; the manufacturer-related information is left to the second article, and no real values ​​appear.
Real machine complete MAC / deviceId four forms The middle byte ends with xx Mask, only the first and last bits are retained to distinguish address types.
Certificate absolute path,keyPassword / storePassword Not citedand please do not src/manifest.json Copy to any external document
Inside the warehouse scripts/ The specific build script name under Without naming names, it was changed to “write dedicated scripts for each product chain.”
specific @dcloudio Version number, UniAppRuntime version, measured readings Did not appear (the reading belongs to the second article and must be marked as a self-test sample)

Before publishing, it is recommended to search the full text again: AppID, package name,hdc tconn After the IP,C:\Users\<你> Path, company domain name.



Source link

Leave a Reply

Your email address will not be published. Required fields are marked *

தீவிர சூறாவளி புயல் 'முரசு' சென்னையில் நாளை பள்ளிகளுக்கு விடுமுறை 'முரசு' புயல் குறித்த தகவல்கள் சென்னையில் நாளை பள்ளிகளுக்கு விடுமுறையா? வானிலை சென்னையில் நாளை விடுமுறையா? 'முரசு' புயல் வானிலை சென்னையில் புயல் 'முரசு' புயல் கண்காணிப்பு சென்னையின் வானிலை தெலுங்கானா சென்னை வானிலை புயல் கண்காணிப்பு செங்கல்பட்டில் இன்று பள்ளிகளுக்கு விடுமுறை சென்னையில் பள்ளிகளுக்கு விடுமுறை செங்கல்பட்டில் பள்ளிகளுக்கு விடுமுறை விஜயவாடா வானிலை வானிலை அறிக்கை 'முரசு' புயல் கண்காணிப்பு இன்றைய வானிலை அறிக்கை சென்னையில் நாளை பள்ளிகளுக்கு விடுமுறை சென்னை வானிலை சென்னையில் இன்று பள்ளிகளுக்கு விடுமுறையா? இன்றைய சென்னை வானிலை விமான சேவைகள் தமிழ் பக்தாகோர் (Pakhtakor) vs அல்-நாசர் (Al-Nassr) பக்தாகோர் எஃப்சி vs அல்-நாசர் எஃப்சி தரவரிசை ஏஎஃப்சி (AFC) சாம்பியன்ஸ் லீக் பக்தாகோர் எஃப்சி vs அல்-நாசர் எஃப்சி அணிகளின் விவரம் ஜோவா ஃபெலிக்ஸ் (João Félix) அல்-நாசர் எஃப்சி பக்தாகோர் எஃப்சி நியூ இங்கிலாந்து (New England) vs இன்டர் மியாமி (Inter Miami) நியூ இங்கிலாந்து ரெவல்யூஷன் vs இன்டர் மியாமி தரவரிசை எம்எல்எஸ் (MLS) இன்டர் மியாமி லியோனல் மெஸ்ஸி இன்டர் மியாமி சிஎஃப் இன்டர் மியாமி vs நியூ இங்கிலாந்து நியூ இங்கிலாந்து ரெவல்யூஷன் vs இன்டர் மியாமி அணிகளின் விவரம் மெஸ்ஸியின் மொத்த கோல்கள் நியூ இங்கிலாந்து ரெவல்யூஷன் vs இன்டர் மியாமி போட்டி நிகழ்வுகள் இன்டர் மியாமி போட்டிகள் நியூ இங்கிலாந்து ரெவல்யூஷன் நியூ இங்கிலாந்து ரெவல்யூஷன் vs இன்டர் மியாமி ஓமன் vs நெதர்லாந்து ஓமன் தேசிய கிரிக்கெட் அணி vs நெதர்லாந்து தேசிய கிரிக்கெட் அணி தரவரிசை ஓமன் vs நெதர்லாந்து ஓமன் தேசிய கிரிக்கெட் அணி vs நெதர்லாந்து தேசிய கிரிக்கெட் அணி போட்டி ஸ்கோர்கார்டு ஐசிசி (ICC) சிடபிள்யூசி (CWC) லீக் 2 ஓமன் தேசிய கிரிக்கெட் அணி vs நெதர்லாந்து தேசிய கிரிக்கெட் அணி தரவரிசை ஓமன் தேசிய கிரிக்கெட் அணி vs நெதர்லாந்து தேசிய கிரிக்கெட் அணி போட்டி ஸ்கோர்கார்டு நவம்பர் 2 - தங்கம் மற்றும் வெள்ளி விலை நிலவரம் வெள்ளி மற்றும் தங்கத்தின் விலைகள் தங்கம் குறித்த செய்திகள் இன்றைய தங்க விலை பெங்களூருவில் இன்றைய தங்க விலை ஹைதராபாத்தில் இன்றைய தங்க விலை கொல்கத்தாவில் இன்றைய தங்க விலை சென்னையில் இன்றைய தங்க விலை இன்றைய தங்கம் மற்றும் வெள்ளி விலை பெங்களூருவில் இன்றைய தங்க விலை சென்னையில் இன்றைய தங்க விலை இன்றைய தங்க விலை தனிஷ்க் (Tanishq) தங்க விலை வெள்ளி - எம்சிஎக்ஸ் (MCX) நேரலை விலை பெங்களூருவில் இன்றைய வெள்ளி விலை கோயம்புத்தூரில் இன்றைய தங்க விலை இன்றைய தங்கம் விலை தங்கத்தின் விலைகள் சென்னையில் இன்றைய தங்க விலை இன்றைய தங்க விலை இன்றைய வெள்ளி விலை MCX தங்கம் MCX தங்க விலை விலைமதிப்பற்ற உலோகம் மும்பையில் இன்றைய தங்க விலை ஹைதராபாத்தில் இன்றைய தங்க விலை டெல்லியில் இன்றைய தங்க விலை ஹைதராபாத்தில் இன்றைய தங்க விலை MCX தங்க விலை சென்னையில் தங்க விலை பெங்களூருவில் இன்றைய தங்க விலை MCX வெள்ளி விலை MCX மலபார் தங்க விலை இன்றைய MCX தங்க விலை இன்றைய 22 காரட் தங்க விலை இன்றைய 22K தங்க விலை நேரலை தங்க விலை இன்றைய 18 காரட் தங்க விலை கிமி அன்டோனெல்லி கிமி F1 தரவரிசை F1 F1-ன் மிக இளம் சாம்பியன் கிமி அன்டோனெல்லி ஃபார்முலா 1 F1 ஓட்டுநர் தரவரிசை F1 பந்தயம் F1 நேரலை F1 மெக்சிகோ கிராண்ட் பிரிக்ஸ் F1 2026 மேக்ஸ் வெர்ஸ்டாப்பன் F1 முடிவுகள் மெக்சிகோ கிராண்ட் பிரிக்ஸ் F1 மெக்சிகோ GP ரிலையன்ஸ் பங்கு விலை ரிலையன்ஸ் பங்கு ரிலையன்ஸ் RIL பங்கு விலை ரிலையன்ஸ் இண்டஸ்ட்ரீஸ் பங்கு விலை RIL பங்கு RIL பங்கு விலை உயர்வு குறித்த பகுப்பாய்வு ரிலையன்ஸ் இண்டஸ்ட்ரீஸ் பங்கு அனுஜ் தாக்கூர் நடிகர் அனுஜ் தாக்கூர் வலிப்பு (seizure) தூக்கம் விமானம் விபத்து புளோரிடா விமான விபத்து லியர்ஜெட் (Learjet) லியர்ஜெட் 60 வீடியோக்கள் புளோரிடா ஆஸ்டின் விபத்து இன்றைய செய்திகள் ரிமி டோமி லிபின் மேத்யூ - ரிமி டோமி ரிமி டோமி திருமணம் திருமணம் லிபின் மேத்யூ ரிமி டோமி டேலைட் சேவிங்ஸ் (Daylight Savings) 2026 டேலைட் சேவிங்ஸ் அமெரிக்காவில் டேலைட் சேவிங்ஸ் 2026 அமெரிக்காவில் டேலைட் சேவிங்ஸ் 2026 டேலைட் சேவிங்ஸ் அமெரிக்காவில் டேலைட் சேவிங்ஸ் 2026 ஷாருக்கான் பிறந்தநாள் ஷாருக்கான் ஷாருக்கான் பிறந்தநாள் கிங் (King) SRK பிறந்த தேதி சித்தார்த் ஆனந்த் SRK வயது ஷாருக் இந்தித் திரைப்படம் கேரள லாட்டரி முடிவுகள் கேரள லாட்டரி முடிவு இன்றைய கேரள லாட்டரி முடிவு இன்றைய பாக்யதாரா லாட்டரி முடிவு இன்றைய லாட்டரி முடிவு இன்றைய கேரள லாட்டரி முடிவு (நேரலை) இன்றைய கேரள லாட்டரி முடிவு இன்றைய கேரள லாட்டரி முடிவு (மதியம் 3 மணி) லாட்டரி இன்றைய முடிவு கேரள லாட்டரி முடிவு - இன்று பிற்பகல் 3 மணி (நேரலை) கேரள லாட்டரி முடிவு - நேற்று サイクロン「ムラス(Murasu)」 チェンナイの学校、明日は休校か サイクロン「ムラス」最新情報 チェンナイの学校は明日休みか? 天気 チェンナイは明日休みか? サイクロン「ムラス」の気象情報 チェンナイのサイクロン サイクロン「ムラス」追跡 チェンナイの天気 テランガーナ州 チェンナイの天気 サイクロン追跡 チェンガルパットゥの学校は今日休校か チェンナイの学校休校情報 チェンガルパットゥの学校休校情報 ビジャヤワーダの天気 天気予報 サイクロン「ムラス」追跡 今日の天気予報 チェンナイの学校、明日は休校 チェンナイの天気 チェンナイの学校は今日休みか? 今日のチェンナイの天気 フライト情報 タミル語 パフタコール対アル・ナスル パフタコールFC対アル・ナスル:順位表 AFCチャンピオンズリーグ パフタコールFC対アル・ナスル:出場メンバー ジョアン・フェリックス アル・ナスルFC パフタコールFC ニューイングランド対インテル・マイアミ ニューイングランド・レボリューション対インテル・マイアミ:順位表 MLS(メジャーリーグサッカー) インテル・マイアミ リオネル・メッシ インテル・マイアミCF インテル・マイアミ対ニューイングランド ニューイングランド・レボリューション対インテル・マイアミ:出場メンバー メッシの通算ゴール数 ニューイングランド・レボリューション対インテル・マイアミ:試合経過 インテル・マイアミの試合 ニューイングランド・レボリューション ニューイングランド・レボリューション対インテル・マイアミ オマーン対オランダ オマーン代表クリケットチーム対オランダ代表クリケットチーム:順位表 オマーン対オランダ オマーン代表クリケットチーム対オランダ代表クリケットチーム:試合スコアカード ICCクリケット・ワールドカップ・リーグ2 オマーン代表クリケットチーム対オランダ代表クリケットチーム:順位 オマーン代表クリケットチーム対オランダ代表クリケットチーム:試合スコアカード 11月2日の金・銀価格 銀・金価格 金に関するニュース 今日の金価格 バンガロールの今日の金価格 ハイデラバードの今日の金価格 コルカタの今日の金価格 チェンナイの今日の金価格 今日の金・銀価格 バンガロールの今日の金価格 チェンナイの今日の金価格 今日の金価格 タニシュク(Tanishq)の金価格 銀のMCX(インド商品取引所)ライブ価格 バンガロールの今日の銀価格 コインバトールの今日の金価格 今日の金価格価格 金価格 チェンナイの今日の金価格 今日の金価格 今日の銀価格 MCX(インド商品取引所)金価格 MCX金価格 貴金属 ムンバイの今日の金価格 ハイデラバードの今日の金価格 デリーの今日の金価格 ハイデラバードの今日の金価格 MCX金価格 チェンナイの金価格 バンガロールの今日の金価格 MCX銀価格 MCX マラバール・ゴールド(Malabar Gold)の金価格 今日のMCX金価格 今日の22金(22カラット)価格 今日の22金価格 金価格(リアルタイム) 今日の18金(18カラット)価格 キミ・アントネッリ キミ F1順位表 F1 キミ・アントネッリ(最年少F1チャンピオン候補) フォーミュラ1 F1ドライバー順位表 F1レース F1ライブ F1メキシコグランプリ F1 2026年シーズン マックス・フェルスタッペン F1結果 メキシコグランプリ F1メキシコGP リライアンス(Reliance)の株価 リライアンス株 リライアンス RIL株価 リライアンス・インダストリーズの株価 RIL株 RIL株価急騰の分析 リライアンス・インダストリーズ株 アヌジ・タクール 俳優アヌジ・タクール 発作 睡眠 飛行機墜落事故 フロリダでの飛行機墜落事故 リアジェット リアジェット60 動画 フロリダ オースティンでの事故 今日のニュース リミ・トミー リビン・マシュー、リミ・トミー リミ・トミーの結婚 結婚 リビン・マシュー リミ・トミー 2026年のサマータイム(デイライト・セービング) サマータイム 2026年米国のサマータイム 2026年米国サマータイム サマータイム 2026年米国サマータイム シャー・ルク・カーンの誕生日 シャー・ルク・カーン シャー・ルク・カーンの誕生日 キング SRK(シャー・ルク・カーン)の誕生日 シッダールト・アーナンド SRKの年齢 シャー・ルク ヒンディー語映画 ケーララ州宝くじの結果 ケーララ州宝くじ結果 今日のケーララ州宝くじ結果 今日の「バギャターラ(Bhagyathara)」宝くじ結果 今日の宝くじ結果 今日のケーララ州宝くじ結果(ライブ) 今日のケーララ州宝くじ結果 今日のケーララ州宝くじ結果(午後3時) 宝くじ本日の結果 ケーララ宝くじ 本日の結果(午後3時ライブ) ケーララ宝くじ 昨日の結果 তীব্র ঘূর্ণিঝড় 'মুরাসু' চেন্নাইতে আগামীকাল স্কুল ছুটি ঘূর্ণিঝড় 'মুরাসু' সংক্রান্ত আপডেট চেন্নাইতে আগামীকাল স্কুল ছুটি কি না আবহাওয়া চেন্নাইতে কি আগামীকাল ছুটি? ঘূর্ণিঝড় 'মুরাসু' ও আবহাওয়া চেন্নাইতে ঘূর্ণিঝড় ঘূর্ণিঝড় 'মুরাসু' ট্র্যাকার চেন্নাইয়ের আবহাওয়া তেলেঙ্গানা চেন্নাইয়ের আবহাওয়া ঘূর্ণিঝড় ট্র্যাকার চেঙ্গলপাট্টুতে আজ স্কুল ছুটি চেন্নাইতে স্কুল ছুটি চেঙ্গলপাট্টুতে স্কুল ছুটি বিজয়ওয়াড়ার আবহাওয়া আবহাওয়া প্রতিবেদন ঘূর্ণিঝড় 'মুরাসু' ট্র্যাকার আজকের আবহাওয়া প্রতিবেদন চেন্নাইতে আগামীকাল স্কুল ছুটি চেন্নাইয়ের আবহাওয়া চেন্নাইতে আজ স্কুল ছুটি কি না আজকের চেন্নাইয়ের আবহাওয়া বিমান চলাচল তামিল পাখতাকোর বনাম আল-নাসর পাখতাকোর এফসি বনাম আল-নাসর পয়েন্ট টেবিল এএফসি চ্যাম্পিয়ন্স লিগ পাখতাকোর এফসি বনাম আল-নাসর লাইনআপ জোয়াও ফেলিক্স আল-নাসর এফসি পাখতাকোর এফসি নিউ ইংল্যান্ড বনাম ইন্টার মায়ামি নিউ ইংল্যান্ড রেভোলিউশন বনাম ইন্টার মায়ামি পয়েন্ট টেবিল এমএলএস (MLS) ইন্টার মায়ামি লিওনেল মেসি ইন্টার মায়ামি সিএফ ইন্টার মায়ামি বনাম নিউ ইংল্যান্ড নিউ ইংল্যান্ড রেভোলিউশন বনাম ইন্টার মায়ামি লাইনআপ মেসির মোট গোল নিউ ইংল্যান্ড রেভোলিউশন বনাম ইন্টার মায়ামি টাইমলাইন ইন্টার মায়ামির ম্যাচসমূহ নিউ ইংল্যান্ড রেভোলিউশন নিউ ইংল্যান্ড রেভোলিউশন বনাম ইন্টার মায়ামি ওমান বনাম নেদারল্যান্ডস ওমান জাতীয় ক্রিকেট দল বনাম নেদারল্যান্ডস জাতীয় ক্রিকেট দল পয়েন্ট টেবিল ওমান বনাম নেদারল্যান্ডস ওমান জাতীয় ক্রিকেট দল বনাম নেদারল্যান্ডস জাতীয় ক্রিকেট দল ম্যাচ স্কোরকার্ড আইসিসি সিডব্লিউসি (CWC) লিগ ২ ওমান জাতীয় ক্রিকেট দল বনাম নেদারল্যান্ডস ক্রিকেট দল র‍্যাঙ্কিং ওমান জাতীয় ক্রিকেট দল বনাম নেদারল্যান্ডস ক্রিকেট দল ম্যাচ স্কোরকার্ড ২রা নভেম্বর সোনা ও রুপার দর সোনা ও রুপার দাম সোনা বিষয়ক খবর আজকের সোনার দর ব্যাঙ্গালোরে আজকের সোনার দর হায়দ্রাবাদে আজকের সোনার দর কলকাতায় আজকের সোনার দর চেন্নাইতে আজকের সোনার দর আজ সোনা ও রুপার দর ব্যাঙ্গালোরে আজকের সোনার দর চেন্নাইতে আজকের সোনার দর আজকের সোনার দর