The Ultimate Scanning App From Huawei - Huawei Developers

Have you ever wanted to be able to scan and create 13+ different types of barcodes from your app? Hopefully you have, otherwise I'm not sure why you're reading this. If you do, then Huawei has an SDK for you: Scan Kit.
Scan Kit allows you to scan and generate various different one-dimensional and two-dimensional barcodes with ease, and you don't even need a Huawei device to use it.
Interested? No? Well, get interested. Now? Good. Let's get started.
Preparation
First up, make sure you have a Huawei Developer Account. This process can take a couple days, and you'll need one to use this SDK, so be sure to start that as soon as possible. You can sign up at https://developer.huawei.com.
Next, you'll want to obtain the SHA-256 representation of your app's signing key. If you don't have a signing key yet, be sure to create one before continuing. To obtain your signing key's SHA-256, you'll need to use Keytool which is part of the JDK installation. Keytool is a command-line program. If you're on Windows, open CMD. If you're on Linux, open Terminal.
On Windows, you'll need to "cd" into the directory containing the Keytool executable. For example, if you have JDK 1.8 v231 installed, Keytool will be located at the following path:
Code:
C:\Program Files\Java\jdk1.8.0_231\bin\
Once you find the directory, "cd" into it:
Code:
C: #Make sure you're in the right drive
cd C:\Program Files\Java\jdk1.8.0_231\bin\
Next, you need to find the location of your keystore. Using Android's debug keystore as an example, where the Android SDK is hosted on the "E:" drive in Windows, the path will be as follows:
Code:
E:\AndroidSDK\.android\debug.keystore
(Keytool also supports JKS-format keystores.)
Now you're ready to run the command. On Windows, it'll look something like this:
Code:
keytool -list -v -keystore E:\AndroidSDK\.android\debug.keystore
On Linux, the command should be similar, just using UNIX-style paths instead.
Enter the keystore password, and the key name (if applicable), and you'll be presented with something similar to the following:
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Make note of the SHA256 field.
SDK Setup
Now we're ready to add the Scan Kit SDK to your Android Studio project. Go to your Huawei Developer Console and click the HUAWEI AppGallery tile. Agree to the terms of use if prompted.
Click the "My projects" tile here. If you haven't already added your project to the AppGallery, add it now. You'll be asked for a project name. Make it something descriptive so you know what it's for.
Now, you should be on a screen that looks something like the following:
Click the "Add app" button. Here, you'll need to provide some details about your app, like its name and package name.
Once you click OK, some SDK setup instructions will be displayed. Follow them to get everything added to your project.
You'll also need to add one of the following to the "dependencies" section of your app-level build.gradle file:
Code:
implementation 'com.huawei.hms:scan:1.2.0.301'
implementation 'com.huawei.hms:scanplus:1.2.0.301'
The difference between these dependencies is fairly simple. The basic Scan Kit SDK is only about 0.8MB in size, while the Scan Kit Plus SDK is about 3.3MB. The basic SDK will function identically to the Plus SDK on Huawei devices. On non-Huawei devices, you'll lose the enhanced recognition capabilities with the basic SDK.
If your app has size restrictions, and you only need basic QR code recognition, then the basic SDK is the best choice. Otherwise, pick the Plus SDK.
If you ever need to come back to these instructions, you can always click the "Add SDK" button after "App information" on the "Project setting" page.
Now you should be back on the "Project setting" page. Find the "SHA-256 certificate fingerprint" field under "App information," click the "+" button, and paste your SHA-256.
Now, if you're using obfuscation in your app, you'll need to whitelist a few things for HMS to work properly.
For ProGuard:
Code:
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.hianalytics.android.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
For AndResGuard:
Code:
"R.string.hms*",
"R.string.agc*",
"R.string.connect_server_fail_prompt_toast",
"R.string.getting_message_fail_prompt_toast",
"R.string.no_available_network_prompt_toast",
"R.string.third_app_*",
"R.string.upsdk_*",
"R.layout.hms*",
"R.layout.upsdk_*",
"R.drawable.upsdk*",
"R.color.upsdk*",
"R.dimen.upsdk*",
"R.style.upsdk*
That's it! The Scan Kit SDK should now be available in your project.
Basic Usage
In order to properly use Scan Kit, you'll need to declare some permissions in your app:
XML:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
These are both dangerous-level permissions, so make sure you request access to them at runtime on Marshmallow and later.
You should also declare a couple required device features, to make sure distribution platforms can hide your app on incompatible devices:
XML:
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
Now that you've got the permissions and features declared, it's time to start scanning. There are four modes you can use: Default View, Customized View, Bitmap, and MultiProcessor.
Default View
The Default View is the quickest way to get set up and running. Scan Kit provides the UI and does all the scanning work for you. This mode is able to scan barcodes live through the camera viewfinder, or by scanning existing images.
The first thing you'll need to do to use this is to declare the Scan Kit's scanner Activity in your Manifest:
XML:
<activity android:name="com.huawei.hms.hmsscankit.ScanKitActivity" />
Next, simply call the appropriate method to start the Activity. This must be done from an Activity context, since it makes use of Android's onActivityResult() API.
Code:
//The options here are optional. You can simply pass null
//to the startScan() method below.
//This is useful if you're only looking to scan certain
//types of codes. Scan Kit currently supports 13. You can
//see the list here: https://developer.huawei.com/consumer/en/doc/HMSCore-Guides-V5/barcode-formats-supported-0000001050043981-V5
val options = HmsScanAnalyzerOptions.Creator()
.setHmsScanTypes(
HmsScan.QRCODE_SCAN_TYPE,
HmsScan.DATAMATRIX_SCAN_TYPE
)
.create()
ScanUtil.startScan(activity, REQUEST_CODE, options)
Now you just need to handle the result:
Code:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode != Activity.RESULT_OK || data == null) {
//Scanning wasn't successful. Nothing to handle.
return
}
if (requestCode == REQUEST_CODE) {
//Scan succeeded. Let's get the data.
val hmsScan = data.getParcelableExtra<HmsScan>(ScanUtil.RESULT)
if (hmsScan != null) {
//Handle appropriately.
}
}
}
We'll talk more about handling the result later.
Customized View
Customized View is similar to Default View in that Scan Kit will handle the scanning logic for you. The difference is that this mode lets you create your own UI. You're also limited to using the live viewfinder.
The following code should be placed inside your Activity's onCreate() method:
Code:
override fun onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_scan)
//A ViewGroup to hold the scanning View that HMS will create
val container = findViewById<FrameLayout>(R.id.scanning_container)
//The position/size of the scanning area inside the scanning
//View itself. This is optional.
val scanBounds = Rect()
//The scanning View itself.
val scanView = RemoteView.Builder()
.setContext(this)
.setBoundingBox(scanBounds) //optional
.setFormat(HmsScan.QR_SCAN_TYPE) //optional, accepts a vararg of formats
.build()
//Initialize the scanning View.
scanView.onCreate(savedInstanceState)
container.addView(scanView)
scanView.setOnResultCallback { result ->
//`result` is an Array<HmsScan>
//Handle accordingly.
}
}
We'll talk about how to handle the HmsScan object later.
In a real application, the "scanView" variable should be a global variable. It's lifecycle-aware, so it has all the lifecycle methods, which you should probably call:
Code:
override fun onStart() {
super.onStart()
scanView.onStart()
}
//etc
Bitmap
This mode is useful if you have a Bitmap and you want to decode it. You can get that Bitmap however you want. All that matters is that you have one.
The example below shows how to obtain a Bitmap either from a camera capture frame or from an existing image in internal storage, and how to pass that Bitmap to Scan Kit for processing.
Code:
val img = YuvImage(
//A byte array representation of an image.
data,
//Depends on your image type: https://developer.android.com/reference/android/graphics/ImageFormat
ImageFormat.NV21,
//The width of the image data.
width,
//The height of the image data.
height
)
val stream = ByteArrayOutputStream()
//Copy the data to an output stream.
img.compressToJpeg(
//Size of the JPEG, in a Rect representation.
Rect(0, 0, width, height),
//Quality.
100,
//Output stream.
stream
)
//Create a Bitmap
val bmp = BitmapFactory.decodeByteArray(
stream.asByteArray(),
0,
stream.asByteArray().size
)
//If you want to use a pre-existing image, just obtain
//a Bitmap for that. This example would be placed in
//onActivityResult() after using ACTION_GET_CONTENT for an image.
val bmp = MediaStore.Images.Media.getBitmap(contentResolver, data.data)
//Set up the options.
val options = HmsScanAnalyzerOptions.Creator()
//Scan types are optional.
.setHmsScanTypes(
HmsScan.QRCODE_SCAN_TYPE,
HmsScan.DATAMATRIX_SCAN_TYPE
)
//If you're retrieving a Bitmap from an existing photo,
//set this to `true`.
.setPhotoMode(false)
.create()
//Send the scanning request and get the result.
val scans: Array<HmsScan> = ScanUtil.decodeWithBitmap(context, bmp, options)
if (!scans.isNullOrEmpty()) {
//Scanning was successful.
//Check individual scanning results.
scans.forEach {
//Handle.
//If zoomValue != 1.0, make sure you update
//the focal length of your camera interface,
//if you're using a camera. See Huawei's
//documentation for details on this.
//https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/android-bitmap-camera-0000001050042014
val zoomValue = it.zoomValue
}
}
We'll go over how to handle the HmsScan later on.
MultiProccessor
The MultiProcessor mode supports both existing images and using a viewfinder. It can take image frames and analyze them using machine learning to simultaneously detect multiple barcodes, along with other objects, like faces.
There are two ways to implement this mode: synchronously, and asychronously.
Here's an example showing how to implement it synchronously.
Code:
//Create the options (optional).
val options = HmsScanAnalyzerOptions.Creator()
.setHmsScanTypes(
HmsScan.QRCODE_SCAN_TYPE,
HmsScan.DATAMATRIX_SCAN_TYPE
)
.create()
//Set up the barcode detector.
val barcodeDetector = HmsScanAnalyzer(options /* or null */)
//You'll need some sort of Bitmap reference.
val bmp = /* However you want to obtain it */
//Convert that Bitmap to an MLFrame.
val frame = MLFrame.fromBitmap(bmp)
//Analyze and handle result(s).
val results: SparseArray<HmsScan> = barcodeDetector.analyseFrame(frame)
results.forEach {
//Handle accordingly.
}
To analyze asynchronously, just change the method called on "barcodeDetector":
Code:
barcodeDetector.analyzInAsyn(frame)
.addOnSuccessListener { scans ->
//`scans` is a List<HmsScan>
scans?.forEach {
//Handle accordingly.
}
}
.addOnFailureListener { error ->
//Scanning failed. Check Exception.
}
Parsing Barcodes
It's finally time to talk about parsing the barcodes! Yay!
The HmsScan object has a bunch of methods you can use to retrieve information about barcodes scanned by each method.
Code:
val scan: HmsScan = /* some HmsScan instance */
//The value contained in the code. For instance,
//if it's a QR code for an SMS, this value will be
//something like: "smsto:1234567890:Hi!".
val originalValue = scan.originalValue
//The type of code. For example, SMS_FORM, URL_FORM,
//or WIFI_CONNTENT_INFO_FORM. You can find all the forms
//here: https://developer.huawei.com/consumer/en/doc/development/HMSCore-References-V5/scan-hms-scan4-0000001050167739-V5.
val scanTypeForm = scan.scanTypeForm
//If it's a call or SMS, you can retrieve the
//destination phone number. This will be something
//like "1234567890".
val destPhoneNumber = scan.destPhoneNumber
//If it's an SMS, you can retrieve the message
//content. This will be something like "Hi!".
val smsContent = scan.smsContent
There are plenty more methods in the HmsScan class to help you parse various barcodes. You can see them all in Huawei's API reference.
Barcode Generation
Finally, let's talk about how to make your own barcodes using Scan Kit. This example will show you how to make a QR code, although you should be able to create any of the formats supported by Scan Kit.
Code:
//The code's content.
val content = "Some Content"
//Can be any supported type.
val type = HmsScan.QRCODE_SCAN_TYPE
//Output dimensions.
val width = 400
val height = 400
//Create the options.
val options = HmsBuildBitmapOption.Creator()
//The background of the barcode image. White is the default.
.setBitmapBackgroundColor(Color.RED)
//The color of the barcode itself. Black is the default
.setBitmapColor(Color.BLUE)
//Margins around the barcode. 1 is the default.
.setBitmapMargin(3)
.create()
try {
//Build the output Bitmap.
val output = ScanUtil.buildBitmap(content, type, width, height, options)
//Save it to internal storage, upload it somewhere, etc.
} catch (e: WriterException) {
//Creation failed. This can happen if one of the arguments for `buildBitmap()` is invalid.
}
Conclusion
And that's it!
Scan Kit is a powerful SDK that doesn't even require a Huawei device to work. Hopefully, this guide helped you get up and running. For more details on implementation, along with the API reference, be sure to check out Huawei's full documentation.

Related

Getting Started with Huawei's Safety Detect SDK

Today we're going to go through getting started with Huawei's Safety Detect SDK. We'll talk about how to get set up, as well as some basic examples of how to use it.
What is Huawei Safety Detect?
Safety Detect builds robust security capabilities, including system integrity check (SysIntegrity), app security check (AppsCheck), malicious URL check (URLCheck), fake user detection (UserDetect), and malicious Wi-Fi detection (WifiDetect), into your app, effectively protecting it against security threats.
Preparation
First up, make sure you have a Huawei Developer Account. This process can take a couple days, and you'll need one to use this SDK, so be sure to start that as soon as possible. You can sign up at https://developer.huawei.com.
Next, you'll want to obtain the SHA-256 representation of your app's signing key. If you don't have a signing key yet, be sure to create one before continuing. To obtain your signing key's SHA-256, you'll need to use Keytool which is part of the JDK installation. Keytool is a command-line program. If you're on Windows, open CMD. If you're on Linux, open Terminal.
On Windows, you'll need to "cd" into the directory containing the Keytool executable. For example, if you have JDK 1.8 v231 installed, Keytool will be located at the following path:
Code:
C:\Program Files\Java\jdk1.8.0_231\bin\
Once you find the directory, "cd" into it:
Code:
C: #Make sure you're in the right drive
cd C:\Program Files\Java\jdk1.8.0_231\bin\
Next, you need to find the location of your keystore. Using Android's debug keystore as an example, where the Android SDK is hosted on the "E:" drive in Windows, the path will be as follows:
Code:
E:\AndroidSDK\.android\debug.keystore
(Keytool also supports JKS-format keystores.)
Now you're ready to run the command. On Windows, it'll look something like this:
Code:
keytool -list -v -keystore E:\AndroidSDK\.android\debug.keystore
On Linux, the command should be similar, just using UNIX-style paths instead.
Enter the keystore password, and the key name (if applicable), and you'll be presented with something similar to the following:
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Make note of the SHA256 field.
SDK Setup
Now we're ready to add the Safety Detect SDK to your Android Studio project. Go to your Huawei Developer Console and click the HUAWEI AppGallery tile. Agree to the terms of use if prompted.
Click the "My projects" tile here. If you haven't already added your project to the AppGallery, add it now. You'll be asked for a project name. Make it something descriptive so you know what it's for.
Now, you should be on a screen that looks something like the following:
Click the "Add app" button. Here, you'll need to provide some details about your app, like its name and package name.
Once you click OK, some SDK setup instructions will be displayed. Follow them to get everything added to your project. You'll also need to add the following to the "dependencies" section of your app-level build.gradle file:
Code:
implementation 'com.huawei.hms:safetydetect:4.0.3.300'
If you ever need to come back to these instructions, you can always click the "Add SDK" button after "App information" on the "Project setting" page.
Now you should be back on the "Project setting" page. Find the "SHA-256 certificate fingerprint" field under "App information," click the "+" button, and paste your SHA-256.
Now, go to the Manage APIs tab on the "Project setting" page. Scroll down until you find "Safety Detect" and make sure it's enabled.
Now, if you're using obfuscation in your app, you'll need to whitelist a few things for HMS to work properly.
For ProGuard:
Code:
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.hianalytics.android.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
For AndResGuard:
Code:
"R.string.hms*",
"R.string.agc*",
"R.string.connect_server_fail_prompt_toast",
"R.string.getting_message_fail_prompt_toast",
"R.string.no_available_network_prompt_toast",
"R.string.third_app_*",
"R.string.upsdk_*",
"R.layout.hms*",
"R.layout.upsdk_*",
"R.drawable.upsdk*",
"R.color.upsdk*",
"R.dimen.upsdk*",
"R.style.upsdk*
That's it! The Safety Detect SDK should now be available in your project.
Basic Usage
Now that the SDK is set up, it's time to actually use it. Safety Detect currently has 5 APIs you can use: SysIntegrity, AppsCheck, URLCheck, UserDetect, and WifiDetect.
The first thing you'll want to do when using any of these APIs is to check whether HMS is actually available:
Code:
if (HuaweiApiAvailability.getInstance().isHuaweiMobileServicesAvailable(context) == ConnectionResult.SUCCESS) {
//HMS is available
} else {
//HMS isn't available. Act accordingly
}
Without HMS, these APIs won't work. Prompt the user to update/install HMS, or simply silently fail, depending on your needs.
SysIntegrity
The SysIntegrity API is similar to Google's SafetyNet. You can use it to check if the current device is insecure (e.g. is rooted). If your app relies heavily on running in a secure environment, you can use this check and refuse to run if it fails.
To use SysIntegrity, you need a few things: a nonce value, your app ID, and an active internet connection. The nonce value should be a secret, needs to be at least 16 bytes long, and can only be used once. It'll be contained in the SysIntegrity check result, so you can verify that the result is genuine.
You can find your app ID under the "App information" section on the "Project Setting" page.
Here's a quick example in Kotlin of how to set up the integrity check request:
Code:
fun checkSysIntegrity() {
val client = SafetyDetect.getClient(context)
//Ideally, you'd use a better nonce generation method, either from your own server
//or some other secure environment.
val nonce = "NONCE_${System.currentTimeMillis()}".toByteArray()
//You can find your APP_ID under "App information" in your project's settings on the AppGallery Developer Console.
val task = client.sysIntegrity(nonce, "APP_ID")
task.addOnSuccessListener {
val result = it.result
//Process the result. It will be in the JWS (JSON Web Signature) format, containing a header, payload, and signature.
//The header contains a certificate chain that should be verified against the HUAWEI CGB Root CA.
//Make sure the domain name of the leaf certificate in the certificate chain is `sysintegrity.platform.hicloud.com`.
//Verify the signature.
//Next, check the payload for the nonce and result. The payload format is something like the following:
/*
{
"advice":"RESTORE_TO_FACTORY_ROM",
"apkCertificateDigestSha256":[
"yT5JtXRgeIgXssx1gQTsMA9GzM9ER4xAgCsCC69Fz3I="
],
"apkDigestSha256":"6Ihk8Wcv1MLm0O5KUCEVYCI/0KWzAHn9DyN38R3WYu8=",
"apkPackageName":"com.huawei.hms.safetydetectsample",
"basicIntegrity":false,
"nonce":"R2Rra24fVm5xa2Mg",
"timestampMs":1571708929141
}
*/
//If basicIntegrity is false, then the check failed and you should handle it appropriately.
//You can use the following library to parse the JWS string: https://mvnrepository.com/artifact/com.nimbusds/nimbus-jose-jwt
}
task.addOnFailureListener {
//The request failed. If `it is ApiException`, you might be able to get more details about why the failure occurred.
//Note that this doesn't imply that the device has failed an integrity check. It merely means the check itself has failed.
//You can choose to retry, or simply ignore the error.
}
}
Put that code in a helper Class, and call it as needed. It is an asynchronous API, so make sure you account for that.
AppsCheck
The functionality of AppsCheck is pretty simple. It'll return a list of apps installed on the current device that are potentially malicious. You can use the result to decide on whether or not you want to restrict features, or prevent your app from running.
To get you up and running, a basic example is provided below. You can use it as the base for your implementation.
Code:
fun checkApps() {
val client = SafetyDetect.getClient(context)
val task = client.maliciousAppsList
task.addOnSuccessListener {
if (it.rtnCode == CommonCode.OK) {
//The request truly succeeded
//An ArrayList<MaliciousAppsData>
val apps = it.maliciousAppsList
if (apps.isEmpty()) {
//No malicious apps were found
} else {
//HMS found at least one potentially malicious app
apps.forEach {
//The package name of the potentially malicious app
val packageName = it.apkPackageName
//The SHA-256 of the potentially malicious app
val sha256 = it.apkSha256
//The category of the potentially malicious app
//Constants are defined in the AppsCheckConstants class
//Currently, this can return either VIRUS_LEVEL_RISK (1)
//or VIRUS_LEVEL_VIRUS (2)
val category = it.apkCategory
}
}
} else {
//Something went wrong with the request
//Use `it.getErrorReason()` to see why
}
}
task.addOnFailureListener {
//A communication error occurred.
//If `it is ApiException`, you may be able to get more details about why
//the failure occurred.
}
}
URLCheck
If your app allows users to visit URLs you aren't able to verify (forum app, social media app, etc), URLCheck can help you screen links that users click. If the URL is detected as malicious, you can prompt the user.
If you want to implement this for yourself, start with the example code below:
Code:
fun checkUrl(url: String) {
val client = SafetyDetect.getClient(context)
//Ensure the URLCheck API is initialized
val initTask = client.initUrlCheck()
initTask.addOnSuccessListener {
//Initialization was successful.
//Make sure to remove any query parameters from the URL before checking it.
//For example, if the full URL is https://google.com/home?someKey=true, you need to pass
//https://google.com/home.
//...
//UrlCheckThreat can either be MALWARE or PHISHING.
//Each category is fairly self-explanatory.
//The threat argument is a vararg, so you can pass one or both.
//...
//You can find your APP_ID under "App information" in your project's settings on the AppGallery Developer Console.
val task = client.urlCheck(url, "APP_ID", UrlCheckThreat.MALWARE, UrlCheckThreat.PHISHING)
task.addOnSuccessListener {
//API call succeeded.
if (it.urlCheckResponse.isEmpty()) {
//URL is safe, continue
} else {
//URL matches either MALWARE or PHISHING category or both. Notify user or refuse to visit
//as is appropriate.
//Get the first threat type. Will match one of the UrlCheckThreat values you pass to
//the urlCheck() method.
val type = it.urlCheckResponse[0].urlCheckResult
}
}
task.addOnFailureListener {
//A communication error occurred.
//If `it is ApiException`, you may be able to get more details about why
//the failure occurred.
}
}
initTask.addOnFailureListener {
//Initialization failed.
}
}
UserDetect
UserDetect is essentially a realtime Captcha service. If there are parts of your app that you don't want to be used by bots (i.e. a clicker game), you can trigger a detection request to determine if the user is a bot or a person.
This one is a bit more complicated to implement, as it requires that you use HMS' cloud API to make the final request (i.e. a web server).
An example implementation in Kotlin is shown below:
Code:
fun checkUser() {
val client = SafetyDetect.getClient(context)
val initTask = client.initUserDetect()
initTask.addOnSuccessListener {
//Initialization was successful
//You can find your APP_ID under "App information" in your project's settings on the AppGallery Developer Console.
val task = client.userDetection("APP_ID")
task.addOnSuccessListener {
val responseToken = it.responseToken
if (responseToken.isNotEmpty()) {
//Pass this token to your server, and have it call HMS' cloud API to do the actual verification.
}
}
task.addOnFailureListener {
//A communication error occurred.
//If `it is ApiException`, you may be able to get more details about why
//the failure occurred.
}
}
initTask.addOnFailureListener {
//Initialization failed.
}
}
WifiDetect
If your app relies on a secure WiFi connection, this API may be helpful to you. You can use it to check whether the user's WiFI connection is actually secure.
Here's a quick example stub in Kotlin:
Code:
fun checkWifi() {
val client = SafetyDetect.getClient(context)
val task = client.wifiDetectStatus
task.addOnSuccessListener {
//The status will either be 0, 1, or 2, depending on the WiFi network state.
//0 means WiFi is disconnected.
//1 means WiFi is secure.
//2 means WiFi is insecure.
val status = it.wifiDetectStatus
}
task.addOnFailureListener {
//A communication error occurred.
//If `it is ApiException`, you may be able to get more details about why
//the failure occurred.
}
}
Conclusion
That's all for the SafetyDetect SDK! If you're using HMS, or you're planning to use HMS, and you want to make sure your app is properly secured, the various included APIs are sure to be helpful.
You can find more details, including the full API reference for the Safety Detect SDK, on Huawei's developer website.

How to Implement the FIDO SDK

If you're developing an app to work on Huawei phones, and you have features that need to be protected by authentication, then Huawei's FIDO SDK might be useful for you.
The FIDO SDK helps you present and verify authentication prompts to your app's users, and supports all sorts of verification methods, including things like NFC Tag and fingerprint scanning. If FIDO is something you want to implement, keep reading, because we're going to talk about how to get set up.
Preparation
First up, make sure you have a Huawei Developer Account. This process can take a couple days, and you'll need one to use this SDK, so be sure to start that as soon as possible. You can sign up at https://developer.huawei.com.
Next, you'll want to obtain the SHA-256 representation of your app's signing key. If you don't have a signing key yet, be sure to create one before continuing. To obtain your signing key's SHA-256, you'll need to use Keytool which is part of the JDK installation. Keytool is a command-line program. If you're on Windows, open CMD. If you're on Linux, open Terminal.
On Windows, you'll need to "cd" into the directory containing the Keytool executable. For example, if you have JDK 1.8 v231 installed, Keytool will be located at the following path:
Code:
C:\Program Files\Java\jdk1.8.0_231\bin\
Once you find the directory, "cd" into it:
Code:
C: #Make sure you're in the right drive
cd C:\Program Files\Java\jdk1.8.0_231\bin\
Next, you need to find the location of your keystore. Using Android's debug keystore as an example, where the Android SDK is hosted on the "E:" drive in Windows, the path will be as follows:
Code:
E:\AndroidSDK\.android\debug.keystore
(Keytool also supports JKS-format keystores.)
Now you're ready to run the command. On Windows, it'll look something like this:
Code:
keytool -list -v -keystore E:\AndroidSDK\.android\debug.keystore
On Linux, the command should be similar, just using UNIX-style paths instead.
Enter the keystore password, and the key name (if applicable), and you'll be presented with something similar to the following:
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Make note of the SHA256 field.
SDK Setup
Now we're ready to add the Safety Detect SDK to your Android Studio project. Go to your Huawei Developer Console and click the HUAWEI AppGallery tile. Agree to the terms of use if prompted.
Click the "My projects" tile here. If you haven't already added your project to the AppGallery, add it now. You'll be asked for a project name. Make it something descriptive so you know what it's for.
Now, you should be on a screen that looks something like the following:
Click the "Add app" button. Here, you'll need to provide some details about your app, like its name and package name.
Once you click OK, some SDK setup instructions will be displayed. Follow them to get everything added to your project. You'll also need to add the following to the "dependencies" section of your app-level build.gradle file:
Code:
implementation 'com.huawei.hms:fido-fido2:4.0.3.300'
If you want to use biometric authentication, include one of the following as well, depending on if you're using AndroidX or not:
Code:
implementation 'com.huawei.hms:fido-bioauthn-androidx:4.0.3.300'
implementation 'com.huawei.hms:fido-bioauthn:4.0.3.300'
If you ever need to come back to these instructions, you can always click the "Add SDK" button after "App information" on the "Project setting" page.
Now you should be back on the "Project setting" page. Find the "SHA-256 certificate fingerprint" field under "App information," click the "+" button, and paste your SHA-256.
Now, go to the Manage APIs tab on the "Project setting" page. Scroll down until you find "FIDO" and make sure it's enabled.
Now, if you're using obfuscation in your app, you'll need to whitelist a few things for HMS to work properly.
For ProGuard:
Code:
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.hianalytics.android.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
For AndResGuard:
Code:
"R.string.hms*",
"R.string.agc*",
"R.string.connect_server_fail_prompt_toast",
"R.string.getting_message_fail_prompt_toast",
"R.string.no_available_network_prompt_toast",
"R.string.third_app_*",
"R.string.upsdk_*",
"R.layout.hms*",
"R.layout.upsdk_*",
"R.drawable.upsdk*",
"R.color.upsdk*",
"R.dimen.upsdk*",
"R.style.upsdk*
That's it! The FIDO SDK should now be available in your project.
Basic Usage
Now that FIDO's all set up, it's time to start using it. We're not going to be talking about the server-side stuff here, just the client-size. If you need help setting up a FIDO server, be sure to check out the instructions for whichever provider you're using.
FIDO2
The following code is a quick sample for getting FIDO2 registration and authentication requests working.
Code:
class FIDO2Example : AppCompatActivity() {
private val client by lazy { Fido2.getFido2Client(this) }
//https://www.w3.org/TR/webauthn/#credential-id
//Ideally this should be persisted somewhere.
private var credentialId: ByteArray? = null
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode != Activity.RESULT_OK) {
//User may have canceled registration or authentication,
//or the related process failed. We shouldn't continue.
return
}
when (requestCode) {
Fido2Client.REGISTRATION_REQUEST -> {
//Get the response data
val response = client.getFido2RegistrationResponse(data)
if (response.isSuccess) {
//Registration was successful. Notify user and store data.
//Save the credential ID
credentialId = response.authenticatorAttestationResponse.credentialId
} else {
//Registration failed. The response data should contain information on why.
}
}
Fido2Client.AUTHENTICATION_REQUEST -> {
//Get the response data
val response = client.getFido2AuthenticationResponse(data)
if (response.isSuccess) {
//Authentication was successful. Allow the user into whatever secure place
//this was protecting.
} else {
//Authentication failed. The response data should have information on why.
}
}
}
}
//Initiate the user registration process
fun doRegistration() {
if (!client.isSupported) {
//Can't use FIDO2 on this device. Tell the user and return.
return
}
val request = createFido2RegistrationRequest()
client.getRegistrationIntent(request, NativeFido2RegistrationOptions.DEFAULT_OPTIONS,
object : Fido2IntentCallback {
override fun onSuccess(intent: Fido2Intent) {
//The Intent was successfully created. Run it.
//This will start an Activity for a result, so we're going to handle the rest of it
//in onActivityResult(). You can use your own request code for this if you want.
intent.launchFido2Activity([email protected], Fido2Client.REGISTRATION_REQUEST)
}
override fun onFailure(errorCode: Int, errorMsg: CharSequence) {
//Unable to get the registration Intent.
//Notify user and/or try again.
}
}
)
}
//Initiate the user authentication process
fun doAuthentication() {
if (credentialId == null) {
//User isn't registered. Tell them to do so.
return
}
if (!client.isSupported) {
//Can't use FIDO2 on this device. Tell the user and return.
return
}
val request = createFido2AuthenticationRequest()
client.getAuthenticationIntent(request, NativeFido2AuthenticationOptions.DEFAULT_OPTIONS,
object : Fido2IntentCallback {
override fun onSuccess(intent: Fido2Intent) {
//The Intent was successfully created. Run it.
//This will start an Activity for a result, so we're going to handle the rest of it
//in onActivityResult(). You can use your own request code for this if you want.
intent.launchFido2Activity([email protected], Fido2Client.AUTHENTICATION_REQUEST)
}
override fun onFailure(errorCode: Int, errorMsg: CharSequence) {
//Unable to get the authentication Intent.
//Notify user and/or try again.
}
}
)
}
//Create the request for registering a new user.
fun createFido2RegistrationRequest(): Fido2RegistrationRequest {
//A 16-byte challenge key, usually obtained fro the FIDO server itself
val challenge = SecureRandom.getSeed(16)
val builder = PublicKeyCredentialCreationOptions.Builder()
//More details on a Relying Party: https://www.w3.org/TR/webauthn/#webauthn-relying-party
builder.setRp(PublicKeyCredentialRpEntity("RELYING_PARTY_ID", "RELYING_PARTY_ID", null))
//USER is the user being authenticated
builder.setUser(PublicKeyCredentialUserEntity("USER", "USER".toByteArray()))
builder.setChallenge(challenge)
//Can also be INDIRECT or NONE
builder.setAttestation(AttestationConveyancePreference.DIRECT)
//An attachment, whether to require a resident key (Boolean), a user verification requirement.
//More details on this here: https://www.w3.org/TR/webauthn/#dictdef-authenticatorselectioncriteria
builder.setAuthenticatorSelection(AuthenticatorSelectionCriteria(null, null, null))
//A list of credential types that the client would like to be created, in order
//Of most-preferred to least-preferred. The server will attempt to create the most-
//preferred one first, stepping down the list if it needs to.
builder.setPubKeyCredParams(arrayListOf(
PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, Algorithm.ES256),
PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, Algorithm.RS256)
))
//How long until this registration request should time out.
builder.setTimeoutSeconds(60L)
if (credentialId != null) {
builder.setExcludeList(arrayListOf(
PublicKeyCredentialDescriptor(PublicKeyCredentialType.PUBLIC_KEY, credentialId)
))
}
//If your client supports token binding, make sure to pass the
//proper TokenBinding instance as the second parameter here.
//https://www.w3.org/TR/webauthn/#dictdef-tokenbinding
return Fido2RegistrationRequest(builder.build(), null)
}
//Create the request for authenticating a current user.
fun createFido2AuthenticationRequest(): Fido2AuthenticationRequest {
//A 16-byte challenge key, usually obtained fro the FIDO server itself
val challenge = SecureRandom.getSeed(16)
val allowList = arrayListOf(
PublicKeyCredentialDescriptor(PublicKeyCredentialType.PUBLIC_KEY, credentialId)
)
val builder = PublicKeyCredentialRequestOptions.Builder()
//More details on a Relying Party: https://www.w3.org/TR/webauthn/#webauthn-relying-party
builder.setRpId("RELYING_PARTY_ID")
builder.setChallenge(challenge)
builder.setAllowList(allowList)
builder.setTimeoutSeconds(60L)
//If your client supports token binding, make sure to pass the
//proper TokenBinding instance as the second parameter here.
//https://www.w3.org/TR/webauthn/#dictdef-tokenbinding
return Fido2AuthenticationRequest(builder.build(), null)
}
}
BioAuthn
BioAuthn is the part of the FIDO SDK that lets you authenticate through biometrics, such as fingerprints and facial recognition.
Here's an example showing a quick implementation. This example is for the AndroidX library, but the implementation is similar for the non-AndroidX version.
Code:
class BioAuthnExample : AppCompatActivity() {
private val bioAuthnManager by lazy { BioAuthnManager(this) }
private val faceManager by lazy { FaceManager(this) }
private val authCallback = object : BioAuthnCallback() {
override fun onAuthSucceeded(result: BioAuthnResult) {
//Authentication was successful. Let the user in!
}
override fun onAuthFailed() {
//Authentication failed. Sternly scold the user.
}
override fun onAuthError(errorId: Int, errorMsg: CharSequence) {
//There was an error performing the authentication.
//Tell the user and/or try again.
}
}
fun doFingerprintAuthentication() {
if (bioAuthnManager.canAuth() != BioAuthnManager.BIO_AUTHN_SUCCESS) {
//Can't do fingerprint authentication.
//This would probably be better in a helper function that
//gets checked before this method is even called.
return
}
val prompt = BioAuthnPrompt(this, ContextCompat.getMainExecutor(this), authCallback)
val builder = BioAuthnPrompt.PromptInfo.Builder()
//Tell the user why we need authentication.
builder.setTitle("SOME DESCRIPTIVE TITLE")
builder.setSubtitle("SOME DESCRIPTIVE SUBTITLE")
builder.setDescription("SOME DESCRIPTIVE... DESCRIPTION")
//Allow the use of biometrics
//Using biometrics means there will be no negative button on the prompt dialog.
//The user can choose to enter their PIN/password/pattern instead in this dialog.
builder.setDeviceCredentialAllowed(true)
//Actually show the prompt.
prompt.auth(builder.build())
}
fun doFaceAuthentication() {
if (faceManager.canAuth() != FaceManager.FACE_SUCCESS) {
//Can't do face authentication.
//This would probably be better in a helper function that
//gets checked before this method is even called.
return
}
//Use this to cancel the face authentication if needed.
val cancellationSignal = CancellationSignal()
//Do the face authentication.
//The first parameter is an optional CryptoObject. At this time, it's not
//recommended to use one.
//The second parameter is the cancellation signal.
//The third parameter is a set of optional flags for the request.
//The fourth parameter is the actual authentication callback.
//The fifth parameter is the Handler that the callback should be run on
//(null for main Handler).
faceManager.auth(null, cancellationSignal, 0, authCallback, null)
}
}
Conclusion
That's all for the FIDO SDK! If you're using HMS, or you're planning to use HMS, and you want to make authentication inside your app easier for you and users, be sure to check it out.
You can find more details, including the full API reference for the FIDO SDK, on Huawei's developer website. (API Reference)
Thank you very much
Very nice and useful with FIDO.
Can we use it for App lock?

Implementing HMS Panorama Kit

The HMS Panorama Kit is an SDK to help you display and interact with panoramic images in your app. Instead of creating your own Surfaces and Views, Panorama Kit can do it all for you.
If that's something you're interested in, read on.
Preparation
First up, make sure you have a Huawei Developer Account. This process can take a couple days, and you'll need one to use this SDK, so be sure to start that as soon as possible. You can sign up at https://developer.huawei.com.
Next, you'll want to obtain the SHA-256 representation of your app's signing key. If you don't have a signing key yet, be sure to create one before continuing. To obtain your signing key's SHA-256, you'll need to use Keytool which is part of the JDK installation. Keytool is a command-line program. If you're on Windows, open CMD. If you're on Linux, open Terminal.
On Windows, you'll need to "cd" into the directory containing the Keytool executable. For example, if you have JDK 1.8 v231 installed, Keytool will be located at the following path:
Code:
C:\Program Files\Java\jdk1.8.0_231\bin\
Once you find the directory, "cd" into it:
Code:
C: #Make sure you're in the right drive
cd C:\Program Files\Java\jdk1.8.0_231\bin\
Next, you need to find the location of your keystore. Using Android's debug keystore as an example, where the Android SDK is hosted on the "E:" drive in Windows, the path will be as follows:
Code:
E:\AndroidSDK\.android\debug.keystore
(Keytool also supports JKS-format keystores.)
Now you're ready to run the command. On Windows, it'll look something like this:
Code:
keytool -list -v -keystore E:\AndroidSDK\.android\debug.keystore
On Linux, the command should be similar, just using UNIX-style paths instead.
Enter the keystore password, and the key name (if applicable), and you'll be presented with something similar to the following:
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Make note of the SHA256 field.
SDK Setup
Now we're ready to add the Panorama Kit SDK to your Android Studio project. Go to your Huawei Developer Console and click the HUAWEI AppGallery tile. Agree to the terms of use if prompted.
Click the "My projects" tile here. If you haven't already added your project to the AppGallery, add it now. You'll be asked for a project name. Make it something descriptive so you know what it's for.
Now, you should be on a screen that looks something like the following:
Click the "Add app" button. Here, you'll need to provide some details about your app, like its name and package name.
Once you click OK, some SDK setup instructions will be displayed. Follow them to get everything added to your project. You'll also need to add the following to the "dependencies" section of your app-level build.gradle file:
Code:
implementation 'com.huawei.hms:panorama:4.0.4.301'
Panorama Kit also works on devices without HMS. If you're targeting non-Huawei devices as well, make sure to add the following dependency:
Code:
implementation 'com.huawei.hms:panorama-local:4.0.4.301'
If you ever need to come back to these instructions, you can always click the "Add SDK" button after "App information" on the "Project setting" page.
Now you should be back on the "Project setting" page. Find the "SHA-256 certificate fingerprint" field under "App information," click the "+" button, and paste your SHA-256.
Now, if you're using obfuscation in your app, you'll need to whitelist a few things for HMS to work properly.
For ProGuard:
Code:
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.hianalytics.android.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
For AndResGuard:
Code:
"R.string.hms*",
"R.string.agc*",
"R.string.connect_server_fail_prompt_toast",
"R.string.getting_message_fail_prompt_toast",
"R.string.no_available_network_prompt_toast",
"R.string.third_app_*",
"R.string.upsdk_*",
"R.layout.hms*",
"R.layout.upsdk_*",
"R.drawable.upsdk*",
"R.color.upsdk*",
"R.dimen.upsdk*",
"R.style.upsdk*
That's it! The Panorama Kit SDK should now be available in your project.
Basic Usage
There are two ways to use the Panorama Kit: inside your app and outside your app.
Displaying inside your app means you can customize the view and how the interface displays. Outside means the SDK itself presents its own view and takes care resource management for you.
Inside
This guide won't be going through how to organize and set up your own interface, but it'll help you get started.
Here's some code walking through how you can display a panorama in your app.
Code:
fun displayInside() {
val instance = Panorama.getInstance().getLocalInstance(context)
//Initialize the API
val result = instance.init()
if (result != 0) {
//API failed to initialize
return
}
//A Uri representation of the panorama to load.
//Currently supports file, content, and resource Uris
val uri = Uri.parse("content://some.uri")
//The type of panorama, either IMAGE_TYPE_SPHERICAL (sphere)
//or IMAGE_TYPE_RING (cylinder)
val type = PanoramaInterface.IMAGE_TYPE_SPHERICAL
//setImage() also takes a Bitmap instead of a Uri
val setResult = instance.setImage(uri, type)
if (setResult != 0) {
//Setting the image failed
return
}
//The Surface to display in your app. You can handle this
//however you want, for example by adding it to a MediaPlayer.
val surface = instance.getSurface(type)
//If you're adding the Surface to a MediaPlayer, you may
//want to specify the aspect ratio.
val player = MediaPlayer()
player.setSurface(surface)
instance.setValue(PanoramaInterface.KEY_VIDEO_RATIO, "${player.videoWidth / player.videoHeight}")
//You can also set the panorama to display in polar
//coordinates.
instance.setValue(PanoramaInterface.KEY_RENDER_MODE, PanoramaInterface.VALUE_RENDER_MODE_POLAR)
//There are three control modes available for panoramas:
//motion control (CONTROL_TYPE_POSE), touch control (CONTROL_TYPE_TOUCH),
//and both (CONTROL_TYPE_MIX).
//If you're using CONTROL_TYPE_TOUCH, or CONTROL_TYPE_MIX,
//make sure you call updateTouchEvent() when the user
//makes a gesture.
instance.setControlMode(PanoramaInterface.CONTROL_TYPE_POSE)
instance.updateTouchEvent(MotionEvent() /* dummy event */)
//For controlling the panorama, you should retrieve the View
//from the API.
val view = instance.view
//You can then set a touch listener on that View
//and pass the touch events to the API.
view.setOnTouchListener { _, e ->
instance.updateTouchEvent(e)
true
}
//After you're done with the panorama API, you should
//deinitialize it. This should be called in your onDestroy().
instance.deInit()
}
Outside
If you don't want to worry about handling your own Surfaces and Views, you can always choose to let HMS display the panorama for you.
Example:
Code:
fun displayOutside() {
fun handleResult(result: PanoramaInterface.ImageInfoResult) {
if (result.status.isSuccess) {
//Intent was created successfully. We can start
//the Activity.
context.startActivity(result.imageDisplayIntent)
} else {
//Intent failed to be created.
val error = result.status.errorString
}
}
//A Uri representation of the panorama to load.
//Currently supports file, content, and resource Uris
val uri = Uri.parse("content://some.uri")
val pendingResult = Panorama.getInstance().loadImageInfo(context, uri)
//You can either await() the result, or use a Callback,
//depending on your app's flow.
val result = pendingResult.await() //Will block the current Thread.
handleResult(result)
//Will handle asynchronously
pendingResult.setResultCallback { asyncResult ->
handleResult(asyncResult)
}
//In some cases you may need to specify the panorama type (e.g. if the image has lost its metadata).
//The image type is either IMAGE_TYPE_SPHERICAL or IMAGE_TYPE_CYLINDRICAL.
val typedPendingResult = Panorama.getInstance().loadImageInfo(context, uri, PanoramaInterface.IMAGE_TYPE_SPHERICAL)
//If the image is in a protected data directory, you should use this method to let the API load it.
val permittedPendingResult = Panorama.getInstance().loadImageInfoWithPermission(context, uri)
}
Conclusion[/CODE]
That's it! The HMS Panorama Kit makes displaying panoramic images much easier than doing it yourself, and it doesn't even require a device with HMS. If you're developing a gallery or camera app, this could certainly be a helpful addition.

Getting Started with HMS Site Kit SDK

The HMS Site Kit SDK is a handy set of APIs to help you implement location and address-based searching in your app with ease. If you want to target Huawei devices with your app, and you're looking for a simple way to find and show results to your user, you've come to the right place.
This guide will get you started with the Site Kit SDK, and give you some basic implementation examples. Let's get started.
Preparation
First up, make sure you have a Huawei Developer Account. This process can take a couple days, and you'll need one to use this SDK, so be sure to start that as soon as possible. You can sign up at https://developer.huawei.com.
Next, you'll want to obtain the SHA-256 representation of your app's signing key. If you don't have a signing key yet, be sure to create one before continuing. To obtain your signing key's SHA-256, you'll need to use Keytool which is part of the JDK installation. Keytool is a command-line program. If you're on Windows, open CMD. If you're on Linux, open Terminal.
On Windows, you'll need to "cd" into the directory containing the Keytool executable. For example, if you have JDK 1.8 v231 installed, Keytool will be located at the following path:
Code:
C:\Program Files\Java\jdk1.8.0_231\bin\
Once you find the directory, "cd" into it:
Code:
C: #Make sure you're in the right drive
cd C:\Program Files\Java\jdk1.8.0_231\bin\
Next, you need to find the location of your keystore. Using Android's debug keystore as an example, where the Android SDK is hosted on the "E:" drive in Windows, the path will be as follows:
Code:
E:\AndroidSDK\.android\debug.keystore
(Keytool also supports JKS-format keystores.)
Now you're ready to run the command. On Windows, it'll look something like this:
Code:
keytool -list -v -keystore E:\AndroidSDK\.android\debug.keystore
On Linux, the command should be similar, just using UNIX-style paths instead.
Enter the keystore password, and the key name (if applicable), and you'll be presented with something similar to the following:
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Make note of the SHA256 field.
SDK Setup
Now we're ready to add the Site Kit SDK to your Android Studio project. Go to your Huawei Developer Console and click the HUAWEI AppGallery tile. Agree to the terms of use if prompted.
Click the "My projects" tile here. If you haven't already added your project to the AppGallery, add it now. You'll be asked for a project name. Make it something descriptive so you know what it's for.
Now, you should be on a screen that looks something like the following:
Click the "Add app" button. Here, you'll need to provide some details about your app, like its name and package name.
Once you click OK, some SDK setup instructions will be displayed. Follow them to get everything added to your project. You'll also need to add the following to the "dependencies" section of your app-level build.gradle file:
Code:
implementation 'com.huawei.hms:site:5.0.0.300'
If you ever need to come back to these instructions, you can always click the "Add SDK" button after "App information" on the "Project setting" page.
Now you should be back on the "Project setting" page. Find the "SHA-256 certificate fingerprint" field under "App information," click the "+" button, and paste your SHA-256.
Now, go to the Manage APIs tab on the "Project setting" page. Scroll down until you find "Site Kit" and make sure it's enabled.
Now, if you're using obfuscation in your app, you'll need to whitelist a few things for HMS to work properly.
For ProGuard:
Code:
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.hianalytics.android.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
For AndResGuard:
Code:
"R.string.hms*",
"R.string.agc*",
"R.string.connect_server_fail_prompt_toast",
"R.string.getting_message_fail_prompt_toast",
"R.string.no_available_network_prompt_toast",
"R.string.third_app_*",
"R.string.upsdk_*",
"R.layout.hms*",
"R.layout.upsdk_*",
"R.drawable.upsdk*",
"R.color.upsdk*",
"R.dimen.upsdk*",
"R.style.upsdk*"
That's it! The Site Kit SDK should now be available in your project.
Basic Usage
Huawei's Site Kit SDK gives you quite a few useful features.
There's Keyword Search, which lets the user type in a search query, along with other options, and see relevant results.
There's Nearby Place Search, which returns points of interest close to the user. There's a Place Details API, to let the user find out more about a specific place.
There's the Place Search Suggestion feature, which adds autofill-like search suggestions in real-time.
And finally, there's the Widget component, which implements Place Search Suggestion in a search bar for you.
We'll go over each feature one by one.
Keyword Search
Below is an example of how you might implement a keyword search.
Code:
//Create the search service. It's recommended you use an Activity
//Context, although it's not required.
//You can find your API key on the Project Setting page for your
//project in AppGallery Connect, under App Information.
val searchService = SearchServiceFactory.create(context, "API_KEY")
//Create a request. For this example, we're going to be
//using dummy inputs, but in a real app, these would
//be provided by the user.
val request = TextSearchRequest()
//This can be any keyword, like "McDonald's" or
//"Washington".
request.setQuery("London")
//Define a location (optional). This could be the user's
//current location, or some other area.
val location = Coordinate(48.893478, 2.334595)
request.setLocation(location)
//Set a radius in meters (optional). The default is 50,000.
location.setRadius(1000)
//Set the type of location (optional, but recommended).
//Values can be found in the HwLocationType class.
request.setHwPoiType(HwLocationType.ENTERTAINMENT_PLACE)
//Set the country code to where these results should be
//confined (optional). Uses the ISO-3166-1 alpha-2 standard.
request.setCountryCode("FR")
//Set the language for results to appear in (optional).
request.setLanguage("fr")
//Set the current page (from 1-60). Default is 1.
request.setPageIndex(1)
//Set how many results should appear per-page (from 1-20).
//Default is 20.
request.setPageSize(5)
//Create a result listener for handling search results.
val resultListener = object : SearchResultListener<TextSearchResponse>() {
override fun onSearchResult(result: TextSearchResponse?) {
//We've got results.
if (result == null || result.totalCount <= 0) {
//We actually don't have results. Return.
return
}
val sites: List<Site>? = result.sites
if (sites.isNullOrEmpty()) {
//Couldn't find any sites. Return.
return
}
//Handle results.
sites.forEach { site ->
val id = site.siteId
val name = site.name
}
}
override fun onSearchError(state: SearchStatus) {
//There was an error retrieving results.
val code = status.errorCode
val message = status.errorMessage
}
}
//Finally, initiate the search.
searchService.textSearch(request, resultListener)
Nearby Place Search
A Nearby Place Search is practically identical to a Keyword Search in terms of implementation. Simply replace the textSearch() call with a nearbySearch() call. Almost everything else is identical.
Code:
//Use this instead of `textSearch()`.
//One notable difference is that the default radius
//for a nearby search is 1,000 meters instead of 50,000.
searchService.nearbySearch(request, resultListener)
Place Details
Creating a Place Details request is similar to the previous two, although there are some differences in implementation. For one, you should know the site ID of the place whose details you're querying, which you can get using one of the above methods.
Code:
/Create the search service. It's recommended you use an Activity
//Context, although it's not required.
//You can find your API key on the Project Setting page for your
//project in AppGallery Connect, under App Information.
val searchService = SearchServiceFactory.create(context, "API_KEY")
//Create the details request.
val request = DetailSearchRequest()
//Set the site ID. You can retrieve this from a keyword or
//nearby place search result.
request.setSiteId("THE_SIDE_ID")
//Set the language (optional).
request.setLanguage("fr")
//Create a results listener.
val resultListener = object : SearchResultListener<DetailSearchResponse>() {
override fun onSearchResult(result: DetailSearchResponse?) {
//Detail search succeeded.
if (result == null) {
//Something weird happened. Return.
return
}
//Retrieve the site. Return if null.
val site = result.site ?: return
//Retrieve various details about the site and display
//for the user.
}
override fun onSearchError(status: SearchStatus) {
//There was an error retrieving results.
val code = status.errorCode
val message = status.errorMessage
}
}
//Initiate the request.
searchService.detailSearch(request, resultListener)
Place Search Suggestion
This feature is similar to the Keyword and Nearby Search features, except that it returns a limited set of results. It's more suitable for rapid-fire requests, such as real-time search suggestions.
Here's an example for how to implement it.
Code:
/Create the search service. It's recommended you use an Activity
//Context, although it's not required.
//You can find your API key on the Project Setting page for your
//project in AppGallery Connect, under App Information.
val searchService = SearchServiceFactory.create(context, "API_KEY")
//Create the request.
val request = QuerySuggestionRequest()
//Set the user's current query.
request.setQuery("Pari")
//Set a location (optional).
val location = Coordinate(48.893478, 2.334595)
request.setLocation(location)
//Set a radius in meters (optional) (from 1-50,000).
//Default is 50,000.
request.setRadius(50)
//Set the search country (optional).
request.setCountryCode("FR")
//Set the language results should appear in
//(optional).
request.setLanguage("fr")
//Set a specific POI type (optional). Should
//be a subset of the values found in LocationType.
request.setPoiTypes(LocationType.ADDRESS)
//Create a results listener.
val resultListener = object : SearchResultListener<QuerySuggestionResponse>() {
override fun onSearchResult(result: QuerySuggestionResponse?) {
if (result == null) {
//No results. Return.
return
}
val sites: List<Site>? = result.sites
if (sites.isNullOrEmpty()) {
//No sites. Return.
return
}
//Handle results.
sites.forEach { site ->
val id = site.sideId
val name = site.name
}
}
override fun onSearchError(status: SearchStatus) {
//There was an error retrieving results.
val code = status.errorCode
val message = status.errorMessage
}
}
//Initiate the search request.
searchServie.querySuggestion(request, resultListener)
Widget
The Site Kit can take care of search logic for you, including suggestions. Here's how.
The first thing you need to do is implement the Fragment in your layout.
XML:
<fragment
android:id="@+id/search_fragment"
android_name="com.huawei.hms.site.widget.SearchFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
You can also create a reference in code and use a FragmentManager to add and remove it as needed.
Next, you need to implement the search functionality.
Code:
//Get a reference to the Fragment. This example assumes it's
//in your layout XML.
val searchFragment = supportFragmentManager.findFragmentById(R.id.search_fragment) as SearchFragment
//Set the API key.
//You can find your API key on the Project Setting page for your
//project in AppGallery Connect, under App Information.
searchFragment.setApiKey("API_KEY")
//Set a selection listener.
searchFragment.setOnSiteSelectedListener(object : SiteSelectionListener() {
override fun onSiteSelected(site: Site) {
//The user has selected a site returned by HMS.
//Handle as applicable.
}
override fun onError(status: SearchStatus) {
//There was an error retrieving results.
val code = status.errorCode
val message = status.errorMessage
}
})
Conclusion
That's it! As you can probably see, HMS Site Kit makes it pretty easy to implement location searching in your app.
This is only for devices that come with HMS pre-installed, but it's certainly a useful set of tools. Be sure to check out Huawei's full documentation for more details.

Implementing HMS Audio Kit into your app

Playing audio on Android can be tricky, especially if you have to manage both online and offline services. Luckily, for apps targeting Huawei devices, there's HMS Audio Kit.
Audio Kit makes managing audio tracks and playlists a bit easier, by unifying the process for both online and offline sources. It allows you to aggregate songs into playlists, control those playlists, and all the other stuff you might want to do with your audio.
If you're making an app that plays audio, even if it isn't user-selected, and you're developing for Huawei devices, this library is worth a look.
Let's see how to implement it.
Preparation
First up, make sure you have a Huawei Developer Account. This process can take a couple days, and you'll need one to use this SDK, so be sure to start that as soon as possible. You can sign up at https://developer.huawei.com.
Next, you'll want to obtain the SHA-256 representation of your app's signing key. If you don't have a signing key yet, be sure to create one before continuing. To obtain your signing key's SHA-256, you'll need to use Keytool which is part of the JDK installation. Keytool is a command-line program. If you're on Windows, open CMD. If you're on Linux, open Terminal.
On Windows, you'll need to "cd" into the directory containing the Keytool executable. For example, if you have JDK 1.8 v231 installed, Keytool will be located at the following path:
Code:
C:\Program Files\Java\jdk1.8.0_231\bin\
Once you find the directory, "cd" into it:
Code:
C: #Make sure you're in the right drive
cd C:\Program Files\Java\jdk1.8.0_231\bin\
Next, you need to find the location of your keystore. Using Android's debug keystore as an example, where the Android SDK is hosted on the "E:" drive in Windows, the path will be as follows:
Code:
E:\AndroidSDK\.android\debug.keystore
(Keytool also supports JKS-format keystores.)
Now you're ready to run the command. On Windows, it'll look something like this:
Code:
keytool -list -v -keystore E:\AndroidSDK\.android\debug.keystore
On Linux, the command should be similar, just using UNIX-style paths instead.
Enter the keystore password, and the key name (if applicable), and you'll be presented with something similar to the following:
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Make note of the SHA256 field.
SDK Setup
Now we're ready to add the Audio Kit SDK to your Android Studio project. Go to your Huawei Developer Console and click the HUAWEI AppGallery tile. Agree to the terms of use if prompted.
Click the "My projects" tile here. If you haven't already added your project to the AppGallery, add it now. You'll be asked for a project name. Make it something descriptive so you know what it's for.
Now, you should be on a screen that looks something like the following:
Click the "Add app" button. Here, you'll need to provide some details about your app, like its name and package name.
Once you click OK, some SDK setup instructions will be displayed. Follow them to get everything added to your project. You'll also need to add the following to the "dependencies" section of your app-level build.gradle file:
Code:
implementation 'com.huawei.hms:audiokit-player:1.0.0.302'
If you ever need to come back to these instructions, you can always click the "Add SDK" button after "App information" on the "Project setting" page.
Now you should be back on the "Project setting" page. Find the "SHA-256 certificate fingerprint" field under "App information," click the "+" button, and paste your SHA-256.
Now, if you're using obfuscation in your app, you'll need to whitelist a few things for HMS to work properly.
For ProGuard:
Code:
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.hianalytics.android.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
For AndResGuard:
Code:
"R.string.hms*",
"R.string.agc*",
"R.string.connect_server_fail_prompt_toast",
"R.string.getting_message_fail_prompt_toast",
"R.string.no_available_network_prompt_toast",
"R.string.third_app_*",
"R.string.upsdk_*",
"R.layout.hms*",
"R.layout.upsdk_*",
"R.drawable.upsdk*",
"R.color.upsdk*",
"R.dimen.upsdk*",
"R.style.upsdk*
That's it! The Audio Kit SDK should now be available in your project.
Basic Usage
Before we get into actually using the API, there are a few permissions you'll need to declare and have granted.
Add these to your AndroidManifest.xml and request access as needed:
XML:
<!-- Use these if you're going to play audio files from the internet -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Use these if you're going to play/save audio files from/to the device's storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_STORAGE" />
Now let's start implementing! Below is an example of how to set up the class instances you'll need.
Code:
//Playback control
lateinit var hwAudioPlayerManager: HwAudioPlayerManager
//Playback configuration
lateinit var hwAudioConfigManager: HwAudioConfigManager
//Queue control
lateinit var hwAudioQueueManager: HwAudioQueueManager
fun setUpAudioManager(context: Context) {
//Use this config to set various player parameters.
//Check the API docs for other config methods.
val config = HwAudioPlayerConfig(context)
//Set the cache size for the player in Mebibytes.
//Default is 200.
config.playCacheSize = 500
//Enable debug mode for verbose logging.
config.debugMode = true
HwAudioManagerFactory.createHwAudioManager(config, object : HwAudioConfigCallBack() {
override fun onSuccess(audioManager: HwAudioManager) {
//Setup succeeded. Let's try getting our instances.
try {
hwAudioPlayerManager = audioManager.playerManager
hwAudioConfigManager = audioManager.configManager
hwAudioQueueManager = audioManager.queueManager
} catch (e: Exception) {
//Something went wrong
}
}
override fun onError(errorCode: Int) {
//Initialization failed. Check the error code.
}
})
}
Now that we have the relevant instances, we can start playing audio. The following example shows how to create a playlist and play it.
Code:
//An online music file.
val firstSongUrl = "https://lfmusicservice.hwcloudtest.cn:18084/HMS/audio/Taoge-chengshilvren.mp3"
//A local music file.
val secondSongPath = "/storage/emulated/0/Download/Some_song.mp3"
//The item representing the first song.
val firstSong = HwAudioPlayItem()
//Set the song's title.
firstSong.audioTitle = "Some Online Song"
//Set the song's artist.
firstSong.singer = "Some Artist"
//Set the song's album art, in different sizes.
//These might be able to take local content URLs,
//but documentation is unclear.
firstSong.smallImageUrl = "https://some.image.url/image_small.jpg"
firstSong.midImageUrl = "https://some.image.url/image_mid.jpg"
firstSong.bigImageUrl = "https://some.image.url/image_big.jpg"
//Set an ID for this song
firstSong.audioId = firstSongUrl.hashCode()
//Since this track is online, set the proper flag.
firstSong.online = 1
//Set the URL.
firstSong.onlinePath = firstSongUrl
//Set the current seek, in milliseconds
firstSong.playPosition = 10000
//The item representing the second song.
val secondSong = HwAudioPlayItem()
secondSong.audioTitle = "Some Local Song"
secondSong.singer = "Some Other Artist"
secondSong.smallImageUrl = "content://some.image.uri/image_small.jpg"
secondSong.midImageUrl = "content://some.image.uri/image_mid.jpg"
secondSong.bigImageUrl = "content://some.image.uri/image_big.jpg"
secondSong.audioId = secondSongPath.hashCode()
//Set the file path.
secondSong.filePath = secondSongPath
//Create a playlist.
val playlist = ArrayList<HwAudioPlayItem>()
//Add items to list.
playlist.add(firstSong)
playlist.add(secondSong)
//Play the playlist.
hwAudioPlayerManager.playList(
playlist,
/* The index of the playlist to start at */ 0,
/* The seek position to start at, in seconds */ 0
)
//Pause playback.
hwAudioPlayerManager.pause()
//Stop playback completely (i.e. shutting down app).
hwAudioPlayerManager.stop()
//Resume playback.
hwAudioPlayerManager.play()
//Play the song at the specified index in the playlist.
hwAudioPlayerManager.play(1)
//Play the song at the specific index in the playlist
//with a given seek time, in seconds.
hwAudioPlayerManager.play(1, 10)
//Go to previous audio track.
hwAudioPlayerManager.playPre()
//Go to the next audio track.
hwAudioPlayerManager.playNext()
//Check if music is currently playing.
val isPlaying: Boolean = hwAudioPlayerManager.isPlaying()
//Check if music is currently buffering.
val isBuffering: Boolean = hwAudioPlayerManager.isBuffering()
//Get the buffer progress.
val bufferPercent: Int = hwAudioPlayerManager.bufferPercent
//Seek to the specified time on the current track (in seconds).
hwAudioPlayerManager.seekTo(10)
//Get the current seek (in seconds)
val seek: Int = hwAudioPlayerManager.offsetTime
//Set the mode for playing the playlist.
//Use 0 for sequential playback
//Use 1 to shuffle the list
//Use 2 to repeat the playlist
//Use 3 to repeat the current song
hwAudioPlayerManager.playMode = 0
You can also manage a playlist after you've already pushed it to be played, using HwAudioQueueManager.
Code:
//Check the current playlist position.
val index: Int = hwAudioQueueManager.currentIndex
//Get the currently playing song.
val currentlyPlaying: HwAudioPlayItem = hwAudioQueueManager.currentPlayItem
//Get the entire playlist.
val currentPlaylist: List<HwAudioPlayItem> = hwAudioQueueManager.allPlaylist
//Remove a song from the playlist, by index.
hwAudioQueueManager.removeListByIndex(1)
//Remove an HwAudioPlayItem from the playlist.
hwAudioQueueManager.removeListByIndex(currentlyPlaying)
//Add a song to the playlist, at the specified position.
hwAudioQueueManager.addPlayItem(/* HwAudioPlayItem */ song, /* position */ 2)
//Add a list of songs to the playlist, starting at the
//specified position.
hwAudioQueueManager.addPlayItemList(
/* List<HwAudioPlayItem> */ songs,
/* position */ 3
)
//Set a new playlist.
hwAudioQueueManager.setPlayList(currentPlaylist)
Conclusion
And that's it! Audio Kit is a pretty simple SDK that makes it easier to manage playing music from various sources. If you're looking for a simple way to play audio on Huawei devices, trye this library out.
Make sure to read Huawei's documentation for more details on implementation and the API.

Categories

Resources