HMS Safety Detect API integration — (MVVM RxAndroid) - Huawei Developers

This article is originally from HUAWEI Developer Forum
Forum link: https://forums.developer.huawei.com/forumPortal/en/home​
This is all about integration of HMS Safety Detect API in the Android app using MVVM RxAndroid.
What is HMS Safety Detect API?
Ø The Safety Detect provides system integrity check (SysIntegrity), app security check (AppsCheck), malicious URL check (URLCheck), and fake user detection (UserDetect), helping you prevent security threats to your app.
{
"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"
}
Let’s create a Demo Project:
HUAWEI HMS Safety Detect integration requires the following preparations
Ø Creating an AGC Application.
Ø Creating an Android Studio Project.
Ø Generating a signature certificate.
Ø Generating a signature certificate fingerprint.
Ø Configuring the signature certificate fingerprint.
Ø Adding the application package name and save the configuration file.
Ø Configure the Maven address and AGC gradle plug-in.
Ø Configure the signature file in Android Studio.
In this article, we will implement SysIntegrity API in demo project using with RxAndroid and MVVM.
Call the API and handle responses.
Verify the certificate chain, signature, and domain name on the server.
1. Open AppGallery Console:
1. We need to create an application inside console.
2. We need to enable the Safety Detect api.
Go to Console > AppGallery Connect > My apps, click your app, and go to Develop > Manage APIs.
Now enable Safety Detect Api
Download the agconnect-services.json
Move the downloaded agconnect-services.json file to the app root directory of your Android Studio project.
We need to add HMS SDK dependency in app:gradle file
Code:
implementation 'com.huawei.hms:safetydetect:4.0.0.300'
We need to add maven dependency inside project:gradle file
Code:
maven { url 'http://developer.huawei.com/repo/' }
We need to add two more dependencies in app:gradle file
Code:
// MVVM
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
// RxAndroid
implementation 'io.reactivex.rxjava2:rxjava:2.2.8'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
Enable Data Binding
Code:
dataBinding {
enabled = true
}
2. Let’s implement api :
I have created following classes.
1. SysIntegrityDataSource : Which invoke the System Integrity Api with help of RxJava.
2. SysIntegrityViewModel : Which handle the response from System Integrity api and provide LiveData for view componets.
3. SysIntegrityFragment : Which observe the livedata from viewmodel class and set values in views such as textviews and button.
Note: If you are not familiar with MVVM or RxAndroid then I would like to suggest you to please go through my following articles:
· Android MyShows App — Rxandroid MVVM LiveData ViewModel DataBinding, Networking with Retrofit, Gson & Glide — Series
· Demystifying Data Binding — Android Jetpack — Series
Let’s see the implementation of SysIntegrityDataSource.java class.
Code:
public class SysIntegrityDataSource {
private static final String APP_ID = "XXXXXXXX";
private Context context;
public SysIntegrityDataSource(Context context) {
this.context = context;
}
public Single<SysIntegrityResp> executeSystemIntegrity() {
return Single.create(this::invokeSysIntegrity);
}
private void invokeSysIntegrity(SingleEmitter<SysIntegrityResp> emitter) {
byte[] nonce = ("Sample" + System.currentTimeMillis()).getBytes();
SafetyDetect.getClient(context)
.sysIntegrity(nonce, APP_ID)
.addOnSuccessListener(emitter::onSuccess)
.addOnFailureListener(emitter::onError);
}
}
invokeSysIntegrity() : This method invoke the System Integrity api and emit the data onSuccess/OnError and past it to Single<SysIntegrityResp> observable.
executeSystemIntegrity() : This method will create Single observable and return the response from invokeSysIntegrity() method.
3. Let’s implement ViewModel :
I have created SysIntegrityViewModel.java class.
Code:
public class SysIntegrityViewModel extends AndroidViewModel {
private final CompositeDisposable disposables = new CompositeDisposable();
private SysIntegrityDataSource sysIntegrityDataSource;
private MutableLiveData<SysIntegrityResp> systemIntegrityLiveData;
private MutableLiveData<String> error;
public SysIntegrityViewModel(Application app) {
super(app);
sysIntegrityDataSource = new SysIntegrityDataSource(app.getBaseContext());
systemIntegrityLiveData = new MutableLiveData<>();
error = new MutableLiveData<>();
}
public LiveData<SysIntegrityResp> observerSystemIntegrity() {
sysIntegrityDataSource.executeSystemIntegrity()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<SysIntegrityResp>() {
@Override
public void onSubscribe(Disposable d) {
disposables.add(d);
}
@Override
public void onSuccess(SysIntegrityResp response) {
systemIntegrityLiveData.setValue(response);
}
@Override
public void onError(Throwable e) {
error.setValue(e.getMessage());
}
});
return systemIntegrityLiveData;
}
public LiveData<String> getError() {
return error;
}
@Override
protected void onCleared() {
disposables.clear();
}
}
MutableLiveData<SysIntegrityResp> systemintegrityLiveData: This field which provide the live data and return the value from viewmodel to fragment class.
observerSysIntegrity() : Which observe RxAndroid’s Single(observable) on main thread and set the value in systemIntegrityLiveData. If we got error while observing it will post the error in MutableLiveData<String> error.
4. Let’s implement Fragment :
I have created SysIntegrityFragment.java class Which obaserve the System Integrity api’s reponse and set the values in views.
Code:
public class SysIntegrityFragment extends Fragment {
private SysIntegrityViewModel sysIntegrityViewModel;
private FragmentSysBinding sysBinding;
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
sysBinding=DataBindingUtil.inflate(inflater, R.layout.fragment_sys, container, false);
sysIntegrityViewModel = ViewModelProviders.of(this).get(SysIntegrityViewModel.class);
sysBinding.btnSys.setOnClickListener(v->{
processView();
sysIntegrityViewModel.observerSystemIntegrity().observe(getViewLifecycleOwner(), this::setSystemIntegrity);
sysIntegrityViewModel.getError().observe(getViewLifecycleOwner(),this::showError);
});
return sysBinding.getRoot();
}
private void setSystemIntegrity(SysIntegrityResp response){
String jwsStr = response.getResult();
String[] jwsSplit = jwsStr.split("\\.");
String jwsPayloadStr = jwsSplit[1];
String payloadDetail = new String(Base64.decode(jwsPayloadStr.getBytes(), Base64.URL_SAFE));
try {
final JSONObject jsonObject = new JSONObject(payloadDetail);
final boolean basicIntegrity = jsonObject.getBoolean("basicIntegrity");
sysBinding.btnSys.setBackgroundResource(basicIntegrity ? R.drawable.btn_round_green : R.drawable.btn_round_red);
sysBinding.btnSys.setText(R.string.rerun);
String isBasicIntegrity = String.valueOf(basicIntegrity);
String basicIntegrityResult = "Basic Integrity: " + isBasicIntegrity;
sysBinding.txtBasicIntegrityTitle.setText(basicIntegrityResult);
if (!basicIntegrity) {
String advice = "Advice: " + jsonObject.getString("advice");
sysBinding.txtPayloadAdvice.setText(advice);
}
} catch (JSONException e) {
}
}
private void showError(String error){
Toast.makeText(getActivity().getApplicationContext(), error, Toast.LENGTH_SHORT).show();
sysBinding.btnSys.setBackgroundResource(R.drawable.btn_round_yellow);
sysBinding.btnSys.setText(R.string.rerun);
}
private void processView() {
sysBinding.txtBasicIntegrityTitle.setText("");
sysBinding.txtPayloadBasicIntegrity.setText("");
sysBinding.btnSys.setText(R.string.processing);
sysBinding.btnSys.setBackgroundResource(R.drawable.btn_round_processing);
}
}
We have instantiated instance of view model using ViewModel factory method.
We will consume the response on button click’s event.
If we got success response then we will display inside textviews and button otherwise we will show the error toast.
5. Let’s see the result:
Build the app and hit run button.
Click > RunDetection Case 1: Success Case 2: SDK Error Case 3: Integrity false (Rooted)
I hope you have learnt something new today. If you have any query regarding this article, please feel free to post any comments.
Any questions about this, you can try to acquire answers from HUAWEI Developer Forum.​

Useful sharing,thanks

Thank you so much for sharing, very useful.

Thank you so much for sharing, very useful.

Thank you so much for sharing, very useful.

Does it work offline?

useful sharing,thanks!

Related

Improving app security with HMS Safety Detect

{
"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"
}
These days mobile devices are part of our life. We do many operations from our mobile phones such as making payment, logging in to social media accounts, checking our bank accounts.
These are the operations which need high security level. If our device will have malicious apps or something like that, our accounts will have trouble and we may suffer many financial and moral damages.
In this article, I will talk about how to improve app security by using HMS Safety Detect Kit.
To do that, I have developed a simple secure web browser app. Because in web browsers, we can use bank websites, we can login to our social media, we can make some payment and use our credit/bank card information. We wouldn’t like to our information to be stolen.
App Preparations
I use Koin framework for dependency injection in my application.
To use Koin Framework in our application, we should add 3 dependencies to our app. In the above, you can find dependencies which you need to add in app-level build.gradle file.
Code:
def koinVersion = "2.2.0-rc-4"
dependencies {
....
// Koin for Android
implementation "org.koin:koin-android:$koinVersion"
// Koin Android Scope feature
implementation "org.koin:koin-android-scope:$koinVersion"
// Koin Android ViewModel feature
implementation "org.koin:koin-android-viewmodel:$koinVersion"
}
After we have implemented the Koin dependencies, we need to create our modules which we will add in our application class.
We will get necessary objects with the help of these modules. I prefer to define different module files for different works.
Code:
val applicationModule = module {
single(named("appContext")){ androidApplication().applicationContext }
factory { HmsHelper() }
factory { SystemHelper() }
}
Code:
val dataModule = module {
factory<ErrorItem>(named("HmsNotAvailable")) { ErrorItem(
icon = ContextCompat.getDrawable(get(named("appContext")), R.drawable.huawei)!!,
title = androidContext().getString(R.string.hms_not_available),
message = androidContext().getString(R.string.download_hms_core)) }
factory<ErrorItem>(named("DeviceNotSecure")) { ErrorItem(
icon = ContextCompat.getDrawable(get(named("appContext")), R.drawable.ic_device_not_secure)!!,
title = androidContext().getString(R.string.device_not_secure),
message = androidContext().getString(R.string.device_not_secure_message)) }
factory<ErrorItem>(named("MaliciousApps")) { ErrorItem(
icon = ContextCompat.getDrawable(get(named("appContext")), R.drawable.ic_malicious_apps)!!,
title = androidContext().getString(R.string.device_not_secure),
message = androidContext().getString(R.string.malicious_apps_message)) }
}
Code:
val viewModelModule = module {
viewModel { SplashViewModel() }
}
After we have defined our modules, we need to setup Koin in our application class.
While starting Koin, we should add our modules which we have defined above, and if we want to use app context, we should androidContext value.
XML:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.berkberber.hms_securewebbrowser">
....
<application
android:name=".SecureWebBrowserApp"
....
>
....
</application>
</manifest>
Code:
class SecureWebBrowserApp: Application(){
override fun onCreate() {
super.onCreate()
setup()
}
private fun setupKoin(){
startKoin {
androidContext([email protected])
modules(
applicationModule,
viewModelModule,
dataModule
)
}
}
private fun setup(){
setupKoin()
}
}
To get more information about app and to see how I used other things such as Navigation Component, MVVM, and etc. you can visit my GitHub repository.
HMS Safety Detect
Safety Detect Kit helps us to improve the security level of our apps. There are 5 different APIs we can use with HMS Safety Detect Kit.
SysIntegrity API: Helps us to check device security. We can determine that device has been rooted or has not.
AppsCheck API: Helps us to determine and list malicious apps which have installed to device.
URLCheck API: Helps us check whether websites are safe.
UserDetect API: Helps us to determine that user is fake or is not.
WifiDetect API: Helps us to check whether Wi-Fi which the device has connected is secure.
Note: UserDetect API is available outside of Chinese mainland. WifiDetect API is available only in the Chinese mainland.
In this article, I have been focused on app security. So, I used SysIntegrity API and AppsCheck API and I will give you informations about these APIs.
Checking is HMS available on device (optional)
We will use Safety Detect Kit in our application. Safety Detect Kit requires HMS Core to be installed on the device.
We don’t have to make this control, but if device doesn’t have HMS, we can’t use HMS Safety Detect Kit. That’s why I recommend you to check HMS Core availability on device and if device doesn’t have HMS, it is better to show an error screen to user.
To check HMS availability we need to add base HMS dependency to our app-level build.gradle file.
To check that device has HMS support or has not, we can write very basic function called as isHmsAvailable().
Code:
def hmsBaseVersion = "5.0.3.300"
dependencies {
...
// HMS Base
implementation "com.huawei.hms:base:${hmsBaseVersion}"
}
Code:
class HmsHelper: KoinComponent{
private val appContext: Context by inject(named("appContext"))
fun isHmsAvailable(): Boolean {
val isAvailable = HuaweiApiAvailability.getInstance().isHuaweiMobileNoticeAvailable(appContext)
return (ConnectionResult.SUCCESS == isAvailable)
}
}
If this function returns true, that means device has HMS support and we can start our application.
If this function returns false, that means device doesn’t have HMS support and we shouldn’t start our application. We may show an error screen to user.
SysIntegrity API
SysIntegrity API helps us to check that the user’s device is secure or is not. Even if the device has been rooted, SysIntegrity API will tell us that device is not secure.
To check the device security, we can call our isDeviceSecure() function.
As you see, this function will create a nonce value with an algorithm and pass this value to checkDeviceSecurity() function.
You may ask that, what is the algorithm value which I have used as “Constants.SAFETY_DETECT_ALGORITHM”. You can define this algorithm value as shown in below:
Code:
object Constants{
const val BASIC_INTEGRITY = "basicIntegrity"
const val SAFETY_DETECT_ALGORITHM = "SHA1PRNG"
}
As you see, we have defined two different values. We will use these values while checking device security.
You already know where to use SAFETY_DETECT_ALGORITHM value.
We will use BASIC_INTEGRITY value to get device security situation from JSON.
If this value returns true, that means user’s device is secure.
If this value returns false, that means device is not secure or device has been rooted.
Code:
object SafetyDetectService : KoinComponent {
private val appContext: Context by inject(named("appContext"))
private val client: SafetyDetectClient = SafetyDetect.getClient(appContext)
fun isDeviceSecure(serviceListener: IServiceListener<Boolean>) {
val nonce = ByteArray(24)
try {
val random: SecureRandom = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
SecureRandom.getInstanceStrong()
else
SecureRandom.getInstance(Constants.SAFETY_DETECT_ALGORITHM)
random.nextBytes(nonce)
} catch (error: NoSuchAlgorithmException) {
serviceListener.onError(ErrorType.NO_SUCH_OBJECT)
}
checkDeviceSecurity(nonce, serviceListener)
}
private fun checkDeviceSecurity(nonce: ByteArray, serviceListener: IServiceListener<Boolean>){
client.sysIntegrity(nonce, BuildConfig.APP_ID)
.addOnSuccessListener { sysIntegrityResp ->
SafetyDetectHelper.getPayloadDetailAsJson(sysIntegrityResp)?.let { jsonObject ->
serviceListener.onSuccess(jsonObject.getBoolean(Constants.BASIC_INTEGRITY))
} ?: kotlin.run {
serviceListener.onError(ErrorType.SERVICE_FAILURE)
}
}
.addOnFailureListener {
serviceListener.onError(ErrorType.SERVICE_FAILURE)
}
}
}
As I talked about above, we need to get a json object from SysIntegrityResp object which has been returned by SysIntegrity API. To get this value, we can define a helper object and we can add all operations about getting json in here.
As you see in the below, we will send a SysIntegrityResp object as parameter and with the help of this function, we can get json object about our device security.
Code:
object SafetyDetectHelper {
fun getPayloadDetailAsJson(sysIntegrityResp: SysIntegrityResp): JSONObject? {
val jwsStr = sysIntegrityResp.result
val jwsSplit = jwsStr.split(".").toTypedArray()
val jwsPayloadStr = jwsSplit[1]
val payloadDetail = String(Base64.decode(
jwsPayloadStr.toByteArray(StandardCharsets.UTF_8), Base64.URL_SAFE),
StandardCharsets.UTF_8)
return try {
JSONObject(payloadDetail)
}catch (jsonError: JSONException){
null
}
}
}
If device is secure, we can do our next operations which we need to do. If device is not secure, we should show an error screen to user and we shouldn’t let user to start our application.
AppsCheck API
AppsCheck API helps us to determine malicious apps in user’s device. Thus, if device has some malicious apps, we will not let user to start our application for user’s security.
getMaliciousAppsList() function gives us a list of malicious app and it uses MaliciousAppsData class which has been defined by Huawei as a model class.
This API will return us a response object and this object will have the malicious apps list. If there is not any malicious apps on the device, we can return null and let user to use our application.
But if there are some malicious apps, we shouldn’t let user to start our application and we can show an error screen to user. If we would like to we can list malicious apps to user.
Note: It is better to list malicious apps and let user to delete these applications from device. That is what I am doing in my app. Also, if we would like to do more operations about malicious apps, we can define our own class like I talked about below.
Code:
object SafetyDetectService : KoinComponent {
private val appContext: Context by inject(named("appContext"))
private val client: SafetyDetectClient = SafetyDetect.getClient(appContext)
fun checkMaliciousApps(serviceListener: IServiceListener<ArrayList<MaliciousApps>?>){
client.maliciousAppsList
.addOnSuccessListener { maliciousAppsListResp ->
if(maliciousAppsListResp.rtnCode == CommonCode.OK){
val maliciousAppsList: List<MaliciousAppsData> = maliciousAppsListResp.maliciousAppsList
if(maliciousAppsList.isEmpty())
serviceListener.onSuccess(null)
else{
var maliciousApps = arrayListOf<MaliciousApps>()
for(maliciousApp in maliciousAppsList){
maliciousApp.apply {
maliciousApps.add(MaliciousApps(packageName = apkPackageName,
sha256 = apkSha256,
apkCategory = apkCategory))
}
}
serviceListener.onSuccess(maliciousApps)
}
}
}
.addOnFailureListener {
serviceListener.onError(ErrorType.SERVICE_FAILURE)
}
}
}
If we would like to do more operations like getting app icon, app name and etc. we can define our own data class.
I defined my own data class as shown in the below to do more specific operations with malicious apps.
Code:
data class MaliciousApps(
val packageName: String,
val sha256: String,
val apkCategory: Int
): KoinComponent{
private val appContext: Context = get(named("appContext"))
private val systemHelper: SystemHelper = get()
fun getAppIcon(): Drawable = systemHelper.getAppIconByPackageName(packageName)
fun getAppName(): String = systemHelper.getAppNameByPackageName(packageName)
fun getThreatDescription(): String {
return when(apkCategory){
1 -> appContext.getString(R.string.risky_app_description)
2 -> appContext.getString(R.string.virus_app_description)
else -> ""
}
}
}
Here I am just using same values with Huawei’s MaliciousAppsData class. But I added my own functions in here to get app icon, app name and threat description.
To get more information about application by package name, we can define new object called as SystemHelper and we can do these operations in here.
Code:
class SystemHelper: KoinComponent {
private val appContext: Context by inject(named("appContext"))
/**
* Getting application information by package name
* @param packageName: Package name of the app that we want to get information about
* @return ApplicationInfo class to get app icons, app names and etc. by package name
*/
private fun getAppByPackageName(packageName: String): ApplicationInfo{
return appContext.packageManager.getApplicationInfo(packageName, 0)
}
/**
* Getting application icon by package name
* @param packageName: Package name of the app which we want to get icon
* @return Icon of the application as drawable
*/
fun getAppIconByPackageName(packageName: String): Drawable{
val app = getAppByPackageName(packageName)
return appContext.packageManager.getApplicationIcon(app)
}
/**
* Getting application name by package name
* @param packageName: Package name of the app which we want to get name
* @return Name of the application as drawable
*/
fun getAppNameByPackageName(packageName: String): String{
val app = getAppByPackageName(packageName)
return appContext.packageManager.getApplicationLabel(app).toString()
}
}
When API founds malicious apps we need to list these apps to user and let user to delete these apps from device.
To do that, we can use selectedApp() function. This function will take the malicious app and ask user to delete them.
We need to detect that user has accepted to deleting application or has not. We need to start activity with result and we need to listen this result. If user really delete the application, we need to remove it from list. If there is not any malicious app on list after removing it, we can navigate user to our app.
Code:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(requestCode == DELETE_REQUEST_CODE){
when(resultCode){
Activity.RESULT_OK -> {
maliciousApps.remove(selectedMaliciousApp)
setRecyclerView()
}
Activity.RESULT_CANCELED -> {
Toast.makeText(requireContext(), requireContext().getString(R.string.should_delete_app), Toast.LENGTH_LONG).show()
}
}
}
}
private var deleteClickListener = object: DeleteClickListener{
override fun selectedApp(maliciousApp: MaliciousApps) {
var deleteIntent = Intent(Intent.ACTION_DELETE).apply {
data = Uri.parse("package:${maliciousApp.packageName}")
putExtra(Intent.EXTRA_RETURN_RESULT, true)
}
startActivityForResult(deleteIntent, DELETE_REQUEST_CODE)
}
}
To learn more about the app and examine it, you can visit my GitHub repository.
References
berkberberr/HMS-SecureWebBrowserExample: This repository is a secure web browser app which is using Huawei Mobile Services. (github.com)
Safety Detect: SysIntegrity, URLCheck, AppsCheck, UserDetect - HUAWEI Developer

Expert: Xamarin Android Weather App Highlights Ads & Analytics Kit

Overview
In this article, I will create a demo app along with the integration of HMS Ads and Analytics Kit which is based on Cross-platform Technology Xamarin. I have implemented Ads Kit and Analytics Kit. So the developer can easily monetise their efforts using Banner, Splash, Reward and Interstitial Ads also to track the user’s behaviour through the Analytics kit.
Ads Kit Service Introduction
HMS Ads kit is powered by Huawei which allows the developer to monetization services such as Banner, Splash, Reward and Interstitial Ads. HUAWEI Ads Publisher Service is a monetization service that leverages Huawei's extensive data capabilities to display targeted, high-quality ad content in your application to the vast user base of Huawei devices.
Analytics Kit Service Introduction
Analytics kit is powered by Huawei which allows rich analytics models to help you clearly understand user behaviour and gain in-depth insights into users, products, and content. As such, you can carry out data-driven operations and make strategic decisions about app marketing and product optimization.
Analytics Kit implements the following functions using data collected from apps:
1. Provides data collection and reporting APIs for collection and reporting custom events.
2. Sets up to 25 user attributes.
3. Supports automatic event collection and session calculation as well as predefined event IDs and parameters.
Prerequisite
1. Xamarin Framework
2. Huawei phone
3. Visual Studio 2019
App Gallery Integration process
1. Sign In and Create or Choose a project on AppGallery Connect portal.
{
"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"
}
2. Add SHA-256 key.
3. Navigate to Project settings and download the configuration file.
4. Navigate to General Information, and then provide Data Storage location.
5. Navigate to Manage APIs and enable APIs to require by application.
6. Navigate to Huawei Analytics > Overview > Custom dashboard > Enable Analytics
Xamarin Analytics Kit Setup Process
1. Download Xamarin Plugin of all the aar and zip files from below URL:
https://developer.huawei.com/consum...ibrary-V1/xamarin-android-0000001061360985-V1
2. Open the XHiAnalytics-5.0.5.300.sln solution in Visual Studio.
3. Navigate to Solution Explorer and right-click on jar Add > Existing Item and choose aar file which download in Step 1.
4. Choose aar file from download location.
5. Right-click on added aar file, then choose Properties > Build Action > LibraryProjectZip.
Note: Repeat Step 3 and 4 for all aar file.
6. Build the Library and make DLL files.
Xamarin Ads Kit Setup Process
1. Download Xamarin Plugin of all the aar and zip files from below URL:
https://developer.huawei.com/consum..._TOPIC_0000001050175494__section1134316505481
2. Open the XAdsIdentifier-3.4.35.300.sln solution in Visual Studio.
3. Navigate to Solution Explorer and right-click on jar Add > Existing Item and choose aar file which download in Step 1.
4. Choose aar file from download location.
5. Right-click on added aar file, then choose Properties > Build Action > LibraryProjectZip.
Note: Repeat Step 3 and 4 for all aar file.
6. Build the Library and make DLL files.
Xamarin App Development
1. Open Visual Studio 2019 and Create A New Project.
2. Navigate to Solution Explore > Project > Add > Add New Folder.
3. Navigate to Folder(created) > Add > Add Existing and add all DLL files.
Read full article in forum
Ads Kit Integration
Banner Ads Integration Procedure
Kindly refer to the below link:
https://developer.huawei.com/consum...in-Guides/xamarin-banner-ads-0000001050418457
Reward Ads Integration Procedure
Kindly refer to the below link:
https://developer.huawei.com/consum...-Guides/xamarin-rewarded-ads-0000001050178541
Interstitial Ads Integration Procedure
Kindly refer to the below link:
https://developer.huawei.com/consum...ugin-Guides/interstitial-ads-0000001050176486
Splash Ads Integration Procedure
Kindly refer to the below link:
https://developer.huawei.com/consum...in-Guides/xamarin-splash-ads-0000001050418461
Analytics Kit Integration
Initializing Analytics Kit Procedure
Kindly refer to the below link:
https://developer.huawei.com/consum...-Plugin-Guides/initanalytics-0000001050141599
LoginActivity.cs
This activity performs all the operation regarding login with Huawei Id along with display banner ads at bottom of the screen along with track analytics events.
C#:
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
using Android.Support.V4.App;
using Android.Support.V4.Content;
using Android.Support.V7.App;
using Android.Util;
using Android.Views;
using Android.Widget;
using Com.Huawei.Agconnect.Config;
using Com.Huawei.Hmf.Tasks;
using Com.Huawei.Hms.Ads;
using Com.Huawei.Hms.Ads.Banner;
using Com.Huawei.Hms.Ads.Nativead;
using Com.Huawei.Hms.Analytics;
using Com.Huawei.Hms.Common;
using Com.Huawei.Hms.Support.Hwid;
using Com.Huawei.Hms.Support.Hwid.Request;
using Com.Huawei.Hms.Support.Hwid.Result;
using Com.Huawei.Hms.Support.Hwid.Service;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WeatherAppDemo
{
[Activity(Label = "LoginActivity", Theme = "@style/AppTheme", MainLauncher = true)]
public class LoginActivity : AppCompatActivity
{
private static String TAG = "LoginActivity";
private HuaweiIdAuthParams mAuthParam;
public static IHuaweiIdAuthService mAuthManager;
// private NativeAd nativeAd;
private Button btnLoginWithHuaweiId;
HiAnalyticsInstance instance;
InterstitialAd interstitialAd;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
SetContentView(Resource.Layout.login_activity);
loadBannerAds();
HiAnalyticsTools.EnableLog();
// Generate the Analytics Instance
instance = HiAnalytics.GetInstance(this);
// You can also use Context initialization
// Context context = ApplicationContext;
// instance = HiAnalytics.GetInstance(context);
// Enable collection capability
instance.SetAnalyticsEnabled(true);
btnLoginWithHuaweiId = FindViewById<Button>(Resource.Id.btn_huawei_id);
btnLoginWithHuaweiId.Click += delegate
{
// Write code for Huawei id button click
mAuthParam = new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DefaultAuthRequestParam)
.SetIdToken().SetEmail()
.SetAccessToken()
.CreateParams();
mAuthManager = HuaweiIdAuthManager.GetService(this, mAuthParam);
StartActivityForResult(mAuthManager.SignInIntent, 1011);
string text = "Login Clicked";
Toast.MakeText(Android.App.Application.Context, text, ToastLength.Short).Show();
// Initiate Parameters
Bundle bundle = new Bundle();
bundle.PutString("text", text);
instance.OnEvent("ButtonClickEvent", bundle);
navigateToHomeScreen();
};
checkPermission(new string[] { Android.Manifest.Permission.Internet,
Android.Manifest.Permission.AccessNetworkState,
Android.Manifest.Permission.ReadSms,
Android.Manifest.Permission.ReceiveSms,
Android.Manifest.Permission.SendSms,
Android.Manifest.Permission.BroadcastSms}, 100);
}
private void loadBannerAds()
{
// Obtain BannerView based on the configuration in layout
BannerView bottomBannerView = FindViewById<BannerView>(Resource.Id.hw_banner_view);
bottomBannerView.AdListener = new AdsListener();
AdParam adParam = new AdParam.Builder().Build();
bottomBannerView.LoadAd(adParam);
// Obtain BannerView using coding
BannerView topBannerview = new BannerView(this);
topBannerview.AdId = "testw6vs28auh3";
topBannerview.BannerAdSize = BannerAdSize.BannerSize32050;
topBannerview.LoadAd(adParam);
}
private void LoadInterstitialAd()
{
InterstitialAd interstitialAd = new InterstitialAd(this);
interstitialAd.AdId = "testb4znbuh3n2"; //testb4znbuh3n2 is a dedicated test ad slot ID.
AdParam adParam = new AdParam.Builder().Build();
interstitialAd.LoadAd(adParam);
}
private void ShowInterstitial()
{
interstitialAd.AdListener = new AdsListenerInterstitial(this);
// Display an interstitial ad.
if (interstitialAd != null && interstitialAd.IsLoaded)
{
interstitialAd.Show();
}
else
{
// The ad was not loaded.
}
}
private class AdsListenerInterstitial : AdListener
{
LoginActivity interstitialActivity;
public AdsListenerInterstitial(LoginActivity interstitialActivity)
{
this.interstitialActivity = interstitialActivity;
}
public override void OnAdClicked()
{
// Called when an ad is clicked.
}
public override void OnAdClosed()
{
// Called when an ad is closed.
}
public override void OnAdFailed(int errorCode)
{
// Called when an ad fails to be loaded.
}
public override void OnAdLeave()
{
// Called when a user leaves an ad.
}
public override void OnAdLoaded()
{
// Called when an ad is loaded successfully.
// Display an interstitial ad.
interstitialActivity.ShowInterstitial();
}
public override void OnAdOpened()
{
// Called when an ad is opened.
}
}
public void checkPermission(string[] permissions, int requestCode)
{
foreach (string permission in permissions)
{
if (ContextCompat.CheckSelfPermission(this, permission) == Permission.Denied)
{
ActivityCompat.RequestPermissions(this, permissions, requestCode);
}
}
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
protected override void AttachBaseContext(Context context)
{
base.AttachBaseContext(context);
AGConnectServicesConfig config = AGConnectServicesConfig.FromContext(context);
config.OverlayWith(new HmsLazyInputStream(context));
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == 1011 || requestCode == 1022)
{
//login success
Task authHuaweiIdTask = HuaweiIdAuthManager.ParseAuthResultFromIntent(data);
if (authHuaweiIdTask.IsSuccessful)
{
AuthHuaweiId huaweiAccount = (AuthHuaweiId)authHuaweiIdTask.TaskResult();
Log.Info(TAG, "signIn get code success.");
Log.Info(TAG, "ServerAuthCode: " + huaweiAccount.AuthorizationCode);
Toast.MakeText(Android.App.Application.Context, "SignIn Success", ToastLength.Short).Show();
// navigateToHomeScreen(huaweiAccount);
}
else
{
Log.Info(TAG, "signIn failed: " + ((ApiException)authHuaweiIdTask.Exception).StatusCode);
Toast.MakeText(Android.App.Application.Context, ((ApiException)authHuaweiIdTask.Exception).StatusCode.ToString(), ToastLength.Short).Show();
Toast.MakeText(Android.App.Application.Context, "SignIn Failed", ToastLength.Short).Show();
}
}
}
private void showLogoutButton()
{
/*logout.Visibility = Android.Views.ViewStates.Visible;*/
}
private void hideLogoutButton()
{
/*logout.Visibility = Android.Views.ViewStates.Gone;*/
}
private void navigateToHomeScreen(/*AuthHuaweiId data*/)
{
Intent intent = new Intent(this, typeof(MainActivity));
/*intent.PutExtra("name", data.DisplayName.ToString());
intent.PutExtra("email", data.Email.ToString());
intent.PutExtra("image", data.PhotoUriString.ToString());*/
StartActivity(intent);
Finish();
}
private class AdsListener : AdListener
{
public override void OnAdClicked()
{
// Called when a user taps an ad.
Log.Info(TAG, "Ad Clicked");
Toast.MakeText(Application.Context, "Ad Clicked", ToastLength.Short).Show();
}
public override void OnAdClosed()
{
// Called when an ad is closed.
Log.Info(TAG, "Ad Closed");
Toast.MakeText(Application.Context, "Ad Closed", ToastLength.Short).Show();
}
public override void OnAdFailed(int errorCode)
{
// Called when an ad fails to be loaded.
Log.Info(TAG, "Ad Failed");
Toast.MakeText(Application.Context, "Ad Failed", ToastLength.Short).Show();
}
public override void OnAdLeave()
{
// Called when a user has left the app.
Log.Info(TAG, "Ad Leave");
/*Toast.MakeText(Android.App.Application.Context, "Ad Leave", ToastLength.Short).Show();*/
}
public override void OnAdOpened()
{
// Called when an ad is opened.
Log.Info(TAG, "Ad Opened");
/*Toast.MakeText(Android.App.Application.Context, "Ad Opened", ToastLength.Short).Show();*/
}
public override void OnAdLoaded()
{
// Called when an ad is loaded successfully.
Log.Info(TAG, "Ad Loaded");
Toast.MakeText(Application.Context, "Ad Loaded", ToastLength.Short).Show();
}
}
}
}
Tips and Tricks
1. On mobile phones whose value of targetSdkVersion is 28 or later, ad video assets may fail to be downloaded. In this case, you need to configure the app to allow HTTP network requests. For details, please refer to Configuring Network Permissions.
2. Xamarin requires the ADB daemon to be started over port 5037. If the ADB daemon runs on a different port, Visual Studio will not be able to detect your device.
Conclusion
In this article, we have learned how to integrate HMS Ads and Analytics Kit in Xamarin based Android application. We can display ads and track the user’s event in the application.
Thanks for reading this article.
Be sure to like and comments on this article, if you found it helpful. It means a lot to me.
References
https://developer.huawei.com/consum...-Guides/service-introduction-0000001050178531
https://developer.huawei.com/consum..._TOPIC_0000001050175494__section1134316505481
https://developer.huawei.com/consum...S-Plugin-Guides/introduction-0000001050139636
https://forums.developer.huawei.com/forumPortal/en/topic/0204485009808440045
Read full article in forum

Make Your Apps More Secure with the Safety SDK

Hi everyone,
In this article, I will talk about the security SDK development in a single code base structure for Huawei Safety Detect and Google Safety Net services, which will make your applications more secure. Thanks to this SDK, Huawei Safety Detect service with HMS (Huawei Mobile Services) and stages with GMS (Google Mobile Services) can be run compatible with Google Safety Net package for 2 platforms.
{
"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"
}
Within the scope of the SDK, we will include the following features;
User Detect: With this feature, you can make your application more secure by checking whether the users using our application are fake users. This feature is a very important and frequently used feature for banks and many e-commerce applications.
Root Detection: With this feature, it allows you to make the application more secure by checking whether the device running the application is a rooted device. It is critically important, especially for applications in the banking industry.
Huawei Safety Detect Service​Huawei Safety Detect service, as I mentioned at the beginning of my article, is a security service that allows you to make your applications more secure and protect against security threats.You can find detailed information about Huawei Safety Detect service here.
Google Safety Net Service​Safety Net is a service that provides a set of services and APIs that help protect your app against security threats, including bad URLs, potentially harmful apps, and rogue users.You can find detailed information about the Google Safety Net service here.
Adding a Module
First, let’s create a new module where we will do all the improvements. Let’s create a new module by choosing File -> New -> New Module -> Android Library and name it safety. After this step, we need to add dependencies to the build.gradle file of our module.
build.gradle(safety)
Code:
implementation 'com.huawei.hms:safetydetect:5.0.5.302'
implementation 'com.google.android.gms:play-services safetynet:17.0.0'
After creating a new module and adding the necessary dependencies, we can now start SDK development.
First of all, we create our interface, which contains the functions that we will use jointly for both platforms (Google-Huawei). Next, we will create the Device class, which will allow us to find the Mapper class and the mobile service type installed on the device.
Code:
interface SafetyService {
fun userDetect(appKey : String,callback: SafetyServiceCallback<SafetyServiceResponse>)
fun rootDetection(appKey: String,callback: SafetyRootDetectionCallback<RootDetectionResponse> )
interface SafetyServiceCallback<T>{
fun onSuccessUserDetect(result: T? = null)
fun onFailUserDetect(e: java.lang.Exception)
}
interface SafetyRootDetectionCallback<T>{
fun onSuccessRootDetect(result: T? = null)
fun onFailRootDetect(e: java.lang.Exception)
}
object Factory {
fun create(context: Context): SafetyService {
return when (Device.getMobileServiceType(context)) {
MobileServiceType.GMS -> {
GoogleSafetyServiceImpl(context)
}
MobileServiceType.HMS -> {
HuaweiSafetyServiceImpl(context)
}
else -> {
throw Exception("Unknown service")
}
}
}
}
}
As seen above, we create methods and callbacks that will perform both user detect and root detection. Then, in the create method, we check the service availability on the device from the Device class and work the Google or Huawei SafetyServiceImpl classes.
Code:
enum class MobileServiceType {
HMS,
GMS,
NON
}
object Device {
/**
* Mobile services availability of devices
*
* @return Device mobile service type enum
*/
fun getMobileServiceType(
context: Context,
firstPriority: MobileServiceType? = null
): MobileServiceType {
val gms: Boolean = GoogleApiAvailability.getInstance()
.isGooglePlayServicesAvailable(context) == com.google.android.gms.common.ConnectionResult.SUCCESS
val hms: Boolean = HuaweiApiAvailability.getInstance()
.isHuaweiMobileServicesAvailable(context) == com.huawei.hms.api.ConnectionResult.SUCCESS
return if (gms && hms) {
firstPriority ?: MobileServiceType.HMS
} else if (gms) {
MobileServiceType.GMS
} else if (hms) {
MobileServiceType.HMS
} else {
MobileServiceType.NON
}
}
After these operations, we must create the Mapper class in order to parse the objects that we send and receive from the services as parameters, and the other classes we need to define.
Code:
abstract class Mapper<I, O> {
abstract fun map(from: I): O
}
After this step, we must define separate Mapper classes for Google and Huawei. For example, as a result of user detect operation, responseToken object is returned to us as Google Safety Net API and Huawei Safety Detect service return parameter. Thanks to our mapper class, we will be able to parse it into our response class, which we will create when it returns from Google or Huawei service.
Code:
class GoogleSafetyMapper: Mapper<SafetyNetApi.RecaptchaTokenResponse, SafetyServiceResponse>() {
override fun map(from: SafetyNetApi.RecaptchaTokenResponse): SafetyServiceResponse = SafetyServiceResponse(
responseToken = from.tokenResult
)
}
Code:
class HuaweiSafetyMapper : Mapper<UserDetectResponse, SafetyServiceResponse>() {
override fun map(from: UserDetectResponse): SafetyServiceResponse = SafetyServiceResponse(
responseToken = from.responseToken
)
}
As seen in the codes above, Huawei Safety Detect service returns UserDetectResponse and Google Safety Net service returns RecaptchaTokenResponse objects for the result of user detect operation. We will return the SafetyServiceResponse object in our SDK.
Code:
data class SafetyServiceResponse(
val responseToken: String
)
We should do the same for the root detection feature. We will create our RootDetectionResponse class, which will enable us to parse objects returned from Google or Huawei service by creating mapper classes for root detection.
Code:
data class RootDetectionResponse(
val apkDigestSha256: String,
val apkPackageName: String,
val basicIntegrity: Boolean,
val nonce: String,
val timestampMs: Long
)
Next we need to create our mapper classes for Google and Huawei. SafetyNet and Safety Detect services return Json object as response parameter. Here, instead of sending a json object, we will use the parsed version of the json object in our SDK.
Code:
class GoogleRootDetectMapper : Mapper<JSONObject,RootDetectionResponse>() {
override fun map(from: JSONObject): RootDetectionResponse = RootDetectionResponse(
apkDigestSha256 = from.getString("apkDigestSha256"),
apkPackageName = from.getString("apkPackageName"),
basicIntegrity = from.getBoolean("basicIntegrity"),
nonce = from.getString("nonce"),
timestampMs = from.getLong("timestampMs")
)
}
Code:
class HuaweiRootDetectMapper : Mapper<JSONObject, RootDetectionResponse>(){
override fun map(from: JSONObject): RootDetectionResponse = RootDetectionResponse(
apkDigestSha256 = from.getString("apkDigestSha256"),
apkPackageName = from.getString("apkPackageName"),
basicIntegrity = from.getBoolean("basicIntegrity"),
nonce = from.getString("nonce"),
timestampMs = from.getLong("timestampMs")
)
}
After all these steps, we will now create our SafetyServiceImpl classes, which we will implement our interface and add functionality to our functions. It must be created separately for both Google and Huawei.
Code:
class GoogleSafetyServiceImpl(private val context: Context): SafetyService {
private val mapper: Mapper<SafetyNetApi.RecaptchaTokenResponse, SafetyServiceResponse> = GoogleSafetyMapper()
private val rootDetectMapper: Mapper<JSONObject, RootDetectionResponse> = GoogleRootDetectMapper()
override fun userDetect(appKey: String,callback: SafetyService.SafetyServiceCallback<SafetyServiceResponse>){
/**
* App key value is the SITE_API_KEY value in Google Mobile Services.
*/
SafetyNet.getClient(context).verifyWithRecaptcha(appKey)
.addOnSuccessListener(){
val responseToken = it.tokenResult
if(responseToken.isNotEmpty()){
callback.onSuccessUserDetect(mapper.map(it))
}
}.addOnFailureListener(){
callback.onFailUserDetect(it)
}
}
override fun rootDetection(
appKey: String,
callback: SafetyService.SafetyRootDetectionCallback<RootDetectionResponse>
){
val nonce = ByteArray(24)
try {
val random: SecureRandom = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
SecureRandom.getInstanceStrong()
} else {
SecureRandom.getInstance("SHA1PRNG")
}
random.nextBytes(nonce)
} catch (e: NoSuchAlgorithmException) {
Log.e(TAG, e.message!!)
}
SafetyNet.getClient(context).attest(nonce, appKey)
.addOnSuccessListener{ result ->
val jwsStr = result.jwsResult
val jwsSplit = jwsStr.split(".").toTypedArray()
val jwsPayloadStr = jwsSplit[1]
val payloadDetail = String(Base64.decode(jwsPayloadStr.toByteArray(StandardCharsets.UTF_8), Base64.URL_SAFE), StandardCharsets.UTF_8)
val jsonObject = JSONObject(payloadDetail)
callback.onSuccessRootDetect(rootDetectMapper.map(jsonObject))
}.addOnFailureListener{ e->
callback.onFailRootDetect(e)
}
}
}
As can be seen in our SafetyServiceImpl class created for the Google side above, functionality has been added to the user detection and root detection methods by implementing the methods we created in the interface. In cases where there is onSuccess() in user detect and root detection processes, we transfer the response returned from the SafetyNet API to our own response class with mapper, thanks to the callbacks we created in our interface. As a result of this process, objects returned from services are transferred to our response class that we created in our SDK.
The important issue here is that the appKey value is different in Google and Huawei services. It corresponds to the SITE_API_KEY value on the Google side. The SITE_API_KEY value needs to be generated by the reCAPTCHA API Console. Thanks to this console, you can prevent risky login attempts in your application, etc. You can track many metrics.
For the Huawei side, we should also create our Huawei Safety ServiceImpl class.
Code:
class HuaweiSafetyServiceImpl(private val context: Context): SafetyService {
private val mapper: Mapper<UserDetectResponse, SafetyServiceResponse> = HuaweiSafetyMapper()
private val rootDetectMapper: Mapper<JSONObject, RootDetectionResponse> = HuaweiRootDetectMapper()
val TAG = "CommonMobileServicesSafetySDK"
/**
App key value is the app_id value in Huawei Mobile Services.
*/
override fun userDetect(
appKey: String,
callback: SafetyService.SafetyServiceCallback<SafetyServiceResponse>
){
val client = SafetyDetect.getClient(context)
client.userDetection(appKey).addOnSuccessListener {
val responseToken = it.responseToken
if(responseToken.isNotEmpty()){
callback.onSuccessUserDetect(mapper.map(it))
}
}.addOnFailureListener {
callback.onFailUserDetect(it)
}
}
@SuppressLint("LongLogTag")
override fun rootDetection(
appKey: String,
callback: SafetyService.SafetyRootDetectionCallback<RootDetectionResponse>
) {
val nonce = ByteArray(24)
try {
val random: SecureRandom = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
SecureRandom.getInstanceStrong()
} else {
SecureRandom.getInstance("SHA1PRNG")
}
random.nextBytes(nonce)
} catch (e: NoSuchAlgorithmException) {
Log.e(TAG, e.message!!)
}
SafetyDetect.getClient(context)
.sysIntegrity(nonce, appKey)
.addOnSuccessListener { result ->
val jwsStr = result.result
val jwsSplit = jwsStr.split(".").toTypedArray()
val jwsPayloadStr = jwsSplit[1]
val payloadDetail = String(Base64.decode(jwsPayloadStr.toByteArray(StandardCharsets.UTF_8), Base64.URL_SAFE), StandardCharsets.UTF_8)
val jsonObject = JSONObject(payloadDetail)
callback.onSuccessRootDetect(rootDetectMapper.map(jsonObject))
}
.addOnFailureListener { e ->
callback.onFailRootDetect(e)
}
}
}
In the Huawei Safety Detect service, the appKey value corresponds to the appId value.
On the root detection side, the SITE_API_KEY value is created from the Google API Console. In the Huawei Safety service, it also corresponds to the appId value.
After all these steps, we have completed the developments on the SDK side. After implementing the SDK in a different project so that we can test it, you can use it as follows.
Code:
private var safetyService = SafetyService.Factory.create(requireContext())
appKey = if(Device.getMobileServiceType(requireContext())== MobileServiceType.GMS){
this.getString(R.string.google_site_api_key)
}
else{
this.getString(R.string.app_id)
}
safetyService?.userDetect(appKey, object : SafetyService.SafetyServiceCallback<SafetyServiceResponse> {
override fun onFailUserDetect(e: Exception) {
Toast.makeText(requireContext(), e.toString(), Toast.LENGTH_SHORT).show()
}
override fun onSuccessUserDetect(result: SafetyServiceResponse?) {
viewModel.signInWithEmail(email, password)
}
})
safetyService?.rootDetection(appKey, object : SafetyService.SafetyRootDetectionCallback<RootDetectionResponse> {
override fun onFailRootDetect(e: Exception) {
Toast.makeText(applicationContext,e.toString(),Toast.LENGTH_SHORT).show()
}
override fun onSuccessRootDetect(result: RootDetectionResponse?) {
if(result!= null){
if(result.basicIntegrity){
showSecurityAlertMessage(getString(R.string.root_device_info),"Info",true)
}
else{
showSecurityAlertMessage(getString(R.string.no_root_device_error),"Security Warning",false)
}
}
}
})
As seen in the example code above, we set our appKey value according to the service availability on the device, thanks to the Device class we created in the SDK. Here, if the device is GMS, we set the API_KEY values that we created from Google reCaptcha and Api Console, and set the appId value to the appKey value if it is HMS. We can easily use the user detect and root detection features by calling the methods we will use in the next step, thanks to the interface we created in our SDK.
You can find screenshots of user detect and root detect features of a different application using the SDK.
Tips and Tricks
During SDK development, all common methods should be handled by interfaces.
App key value is app id for Huawei services, SITE_API_KEY value generated from Google Api Console for Google services.
Conclusion
In this article, I tried to explain how the services used for security in Google and Huawei services can be developed by making them compatible with both GMS and HMS devices and combining them under a single SDK. I hope it was a useful article for everyone. Thank you for taking the time to read.
References
Google Safety Net API
Huawei Safety Detect Service
Original Source

How to achieve Place Search and Marker Clustering Implementation in Map App

Background​Lots of apps these days include an in-app map feature and the ability to mark places of interest on the map. HMS Core Map Kit enables you to implement such capabilities for your apps. With Map Kit, you can first draw a map and then add markers to the map, as well as configure the map to cluster markers depending on the level of zoom. This article will show you how to implement searching for nearby places using the keyword search capability of Site Kit and display the results on the map.
Application scenarios:
A travel app that allows users to search for scenic spots and shows the results on a map.
2.A bicycle sharing app that can show users nearby bicycles on a map.
Key functions used in the project:
Location service: Use Location Kit to obtain the current longitude-latitude coordinates of a device.
Keyword search: Use Site Kit to search for places such as scenic spots, businesses, and schools in the specified geographical area based on the specified keyword.
Map display: Use Map Kit to draw a map. Marker clustering: Use Map Kit to add markers to the map and configure the map to cluster markers depending on the level of zoom.
Integration Preparations​1.Register as a developer and create a project in AppGallery Connect.
(1)Register as a developer Registration URL
{
"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"
}
(2)Create an app, add the SHA-256 signing certificate fingerprint, enable Map Kit and Site Kit, and download the agconnect-services.json file of the app.
2.Integrate the Map SDK and Site SDK.
(1)Copy the agconnect-services.json file to the app's directory of your project.
Go to allprojects > repositories and configure the Maven repository address for the HMS Core SDK.
Go to buildscript > repositories and configure the Maven repository address for the HMS Core SDK.
If the agconnect-services.json file has been added to the app, go to buildscript > dependencies and add the AppGallery Connect plugin configuration.
Code:
buildscript {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.huawei.agconnect:agcp:1.3.1.300'
}
}
allprojects {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
}
}
(2)Add build dependencies in the dependencies block.
Code:
dependencies {
implementation 'com.huawei.hms:maps:{version}'
implementation 'com.huawei.hms:site:{version}'
implementation 'com.huawei.hms:location:{version}'
}
(3)Add the following configuration to the file header:
Code:
apply plugin: 'com.huawei.agconnect'
(4)Copy the signing certificate generated in Generating a Signing Certificate to the app directory of your project, and configure the signing certificate in android in the build.gradle file.
Code:
signingConfigs {
release {
// Signing certificate.
storeFile file("**.**")
// KeyStore password.
storePassword "******"
// Key alias.
keyAlias "******"
// Key password.
keyPassword "******"
v2SigningEnabled true
v2SigningEnabled true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
debuggable true
}
debug {
debuggable true
}
}
Main Code and Used Functions​1.Use Location Kit to obtain the device location.
Code:
private void getMyLoction() {
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
mLocationRequest = new LocationRequest();
builder.addLocationRequest(mLocationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
//Check the device location settings.
settingsClient.checkLocationSettings(locationSettingsRequest)
.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
//Initiate location requests when the location settings meet the requirements.
fusedLocationProviderClient
.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
// Processing when the API call is successful.
Log.d(TAG, "onSuccess: " + aVoid);
}
});
}
})
2.Implement the text search function using Site Kit to search for nearby places.
Code:
SearchResultListener<TextSearchResponse> resultListener = new SearchResultListener<TextSearchResponse>() {
// Return search results upon a successful search.
@Override
public void onSearchResult(TextSearchResponse results) {
List<Site> siteList;
if (results == null || results.getTotalCount() <= 0 || (siteList = results.getSites()) == null
|| siteList.size() <= 0) {
resultTextView.setText("Result is Empty!");
return;
}
updateClusterData(siteList);// Mark places on the map.
}
// Return the result code and description upon a search exception.
@Override
public void onSearchError(SearchStatus status) {
resultTextView.setText("Error : " + status.getErrorCode() + " " + status.getErrorMessage());
}
};
// Call the place search API.
searchService.textSearch(request, resultListener);
3.Draw a map
Code:
@Override
public void onMapReady(HuaweiMap huaweiMap) {
hMap = huaweiMap;
hMap.moveCamera(CameraUpdateFactory.newLatLngZoom(Constants.sMylatLng, 1));
hMap.setMyLocationEnabled(true);
hMap.getUiSettings().setMyLocationButtonEnabled(true);
initCluster(huaweiMap);
}
4.Cluster markers on the map.
Code:
private ClusterManager<MyItem> mClusterManager;
List<MyItem> items = new ArrayList<>();
private void initCluster(HuaweiMap hMap) {
mClusterManager = new ClusterManager<>(this, hMap);
hMap.setOnCameraIdleListener(mClusterManager);
// Add a custom InfoWindowAdapter by setting it to the MarkerManager.Collection object from
// ClusterManager rather than from GoogleMap.setInfoWindowAdapter
//refer: https://github.com/billtom20/3rd-maps-utils
mClusterManager.getMarkerCollection().setInfoWindowAdapter(new HuaweiMap.InfoWindowAdapter() {
@Override
public View getInfoWindow(Marker marker) {
final LayoutInflater inflater = LayoutInflater.from(SearchClusterActivity.this);
final View view = inflater.inflate(R.layout.custom_marker_window, null);
final TextView textView = view.findViewById(R.id.textViewTitle);
String text = (marker.getTitle() != null) ? marker.getTitle() : "Cluster Item";
textView.setText(text);
return view;
}
@Override
public View getInfoContents(Marker marker) {
return null;
}
});
}
// Update clustered markers.
private void updateClusterData(List<Site> siteList) {
items = new ArrayList<>();
mClusterManager.clearItems();
for (Site s:
siteList) {
Coordinate location = s.getLocation();
MyItem myItem = new MyItem(location.lat,location.lng,s.name,s.formatAddress);
items.add(myItem);
}
mClusterManager.addItems(items);
Coordinate coordinate = siteList.get(0).getLocation();
LatLng latLng = new LatLng(coordinate.lat,coordinate.lng);
mClusterManager.cluster();
hMap.animateCamera(CameraUpdateFactory.newLatLngZoom (latLng,14 ));
}
Results​Enter a place or service in the Query box and tap Search. The figures below show how the search results are displayed as markers on the map.
The preceding four figures show the effect of searching for food and school, as well as the marker clustering effect at different zoom levels. Congratulations, you have now successfully integrated place search and marker clustering into your in-app map.
References​For more details, you can go to:official website
Development Documentation page, to find the documents you need
Reddit to join our developer discussion
GitHub to download sample codes
Stack Overflow to solve any integration problems
Thanks for sharing..

Pygmy Collection Application Part 4 (Analytics Kit Custom Events)

Introduction​
In my last article, I have explained how to integrate an account kit finance application. Have a look into Pygmy collection application Part 1 (Account kit).
In this article, we will learn how to integrate Analytics kit kit in Pygmy collection finance application.
Adding Events with Huawei Analytics Kit
This guide walks you through the process of building application that uses Huawei Analytics Kit to trigger event and can find data on the console.
What You Will Build
You will build an application that triggers events, setting user properties, logging custom event etc.
What You Need
About 10 minutes
A favorite text editor or IDE(For me Android Studio)
JDK 1.8 or later
Gradle 4+
SDK platform 19
What is Mobile analytics?
Mobile analytics captures data from mobile app, website, and web app visitors to identify unique users, track their journeys, record their behaviour, and report on the app’s performance. Similar to traditional web analytics, mobile analytics are used to improve conversions, and are the key to crafting world-class mobile experiences.
How to complete this guide
When a person says that I know theoretical concept, only when he/she knows the answer for all WH questions. To complete this guide, lets understand all WH questions.
1. Who has to use analytics?
2. Which one to use?
3. What is Huawei Analytics kit?
4. When to use HMS Analytics kit?
5. Why to use analytics kit?
6. Where to use analytics Kit?
Once you get answer for all the above questions, then you will get theoretical knowledge. But to understand with result you should know answer for below question.
1. How to integrate Huawei analytics kit?
Who has to use the analytics kit?
The answer is very simple, the analytics kit will be used in the mobile/web application. So off course software developer has to use analytics kit.
Which one to use?
Since there are many analytics vendors in the market. But for mobile application I recommend Huawei analytics kit. Now definitely you will have question why? To answer this I’ll give some reasons.
Very easy to integrate.
Documentation is too good.
Community is too good. Response from community is so fast.
Moreover, it is very similar to other vendors, so no need to learn new things.
You can see events in real time.
What is Huawei Analytics kit?
Flutter Analytics plugin enables the communication between HMS Core analytics SDK and Flutter platform. This plugin exposed all the functionality which is provided by HMS core analytics SDK.
Huawei Analytics kit offers you a range of analytics models that helps you to analyse the users’ behaviour with predefined and custom events, you can gain a deeper insight into your users, products and content. It helps you to gain insight into that how users behave on different platforms based on the user behaviour events and user attributes reported through apps.
Huawei Analytics kit, our one-stop analytics platform provides developers with intelligent, convenient and powerful analytics capabilities, using this we can optimize apps performance and identify marketing channels.
Collect and report custom events.
Set a maximum of 25 user attributes.
Automate event collection and session calculation.
Preset event IDs and parameters.
When to use HMS Analytics kit?
Mobile app analytics are a developer’s best friend. It helps you gain understanding about that how users’ behaviour and app can be optimized to reach your goals. Without mobile app analytics, you would be trying out different things blindly without any data to back up your experiments.
That’s why it’s extremely important for developers to understand their mobile app analytics to track their progress while working towards achieving their goals.
Why to use analytics kit?
Mobile app analytics are essential to development process for many reasons. They give you insights into that how users are using your app, which parts of the app they interact with, and what actions they take within the app. You can use these insights to come up with an action plan to improve your product in future, like adding new features that the users seem to need, or improve existing ones in a way that would make the users lives easier, or removing features that the users don’t seem to use.
You’ll also gain insights into whether you’re achieving your goals for your mobile app, whether its revenue, awareness, or other KPIs, and then take the data you have to adjust your strategy and optimize your app to reach your further goals.
When it comes to why? Always everyone thinks about benefits.
Benefits of Analytics
App analytics helps you to drive ROI over every aspect of performance.
App analytics helps you to gather accurate data to better serve for customers.
App analytics allows you to drive personalized and customer-focused marketing.
App analytics allowss you to track individual and group achievements of marketing goals from campaigns.
App analytics offers data-driven insights into issues concerning churn and retention.
Where to use analytics Kit?
This is very important question, because you already know why to use the analytics kit. So wherever you want understand about user behaviour, which part of the application users are using regularly, which functionality of the application users are using more. In the scenario you can use analytics kit in either mobile/web application you can use the analytics kit.
Now start with practical
Till now you understood theoretical concept of the analytics kit. Now let’s start with the practical example, to understand about practical we should get answer for the below question.
How to integrate Huawei analytics kit in Android finance application?
To achieve this you need to follow couple of steps as follows.
1. Configure application on the AGC.
2. Client application development process.
Configure application on the AGC
Follow the steps.
Step 1: We need to register as a developer account in AppGallery Connect. If you are already developer ignore this step.
Step 2: Create an app by referring to Creating a Project and Creating an App in the Project
Step 3: Set the data storage location based on current location.
Step 4: Enabling Analytics Kit. Project setting > Manage API > Enable analytics kit toggle button.
Step 5: Generating a Signing Certificate Fingerprint.
Step 6: Configuring the Signing Certificate Fingerprint.
Step 7: Download your agconnect-services.json file, paste it into the app root directory.
Client application development process
Follow the steps.
Step 1: Create Android application in the Android studio (Any IDE which is your favorite)
Step 2: Add the App level gradle dependencies. Choose inside project Android > app > build.gradle.
How to integrate Ads Kit
1. Configure the application on the AGC.
2. Client application development process.
3. Testing a Splash Ad.
Client application development process
Follow the steps.
Step 1: Create an Android application in the Android studio (Any IDE which is your favorite).
Step 2: Add the App level Gradle dependencies. Choose inside project Android > app > build.gradle.
Code:
apply plugin: 'com.android.application'
apply plugin: 'com.huawei.agconnect'
dependencies {
implementation 'com.huawei.hms:hianalytics:5.1.0.300'
}
Root level gradle dependencies.
Code:
maven { url 'https://developer.huawei.com/repo/' }
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
Step 3: To allow HTTP and HTTPS network requests on devices with targetSdkVersion 28 or later, configure the following information in the AndroidManifest.xml file:
XML:
<application
...
android:usesCleartextTraffic="true"
>
...
</application>
Step 4: Initialize Ads kit activity or application class.
Step 5: Build Application.
HuaweiUserProperty.java
Java:
public class HuaweiUserProperty {
public enum KeyName {
USER_CUSTOMER_ID("user_session_id"),
USER_PHONE_NUMBER("user_phone_number");
String textValue;
KeyName(String textValue) {
this.textValue = textValue;
}
public String textValue() {
return textValue;
}
}
}
HuaweiEvenParams.java
Java:
public enum HuaweiEventParams {
temp;
public enum EventName {
TAP("tap"),
OPEN("open");
String textValue;
EventName(String textValue) {
this.textValue = textValue;
}
public String textValue() {
return textValue;
}
}
public enum Key {
PREVIOUS_SCREEN_NAME("previous_screen_name"),
SCREEN_NAME("screen_name"),
UI_ELEMENT("ui_element_name"),
DESCRIPTION("description_key"),
PARENT_SCREEN_NAME("parent_screen_name"),
CUSTOMER_ID("customer_id"),
MODEL_NUMBER("model_number");
String textValue;
Key() {
}
Key(String textValue) {
this.textValue = textValue;
}
String textValue() {
return this.textValue;
}
}
public enum ScreenName {
PLATFORM_APP_LAUNCHER("platform_app_launcher"),
GRANT_PERMISSION_DIALOG_SCREEN("grant_permission_dialog_screen"),
CONFIGURATION_SCREEN("configuration_screen"),
MAIN_SPLASH("main_splash"),
LOGIN_SCREEN("login_screen"),
COLLECTION_SCREEN("collection_screen"),
PHONE_NUMBER_SCREEN("phone_number_screen"),
PHONE_CONF_POPUP("phone_number_confirmation_popup"),
OTP_SCREEN("otp_screen"),
PROFILE_POPUP("profile_popup"),
SOCIAL_MEDIA_LOGIN("social_media_login_screen"),
MAIN_HOME_DASHBOARD("main_home_dashboard"),
MAIN_HOME_NAVIGATION("main_home_navigation"),
PROFILE_SCREEN("profile_screen"),
IMAGE_SELECTION_POPUP("image_selection_popup"),
PHONE_NUMBER_POPUP("phone_number_popup"),
FEEDBACK_SCREEN("feedback_screen"),
NAVIGATION_SCREEN("navigation_screen");
String textValue;
ScreenName(String textValue) {
this.textValue = textValue;
}
String textValue() {
return this.textValue;
}
}
public enum Description {
BACKGROUND_POPUP("background_popup"),
OPEN_PHONE_NUMBER_SCREEN("open_phone_number_screen"),
OPEN_TERMS_AND_CONDITION_SCREEN("open_terms_and_condition"),
OPEN_PHONE_NUMBER_CONFIRMATION_POPUP("open_phone_number_confirmation_popup"),
OPEN_OTP_SCREEN("open_otp_screen"),
PHONE_NUMBER_SCREEN("phone_number_screen"),
OPEN_PROFILE_POPUP("open_profile_popup"),
SOCIAL_MEDIA_LOGIN_SCREEN("social_media_login_screen"),
MAIN_HOME_DASHBOARD("main_home_dashboard"),
OPEN_PROFILE_SCREEN("open_profile_screen"),
OPEN_RECONNECTION_POPUP("open_reconnection_popup"),
OPEN_MAIN_HOME_NAVIGATION("open_main_home_navigation"),
OPEN_IMAGE_SELECTION_POPUP("open_image_selection_popup"),
EDIT_PHONE_NUMBER_POPUP("edit_phone_number_popup"),
OPEN_GALLERY("open_gallery"),
OPEN_CAMERA("open_camera"),
OPEN_CONTACT_SCREEN("open_contact_screen"),
OPEN_SHARE_SCREEN("show_share_screen"),
OPEN_LOGIN_SCREEN("open_login_screen"),
OPEN_HOME_SCREEN("open_home_screen")
;
String textValue;
Description(String textValue) {
this.textValue = textValue;
}
String textValue() {
return this.textValue;
}
}
public enum UiElementName {
SWIPE_LEFT("swipe_left"),
SWIPE_RIGHT("swipe_right"),
SKIP_BUTTON("skip_button"),
NEXT_BUTTON("next_button"),
OK_BUTTON("ok_button"),
CANCEL_BUTTON("cancel_button"),
RESEND_OTP_BUTTON("resend_button"),
GALLERY_BUTTON("gallery_button"),
CATURE_FROM_CAMERA_BUTTON("cature_from_camera_button"),
DONE_BUTTON("done_button"),
COLLECTION_BUTTON("collection_button"),
GALLARY_BUTTON("gallary_button");
String textValue;
UiElementName(String textValue) {
this.textValue = textValue;
}
String textValue() {
return this.textValue;
}
}
}
HuaweiLog.java
Java:
import android.os.Bundle;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class HuaweiLog {
private HuaweiEventParams.EventName eventName;
private HashMap<String, String> data = new HashMap<>();
private HashMap<String, ArrayList> testdata = new HashMap<>();
public HuaweiLog() {
}
public HuaweiEventParams.EventName getEventName() {
return eventName;
}
public HuaweiLog setEventName(HuaweiEventParams.EventName eventName) {
this.eventName = eventName;
return this;
}
public HuaweiLog setPreviousScreenName(HuaweiEventParams.ScreenName previousScreenName) {
data.put(HuaweiEventParams.Key.PREVIOUS_SCREEN_NAME.textValue(), previousScreenName.textValue());
return this;
}
public HuaweiLog setDescription(HuaweiEventParams.Description description) {
data.put(HuaweiEventParams.Key.DESCRIPTION.textValue(), description.textValue());
return this;
}
public HuaweiLog setDescription(String description) {
data.put(HuaweiEventParams.Key.DESCRIPTION.textValue(), description);
return this;
}
public HuaweiLog setCustomerId(String cId) {
data.put(HuaweiEventParams.Key.CUSTOMER_ID.textValue(), cId);
return this;
}
public HuaweiLog setCustomerMobileNumber(String mobileNumber) {
data.put(HuaweiEventParams.Key.CUSTOMER_ID.textValue(), mobileNumber);
return this;
}
public HuaweiLog setParentScreenName(HuaweiEventParams.ScreenName parentScreenName) {
data.put(HuaweiEventParams.Key.PARENT_SCREEN_NAME.textValue(), parentScreenName.textValue());
return this;
}
public HuaweiLog setScreenName(HuaweiEventParams.ScreenName screenName) {
data.put(HuaweiEventParams.Key.SCREEN_NAME.textValue(), screenName.textValue());
return this;
}
public HuaweiLog setScreenName(String screenName) {
data.put(HuaweiEventParams.Key.SCREEN_NAME.textValue(), screenName);
return this;
}
public HuaweiLog setUiElementName(String uiElementName) {
data.put(HuaweiEventParams.Key.UI_ELEMENT.textValue(), uiElementName);
return this;
}
public HuaweiLog setUiElementName(HuaweiEventParams.UiElementName uiElementName) {
data.put(HuaweiEventParams.Key.UI_ELEMENT.textValue(), uiElementName.textValue());
return this;
}
public HuaweiLog setKeyAndValue(String key, String value) {
data.put(key, value);
return this;
}
public Bundle toBundle() {
Bundle bundle = new Bundle();
try {
if (data != null && data.size() > 0) {
for (Map.Entry<String, String> entry : data.entrySet()) {
bundle.putString(entry.getKey(), entry.getValue());
Log.d("Huawei",entry.getKey()+" "+ entry.getValue());
}
}
} catch (Exception e) {
e.printStackTrace();
}
return bundle;
}
public HuaweiLog setTestDescription(ArrayList list) {
testdata.put(HuaweiEventParams.Key.DESCRIPTION.textValue(), list);
return this;
}
}
HuaweiAnalyticsClient.java
Java:
import android.content.Context;
import android.util.Log;
import com.huawei.hms.analytics.HiAnalytics;
import com.huawei.hms.analytics.HiAnalyticsInstance;
import com.huawei.hms.analytics.type.ReportPolicy;
import com.shea.pygmycollection.utils.UserDataUtils;
import java.util.HashSet;
import java.util.Set;
public class HuaweiAnalyticsClient {
private static final String TAG = HuaweiAnalyticsClient.class.getSimpleName();
private static HuaweiAnalyticsClient ourInstance;
private static HiAnalyticsInstance mHuaweiAnalyticsClient;
private HuaweiAnalyticsClient() {
}
public static HuaweiAnalyticsClient getInstance() {
if (ourInstance == null) {
ourInstance = new HuaweiAnalyticsClient();
}
return ourInstance;
}
public void initAnalytics(Context context) {
mHuaweiAnalyticsClient = HiAnalytics.getInstance(context);
if (mHuaweiAnalyticsClient == null) {
Log.e(TAG, "Analytics Client could not be initialized.");
return;
}
mHuaweiAnalyticsClient.setAnalyticsEnabled(true);
mHuaweiAnalyticsClient.setUserId("UserId");
mHuaweiAnalyticsClient.setAutoCollectionEnabled(true);
if (UserDataUtils.getUserData(context) != null) {
if (UserDataUtils.getUserId(context) != 0) {
Integer userId = UserDataUtils.getUserId(context);
Log.d(TAG, "initAnalytics is called");
if (userId != null && userId != 0) {
setHuaweiUserId(String.valueOf(userId));
putHuaweiUserProperty(HuaweiUserProperty.KeyName.USER_PHONE_NUMBER, UserDataUtils.getUserPhoneNumber(context));
} else {
setHuaweiUserId("UNKNOWN");
putHuaweiUserProperty(HuaweiUserProperty.KeyName.USER_PHONE_NUMBER, UserDataUtils.getUserPhoneNumber(context));
}
} else {
setHuaweiUserId("UNKNOWN_USER");
putHuaweiUserProperty(HuaweiUserProperty.KeyName.USER_PHONE_NUMBER, UserDataUtils.getUserPhoneNumber(context));
}
}
// Used to report an event upon app switching to the background.
ReportPolicy moveBackgroundPolicy = ReportPolicy.ON_MOVE_BACKGROUND_POLICY;
// Used to report an event at the specified interval.
ReportPolicy scheduledTimePolicy = ReportPolicy.ON_SCHEDULED_TIME_POLICY;
// Set the event reporting interval to 600 seconds.
scheduledTimePolicy.setThreshold(600);
Set<ReportPolicy> reportPolicies = new HashSet<>();
// Add the ON_SCHEDULED_TIME_POLICY and ON_MOVE_BACKGROUND_POLICY policies.
reportPolicies.add(scheduledTimePolicy);
reportPolicies.add(moveBackgroundPolicy);
// Set the ON_MOVE_BACKGROUND_POLICY and ON_SCHEDULED_TIME_POLICY policies.
mHuaweiAnalyticsClient.setReportPolicies(reportPolicies);
}
public void logEvent(HuaweiLog log) {
if (mHuaweiAnalyticsClient == null) {
throw new RuntimeException("HuaweiAnalyticsClient is not initialized. Please call initAnalytics().");
}
try {
mHuaweiAnalyticsClient.onEvent(log.getEventName().textValue(), log.toBundle());
Log.d("Huawei", log.getEventName().textValue());
} catch (Exception e) {
Log.d(TAG, "Huawei analytics failed" + e.getMessage());
}
}
public void putHuaweiUserProperty(HuaweiUserProperty.KeyName propertyKey, String value) {
if (mHuaweiAnalyticsClient == null) {
throw new RuntimeException("HuaweiAnalyticsClient is not initialized. Please call initAnalytics().");
}
try {
mHuaweiAnalyticsClient.setUserProfile(propertyKey.textValue(), value);
} catch (Exception e) {
Log.d(TAG, "Huawei analytics failed", e);
}
}
public void setHuaweiUserId(String userId) {
if (mHuaweiAnalyticsClient == null) {
throw new RuntimeException("HuaweiAnalyticsClient is not initialized. Please call initAnalytics().");
}
if (userId == null) {
mHuaweiAnalyticsClient.setUserId(null);
return;
}
mHuaweiAnalyticsClient.setUserId(userId);
}
}
AnalyticsUtils.java
Java:
import android.util.Log;
public class AnalyticUtils {
private static final String TAG = AnalyticUtils.class.getSimpleName();
public static void logHuaweiAnalyticEvent(HuaweiLog huaweiLog) {
try {
HuaweiAnalyticsClient.getInstance().logEvent(huaweiLog);
Log.d(TAG, "Huawei analytics " + huaweiLog.toString());
} catch (Exception e) {
Log.d(TAG, "Huawei analytics failed");
}
}
}
Now log the events in activity/fragments/dialog
Java:
AnalyticUtils.logHuaweiAnalyticEvent(new HuaweiLog()
.setScreenName(HuaweiEventParams.ScreenName.MAIN_SPLASH)
.setDescription(HuaweiEventParams.Description.OPEN_SHARE_SCREEN)
.setEventName(HuaweiEventParams.EventName.OPEN)
.setUiElementName(HuaweiEventParams.UiElementName.GALLARY_BUTTON)
);
Java:
AnalyticUtils.logHuaweiAnalyticEvent(new HuaweiLog()
.setScreenName(HuaweiEventParams.ScreenName.COLLECTION_SCREEN)
.setDescription(HuaweiEventParams.Description.OPEN_HOME_SCREEN)
.setEventName(HuaweiEventParams.EventName.TAP)
.setUiElementName(HuaweiEventParams.UiElementName.COLLECTION_BUTTON)
);
Result​
{
"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"
}
Tips and Tricks​
Make sure you added agconnect-service.json file.
Add internet permission in AndroidManifest.xml
Add the below code to download the HMS core apk
XML:
<application ...>
<meta-data
android:name="com.huawei.hms.client.channel.androidMarket"
android:value="false" />
...
</application>
​Conclusion​
In this article, we have learnt what is analytics, why to use analytics kit, where to use, how to use, how to integrate HMS analytics kit and how to add custom events.
Reference​
Huawei Analytics
Thanks for sharing!!!

Categories

Resources