Getting Started with Huawei's Safety Detect SDK - Huawei Developers

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.

Related

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.

Search places by keywords with HMS Site Kit

Hello everyone, in this article series, I will tell you about what is HMS Site Kit and how to use it’s features. With HMS Site Kit, you can basically provide users with easy and reliable access to services to related to locations and places.
With the HMS Site Kit, we can provide them make use of this features while helping users to to discover world quickly;
We can take place suggestions according to the keywords that we have determined,
According to the location of the user’s device, we can search for nearby places,
We can get detailed information about a location,
We can learn the human readable address information of a coordinate point,
We can learn the time period where a coordinate point is found.
In the first article of Site Kit series, I will give you an information about how to setup Site Kit to Android project and how to use Keyword Search.
How to integrate HMS Site Kit to project?
First of all, we need to create a signed Bundle/APK of our project. For this, you can follow the steps which have shown in the picture below.
We can start to creating signature by clicking on the Build->Generate Signed Bundle/APK menu on Android Studio. Then, we can start the process of generating a signed APK by selecting the APK option on screen that comes up.
{
"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"
}
By pressing the Create New button on the screen that comes up, we can determine the path, password, key alias and key password values of the .jks file to be created for our application. Informations in the Certificate field is not mandatory.
After clicking OK button, we can continue the APK signing process by entering our password informations.
Then, we can complete the signing process by choosing which version of our application we want to sign such as release and debug, together with the signature versions.
After completing this process, we need to make configurations of this signature file in the build.gradle file at the app level of our application.
Code:
signingConfigs {
release {
storeFile file('SiteKitDemo.jks')
keyAlias 'SiteKitDemo'
keyPassword '****'
storePassword '****'
v1SigningEnabled true
v2SigningEnabled true
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
signingConfig signingConfigs.release
debuggable true
}
}
After performing this process, we can perform the operations related to Gradle synchronization by clicking on the sync now button.
After performing this process, we need to add ‘SHA-256 certificate fingerprint’ value of our application to AppGallery Connect.
We can learn value of ‘SHA-256 certificate fingerprint’ via termianl/CMD. For this, we need to go by terminal to the bin folder under the jre(Java Runtime Environment) installed on our system and run the command below.
Code:
C:\Program Files (x86)\Java\jre1.8.0_251\bin>keytool -list -v -keystore <keystore-path>
We will see a screen output as follows. Here, we need to get the value of SHA256.
We need to add this SHA256 value which we have received to the General Information field in the Project Settings menu on AppGalleryConnect. After performing this process, we can download the agconnect-services.json file.
After performing this process, we need to enable Site Kit service in Manage APIs tab on Project Settings tab.
We need to add agconnect-services.json file which we have downloaded, to under app folder on Android Studio of our project as follows.
After performing this process, we need to add Maven libraries and dependency values on build.gradle files.
First of all, we need to open build.gradle file at the project level and add the lines shown below:
Code:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.3.61'
repositories {
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' } // HUAWEI Maven repository
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
def agcpVersion = "1.3.1.300"
classpath "com.huawei.agconnect:agcp:${agcpVersion}" // HUAWEI agcp plugin
}
}
allprojects {
repositories {
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' } // HUAWEI Maven repository
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
After performing this process, we need to add plugin and dependency values in the build.gradle file at the app level as follows.
Code:
apply plugin: 'com.huawei.agconnect'
...
...
dependencies {
...
def siteKitVersion = "4.0.3.300"
implementation "com.huawei.hms:site:${siteKitVersion}"
}
To prevent HMS SDK from hiding, we need to add following lines of code to proguard-rules.pro file which is located under the app folder.
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.**{*;}
HMS Site Kit — Keyword Search
Thanks to this feature provided by Site Kit, we can search for many places such as tourist attractions, restaurants, schools and hotels by entering information such as keywords, coordinates.
Thanks to the data from this search result, we can easily access many different information about places such as name, address, coordinates, phone numbers, pictures, address details. Within the AddressDetail model, we can easily access information about the address piece by piece through different variables and change the way the address’ notation as we wish.
First of all, after sharing sharing the method what we can search by keyword, we will examine these pieces of code and parameters one by one.
Code:
fun keywordSearch(coordinate: Coordinate, keyword: String, radius: Int,
pageIndex: Int, pageSize: Int, countryCode: String){
val searchService = SearchServiceFactory.create(context,
URLEncoder.encode(
"Your-API-KEY",
"utf-8"))
var request = TextSearchRequest()
request.query = keyword
request.location = coordinate
request.radius = radius
request.pageIndex = pageIndex
request.pageSize = pageSize
request.language = Locale.getDefault().language // Getting system language
request.countryCode = countryCode
searchService.textSearch(request, object: SearchResultListener<TextSearchResponse>{
override fun onSearchError(searchStatus: SearchStatus?) {
Log.e("SITE_KIT","${searchStatus?.errorCode} - ${searchStatus?.errorMessage}")
}
override fun onSearchResult(textSearchResponse: TextSearchResponse?) {
var siteList = textSearchResponse?.sites
siteList?.let {
for(site in siteList){
Log.i("SITE_KIT", "Name => ${site.name}," +
"Format address => ${site.formatAddress}, " +
"Coordinate => ${site.location.lat} - ${site.location.lng}, " +
"Phone => ${site.poi.phone}, " +
"Photo URLS => ${site.poi.photoUrls}, " +
"Rating => ${site.poi.rating}, " +
"Address Detail => ${site.address.thoroughfare}, ${site.address.subLocality}, " +
"${site.address.locality}, ${site.address.adminArea}, ${site.address.country}")
}
} ?: kotlin.run {
Log.e("SITE_KIT","There is not any site")
}
}
})
}
First, we need to create a SearchService object from the SearchServiceFactory class. For this, we can use the create() method of the SearchServiceFactory class. We need to declare two parameters in create() method.
The first of these parameters is context value. It is recommended that Context value should be in Activity type. Otherwise, when HMS Core(APK) needs to be updated, we can not receive any notification about it.
The second parameter is API Key value that we can access via AppGallery Connect. This value is generated automatically by AppGallery Connect when a new app is created. We need to encode API parameter as encodeURI.
We need to create a TextSearchRequest object to perform searching by keyword. We will perform the related search criteria on this TextSearchRequest object.
While performing the searching operation, we can set many different criteria as we see in the code snippet. Let us examine the duties of these criteria one by one if you want to:
Query: Used to specify the keyword that we will use during the search process.
Location: It is used to specify latitude and longitude values with a Coordinate object to ensure that search results are searched as closely to the location that we want.
Radius: It is used to make the search results within in a radius determined in meters. It can take values between 1 and 50000, and its default value is 50000.
CountryCode: It is using to limit search results according to certain country borders.
Language: It is used to specify the language that search results have to be returned. If this parameter is not specified, the language of the query field we have specified in the query field is accepted by default. In example code snippet in above, the language of device has been added automatically in order to get a healthy result.
PageSize: Results return with the Pagination structure. This parameter is used to determine the number of Sites to be found in each page.
PageIndex: It is used to specify the number of the page to be returned with the Pagination structure.
Once we have determined our criteria, we can start the search using textSearch() method of SearchService object. textSearch() method takes two parameters.
First parameter is TextSearchRequest object which we have defined above. Here, our search criterias are defined.
For the second parameter, we need to implement SearchResultListener interface. Since the SearchResultListener interface is generic, we need the data type that results will return here. Here we can specify TextSearchResponse class that is model provided by Huawei Site Kit. This interface contains two methods, onSearchError() and onSearchResult() methods. We can configure these methods according to logic of our program and take necessary actions.

The Ultimate Scanning App From Huawei

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.

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.

Categories

Resources