Read the original article:Seamless Data Synchronization Between Phone and Wearable via Wear Engine
Requirement Description
A unified architecture is required to synchronize data between a mobile device and a HarmonyOS wearable using the Wear Engine framework. The solution must support real-time updates, offline tolerance, automatic retry on failures, and bi-directional communication with minimal battery and bandwidth consumption.
Background Knowledge
- HarmonyOS Wear Engine supports phone–wearable communication with capabilities such as messaging, data transfer, and event subscription.
- Wearable devices have limitations: reduced compute, limited battery, BLE-based transmission characteristics, and strict payload size limits.
- Data synchronization needs to avoid redundant transfers, support retries with controlled backoff, and ensure consistency and idempotency across both devices.
Implementation Steps
-
Define Sync Model
- Identify data types (settings, activity metrics, preferences, user actions).
- Define lightweight DTOs for Wear Engine transfer.
- Add a
syncIdandversion/timestampto each payload for idempotent retries.
-
Establish Communication Channel
- Use
WearEngineClientfor connection initialization on mobile. - Use
WearEngine.getInstance()on wearable to listen to commands. - Define a common message contract:
{ syncId, type, payload, version }.
- Use
-
Design Sync Flow
- Trigger-based sync (user action, scheduled interval, API push).
- State-based sync (hash comparison to avoid unnecessary payload).
- Conflict resolution rule (mobile-first, wearable-first, timestamp-based).
-
Retry Mechanism Design (Core Part)
- Maintain a Retry Queue on the sender side:
- Each item:
{ syncId, payload, attemptCount, nextRetryAt }.
- Each item:
- On send failure or missing ACK within timeout:
- Increment
attemptCount. - Calculate
nextRetryAtusing exponential backoff (e.g.baseDelay * 2^(attemptCount-1)with an upper limit). - Re-enqueue the item if
attemptCount < MAX_RETRY.
- Increment
- On ACK received:
- Remove the item from the Retry Queue.
- Ensure all operations are idempotent:
- Receiver uses
syncId+versionto detect duplicates. - If
syncIdalready processed with same or higher version, ignore but still send ACK.
- Receiver uses
- Maintain a Retry Queue on the sender side:
-
Architectural Layers
-
Sync Manager (Mobile):
- Builds sync payloads, pushes to Transport Layer, manages Retry Queue and timeout/ACK logic.
-
Sync Service (Wearable):
- Receives updates, validates
syncId/version, applies changes, and sends ACK.
- Receives updates, validates
-
Local Cache Layer:
- Stores last applied
syncId+versionfor quick duplicate detection.
- Stores last applied
-
Transport Layer:
- Wear Engine messaging (send/receive).
-
Sync Manager (Mobile):
-
Data Packaging Strategy
- Serialize data to JSON or binary.
- Compress if needed and ensure payload < BLE recommended limits.
- Include
metafields:syncId,version,type.
-
Sequence Diagram Explanation
- Mobile triggers sync
- Sync Manager sends message via Wear Engine
- Wearable receives, checks duplicate, applies update
- Wearable sends ACK containing
syncId+ result - Mobile marks sync item as completed and removes it from Retry Queue.
- If ACK not received in T seconds → retry logic kicks in.
Code Snippet
Sender Side (Mobile) : Basic Retry Skeleton
interface SyncItem {
syncId: string;
payload: any;
attemptCount: number;
nextRetryAt: number;
}
const MAX_RETRY = 5;
const BASE_DELAY_MS = 2000; // 2 seconds
let retryQueue: SyncItem[] = [];
function sendWithRetry(deviceId: string, payload: any) {
const syncId = generateSyncId();
const item: SyncItem = {
syncId,
payload: { ...payload, syncId },
attemptCount: 0,
nextRetryAt: Date.now()
};
retryQueue.push(item);
processRetryQueue(deviceId);
}
function processRetryQueue(deviceId: string) {
const now = Date.now();
retryQueue
.filter(item => item.nextRetryAt <= now)
.forEach(item => {
wearEngineClient.sendMessage(
deviceId,
"SYNC_REQUEST",
JSON.stringify(item.payload),
(err) => {
if (err) {
item.attemptCount++;
if (item.attemptCount < MAX_RETRY) {
const delay = BASE_DELAY_MS * Math.pow(2, item.attemptCount - 1);
item.nextRetryAt = now + Math.min(delay, 30000); // cap at 30s
} else {
// mark as failed / log for monitoring
removeItemFromQueue(item.syncId);
}
} else {
// message send ok – still wait for ACK
// optional: start ACK timeout timer here
}
}
);
});
}
// Called when ACK is received from wearable
function onAckReceived(syncId: string) {
removeItemFromQueue(syncId);
}
function removeItemFromQueue(syncId: string) {
retryQueue = retryQueue.filter(item => item.syncId !== syncId);
}
Receiver Side (Wearable) : Idempotent Apply + ACK
let processedMap: Map<string, number> = new Map(); // syncId -> version
wearEngine.onMessageReceived((msg) => {
const data = JSON.parse(msg.data);
const { syncId, version } = data;
const lastVersion = processedMap.get(syncId) ?? 0;
if (version > lastVersion) {
applySync(data); // domain-specific logic
processedMap.set(syncId, version);
}
// Always ACK, even on duplicate, so sender stops retrying
wearEngine.sendMessage(msg.sourceDeviceId, "SYNC_ACK", JSON.stringify({ syncId }));
});
Note: In the actual project, error management, persistent storage (persistent map), and timer management will be detailed according to the project.
Test Results
- Verified sync reliability with 50+ consecutive transfers under normal conditions.
- Simulated temporary connection loss: confirmed that retry mechanism successfully completed sync once the connection was restored.
- Verified that duplicate messages (due to retries) did not create inconsistent state on the wearable because of
syncId + versionchecks. - Measured that exponential backoff reduced battery impact compared to constant-interval retries.
Limitations
- Excessive retries still consume battery; set reasonable
MAX_RETRYand cap maximum delay. - For long offline periods, it may be better to collapse multiple pending items into a single aggregated sync.
- BLE transmission may drop under poor signal or OS power restrictions; retry cannot fully guarantee delivery.
- Idempotency logic (
syncId,version) must be properly implemented to avoid inconsistent states. - Persistent storage for
processedMapmay be required if the wearable frequently restarts.
Related Documents or Links
- https://developer.huawei.com/consumer/en/doc/development/connectivity-Guides/service-introduction-0000000000018585
- https://developer.huawei.com/consumer/en/doc/harmonyos-guides/watch_query_connected_devices
Top comments (0)