DEV Community

HarmonyOS
HarmonyOS

Posted on

P2P Communication Between Android and HarmonyOS Wearable (FA + Stage Model) Device - Technical Guide

Read the original article:P2P Communication Between Android and HarmonyOS Wearable (FA + Stage Model) Device - Technical Guide

Problem Description

Establishing reliable peer-to-peer (P2P) communication between Android phone applications and HarmonyOS wearable device applications presents unique challenges due to the mixed platform architecture. This guide addresses message delivery, connection stability, and proper synchronization between Android (using HiWear SDK) and HarmonyOS(using wearEngine SDK) platforms.

Background Knowledge

Communication Architecture

The P2P communication system uses the wearEngine SDK to establish a bidirectional communication channel between phone and wearable applications. The system uses three primary API clients: wearEngine.AuthClient for authorization management, wearEngine.P2pClient for peer-to-peer communication, and wearEngine.DeviceClient for device discovery and management.

The hybrid P2P communication system uses:

Key Capabilities

  • Message Communication: Short text messages up to 1KB
  • File Transfer: Files up to 100MB (phone to wearable) or 4MB (wearable to phone)
  • Status Checking: Verification of app installation and running status
  • Device Management: Connection monitoring and device pairing

Prerequisites

  • Android Side: DEVICE_MANAGER permission
  • HarmonyOS Side: Developer console permission approval (3-5 days processing)
  • Both applications must be installed on their respective devices
  • Wearable device must be connected to phone via Huawei Health app
  • Proper signing certificate fingerprint configuration on both sides

Key Components

  • wearEngine.AuthClient: Authorization and permission management
  • wearEngine.DeviceClient: Device discovery and connection management
  • wearEngine.P2pClient: Core P2P communication object
  • wearEngine.P2pMessage: Message objects for communication
  • wearEngine.Permission: Permission enumeration for different access levels
  • Message Communication: Short text messages up to 1KB
  • File Transfer: Files up to 100MB (phone to wearable) or 4MB (wearable to phone)

Permission Requirements

Available permission enumerations are:

  • USER_STATUS (User status data)
  • HEALTH_SENSOR (Health sensor data like heart rate)
  • MOTION_SENSOR (Motion sensor data like accelerometer)
  • DEVICE_IDENTIFIER (Device identifier information)

Troubleshooting Process

Step 1: Verify Device Connection and App Installation

Enter the "Management Center" of the Huawei Developer Alliance, and click on the "Wear Engine" card under the "Application Service" tab.

Please refer to: Development Preparations

Step 2: Requesting User Authorization

In order to safeguard user privacy, the Wear Engine APIs require the user's authorization. It's advisable to execute the actions outlined in this section during the user's initial invocation of Wear Engine's open capabilities.

Please refer to: Requesting User Authorization

Step 3: Establish Communication Channel

Android FingerPrint Configuration:

Please refer to: setPeerPkgName

P2pClient p2pClient = HiWear.getP2pClient(this);
p2pClient.setPeerPkgName("com.example.wearableapp");
p2pClient.setPeerFingerPrint("FINGERPRINT");
Enter fullscreen mode Exit fullscreen mode

Harmony OS Wearable Configuration (Stage Model):

Please refer to: P2pAppParam

let appInfo: wearEngine.AppInfo = {
  // Set the device-side app information, including the bundle name and fingerprint.
  bundleName: '',
  fingerprint: ''
}
let appParam: wearEngine.P2pAppParam = {
  remoteApp: appInfo
  // The default value of transformLocalAppInfo is false, indicating that the bundle name and fingerprint are not converted.
}
Enter fullscreen mode Exit fullscreen mode

Harmony OS Wearable Configuration (FA Model):

Please refer to: P2pAppParam

var p2pClient = new P2pClient();
p2pClient.setPeerPkgName("com.example.phoneapp");
p2pClient.setPeerFingerPrint("FINGERPRINT")
Enter fullscreen mode Exit fullscreen mode

Step 4: Verify Device Connection and App Installation / Test Communication with Ping

Android Side (Phone):

Please refer to: Querying Wearable Device

// Step 2: Obtain the P2P communication object.
P2pClient p2pClient = HiWear.getP2pClient(this);
// Package name of an app on a specific device.
String devicePkgName = "com.*.*";

// Step 3: Obtain the version number of your app on the wearable device.
if (connectedDevice != null && connectedDevice.isConnected()) {
    p2pClient.getAppVersion(connectedDevice, devicePkgName)
        .addOnSuccessListener(new OnSuccessListener<Integer>() {
            @Override
            public void onSuccess(Integer versionCode) {
// The logic used when the task of obtaining the app version number on the device is successfully executed.
                // -1: The app has not been installed.
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(Exception e) {
// The logic used when the task of obtaining the app version number on the device fails to be executed.
            }
        });
}
Enter fullscreen mode Exit fullscreen mode

FA Model Hmos - Wearable Side:

Please refer to: P2pClient.ping

// Step 1: Create a P2P communication object.
var p2pClient = new P2pClient();
var peerPkgName = "com.*.*";

// Step 2: Set the package name of your phone app to be communicated with.
p2pClient.setPeerPkgName(peerPkgName);

// Step 3: Check whether your app has been installed on the phone.
p2pClient.ping({
  onSuccess: function() {
    console.log('ping success.');
  },
  onFailure: function() {
    console.log('ping failed');
  },
  onPingResult: function(resultCode) {
    console.log(resultCode.data + resultCode.code);
  },
});
Enter fullscreen mode Exit fullscreen mode

Stage Model Hmos - Wearable Side:

Please refer to: P2pClient

import { wearEngine } from '@kit.WearEngine';
import { BusinessError } from '@kit.BasicServicesKit';


let deviceClient: wearEngine.DeviceClient = wearEngine.getDeviceClient(this.getUIContext().getHostContext());
let p2pClient: wearEngine.P2pClient = wearEngine.getP2pClient(this.getUIContext().getHostContext());
let deviceList: wearEngine.Device[] = await deviceClient.getConnectedDevices();


deviceList.forEach(async (device, idx, arr) => {
  // Select the device that supports app installation.
  if (await device.isDeviceCapabilitySupported(wearEngine.DeviceCapability.APP_INSTALLATION)) {
    // Define the device-side app bundle name as remoteBundleName.
    let remoteBundleName: string = '';


    p2pClient.isRemoteAppInstalled(device.randomId, remoteBundleName).then((isInstall) => {
      console.info(`Succeeded in checking remote app install, result is ${isInstall}.`);
    }).catch((error: BusinessError) => {
      console.error(`Failed to check remote app install. Code is ${error.code}, message is ${error.message}.`);
    })
  }
  if (idx === deviceList.length - 1) {
    // An error is thrown if the target device does not exist.
    throw new Error('cannot find target device');
  }
})
Enter fullscreen mode Exit fullscreen mode

Step 5: Implement Message Sending

Android to Wearable:

Please refer to: Sending P2P Messages

// Step 2: Send a message.
String messageStr = "Hello, Wear Engine!";
Message.Builder builder = new Message.Builder();
builder.setPayload(messageStr.getBytes(StandardCharsets.UTF_8));
Message sendMessage = builder.build();


// Step 3: Obtain the P2P communication object.
P2pClient p2pClient = HiWear.getP2pClient(this);


// Step 4: Specify the package name of your wearable app to be communicated with.
String peerPkgName = "com.*.*";
p2pClient.setPeerPkgName(peerPkgName);


// Step 5: Specify the signing certificate fingerprint of your wearable app to be communicated with. The maximum length of the fingerprint on the lite wearable device is 127 bits.
String peerFingerPrint = "*******";
p2pClient.setPeerFingerPrint(peerFingerPrint);


// Step 6: Send short messages from your phone app to the wearable app.
// Create the callback method.
SendCallback sendCallback = new SendCallback() {
    @Override
    public void onSendResult(int resultCode) {
// If the resultCode value is 207, the messages have been sent successfully. Other values indicate that the messages fail to be sent.
    }
    @Override
    public void onSendProgress(long progress) {
    }
};
if(connectedDevice != null && connectedDevice.isConnected() && sendMessage != null && sendCallback != null){
    p2pClient.send(connectedDevice, sendMessage, sendCallback)
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void successVoid) {
                // Related processing logic for your app after the send task is successfully executed.
            }
     })
       .addOnFailureListener(new OnFailureListener() {
           @Override
           public void onFailure(Exception e) {
               // Related processing logic for your app after the send task fails.
           }
       });
}
Enter fullscreen mode Exit fullscreen mode

FA Model Wearable to Android:

Please refer to: P2P Send Message

// Step 1: Create a P2P communication object.
var p2pClient = new P2pClient();
var peerPkgName = "com.*.*";
var peerFinger = "67DFB7FD********";

// Step 2: Set the package name of your phone app to be communicated with.
p2pClient.setPeerPkgName(peerPkgName);

// Step 3: Set the app fingerprint information on the phone.
p2pClient.setPeerFingerPrint(peerFinger);

// Step 4: Send a short message to your phone app.
// Build a Builder object.
var builderClient = new Builder();
var messageStr = "Hello, Wear Engine!";
builderClient.setDescription(messageStr);
// Build a Message object
var sendMessage = new Message();
sendMessage.builder = builderClient;
// Define the callback function.
var sendCallback = {
  onSuccess: function() {
    // Related processing logic for your app after the send task is successfully executed.
  },
  onFailure: function() {
    // Related processing logic for your app after the send task fails.
  },
  onSendResult: function(resultCode) {
    // Process the result code and information returned after the send task is complete.
    console.log(resultCode.data + resultCode.code);
  },
}
if(sendMessage != null && sendCallback != null){
  p2pClient.send(sendMessage, sendCallback);
};
Enter fullscreen mode Exit fullscreen mode

Stage Model Wearable to Android

Please refer to: P2P Send Message

import { wearEngine } from '@kit.WearEngine';
import { BusinessError } from '@kit.BasicServicesKit';
import { util } from '@kit.ArkTS';


let deviceClient: wearEngine.DeviceClient = wearEngine.getDeviceClient(this.getUIContext().getHostContext());
let p2pClient: wearEngine.P2pClient = wearEngine.getP2pClient(this.getUIContext().getHostContext());
let deviceList: wearEngine.Device[] = await deviceClient.getConnectedDevices();


deviceList.forEach(async (device, idx, arr) => {
  // Select the device that supports app installation.
  if (await device.isDeviceCapabilitySupported(wearEngine.DeviceCapability.APP_INSTALLATION)) {
    // Set the device-side app information, including the bundle name and fingerprint.
    let appInfo: wearEngine.AppInfo = {
      bundleName: '',
      fingerprint: ''
    }
    // Define the device-side app parameter class as appParam.
    let appParam: wearEngine.P2pAppParam = {
      remoteApp: appInfo
      // The default value of transformLocalAppInfo is false, indicating that the bundle name and fingerprint are not converted.
    }


    // Set the message to be sent.
    let messageContent: string = 'this is message';
    let textEncoder: util.TextEncoder = new util.TextEncoder;
    let message: wearEngine.P2pMessage = {
      content: textEncoder.encodeInto(messageContent)
    }


    p2pClient.sendMessage(device.randomId, appParam, message).then((p2pResult) => {
      console.info(`Succeeded in sending message, result is ${p2pResult.code}.`);
    }).catch((error: BusinessError) => {
      console.error(`Failed to send message. Code is ${error.code}, message is ${error.message}.`);
    })
  }
  if (idx === deviceList.length - 1) {
    // An error is thrown if the target device does not exist.
    throw new Error('cannot find target device');
  }
})
Enter fullscreen mode Exit fullscreen mode

Step 5: Set Up Message Receivers

Android Receiver:

Please refer to: P2P Receiver Android

Receiver receiver = new Receiver() {
    @Override
    public void onReceiveMessage(Message message) {
        if (message.getType() == Message.MESSAGE_TYPE_DATA) {
            // Process messages sent by your wearable app.
        } else if (message.getType() == Message.MESSAGE_TYPE_FILE) {
            // Process the file sent by your wearable app.
        }
    }
};
Enter fullscreen mode Exit fullscreen mode

FA Model Wearable Receiver:

Please refer to: P2P Receiver FA

// Step 1: Create a P2P communication object.
var p2pClient = new P2pClient();
var peerPkgName = "com.*.*";
var peerFinger = "67DFB7FD********";


// Step 2: Set the package name of your phone app to be communicated with.
p2pClient.setPeerPkgName(peerPkgName);


// Step 3: Set the app fingerprint information on the phone.
p2pClient.setPeerFingerPrint(peerFinger);


// Step 4: Receive short messages or files from your phone app.
// Define the receiver
var flash = this;
var receiver = {
  onSuccess: function() {
    // Process the callback function returned when messages or files have been received from the phone during registration.
    flash.receiveMessageOK="Succeeded in receiving the message";
  },
  onFailure: function() {
    // Process the callback function returned when messages or files fail to be received from the phone during registration.
    flash.receiveMessageOK="Failed to receive the message";
  },
  onReceiveMessage: function (data) {
    if (data && data.isFileType) {
      // Process the file sent by your phone app.
      flash.receiveMessageOK = "file:"+data.name;
    } else {
      // Process the message sent from your phone app.
      flash.receiveMessageOK = "message:"+data;
    }
  },
}
p2pClient.registerReceiver(receiver);


// Step 5: Cancel the reception of messages or files from your phone app.
p2pClient.unregisterReceiver({
    onSuccess:function() {
console.log = ("Stopped receiving messages"); 
    },
    onFailure:function() {
console.log = ("Failed to stop receiving messages");
    }
});
Enter fullscreen mode Exit fullscreen mode

Stage Model Wearable Receiver:

Please refer to: P2P Receiver Stage

import { wearEngine } from '@kit.WearEngine';
import { BusinessError } from '@kit.BasicServicesKit';


let deviceClient: wearEngine.DeviceClient = wearEngine.getDeviceClient(this.getUIContext().getHostContext());
let p2pClient: wearEngine.P2pClient = wearEngine.getP2pClient(this.getUIContext().getHostContext());
let deviceList: wearEngine.Device[] = await deviceClient.getConnectedDevices();


deviceList.forEach(async (device, idx, arr) => {
  // Select the device that supports app installation.
  if (await device.isDeviceCapabilitySupported(wearEngine.DeviceCapability.APP_INSTALLATION)) {
    // Set the device-side app information, including the bundle name and fingerprint.
    let appInfo: wearEngine.AppInfo = {
      bundleName: '',
      fingerprint: ''
    }
    // Define the device-side app parameter class as appParam.
    let appParam: wearEngine.P2pAppParam = {
      remoteApp: appInfo
      // The default value of transformLocalAppInfo is false, indicating that the bundle name is not converted.
    }
    // Set information about the file to be sent.
    let callback = (p2pMessage: wearEngine.P2pMessage) => {
      console.info(`Succeeded in receiving message, the message is ${p2pMessage.content}.`)
    }


    p2pClient.registerMessageReceiver(device.randomId, appParam, callback).then(() => {
      console.info(`Succeeded in registering message receiver.`);
    }).catch((error: BusinessError) => {
      console.error(`Failed to register message receiver. Code is ${error.code}, message is ${error.message}.`);
    })
  }
  if (idx === deviceList.length - 1) {
    // An error is thrown if the target device does not exist.
    throw new Error('cannot find target device');
  }
})
Enter fullscreen mode Exit fullscreen mode

Analysis Conclusion

Critical Success Factors

  1. Proper Permission Management: DEVICE_MANAGER permission is mandatory
  2. Certificate Fingerprint Matching: Fingerprints must be correctly configured
  3. Package Name Consistency: Peer package names must match exactly
  4. Connection State Verification: Always check device connection before operations
  5. Lifecycle Management: Proper registration/unregistration of receivers
  6. Permission Management: The permissions you request must correspond to the permissions you've applied for in the developer console. Permission mismatches result in error code 1008500004.
  7. Data Format Conversion: Only binary data can be sent, so it is necessary to convert it into the corresponding format through textEncoder.encodeInto.
  8. Remote App Configuration: Configure the package name and appid of the current application on both the mobile phone side and the watch side. If not configured properly, errors such as 206 and 207 will occur.
  9. Early Permission Application: The permission review may take a long time. Even if expedited, it may take 3 to 5 days. Therefore, if you need to use this permission, you should apply for it as early as possible.

Common Failure Points

  • Permission mismatch between requested and approved permissions (error 1008500004)
  • Missing or incorrect wearEngineRemoteAppNameList configuration
  • Attempting to send non-binary data without proper conversion
  • Remote app not installed or not properly launched
  • Incorrect bundleName or fingerprint configuration

Solution

Complete Implementation Template

Wearable App Implementation Example:

public class P2PCommunicationManager {
    private P2pClient p2pClient;
    private Device connectedDeice;
    private static final String PEER_PKG_NAME = "com.example.wearableapp";
    private static final String PEER_FINGERPRINT = "FINGERPRINT";

    public void initializeP2P(Context context) {
        p2pClient = HiWear.getP2pClient(context);
        p2pClient.setPeerPkgName(PEER_PKG_NAME);
        p2pClient.setPeerFingerPrint(PEER_FINGERPRINT);
    }

    public void sendMessage(String message) {
        if (isDeviceReady()) {
            Message.Builder builder = new Message.Builder();
            builder.setPayload(message.getBytes(StandardCharsets.UTF_8));
            Message sendMessage = builder.build();

            p2pClient.send(connectedDevice, sendMessage, new SendCallback() {
                @Override
                public void onSendResult(int resultCode) {
                    handleSendResult(resultCode);
                }

                @Override
                public void onSendProgress(long progress) {
                    // Handle progress
                }
            });
        }
    }

    public void registerMessageReceiver() {
        if (isDeviceReady()) {
            Receiver receiver = new Receiver() {
                @Override
                public void onReceiveMessage(Message message) {
                    processReceivedMessage(message);
                }
            };

            p2pClient.registerReceiver(connectedDevice, receiver);
        }
    }

    private boolean isDeviceReady() {
        return connectedDevice != null && connectedDevice.isConnected();
    }
Enter fullscreen mode Exit fullscreen mode

FA Model Wearable App Implementation Example:

var p2pClient = new P2pClient();
var messageClient = new Message();
var builderClient = new Builder();

export default {
    data: {
    },
    onInit() {
        p2pClient.setPeerPkgName("com.example.phoneapp");
        p2pClient.setPeerFingerPrint("PEER_FINGERPRINT");
        this.registerMessage()
    },
    onDestroy() {
        this.unregisterMessage();
    },
    registerMessage() {
        var flash = this;
        console.log('Register message button click');
        p2pClient.registerReceiver({
            onSuccess: function () {
                console.log('Message receive success');
            },
            onFailure: function () {
                console.log('Message receive fail');
            },
            onReceiveMessage: function (data) {
                if (data && data.isFileType) {
                    console.log("Receive file name:" + data.name);
                } else {
                    console.log('Received message: ' + data);
                }
            },
        });
    },
    unregisterMessage() {
        p2pClient.unregisterReceiver({
            onSuccess: function () {
                console.log("Stop receiving messages is sent");
            },
        });
    },
    sendMessage() {
        builderClient.setDescription("hello wearEngine");
        messageClient.builder = builderClient;
        p2pClient.send(messageClient, {
            onSuccess: function () {
                console.log("Message sent successfully");
            },
            onFailure: function () {
                console.log("Failed to send message");
            },
            onSendResult: function (resultCode) {
                console.log(resultCode.data + resultCode.code);
            },
            onSendProgress: function (count) {
                console.log(count);
            },
        });

    },
}
Enter fullscreen mode Exit fullscreen mode

Stage Model Wearable App Implementation Example:

import { wearEngine } from '@kit.WearEngine';
import { BusinessError } from '@kit.BasicServicesKit';
import { util } from '@kit.ArkTS';

export class StageModelWearableP2PManager {
    private deviceClient: wearEngine.DeviceClient;
    private p2pClient: wearEngine.P2pClient;
    private authClient: wearEngine.AuthClient;
    private targetDevice: wearEngine.Device | null = null;
    private appParam: wearEngine.P2pAppParam;
    private isInitialized: boolean = false;

    constructor(context: Context, phoneAppBundleName: string, phoneAppFingerprint: string) {
        this.deviceClient = wearEngine.getDeviceClient(context);
        this.p2pClient = wearEngine.getP2pClient(context);
        this.authClient = wearEngine.getAuthClient(context);

        // Set the phone app information
        let appInfo: wearEngine.AppInfo = {
            bundleName: phoneAppBundleName,
            fingerprint: phoneAppFingerprint
        };

        this.appParam = {
            remoteApp: appInfo,
            transformLocalAppInfo: false
        };
    }

    async initializeP2P(): Promise<boolean> {
        try {
            // Step 1: Request authorization
            let request: wearEngine.AuthorizationRequest = {
                permissions: [wearEngine.Permission.USER_STATUS]
            };

            await this.authClient.requestAuthorization(request);
            console.info('Authorization granted successfully');

            // Step 2: Get connected devices
            let deviceList: wearEngine.Device[] = await this.deviceClient.getConnectedDevices();
            console.info(`Found ${deviceList.length} connected devices`);

            if (deviceList.length === 0) {
                throw new Error('No connected devices found');
            }

            // Step 3: Find target device with app installation capability
            for (let idx = 0; idx < deviceList.length; idx++) {
                const device = deviceList[idx];

                if (await device.isDeviceCapabilitySupported(wearEngine.DeviceCapability.APP_INSTALLATION)) {
                    this.targetDevice = device;
                    console.info(`Target device found: ${device.category}`);
                    break;
                }

                if (idx === deviceList.length - 1 && !this.targetDevice) {
                    throw new Error('Cannot find target device with app installation capability');
                }
            }

            // Step 4: Check remote app installation
            const isInstalled = await this.p2pClient.isRemoteAppInstalled(
                this.targetDevice!.randomId, 
                this.appParam.remoteApp.bundleName
            );

            console.info(`Remote app installation status: ${isInstalled}`);

            if (!isInstalled) {
                console.warn('Remote app not installed');
                // Optionally try to start the remote app
                await this.startRemoteApp();
            }

            this.isInitialized = true;
            return true;

        } catch (error) {
            console.error(`P2P initialization failed: ${error}`);
            return false;
        }
    }

    async sendMessage(messageContent: string): Promise<boolean> {
        if (!this.isInitialized || !this.targetDevice) {
            console.error('P2P not initialized or no target device');
            return false;
        }

        try {
            const textEncoder: util.TextEncoder = new util.TextEncoder();
            const message: wearEngine.P2pMessage = {
                content: textEncoder.encodeInto(messageContent)
            };

            const result = await this.p2pClient.sendMessage(
                this.targetDevice.randomId, 
                this.appParam, 
                message
            );

            console.info(`Message sent successfully, result code: ${result.code}`);
            return result.code === 0;

        } catch (error) {
            console.error(`Failed to send message: ${error}`);
            return false;
        }
    }

    async registerMessageReceiver(): Promise<boolean> {
        if (!this.isInitialized || !this.targetDevice) {
            console.error('P2P not initialized or no target device');
            return false;
        }

        try {
            const callback = (p2pMessage: wearEngine.P2pMessage) => {
                const textDecoder = new util.TextDecoder();
                const messageText = textDecoder.decodeWithStream(p2pMessage.content);
                console.info(`Received message: ${messageText}`);
                this.handleReceivedMessage(messageText);
            };

            await this.p2pClient.registerMessageReceiver(
                this.targetDevice.randomId,
                this.appParam,
                callback
            );

            console.info('Message receiver registered successfully');
            return true;

        } catch (error) {
            console.error(`Failed to register message receiver: ${error}`);
            return false;
        }
    }

    private async startRemoteApp(): Promise<boolean> {
        if (!this.targetDevice) {
            return false;
        }

        try {
            const result = await this.p2pClient.startRemoteApp(
                this.targetDevice.randomId,
                this.appParam.remoteApp.bundleName
            );

            console.info(`Remote app start result: ${result.code}`);
            return result.code === 0;

        } catch (error) {
            console.error(`Failed to start remote app: ${error}`);
            return false;
        }
    }

    private handleReceivedMessage(message: string) {
        try {
            // Try to parse as JSON, fallback to plain text
            let data: any;
            try {
                data = JSON.parse(message);
            } catch {
                data = { type: 'text', content: message };
            }

            // Handle different message types
            switch (data.type) {
                case 'notification':
                    this.showNotification(data.content);
                    break;
                case 'health_request':
                    this.sendHealthData();
                    break;
                case 'command':
                    this.executeCommand(data.command);
                    break;
                default:
                    console.info(`Received text message: ${message}`);
            }

        } catch (error) {
            console.error(`Error handling received message: ${error}`);
        }
    }

    private showNotification(content: string) {
        console.info(`Showing notification: ${content}`);
        // Implement notification display logic here
    }

    private async sendHealthData() {
        const healthData = {
            type: 'health_data',
            heartRate: 72,
            steps: 8500,
            calories: 320,
            timestamp: Date.now()
        };

        await this.sendMessage(JSON.stringify(healthData));
    }

    private executeCommand(command: string) {
        console.info(`Executing command: ${command}`);

        switch (command) {
            case 'vibrate':
                // Implement vibration
                break;
            case 'get_battery':
                this.sendBatteryStatus();
                break;
            default:
                console.warn(`Unknown command: ${command}`);
        }
    }

    private async sendBatteryStatus() {
        const batteryData = {
            type: 'battery_status',
            level: 85,
            charging: false,
            timestamp: Date.now()
        };

        await this.sendMessage(JSON.stringify(batteryData));
    }

    // Public method to send specific data types
    async sendSensorData(sensorType: string, value: number): Promise<boolean> {
        const sensorData = {
            type: 'sensor_data',
            sensorType: sensorType,
            value: value,
            timestamp: Date.now()
        };

        return await this.sendMessage(JSON.stringify(sensorData));
    }

    // Public method to check connection status
    isConnected(): boolean {
        return this.isInitialized && this.targetDevice !== null;
    }

    // Cleanup method
    async cleanup(): Promise<void> {
        try {
            // Unregister receivers if needed
            this.isInitialized = false;
            this.targetDevice = null;
            console.info('P2P cleanup completed');
        } catch (error) {
            console.error(`Cleanup error: ${error}`);
        }
    }
}

// Usage in Wearable App Main Class
export default class WearableMainAbility {
    private p2pManager: StageModelWearableP2PManager | null = null;

    onCreate() {
        console.info('Wearable app created');
        this.initializeP2P();
    }

    private async initializeP2P() {
        try {
            // Initialize P2P manager with phone app details
            this.p2pManager = new StageModelWearableP2PManager(
                getContext(this),
                'com.example.phoneapp',    // Phone app bundle name
                'PHONE_APP_FINGERPRINT'    // Phone app fingerprint
            );

            // Initialize connection
            const success = await this.p2pManager.initializeP2P();

            if (success) {
                // Register message receiver
                await this.p2pManager.registerMessageReceiver();

                // Send initial status
                const initialStatus = {
                    type: 'wearable_ready',
                    deviceModel: 'Huawei Watch GT',
                    appVersion: '1.0.0',
                    timestamp: Date.now()
                };

                await this.p2pManager.sendMessage(JSON.stringify(initialStatus));
                console.info('Wearable P2P communication initialized successfully');

                // Example: Send periodic health data
                this.startPeriodicHealthUpdates();

            } else {
                console.error('Failed to initialize P2P communication');
            }

        } catch (error) {
            console.error(`P2P initialization error: ${error}`);
        }
    }

    private startPeriodicHealthUpdates() {
        // Send health data every 30 seconds
        setInterval(async () => {
            if (this.p2pManager?.isConnected()) {
                await this.p2pManager.sendSensorData('heart_rate', Math.floor(Math.random() * 40) + 60);
            }
        }, 30000);
    }

    onDestroy() {
        console.info('Wearable app destroying');
        this.p2pManager?.cleanup();
    }

    // Example method to handle user interactions
    onUserButtonClick() {
        if (this.p2pManager?.isConnected()) {
            const userAction = {
                type: 'user_action',
                action: 'button_pressed',
                timestamp: Date.now()
            };

            this.p2pManager.sendMessage(JSON.stringify(userAction));
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Verification Result

Testing Checklist

  • Developer Console Permissions: Applied for and approved WearEngine permissions (3-5 days processing time)
  • Both apps installed and permissions granted
  • Device connection established and verified
  • Ping test successful (appropriate result codes returned)
  • Message sending works in both directions
  • File transfer functional within size limits
  • Receivers properly registered and processing messages
  • App launch via ping method functional (if applicable)
  • Module Configuration: client_id and wearEngineRemoteAppNameList properly configured in module.json5
  • Authorization Success: requestAuthorization() completes without error 1008500004
  • Device Discovery: getConnectedDevices() returns the target wearable device
  • Remote App Installation: isRemoteAppInstalled() returns true for the target bundle
  • Binary Data Conversion: Messages are properly converted using textEncoder.encodeInto()
  • Bidirectional Communication: Both send and receive operations working correctly
  • Error Handling: Proper handling for common error codes (206, 207, 1008500004)

Expected Results

  • Authorization callback succeeds with proper permissions
  • Device discovery returns connected HarmonyOS wearable devices
  • Remote app installation check returns appropriate status
  • Message sending completes without exceptions
  • Message receiver callback triggers on the target device
  • Binary data converts properly using textEncoder.encodeInto()

Common Error Codes

  • 1008500004: Permission mismatch between requested and approved permissions
  • 206/207: Configuration errors with wearEngineRemoteAppNameList or bundleName

Related Documents or Links

Official Documentation

Development Resources

Troubleshooting References

Written by Mustafa Sahin

Top comments (0)