[Huawei Developers] ask011:
Introduction

In this article, will explain how to develop a security application in Lite wearable. To achieve it we have to use the Wear Engine library. It will give us the solution for communication between Harmony wearable and android smartphone.

Requirements

1) DevEco IDE.

2) Lite wearable watch.

3) Android Smartphone.

4) Huawei developer account.

Integration process

The integration process contains two parts. Android smartphone side and Wear app side.

Android side

Step 1: Create the android project on Android studio.

Step 2: Generate Android signature files.

Step 3: Generate SHA -256 from the keystore generated. Please refer this link. https://developer.huawei.com/consumer/en/codelab/HMSPreparation/index.html#0

Step 4: Navigate to Huawei developer console. Click on Huawei ID (https://developer.huawei.com/consumer/en/console#/productlist/32).

Step 5: Create new product. Add the SHA-256 as the first signed certificate.

Step 6: Click Wear Engine under App services.

Step 7: Click Apply for Wear Engine, agree to the agreement, and the screen for the data permission application is displayed.

Wait for the approval.

Step 8: Open the project-level build gradle of your Android project.

Step 9: Navigateto buildscript > repositories and add the Maven repository configurations.

maven {url 'https://developer.huawei.com/repo/'}

Step 10: Navigate to allprojects > repositories and add the Maven repository address

maven {url 'https://developer.huawei.com/repo/'}

Step 11: Add wear engine sdk on the build gradle.

implementation 'com.huawei.hms:wearengine:{version}'

Step 12: Add the proguard rules in proguard-rules.pro

<p>-keepattributes *Annotation*
-keepattributes Signature
-keepattributes InnerClasses
-keepattributes EnclosingMethod
-keep class com.huawei.wearengine.**{*;}
</p>

Step 13: Add code snippet to Search for the available device on the MainActivity.java

private void searchAvailableDevices() {
DeviceClient deviceClient = HiWear.getDeviceClient(this);
deviceClient.hasAvailableDevices().addOnSuccessListener(new OnSuccessListener<Boolean>() {
@Override
public void onSuccess(Boolean result) {
checkPermissionGranted();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
}
});

Step 14: If the devices are available call for device permission granted or not.

private void checkPermissionGranted() {
AuthClient authClient = HiWear.getAuthClient(this);
authClient.checkPermission(Permission.DEVICE_MANAGER).addOnSuccessListener(new OnSuccessListener<Boolean>() {
@Override
public void onSuccess(Boolean aBoolean) {
if (!aBoolean) {
askPermission();
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
}
});
}

Step 15: If permission is not granted ask for permission.

private void askPermission() {
AuthClient authClient = HiWear.getAuthClient(this);
AuthCallback authCallback = new AuthCallback() {
@Override
public void onOk(Permission[] permissions) {
if (permissions.length != 0) {
checkCurrentConnectedDevice();
}
}

@Override
public void onCancel() {
}
};

authClient.requestPermission(authCallback, Permission.DEVICE_MANAGER)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void successVoid) {
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
}
});
}

Step 16: Get the connected device object for the communication.

private void checkCurrentConnectedDevice() {
final List<Device> deviceList = new ArrayList<>();
DeviceClient deviceClient = HiWear.getDeviceClient(this);
deviceClient.getBondedDevices()
.addOnSuccessListener(new OnSuccessListener<List<Device>>() {
@Override
public void onSuccess(List<Device> devices) {
deviceList.addAll(devices);
if (!deviceList.isEmpty()) {
for (Device device : deviceList) {
if (device.isConnected()) {
connectedDevice = device;
}
}
}
if (connectedDevice != null) {
checkAppInstalledInWatch(connectedDevice);
}
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
//Process logic when the device list fails to be obtained
}
});
}

Step 17: Call pingfunction to check if the Wear app is installed on the watch.

private void checkAppInstalledInWatch(final Device connectedDevice) {
P2pClient p2pClient = HiWear.getP2pClient(this);

String peerPkgName = "com.wearengine.huawei";
p2pClient.setPeerPkgName(peerPkgName);

if (connectedDevice != null && connectedDevice.isConnected()) {
p2pClient.ping(connectedDevice, new PingCallback() {
@Override
public void onPingResult(int errCode) {
}
}).addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void successVoid) {

}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
}
});
}

Step 18: If the ping is success your watch app will launch automatically.

Step 19: Add Password check method on click listener function.

@Override
public void onClick(View view) {
if (view.getId() == R.id.btLogin) {
if (etPin.getText().toString().equals("1234")) {
sendMessageToWatch("Success", connectedDevice);
} else {
sendMessageToWatch("Wrong password", connectedDevice);
}
}
}

Step 20: Send message to the watch.

private void sendMessageToWatch(String message, Device connectedDevice) {
P2pClient p2pClient = HiWear.getP2pClient(this);

String peerPkgName = "com.wearengine.huawei";
p2pClient.setPeerPkgName(peerPkgName);

String peerFingerPrint = "com.wearengine.huawei_BALgPWTbV2CKZ9swMfG1n9ReRlQFqiZrEGWyVQp/6UIgCUsgXn7PojLPA4iatPktya1pLAORwvHgHpv/Z5DfMK8=";
p2pClient.setPeerFingerPrint(peerFingerPrint);

Message.Builder builder = new Message.Builder();
builder.setPayload(message.getBytes(StandardCharsets.UTF_8));
Message sendMessage = builder.build();

SendCallback sendCallback = new SendCallback() {
@Override
public void onSendResult(int resultCode) {
}

@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 aVoid) {
//Related processing logic for your app after the send command runs
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
//Related processing logic for your app after the send command fails to run
}
});
}

Step 21: Generate the p2p fingerprint. Please follow this article - https://forums.developer.huawei.com/forumPortal/en/topic/0202466737940270075

The final code for your android application will be as given below.

package com.phone.wearengine;

import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

import androidx.appcompat.app.AppCompatActivity;

import com.huawei.hmf.tasks.OnFailureListener;
import com.huawei.hmf.tasks.OnSuccessListener;
import com.huawei.wearengine.HiWear;
import com.huawei.wearengine.auth.AuthCallback;
import com.huawei.wearengine.auth.AuthClient;
import com.huawei.wearengine.auth.Permission;
import com.huawei.wearengine.device.Device;
import com.huawei.wearengine.device.DeviceClient;
import com.huawei.wearengine.p2p.Message;
import com.huawei.wearengine.p2p.P2pClient;
import com.huawei.wearengine.p2p.PingCallback;
import com.huawei.wearengine.p2p.SendCallback;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Device connectedDevice;
private EditText etPin;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

initUi();

searchAvailableDevices();
checkCurrentConnectedDevice();
}

private void initUi() {
etPin = findViewById(R.id.etPin);
findViewById(R.id.btLogin).setOnClickListener(this);
}

private void searchAvailableDevices() {
DeviceClient deviceClient = HiWear.getDeviceClient(this);
deviceClient.hasAvailableDevices().addOnSuccessListener(new OnSuccessListener<Boolean>() {
@Override
public void onSuccess(Boolean result) {
checkPermissionGranted();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
}
});
}

private void checkPermissionGranted() {
AuthClient authClient = HiWear.getAuthClient(this);
authClient.checkPermission(Permission.DEVICE_MANAGER).addOnSuccessListener(new OnSuccessListener<Boolean>() {
@Override
public void onSuccess(Boolean aBoolean) {
if (!aBoolean) {
askPermission();
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
}
});
}

private void askPermission() {
AuthClient authClient = HiWear.getAuthClient(this);
AuthCallback authCallback = new AuthCallback() {
@Override
public void onOk(Permission[] permissions) {
if (permissions.length != 0) {
checkCurrentConnectedDevice();
}
}

@Override
public void onCancel() {
}
};

authClient.requestPermission(authCallback, Permission.DEVICE_MANAGER)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void successVoid) {
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
}
});
}

private void checkCurrentConnectedDevice() {
final List<Device> deviceList = new ArrayList<>();
DeviceClient deviceClient = HiWear.getDeviceClient(this);
deviceClient.getBondedDevices()
.addOnSuccessListener(new OnSuccessListener<List<Device>>() {
@Override
public void onSuccess(List<Device> devices) {
deviceList.addAll(devices);
if (!deviceList.isEmpty()) {
for (Device device : deviceList) {
if (device.isConnected()) {
connectedDevice = device;
}
}
}
if (connectedDevice != null) {
checkAppInstalledInWatch(connectedDevice);
}
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
//Process logic when the device list fails to be obtained
}
});

}

private void checkAppInstalledInWatch(final Device connectedDevice) {
P2pClient p2pClient = HiWear.getP2pClient(this);

String peerPkgName = "com.wearengine.huawei";
p2pClient.setPeerPkgName(peerPkgName);

if (connectedDevice != null && connectedDevice.isConnected()) {
p2pClient.ping(connectedDevice, new PingCallback() {
@Override
public void onPingResult(int errCode) {
}
}).addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void successVoid) {

}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
}
});
}
}

private void sendMessageToWatch(String message, Device connectedDevice) {
P2pClient p2pClient = HiWear.getP2pClient(this);

String peerPkgName = "com.wearengine.huawei";
p2pClient.setPeerPkgName(peerPkgName);

String peerFingerPrint = "com.wearengine.huawei_BALgPWTbV2CKZ9swMfG1n9ReRlQFqiZrEG*******";
p2pClient.setPeerFingerPrint(peerFingerPrint);

Message.Builder builder = new Message.Builder();
builder.setPayload(message.getBytes(StandardCharsets.UTF_8));
Message sendMessage = builder.build();

SendCallback sendCallback = new SendCallback() {
@Override
public void onSendResult(int resultCode) {
}

@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 aVoid) {
//Related processing logic for your app after the send command runs
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
//Related processing logic for your app after the send command fails to run
}
});
}
}

@Override
public void onClick(View view) {
if (view.getId() == R.id.btLogin) {
if (etPin.getText().toString().equals("1234")) {
sendMessageToWatch("Success", connectedDevice);
} else {
sendMessageToWatch("Wrong password", connectedDevice);
}
}
}
}

Watch side

Step 1: Create a Lite Wearable project on DevEco studio.

Step 2: Generate the required certificates to run the application. Please refer to this article https://forums.developer.huawei.com/forumPortal/en/topic/0202465210302250053

Step 3: Download and Add the Wear Engine library in the pages folder of the Harmony project. https://developer.huawei.com/consum...ity-Library/litewearable-sdk-0000001053562589

Step 4: Design the UI.

Index.hml

<div class="container">
<text class="title">
{{title}}
</text>
</div>

Index.css

.container {
display: flex;
justify-content: center;
align-items: center;
left: 0px;
top: 0px;
width: 454px;
height: 454px;
background-color: cadetblue;
}
.title {
font-size: 90px;
text-align: center;
width: 300px;
height: 150px;
}

Step 5: Open index.js file and import the wearengine SDK.

import {P2pClient, Message, Builder} from '../wearengine';

Step 6: Add the receiver code snippet on index.js.

onInit() {
var _that = this;
_that.setBrightnessKeepScreenOn();
//Step 1: Obtain the point-to-point communication object
var p2pClient = new P2pClient();
var peerPkgName = "com.phone.wearengine";
var peerFinger = "79C3B257672C32974283E712EF7FEC******";

//Step 2: Set your app package name that needs communications on the phone
p2pClient.setPeerPkgName(peerPkgName);

//Step 3: Set the fingerprint information of the app on the phone. (This API is unavailable currently. In this version, you need to set fingerprint mode in the config.json file in Step 5.)
p2pClient.setPeerFingerPrint(peerFinger);

//Step 4: Receive short messages or files from your app on the phone
//Define the receiver
var flash = this;
var receiver = {
onSuccess: function () {
console.info("Recieved message");
//Process the callback function returned when messages or files fail to be received from the phone during registration.
flash.receiveMessageOK = "Succeeded in receiving the message";
},
onFailure: function () {
console.info("Failed message");

//Registering a listener for the callback method of failing to receive messages or files from phone
flash.receiveMessageOK = "Failed to receive the message";
},
onReceiveMessage: function (data) {
if (data && data.isFileType) {
//Process the file sent by your app on the phone
flash.receiveMessgeOK = "file:" + data.name;
} else {
console.info("Got message - " + data);
//Process the message sent from your app on the phone.
flash.receiveMessageOK = "message:" + data;
_that.title = "" + data;
if (data != "Success") {
vibrator.vibrate({
mode: "long"
})
}
}
},
}
p2pClient.registerReceiver(receiver);
},

PeerFingerPrint on watch side is SHA-256 of Android application (Make sure you have removed the colons)

Step 7: Unregister the receiver on destroy of wearable app.

onDestroy() {
this.p2pClient.unregisterReceiver();
}

Step 8: Add metadata inside of module object of config.json.

"metaData": {
"customizeData": [
{
"name": "supportLists",
"value": "com.phone.wearengine:79C3B257672C32974283E756535C86728BE4DF51E*******",
"extra": ""
}
]
}

The final code for your android application given below.

import {P2pClient, Message, Builder} from '../wearengine';
import brightness from '@system.brightness';
import vibrator from '@system.vibrator';

export default {
data: {
title: 'Enter pin'
},
onInit() {
var _that = this;
_that.setBrightnessKeepScreenOn();
//Step 1: Obtain the point-to-point communication object
var p2pClient = new P2pClient();
var peerPkgName = "com.phone.wearengine";
var peerFinger = "79C3B257672C32974283E756535C*****************";

//Step 2: Set your app package name that needs communications on the phone
p2pClient.setPeerPkgName(peerPkgName);

//Step 3: Set the fingerprint information of the app on the phone. (This API is unavailable currently. In this version, you need to set fingerprint mode in the config.json file in Step 5.)
p2pClient.setPeerFingerPrint(peerFinger);

//Step 4: Receive short messages or files from your app on the phone
//Define the receiver
var flash = this;
var receiver = {
onSuccess: function () {
console.info("Recieved message");
//Process the callback function returned when messages or files fail to be received from the phone during registration.
flash.receiveMessageOK = "Succeeded in receiving the message";
},
onFailure: function () {
console.info("Failed message");

//Registering a listener for the callback method of failing to receive messages or files from phone
flash.receiveMessageOK = "Failed to receive the message";
},
onReceiveMessage: function (data) {
if (data && data.isFileType) {
//Process the file sent by your app on the phone
flash.receiveMessgeOK = "file:" + data.name;
} else {
console.info("Got message - " + data);
//Process the message sent from your app on the phone.
flash.receiveMessageOK = "message:" + data;
_that.title = "" + data;
if (data != "Success") {
vibrator.vibrate({
mode: "long"
})
}
}
},
}
p2pClient.registerReceiver(receiver);
},
setBrightnessKeepScreenOn: function () {
brightness.setKeepScreenOn({
keepScreenOn: true,
success: function () {
console.log("handling set keep screen on success")
},
fail: function (data, code) {
console.log("handling set keep screen on fail, code:" + code);
}
});
},
onDestroy() {
// FeatureAbility.unsubscribeMsg();
this.p2pClient.unregisterReceiver();
}
}

Results

Tips & Tricks

Make sure you are generated the SHA - 256 fingerprint of proper keystore.

Follow the P2P generation steps properly.

Conclusion

In this article, we are learned how to develop a security app using Wear Engine. The wear engine will allow us to communicate between the Android application and the Harmony Wear application.

Reference

Harmony Official document - https://developer.harmonyos.com/en/docs/documentation/doc-guides/harmonyos-overview-0000000000011903

Wear Engine documentation - https://developer.huawei.com/consumer/en/doc/development/connectivity-Guides/service-introduction-0000001050978399

Certificate generation article - https://forums.developer.huawei.com/forumPortal/en/topic/0202465210302250053

P2P generation article - https://forums.developer.huawei.com/forumPortal/en/topic/0202466737940270075