Introduction
If are you new to this application, please follow my previous articles
Pygmy collection application Part 1 (Account kit)
Intermediate: Pygmy Collection Application Part 2 (Ads Kit)
Intermediate: Pygmy Collection Application Part 3 (Crash service)
Intermediate: Pygmy Collection Application Part 4 (Analytics Kit Custom Events)
Intermediate: Pygmy Collection Application Part 5 (Safety Detect)
Intermediate: Pygmy Collection Application Part 6 (Room database)
Intermediate: Pygmy Collection Application Part 7 (Document Skew correction Huawei HiAI)
Intermediate: Pygmy Collection Application Part 8 (Scan kit customized view)
Click to expand...
Click to collapse
In this article, we will learn how to integrate Cloud Testing in Pygmy collection finance application.
Why do we need testing?
Delivering the quality product matters in the software industry. If the product has the errors or crashes end users will switch other similar products. End of the day user base matters for mobile application, so application has to test thoroughly.
The delivery of an optimal quality software product that has unique and innovative features has been the priority of the software industry worldwide. However, without evaluating software components under various expected and unexpected conditions, the team cannot guarantee these aspects. Therefore, testing is performed to test every software component large and small.
Cloud based testing service is most important and powerful feature for developers. So Huawei has come up with great solution that is cloud testing. It uses real time devices and gives the full report.
Currently available types of testing added:
1. Compatibility Test
2. Stability Test
3. Performance Test
4. Power consumption Test
Requirements
1. To use cloud testing you should have developer account. Register here.
2. Create an android project in android studio.
3. Get the SHA Key. Create SHA key
4. Provide the SHA key in the information section.
5. Provide storage location.
6. After all the steps need to download the agconnect-services.json from the app information section. Copy and paste the json file in the app folder of the android project.
7. Add required dependencies to root and app directory.
8. Sync project.
9. Create sample application
1) Compatibility Test
What is Software Compatibility Testing?
Compatibility is non-functional testing to ensure customer satisfaction. It is to determine whether your software application or product is proficient enough to run in different browsers, database, hardware, operating system, mobile devices, and networks.
The application could also impact due to different versions, resolution, internet speed and configuration etc. Hence it’s important to test the application in all possible manners to reduce failures and overcome from embarrassments of bug’s leakage. As a Non- functional tests, Compatibility testing is to endorse that the application runs properly in different browsers, versions, OS and networks successfully.
Compatibility test should always perform in the real environment instead of a virtual environment. Since Huawei Cloud testing gives the real environment
Types of Software Compatibility Testing
Browser compatibility testing
Hardware
Networks
Mobile Devices
Operating System
Versions
Steps to be followed for Compatibility test.
Step 1: Choose Project Setting > Quality > Cloud Testing and select Test for free.
{
"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"
}
Step 2: Select the Compatibility test.
Step 3: Upload APK into Coud Testing and click Next button.
Step 4: Select Device model, OS version and click OK button.
Step 5: Select create another test if you wish to create another test else select View test list to view the test list.
Step 6: Select Compatibility test.
Step 7: Click View to check the result.
Result
2) Stability Testing
What is stability testing?
Stability Testing is a type of non-functional software testing performed to measure efficiency and ability of a software application to continuously function over a long period of time. The purpose of Stability testing is checking, if the software application crashes or fails over normal use at any point of time by exercising its full range of use.
Stability Testing is done to check the efficiency of a developed product beyond normal operational capacity, often to a breakpoint. There is greater significance is on error handling, software reliability, robustness and scalability of a product under heavy load rather than checking the system behaviour under normal circumstances.
Steps to be followed for Stability test.
Step 1: Choose Project Setting > Quality > Cloud Testing and Select Test for free. Or Select New test.
Or
Step 2: Select the Stability test and Upload APK into cloud testing. Select duration from 10-60 minutes, and Click Next button.
Step 4: Select Device model, OS version and click Ok button.
Step 5: Select Create another test if you wish to create another test else select View test list to view the test list.
Step 6: Select Stability test.
Step 7: Click View to check the result.
Result
3) Performance Test
What is Performance Testing?
Performance Testing is a software testing process used for testing the speed, response time, stability, reliability, scalability and resource usage of a software application under particular workload. The main purpose of performance testing is to identify and eliminate the performance bottlenecks in the software application. It is a subset of performance engineering and also known as “Perf Testing”.
The focus of Performance Testing is checking a software programs.
Speed - Determines whether the application responds quickly.
Scalability - Determines maximum user load the software application can handle.
Stability - Determines if the application is stable under varying loads.
Steps to be followed for Performance test.
Step 1: Choose Project Setting > Quality > Cloud Testing. Select Test for free.
Or
Step 2: Select Test for free. Or Select New test
Step 3: Select the Performance test.
Or
Step 4: Upload APK into Cloud Testing.
Step 5: Set the App category and Click on Next button.
Step 6: Select Device models, OS version and click OK button.
Step 7: Select Create another test if you wish to create another test else select View test list to view the test list.
Step 8: Select Performance test.
Step 9: Select View to check the result.
Result
4) Power consumption Test
What is power consumption testing?
Thousands of new mobile apps are being launched every day. And these apps have gone beyond just utilities, games and shopping apps, nowadays, apps need to be integrated into self-driving cars, digital assistants, wearable devices etc. Billions of users need to install apps that are not only compatible with their varying devices, but also provide quality experience of the app so that it doesn’t prompt the user to uninstall it and move to an alternate app. So basically power consumption test is how much battery is consumed by application.
Steps to be followed for Power consumption test.
Step 1: Choose Project Setting > Quality > Cloud Testing.
Or
Step 2: Select Test for free. Or Select New test
Step 3: Select the Power consumption Test.
Or
Step 4: Upload APK into Cloud Testing.
Step 5: Set the App category and Click on Next button.
Step 6: Select Device models, OS version and click Ok button.
Step 7: Select Create another test if you wish to create another test else select View test list to view the test list.
Step 8: Select Power consumption test.
Step 9: Select View to check the result.
Result
Tips and Tricks
You can download report and check the details about test cases.
You can download logs and track errors.
Make sure you add agconnect-service.json file to app directory.
Conclusion
In this article, we have learnt cloud testing, what is Compatibility / Stability / Performance / Power consumption testing, how to check Compatibility / Stability / Performance / Power consumption test report and logs download.
Reference
Cloud Testing
Related
Introduction
Hello everyone ,
I will introduce you App Gallery Connect A/B Testing in this article. I hope this article will be help you in yours projects
Service Introduction
A/B Testing provides a collection of refined operation tools to optimize app experience and improve key conversion and growth indicators. You can use the service to create one or more A/B tests engaging different user groups to compare your solutions of app UI design, copywriting, product functions, or marketing activities for performance metrics and find the best one that meets user requirements. This helps you make correct decisions.
Implementation Process
Enable A/B Testing.
Create an experiment.
Manage an experiment.
1. Enable A/B Testing
1.1. Enable A/B Testing
First of all you need to enable A/B Testing from AG Connect .
Process:
1. Sign in to AppGallery Connect and click My projects.
2. In the project list, find your project and click the app for which you need to enable A/B Testing.
MindSpore is an open-sourced framework for AI based application development which is announced by Huawei. It is a robust alternative to AI frameworks such as TensorFlow and PyTorch which are widely used in the market.
{
"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 start by emphasizing the features and advantages of MindSpore framework:
MindSpore implements AI algorithms for easier model development and provides cutting-edge technologies with Huawei AI processors to improve runtime efficiency and computing performance.
One of its advantages is that it can be used in several environments like on devices, cloud and edge environments. It supports operating systems like IOS and Android, and AI applications on various devices such as mobile phones, tablets and IoT devices.
MindSpore supports parallel training across hardware to reduce training times. It maximizes both hardware computing power and minimizes inference latency and power consumption.
It provides dynamic debugging ability for developers which enables to find out bugs in the apps easily.
According to Huawei, MindSpore does not process data by itself but ingests the gradient and model information that has been processed. This ensures the integrity of sensitive data.
MindSpore Lite is an inference framework for custom models which is provided by HMS ML Kit to simplify the integration and development. The developers can define their own model and implement model inference thanks to MindSpore Lite capabilities.
MindSpore Lite is compatible with commonly used AI platforms like TensorFlow Lite, Caffe, and Onnx. Different models can be converted into .ms (MindSpore) format and then run perfectly.
Custom models can be deployed and executed easily since they are compressed and occupy small storage.
It provides complete APIs to integrate inference framework of an on-device custom model.
HMS ML Kit enables to train and generate custom models with deep machine learning. It also offers pre-trained image classification model. You can develop your own custom model by using Transfer Learning feature of ML Kit with a specific dataset.
I will basically explain you how to train your own model over an example which contains three plant categories. We will use a small data set for reference and train the image classification model to identify cactus, pine and succulent plants. The model will be created by using HMS Toolkit plug-in and AI Create.
HMS Toolkit: As a lightweight IDE tool plugin, HMS Toolkit implements app creation, coding, conversion, debugging, test, and release. It helps you integrate HMS Core APIs with lower costs and higher efficiency.
AI Create: Provides the transfer learning capabilities of image classification and text classification. Images and texts can be identified thanks to AI Create. It uses MindSpore as a training framework and MindSpore Lite as inference framework.
Note: Use the Android Studio marketplace to install HMS Toolkit plug-in. Please go to File > Settings > Plugins > Marketplace, enter HMS Toolkit into the search box and click install. After installation complete, restart Android Studio.
We should prepare the environment to train our model first. AI Create only supports Windows operating system currently. Please open Coding Assistant by using the new HMS section that came with HMS Toolkit plug-in. Go to AI > AI Create in Coding Assistant and select Image and click Confirm for Image Classification.
After this step HMS Toolkit automatically downloads resources for you. If the Python environment is not configured, the dialog box will be displayed as below.
Note: You should download and install Python 3.7.5 from the link to use AI Create. After installation complete, please do not forget to add Python installation path into the Path variable in Environment Variables and restart the Android Studio.
After environment is ready, if you select Image and click Confirm from AI Create it will automatically start to install MindSpore. Please be sure the framework has been installed successfully by checking the Event logs.
From now, new model section will be opened to select an image folder to train our own model. You should prepare your data set in accordance with the requirements. We will train the model for our demo to identify cactus, succulent and pine plants with a small data set.
The folder structure should be like below :
The following conditions should be met for image resources:
The minimum number of pictures for each category of training data is 10.
The lower limit of the classification number of the training data set is 2, and the upper limit is 1000.
Supported image formats: .bmp, .jpg, .jpeg, .png or .gif.
After training image folder is selected, please set Output model file path and training parameters. If you check HMS Custom Model, a complete model will be generated. The train parameters affects the accuracy of image recognition model. You can modify them if you have a experience with deep learning. When you click on Create Model, MindSpore will start to train your model according to the data set.
Training process will take a time depending on your data set. As we used a small data set with the minimum number of the requirements it is completed quickly. You can also track training logs, your model will be created on the specified path at the end of the process.
The training results will be shared after model training is completed. AI create enables to test your model by adding the test images before using it in any project. You can also generate a demo project that implements your new model with Generate Demo option.
You should create a new test image folder with the same structure of provided data set.
As you see above, our test average accuracy is calculated as 57.1%. This accuracy can be improved by providing comprehensive data set and training.
You can also use and experience results of your new model over a demo project which can be created by HMS Toolkit. After the demo is created, you may directly run and build the project and check the results on real device.
In this article, I wanted to share basic information about MindSpore and how we can use Transfer Learning function of HMS for custom models.
You can also develop your own classification model by using this post as a reference. I hope that it will be useful for you !
Please follow our next articles for more details about ML Kit Custom Model and MindSpore.
References
https://developer.huawei.com/consum...ore-Guides/ml-mindspore-lite-0000001055328885
https://www.mindspore.cn/lite/en
{
"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"
}
IntroductionHello everybody! In this article, I will be introducing the brand new version of HMS Unity Plugin version 2.0! Yes, it is out and it will make your life much easier, even when compared to the previous version of the plugin 1.2.0!
The HMS Unity Plugin is a tool that helps developers to quickly integrate Huawei Mobile Services (HMS) to their games in Unity without worrying about the boilerplate codes that has to be written in the background. All the necessary backend code is dealt with for you, and all you have to do is to focus on your own game and HMS features.
In this article, I will be using my own game as a scenario to quickly explain the steps required for you to integrate many HMS kits with a few clicks and/or lines of code. To be specific, I am using the version 2.0.1 for this article.
Before diving into details, you can check out here, the plugin’s GitHub page, if you think you are experienced enough with the plugin and that you do not require any specific scenario to start using the plugin. Readme already has general details about how to start using the kit.
Please note that I developed this game and used the plugin for this article series in Unity editor version 2019.4.18f1. For 2020 version of the Unity, you should be able to do the same steps with the same version of the plugin. For 2018 or other versions, please check out here, the releases page, for the corresponding plugin release (if any) and for the latest updates.
I further suggest that you download the latest version of the plugin for the corresponding Unity version, although I have used version 2.0.1 here. Details on how to use/import the plugin will follow, but I wanted to let you know beforehand.
About My GameLet me quickly introduce my game to you, so that during the phases of integration, it makes sense to you why I am implementing the plugin features in this way.
It is a hypercasual game called Raining Apocalypse, where you simply escape from the rain! You are the cool fire character that run horizontally. The more rains you run away from the more points you score. So, as you can see, very simple and affordable to implement.
I developed this game using a Udemy course and the source code is not completely written by me. However, we will not focus on the game development parts anyway, we will integrate the HMS kits to our game to increase our chances of survival in the game industry.
It consists of two scenes: main menu scene and game scene. It has several scripts attached, some of which we will use in the integration.
I will integrate “Account Kit, Ads Kit, Push Kit, Game Service, IAP, Analytics Kit and Crash Kit” to my game. For this part 1 of the article, I will talk about Account Kit, Ads Kit, Analytics Kit, Crash Kit and Push Kit. Game Service and IAP will be talked about in Part 2 of the series.
It looks too many and seems to cost the developers a lot of time, but not with Plugin 2.0 and you will see how, if you read on.
Development ProcessTo start using the plugin you must go here, the readme of the official GitHub page of the plugin and complete the phases, starting from the phase called “1 — Register your app at Huawei Developer” to “4 — Connect your game with any HMS Kit”, so that the AppGallery Connect side of your application is done. HMS requires AppGallery Connect configurations to correctly work with the in-game features you want to implement.
I will, from now on, assume that you have completed the first 3 phases and now ready to implement the 4th phase and onwards. You can continue using the following phases for the kits as well; but here, I will merge them with a real life scenario, i.e. my game, so that you can better understand how those features would work in your own game. By this way, you can decide easily where to put those methods in your own game.
Now, assuming that you are done with the AGC side, let’s get to the coding. I will talk about AGC side a bit in some of the kits I explain as well.
Coding PhaseLet’s start with Account Kit and Ads Kit. The main menu scene of my game has a logo and a play button to start the game. What I want to add is a banner ad to the bottom and also to implement sign in functionality. By this way, I will show 320*50 (or any size you choose) ads to the users at the beginning of my game. Also, since I do not want to proceed to the game without the user signed in, I will implement the sign in functionality so that when I try to use the other kits in-game, I do not have to deal with sign in process again.
To start using any kit, you must import the plugin (downloaded from the releases page) and click on the kits that you want to use. Mine currently looks like this:
Clicking them will add a manager to your game screen. They are coming with DontDestroyOnLoad() function by default, so you do not have to worry about carrying it over to the other scenes. However, it is strongly suggested that you do this in the outermost scene, so this carry-over process is smooth and bug-free. I do it in my main menu scene because it comes first, and the game scene opens the second.
I have my own manager script called EnesGameManager.cs to control the behaviour of kits and game-specific functionalities.
Before every use of managers, you must call them with .Instance because the plugin uses the singleton pattern to implement the managers. That is also helpful in changing scenes all you like because the plugin will delete the unnecessary copies of the manager and will make sure that you only work with the one and the only instance. This will save you from coding overhead and wrong instance usage.
Account KitAfter ticking the box, HMSAccountManager is added to the scene. All you have to do is to add the below line to anywhere you choose as per your own game logic. You can place it inside a new method to add a button click to the play button, for example.
HMSAccountManager.Instance.SignIn();
Important Note: If you plan to use GameService, it has automatic sign-in functionality. Instead of using Account Kit, you can just enable the GameService, tick the box (“Initialize on Start”) under Game Service tab and your app will do auto sign-in every time the user opens the app. If this is not what you want, use of Account Kit is required and GameService function should be manually initialized. All of the details about this can be found in the part 2 of the article, which is here.
GameService is dependent on AccountKit anyway, so even if you do not use Account Kit to login (which is perfectly fine), GameService login system will use it for you in the background.
Ads Kit — Part 1Ads Kit has three types of advertisements as of the publish date of this article. If you are reading this later than the publish date, some new types of ads might have been added to the plugin, so I would suggest you to check them out as well. Ads Kit, right now, supports “Banner Ads, Interstitial Ads and Rewarded Ads”. I will be using banner ads and interstitial ads in my game. Since the interstitial ads will be implemented in the game scenes, in this part 1, I will only show how to implement banner ads.
To enable the ads you want to use, just tick the corresponding boxes. That is very easy. Also, if you want to use test ads like me, check that box too. It will replace any ID you enter above with the test ID, so you can test the layout of ads in your game for example, before getting a real ID. If you have the ID already you can uncheck the test ID box, enter the ID and click save. Replacing does not mean you will lose the already-entered ID, but you will see the test ads from now on, until you uncheck the box.
The default size is 320*50 and the default position is POSITION_BOTTOM. If you require different sizes and positions, you can only change them inside of manager script in this version of the plugin. You can check Huawei -> Scripts -> Ads folder to reach the manager script and configure as per your needs.
If you build now, you should get your ads like below. You can work on alignment yourself to match the elements.
There is one more thing left. This banner ad will show in every screen you will be opening from now on. For my case, it will be present on my game screen if I press play button; which is not what I want. Thus, in the game scene, I will call below one line code to hide the ads because it is the behaviour I want. You can call this code piece in any Start() function of the active object scripts.
HMSAdsKitManager.Instance.HideBannerAd();
As you can see, no initialization etc. required. HMSAdsKitManager will remain on your other scenes and can be directly called by using its instance.
If you do not want the banner ads in your main screen and want it in other scenes, you can always use the above hide code to hide it in the beginning and call the below show method to show it anywhere you like.
HMSAdsKitManager.Instance.ShowBannerAd();
That’s it for banner ads. Very short, very simple.
Ads Kit — Part 2I also want to use interstitial ads in my app. The scenario I want to use it is when the user dies, before showing a lose screen to retry, I want to show interstitial ads, unless the user has purchased the remove_ads product (which I will talk about in IAP section).
To implement this, I need to put the code into the proper place in my own game code. There is no one way to do it. If you have a similar scenario like me, you can also follow my code and find your corresponding code and implement your own interstitial ads logic.
In my player script, I have the TakeDamage function where I control the damage inflicted on my player. It also controls the death, when the health drops below zero. So here, when the player dies, I call interstitial ad show code to display the user interstitial ads. The if check can be ignored now and will be talked about in IAP section.
public void TakeDamage(int damageAmount)
{
source.Play();
health -= damageAmount;
if (health <= 0)
{
healthDisplay.text = "0";
HMSAnalyticsManager.Instance.SendEventWithBundle("$GameCompleted", "Score", score.ToString());
Destroy(gameObject);
if (!GameObject.Find("EnesGameManager").GetComponent<EnesGameManager>().isAdsRemoved)
HMSAdsKitManager.Instance.ShowInterstitialAd();
losePanel.SetActive(true);
HMSAchievementsManager.Instance.GetAchievementsList();
}
else
{
updateHealthDisplay();
}
}
Basically, just calling the ShowInterstitialAd() function is enough to show the ads. Once the player dies, it will be shown immediately and after the user closes it, the lose panel will be shown.
Like most kits, there are callbacks that you may want to implement. For example, interstitial ads has “OnInterstitialAdClosed” callback that can be implemented. If you want to control what will happen right after the user closes the interstitial ad, you can implement this by using the code below in start function.
void Start()
{
//...
HMSAdsKitManager.Instance.OnInterstitialAdClosed = OnInterstitialAdClosed;
}
The second “OnInterstitialAdClosed” is the name of the function that you will be defining. So it can be changed to whatever you like. You can generate a new function manually by using the name you defined in the right hand side of the equal sign. However, since some callbacks come with parameters from the plugin, it is recommended that you show the potential fixes and generate one from there automatically. By this way, you will also which parameters, if any, will be returned from the callback. You can check other methods in all kits by typing “HMS…Manager.Instance.On…” and see which callbacks are supported.
Analytics KitIn the code above, you can see an AnalyticsManager instance is used. That is the whole implementation of analytics kit I have in my game. After I enabled it from the Kit Settings menu in the Unity Editor, I can call HMSAnalyticsManager however I like, as in the other managers. Here, my scenario for Analytics Kit is sending the score of the player to the server to see how much score people are achieving. You can use, just as I did, SendEventWithBundle function to send whatever items need to be sent as your game logic requires. The function requires an EventID, key and a value to be sent that can be of type string or int. That’s it and now you can check if the parameters are coming to AGC console by checking the tab “Real-time Overview”
Some of the events are predefined. As long as you enable Analytics Kit, they will be sent to the console anyway, even if you do not code anything in your game. If you cannot see your own custom event here, I would suggest adding that even manually from the Events tab close to bottom in AGC console. You can also look for support from the Huawei Developer website and/or forum.
Crash KitCrash Kit, when clicked, is automatically implemented thanks to the plugin. You should see crash reports in AGC Console, if any crash appears. You can also deliberately cause your app to crush, but how to do so is outside the scope of this article.
Push KitPush Kit, like Crash Kit, is also automatically enabled when you tick the box besides it. It is complete and ready to use. Simple as that, you should go to AGC Console, create a notification and you should receive notification depending on the time you set.
Tips & Tricks
Do not forget to get the agconnect-services.json file from the AGC and paste it to the StreamingAssets folder. The folder must be placed inside Assets folder of the Unity files.
In case any method or code piece that I shared will not work and you face any compiler complaints, make sure that you have imported the right libraries with “using” keyword. For any usage of the plugin, first line below is required and the other two lines are needed for most functions related to the kits. Make sure you imported them to use them smoothly.
using HmsPlugin;
using HuaweiMobileServices.Game;
using HuaweiMobileServices.Utils;
It is very normal that your game is different and the scenario you wanted this kits may differ from mine. That’s why, I always talked about how my need/scenario for the kit and then implemented it. If you are having trouble how to convert this to your own game logic, try to understand what I did and where, so you can implement the similar functionality where you want it to be in your own game.
Please make sure that your package name ends with either . Huawei or with .HUAWEI if you want to use IAP in your game. If you used another package name, please change it for AppGallery. Otherwise, IAP will not work. IAP will be talked about in part 3 but I wanted to warn here, so if you do not have an existing game yet, you can start off right.
ConclusionIn this article, we integrated many kits to our game. This was not just a “to integrate, do this” kind of article, but rather I tried to show you a real game scenario, so while you are applying this article to your game, you will hopefully have a better understanding. With Plugin 2.0, the speed of integration has increased dramatically, reduced down from days to perhaps hours depending on the complexity of your app.
I hope that this article has been helpful for you. You can always ask questions below, if you have anything unanswered in your mind.
Remaining two kits will be talked about here, in the part 2.
See you there!
References
HMS Unity Plugin 2.0 Branch (Github Page)
Documentation of every single kit in Huawei Docs (Links are present in the GitHub readme)
Checkout in forum
{
"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"
}
IntroductionIf you are not coming to this article from the Part 1 of the series, you can read here. This is the second part of our HMS Unity Plugin 2.0 integration guide. As you know, I wanted to talk about a part of GameService here because it requires a bit more work, not because of the plugin but because of its intrinsic nature. Adding products, managing behaviors, configuring achievements etc. take a bit more time in the AGC side. I will try to give as many details as I can give in this article; but since some of the topics are not directly related with the plugin, you may further research on how to do the tasks that I do not extensively talk about here.
I will be talking about just the Achievements parts of the GameService. However, it also has the capabilities of SaveGame and Leaderboard. You can read more about them in other articles and believe me, they are as easy to integrate as the ones I talk about, thanks to the HMS Unity Plugin 2.0.
This article also assumes that you have completed the steps in Part 1, at least the ones that are essential. GameService is already dependent on Account Kit you must check Account Kit as well from the Kit Settings menu, even if you will not use it directly in your game. (Plugin should automatically tick it for you once you tick GameService)
You do not have to integrate other kits to integrate these two kits, but some AGC side requirements are standard for all kits. I will talk about the specific parts that are about GameService here and IAP (In-app purchases) in part 3.
Without further ado, let’s get started.
GameServiceAfter enabling GameService in HMS Settings (aka Kit Settings) menu, a “Game Service” tab will be automatically added to the settings menu, as can be seen below in the screenshots. Now, I walk you through GameService step by step for those who want a bit of additional information.
Sign-In Function ImplementationAs I have warned in part 1, for the use of GameService, sign-in is required. This must be either done through Account Kit by yourself, or through GameService.
The easiest way to the do this is to just to check the box at the bottom of GameService tab. When you tick “Initialize On Start”, whenever users start your game, your game will try to log the user in immediately and they will see the “Welcome *username*” greeting message immediately if they logged in at least once in your game.
In the first-ever login in your game, they will be directed to the Huawei login page automatically, which will be done at the very first opening of your app. If you choose to do this, you do not even have to implement Account Kit. That’s it, login is done and you are ready to continue with just one click.
If you opt for not checking the box because this is not a desirable in-app behavior for you, then you must initialize the GameService manually and use the Account Kit in your own logic to log the user in.
It requires a bit of code but is not hard at all. Let’s assume that you sign-in at the Start() function of your app using Account Kit. What you have to do is to implement the SignInSuccess callback. If login is successful, success callback will be automatically executed and in there, you must initialize the GameService with just one line of code.
void Start()
{
HMSAccountManager.Instance.SignIn(); //sign the user in HMSAccountManager.Instance.OnSignInSuccess = OnSignInSuccess;
//implement callback on Start()
}
private void OnSignInSuccess(AuthAccount obj)
{
HMSGameManager.Instance.Init();
}
That’s it for the manual control. Now, you control where you want to sign your users in and also initialize the GameManager so that you can use Achievements, Leaderboards and SaveGame features.
I suggest that whichever way you choose, you do this at the first scene of the app (like a main menu etc.) and not inside the game itself, so users will not be bothered by sign-in process in-game.
AchievementsI want to add achievements to my app so when the user has done certain actions, I will reward them by unlocking some achievements. There are mainly two actions required to be done by you, the developer: First, add achievements to your app in AGC and get their ID. And second, enter the IDs to Achievements part of the plugin and implement in-game logic. That means, you need to determine where you will grant your users an achievement in your game. What kind of actions are needed to be carried out to get them?
In my case, this process is very simple. I have “Beginner, Medium and Master Scorer” achievements defined and I grant them whenever the user completes a certain score in my game. Since my game is very simple, the score is the utmost indicator of a “skilled” player, so I thought, why not?
First, let’s go to AGC (AppGallery Connect) together to add some achievements. You can go to AGC by using this link. Sign in to your developer account, click “My apps” and choose your game from the list. You will be directed to “Distribute” tab. From the left-upper bar, choose “Operate” tab instead. There, you will have “Product Management” tab opened at first from the left navigation menu, which I will use it for IAP later. Now, move to the Achievements tab to add some achievements to your game. Click Create on right to create an achievement.
You enter a name and a description to remember what this achievement is for. You can leave “incremental achievement” unchecked because I do not need it for this simple game. Also for the “revealed, hidden” option, what I did was to make the BeginnerScorer achievement revealed and the other two are hidden. So user will see them in achievements list but will not know what they are before achieving the previous achievement. You can configure them however you like. Make sure they are fitting to your game content, so users will try to play longer to achieve them. Also, I set the same logo for every one of them but I suggest you design different icons for each and every one of your achievements.
After you are done, it should look like something like this:
Do not release your achievements so you can test them. If you release them, they will be checked by AGC and be approved if they are proper. However, then, you cannot reset their progress even if you did not publish your game yet. Thus, to make sure that the development side works correctly, I will leave them as it is. Whenever you achieve them in your own game testing, you can just reset the progress and keep testing if you want to change something you do not like.
Now that I am done creating them, you can click “Obtain Resources” above and copy their IDs one by one. Then, paste them to our HMS Settings menu. After you copied them all, click “Create Constant Classes”, so HMS Unity Plugin can create a constant class for you.
The constant class will be called HMSAchievementConstants. Now let’s see how can I use them. I will need the “state”s of these achievements for my game implementation because I will check the states to grant the achievements one by one. Imagine a scenario where BeginnerScorer needs 15 points and MediumScorer needs 25 points to unlock. If the user surpasses 25 points in the first game, then the game would grant them consecutively in one run. This is not what I want, so I will access the achievement states and that requires Achievement objects. You do not have to use Achievement objects, you can just use the constant class to retrieve the IDs and immediately reveal and/or unlock them.
public void TakeDamage(int damageAmount)
{
//...
if (health <= 0)
{
//...
//Player is dead
losePanel.SetActive(true);
HMSAchievementsManager.Instance.GetAchievementsList();
}
}
Remember my TakeDamage function shown above. Since I will be unlocking achievements when the game is done, I will call my GetAchievementsList() function after the player dies. This function is necessary because it has several callbacks that which I will use. You should decide to call this function depending on your game logic and code structure. As I always do, I tell my structure in detail so you can project where you should put yours.
void Start()
{
//... HMSAchievementsManager.Instance.OnGetAchievementsListSuccess = OnGetAchievemenListSuccess;
HMSAchievementsManager.Instance.OnGetAchievementsListFailure = OnGetAchievementsListFailure; //optional
}
In the Start() function of wherever you will call GetAchievementsList() function, do as above. Basically, you are registering the these callbacks so when getting the achievements list is successful, the OnGetAchievemenListSuccess that you will write will be triggered. Failure callback is optional, you can track the errors and add some user warning if you like.
using System.Linq;
private void OnGetAchievemenListSuccess(IList<Achievement> achievementList)
{
//Implement your own achievement system here...
//Achievement beginnerScorer = achievementList[3]; -> Same thing as the line below
Achievement beginnerScorer = achievementList.First(ach => ach.Id == HMSAchievementConstants.BeginnerScorer); //Score of 15 is needed
Achievement mediumScorer = achievementList[4]; //Score of 25 is needed
Achievement masterScorer = achievementList[5]; //Score of 50 is needed
if (score >= 15 && beginnerScorer.State != 3)
{
HMSAchievementsManager.Instance.UnlockAchievement(beginnerScorer.Id);
//HMSAchievementsManager.Instance.UnlockAchievement(HMSAchievementConstants.BeginnerScorer); -> same as above
HMSAchievementsManager.Instance.RevealAchievement(mediumScorer.Id);
}
else if (score >= 25 && beginnerScorer.State == 3 && mediumScorer.State != 3)
{
HMSAchievementsManager.Instance.UnlockAchievement(mediumScorer.Id);
HMSAchievementsManager.Instance.RevealAchievement(masterScorer.Id);
}
else if (score >= 50 && mediumScorer.State == 3 && masterScorer.State != 3)
{
HMSAchievementsManager.Instance.UnlockAchievement(masterScorer.Id);
}
}
private void OnGetAchievementsListFailure(HMSException obj)
{
Debug.Log("OnGetAchievementsListFailure with code: " + obj.ErrorCode);
}
Let me explain the code above. It may look a bit complicated but it is not hard to understand. Since I registered to my callbacks, I need to implement them now. You need to implement the this callback yourself, so users can unlock achievements.
As I said, since I need the states, I use the objects of Achievement class. Normally, if I were not to care about the states, I would not even need them. I would just do:
HMSAchievementsManager.Instance.UnlockAchievement(HMSAchievementConstants.BeginnerScorer);
So, if you do not need states or other properties of Achievement class, you can also do the same. Your development cost is much less this way, thanks to the plugin. As you see, you do not even need to copy the long IDs to wherever you want to use them, you can just call constants class and use the IDs by the name you gave to them.
In the following part of the code, I get my achievements one by one from the callback parameter. A list already returned to me and I can pick what I want. Since I previously added 3 more achievements that I did not show you, my ordinal numbers start from 4. (you can check AGC console screenshot above)
Achievement beginnerScorer = achievementList.First(ach => ach.Id == HMSAchievementConstants.BeginnerScorer); //15 score is needed
Achievement mediumScorer = achievementList[4]; //25 score is needed
What I do is to get to the (4–1)rd index to get my beginner achievement. You can always match the indices of the achievements from the AGC console ordinals. There is also another way. If you import System.Linq, you can also use First function to get the achievements without using index numbers. Example is shown above. This is just to provide some alternatives for you.
In the rest of the code, I check the states and if they are not unlocked yet, or surely unlocked in the next step, I unlock my achievements. Since I made the other two achievements hidden, I also reveal them when the user unlocks the previous achievement. It is all under my control, so you can code your own logic however you like.
Also notice that I use the instance of HMSAchievementsManager when revealing and unlocking achievements. No further code required to call this because plugin handles the other cumbersome processes for you.
Achievements are done. You can see how I have become the master of my own game.
One little thing is left though. Users should be able to see what kind of achievements are there even if they are hidden. (It will be shown as hidden)
AppGallery already provides an interface for this, thus, if you want to implement this functionality you can just call one line function.
public void ShowAchievements()
{
HMSAchievementsManager.Instance.ShowAchievements();
}
Since I use a button click to call this function, I put the code in another local function. Depending on your requirements, you can call it directly.
Tips & Tricks
There are certain other callbacks related to the kits that you use through plugin. I did not talk about them because they were irrelevant for my use case. You can always check them with IntelliSense suggesting while coding. It should suggest available callbacks after Instance.
ConclusionI have integrated simple achievements to my game so that users could spend more time in my game. You can adjust the details I provided for your use case and devise a scenario that works for you.
I hope that this article has been helpful for you. You can always ask questions below, if you have anything unanswered in your mind.
The only remaining kit is IAP and it will talked about here, the part 3.
See you there!
References
HMS Unity Plugin 2.0 Branch (Github Page)
Documentation of every single kit in Huawei Docs (Links are present in the GitHub readme)
Checkout in forum
{
"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"
}
IntroductionBefore I begin, if you are not coming to this article from part 3 of the article, you can read here. For part 2 of the series, you can read here. If you have not seen part 1 either, you can click here. This is the fourth part of our HMS Unity Plugin 2.0 integration guide. This time I will be talking about other features of GameService: Leaderboards and SaveGame.
Normally, this part of the series was not planned, however, I thought that developers who might be interested in the other two parts of the GameService may be left off without a guide. Thus, I am adding this 4th part. I will be using a different game than the other three, but, I will try to be as helpful and as guiding as I can in this article as well, so you can adjust these two features to wherever you want to.
Small Warning Before We ProceedI will show the AGC side steps as much as I can, but this article also assumes that you have completed the part 1 app/project creation etc. and have an app running in contact with AGC and the plugin is ready to use. (You can just enable Banner Ads and tick test ads to test if the plugin is working.) Also, for the tests, make sure your account is registered as a sandbox test account. Details can be found in the docs link, if you have not done it yet.
My Game
As I said, I am using a different game for this part, but again a very simple hyper-casual one. You have a rock and 5 rock counts at the beginning of the game. You throw it in a projected trajectory to hit the balloons and you score points. Since the balloon generation and speed are determined at random, it is not as easy as it looks but it has a very simple logic. Its name is “Hit The Target”.
GameService — LeaderboardsLeaderboards let you create leaderboards in your game so that the players can compete and see how they rank in comparison to others. Huawei, like achievements, has its own UI to help you up setting up the leaderboard system. All you have to do is to make sure that GameService is enabled in AppGallery Connect (aka AGC), then create a leaderboard with some pre-defined rules and use the plugins easy-to-use managers to send/submit scores to leaderboards. It literally takes one line to submit the score in simple scenarios after the AGC is set up, thanks to HMS Unity Plugin 2.0.x.
AGC SideYou need to sign in to AGC and go to My apps. Then choose your app. My app in this case is “Hit The Target”. Go from “Distribute” tab to “Operate” tab and choose “Leaderboards”. Then click “New” button. You should see the screen below.
Add the details of your leaderboard. What kind of scores you want, how the formatting should be, min/max numbers that can be submitted etc. are all can be edited here. When you are done, click “Save”.
Now, we need to copy the ID of the leaderboard, so we can feed it to the plugin and use it in our game.
Do not release the leaderboards. Click “Obtain Resources” and copy the ID of the leaderboard you just created.
Unity SideNow head to Unity. Open the drop-down Huawei menu, click Kit Settings. Enable GameService (Account Kit will automatically be enabled and it is okay.) and go to the GameService tab.
Add a name to your leaderboard (which I used the same long name that I used in AGC) and paste the ID you copied in the previous step. Then, click create constant classes. Make sure to check the “Initialize On Start” button, or else you will have to write additional code.
Coding PhaseThe coding phase in Leaderboards is very easy. All you have to do is to submit the score to the leaderboard you have created.
Code:
HMSLeaderboardManager.Instance.SubmitScore(HMSLeaderboardConstants.HitTheTargetGeneralLeaderboard, GameManager.score /*score you want to submit*/);
You use the instance of HMSLeaderboardManager as usual and just call SubmitScore() function. Use the constant class that is automatically generated by the plugin to get which leaderboard you want to submit and enter the score type as the second parameter.
That's it for submitting the score, you should see it in the leaderboards and in the AGC.
One thing left for the integration. You should allow your users to see the leaderboard UI done by Huawei and check which leaderboards are there and which scores are submitted. This will help with the competitiveness of the game.
For that, all you need to do is to call again a one-liner code thanks to the plugin.
Code:
HMSLeaderboardManager.Instance.ShowLeaderboards();
I use this line inside a function and call that function in a UI Button onClick. Thus, whenever users click on the button, they are directed to the leaderboard UI and check which leaderboards are present. It should look like below.
GameService — SaveGameSaveGame takes more time than usual because of its very nature and purpose but it is a very powerful tool. As the name suggests, this kit helps you save the game progress of the player to the Huawei Cloud and lets the players load the saved progress to the current game. By this way, users never lose progress. It has its own UI to show saved games but it is also possible to implement your own UI, if you wish to do so.
You may save and load the game progress automatically in the background and set up a load-on-prompt system, or, like I would do it, save and load by the user’s actions. It is totally up to and to your game.
In my game, since it is a very simple game, I save the progress (score) and the rockCount and let the user save whenever s/he wishes. Later, the user can load this progress anytime in the pause menu and keep playing from that saved game. I will use the default Huawei UI, but if you wish to implement your own UI, I will leave links to docs where it talks about custom UI in the reference section. Make sure you check out that link, or alternatively, click here. I will talk about the code details later. First, let’s solve some error codes that you may possibly bump into.
Error Code 7219 in HMS GameService and Its Solution
If you have started the development already, you might have gotten the error 7219 in GameService SaveGame implementation and wonder why that could arise. It is because you need to agree to the user agreement in Drive Kit by Huawei located in https://cloud.huawei.com/ to be able to use SaveGame feature. The reason is that SaveGame saves the game files to the cloud using Drive Kit and if that agreement is not signed by your developer account, you will receive an error called 7219 and will not be able to proceed/test your code. Make sure you click the link, sign in, and agree to it. This is suggested before you start the implementation.
Coding PhaseBefore going into actual coding, let me mention this first. To let the users see the saved games in default UI and load the games with simple clicks, call the one-liner function below. (just like leaderboards) It will open the UI provided by AppGallery.
Code:
HMSSaveGameManager.Instance.ShowArchive();
Make sure you assign this code as an onClick to a UI button, or implement your own logic to access that UI.
Now, for the SaveGame we follow this doc, but on a Unity setting with the plugin. The order will not change but to see how you should code, bear with me. I will share the full new class in my game and explain/break down the code later. You do not have to open the docs, I will share the steps with you below, but always keep this doc in mind for the latest updates.
What needs to be done:The order in the official doc (written in Java):
Request DRIVE_DATA permission from the user and get ArchivesClient() object.
Get maxThumbnailSize and detailSize from the SDK. These must be requested, although you may not need them in your code.
Determine the details to save (your own parameters to save) and create ArchiveDetails object.
Write the archive metadata (such as the archive description, progress, and cover image) to the ArchiveSummaryUpdate object.
Call addArchive() method to save the game to the drive.
Notes:
You do not need to request a user permission in Unity side thanks to the plugin. It will be handled automatically.
Others will be talked about in detail below on a simple game I mentioned. If you have more complicated cases that cannot be adjusted, please refer to official documentation.
Coding in C#Let me share the code first.
Code:
using UnityEngine;
using HmsPlugin;
using HuaweiMobileServices.Game;
using System.Text;
public class ManagerOfSaveGame : MonoBehaviour
{
// Start is called before the first frame update
int maxThumbnailSize;
int detailSize;
GameStarterScript gameStarterScript;
void Start()
{
gameStarterScript = GameObject.Find("PauseButton").GetComponent<GameStarterScript>();
//HMSSaveGameManager.Instance.GetArchivesClient().LimitThumbnailSize.AddOnSuccessListener((x) => { });
HMSSaveGameManager.Instance.GetArchivesClient().LimitThumbnailSize.AddOnSuccessListener(LimitThumbnailSizeSuccess);
HMSSaveGameManager.Instance.GetArchivesClient().LimitDetailsSize.AddOnSuccessListener(LimitDetailSizeSuccess);
HMSSaveGameManager.Instance.SelectedAction = SelectedActionCreator;
HMSSaveGameManager.Instance.AddAction = AddActionCreator;
}
private void LimitDetailSizeSuccess(int thumbnailSize)
{
maxThumbnailSize = thumbnailSize;
}
private void LimitThumbnailSizeSuccess(int returnedDetailSize)
{
detailSize = returnedDetailSize;
}
private void SelectedActionCreator(ArchiveSummary archiveSummary)
{
//load your game
Debug.Log("YOU ENTERED SELECTED ACTION CALLBACK!");
long score = archiveSummary.CurrentProgress;
long rockCount = archiveSummary.ActiveTime;
if (GameManager.rockCount <= 0)
{
gameStarterScript.PlayGameWithParameters((int)score, (int)rockCount);
}
else
{
Debug.Log("Cannot load a finished game");
}
//start the game but change the parameters to load.
}
private void AddActionCreator(bool obj)
{
if(GameManager.rockCount != 0)
{
//save your game
string description = "Rock:" + GameManager.rockCount + " Score:" + GameManager.score;
long playedTime = GameManager.rockCount; //rock count
long progress = GameManager.score;
ArchiveDetails archiveContents = new ArchiveDetails.Builder().Build();
archiveContents.Set(Encoding.ASCII.GetBytes(progress + description + playedTime));
ArchiveSummaryUpdate archiveSummaryUpdate =
new ArchiveSummaryUpdate.Builder()
.SetActiveTime(playedTime)
.SetCurrentProgress(progress)
.SetDescInfo(description)
//.SetThumbnail(bitmap)
//.SetThumbnailMimeType(imageType)
.Build();
HMSSaveGameManager.Instance.GetArchivesClient().AddArchive(archiveContents, archiveSummaryUpdate, true).AddOnSuccessListener((archiveSummary) => {
string fileName = archiveSummary.FileName;
string archiveId = archiveSummary.Id;
//if you wanna use these you can. But this just indicates that it is successfully saved.
print("fileName is: " + fileName + " and archiveId is " + archiveId);
print("GamePlayer is: " + archiveSummary.GamePlayer + " and GameSummary is " + archiveSummary.GameSummary);
print("CurrentProgress is: " + archiveSummary.CurrentProgress + " and ActiveTime is " + archiveSummary.ActiveTime);
}).AddOnFailureListener((exception) => {
print("statusCode:" + exception.GetBaseException());
});
}
else
{
print("Game is over. Cannot save a finished game!");
}
}
}
Let's break down the code to understand.
First, I created a separate function called ManagerOfSaveGame.cs to manage SaveGames. I also create a game object in my scene and put the script in it. It has no appearance in the scene to the user. This is just to control it.
In the Start() function, I get the methods to request the parameters because documentation lists them as first thing to do. I will not use them later, so I just get the parameters and be done with it.
Then I create the corresponding functions in my script to SelectedAction and AddAction fields. First is to load the game from UI on click and the second is to save the game to the drive.
AddAction (Save your game)If I were you, I would copy the contents of the shown function and paste it to my game. Then, I would alter the parameters I want to alter. I first put an if check to see if the game is over. Since my game is a simple throw game and my rock count goes from 5 to 0, 0 rock count means a finished game. Although I could, I do not allow my users to save their games if they are already done because my UI technically allows users to access save game screen after the game is over.
You have several parameters that you can adjust. My code above follows the documentation order so you can be sure of that. What you should do with your game is to determine a description of the save games, a progress indicator, and if needed, the active time. I keep my score in score parameter and my rock count in active time parameter. Normally, I do not use time related functions but since the parameters that one can save is limited, I decided to use active time as an in-game save functionality. You can also do the same if you need. Typically, you can keep the level information, score information etc. in the progress “long” type parameter, and retrieve it when loading the game.
Rest goes according to “rules”. You can take them as is and adjust where needed. I do not use a Bitmap or an image to save with my save files. You can alternatively take a screenshot of the save moment and save it with the current progress. Huawei SDK allows that too, but I do not need it in my game.
Then you call AddArchive method as shown and success callback indicates that the game is saved. You need need to do anything with return parameter but I showed how to retrieve values nonetheless, if anyone ever needs it.
You can also get the exception message if the game cannot be saved for some reason.
SelectedAction (Load your game)This function will be automatically called when the users click on a previously saved game in default Huawei UI. Thus, what you need to do is to retrieve the values that you saved while saving the game and load the game according to your game logic.
For my case, I retrieve the rock count and score as shown, then start my scene with these parameter. They are set as static, so I can alter them easily.
You can adjust here depending on your game logic and how you want to load your game when the user clicks it. For example, if you kept the level information in progress parameter, then you try reloading that Unity scene to start that level from scratch.
Tips and Tricks
Do not publish the leaderboards if you want to keep testing them. Unless you are done with testing and want to publish your app in AppGallery, it should always be left as in Testable mod and releasing it will hinder your testing efforts.
Custom UI can be programmed, although Huawei already provides a UI for Leaderboards and SaveGames (for Achievements too!). Please refer to docs below in references to see the details.
When loading your game, beware that progress parameter is called “CurrentProgress”. If you called it something else, like I called just “progress”, make sure you retrieve the “CurrentProgress” field because there is no such field called “progress”.
ConclusionThat's it! You have successfully integrated Leaderboards and SaveGame features. They have a wide variety of use cases and I know that mine are simple; but at least, I believe, I gave you the insight so that you can adapt these kits to your game and draw more users.
I hope that this article series has been helpful for you. You can always ask questions below, if you have anything unanswered in your mind.
Good luck on the store and see you in my other articles!
References
HMS Unity Plugin 2.0 Branch (Github Page)
GameService Result Codes Page
SaveGame Docs
Leaderboard Docs
Documentation of every kit in Huawei Docs (Links are present in the GitHub readme)
Original Source