How Can I Integrate Auth Service of AppGallery Connect in Flutter? - Huawei Developers

Recently, it is found that some services of AppGallery Connect start to support Flutter. Let’s have a try on Auth Service with an email address.If you want to quickly experience this service, see the demo on GitHub.
Integration Procedure
1. Install the Flutter environment.
a) Download the Flutter SDK package from https://flutter.dev/docs/get-started/install/windows.
{
"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"
}
Decompress the package to any directory, for example, D:\Flutter.
b) Add the Flutter command file as an environment variable. Here, the path is D:\Flutter\flutter_windows_1.22.2-stable\flutter\bin.
c) In Android Studio, go to File > Settings > Plugins, download the Flutter and Dart plug-ins, and restart Android Studio for the plug-ins to take effect.
2. Create a project and enable Auth Service.
a) Create an Android app and enable Auth Service for it in AppGallery Connect.
b) Enable the mobile number, email address, and anonymous account as the authentication modes.
c) In Android Studio, create a Flutter project.
d) Add the agconnect-services.json file to the android/app directory.
e) Configure the Maven repository address and AppGallery Connect plug-in address.
a. Open the build.gradle file in the android directory of the Flutter project.
b. Go to allprojects > repositories and configure the Maven repository address.
c. Go to buildscript > repositories and configure the Maven repository address.
d. Go to buildscript > dependencies and configure the AppGallery Connect plug-in address.
1. Add build dependencies and the AppGallery Connect plug-in address.
a. Open the build.gradle file in the android/app directory of the Flutter project.
b. Add the following content to the file.
3. Integrate the AppGallery Connect SDK.
Add the dependency to the pubspec.yaml file of the Flutter project.
XML:
dependencies:
flutter:
sdk: flutter
# Add the following line:
agconnect_auth: ^1.1.0
Click Pub get to synchronize the data.
4. Integrate functions.
1. Anonymous account sign-in
Call the signInAnonymously API.
JavaScript:
_signIn() async {
AGCAuth.instance.signInAnonymously().then((value) {
setState(() {
_log =
‘signInAnonymously = ${value.user.uid} , ${value.user.providerId}’;
});
});
}
You can obtain user information from the returned value. In this example, the UID is returned.
2. Sign-in with a mobile number or an email address
A verification code needs to be sent.
For a mobile number, call the requestVerifyCode method, and pass the mobile number, country/region code, and settings.
JavaScript:
_requestPhoneVerifyCode(VerifyCodeAction action) {
String countryCode = _countryCodeController.text;
String phoneNumber = _phoneNumberController.text;
VerifyCodeSettings settings = VerifyCodeSettings(action, sendInterval: 30);
PhoneAuthProvider.requestVerifyCode(countryCode, phoneNumber, settings).then((value) => print(value.validityPeriod));
}
For an email address, call the requestVerifyCode method, and pass the email address and settings.
JavaScript:
_requestEmailVerifyCode(VerifyCodeAction action) {
String email = _emailController.text;
VerifyCodeSettings settings = VerifyCodeSettings(action, sendInterval: 30);
EmailAuthProvider.requestVerifyCode(email, settings)
.then((value) => print(value.validityPeriod));
}
Then, create a user.
To create a mobile phone user, call the createPhoneUser method, and pass the PhoneUser object.
JavaScript:
_createPhoneUser() async {
bool result = await _showPhoneDialog(VerifyCodeAction.registerLogin);
if (result == null) {
print("cancel");
return;
}
String countryCode = _countryCodeController.text;
String phoneNumber = _phoneNumberController.text;
String verifyCode = _verifyCodeController.text;
String password = _passwordController.text;
AGCAuth.instance.createPhoneUser(PhoneUser(countryCode, phoneNumber, verifyCode, password: password)) .then((value) {
setState(() {
_log = 'createPhoneUser = ${value.user.uid} , ${value.user.providerId}';
});
}).catchError((error)=>print(error));
}
To create an email address user, call the createEmailUse method, and pass the EmailUser object.
JavaScript:
_createEmailUser() async {
bool result = await _showEmailDialog(VerifyCodeAction.registerLogin);
if (result == null) {
print("cancel");
return;
}
String email = _emailController.text;
String verifyCode = _verifyCodeController.text;
String password = _passwordController.text;
AGCAuth.instance
.createEmailUser(EmailUser(email, verifyCode, password: password))
.then((value) {
setState(() {
_log = 'createEmailUser = ${value.user.uid} , ${value.user.providerId}';
});
}).catchError((error) => print(error));
}
Then, configure the sign-in mode. If a user signs in with a password:
· For a mobile number, call the signIn method, and pass the user token generated using the mobile number.
JavaScript:
_signInWithPassword() async {
bool result = await _showPhoneDialog(VerifyCodeAction.registerLogin);
if (result == null) {
print("cancel");
return;
}
String countryCode = _countryCodeController.text;
String phoneNumber = _phoneNumberController.text;
String password = _passwordController.text;
AGCAuthCredential credential = PhoneAuthProvider.credentialWithPassword(countryCode, phoneNumber, password);
AGCAuth.instance.signIn(credential).then((value) {
setState(() {
_log = 'signInWithPassword = ${value.user.uid} , ${value.user.providerId}';
});
});
}
· For an email address, call the signIn method, and pass the user token generated using the email address and its password.
JavaScript:
_signInWithPassword() async {
bool result = await _showEmailDialog(VerifyCodeAction.registerLogin);
if (result == null) {
print("cancel");
return;
}
String email = _emailController.text;
String password = _passwordController.text;
AGCAuthCredential credential =
EmailAuthProvider.credentialWithPassword(email, password);
AGCAuth.instance.signIn(credential).then((value) {
setState(() {
_log =
'signInWithPassword = ${value.user.uid} , ${value.user.providerId}';
});
});
}
If a user signs in with a verification code:
· For a mobile number, call the signIn method, and pass the user token generated using the mobile number, password, and verification code.
JavaScript:
_signInWithVerifyCode() async {
bool result = await _showPhoneDialog(VerifyCodeAction.registerLogin);
if (result == null) {
print("cancel");
return;
}
String countryCode = _countryCodeController.text;
String phoneNumber = _phoneNumberController.text;
String verifyCode = _verifyCodeController.text;
String password = _passwordController.text;
AGCAuthCredential credential = PhoneAuthProvider.credentialWithVerifyCode(countryCode, phoneNumber, verifyCode, password: password);
AGCAuth.instance.signIn(credential).then((value) {
setState(() {
_log = 'signInWithVerifyCode = ${value.user.uid} , ${value.user.providerId}';
});
});
}
· For an email address, call the signIn method, and pass the user token generated using the email address, password, and verification code.
JavaScript:
_signInWithVerifyCode() async {
bool result = await _showEmailDialog(VerifyCodeAction.registerLogin);
if (result == null) {
print("cancel");
return;
}
String email = _emailController.text;
String verifyCode = _verifyCodeController.text;
String password = _passwordController.text;
AGCAuthCredential credential = EmailAuthProvider.credentialWithVerifyCode(
email, verifyCode,
password: password);
AGCAuth.instance.signIn(credential).then((value) {
setState(() {
_log =
'signInWithVerifyCode = ${value.user.uid} , ${value.user.providerId}';
});
});
}
3. Self-owned account
You need to create a JWT and obtain the user token for a self-owned account on your server. In your app, you need to use the token for sign-in only.
JavaScript:
_signIn() async {
bool result = await _showSelfBuildDialog(VerifyCodeAction.registerLogin);
if (result == null) {
print("cancel");
return;
}
String token = _selfBuildController.text;
AGCAuthCredential credential = SelfBuildAuthProvider.credentialWithToken(token);
AGCAuth.instance.signIn(credential).then((value) {
setState(() {
_log = 'signIn = ${value.user.uid} , ${value.user.providerId}';
});
});
}
5. Package the APK file.
Similar to Android, you only need to run your project in Android Studio.
For more details, please check:
Auth Service development guide:
https://developer.huawei.com/consum...Guides/agc-auth-introduction-0000001053732605
Auth Service codelab for Android:
https://developer.huawei.com/consumer/en/codelab/AuthenticationService/index.html#0
Auth Demo:https://github.com/AppGalleryConnect/agc-flutter-plugin/tree/master/agc-authservice-flutter

Related

Samachar a news application using HMS Push Kit Client + Server Side (Part2)

More information like this, you can visit HUAWEI Developer 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"
}
This article is the continuity of my previous article. To get a better picture or knowledge, refer my previous article first. Below is the link:
https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0202326236067510002&fid=0101187876626530001
Why you are having own server?
Using our own server to communicate with our app is generally the best option for sending push notification directly to our application. Because, our app will recognize and trust our own server which will allow us to control all transactions between our server and user devices.
Also if we need to send notification using Huawei AGC console, we need to copy and paste our users push token every time, which is a tedious job. Having our own server will allow us to store our users token and can send notification easily by fetching the entire list of token from database. That is what we are going to learn today.
Setting up the server
If you are not familiar with setting up your own local server and connecting the server with the device, refer my previous article “Build your own server from scratch to send push notification“. My previous article will help you setting up local server from scratch also, it is healthy to learn something new every day as our brain can store more information than a computer.
Prerequisite
1) We must have latest version of Node installed.
2) We must have latest version of Visual Studio Code installed.
3) We must have latest version of MongoDB database installed.
4) Laptop/desktop and Huawei mobile device must share same Wi-Fi connection.
5) We must have a working app integrate with HMS Push Kit.
We will divide this article into two parts
1) Server Side: The server side contains Node, Express, Request and JavaScript.
2) Client Side: The client side contains Android Native, Java, Retrofit and HMS Push Kit.
Demo
Send notification from server
Notification on device side
Goal
Our goal here is to subscribe, unsubscribe and send notification using topic-based message sending, also when user will tap the notification it will take user to a specific page. All this will be done using our local server side.
Server Side
Obtaining app-level access token API
The request header uses AccessToken for authentication, which is obtained using the service API provided by the open platform. The service API provides two modes to obtain AccessToken: authorization code mode and client password mode. This API uses the client password mode.
Do not apply for a new app-level access token each time before the server API is called. Frequent application requests may trigger rejection, leading to application failure within a specified period. Each access token has a validity period.
Within the validity period, it can be used repeatedly. You are advised to apply for an access token again, only when the server API is accessed and HTTP result code 401 is return
Code:
var request = require("request");
const getAppToken = (callBack) => {
var options = {
method: 'POST',
url: 'https://oauth-login.cloud.huawei.com/oauth2/v3/token',
headers:
{
'content-type': 'application/x-www-form-urlencoded',
host: 'Login.cloud.huawei.com',
post: '/oauth2/v2/token HTTP/1.1'
},
form:
{
grant_type: "client_credentials",
client_secret: 'Put Your Client Secret Here...',
client_id: 'Put Your APP ID Here ...'
}
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
var tokenValue = JSON.parse(body);
callBack(tokenValue.access_token);
});
}
exports.getAppToken = getAppToken;
Subscribe to a topic API
The API is used to subscribe to a topic for one or more users. A maximum of 1,000 tokens are allowed in each call request. Currently, this API only supports Android apps.
URL: https://push-api.cloud.huawei.com/v1/[appid]/topic:subscribe
API
subscribeToTopic.js
Code:
var request = require("request");
const subscribeToTopicNotify = (appLevelToken, tokenVal, topicSubscribeVal, callBack) => {
var options = {
method: 'POST',
url: 'https://push-api.cloud.huawei.com/v1/[appid]/topic:subscribe',
headers:
{
authorization: 'Bearer ' + appLevelToken,
host: 'oauth-login.cloud.huawei.com',
post: '/oauth2/v2/token HTTP/1.1',
'content-type': 'application/json'
},
body:
{
topic: topicSubscribeVal,
tokenArray: tokenVal
},
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
// console.log(body);
var notify = JSON.parse(JSON.stringify(body));
// console.log(">>>"+notify.msg);
callBack(notify.msg);
});
}
exports.subscribeToTopicNotify = subscribeToTopicNotify;
app.js
Code:
app.post('/subscribeToTopic', (req, res, next) => {
// topicSubscribeVal = req.body.topic;
let topic = {
topic: req.body.topic,
};
console.log(topic.topic);
// Fetching Token from mongodb ...
dbase.collection('token').find().toArray((err, results) => {
if (results) {
//clear the token list ...
arrToken = [];
// adding token in the list ...
for (var i = 0; i < results.length; i++) {
console.log("Token " + i + " " + results[i].token);
arrToken.push(results[i].token);
}
// if error code 401 returned it means access token becomes invalid
// and we need to obtain a new token. Token Validity is 60 mins...
// fetchin app level access token here ...
appToken.getAppToken((callBack) => {
console.log("TOKEN >>>" + callBack);
appLevelAccesToken = callBack;
subscribeToTopic.subscribeToTopicNotify(appLevelAccesToken, arrToken, topic.topic,callBackMessage => {
notifySucesssMessage = callBackMessage;
console.log(notifySucesssMessage);
if(callBackMessage!=null){
res.send(callBackMessage);
}
});
});
}
});
});
Unsubscribe to a topic API
The API is used to unsubscribe to a topic for one or more users. A maximum of 1,000 tokens are allowed in each call request. Currently, this API only supports Android apps.
URL: https://push-api.cloud.huawei.com/v1/[appid]/topic:unsubscribe
API
unSubscribeToTopic.js
Code:
var request = require("request");
const unSubscribeToTopicNotify = (appLevelToken, tokenVal, topicSubscribeVal, callBack) => {
var options = {
method: 'POST',
url: 'https://push-api.cloud.huawei.com/v1/[appid]/topic:unsubscribe',
headers:
{
authorization: 'Bearer ' + appLevelToken,
host: 'oauth-login.cloud.huawei.com',
post: '/oauth2/v2/token HTTP/1.1',
'content-type': 'application/json'
},
body:
{
topic: topicSubscribeVal,
tokenArray: tokenVal
},
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
// console.log(body);
var notify = JSON.parse(JSON.stringify(body));
// console.log(">>>"+notify.msg);
callBack(notify.msg);
});
}
exports.unSubscribeToTopicNotify = unSubscribeToTopicNotify;
app.js
Code:
// Push Kit unsubscribe to a topic ...
app.post('/unsubscribeToTopic', (req, res, next) => {
let topic = {
topic: req.body.topic,
};
// Fetching Token from mongodb ...
dbase.collection('token').find().toArray((err, results) => {
if (results) {
//clear the token list ...
arrToken = [];
// adding token in the list ...
for (var i = 0; i < results.length; i++) {
console.log("Token " + i + " " + results[i].token);
arrToken.push(results[i].token);
}
// if error code 401 returned it means access token becomes invalid
// and we need to obtain a new token. Token Validity is 60 mins...
// fetchin app level access token here ...
appToken.getAppToken((callBack) => {
console.log("TOKEN >>>" + callBack);
appLevelAccesToken = callBack;
unSubscribeToTopic.unSubscribeToTopicNotify(appLevelAccesToken, arrToken, topic.topic,callBackMessage => {
notifySucesssMessage = callBackMessage;
console.log(notifySucesssMessage);
if(callBackMessage!=null){
res.send(callBackMessage);
}
});
});
}
});
});
Querying the topic subscription list API
The API is used to query the topic subscription list of a token. Currently, this API only supports Android apps.
URL: https://push-api.cloud.huawei.com/v1/[appid]/topic:list
API
getTopicList.js
Code:
var request = require("request");
const getTopicList = (appLevelToken, tokenVal, callBack) => {
var options = {
method: 'POST',
url: 'https://push-api.cloud.huawei.com/v1/[appid]/topic:list',
headers:
{
authorization: 'Bearer ' + appLevelToken,
host: 'oauth-login.cloud.huawei.com',
post: '/oauth2/v2/token HTTP/1.1',
'content-type': 'application/json'
},
body:
{
token: tokenVal
},
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
// console.log(body);
var notify = JSON.parse(JSON.stringify(body));
console.log(">>>"+notify);
callBack(notify.topics);
});
}
exports.getTopicList = getTopicList;
app.js
Code:
app.post('/getTopicList', (req, res, next) => {
console.log("CALLLLLING")
// Fetching Token from mongodb ...
dbase.collection('token').find().toArray((err, results) => {
if (results) {
//clear the token list ...
arrToken = [];
// adding token in the list ...
for (var i = 0; i < results.length; i++) {
console.log("Token " + i + " " + results[i].token);
arrToken.push(results[i].token);
}
var uniqueItems = Array.from(new Set(arrToken));
// if error code 401 returned it means access token becomes invalid
// and we need to obtain a new token. Token Validity is 60 mins...
// fetchin app level access token here ...
appToken.getAppToken((callBack) => {
console.log("TOKEN VA L >>>" + uniqueItems);
appLevelAccesToken = callBack;
getTopicList.getTopicList(appLevelAccesToken, uniqueItems[0],callBackMessage => {
notifySucesssMessage = callBackMessage;
console.log("MSG >>>>>>>>>"+notifySucesssMessage);
res.send(notifySucesssMessage);
});
});
}
});
});
Sending notification using topic subscription API
The API is used to send notification using topic subscription, also an intent to send user to specific page. In this case we are sending URL as a data in an intent which will make user to view the website in android WebActivity page on taping the notification.
URL: https://push-api.cloud.huawei.com/v1/[appid]/messages:send
This is not the end. For full content, you can visit https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201327882870070045&fid=0101187876626530001

Huawei Cab Application (Login Module with HMS Account Kit and AGC Auth Service) Part1

More information like this, you can visit HUAWEI Developer Forum​
Introduction
Huawei Cab Application is to explore HMS Kits in real time scenario, use this app as reference to CP during HMS integration and understand easily about HMS function.
Login Module
The user can access Huawei Cab Application in Login page by HUAWEI ID or Email ID Login or Mobile Login and Google Sign In.
You can use AGC Auth Service to integrate one or more of the following authentication methods into your app for achieving easy and efficient user registration, and sign-in.
AGC Auth service is not providing user google mail id. So, you can retrieve your mail Id directly from third party google server by ID token, we have covered that one also in this article.
Huawei Cab Application needs user authentication to access application using following method:
Huawei Cab Authentication type:
1. Huawei Account Kit
2. Huawei Auth Service
App Screen
{
"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
HUAWEI Account Kit provides developers with simple, secure, and quick sign-in, and authorization functions. Instead of entering accounts and passwords, and authorization waiting, users can click the Sign In with Huawei ID button to quickly and securely sign in to app.
HUAWEI Auth Service
Auth Service provides backend services and an SDK to authenticate users to your app. It supports multiple authentication providers such as Phone Number, Google Sign-In, Email ID and more, and report authentication credentials to the AppGallery Connect.
When a user signs in to an app again, the app can obtain the users personal information and other data protected by security rules in other server less functions from Auth Service.
Auth Service can greatly reduce your investment and costs in building an authentication system and its O&M.
Integration Preparations
To integrate HUAWEI Account Kit, you must complete the following preparations:
Create an app in AppGallery Connect.
Create a project in Android Studio.
Generate a signing certificate.
Generate a signing certificate fingerprint.
Configure the signing certificate fingerprint.
Add the app package name and save the configuration file.
Add the AppGallery Connect plug-in and the Maven repository in the project-level build.gradle file.
Configure the signature file in Android Studio.
Configuring the Development Environment
Enabling HUAWEI Account Kit and Auth Service
1. Sign in to AppGallery Connect, select My apps and click an App. Choose Develop > Overview > Manage APIs.
Enabling Authentication Modes
1. Sign in to AppGallery Connect, select My apps, and click your App. Choose Develop > Build > Auth Service. If it is the first time that you use Auth Service, click Enable now in the upper right corner.
2. Click Enable in the row of each authentication mode to be enabled. In this codelab, click Enable for Huawei account, Huawei game, and Anonymous account.
3. In the displayed dialog box, configure app information. Required information can be obtained as follows:
Huawei account: Obtain the app ID and secret by referring to Querying App Information.
Huawei game: Sign in to AppGallery Connect, select My apps, click your game. Choose Develop > Build > Google Sign In, and obtain the client id and client secret id.
Integrating the Account Kit and Auth Service SDK
If you are using Android Studio, you can integrate the App Linking SDK by using the Maven repository into your Android Studio project before development.
1. Sign in to AppGallery Connect, select My apps and click your App. Choose Develop > Overview.
2. Click agconnect-services.json to download the configuration file.
3. Copy agconnect-services.json file to the app's root directory.
4. Open the build.gradle file in the root directory of your Android Studio project.
5. Configure the following information in the build.gradle file:
Code:
buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.huawei.agconnect:agcp:1.3.2.301'
}
}
6. Open the build.gradle file in the app directory.
7. Configure the HUAWEI Account Kit service address, Auth Service SDK address, and HUAWEI Game Service address.  
Code:
// Apply the APM plug-in.
apply plugin: 'com.huawei.agconnect'
dependencies {
implementation 'com.huawei.hms:hwid:4.0.1.300'
implementation 'com.huawei.agconnect:agconnect-auth:1.4.0.300'
implementation 'net.openid:appauth:0.7.1'
}
8. Click Sync Now to synchronize the configuration.
9. Add into your Manifest.
Code:
<activity android:name="net.openid.appauth.RedirectUriReceiverActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="Your package name"/>
</intent-filter>
</activity>
10. Add your app client Id from Google Developer Console for Google Sign In.
Code:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- android-client id-->
<string name="google_client_ids">Your Client ID</string>
<string name="redirect_uri">"your_package_name:/oauth2callback"</string>
</resources>
Code Snipped
Code:
private var mAuthManager: HuaweiIdAuthService? = null
private var mAuthParam: HuaweiIdAuthParams? = null
fun initHuaweiID() {
mAuthParam = HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM)
.setEmail()
.setUid()
.setProfile()
.setMobileNumber()
.setIdToken()
.setAccessToken()
.createParams()
mAuthManager = HuaweiIdAuthManager.getService(this, mAuthParam)
}
fun onLoginButtonClick(view : View) {
if (!isConnected) {
toast("No network connectivity")
} else {
startActivityForResult(mAuthManager?.signInIntent, RC_SIGN_IN)
}
}
fun signInGoogle() {
val serviceConfiguration =
AuthorizationServiceConfiguration(
Uri.parse("https://accounts.google.com/o/oauth2/auth"), // authorization endpoint
Uri.parse("https://oauth2.googleapis.com/token")
)
val authorizationService = AuthorizationService(this)
val clientId = getString(R.string.google_client_ids)
val redirectUri = Uri.parse(getString(R.string.redirect_uri))
val builder = AuthorizationRequest.Builder(
serviceConfiguration,
clientId,
ResponseTypeValues.CODE,
redirectUri
)
builder.setScopes("openid email profile")
val request = builder.build()
val intent = authorizationService.getAuthorizationRequestIntent(request)
startActivityForResult(
intent,
RC_GOOGLE_SIGN_IN
)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == RC_SIGN_IN) {
//login success
//get user message by parseAuthResultFromIntent
val authHuaweiIdTask =
HuaweiIdAuthManager.parseAuthResultFromIntent(data)
if (authHuaweiIdTask.isSuccessful) {
val huaweiAccount = authHuaweiIdTask.result
Log.i(
TAG,
huaweiAccount.uid + " signIn success "
)
Log.i(
TAG,
"AccessToken: " + huaweiAccount.accessToken
)
displayInfo(huaweiAccount)
} else {
Log.i(
TAG,
"signIn failed: " + (authHuaweiIdTask.exception as ApiException).statusCode
)
}
} else if (requestCode == RC_GOOGLE_SIGN_IN) {
val response = AuthorizationResponse.fromIntent(data!!)
val error = AuthorizationException.fromIntent(data)
val authState =
AuthState(response, error)
if (response != null) {
Log.i(
TAG,
String.format("Handled Authorization Response %s ", authState.toString())
)
val service = AuthorizationService(this)
service.performTokenRequest(
response.createTokenExchangeRequest()
) { tokenResponse, exception ->
if (exception != null) {
Log.w(
TAG,
"Token Exchange failed",
exception
)
} else {
if (tokenResponse != null) {
val suffixUrl = "tokeninfo?id_token=${tokenResponse.idToken}"
viewModel.getGmailMailID(suffixUrl)
viewModel.googleMailResponse.observe([email protected], Observer {
if (it != null) {
if (it.error.toString().contentEquals("invalid_token")) {
Toast.makeText([email protected], "${it.error_description}", Toast.LENGTH_LONG).show()
} else{
GoogleMailID = "${it.email}"
Log.d("GoogleMail_ID ", "${it.email}")
tokenResponse.idToken?.let { agcAuthWithGoogle(it) }
}
} else {
Toast.makeText([email protected], "Somethings error. Please try again later", Toast.LENGTH_LONG).show()
}
})
}
}
}
}
}
else {
mCallbackManager!!.onActivityResult(requestCode, resultCode, data)
}
}
fun getGmailMailID(url: String) {
val googleUserModel: GoogleUserModel
viewModelScope.launch {
try {
MyGoogleApi
.invoke()
.getGoogleMailID(url)
.enqueue(object : Callback<GoogleUserModel> {
override fun onFailure(call: Call<GoogleUserModel>, t: Throwable) {
Log.e(TAG, "onFailure: "+t.localizedMessage )
googleMailResponse.value = null
}
override fun onResponse(
call: Call<GoogleUserModel>,
response: Response<GoogleUserModel>
) {
if (response.isSuccessful) {
googleMailResponse.value = response.body()
} else {
googleMailResponse.value = null
}
}
})
} catch (e: Exception) {
e.stackTrace
}
}
}
private fun createAccount(email: String, password: String) {
val settings = VerifyCodeSettings.newBuilder()
.action(VerifyCodeSettings.ACTION_REGISTER_LOGIN) //ACTION_REGISTER_LOGIN/ACTION_RESET_PASSWORD
.sendInterval(30) // Minimum sending interval, ranging from 30s to 120s.
.locale(Locale.getDefault()) // Language in which a verification code is sent, which is optional. The default value is Locale.getDefault.
.build()
val task =
EmailAuthProvider.requestVerifyCode(email, settings)
task.addOnSuccessListener(
TaskExecutors.uiThread(),
OnSuccessListener {
Log.d("Email Auth", " Success")
val inflater = layoutInflater
val alertLayout: View =
inflater.inflate(R.layout.dialog_verification_code, null)
val verifyBtn =
alertLayout.findViewById<Button>(R.id.verifyBtn)
val edtverifyBtn = alertLayout.findViewById<EditText>(R.id.smsCodeEt)
val alert =
AlertDialog.Builder(this)
alert.setTitle("Verifying code")
// this is set the view from XML inside AlertDialog
alert.setView(alertLayout)
// disallow cancel of AlertDialog on click of back button and outside touch
alert.setCancelable(false)
val dialog = alert.create()
verifyBtn.setOnClickListener {
if (!edtverifyBtn.text.toString().isEmpty()) {
dialog.dismiss()
verifyEmailWithCode(
edtverifyBtn.text.toString(),
email,
password
)
} else {
Toast.makeText(
[email protected],
"Email Code must not be empty!",
Toast.LENGTH_LONG
).show()
}
}
dialog.show()
}).addOnFailureListener(
TaskExecutors.uiThread(),
OnFailureListener { e -> Log.d("Email Auth", " Failed " + e.message.toString()) })
}
private fun verifyEmailWithCode(
code: String,
email: String,
password: String
) {
val emailUser = EmailUser.Builder()
.setEmail(email)
.setVerifyCode(code)
.setPassword(password) // Optional. If this parameter is set, the current user has created a password and can use the password to sign in.
// If this parameter is not set, the user can only sign in using a verification code.
.build()
viewModel.AGCCreateUser_EmailVerificationCode(emailUser)
}
private fun startPhoneNumberVerification(phoneNumber: String) {
val settings = VerifyCodeSettings.newBuilder()
.action(VerifyCodeSettings.ACTION_REGISTER_LOGIN) //ACTION_REGISTER_LOGIN/ACTION_RESET_PASSWORD
.sendInterval(30) // Minimum sending interval, which ranges from 30s to 120s.
.locale(Locale.getDefault()) // Optional. It indicates the language for sending a verification code. The value of locale must contain the language and country/region information. The defualt value is Locale.getDefault.
.build()
PhoneAuthProvider.verifyPhoneCode(
"91", // Country Code
phoneNumber, // Phone Num
settings,
object : VerifyCodeSettings.OnVerifyCodeCallBack {
override fun onVerifySuccess(
shortestInterval: String,
validityPeriod: String
) {
Log.d("Phone Auth", " Success")
}
override fun onVerifyFailure(e: Exception) {
Log.d("Phone Auth", " Failed " + e.message.toString())
}
})
}
private fun verifyPhoneNumberWithCode(
code: String,
phoneNumber: String
) {
val phoneUser = PhoneUser.Builder()
.setCountryCode("+91")
.setPhoneNumber(phoneNumber) // The value of phoneNumber must contains the country/region code and mobile number.
.setVerifyCode(code)
.setPassword("Your password") // Mandatory. If this parameter is set, a password has been created for the current user by default and the user can sign in using the password.
// Otherwise, the user can only sign in using a verification code.
.build()
viewModel.AGCCreateUser_VerificationCode(phoneUser)
}
private fun signin_withverificationcode() {
val credential = PhoneAuthProvider.credentialWithVerifyCode(
"+91",
field_phone_number!!.text.toString(),
"Your password",
field_verification_code1!!.text.toString()
)
viewModel.AGCGoogleSignIn(credential)
}
private fun validatePhoneNumber(): Boolean {
val phoneNumber = field_phone_number!!.text.toString()
if (TextUtils.isEmpty(phoneNumber)) {
field_phone_number!!.error = "Invalid phone number."
return false
}
return true
}
Video Demo for Login with Mobile No
Reference URL:
Account Kit: https://developer.huawei.com/consumer/en/doc/development/HMS-Guides/account-introduction-v4
AGC Auth Service: https://developer.huawei.com/consumer/en/doc/development/AppGallery-connect-Guides/agc-auth-service-introduction
Hi, how do I verify an anonymous account?

Huawei Cab Application Part-2 – Get Location updates using Map and Site Kit

More information like this, you can visit HUAWEI Developer Forum​
Introduction
Huawei Cab Application is to explore more about HMS Kits in real time scenario, we can use this app as reference to CP during HMS integration, and they can understand easily how HMS works in real time scenario, refer previous article.
Dashboard Module
The Dashboard page allows a user to book a cab with help of Huawei location, map and site kits, as follows:
Location kit provides to get the current location and location updates, and it provides flexible location based services globally to the users.
Huawei Map kit is to display maps, it covers map data of more than 200 countries and regions for searching any location address.
Site kit provides with convenient and secure access to diverse, place-related services to users.
Kits covered in Dashboard Module:
1. Location kit
2. Map kit
3. Site kit
4. Ads kit
Third Party API’s:
1. TomTom for Directions API
App Screenshots:
Auto fetch current location and also customize current location button in huawei map.
{
"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"
}
Pick destination you want to travel with marker in the huawei map view.
Pick destination using HMS Site Kit.
Draw route between start and end location.
Huawei Location Kit
HUAWEI Location Kit combines the GPS, Wi-Fi, and base station location functionalities in your app to build up global positioning capabilities, allowing you to provide flexible location-based services targeted at users around globally. Currently, it provides three main capabilities: fused location, activity identification, and geo-fence. You can call one or more of these capabilities as needed.
Huawei Map Kit
The HMS Core Map SDK is a set of APIs for map development in Android. The map data covers most countries outside China and supports multiple languages. The Map SDK uses the WGS 84 GPS coordinate system, which can meet most requirements of map development outside China. You can easily add map-related functions in your Android app, including:
Map display: Displays buildings, roads, water systems, and Points of Interest (POIs).
Map interaction: Controls the interaction gestures and buttons on the map.
Map drawing: Adds location markers, map layers, overlays, and various shapes.
Site Kit
HUAWEI Site Kit provide to users with convenient and secure access to diverse, place-related services.
Ads Kit
Huawei Ads provide developers extensive data capabilities to deliver high quality ad content to users. By integrating HMS ads kit we can start earning right away. It is very useful particularly when we are publishing a free app and want to earn some money from it.
Integrating HMS ads kit does not take more than 10 minuts HMS ads kit currently offers five types of ad format like Banner, Native, Rewarded, Interstitial and Splash ads.
In this article, we will see banner ad also.
Banner Ad: Banner ads are rectangular images that occupy a spot at the top, middle, or bottom within an app's layout. Banner ads refresh automatically at regular intervals. When a user taps a banner ad, the user is redirected to the advertiser's page in most cases.
TomTom for Direction API
TomTom Technology for a moving world. Meet the leading independent location, navigation and map technology specialist.
Follow the steps for TomTom Direction API.
Step1: Visit TomTom Developer Portal. https://developer.tomtom.com/
Step2: Login/Signup.
Step3: Click PRODUCTS and select Directions API
Step 4: Route API, as follows: https://developer.tomtom.com/routing-api/routing-api-documentation-routing/calculate-route
Step5: Click MY DASHBOARD and Copy Key and Use it in your application.
Integration Preparations
To integrate HUAWEI Map, Site, Location and Ads Kit, you must complete the following preparations:
Create an app in AppGallery Connect.
Create a project in Android Studio.
Generate a signing certificate.
Generate a signing certificate fingerprint.
Configure the signing certificate fingerprint.
Add the app package name and save the configuration file.
Add the AppGallery Connect plug-in and the Maven repository in the project-level build.gradle file.
Configure the signature file in Android Studio.
Configuring the Development Environment
Enabling HUAWEI Map, Site, Location and Ads Kit.
1. Sign in to AppGallery Connect, select My apps, click an app, and navigate to Develop > Overview > Manage APIs.
2. Click agconnect-services.json to download the configuration file.
3. Copy the agconnect-services.json file to the app's root directory.
4. Open the build.gradle file in the root directory of your Android Studio project.
5. Configure the following information in the build.gradle file.
Code:
buildscript {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
classpath 'com.huawei.agconnect:agcp:1.3.2.301'
}
}
allprojects {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
}
6. Open the build.gradle file in the app directory.
7. Add Dependencies in app level build.gradle.
Code:
apply plugin: 'com.huawei.agconnect'dependencies {
implementation 'com.huawei.hms:maps:5.0.1.300'
implementation 'com.huawei.hms:location:5.0.0.302'
implementation 'com.huawei.hms:site:5.0.0.300'
implementation 'com.huawei.hms:ads-lite:13.4.30.307'
}
8. Apply for relevant permissions in sections at the same level as the application section in the AndroidManifest.xml file.
Code:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
9. Add Huawei MapView and Banner Ad in layout file: activity_maview.xml
Code:
<!--MapView-->
<com.huawei.hms.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:cameraTargetLat="51"
map:cameraTargetLng="10"
map:cameraZoom="8.5"
map:mapType="normal"
map:uiCompass="true"
map:uiZoomControls="true" />
<!--BannerView-->
<com.huawei.hms.ads.banner.BannerView
android:id="@+id/hw_banner_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
hwads:adId="@string/banner_ad_id"
android:layout_alignParentTop="true"
hwads:bannerSize="BANNER_SIZE_360_57" />
10. Add the configuration for calling the MapView to the activity.
Code:
class DashboardFragment : Fragment(), OnMapReadyCallback, ReverseGeoCodeListener {private var hMap: HuaweiMap? = null
private var mMapView: MapView? = null
private var pickupLat: Double = 0.0
private var pickupLng: Double = 0.0
private var dropLat: Double = 0.0
private var dropLng: Double = 0.0
private var mPolyline: Polyline? = null
private var mMarkerDestination: Marker? = nulloverride fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) // create fusedLocationProviderClient
mFusedLocationProviderClient = LocationServices.getFusedLocation ProviderClient(activity) mapView?.onCreate(savedInstanceState)
mapView?.onResume()
mapView?.getMapAsync(this)}
fun initBannerAds() {
// Obtain BannerView based on the configuration in layout.
val adParam: AdParam = AdParam.Builder().build()
hw_banner_view.loadAd(adParam)
}
override fun onMapReady(map: HuaweiMap) {
Log.d(TAG, "onMapReady: ")
hMap = map hMap?.isMyLocationEnabled = true
hMap?.uiSettings?.isMyLocationButtonEnabled = false
getLastLocation()
hMap?.setOnCameraMoveStartedListener {
when (it) {
HuaweiMap.OnCameraMoveStartedListener.REASON_GESTURE -> {
Log.d(TAG, "The user gestured on the map.")
val midLatLng: LatLng = hMap?.cameraPosition!!.target
Log.d("Moving_LatLng ", "" + midLatLng)
dropLat = midLatLng.latitude
dropLng = midLatLng.longitude
val task = MyAsyncTask(this, false)
task.execute(midLatLng.latitude, midLatLng.longitude) }
HuaweiMap.OnCameraMoveStartedListener
.REASON_API_ANIMATION -> {
Log.d(TAG, "The user tapped something on the map.")
}
HuaweiMap.OnCameraMoveStartedListener
.REASON_DEVELOPER_ANIMATION -> {
Log.d(TAG, "The app moved the camera.")
}
}
}
}
11. Add the life cycle method of the MapView
Code:
override fun onStart() {
super.onStart()
mMapView?.onStart()
}
override fun onStop() {
super.onStop()
mMapView?.onStop()
}
override fun onDestroy() {
super.onDestroy()
mMapView?.onDestroy()
}
override fun onPause() {
mMapView?.onPause()
super.onPause()
}
override fun onResume() {
super.onResume()
mMapView?.onResume()
}
override fun onLowMemory() {
super.onLowMemory()
mMapView?.onLowMemory()
}
12. Check permissions to let the user allow App to access user location from android 6.0
Code:
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "sdk < 28 Q")
if (checkSelfPermission(
this,
ACCESS_FINE_LOCATION
) != PERMISSION_GRANTED && checkSelfPermission(
this,
ACCESS_COARSE_LOCATION
) != PERMISSION_GRANTED
) {
val strings = arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION)
requestPermissions(this, strings, 1)
}
} else {
if (checkSelfPermission(
[email protected],
ACCESS_FINE_LOCATION
) != PERMISSION_GRANTED && checkSelfPermission(
[email protected], ACCESS_COARSE_LOCATION
) != PERMISSION_GRANTED && checkSelfPermission(
[email protected],
"android.permission.ACCESS_BACKGROUND_LOCATION"
) != PERMISSION_GRANTED
) {
val strings = arrayOf(
ACCESS_FINE_LOCATION,
ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"
)
requestPermissions(this, strings, 2)
}
}
13. In you activity you need to handle the response by this way.
Code:
Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 1) {
if (grantResults.size > 1 && grantResults[0] == PERMISSION_GRANTED && grantResults[1] == PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSION successful")
} else {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSSION failed")
}
}
if (requestCode == 2) {
if (grantResults.size > 2 && grantResults[2] == PERMISSION_GRANTED && grantResults[0] == PERMISSION_GRANTED && grantResults[1] == PERMISSION_GRANTED) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION successful")
} else {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION failed")
}
}
}
You can perform subsequent steps by referring to the RequestLocationUpdatesWithCallbackActivity.kt file.
14. Create a location provider client and device setting client.
Code:
// create fusedLocationProviderClient
fusedLocationProviderClient=LocationServices.getFusedLocationProviderClient(this)
// create settingsClient
settingsClient = LocationServices.getSettingsClient(this)
15. Create a location request.
Code:
mLocationRequest = LocationRequest().apply {
// set the interval for location updates, in milliseconds
interval = 1000
needAddress = true
// set the priority of the request
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
16. Create a result callback.
Code:
mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
if (locationResult != null) {
val locations: List<Location> =
locationResult.locations
if (locations.isNotEmpty()) {
for (location in locations) {
LocationLog.i(TAG,"onLocationResult location[Longitude,Latitude,Accuracy]:${location.longitude} , ${location.latitude} , ${location.accuracy}")
}
}
}
}
override fun onLocationAvailability(locationAvailability: LocationAvailability?) {
locationAvailability?.let {
val flag: Boolean = locationAvailability.isLocationAvailable
LocationLog.i(TAG, "onLocationAvailability isLocationAvailable:$flag")
}
}
}
17. Request location updates.
Code:
private fun requestLocationUpdatesWithCallback() {
try {
val builder = LocationSettingsRequest.Builder()
builder.addLocationRequest(mLocationRequest)
val locationSettingsRequest = builder.build()
// check devices settings before request location updates.
//Before requesting location update, invoke checkLocationSettings to check device settings.
val locationSettingsResponseTask: Task<LocationSettingsResponse> = settingsClient.checkLocationSettings(locationSettingsRequest)
locationSettingsResponseTask.addOnSuccessListener { locationSettingsResponse: LocationSettingsResponse? ->
Log.i(TAG, "check location settings success {$locationSettingsResponse}")
// request location updates
fusedLocationProviderClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener {
LocationLog.i(TAG, "requestLocationUpdatesWithCallback onSuccess")
}
.addOnFailureListener { e ->
LocationLog.e(TAG, "requestLocationUpdatesWithCallback onFailure:${e.message}")
}
}
.addOnFailureListener { e: Exception ->
LocationLog.e(TAG, "checkLocationSetting onFailure:${e.message}")
when ((e as ApiException).statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
val rae = e as ResolvableApiException
rae.startResolutionForResult(
[email protected]uestLocationUpdatesWithCallbackActivity, 0
)
} catch (sie: SendIntentException) {
Log.e(TAG, "PendingIntent unable to execute request.")
}
}
}
} catch (e: Exception) {
LocationLog.e(TAG, "requestLocationUpdatesWithCallback exception:${e.message}")
}
}
18. Remove location updates.
Code:
private fun removeLocationUpdatesWithCallback() {
try {
fusedLocationProviderClient.removeLocationUpdates(mLocationCallback)
.addOnSuccessListener {
LocationLog.i(
TAG,
"removeLocationUpdatesWithCallback onSuccess"
)
}
.addOnFailureListener { e ->
LocationLog.e(
TAG,
"removeLocationUpdatesWithCallback onFailure:${e.message}"
)
}
} catch (e: Exception) {
LocationLog.e(
TAG,
"removeLocationUpdatesWithCallback exception:${e.message}"
)
}
}
19. Reverse Geocoding
Code:
companion object {
private const val TAG = "MapViewDemoActivity"
private const val MAPVIEW_BUNDLE_KEY = "MapViewBundleKey"
class MyAsyncTask internal constructor(
private val context: DashboardFragment,
private val isStartPos: Boolean
) : AsyncTask<Double, Double, String?>() {
private var resp: String? = null
lateinit var geocoding: Geocoding
override fun onPreExecute() {
}
override fun doInBackground(vararg params: Double?): String? {
try {
geocoding = Geocoding()
geocoding.reverseGeoCodeListener = context
geocoding.reverseGeocoding(
"reverseGeocode",
"YOUR_API_KEY",
params[0],
params[1],
isStartPos
)
} catch (e: InterruptedException) {
e.printStackTrace()
} catch (e: Exception) {
e.printStackTrace()
}
return resp
} override fun onPostExecute(result: String?) {
}
override fun onProgressUpdate(vararg values: Double?) {
}
}
}
20. Geocoding class for converting latlng into Address
Code:
class Geocoding {
var reverseGeoCodeListener: ReverseGeoCodeListener? = null
val ROOT_URL = "https://siteapi.cloud.huawei.com/mapApi/v1/siteService/"
val conection =
"?key="
val JSON = MediaType.parse("application/json; charset=utf-8")
open fun reverseGeocoding(serviceName: String, apiKey: String?, lat: Double?, lng: Double?, isStartPos: Boolean) {
var sites: String = ""
val json = JSONObject()
val location = JSONObject()
try {
location.put("lng", lng)
location.put("lat", lat)
json.put("location", location)
json.put("language", "en")
json.put("politicalView", "CN")
json.put("returnPoi", true)
Log.d("MapViewDemoActivity",json.toString())
} catch (e: JSONException) {
Log.e("error", e.message)
}
val body : RequestBody = RequestBody.create(JSON, json.toString())
val client = OkHttpClient()
val request = Request.Builder()
.url(ROOT_URL + serviceName + conection + URLEncoder.encode(apiKey, "UTF-8"))
.post(body)
.build()
client.newCall(request).enqueue(object : Callback {
@Throws(IOException::class)
override fun onResponse(call: Call, response: Response) {
var str_response = response.body()!!.string()
val json_response:JSONObject = JSONObject(str_response)
val responseCode:String = json_response.getString("returnCode")
if (responseCode.contentEquals("0")) {
Log.d("ReverseGeocoding", str_response)
var jsonarray_sites: JSONArray = json_response.getJSONArray("sites")
var i:Int = 0
var size:Int = jsonarray_sites.length()
var json_objectdetail:JSONObject=jsonarray_sites.getJSONObject(0)
sites = json_objectdetail.getString("formatAddress")
Log.d("formatAddress", sites)
reverseGeoCodeListener?.getAddress(sites, isStartPos)
} else{
sites = "No Result"
Log.d("formatAddress", "")
reverseGeoCodeListener?.onAdddressError(sites)
}
}
override fun onFailure(call: Call, e: IOException) {
sites = "No Result"
Log.e("ReverseGeocoding", e.toString())
reverseGeoCodeListener?.onAdddressError(sites)
}
})
}
}
This is not the end. For full content, you can visit https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201352135916100198&fid=0101187876626530001
When am integrating site getting error code 6? can you explain why
sujith.e said:
When am integrating site getting error code 6? can you explain why
Click to expand...
Click to collapse
Hi, Sujith.e. The possible cause is that the API key contains special characters. You need to encode the special characters using encodeURI.

Demystifying HMS ML Kit with Product Visual Search API using Xamarin

Overview
In this article, I will create a demo app along with the integration of HMS ML Kit which based on Cross-platform Technology Xamarin. User can easily scan any items from this application with camera Product Vision Search ML Kit technique and choose best price and details of product.
{
"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"
}
Service Introduction
HMS ML Kit allows your apps to easily leverage Huawei's long-term proven expertise in machine learning to support diverse artificial intelligence (AI) applications throughout a wide range of industries.
A user can take a photo of a product. Then the Product Visual Search service searches for the same or similar products in the pre-established product image library and returns the IDs of those products and related information. In addition, to better manage products in real-time, this service supports offline product import, online product addition, deletion, modification, query, and product distribution.
We can capture any kind of image for products to buy or check the price of a product using Machine Learning. It will give the other options so that you can improve your buying skills.
Prerequisite
1. Xamarin Framework
2. Huawei phone
3. Visual Studio 2019
App Gallery Integration process
1. Sign In and Create or Choose a project on AppGallery Connect portal.
2. Add SHA-256 key.
3. Navigate to Project settings and download the configuration file.
4. Navigate to General Information, and then provide Data Storage location.
5. Navigate to Manage APIs and enable APIs which require by application.
Xamarin ML Kit Setup Process
1. Download Xamarin Plugin all the aar and zip files from below url:
https://developer.huawei.com/consum...Library-V1/xamarin-plugin-0000001053510381-V1
2. Open the XHms-ML-Kit-Library-Project.sln solution in Visual Studio.
3. Navigate to Solution Explore and right-click on jar Add > Exsiting Item and choose aar file which download in Step 1.
4. Right click on added aar file then choose Properties > Build Action > LibraryProjectZip
Note: Repeat Step 3 & 4 for all aar file.
5. Build the Library and make dll files.
Xamarin App Development
1. Open Visual Studio 2019 and Create A New Project.
2. Navigate to Solution Explore > Project > Assets > Add Json file.
3. Navigate to Solution Explore > Project > Add > Add New Folder.
4. Navigate to Folder(created) > Add > Add Existing and add all DLL files.
5. Select all DLL files.
6. Right-click on Properties, choose Build Action > None.
7. Navigate to Solution Explore > Project > Reference > Right Click > Add References, then navigate to Browse and add all DLL files from recently added folder.
8. Added reference, then click OK.
ML Product Visual Search API Integration
1. Create an analyzer for product visual search. You can create the analyzer using the MLRemoteProductVisionSearchAnalyzerSetting class.
C#:
// Method 1: Use default parameter settings.
MLRemoteProductVisionSearchAnalyzer analyzer = MLAnalyzerFactory.Instance.RemoteProductVisionSearchAnalyzer;
// Method 2: Use customized parameter settings.
MLRemoteProductVisionSearchAnalyzerSetting settings = new MLRemoteProductVisionSearchAnalyzerSetting.Factory()
// Set the maximum number of products that can be returned.
.SetLargestNumOfReturns(16)
.Create();
MLRemoteProductVisionSearchAnalyzer analyzer = MLAnalyzerFactory.Instance.GetRemoteProductVisionSearchAnalyzer(settings);
2. Create an MLFrame object by using Android.Graphics.Bitmap. JPG, JPEG, PNG, and BMP images are supported.
C#:
// Create an MLFrame object using the bitmap, which is the image data in bitmap format.
MLFrame frame = MLFrame.FromBitmap(bitmap);
3. Implement image detection.
Code:
Task<IList<MLProductVisionSearch>> task = this.analyzer.AnalyseFrameAsync(frame);
await task;
if (task.IsCompleted && task.Result != null)
{
// Analyze success.
var productVisionSearchList = task.Result;
if (productVisionSearchList.Count != 0)
{
//Product detected successfully
}
else
{
//Product not found
}
}
4. After the recognition is complete, stop the analyzer to release recognition resources.
if (analyzer != null) {
analyzer.Stop();
}
ProductVisionSearchAnalyseActivity.cs
This activity performs all the operation regarding product search with camera.
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Android;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using AndroidX.AppCompat.App;
using AndroidX.Core.App;
using AndroidX.Core.Content;
using Com.Huawei.Hms.Mlplugin.Productvisionsearch;
using Com.Huawei.Hms.Mlsdk;
using Com.Huawei.Hms.Mlsdk.Common;
using Com.Huawei.Hms.Mlsdk.Productvisionsearch;
using Com.Huawei.Hms.Mlsdk.Productvisionsearch.Cloud;
using Java.Lang;
namespace HmsXamarinMLDemo.MLKitActivities.ImageRelated.ProductVisionSearch
{
[Activity(Label = "ProductVisionSearchAnalyseActivity")]
public class ProductVisionSearchAnalyseActivity : AppCompatActivity, View.IOnClickListener
{
private const string Tag = "ProductVisionSearchTestActivity";
private static readonly int PermissionRequest = 0x1000;
private int CameraPermissionCode = 1;
private static readonly int MaxResults = 1;
private TextView mTextView;
private ImageView productResult;
private Bitmap bitmap;
private MLRemoteProductVisionSearchAnalyzer analyzer;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
this.SetContentView(Resource.Layout.activity_image_product_vision_search_analyse);
this.mTextView = (TextView)this.FindViewById(Resource.Id.result);
this.productResult = (ImageView)this.FindViewById(Resource.Id.image_product);
this.bitmap = BitmapFactory.DecodeResource(this.Resources, Resource.Drawable.custom_model_image);
this.productResult.SetImageResource(Resource.Drawable.custom_model_image);
this.FindViewById(Resource.Id.product_detect_plugin).SetOnClickListener(this);
this.FindViewById(Resource.Id.product_detect).SetOnClickListener(this);
// Checking Camera Permissions
if (!(ActivityCompat.CheckSelfPermission(this, Manifest.Permission.Camera) == Permission.Granted))
{
this.RequestCameraPermission();
}
}
private void RequestCameraPermission()
{
string[] permissions = new string[] { Manifest.Permission.Camera };
if (!ActivityCompat.ShouldShowRequestPermissionRationale(this, Manifest.Permission.Camera))
{
ActivityCompat.RequestPermissions(this, permissions, this.CameraPermissionCode);
return;
}
}
private void CheckPermissions(string[] permissions)
{
bool shouldRequestPermission = false;
foreach (string permission in permissions)
{
if (ContextCompat.CheckSelfPermission(this, permission) != Permission.Granted)
{
shouldRequestPermission = true;
}
}
if (shouldRequestPermission)
{
ActivityCompat.RequestPermissions(this, permissions, PermissionRequest);
return;
}
StartVisionSearchPluginCapture();
}
private async void RemoteAnalyze()
{
// Use customized parameter settings for cloud-based recognition.
MLRemoteProductVisionSearchAnalyzerSetting setting =
new MLRemoteProductVisionSearchAnalyzerSetting.Factory()
// Set the maximum number of products that can be returned.
.SetLargestNumOfReturns(MaxResults)
.SetProductSetId("vmall")
.SetRegion(MLRemoteProductVisionSearchAnalyzerSetting.RegionDrChina)
.Create();
this.analyzer = MLAnalyzerFactory.Instance.GetRemoteProductVisionSearchAnalyzer(setting);
// Create an MLFrame by using the bitmap.
MLFrame frame = MLFrame.FromBitmap(bitmap);
Task<IList<MLProductVisionSearch>> task = this.analyzer.AnalyseFrameAsync(frame);
try
{
await task;
if (task.IsCompleted && task.Result != null)
{
// Analyze success.
var productVisionSearchList = task.Result;
if(productVisionSearchList.Count != 0)
{
Toast.MakeText(this, "Product detected successfully", ToastLength.Long).Show();
this.DisplaySuccess(productVisionSearchList);
}
else
{
Toast.MakeText(this, "Product not found", ToastLength.Long);
}
}
else
{
// Analyze failure.
Log.Debug(Tag, " remote analyze failed");
}
}
catch (System.Exception e)
{
// Operation failure.
this.DisplayFailure(e);
}
}
private void StartVisionSearchPluginCapture()
{
// Set the config params.
MLProductVisionSearchCaptureConfig config = new MLProductVisionSearchCaptureConfig.Factory()
//Set the largest OM detect Result,default is 20,values in 1-100
.SetLargestNumOfReturns(16)
//Set the fragment you created (the fragment should implement AbstractUIExtendProxy)
.SetProductFragment(new ProductFragment())
//Set region,current values:RegionDrChina,RegionDrSiangapore,RegionDrGerman,RegionDrRussia
.SetRegion(MLProductVisionSearchCaptureConfig.RegionDrChina)
//设set product id,you can get the value by AGC
//.SetProductSetId("xxxxx")
.Create();
MLProductVisionSearchCapture capture = MLProductVisionSearchCaptureFactory.Instance.Create(config);
//Start plugin
capture.StartCapture(this);
}
private void DisplayFailure(System.Exception exception)
{
string error = "Failure. ";
try
{
MLException mlException = (MLException)exception;
error += "error code: " + mlException.ErrCode + "\n" + "error message: " + mlException.Message;
}
catch (System.Exception e)
{
error += e.Message;
}
this.mTextView.Text = error;
}
private void DrawBitmap(ImageView imageView, Rect rect, string product)
{
Paint boxPaint = new Paint();
boxPaint.Color = Color.White;
boxPaint.SetStyle(Paint.Style.Stroke);
boxPaint.StrokeWidth = (4.0f);
Paint textPaint = new Paint();
textPaint = new Paint();
textPaint.Color = Color.White;
textPaint.TextSize = 100.0f;
imageView.DrawingCacheEnabled = true;
Bitmap bitmapDraw = Bitmap.CreateBitmap(this.bitmap.Copy(Bitmap.Config.Argb8888, true));
Canvas canvas = new Canvas(bitmapDraw);
canvas.DrawRect(rect, boxPaint);
canvas.DrawText("product type: " + product, rect.Left, rect.Top, textPaint);
this.productResult.SetImageBitmap(bitmapDraw);
}
private void DisplaySuccess(IList<MLProductVisionSearch> productVisionSearchList)
{
List<MLVisionSearchProductImage> productImageList = new List<MLVisionSearchProductImage>();
foreach (MLProductVisionSearch productVisionSearch in productVisionSearchList)
{
this.DrawBitmap(this.productResult, productVisionSearch.Border, productVisionSearch.Type);
foreach (MLVisionSearchProduct product in productVisionSearch.ProductList)
{
productImageList.AddRange(product.ImageList);
}
}
StringBuffer buffer = new StringBuffer();
foreach (MLVisionSearchProductImage productImage in productImageList)
{
string str = "ProductID: " + productImage.ProductId + "\nImageID: " + productImage.ImageId + "\nPossibility: " + productImage.Possibility;
buffer.Append(str);
buffer.Append("\n");
}
this.mTextView.Text = buffer.ToString();
this.bitmap = BitmapFactory.DecodeResource(this.Resources, Resource.Drawable.custom_model_image);
this.productResult.SetImageResource(Resource.Drawable.custom_model_image);
}
public void OnClick(View v)
{
switch (v.Id)
{
case Resource.Id.product_detect:
this.RemoteAnalyze();
break;
case Resource.Id.product_detect_plugin:
CheckPermissions(new string[]{Manifest.Permission.Camera, Manifest.Permission.ReadExternalStorage,
Manifest.Permission.WriteExternalStorage, Manifest.Permission.AccessNetworkState});
break;
default:
break;
}
}
protected override void OnDestroy()
{
base.OnDestroy();
if (this.analyzer == null)
{
return;
}
this.analyzer.Stop();
}
}
}
Xamarin App Build
1. Navigate to Solution Explore > Project > Right Click > Archive/View Archive to generate SHA-256 for build release and Click on Distribute.
2. Choose Distribution Channel > Ad Hoc to sign apk.
3. Choose Demo Keystore to release apk.
4. Finally here is the Result.
Tips and Tricks
1. HUAWEI ML Kit complies with GDPR requirements for data processing.
2. HUAWEI ML Kit does not support the recognition of the object distance and colour.
3. Images in PNG, JPG, JPEG, and BMP formats are supported. GIF images are not supported.
Conclusion
In this article, we have learned how to integrate HMS ML Kit in Xamarin based Android application. User can easily search items online with the help of product visual search API in this application.
Thanks for reading this article. Be sure to like and comments to this article, if you found it helpful. It means a lot to me.
References
https://developer.huawei.com/consum...-Plugin-Guides/about-service-0000001052602130

Intermediate: Easy fix of application crash using Huawei Crash Service and Remote Configuration

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

Categories

Resources