Introduction
In this article, we will cover Integration of Huawei Kit in Unity Project using Official Plugin (Huawei HMS Core App Services). Here we will cover below Kits. With Huawei Game Service, you will have access to a range of development capabilities. You can promote your game quickly and efficiently to Huawei's vast user base by users sign in with their Huawei IDs. You can also use the service to quickly implement achievements, game events, and game addiction prevention functions, build basic game capabilities at a low cost, and perform in-depth game operations based on user and content localization.
Game Service provides the following basic functions for your game apps, with which you can quickly build basic game capabilities.
Game Service Login
Achievements
Leader Board Data
Current Player Info
Game Event begin and end
Development Overview
You need to install Unity software and I assume that you have prior knowledge about the unity and C#.
Hardware Requirements
A computer (desktop or laptop) running Windows 10.
A Huawei phone (with the USB cable), which is used for debugging.
Software Requirements
Java JDK installation package.
Unity software installed.
Visual Studio/Code installed.
HMS Core (APK) 4.X or later.
Follows the steps.
1. Create Unity Project.
Open unity Hub.
Click NEW, select3D, Project Name and Location.
Click CREATE, as follows:
{
"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. Click Asset Store, search Huawei HMS Core App Servicesand click Import, as follows.
3. Once import is successful, verify directory in Assets> Huawei HMS Core App Services path, as follows.
4. Choose Edit > Project Settings > Player and edit the required options in Publishing Settings, as follows.
5. Generate a SHA-256 certificate fingerprint.
To generating SHA-256 certificate fingerprint use below command.
Code:
keytool -list -v -keystore D:\Unity\projects_unity\file_name.keystore -alias alias_name
6. Download agconnect-services.json and copy and paste to Assets > Plugins > Android, as follows.
7. Choose Project Settings > Player and update package name.
8. Open LauncherTemplate.gradle and add below lines.
Java:
apply plugin: 'com.huawei.agconnect'
Java:
implementation 'com.huawei.agconnect:agconnect-core:1.4.2.300'
implementation 'com.huawei.hms:base:5.0.5.300'
implementation 'com.huawei.hms:hwid:5.0.5.301'
implementation 'com.huawei.hms:game:5.0.4.302'
9. Open "baseProjectTemplate.gradle" and add lines, as follows.
Java:
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
Java:
maven {url 'https://developer.huawei.com/repo/'}
10. Open "mainTemplate.gradle" and add lines, as follows.
Java:
implementation 'com.huawei.agconnect:agconnect-core:1.4.2.300'
implementation 'com.huawei.hms:base:5.0.5.300'
implementation 'com.huawei.hms:hwid:5.0.5.301'
implementation 'com.huawei.hms:game:5.0.4.302'
11. Open AndroidManifest file and add below permissions.
Java:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
12. Create Scripts folder and create a class.
HmsGameService.cs
Java:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
using HuaweiService;
using UnityEngine.HuaweiAppGallery;
using UnityEngine.HuaweiAppGallery.Listener;
using UnityEngine.HuaweiAppGallery.Model;
using UnityEngine.SceneManagement;
public class HmsGameService : MonoBehaviour
{
// Start is called before the first frame update
private ILoginListener iLoginListener = new LoginListener();
public Text userName;
public Button ButtonLogout;
public Button ButtonLogin;
public Button ButtonGetPlayerInfo;
static string user,sessionId;
static string playerId,guid;
private static List<string> achievementIds = new List<string>();
void Start()
{
HuaweiGameService.AppInit();
}
// Update is called once per frame
void Update()
{
StartCoroutine(UpdateUICoroutine());
}
public void GetAchievements()
{
string guid = System.Guid.NewGuid().ToString();
HuaweiGameService.GetAchievementList(true, new MyGetAchievementListListener());
}
public void GetLeaderBoardData(){
string guid = System.Guid.NewGuid().ToString();
HuaweiGameService.GetAllLeaderboardsIntent(new MyGetLeaderboardIntentListener());
}
public class MyGetLeaderboardIntentListener : IGetLeaderboardIntentListener
{
public void OnSuccess(AndroidJavaObject intent)
{
var msg = "Get leader board intent succeed";
Debug.Log(msg);
user = msg;
}
public void OnFailure(int code, string message)
{
var msg = "Get leaderboard failed, code:" + code + " message:" + message;
Debug.Log(msg);
user = msg;
}
}
public void GetInfo(){
HuaweiGameService.GetCurrentPlayer(true, new MyGetCurrentPlayer());
}
public class MyGetAchievementListListener : IGetAchievementListListener
{
public void OnSuccess(List<Achievement> achievementList)
{
string message = "Achievement count :" + achievementList.Count + "\n";
achievementIds = new List<string>();
foreach (var achievement in achievementList)
{
message += string.Format(
"id:{0}, type:{1}, name:{2}, description:{3} \n",
achievement.AchievementId,
achievement.Type,
achievement.Name,
achievement.Description
);
achievementIds.Add(achievement.AchievementId);
}
user = message;
}
public void OnFailure(int code, string message)
{
string msg = "get achievement list failed, code:" + code + " message:" + message;
user = msg;
}
}
void display(){
userName.text = user;
}
void display(string name)
{
userName.text = name;
}
IEnumerator UpdateUICoroutine() {
//yield on a new YieldInstruction that waits for 5 seconds.
yield return new WaitForSeconds(3);
display();
}
public void onLoginClick()
{
Debug.Log("starting Init");
HuaweiGameService.Init();
Debug.Log("starting login");
HuaweiGameService.Login(iLoginListener);
Debug.Log("finshed login");
}
public class LoginListener : ILoginListener
{
public void OnSuccess(SignInAccountProxy signInAccountProxy)
{
user = "Wel-come "+signInAccountProxy.DisplayName;
}
public void OnFailure(int code, string message)
{
string msg = "login failed, code:" + code + " message:" + message;
Debug.Log(msg);
}
public void OnSignOut(){
}
}
public class MyGetCurrentPlayer : IGetPlayerListener
{
public void OnSuccess(Player player)
{
string msg = "Player ID: " + player.PlayerId +"\nPlayer Name : "+ player.DisplayName;
playerId = player.PlayerId;
Debug.Log(msg);
user = msg;
}
public void OnFailure(int code, string message)
{
string msg = "Get Current Player failed, code:" + code + " message:" + message;
Debug.Log("OnFailure :"+msg);
user = msg;
}
}
public class MyLeaderboardSwitchStatus : ILeaderboardSwitchStatusListener
{
public void OnSuccess(int statusValue)
{
string msg = "LeaderboardSwitchStatus Success: " + statusValue;
Debug.Log(msg);
user = msg;
}
public void OnFailure(int code, string message)
{
string msg = "LeaderboardSwitchStatus failed, code:" + code + " message:" + message;
Debug.Log(msg);
user = msg;
}
}
public class MySubmitPlayerEventBegin : ISubmitPlayerEventListener
{
public void OnSuccess(string jsonRequest)
{
string msg = "submitPlayerEventBegin Success, player info: " + jsonRequest;
ConvertMessageData data = JsonUtility.FromJson<ConvertMessageData>(jsonRequest);
Debug.Log(msg);
sessionId = data.transactionId;
if(sessionId !=null){
HuaweiGameService.GetPlayerExtraInfo(sessionId, new MyGetPlayerExtraInfo());
}
}
public void OnFailure(int code, string message)
{
string msg = "submitPlayerEventBegin failed, code:" + code + " message:" + message;
Debug.Log(msg);
}
public class ConvertMessageData
{
public string transactionId;
}
}
public class MyGetPlayerExtraInfo : IGetPlayerExtraInfoListener
{
public void OnSuccess(AndroidJavaObject jo)
{
string msg = "getPlayerInfo Success, player info: " + jo.ToString();
Debug.Log(msg);
}
public void OnFailure(int code, string message)
{
string msg = "getPlayerInfo failed, code:" + code + " message:" + message;
Debug.Log(msg);
user = msg;
}
public void OnSuccess(PlayerExtraInfo playerExtraInfo)
{
string msg = "getPlayerInfo Success, player info: " + playerExtraInfo.ToString();
Debug.Log(msg);
user = msg;
}
}
}
AndroidManifest.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<!-- GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application>
<activity android:name="com.unity3d.player.UnityPlayerActivity"
android:theme="@style/UnityThemeSelector">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
</application>
</manifest>
13. Follow the steps, as shown in image:
a. Assign HmsGameService script to Canvas.
b. Select Button and add onclick event.
c. Assign button to button handler.
14. Onclick Button Handler you find your script HmsGameService (As per your script name) and attach method as per below screen shot.
15. To build apk and run in device, choose File > Build Settings > Build for apk or Build and Run into connected device.
Result
1. Click on Login Button you can see, it will login into game service as per below screenshot.
2. Click on Player Info, Leader Board and Achievement button you and see result as per below screenshot.
Tips and Tricks
Always use the latest version of the library.
Add agconnect-services.json file without fail.
Add SHA-256 fingerprint without fail.
Make sure dependencies added in build files.
Add Achievements and LeaderBoard details before run.
Conclusion
We have learnt integration of HMS Game Service Kit into Unity Game development. You have successfully built a game app and learned how to.
Use Huawei Game Service.
Use Huawei Game Service to develop the game sign-in function.
Use Huawei Game Service to develop the game addiction prevention function.
Thanks for reading the article, please do like and comment your queries or suggestions.
References
Game Service: https://developer.huawei.com/consum.../HMSCore-Guides/introduction-0000001050121216
Unity Manual : https://docs.unity.cn/cn/Packages-cn/[email protected]/manual/gameservices.html
Will it work on non huawei device?
Related
More information like this, you can visit HUAWEI Developer Forum
In this article, we will integrate various sign-in options in our single android application using Huawei Account kit and Google Sign-In.
Use case:
To allow user to sign in either by Huawei account or Google account by if device has HMS or GMS respectively.
Allow user to sign in using Huawei if device has HMS.
Allow user to sign in using Google if device has GMS.
{
"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"
}
Huawei Account kit
Prerequisite
1) You must have Huawei developer account.
2) Huawei phone with HMS 4.0.0.300 or later
3) Android Studio, Jdk 1.8, SDK platform 26 and Gradle 4.6 installed.
Setup:
1) Create a project in android studio.
2) Get the SHA-256 Key.
3) Create an app in the Huawei app gallery connect.
4) Enable account kit setting in Manage APIs section.
5) Provide the SHA-256 Key in App Information Section.
6) Provide storage location.
7) Enable Huwaei account under Auth Service in AGC
8) After completing all the above points we need to download the agconnect-services.json from App Information Section. Place the json file in the app folder of the android project.
9) Enter the below maven url inside the repositories of buildscript and allprojects respectively ( project build.gradle file )
Code:
maven { url 'http://developer.huawei.com/repo/' }
10) Enter the below plugin in the app build.gradle file
Code:
apply plugin: 'com.huawei.agconnect'
dependencies {
implementation 'com.huawei.hms:hwid:4.0.0.300'
}
11) Now Sync the gradle.
Implementation
1) In this article, we will implement Authorization code method.
Code:
HuaweiIdAuthParams authParams = new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setAuthorizationCode().createParams();
huaweiservice = HuaweiIdAuthManager.getService(MainActivity.this, authParams);
startActivityForResult(huaweiservice.getSignInIntent(), HUAWEI_SIGNIN);
2) To Process the sign-in result after the authorization is complete.
Code:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == HUAWEI_SIGNIN) {
com.huawei.hmf.tasks.Task<AuthHuaweiId> authHuaweiIdTask = HuaweiIdAuthManager.parseAuthResultFromIntent(data);
if (authHuaweiIdTask.isSuccessful()) {
//The sign-in is successful, and the user's HUAWEI ID information and authorization code are obtained.
AuthHuaweiId huaweiAccount = authHuaweiIdTask.getResult();
Log.i(TAG, "Authorization code:" + huaweiAccount.getAuthorizationCode());
Log.d(TAG, "name: " + huaweiAccount.getDisplayName());
Log.d(TAG, "email: " + huaweiAccount.getEmail());
Log.d(TAG , "avatar : "+huaweiAccount.getAvatarUriString());
launchLoggedinActivity(huaweiAccount.getFamilyName() , huaweiAccount.getGivenName() , huaweiAccount.getAvatarUriString(),"huawei");
} else {
// The sign-in failed.
Log.e(TAG, "sign in failed : " + ((com.huawei.hms.common.ApiException) authHuaweiIdTask.getException()).getStatusCode());
}
}
}
3) To handle silent Sign-in
The authorization is required only on first registration with the HUAWEI ID. Then no approval is required for subsequent registrations with the same HUAWEI ID.
Code:
private void handleHuaweiSilentSignIn() {
HuaweiIdAuthParams authParams = new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM).createParams();
HuaweiIdAuthService service = HuaweiIdAuthManager.getService(MainActivity.this, authParams);
com.huawei.hmf.tasks.Task<AuthHuaweiId> task = service.silentSignIn();
task.addOnSuccessListener(new OnSuccessListener<AuthHuaweiId>() {
@Override
public void onSuccess(AuthHuaweiId authHuaweiId) {
// Obtain the user's HUAWEI ID information.
Log.i(TAG, "displayName:" + authHuaweiId.getDisplayName());
launchLoggedinActivity(authHuaweiId.getFamilyName() , authHuaweiId.getGivenName() , authHuaweiId.getAvatarUriString(),"huawei");
}
});
task.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
// The sign-in failed. Try to sign in explicitly using getSignInIntent().
if (e instanceof ApiException) {
ApiException apiException = (ApiException)e;
Log.i(TAG, "sign failed status:" + apiException.getStatusCode());
}
}
});
}
4) To sign out from Huawei account
Code:
Task<Void> signOutTask = service.signOut();
signOutTask.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(Task<Void> task) {
Log.i(TAG, "signOut complete");
}
});
5) To revoke authorization
Code:
service.cancelAuthorization().addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(Task<Void> task) {
if (task.isSuccessful()) {
// Processing after a successful authorization revoking.
Log.i(TAG, "onSuccess: ");
} else {
// Handle the exception.
Exception exception = task.getException();
if (exception instanceof ApiException){
int statusCode = ((ApiException) exception).getStatusCode();
Log.i(TAG, "onFailure: " + statusCode);
}
}
}
Google Sign in
1) To add google play services, In your projects root-level build.gradle file, ensure that Googles Maven repository is included:
Code:
allprojects {
repositories {
google()
// If you're using a version of Gradle lower than 4.1, you must instead use:
// maven {
// url 'https://maven.google.com'
// }:
}
}
2) In app-level build.gradle file, declare Google Play services as a dependency:
Code:
dependencies {
implementation 'com.google.android.gms:play-services-auth:18.1.0'
}
3) To specify your app's SHA-1 fingerprint, go to Settings page of the Firebase console. Refer to Authenticating Your Client for details on how to get your app's SHA-1 fingerprint.
4) Enable Google Sign-In in the Firebase console:
In the Firebase console, open the Auth section.
On Sign in method tab, enable the Google sign-in method and click Save.
5) To Configure Google Sign-in and the GoogleSignInClient object.
Code:
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).requestEmail().build();
// Build a GoogleSignInClient with the options specified by gso.
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
6) To check for an existing sign-in user.
Code:
// Check for existing Google Sign In account, if the user is already signed in
// the GoogleSignInAccount will be non-null.
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
updateUI(account);
If GoogleSignInAccount instanse is not null, user is already signed in.
7) On click of google sign in button, we will create a sign-in intent with the getSignInIntent method, and starting the intent with startActivityForResult.
Code:
private View.OnClickListener googleClickListner = new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, RC_SIGN_IN);
}
};
8) To process the sign in result.
Code:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInClient.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
// The Task returned from this call is always completed, no need to attach
// a listener.
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
handleGoogleSignInResult(task);
}
} private void handleGoogleSignInResult(Task<GoogleSignInAccount> completedTask) {
try {
GoogleSignInAccount account = completedTask.getResult(ApiException.class);
Log.d(TAG, "name: " + account.getDisplayName());
Log.d(TAG, "email: " + account.getEmail());
Log.d(TAG , "avatar : "+account.getPhotoUrl());
launchLoggedinActivity(account.getGivenName(), account.getFamilyName(),account.getPhotoUrl()!=null ? account.getPhotoUrl().toString():null, "google");
} catch (ApiException e) {
// The ApiException status code indicates the detailed failure reason.
// Please refer to the GoogleSignInStatusCodes class reference for more information.
Log.w(TAG, "signInResult:failed code=" + e.getStatusCode());
}
}
9) Code snippet for sign out from google is
Code:
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
GoogleSignInClient googleSignInClient = GoogleSignIn.getClient(LoggedInActivity.this, gso);
googleSignInClient.signOut();
Huawei and Google Sign in Button Integration
Add the following code in activity_main.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:visibility="gone"
android:id="@+id/login_layout"
android:orientation="vertical">
<com.google.android.gms.common.SignInButton
android:id="@+id/sign_in_button"
android:layout_width="242dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:visibility="gone"
android:layout_gravity="center_horizontal"
android:layout_height="wrap_content" />
<com.huawei.hms.support.hwid.ui.HuaweiIdAuthButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/hwi_sign_in"
android:layout_gravity="center_horizontal"
android:visibility="gone"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:background="#3b5998"
app:hwid_button_theme="hwid_button_theme_full_title"
app:hwid_corner_radius="hwid_corner_radius_small"
/>
</LinearLayout>
</RelativeLayout>
Permissions:
Add the following permissions in manifest.
Code:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
To check if device has HMS or GMS installed.
Code:
public class Utils {
public static boolean isSignedIn = false;
public static boolean isGooglePlayServicesAvailable(Activity activity) {
GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();
int status = googleApiAvailability.isGooglePlayServicesAvailable(activity);
if(status != ConnectionResult.SUCCESS) {
if(googleApiAvailability.isUserResolvableError(status)) {
googleApiAvailability.getErrorDialog(activity, status, 2404).show();
}
return false;
}
return true;
}
public static boolean isHuaweiMobileServicesAvailable(Context context) {
if (HuaweiApiAvailability.getInstance().isHuaweiMobileServicesAvailable(context) == ConnectionResult.SUCCESS){
return true;
}
return false;
}
public static boolean isDeviceHuaweiManufacturer () {
String manufacturer = Build.MANUFACTURER;
Log.d("Device : " , manufacturer);
if (manufacturer.toLowerCase().contains("huawei")) {
return true;
}
return false;
}
}
Conclusion
We have developed a single application to allow sign in using either by Huawei or google.
Reference
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/introduction-0000001050048870
https://developers.google.com/identity/sign-in/android/start-integrating
More information like this, you can visit HUAWEI Developer Forum
In this article we are going to take a look at Huawei Mobile Services (HMS) Push Kit Plugin for Xamarin.Android then we will send our first notification and data message by Huawei Console. After that we will also send them by Push Kit APIs.
{
"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"
}
HUAWEI Push Kit
Push Kit, is a messaging service provided by Huawei for developers. It offers sending real time notifications and information messages. This helps developers maintain closer ties with users and increases user awareness and engagement. Furthermore, you are free to use on any different meaningful purposes.
HUAWEI Push Kit Xamarin.Android Integration
First of all, you need to be a Huawei Developer to use Huawei Push Kit. If you do not have a HUAWEI ID, register as a Huawei Developer and complete real-name authentication. For details, see Registering as a Developer.
Next, Sign in to AppGallery Connect using the approved Huawei ID and click on the “My projects” button.
Then click the “Add project” button and enter a name for your project.
After that, set project data storage location. For this Project Setting > General information > Project > Data storage location. As a location choose Germany then submit it. Afterwards, click “Add app” button in the same page then fill all the fields (if you do not know what “Package name” is just copy from Xamarin.Android Solution > Project > Properties >AndroidManifest.xml > package) after that submit.
Adding Push Kit to Your Xamarin.Android App
Firstly, we must generate the “.keystore” file. You can copy following text into batch file and change toolpath and aliasName then run it in “C:\Program Files\Java\jdk1.8.0\bin” folder. For details, see Pre-development Procedure.
Code:
SET toolPath="C:\tmp\tool.jks"
SET aliasName=aliasname
keytool -genkey -keystore %toolPath% -alias %aliasName% -keyalg RSA -dname "o=Huawei"
pause
keytool -list -v -keystore %toolPath%
pause
Keep these Alias name and SHA256 code. Open the project in Visual Studio then Properties of project afterwards fill the fields. It would be better to do this for both Debug and Release because later when you release the project you have to fill these areas.
Now, it is turn to use SHA256 fingerprint. Copy it and paste SHA-256 certificate fingerprint section then click to tick icon to save it.
Next, download “agconnect-services.json” file, afterwards right click on “Assets” folder in your project then Add > Existing Item and choose this file. At last enable the Push Kit.
Adding HUAWEI Push Kit Plugins in Our Project
Firstly, you need to create Android Binding Libraries for Xamarin. For this, see Creating Android Binding Libraries for Xamarin.
Secondly, you need to add these libraries to your project. For this, see Integrating the Xamarin HMS Push Kit Libraries.
Finally, HUAWEI Push Kit requires some permissions to work correctly. For this right click your project >Properties > Android Manifest then scroll to the bottom of the page. Enable following permissions.
· ACCESS_NETWORK_STATE
· INTERNET
· WAKE_LOCK
· DEFAULT (android.intent.category)
· BROWSABLE (android.intent.category)
· DEFAULT (android.permission)
Integrating HMS Core SDK
Add new class as “HmsLazyInputStream.cs” then paste following code.
Code:
using System;
using System.IO;
using Android.Util;
using Android.Content;
using Com.Huawei.Agconnect.Config;
namespace XamarinHmsPushDemo.Hmssample
{
class HmsLazyInputStream : LazyInputStream
{
public HmsLazyInputStream(Context context) : base(context)
{
}
public override Stream Get(Context context)
{
try
{
return context.Assets.Open("agconnect-services.json");
}
catch (Exception e)
{
Log.Error(e.ToString(), "Can't open agconnect file");
return null;
}
}
}
}
Next, add “using Com.Huawei.Agconnect.Config;” library in your MainActivity class afterwards add following code.
Code:
protected override void AttachBaseContext(Context context)
{
base.AttachBaseContext(context);
AGConnectServicesConfig config = AGConnectServicesConfig.FromContext(context);
config.OverlayWith(new HmsLazyInputStream(context));
}
Push Notification
When we send push notification, phone shows this notification on Notification Center. Before we send notification by HUAWEI Push Kit, first the device needs to get a push token.
Add following method into your MainActivity class afterwards call from OnCreate() method then copy the token from Output.
Code:
private void GetToken()
{
System.Threading.Thread thread = new System.Threading.Thread(() =>
{
try
{
string appid = AGConnectServicesConfig.FromContext(this).GetString("client/app_id");
string token = HmsInstanceId.GetInstance(this).GetToken(appid, "HCM");
Log.Info("token", token);
}
catch (Exception e)
{
Log.Info("token", e.ToString());
}
}
);
thread.Start();
}
Open your project in AppGallery Connect then Growing > Push Kit > Add notification. Fill the areas as you wish then click “Test effect” button and paste your token there.
Data Message
When we send data message to a device, OnMessageReceived method will be triggered then we can use this message. In this example we will send data message and show on application.
To receive a push data message and call other related Push Kit APIs, first you need to create a class that implements “HmsMessageService”. You can use all the code in this link but I will just use omitted OnMessageReceived method for clarity. Furthermore, I want to show you this message on Toast therefore we will also add MyBroadcastReceiver class. Moreover you should get instance of MyBroadcastReceiver in OnCreate method.
Code:
using Android.App;
using Android.Content;
using Android.Widget;
using Com.Huawei.Hms.Push;
namespace PushDemo
{
[Service]
[IntentFilter(new[] { "com.huawei.push.action.MESSAGING_EVENT" })]
public class MyMessagingService:HmsMessageService
{
private readonly static string PUSHDEMO_ACTION = "com.companyname.pushdemo.action";
public override void OnMessageReceived(RemoteMessage message)
{
Intent intent = new Intent(PUSHDEMO_ACTION);
intent.PutExtra("msg", message.Data);
SendBroadcast(intent);
}
}
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { "com.companyname.pushdemo.action" })]
public class MyBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Toast.MakeText(context, intent.GetStringExtra("msg"), ToastLength.Long).Show();
}
}
}
You will get the Toast, when you click Test effect then OK.
Using Push Kit APIs
We have sent notification and data message by HUAWEI console, now it is time to send it by HUAWEI Push Kit APIs. At this part main point is showing sample code. You can use this sample code on your other application (WFA, Web APIs, and Web Site etc.). Here is a sample code and little bit modify on GetToken and OnCreate :
Code:
using Android.App;
using Android.OS;
using Android.Support.V7.App;
using Android.Runtime;
using Android.Widget;
using Com.Huawei.Agconnect.Config;
using Android.Content;
using XamarinHmsPushDemo.Hmssample;
using Com.Huawei.Hms.Aaid;
using Android.Util;
using System;
using System.Collections.Generic;
using System.Net.Http;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.Text;
using System.Threading.Tasks;
namespace PushDemoForArticle
{
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
string tokenFromGetToken;//GetToken()
string appID = "appID";//AppGallery Connect > Project Setting > App information > App ID
string appKey = "APIkey";//AppGallery Connect > Project Setting > App information > App key
private static readonly HttpClient client = new HttpClient();
Button btnGetToken;
Button btnNotification;
Button btnDataMessage;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
SetContentView(Resource.Layout.activity_main);
btnGetToken = FindViewById<Button>(Resource.Id.btnGetToken);
btnGetToken.Click += (sender, args) => GetToken();
btnNotification = FindViewById<Button>(Resource.Id.btnNotification);
btnNotification.Click += (sender, args) => SendNotification();
btnDataMessage = FindViewById<Button>(Resource.Id.btnDataMessage);
btnDataMessage.Click += (sender, args) => SendDataMessage();
MyBroadcastReceiver myReceiver = new MyBroadcastReceiver();
}
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));
}
private void GetToken()
{
System.Threading.Thread thread = new System.Threading.Thread(() =>
{
try
{
string appid = AGConnectServicesConfig.FromContext(this).GetString("client/app_id");
tokenFromGetToken = HmsInstanceId.GetInstance(this).GetToken(appid, "HCM");
Log.Info("token", tokenFromGetToken);
RunOnUiThread(() =>
{
btnNotification.Visibility = Android.Views.ViewStates.Visible;
btnDataMessage.Visibility = Android.Views.ViewStates.Visible;
});
}
catch (Exception e)
{
Log.Info("token", e.ToString());
}
}
);
thread.Start();
}
public async Task<string> GetAccessToken()
{
string uri = "https://oauth-login.cloud.huawei.com/oauth2/v3/token";
var values = new Dictionary<string, string>
{
{ "grant_type", "client_credentials" },
{ "client_id", appID },
{ "client_secret", appKey }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync(uri, content);
var jsonResponse = JObject.Parse(await response.Content.ReadAsStringAsync()); //Install-Package Newtonsoft.Json
string accessToken = jsonResponse["access_token"].ToString(); //It is valid for 3600 seconds
return accessToken;
}
public async void SendNotification()
{
string uriNot = "https://push-api.cloud.huawei.com/v1/" + appID + "/messages:send";
var jObject = new
{
message = new
{
notification = new
{
title = "This is title",
body = "This is body part"
},
android = new
{
notification = new
{
click_action = new
{
type = 3
}
}
},
token = new[] { tokenFromGetToken }
}
};
string myJson = JsonConvert.SerializeObject(jObject, Formatting.Indented);
client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", await GetAccessToken());
var responseData = await client.PostAsync(uriNot, new StringContent(myJson, Encoding.UTF8, "application/json"));
}
public async void SendDataMessage()
{
string uriNot = "https://push-api.cloud.huawei.com/v1/" + appID + "/messages:send";
var jObject = new
{
message = new
{
data = JsonConvert.SerializeObject(new
{
title = "Message Title",
text = "Message Body",
randomKey = "You can write any key and value"
}, Formatting.None),
token = new[] { tokenFromGetToken }
}
};
string myJson = JsonConvert.SerializeObject(jObject, Formatting.Indented);
client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", await GetAccessToken());
var responseData = await client.PostAsync(uriNot, new StringContent(myJson, Encoding.UTF8, "application/json"));
}
}
}
copy
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:text="Get Token"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="25px"
android:minHeight="150px"
android:id="@+id/btnGetToken" />
<Button
android:text="Send Notification"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="25px"
android:minHeight="150px"
android:visibility="invisible"
android:id="@+id/btnNotification" />
<Button
android:text="Send Data Message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="25px"
android:minHeight="150px"
android:visibility="invisible"
android:id="@+id/btnDataMessage" />
</LinearLayout>
Re- How to use Huawei Push Kit on Xamarin.Android
This is quite a helpful guide for the integration process.
{
"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"
}
"Hey, they say it's five centimeters per second. The falling speed of a cherry blossom petal. Five centimeters per second."
Upon hearing these famous lines from a well-known Japanese anime, John, a Huawei programmer, realized that cherry trees are currently blossoming.
John's girlfriend, Jenny, also loves cherry blossoms and planned to visit Paris's most famous park for cherry blossoms, Parc de Sceaux, on the weekend. John, unfortunately, was still on a business trip that weekend and could not go with his girlfriend.
So John said to himself, "How about I make an intelligent travel app, I am a programmer after all, for Jenny, so that she can enjoy the cherry blossoms in the best possible way?" John then listed the following requirements for the app he was about to quickly create:
l Considerate travel reminders: remind her of important events in advance in her schedule, such as when to depart.
l Weather forecast: provide suggestions on what to bring and wear based on the weather conditions at her destination.
l Push messages: push helpful tips and discount information to her once she arrives at the destination.
...
Luckily for John, the preceding capabilities can be implemented without hassle using the time and weather awareness capabilities of HUAWEI Awareness Kit, the geofence capabilities of HUAWEI Location Kit, and the message pushing capabilities of HUAWEI Push Kit.
OverviewAwareness Kit provides your app the ability to obtain contextual information including users' current time, location, behavior, headset status, weather, ambient light, car stereo connection status, and beacon connection status, which can be combined to create various barriers that run in the background and trigger once the predefined context is met.
Location Kit combines GNSS, Wi-Fi, and base station positioning capabilities into your app, allowing you to provide flexible location-based services for users around the world.
Push Kit is a messaging service tailored for developers, which helps create a cloud-to-device messaging channel. With Push Kit integrated, your app can send messages to users' devices in real time.
Code Development1. Awareness Kit IntegrationPreparationsThe following three key steps are required for integrating Awareness Kit. For details, please refer to the development guide on the HUAWEI Developers website.
1. Configure app information in AppGallery Connect.
2. Integrate the HMS Core Awareness SDK.
3. Configure obfuscation scripts.
Development Procedure 1. Declare required permissions in the AndroidManifest.xml file.
XML:
<p style="line-height: 1.5em;"><
uses-permission
android
:name
="android.permission.ACCESS_FINE_LOCATION"
/>
<
uses-permission
android
:name
="android.permission.ACCESS_BACKGROUND_LOCATION"
/></p>
2. Obtain weather information based on the city name.
Java:
String city = edCity.getText().toString();
if (city != null && !city.equals("")) {
WeatherPosition weatherPosition = new WeatherPosition();
weatherPosition.setCity(city);
// Pass the language type of the passed address. The value format is "Language_country", such as "zh_CN", "en_US".
weatherPosition.setLocale("en_US");
// Obtain the Capture Client of Awareness Kit, and call the weather query capability.
Awareness.getCaptureClient(getApplicationContext()).getWeatherByPosition(weatherPosition)
.addOnSuccessListener(new OnSuccessListener<WeatherStatusResponse>() {
@Override
public void onSuccess(WeatherStatusResponse weatherStatusResponse) {
// Process the returned weather data.
WeatherStatus weatherStatus = weatherStatusResponse.getWeatherStatus();
WeatherSituation weatherSituation = weatherStatus.getWeatherSituation();
Situation situation = weatherSituation.getSituation();
String weather;
// Match the weather ID with the weather.
weather = getApplicationContext().getResources().getStringArray(R.array.cnWeather)[situation.getCnWeatherId()];
// Update UI.
((TextView) findViewById(R.id.tv_weather)).setText(weather);
((TextView) findViewById(R.id.tv_windDir)).setText(situation.getWindDir());
((TextView) findViewById(R.id.tv_windSpeed)).setText(situation.getWindSpeed() + " km/h");
((TextView) findViewById(R.id.tv_temperature)).setText(situation.getTemperatureC() + "℃");
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
}
});
}
3. Implement scheduled reminders and message pushing once a user arrives at the destination.
(1) Register a static broadcast receiver to receive notifications when the app is terminated.
The sample code in the AndroidManifest.xml file is as follows:
XML:
<receiver android:name=".BarrierReceiver">
<intent-filter>
<action android:name="com.test.awarenessdemo.TimeBarrierReceiver.BARRIER_RECEIVER_ACTION"/>
</intent-filter>
</receiver>
The Java sample code is as follows:
Java:
Intent intent = new Intent();
intent.setComponent(new ComponentName(MainActivity.this, BarrierReceiver.class));
mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
(2) Define the time barrier and corresponding label, then add the barrier.
Java:
// Obtain the entered time.
String timeHour = edTimeHour.getText().toString();
String timeMinute = edTimeMinute.getText().toString();
int hour = 0;
int minute = 0;
if (!timeHour.equals("")) {
hour = Integer.parseInt(timeHour);
if (!timeMinute.equals("")) {
minute = Integer.parseInt(timeMinute);
}
}
long oneHourMilliSecond = 60 * 60 * 1000L;
long oneMinuteMilliSecond = 60 * 1000L;
// Define the duringPeriodOfDay barrier to send notifications within a specified time period in a specified time zone.
AwarenessBarrier periodOfDayBarrier = TimeBarrier.duringPeriodOfDay(TimeZone.getDefault(),
// Set the notification time to two hours in advance.
(hour - 2) * oneHourMilliSecond + minute * oneMinuteMilliSecond,
hour * oneHourMilliSecond + minute * oneMinuteMilliSecond);
String timeBarrierLabel = "period of day barrier label";
// Define a request for updating a barrier.
BarrierUpdateRequest.Builder builder = new BarrierUpdateRequest.Builder();
BarrierUpdateRequest request = builder.addBarrier(timeBarrierLabel, periodOfDayBarrier, mPendingIntent).build();
Awareness.getBarrierClient(getApplicationContext()).updateBarriers(request)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
}
});
(3) Define the location barrier and corresponding label, then add the barrier.
Java:
if (city != null && !city.equals("")) {
// Obtain the longitude and latitude of the city based on the city name from the assets folder.
String data = cityMap.get(city);
if (data != null){
int flag = data.indexOf(",");
double latitude = Double.parseDouble(data.substring(flag+1));
double longitude = Double.parseDouble(data.substring(0,flag));
double radius = 50;
long timeOfDuration = 5000;
// Define the stay barrier. If a user enters a specified area and stays for a specified time period, a barrier event is triggered and reported.
AwarenessBarrier stayBarrier = LocationBarrier.stay(latitude, longitude, radius, timeOfDuration);
String stayBarrierLabel = "stay barrier label";
// Define a request for updating a barrier.
BarrierUpdateRequest.Builder builder = new BarrierUpdateRequest.Builder();
BarrierUpdateRequest request = builder.addBarrier(stayBarrierLabel, stayBarrier, mPendingIntent).build();
Awareness.getBarrierClient(getApplicationContext()).updateBarriers(request)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
}
});
}
}
(4) Define the broadcast receiver to listen for the barrier event for further processing
Java:
class BarrierReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
BarrierStatus barrierStatus = BarrierStatus.extract(intent);
String label = barrierStatus.getBarrierLabel();
int barrierPresentStatus = barrierStatus.getPresentStatus();
String city = intent.getStringExtra("city");
switch (label) {
case DURING_PERIOD_OF_DAT_BARRIER_LABEL:
if (barrierPresentStatus == BarrierStatus.TRUE) {
initNotification(context,"1","time_channel","Travel reminder","Two hours before departure");
} else if (barrierPresentStatus == BarrierStatus.FALSE) {
showToast(context, "It's not between ");
} else {
showToast(context, "The time status is unknown.");
}
break;
case STAY_BARRIER_LABEL:
if (barrierPresentStatus == BarrierStatus.TRUE) {
initNotification(context,"2","area_channel","Welcome to"+city,"View travel plans");
} else if (barrierPresentStatus == BarrierStatus.FALSE) {
showToast(context,"You are not staying in the area set by locationBarrier" +
" or the time of duration is not enough.");
} else {
showToast(context, "The location status is unknown.");
}
break;
}
}
}
2. Location-based Message Pushing
Preparations1. Add the Huawei Maven repository address to the build.gradle file in the root directory of your project. The sample code is as follows:
XML:
<p style="line-height: 1.5em;">buildscript {
repositories {
maven { url 'http://developer.huawei.com/repo/'}
}
dependencies {
...
// Add AppGallery Connect plugin configuration.
classpath 'com.huawei.agconnect:agcp:1.4.2.300'
}
}allprojects {
repositories {
maven { url 'http://developer.huawei.com/repo/'}
}
}</p>
2. Add dependencies on the Location and Push SDKs to the build.gradle file in the app directory of your project.
Java:
<p style="line-height: 1.5em;">dependencies {
implementation 'com.huawei.hms:location:5.0.2.300'
implementation 'com.huawei.hms:push: 5.0.2.301'
}</p>
Key Steps1. Declare system permissions in the AndroidManifest.xml file.
Location Kit incorporates GNSS, Wi-Fi, and base station positioning capabilities into your app. In order to do this, it requires the network, precise location, and coarse location permissions. If you want the app to continuously obtain user locations when running in the background, you also need to declare the ACCESS_BACKGROUND_LOCATION permission in the AndroidManifest.xml file.
XML:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="com.huawei.hms.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
Note: The ACCESS_FINE_LOCATION, WRITE_EXTERNAL_STORAGE, and READ_EXTERNAL_STORAGE permissions are dangerous system permissions, so you need to dynamically apply for these permissions. If your app does not have the permissions, Location Kit will be unable to provide services for your app.
2. Create a geofence and trigger it.
Create a geofence or geofence group as needed, and set related parameters.
Java:
LocationSettingsRequest.Builder builders = new LocationSettingsRequest.Builder();
builders.addLocationRequest(mLocationRequest);
LocationSettingsRequest locationSettingsRequest = builders.build();
// Before requesting location update, call checkLocationSettings to check device settings.
Task<LocationSettingsResponse> locationSettingsResponseTasks = mSettingsClient.checkLocationSettings(locationSettingsRequest);
locationSettingsResponseTasks.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
Log.i(TAG, "check location settings success");
mFusedLocationProviderClient
.requestLocationUpdates(mLocationRequest, mLocationCallbacks, Looper.getMainLooper())
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
LocationLog.i(TAG, "geoFence onSuccess");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
LocationLog.e(TAG,
"geoFence onFailure:" + e.getMessage());
}
});
}
})
3. Trigger message pushing.
Send a push message when onReceive of GeoFenceBroadcastReceiver detects that the geofence is triggered successfully. The message will be displayed in the notification panel on the device.
Java:
if (geofenceData != null) {
int errorCode = geofenceData.getErrorCode();
int conversion = geofenceData.getConversion();
ArrayList<Geofence> list = (ArrayList<Geofence>) geofenceData.getConvertingGeofenceList();
Location myLocation = geofenceData.getConvertingLocation();
boolean status = geofenceData.isSuccess();
sb.append("errorcode: " + errorCode + next);
sb.append("conversion: " + conversion + next);
if (list != null) {
for (int i = 0; i < list.size(); i++) {
sb.append("geoFence id :" + list.get(i).getUniqueId() + next);
}
}
if (myLocation != null) {
sb.append("location is :" + myLocation.getLongitude() + " " + myLocation.getLatitude() + next);
}
sb.append("is successful :" + status);
LocationLog.i(TAG, sb.toString());
Toast.makeText(context, "" + sb.toString(), Toast.LENGTH_LONG).show();
//
new PushSendUtils().netSendMsg(sb.toString());
}
Note: The geofence created using the sample code will trigger two callbacks for conversion types 1 and 4. One is triggered when a user enters the geofence and the other is triggered when the user stays in the geofence. If Trigger is set to 7 in the code, callbacks for all scenarios, including entering, staying, and leaving the geofence, are configured.
Let's see this Demo:
For more details, you can go to:
l Our official website
l Our Development Documentation page, to find the documents you need
l Experience the easy-integration process on Codelabs
l GitHub to download demos and sample codes
l Stack Overflow to solve any integration problem
| Original Source
This is so nice, and a great app too.
Introduction
Whether you are tracking down a weird behavior in your app or chasing a crash in app making the user frustrated, getting a precise and real time information is important. Huawei crash analytics is a primary crash reporting solution for mobile. It monitors and captures your crashes, intelligently analyses them, and then groups them into manageable issues. And it does this through lightweight SDK that won’t bloat your app. You can integrate Huawei crash analytics SDK with a single line of code before you publish.
{
"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"
}
In this article, we will change app theme using Huawei Remote configuration and if something goes wrong while fetching data from remote config, we will report crash/exception using Huawei Crash Service.
To learn how to change app theme using Huawei Dark mode Awareness service, refer this.
Prerequisite
If you want to use Huawei Remote Configuration and Crash Service, you must have a developer account from AppGallery Connect. You need to create an application from your developer account and then integrate the HMS SDK into your project. I will not write these steps so that the article doesn’t lose its purpose and I will assume that it is already integrated in your project. You can find the guide from the link below.
HMS Integration Guide
Integration
1. Enable Remote Configuration and Crash Service in Manage APIs. Refer to Service Enabling.
2. Add AGC connect plugin in app-level build.gradle.
Code:
apply plugin: 'com.huawei.agconnect'
3. Integrate Crash Service and Remote configuration SDK by adding following code in app-level build.gradle.
Code:
implementation 'com.huawei.agconnect:agconnect-remoteconfig:1.5.2.300'
implementation 'com.huawei.agconnect:agconnect-crash:1.5.2.300'4.
4. Add following code in root-level build.gradle.
Code:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
// Configure the Maven repository address for the HMS Core SDK.
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
classpath "com.android.tools.build:gradle:4.0.1"
// Add AppGallery Connect plugin configurations.
classpath 'com.huawei.agconnect:agcp:1.4.2.300'
}
}
allprojects {
repositories {
// Configure the Maven repository address for the HMS Core SDK.
maven {url 'https://developer.huawei.com/repo/'}
}
}
5. Declare the following permissions in Androidmanifest.xml
Code:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Development
We will define JSON which will have mode value as 0 or 1.
1. If the value of mode is 0, we will use system setting to change app theme. For example, if device has dark mode enabled in system setting, our app theme will be dark.
2. If the value of mode is 1, we will force our app to use day theme.
Code:
{
"jsonmode": [{
"mode": 0,
"details": "system_settings_mode"
}]
}
Open AGC, select your project. Choose Growing > Remote Config and enable Remote Config service. Once the remote config is enabled, define the key-value parameters.
Key : “mode_status”
Value : {
"jsonmode": [{
"mode": "0",
"details": "system_settings_mode"
}]
}
Note: mode value should be int, however we are intentionally adding value as String, so that our app throws JSONException which we can monitor on AGC dashboard.
Implementation
Let’s create instance of AGConnectConfig and add the default value to hashmap before connecting to remote config service.
Java:
private void initializeRemoteConfig() {
agConnectConfig = AGConnectConfig.getInstance();
Map<String, Object> map = new HashMap<>();
map.put("mode_status", "NA");
agConnectConfig.applyDefault(map);
}
To fetch parameter values from Remote Configuration.
Java:
agConnectConfig.fetch(5).addOnSuccessListener(new OnSuccessListener<ConfigValues>() {
@Override
public void onSuccess(ConfigValues configValues) {
agConnectConfig.apply(configValues);
String value = agConnectConfig.getValueAsString("mode_status");
Log.d(TAG, "remoteconfig value : " + value);
try {
int mode = parseMode(value);
Log.d(TAG, "mode value : " + mode);
if(mode == 0) {
initilizeDarkModeListner();
}
else if(mode == 1) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
} catch (JSONException e) {
Log.e(TAG,"JSONException : " +e.getMessage());
AGConnectCrash.getInstance().recordException(e);
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, " error: " + e.getMessage());
}
});
To parse the JSON received from Remote config.
Code:
private int parseMode(String json) throws JSONException {
if(json != null) {
JSONObject jsonObj = new JSONObject(json);
JSONArray jsonArrayMenu = jsonObj.getJSONArray("jsonmode");
for (int i = 0; i < jsonArrayMenu.length(); i++) {
JSONObject modeJsonObj = jsonArrayMenu.getJSONObject(i);
return modeJsonObj.getInt("mode");
}
}
return -1;
}
If parsing is successful, we will able to retrieve the mode value as 0 or 1.
However if parsing is unsuccessful, JSONException will be thrown and we will log this exception in AGC using Huawei Crash Service.
Java:
catch (JSONException e) {
Log.e(TAG,"JSONException : " +e.getMessage());
AGConnectCrash.getInstance().recordException(e);
}
Now when app encounters crash, Crash service reports the crash on dashboard in App Gallery connect. To monitor crash, as follows:
1. Sign in to App Gallery connect and select my project.
2. Choose the app.
3. Select Quality > Crash on left panel of the screen.
If you see parsing implementation of JSON, expected mode value should be integer
"mode": 0
But mistakenly, we have added mode value as string in remote config.
Code:
{
"jsonmode": [{
"mode": "0",
"details": "system_settings_mode"
}]
}
Now when we try to run our app, it will throw JSONException, since we are expecting mode value as int from remote config. This exception will be added to AGC dashboard using Huawei crash service.
As a developer, when I go to AGC dashboard to monito my app crash report, I realize my mistake and update the value in AGC remote config as follows:
Code:
{
"jsonmode": [{
"mode": 0,
"details": "system_settings_mode"
}]
}
Now our app will change its theme based on system settings whether if dark mode is enabled or not.
Code snippet of MainActivity.java
Java:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private AGConnectConfig agConnectConfig;
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeRemoteConfig();
ConfigValues last = agConnectConfig.loadLastFetched();
agConnectConfig.apply(last);
agConnectConfig.fetch(5).addOnSuccessListener(new OnSuccessListener<ConfigValues>() {
@Override
public void onSuccess(ConfigValues configValues) {
agConnectConfig.apply(configValues);
String value = agConnectConfig.getValueAsString("mode_status");
Log.d(TAG, "remoteconfig value : " + value);
try {
int mode = parseMode(value);
Log.d(TAG, "mode value : " + mode);
if(mode == 0)) {
initilizeDarkModeListner();
}
else if(mode == 1) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
} catch (JSONException e) {
Log.e(TAG,"JSONException : " +e.getMessage());
AGConnectCrash.getInstance().recordException(e);
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, " error: " + e.getMessage());
}
});
}
private void initializeRemoteConfig() {
agConnectConfig = AGConnectConfig.getInstance();
Map<String, Object> map = new HashMap<>();
map.put("mode_status", "NA");
agConnectConfig.applyDefault(map);
}
private void initilizeDarkModeListner() {
Awareness.getCaptureClient(this).getDarkModeStatus()
// Callback listener for execution success.
.addOnSuccessListener(new OnSuccessListener<DarkModeStatusResponse>() {
@Override
public void onSuccess(DarkModeStatusResponse darkModeStatusResponse) {
DarkModeStatus darkModeStatus = darkModeStatusResponse.getDarkModeStatus();
if (darkModeStatus.isDarkModeOn()) {
Log.i(TAG, "dark mode is on");
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else {
Log.i(TAG, "dark mode is off");
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
}
})
// Callback listener for execution failure.
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "get darkMode status failed " + e.getMessage());
}
});
}
private int parseMode(String json) throws JSONException {
if(json != null) {
JSONObject jsonObj = new JSONObject(json);
JSONArray jsonArrayMenu = jsonObj.getJSONArray("jsonmode");
for (int i = 0; i < jsonArrayMenu.length(); i++) {
JSONObject modeJsonObj = jsonArrayMenu.getJSONObject(i);
return modeJsonObj.getInt("mode");
}
}
return -1;
}
}
Tips and Tricks
1. Huawei Crash services work on non-Huawei device.
2. AGConnectCrash.getInstance().testIt(mContext) triggers app crash. Make sure to comment or remove it before releasing your app.
3. Crash Service takes around 1 to 3 minutes to post the crash logs on App Gallery connect dashboard/console.
4. Crash SDK collects App and system data.
System data:
AAID, Android ID (obtained when AAID is empty), system type, system version, ROM version, device brand, system language, device model, whether the device is rooted, screen orientation, screen height, screen width, available memory space, available disk space, and network connection status.
App data:
APK name, app version, crashed stack, and thread stack.
5. The Crash SDK collects data locally and reports data to the collection server through HTTPS after encrypting the data.
Conclusion
In this article, we have learnt how Huawei crash service can help developers to monitor crash/exception report on AGC and fix it.
We uploaded wrong JSON data into Remote Configuration and cause our app to go into JSONException. Using Huawei Crash Service, we monitored the exception in AGC dashboard. After finding out issue in JSON data, we added correct data in remote config and fixed our app.
References
Huawei Crash Service
Huawei Remote Configuration
Original Source
Introduction
In this article, we will learn how to implement Huawei HiAI kit using Table Recognition service into android application, this service helps us to extract the table content from images.
Table recognition algorithms, this one is based on the line structure of table. Clear and detectable lines are necessary for the proper identification of cells.
Use case: Imagine you have lots of paperwork and documents where you would be using tables, and using the same you would like to manipulate data. Conventionally you can copy them manually or generate excel files for third party apps.
{
"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"
}
Requirements
1. Any operating system (MacOS, Linux and Windows).
2. Any IDE with Android SDK installed (IntelliJ, Android Studio).
3. HiAI SDK.
4. Minimum API Level 23 is required.
5. Required EMUI 9.0.0 and later version devices.
6. Required process kirin 990/985/980/970/ 825Full/820Full/810Full/ 720Full/710Full
Features
1. Restores the table information including text in the cells, and identifies merged cells as well.
2. Fast recognition it returns the text in a cell containing 50 lines within 3seconds
3. Recognition accuracy level >85%
4. Recall rate >80%
How to integrate HMS Dependencies
1. First of all, we need to create an app on AppGallery Connect and add related details about HMS Core to our project. For more information check this link
2. Download agconnect-services.json file from AGC and add into app’s root directory.
3. Add the required dependencies to the build.gradle file under root folder.
Code:
maven {url'https://developer.huawei.com/repo/'}
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
4. Add the App level dependencies to the build.gradle file under app folder.
Code:
apply plugin: 'com.huawei.agconnect'
5. Add the required permission to the Manifestfile.xml file.
Code:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.HARDWARE_TEST.camera.autofocus"/>
6. Now, sync your project.
How to apply for HiAI Engine Library
1. Navigate to this URL, choose App Service > Development and click HUAWEI HiAI.
2. Click Apply for HUAWEI HiAI kit.
3. Enter required information like Product name and Package name, click Next button.
4. Verify the application details and click Submit button.
5. Click the Download SDK button to open the SDK list.
6. Unzip downloaded SDK and add into your android project under lib folder.
7. Add jar files dependences into app build.gradle file.
Code:
implementation fileTree(<b><span style="font-size: 10.0pt;font-family: Consolas;">include</span></b>: [<b><span style="font-size: 10.0pt;">'*.aar'</span></b>, <b><span style="font-size: 10.0pt;">'*.jar'</span></b>], <b><span style="font-size: 10.0pt;">dir</span></b>: <b><span style="font-size: 10.0pt;">'libs'</span></b>)
implementation <b><span style="font-size: 10.0pt;">'com.google.code.gson:gson:2.8.6'
repositories {
flatDir {
dirs 'libs'
}
}</span></b><b style="font-family: Consolas;font-size: 10.0pt;background-color: white;">
</b>
8. After completing this above setup, now Sync your gradle file.
Let’s do code
I have created a project on Android studio with empty activity let’s start coding.
In the MainActivity.java we can create the business logic.
Code:
MainActivity extends AppCompatActivity {
private boolean isConnection = false;
private int REQUEST_CODE = 101;
private int REQUEST_PHOTO = 100;
private Bitmap bitmap;
private Bitmap resultBitmap;
private Button btnImage;
private ImageView originalImage;
private ImageView conversionImage;
private TextView textView;
private TextView contentText;
private final String[] permission = {
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE};
private ImageSuperResolution resolution;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermissions(permission, REQUEST_CODE);
initHiAI();
originalImage = findViewById(R.id.super_origin);
conversionImage = findViewById(R.id.super_image);
textView = findViewById(R.id.text);
contentText = findViewById(R.id.content_text);
btnImage = findViewById(R.id.btn_album);
btnImage.setOnClickListener(v -> {
selectImage();
});
}
private void initHiAI() {
VisionBase.init(this, new ConnectionCallback() {
@Override
public void onServiceConnect() {
isConnection = true;
DeviceCompatibility();
}
@Override
public void onServiceDisconnect() {
}
});
}
private void DeviceCompatibility() {
resolution = new ImageSuperResolution(this);
int support = resolution.getAvailability();
if (support == 0) {
Toast.makeText(this, "Device supports HiAI Image super resolution service", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Device doesn't supports HiAI Image super resolution service", Toast.LENGTH_SHORT).show();
}
}
public void selectImage() {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, REQUEST_PHOTO);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (data != null && requestCode == REQUEST_PHOTO) {
try {
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), data.getData());
if (isConnection) {
setTableAI();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private void setTableAI() {
textView.setText("Extraction Table Text");
contentText.setVisibility(View.VISIBLE);
TableDetector mTableDetector = new TableDetector(this);
VisionImage image = VisionImage.fromBitmap(bitmap);
VisionTableConfiguration mTableConfig = new VisionTableConfiguration.Builder()
.setAppType(VisionTableConfiguration.APP_NORMAL)
.setProcessMode(VisionTableConfiguration.MODE_OUT)
.build();
mTableDetector.setVisionConfiguration(mTableConfig);
mTableDetector.prepare();
Table table = new Table();
int mResult_code = mTableDetector.detect(image, table, null);
if (mResult_code == 0) {
int count = table.getTableCount();
List<TableContent> tc = table.getTableContent();
StringBuilder sbTableCell = new StringBuilder();
List<TableCell> tableCell = tc.get(0).getBody();
for (TableCell c : tableCell) {
List<String> words = c.getWord();
StringBuilder sb = new StringBuilder();
for (String s : words) {
sb.append(s).append(",");
}
String cell = c.getStartRow() + ":" + c.getEndRow() + ": " + c.getStartColumn() + ":" +
c.getEndColumn() + "; " + sb.toString();
sbTableCell.append(cell).append("\n");
contentText.setText("Count = " + count + "\n\n" + sbTableCell.toString());
}
}
}
}
Demo
Tips and Tricks
1. Download latest Huawei HiAI SDK.
2. Set minSDK version to 23 or later.
3. Do not forget to add jar files into gradle file.
4. It supports slides images.
5. Input resolution larger than 720p and with aspect ratio smaller than 2:1.
6. It supports only printed text, images, formulas, handwritten content, seals, watermarks cannot be identified.
7. Refer this URL for supported Countries/Regions list.
Conclusion
That’s it! Now your table content extracted from image, for further analysis with statistics or just for editing it. This works for tables with clear and simple structure information.
Thanks for reading! If you enjoyed this story, please click the Like button and Follow. Feel free to leave a Comment below.
Reference
Huawei HiAI Table Recognition Kit URL
Original Source