Problem Description
Establishing reliable peer-to-peer (P2P) communication between Android phone applications and wearable device applications presents several technical challenges. Developers often encounter issues with message delivery, file transfer limitations, connection stability, and proper synchronization between the two platforms. The complexity increases when dealing with different device types (lite wearable vs smart wearable) and ensuring both applications are properly installed and running.
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.
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)
Prerequisites
Developer console permission approval (takes 3-5 days even with expedited processing), proper client_id configuration in module.json5, and binary data format conversion using textEncoder.encodeInto() before transmission. Both applications must be installed on their respective devices and wearable device must be connected to the 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
Note: The permission review may take a long time. Even if expedited, it may take 3 to 5 days.
Harmony OS Side (Phone):
- Querying Whether the Wearable Device Supports Certain Wear Engine Capabilities
let deviceClient: wearEngine.DeviceClient = wearEngine.getDeviceClient(getContext(this));
let deviceList: wearEngine.Device[] = [];
deviceClient.getConnectedDevices().then(devices => {
// Store the list of connected devices.
deviceList = devices;
console.info(`Succeeded in getting deviceList, devices number is ${deviceList.length}`);
}).catch((error: BusinessError) => {
// Process the exception captured when the calling fails.
console.error(`Failed to get deviceList. Code is ${error.code}, message is ${error.message}`);
})
if (deviceList.length > 0) {
// Step 3 Select the target device from the obtained device list and define it as device. (Assume that there are connected devices in the array and the first one is the target device.)
let targetDevice: wearEngine.Device = deviceList[0];
// Step 4 Call the method to check whether certain Wear Engine capability is supported (the P2P capability is used as an example).
targetDevice.isWearEngineCapabilitySupported(wearEngine.WearEngineCapability.P2P_COMMUNICATION).then((isSupportP2P) => {
console.info(`Succeeded in checking p2p capability, result is ${isSupportP2P}`);
}).catch((error: BusinessError) => {
console.error(`Failed to check p2p capability. Code is ${error.code}, message is ${error.message}`);
})
}
- Querying Whether the Wearable Device Supports Certain Device Capabilities
let deviceClient: wearEngine.DeviceClient = wearEngine.getDeviceClient(getContext(this));
let deviceList: wearEngine.Device[] = [];
deviceClient.getConnectedDevices().then(devices => {
// Store the list of connected devices.
deviceList = devices;
console.info(`Succeeded in getting deviceList, devices number is ${deviceList.length}`);
}).catch((error: BusinessError) => {
// Process the exception captured when the calling fails.
console.error(`Failed to get deviceList. Code is ${error.code}, message is ${error.message}`);
})
if (deviceList.length > 0) {
// Step 3 Select the target device from the obtained device list and define it as device. (Assume that there are connected devices in the array and the first one is the target device.)
let targetDevice: wearEngine.Device = deviceList[0];
// Step 4 Call the device method to query whether a certain device capability is supported (the app installation capability is used as an example).
targetDevice.isDeviceCapabilitySupported(wearEngine.DeviceCapability.APP_INSTALLATION).then((isSupportInstall) => {
console.info(`Succeeded in checking install app capability, result is ${isSupportInstall}`);
}).catch((error: BusinessError) => {
console.error(`Failed to check install app capability. Code is ${error.code}, message is ${error.message}`);
})
}
- Selecting by Device Type
Use the DeviceCategory field from each device to filter for a specific type (e.g., WATCH):
let targetDevice: wearEngine.Device;
deviceList.forEach((device, idx, arr) => {
if (device.category === wearEngine.DeviceCategory.WATCH) {
targetDevice = device;
}
if (idx === deviceList.length - 1) {
throw new Error('cannot find target device');
}
});
- Selecting by Wear Engine Capabilities Filter devices that support a specific Wear Engine feature, such as MONITOR:
let targetDevice: wearEngine.Device;
deviceList.forEach(async (device, idx, arr) => {
if (await device.isWearEngineCapabilitySupported(wearEngine.WearEngineCapability.MONITOR)) {
targetDevice = device;
}
if (idx === deviceList.length - 1) {
throw new Error('cannot find target device');
}
});
- Selecting by General Device Capabilities Check for support of broader device-level capabilities like app installation:
let targetDevice: wearEngine.Device;
deviceList.forEach(async (device, idx, arr) => {
if (await device.isDeviceCapabilitySupported(wearEngine.DeviceCapability.APP_INSTALLATION)) {
targetDevice = device;
}
if (idx === deviceList.length - 1) {
throw new Error('cannot find target device');
}
});
Step 2: Establish a Communication Channel
Harmony OS Side (Phone):
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.
}
Harmony OS Wearable Configuration (Stage Model):
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.
}
Harmony OS Wearable Configuration (FA Model):
var p2pClient = new P2pClient();
p2pClient.setPeerPkgName("com.example.phoneapp");
p2pClient.setPeerFingerPrint("FINGERPRINT")
Step 3: Checking Whether the Wearable App Has Been Installed
Harmony OS Side (Phone):
let remoteBundleName: string = '';
// Step 3 Obtain the P2pClient object.
let p2pClient: wearEngine.P2pClient = wearEngine.getP2pClient(getContext(this));
// Step 4 Check whether the specified app has been installed on the device.
p2pClient.isRemoteAppInstalled(targetDevice.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}.`);
})
Harmony OS Wearable Set P2P Communication Object (Stage Model):
// Define the device-side app bundle name as remoteBundleName.
let remoteBundleName: string = '';
// Step 3 Obtain the P2pClient object.
let p2pClient: wearEngine.P2pClient = wearEngine.getP2pClient(getContext(this));
// Step 4 Launch the specified device-side app (transformLocalBundleName defaults to false).
p2pClient.startRemoteApp(targetDevice.randomId, remoteBundleName).then((p2pResult) => {
console.info(`Succeeded in starting remote app, result is ${p2pResult.code}.`);
}).catch((error: BusinessError) => {
console.error(`Failed to start remote app. Code is ${error.code}, message is ${error.message}.`);
})
Harmony OS Wearable Set P2P (FA Model) :
You can use a 'ping' in the FA model
// 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);
},
});
Step 4: Implement Message Sending
HMOS Watch/Wearable (Since both are HMOS devices, their implementation is similar):
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');
}
})
Step 5: Set Up Message Receivers
HMOS Watch/Wearable (Since both are HMOS devices, their implementation is similar):
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');
}
})
Analysis Conclusion
Critical Success Factors
- 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.
- Data Format Conversion: Only binary data can be sent, so it is necessary to convert it into the corresponding format through textEncoder.encodeInto.
- 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.
- 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
Harmony OS Phone Side
import { util } from '@kit.ArkTS';
export class HarmonyOSP2PCommunicationManager {
private authClient: wearEngine.AuthClient;
private deviceClient: wearEngine.DeviceClient;
private p2pClient: wearEngine.P2pClient;
private targetDevice: wearEngine.Device | null = null;
private appParam: any;
constructor(context: Context, remoteBundleName: string, remoteFingerprint: string) {
this.authClient = wearEngine.getAuthClient(context);
this.deviceClient = wearEngine.getDeviceClient(context);
this.p2pClient = wearEngine.getP2pClient(context);
this.appParam = {
remoteApp: {
bundleName: remoteBundleName,
fingerprint: remoteFingerprint
}
};
}
async initializeConnection(): Promise<boolean> {
try {
// Step 1: Request authorization
let request: wearEngine.AuthorizationRequest = {
permissions: [wearEngine.Permission.USER_STATUS]
};
await this.authClient.requestAuthorization(request);
// Step 2: Get connected devices
const deviceList = await this.deviceClient.getConnectedDevices();
if (deviceList.length === 0) {
console.error('No connected devices found');
return false;
}
// Step 3: Find target wearable device
this.targetDevice = deviceList.find(device =>
device.category === wearEngine.DeviceCategory.WATCH
);
if (!this.targetDevice) {
console.error('No wearable device found');
return false;
}
// Step 4: Check remote app installation
const isInstalled = await this.p2pClient.isRemoteAppInstalled(
this.targetDevice.randomId,
this.appParam.remoteApp.bundleName
);
if (!isInstalled) {
console.warn('Remote app not installed, attempting to start...');
await this.startRemoteApp();
}
return true;
} catch (error) {
console.error(`Connection initialization failed: ${error}`);
return false;
}
}
async sendMessage(messageContent: any): Promise<boolean> {
if (!this.targetDevice) {
console.error('No target device available');
return false;
}
try {
const textEncoder: util.TextEncoder = new util.TextEncoder();
const messageStr = JSON.stringify(messageContent);
const message: wearEngine.P2pMessage = {
content: textEncoder.encodeInto(messageStr)
};
await this.p2pClient.sendMessage(
this.targetDevice.randomId,
this.appParam,
message
);
console.info('Message sent successfully');
return true;
} catch (error) {
console.error(`Failed to send message: ${error}`);
return false;
}
}
async registerMessageReceiver(onMessageReceived: (message: string) => void): Promise<boolean> {
if (!this.targetDevice) {
console.error('No target device available');
return false;
}
try {
const callback = (p2pMessage: wearEngine.P2pMessage) => {
const textDecoder = new util.TextDecoder();
const messageText = textDecoder.decodeWithStream(p2pMessage.content);
console.info(`Received message: ${messageText}`);
onMessageReceived(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;
}
}
async startRemoteApp(): Promise<boolean> {
if (!this.targetDevice) {
return false;
}
try {
await this.p2pClient.startRemoteApp(
this.targetDevice.randomId,
this.appParam.remoteApp.bundleName
);
console.info('Remote app started successfully');
return true;
} catch (error) {
console.error(`Failed to start remote app: ${error}`);
return false;
}
}
async checkRemoteAppInstallation(): Promise<boolean> {
if (!this.targetDevice) {
return false;
}
try {
const isInstalled = await this.p2pClient.isRemoteAppInstalled(
this.targetDevice.randomId,
this.appParam.remoteApp.bundleName
);
console.info(`Remote app installation status: ${isInstalled}`);
return isInstalled;
} catch (error) {
console.error(`Failed to check remote app installation: ${error}`);
return false;
}
}
}
Usage Example
typescript// Initialize P2P communication manager
const p2pManager = new HarmonyOSP2PCommunicationManager(
getContext(this),
'com.example.wearableapp', // Remote app bundle name
'REMOTE_APP_FINGERPRINT' // Remote app fingerprint
);
// Initialize connection
const connectionSuccess = await p2pManager.initializeConnection();
if (connectionSuccess) {
// Register message receiver
await p2pManager.registerMessageReceiver((message: string) => {
console.info(`App received: ${message}`);
// Handle received message
});
// Send a message
await p2pManager.sendMessage({ text: 'Hello from phone!', timestamp: Date.now() });
}
Verification Result
Testing Checklist
- Developer Console Permissions: Applied for and approved WearEngine permissions (3-5 days processing time)
- 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
- WearEngine HMOS API Reference: https://developer.huawei.com/consumer/en/doc/harmonyos-references/wearengine_api
- Developer Console: Huawei Developer AGC - Wear Engine Service
Top comments (0)