Related
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"
}
Introduction
Hello everyone. In this article we are going to take a look at Huawei Mobile Services(HMS) Site Kit Plugin for react native. We will cover how to install and use HMS Site Kit.
HMS Site Kit has following features
Keyword Search: Returns a place list based on keywords entered by the user.
Nearby Place Search: Searches for nearby places based on the current location of the user's device.
Place Details: Searches for details about a place.
Place Search Suggestion: Returns a list of place suggestions.
Before we begin, you need to have Huawei developer account to use Huawei Mobile Services and thus the HMS Site Kit. You can sign in/register to Huawei developer website from here.
Configure your project on AppGallery Connect
First of all, you need to integrate Huawei Mobile Services with your application. I will not get into details about how to integrate your application but you can use this article as step by step guide.
Installation
First things first, let's install the library.
Code:
npm i @hmscore/react-native-hms-site
After the installation completed, we can import the library.
Code:
import RNHMSSite from '@hmscore/react-native-hms-site'
Before we can use the features of HMS site kit. We need to initialize it. In order to initialize the service, you will need an API key. When you integrated your application with HMS, AppGallery Connect will automatically provide an API key for you. You can find your API key on AppGallery Connect > YourApp > Project Settings > General information > App information.
Since we have our api key let's call initialize service function.
Code:
const config = {
apiKey: '<Your_API_KEY>' // You can find it in AppGallery Connect > YourApp > Project Settings > General information > App information};
RNHMSSite.initializeService(config)
.then(() => {
console.log('Service is initialized successfully');
})
.catch((err) => {
console.log('Error : ' + err);
});
If your API key is correct you will see "Service is initialized successfully" on your console.
Usage
Now we can start using HMS React Native Site Kit. Let's start with keyword search.
Keyword (Text) Search
HMS Site kit keyword search feature let's you implement a functionality that returns place list based on your user's keyword input. Also you can specify a location which search result will be baised. You can specify search radius, country, language and page size. For the keyword search you can set the POI (Point of Interest) where results can be filtered based on POI. User can search Bakery, School, ATM etc.
Let's create a TextSearchRequest object, which is used as the request body for keyword search. Related parameters are as follows, among which query is mandatory and others are optional:
query: search keyword.
location: longitude and latitude to which search results need to be biased.
radius: search radius, in meters. The value ranges from 1 to 50000. The default value is 50000.
poiType: POI type. The value range is the same as that of LocationType.
countryCode: code of the country where places are searched, which complies with the ISO 3166-1 alpha-2 standard.
language: language in which search results are displayed. For details about the value range, please refer to language codes in Language Mapping. If this parameter is not passed, the language of the query field is used in priority. If the field language is unavailable, the local language will be used.
pageSize: number of records on each page. The value ranges from 1 to 20. The default value is 20.
pageIndex: current page number. The value ranges from 1 to 60. The default value is 1.
After that we can call textSearch function and send our TextSearchRequest object as a parameter like this.
Let's find international school at Paris
Code:
const onTextSearch = () => {
let textSearchReq = {
query: 'International',
location: {
lat: 48.893478,
lng: 2.334595,
},
radius: 1000,
countryCode: 'FR',
language: 'en',
pageIndex: 1,
pageSize: 1,
poiType: RNHMSSite.LocationType.SCHOOL
};
RNHMSSite.textSearch(textSearchReq)
.then((response) => {
console.log(JSON.stringify(response));
})
.catch((err) => {
console.log(JSON.stringify(err));
});
};
The response json should be like this and as you can see there is alot of information to play around with.
Code:
{
"totalCount": 1,
"sites": [
{
"siteId": "FB3941B313927D74413FFF0E883144FE",
"poi": {
"rating": 0,
"poiTypes": [
"SCHOOL"
],
"phone": "+(33)-(1)-42000679",
"openingHours": {},
"internationalPhone": "+(33)-(1)-42000679"
},
"viewport": {
"southwest": {
"lng": 2.3455935548062814,
"lat": 48.87367776679441
},
"northeast": {
"lng": 2.3494610451937183,
"lat": 48.87622143320559
}
},
"name": "Acting International",
"formatAddress": "15, Rue Ambroise Thomas, 75009, 9e Arrondissement, Paris, Ile-de-France, France",
"address": {
"subLocality": "9e Arrondissement",
"subAdminArea": "Paris",
"postalCode": "75009",
"thoroughfare": "Rue Ambroise Thomas",
"countryCode": "FR",
"locality": "Paris",
"country": "France",
"adminArea": "Ile-de-France"
},
"distance": 2269.4454697030014,
"location": {
"lng": 2.3475273,
"lat": 48.8749496
}
}
]
}
Nearby Place Search
HMS Site kit nearby search feature let's you implement a functionality that returns nearby places using the current location of the user. Also you can specify search keyword, search radius, language and page size. For the nearby search you can set the POI (Point of Interest) where results can be filtered based on POI. User can search Bakery, School, ATM etc.
Let's create a NearbySearchRequest object, which is used as the request body for nearby place search. Related parameters are as follows, among which location is mandatory and others are optional:
location: longitude and latitude to which search results need to be biased.
radius: search radius, in meters. The value ranges from 1 to 50000. The default value is 50000.
query: search keyword.
poiType: POI type. The value range is the same as that of LocationType.
language: language in which search results are displayed. For details about the value range, please refer to language codes in Language Mapping. If this parameter is not passed, the language of the query field is used in priority. If the field language is unavailable, the local language will be used.
pageSize: number of records on each page. The value ranges from 1 to 20. The default value is 20.
pageIndex: current page number. The value ranges from 1 to 60. The default value is 1.
After that we can call nearbySearch function and send our NearbySearchRequest object as a parameter like this.
Let's find an ATM nearby.
Code:
const onNearbySearch = () => {
let nearbySearchReq = {
location: {
lat: 51.500775,
lng: -0.115756,
},
query: 'BANK',
radius: 1000,
poiType: RNHMSSite.LocationType.ATM,
language: 'en',
pageIndex: 1,
pageSize: 1
};
RNHMSSite.nearbySearch(nearbySearchReq)
.then((response) => {
console.log(JSON.stringify(response));
})
.catch((err) => {
console.log(JSON.stringify(err));
});
};
The response json should be like this and as you can see there is alot of information to play around with.
Code:
{
"totalCount": 1,
"sites": [
{
"siteId": "7B4F4024A4FD4D700E61B659247BB854",
"poi": {
"rating": 0,
"poiTypes": [
"ATM"
],
"openingHours": {},
"internationalPhone": ""
},
"viewport": {
"southwest": {
"lng": -0.11576103182719415,
"lat": 51.498155166794405
},
"northeast": {
"lng": -0.11167496817280585,
"lat": 51.50069883320559
}
},
"name": "Bank of Ireland - Post Office",
"formatAddress": "125-131, Westminster Bridge Road, Lambeth, London, England, the United Kingdom",
"address": {
"subAdminArea": "London",
"thoroughfare": "Westminster Bridge Road",
"countryCode": "GB",
"locality": "Lambeth",
"country": "the United Kingdom",
"adminArea": "England"
},
"distance": 206.06612089844526,
"location": {
"lng": -0.113718,
"lat": 51.499427
}
}
]
}
Place Details Search
Place details search returns search details about a place based on the unique ID (Site Id) of the place. SiteId can get from keyword or nearby or Place Suggestion search.
Let's create a DetailSearchRequest object, which is used as the request body for place details search. Related parameters are as follows, among which siteId is mandatory and others are optional:
siteId: ID of a place.
language: language in which search results are displayed. If this parameter is not passed, the local language will be used.
After that we can call detailSearch function and send our DetailSearchRequest object as a parameter like this.
Let's look at the details of the atm we found on nearby search.
Code:
const onDetailSearch = () => {
let detailSearchReq = {
siteId: '7B4F4024A4FD4D700E61B659247BB854',
language: 'en'
};
RNHMSSite.detailSearch(detailSearchReq)
.then((response) => {
console.log(JSON.stringify(response));
})
.catch((err) => {
console.log(JSON.stringify(err));
});
};
The response json should be like this and as you can see there is alot of information to play around with.
Code:
{
"site": {
"siteId": "7B4F4024A4FD4D700E61B659247BB854",
"poi": {
"rating": 0,
"poiTypes": [
"ATM"
],
"openingHours": {},
"internationalPhone": ""
},
"viewport": {
"southwest": {
"lng": -0.11576103182719415,
"lat": 51.498155166794405
},
"northeast": {
"lng": -0.11167496817280585,
"lat": 51.50069883320559
}
},
"name": "Bank of Ireland - Post Office",
"formatAddress": "125-131, Westminster Bridge Road, Lambeth, London, England, the United Kingdom",
"address": {
"subAdminArea": "London",
"thoroughfare": "Westminster Bridge Road",
"countryCode": "GB",
"locality": "Lambeth",
"country": "the United Kingdom",
"adminArea": "England"
},
"distance": 0,
"location": {
"lng": -0.113718,
"lat": 51.499427
}
}
}
Place Search Suggestion
Place search suggestion returns search suggestions during user input.
Let's create a QuerySuggestionRequest object, which is used as the request body for search suggestion. Related parameters are as follows, among which query is mandatory and others are optional:
query: search keyword.
location: longitude and latitude to which search results need to be biased.
radius: search radius, in meters. The value ranges from 1 to 50000. The default value is 50000.
bounds: coordinate bounds to which search results need to be biased.
poiTypes: List of POI types. The value range is a subset of LocationType. The options are as follows:
countryCode: code of the country where places are searched, which complies with the ISO 3166-1 alpha-2 standard.
language: language in which search results are displayed. For details about the value range, please refer to language codes in Language Mapping. If this parameter is not passed, the language of the query field is used in priority. If the field language is unavailable, the local language will be used.
If both bounds and location are passed, the value of bounds takes precedence.
After that we can call querySuggestion function and send our QuerySuggestionRequest object as a parameter like this.
Code:
onQuerySuggestion = () => {
let querySuggestionReq = {
query: "Big",
location: {
lat: 51.500775,
lng: -0.115756,
},
radius: 50000,
poiTypes: [RNHMSSite.LocationType.ADDRESS, RNHMSSite.LocationType.GEOCODE],
language: 'en',
};
RNHMSSite.querySuggestion(querySuggestionReq)
.then((response) => {
console.log(JSON.stringify(response));
})
.catch((err) => {
console.log(JSON.stringify(err));
});
};
The response json should be like this.
Code:
{
"sites": [
{
"address": [Object],
"distance": 2440116.1140924874,
"formatAddress": "Turkey",
"location": [Object],
"name": "Biga",
"poi": [Object],
"siteId": "2C462CB00BCF862B69D61DE831BF71E7"
},
{
"address": [Object],
"distance": 8749522.705467587,
"formatAddress": "United States",
"location": [Object],
"name": "Big Sur",
"poi": [Object],
"siteId": "58DDFA5DD1C4612CCA4FBC5EF5108062"
},
{
"address": [Object],
"distance": 2417935.062591788,
"formatAddress": "Kemer, Turkey",
"location": [Object],
"name": "Parium",
"poi": [Object],
"siteId": "EA13FD95D3EAFD7CA4D58CD543A8F801"
},
{
"address": [Object],
"distance": 44437.27858333883,
"formatAddress": "Stubbles Lane, the United Kingdom",
"location": [Object],
"name": "Bigfrith",
"poi": [Object],
"siteId": "06A86F8B8118741D6485DFE8E65E0833"
},
{
"address": [Object],
"distance": 23565.326723216425,
"formatAddress": "Main Road, the United Kingdom",
"location": [Object],
"name": "Biggin Hill",
"poi": [Object],
"siteId": "EFFF479C18F55D7FCB776E80FD790A39"
}
]
}
Conclusion
Now you know how to use HMS Site Kit plugin for React Native. With that knowledge you can implement amazing functionalities to your app that HMS Site Kit offers. You can interact with your users in more and different ways and attract even more users. You can implement keyword search for places, search nearby places, get places details and give search suggestions to your user.
References
Huawei Developer Documents
More information like this, you can visit HUAWEI Developer Forum
Introduction
Hello everyone. In this article we are going to take a look at Huawei Mobile Services(HMS) Site Kit Plugin for react native. We will cover how to install and use HMS Site Kit.
HMS Site Kit has following features
Keyword Search: Returns a place list based on keywords entered by the user.
Nearby Place Search: Searches for nearby places based on the current location of the user's device.
Place Details: Searches for details about a place.
Place Search Suggestion: Returns a list of place suggestions.
Before we begin, you need to have Huawei developer account to use Huawei Mobile Services and thus the HMS Site Kit. You can sign in/register to Huawei developer website from here.
Configure your project on AppGallery Connect
First of all, you need to integrate Huawei Mobile Services with your application. I will not get into details about how to integrate your application but you can use this article as step by step guide.
Installation
First things first, let's install the library.
Code:
npm i @hmscore/react-native-hms-site
After the installation completed, we can import the library.
Code:
import RNHMSSite from '@hmscore/react-native-hms-site'
Before we can use the features of HMS site kit. We need to initialize it. In order to initialize the service, you will need an API key. When you integrated your application with HMS, AppGallery Connect will automatically provide an API key for you. You can find your API key on AppGallery Connect > YourApp > Project Settings > General information > App information.
{
"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"
}
Since we have our api key let's call initialize service function.
Code:
const config = {
apiKey: '<Your_API_KEY>' // You can find it in AppGallery Connect > YourApp > Project Settings > General information > App information};
RNHMSSite.initializeService(config)
.then(() => {
console.log('Service is initialized successfully');
})
.catch((err) => {
console.log('Error : ' + err);
});
If your API key is correct you will see "Service is initialized successfully" on your console.
Usage
Now we can start using HMS React Native Site Kit. Let's start with keyword search.
Keyword (Text) Search
HMS Site kit keyword search feature let's you implement a functionality that returns place list based on your user's keyword input. Also you can specify a location which search result will be baised. You can specify search radius, country, language and page size. For the keyword search you can set the POI (Point of Interest) where results can be filtered based on POI. User can search Bakery, School, ATM etc.
Let's create a TextSearchRequest object, which is used as the request body for keyword search. Related parameters are as follows, among which query is mandatory and others are optional:
query: search keyword.
location: longitude and latitude to which search results need to be biased.
radius: search radius, in meters. The value ranges from 1 to 50000. The default value is 50000.
poiType: POI type. The value range is the same as that of LocationType.
countryCode: code of the country where places are searched, which complies with the ISO 3166-1 alpha-2 standard.
language: language in which search results are displayed. For details about the value range, please refer to language codes in Language Mapping. If this parameter is not passed, the language of the query field is used in priority. If the field language is unavailable, the local language will be used.
pageSize: number of records on each page. The value ranges from 1 to 20. The default value is 20.
pageIndex: current page number. The value ranges from 1 to 60. The default value is 1.
After that we can call textSearch function and send our TextSearchRequest object as a parameter like this.
Let's find international school at Paris
Code:
const onTextSearch = () => {
let textSearchReq = {
query: 'International',
location: {
lat: 48.893478,
lng: 2.334595,
},
radius: 1000,
countryCode: 'FR',
language: 'en',
pageIndex: 1,
pageSize: 1,
poiType: RNHMSSite.LocationType.SCHOOL
};
RNHMSSite.textSearch(textSearchReq)
.then((response) => {
console.log(JSON.stringify(response));
})
.catch((err) => {
console.log(JSON.stringify(err));
});
};
The response json should be like this and as you can see there is alot of information to play around with.
Code:
{
"totalCount": 1,
"sites": [
{
"siteId": "FB3941B313927D74413FFF0E883144FE",
"poi": {
"rating": 0,
"poiTypes": [
"SCHOOL"
],
"phone": "+(33)-(1)-42000679",
"openingHours": {},
"internationalPhone": "+(33)-(1)-42000679"
},
"viewport": {
"southwest": {
"lng": 2.3455935548062814,
"lat": 48.87367776679441
},
"northeast": {
"lng": 2.3494610451937183,
"lat": 48.87622143320559
}
},
"name": "Acting International",
"formatAddress": "15, Rue Ambroise Thomas, 75009, 9e Arrondissement, Paris, Ile-de-France, France",
"address": {
"subLocality": "9e Arrondissement",
"subAdminArea": "Paris",
"postalCode": "75009",
"thoroughfare": "Rue Ambroise Thomas",
"countryCode": "FR",
"locality": "Paris",
"country": "France",
"adminArea": "Ile-de-France"
},
"distance": 2269.4454697030014,
"location": {
"lng": 2.3475273,
"lat": 48.8749496
}
}
]
}
Nearby Place Search
HMS Site kit nearby search feature let's you implement a functionality that returns nearby places using the current location of the user. Also you can specify search keyword, search radius, language and page size. For the nearby search you can set the POI (Point of Interest) where results can be filtered based on POI. User can search Bakery, School, ATM etc.
Let's create a NearbySearchRequest object, which is used as the request body for nearby place search. Related parameters are as follows, among which location is mandatory and others are optional:
location: longitude and latitude to which search results need to be biased.
radius: search radius, in meters. The value ranges from 1 to 50000. The default value is 50000.
query: search keyword.
poiType: POI type. The value range is the same as that of LocationType.
language: language in which search results are displayed. For details about the value range, please refer to language codes in Language Mapping. If this parameter is not passed, the language of the query field is used in priority. If the field language is unavailable, the local language will be used.
pageSize: number of records on each page. The value ranges from 1 to 20. The default value is 20.
pageIndex: current page number. The value ranges from 1 to 60. The default value is 1.
After that we can call nearbySearch function and send our NearbySearchRequest object as a parameter like this.
Let's find an ATM nearby.
Code:
const onNearbySearch = () => {
let nearbySearchReq = {
location: {
lat: 51.500775,
lng: -0.115756,
},
query: 'BANK',
radius: 1000,
poiType: RNHMSSite.LocationType.ATM,
language: 'en',
pageIndex: 1,
pageSize: 1
};
RNHMSSite.nearbySearch(nearbySearchReq)
.then((response) => {
console.log(JSON.stringify(response));
})
.catch((err) => {
console.log(JSON.stringify(err));
});
};
The response json should be like this and as you can see there is alot of information to play around with.
Code:
{
"totalCount": 1,
"sites": [
{
"siteId": "7B4F4024A4FD4D700E61B659247BB854",
"poi": {
"rating": 0,
"poiTypes": [
"ATM"
],
"openingHours": {},
"internationalPhone": ""
},
"viewport": {
"southwest": {
"lng": -0.11576103182719415,
"lat": 51.498155166794405
},
"northeast": {
"lng": -0.11167496817280585,
"lat": 51.50069883320559
}
},
"name": "Bank of Ireland - Post Office",
"formatAddress": "125-131, Westminster Bridge Road, Lambeth, London, England, the United Kingdom",
"address": {
"subAdminArea": "London",
"thoroughfare": "Westminster Bridge Road",
"countryCode": "GB",
"locality": "Lambeth",
"country": "the United Kingdom",
"adminArea": "England"
},
"distance": 206.06612089844526,
"location": {
"lng": -0.113718,
"lat": 51.499427
}
}
]
}
Place Details Search
Place details search returns search details about a place based on the unique ID (Site Id) of the place. SiteId can get from keyword or nearby or Place Suggestion search.
Let's create a DetailSearchRequest object, which is used as the request body for place details search. Related parameters are as follows, among which siteId is mandatory and others are optional:
siteId: ID of a place.
language: language in which search results are displayed. If this parameter is not passed, the local language will be used.
After that we can call detailSearch function and send our DetailSearchRequest object as a parameter like this.
Let's look at the details of the atm we found on nearby search.
Code:
const onDetailSearch = () => {
let detailSearchReq = {
siteId: '7B4F4024A4FD4D700E61B659247BB854',
language: 'en'
};
RNHMSSite.detailSearch(detailSearchReq)
.then((response) => {
console.log(JSON.stringify(response));
})
.catch((err) => {
console.log(JSON.stringify(err));
});
};
The response json should be like this and as you can see there is alot of information to play around with.
Code:
{
"site": {
"siteId": "7B4F4024A4FD4D700E61B659247BB854",
"poi": {
"rating": 0,
"poiTypes": [
"ATM"
],
"openingHours": {},
"internationalPhone": ""
},
"viewport": {
"southwest": {
"lng": -0.11576103182719415,
"lat": 51.498155166794405
},
"northeast": {
"lng": -0.11167496817280585,
"lat": 51.50069883320559
}
},
"name": "Bank of Ireland - Post Office",
"formatAddress": "125-131, Westminster Bridge Road, Lambeth, London, England, the United Kingdom",
"address": {
"subAdminArea": "London",
"thoroughfare": "Westminster Bridge Road",
"countryCode": "GB",
"locality": "Lambeth",
"country": "the United Kingdom",
"adminArea": "England"
},
"distance": 0,
"location": {
"lng": -0.113718,
"lat": 51.499427
}
}
}
Place Search Suggestion
Place search suggestion returns search suggestions during user input.
Let's create a QuerySuggestionRequest object, which is used as the request body for search suggestion. Related parameters are as follows, among which query is mandatory and others are optional:
query: search keyword.
location: longitude and latitude to which search results need to be biased.
radius: search radius, in meters. The value ranges from 1 to 50000. The default value is 50000.
bounds: coordinate bounds to which search results need to be biased.
poiTypes: List of POI types. The value range is a subset of LocationType. The options are as follows:
countryCode: code of the country where places are searched, which complies with the ISO 3166-1 alpha-2 standard.
language: language in which search results are displayed. For details about the value range, please refer to language codes in Language Mapping. If this parameter is not passed, the language of the query field is used in priority. If the field language is unavailable, the local language will be used.
If both bounds and location are passed, the value of bounds takes precedence.
After that we can call querySuggestion function and send our QuerySuggestionRequest object as a parameter like this.
Code:
onQuerySuggestion = () => {
let querySuggestionReq = {
query: "Big",
location: {
lat: 51.500775,
lng: -0.115756,
},
radius: 50000,
poiTypes: [RNHMSSite.LocationType.ADDRESS, RNHMSSite.LocationType.GEOCODE],
language: 'en',
};
RNHMSSite.querySuggestion(querySuggestionReq)
.then((response) => {
console.log(JSON.stringify(response));
})
.catch((err) => {
console.log(JSON.stringify(err));
});
};
The response json should be like this.
Code:
{
"sites": [
{
"address": [Object],
"distance": 2440116.1140924874,
"formatAddress": "Turkey",
"location": [Object],
"name": "Biga",
"poi": [Object],
"siteId": "2C462CB00BCF862B69D61DE831BF71E7"
},
{
"address": [Object],
"distance": 8749522.705467587,
"formatAddress": "United States",
"location": [Object],
"name": "Big Sur",
"poi": [Object],
"siteId": "58DDFA5DD1C4612CCA4FBC5EF5108062"
},
{
"address": [Object],
"distance": 2417935.062591788,
"formatAddress": "Kemer, Turkey",
"location": [Object],
"name": "Parium",
"poi": [Object],
"siteId": "EA13FD95D3EAFD7CA4D58CD543A8F801"
},
{
"address": [Object],
"distance": 44437.27858333883,
"formatAddress": "Stubbles Lane, the United Kingdom",
"location": [Object],
"name": "Bigfrith",
"poi": [Object],
"siteId": "06A86F8B8118741D6485DFE8E65E0833"
},
{
"address": [Object],
"distance": 23565.326723216425,
"formatAddress": "Main Road, the United Kingdom",
"location": [Object],
"name": "Biggin Hill",
"poi": [Object],
"siteId": "EFFF479C18F55D7FCB776E80FD790A39"
}
]
}
Conclusion
Now you know how to use HMS Site Kit plugin for React Native. With that knowledge you can implement amazing functionalities to your app that HMS Site Kit offers. You can interact with your users in more and different ways and attract even more users. You can implement keyword search for places, search nearby places, get places details and give search suggestions to your user.
You can ask questions on the comments section, I would be glad to answer them.
Have a great day.
References
Huawei Developer Documents
Site Kit Android SDK Integration
Github link: https://github.com/HMS-Core/hms-react-native-plugin/tree/master/react-native-hms-site
For more details, you can go to:
Our official website
Our Development Documentation page, to find the documents you need
Reddit to join our developer discussion
GitHub to download demos and sample codes
Stack Overflow to solve any integration problems
On an Enterprise environment maybe you want to perform some console operations from a custom plaform, for example, to manage your app information, to automatize the download of the app finance report, or to automatically release an app allocated in your own server. If this is your case, yo may be interested on App Gallery Connect API.
Previous requirements
A developer account
At least one project on AGC
What will we do in this article?
We will generate our client credentials to obtain an app level access token which will give us access to the App Gallery Connect API. After that we wiil use the Connect API to perform the next operations.
Obtaining the App Id related to an app package name
Obtaining the basic app information
Obtaining the upload URL to upload a new version of our app
Obtaining the URL to download your App Report
All the API requests on this article will be performed by using Kotlin, so you can use it to develop your own management platform for mobile, desktop or web.
Generating the client credentials
Sign into AppGallery Connect and then go to Users and permissionfrr4qwq
{
"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"
}
From the left side panel, select Connect API and click on the Create button to generate your client credentials.
In the pop up dialog, choose a name, project and applicable roles for your API client. In this example, I will use Administrator.
Note: Some APIs require project-level authorization. Please specify the projects you want to access through these APIs. Select N/A if the APIs only require team-level authorization.
Once you have confirmed your settings, your client ID and secret key will appear on the Connect API screen.
Copy your Client ID and Key. Make sure to keep them safe.
Request Helper
I wrote a helper class to perform the REST calls to the Connect API
Code:
data class ResponseObject(val code:Int,val message: String,var responseBody:JSONObject?)
class RequestHelper {
companion object{
fun sendRequest(host:String, headers: HashMap<String,String>?, body:JSONObject?, requestType:String="GET"):ResponseObject{
try {
val conn = URL(host)
.openConnection() as HttpURLConnection
conn.apply {
requestMethod = requestType
headers?.apply {
for(key in keys)
setRequestProperty(key, get(key))
}
doOutput = requestType == "POST"
doInput = true
}
if(requestType!="GET"){
conn.outputStream.let{
body?.apply { it.write(toString().toByteArray()) }
}
}
val result = when (conn.responseCode) {
in 0..300 -> convertStreamToString(conn.inputStream)
else -> convertStreamToString(conn.errorStream)
}
//Returns the access token, or an empty String if something fails
return ResponseObject(conn.responseCode,conn.responseMessage, JSONObject(result)).also { conn.disconnect() }
} catch (e: Exception) {
return ResponseObject(400,e.toString(),null)
}
}
private fun convertStreamToString(input: InputStream): String {
return BufferedReader(InputStreamReader(input)).use {
val response = StringBuffer()
var inputLine = it.readLine()
while (inputLine != null) {
response.append(inputLine)
inputLine = it.readLine()
}
it.close()
response.toString()
}
}
}
}
Obtaining the App Level Access Token
This is a mandatory step, the access token contains information about the scope level provided to your client credentials.
Perform the following POST request:
Hostname: connect-api.cloud.huawei.com
Path: /api/oauth2/v1/token
Headers:
Content-Type: application/json
Body:
Code:
{
"grant_type":"client_credentials",
"client_id":"YOUR_CLIENT ID",
"client_secret":"YOUR_CLIENT_KEY"
}
If everything goes fine, the request will return an access token and the validity period of the token. You can use the same access token for any of the following operations until the expiration time. If the token expires, you must apply for a new one.
Example:
Code:
data class AGCredential(val clientId: String, val key: String)
class AGConnectAPI(credential: AGCredential) {
companion object {
@JvmField
val HOST = "https://connect-api.cloud.huawei.com/api"
private val MISSING_CREDENTIALS = "must setup the client credentials first"
val MISSING_CREDENTIALS_RESPONSE=ResponseObject(403, MISSING_CREDENTIALS, null)
}
var token: String? = null
var credential: AGCredential= credential
set(value) {
field = value
getToken()
}
init {
getToken()
}
private fun getToken(): Int {
val host = "$HOST/oauth2/v1/token"
val headers = HashMap<String, String>().apply {
put("Content-Type", "application/json")
}
val body = JSONObject().apply {
put("client_id", credential.clientId)
put("client_secret", credential.key)
put("grant_type", "client_credentials")
}
val response = RequestHelper.sendRequest(host, headers, body, "POST")
val token = response.responseBody?.let {
if (it.has("access_token")) {
it.getString("access_token")
} else null
}
return if (token != null) {
this.token = token
200
} else response.code
}
}
Obtaining the App Id for a given package name
The App Id is required as a unique identifier for app management operations.
Perform the following GET request:
Hostname: connect-api.cloud.huawei.com
Path: /api/publish/v2/appid-list?packageName=$packageName
Headers:
Authorization: Bearer $token
client_id: clientId
Example
Code:
fun queryAppId(packageName: String): ResponseObject {
return if (!token.isNullOrEmpty()) {
val url = "$HOST/publish/v2/appid-list?packageName=$packageName"
RequestHelper.sendRequest(url, getClientHeaders(), null)
} else MISSING_CREDENTIALS_RESPONSE
}
private fun getClientHeaders(): HashMap<String, String> {
return HashMap<String, String>().apply {
put("Authorization", "Bearer $token")
put("client_id", credential.clientId)
}
}
Obtaining the upload URL to upload a new version of our app
The Connect API provides URLs to upload different files of your app configuration in AppGallery. For this example we will get the URL to upload the APK. Currently, files with the following extensions can be uploaded:
apk/rpk/pdf/jpg/jpeg/png/bmp/mp4/mov/aab.
Perform the following GET request:
Hostname: connect-api.cloud.huawei.com
Path: /api//publish/v2/upload-url?appId=$appId&suffix=$(apk/rpk/pdf/jpg/jpeg/png/bmp/mp4/mov/aab)
Headers:
Content-Type: application/json
Authorization: Bearer $token
client_id: clientId
Example:
Code:
fun getUploadURL(appId: String,suffix: String):ResponseObject{
return if (!token.isNullOrEmpty()){
val url="$HOST/publish/v2/upload-url?appId=$appId&suffix=$suffix"
RequestHelper.sendRequest(url,getClientHeaders(),null)
} else MISSING_CREDENTIALS_RESPONSE
}
Obtaining the URL to download your App Report
You can download detailed reports about your app downloads and installations, purchases made in your app and if your app is a paid app, you can get the Paid Download report.
For the Paid Download report the hostname is different for every region
Hostname: https://{domain}
Domain name for China: connect-api.cloud.huawei.com
Domain name for Europe: connect-api-dre.cloud.huawei.com
Domain name for Asia Pacific: connect-api-dra.cloud.huawei.com
Domain name for Russia: connect-api-drru.cloud.huawei.com
Path: /api/report/distribution-operation-quality/v1/orderDetailExport/$appId
Headers:
Authorization: Bearer $token
client_id: clientId
This API require some querys to generate the report, to se the query details, refer to the official documentation
Example:
Code:
fun getReportUrl(
appId: String,
lang: String,
startTime: String,
endTime: String,
filterConditions:HashMap<String,String>
):ResponseObject {
return if (!token.isNullOrEmpty()){
val fc = StringBuilder().apply {
for (key in filterConditions.keys) {
append("&filterCondition=")
append(key)
append("&filterConditionValue=")
append(filterConditions[key])
}
}
val url =
"$HOST/report/distribution-operation-quality/v1/orderDetailExport/$appId?language=$lang&startTime=$startTime&endTime=$endTime${fc}"
RequestHelper.sendRequest(url,getClientHeaders(),null)
} else MISSING_CREDENTIALS_RESPONSE
}
Conclusion
Now you know what is the Connect API and how you can use it to automatize some management operations or to develop yur own custom console. There are also a lot of things what you can do with the Connect API. For more information you can refer to the official documentation.
Check this and other demos: https://github.com/danms07/dummyapp
Using this API can we customize Roles and permissions user basis?
Your app may fail to launch HUAWEI In-App Purchases (IAP) if you have integrated the IAP SDK 4.0.4.300 or later into it.
Problem
When a user initiates a payment request, the payment page is not displayed.
Troubleshooting
Check the result code returned by the HMS Core SDK, and perform a check by referring to the official documentation.
Capture all app logs, and search for the keyword hms_pay to locate the fault.
Possible Causes
Common Products (Consumables/Non-Consumables) Not Activated
When you create a product in AppGallery Connect, the product is not activated by default. A user cannot pay for an unactivated 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"
}
Result code: 60003 (indicating incorrect product information)
Search for the keyword hms_pay. The following log information will be found:
2020–09–30 14:48:52.850 21970–17650/? E/hms_pay: hms_pay [Network-Request]parse createOrder, responseCode = 6, subErrCode = 214, responseMessage = Product info cannot be found.
2020–09–30 14:48:52.850 21970–17650/? I/hms_pay: hms_pay baseBiz result:: get result Success
2020–09–30 14:48:52.850 21970–17650/? I/hms_pay: hms_pay createOrder onResponse responseCode:6,responseMessageroduct info cannot be found.
2020–09–30 14:48:52.851 21970–17650/? E/hms_pay: hms_pay createOrder fail, returnCode: 6
Subscriptions Not Activated
Result code: -1 (indicating common failure)
Search for the keyword hms_pay. The following log information will be found:
2020–09–30 15:20:38.940 21970–22803/? E/hms_pay: hms_pay [Network-Request]parse createOrder, responseCode = 6, subErrCode = 221, responseMessage = product status must 0(online)
2020–09–30 15:20:38.940 21970–22803/? I/hms_pay: hms_pay baseBiz result:: get result Success
2020–09–30 15:20:38.943 21970–22803/? I/hms_pay: hms_pay getCurrentTime error, content is inValid
2020–09–30 15:20:38.945 21970–22803/? I/hms_pay: hms_pay no InAppPurchaseData
2020–09–30 15:20:38.946 21970–22803/? E/hms_pay: hms_pay SubscribeRequestInterceptor createOrder, errorCode: 6
Incorrect Product ID
The ID of the product to be paid needs to be passed in the createPurchaseIntent API. If the product ID has not been configured in AppGallery Connect, no ID will be passed and IAP therefore cannot be launched.
Result code: 60003 (indicating incorrect product information)
Search for the keyword hms_pay. The following log information will be found:
2020–09–30 15:07:59.438 21970–19979/? E/hms_pay: hms_pay [Network-Request]parse createOrder, responseCode = 6, subErrCode = 214, responseMessage = Product info cannot be found.
2020–09–30 15:07:59.439 21970–19979/? I/hms_pay: hms_pay baseBiz result:: get result Success
2020–09–30 15:07:59.447 21970–19979/? I/hms_pay: hms_pay createOrder onResponse responseCode:6,responseMessageroduct info cannot be found.
2020–09–30 15:07:59.448 21970–19979/? E/hms_pay: hms_pay createOrder fail, returnCode: 6
Incorrect Parameter Setting (setPriceType) for Common*Products
You can create consumables, non-consumables, and subscriptions in AppGallery Connect. In the createPurchaseIntent API, the setPriceType parameter must be set, and the product type must be the same as that configured on your server.
Result code: 60006 (indicating that the product type is inconsistent with that defined in the PMS)
Search for the keyword hms_pay. The following log information will be found:
2020–09–30 15:05:08.560 21970–18765/? E/hms_pay: hms_pay [Network-Request]parse createOrder, responseCode = 6, subErrCode = 216, responseMessage = Product type doesn't match that in pms.
2020–09–30 15:05:08.560 21970–18765/? I/hms_pay: hms_pay baseBiz result:: get result Success
2020–09–30 15:05:08.561 21970–18765/? I/hms_pay: hms_pay createOrder onResponse responseCode:6,responseMessageroduct type doesn't match that in pms.
2020–09–30 15:05:08.561 21970–18765/? E/hms_pay: hms_pay createOrder fail, returnCode: 6
Incorrect Parameter Setting (setPriceType) for Subscriptions
Result code: -1 (indicating common failure)
Search for the keyword hms_pay. The following log information will be found:
2020–09–30 15:24:48.019 21970–23368/? E/hms_pay: hms_pay [Network-Request]parse createOrder, responseCode = 6, subErrCode =*, responseMessage = App doesn't exist from pms.
2020–09–30 15:24:48.019 21970–23368/? I/hms_pay: hms_pay baseBiz result:: get result Success
2020–09–30 15:24:48.019 21970–23368/? I/hms_pay: hms_pay createOrder onResponse responseCode:6,responseMessage:App doesn't exist from pms.
2020–09–30 15:24:48.020 21970–23368/? E/hms_pay: hms_pay createOrder fail, returnCode: 6
For more details, you can go to:
Result code documentation:
https://developer.huawei.com/consum...nces-V5/client-error-code-0000001050746111-V5
{
"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"
}
Article Introduction
Validating identity is incredibly important in mobile development, and assuring new user signups are real human beings is critical. Developers need reliable ways to confirm the identities of their users to prevent security issues. Developers can implement verification systems using phone numbers in two main ways: either by calling or by sending an SMS containing a code that the user must input. In this article, we’ll implement SMS Retriever API to support both GMS and HMS, so our app can read the Verification/OTP SMS and verify the user automatically.
Automatic and one-tap SMS verification
Verify your users by SMS without making them deal with verification codes. If your app requires a user to enter a mobile number and verifies the user identity using an SMS verification code, you can integrate the ReadSmsManager service so that your app can automatically read the SMS verification code without applying for the SMS reading permission. After the integration, SMS verification codes are automatically filled in for verification, greatly improving user experience.
The process is described as follows:
1. HMS Core (APK) sends the SMS message that meets the rules to your app through a directed broadcast.
2. Your app receives the directed broadcast, parses it to obtain the SMS verification code, and displays it on your app.
3. The user checks whether the verification code is correct and if so, sends a verification request.
4. Your app sends the verification code from the user to your app server for check.
5. Your app server checks whether the verification code is correct and if so, returns the verification result to your app.
Pre-Requisites
ReadSmsManager Support the following:
Support
Value
Devices
Phones and Tablets
Operating System
EMUI 3.0 or later
Android
Android 4.4 or later
SMS message rules
SMS Template:
prefix_flag short message verification code is XXXXXX hash_value
prefix_flag
indicates the prefix of an SMS message, which can be <#>, [#], or \u200b\u200b. \u200b\u200b is invisible Unicode characters.
short message verification code is
indicates the SMS message content, which you can define as needed.
XXXXXX
indicates the verification code.
hash_value
indicates the hash value generated by the HMS Core SDK based on the package name of an app to uniquely identify the app
Step 1: Get Hash Value:
You get your hash value by implementing the following class:
Java:
public class hashcodeHMS extends ContextWrapper {
public static final String TAG = hashcodeHMS.class.getSimpleName();
public hashcodeHMS(Context context) {
super(context);
}
public MessageDigest getMessageDigest() {
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "No Such Algorithm.", e);
}
return messageDigest;
}
public String getSignature(Context context, String packageName) {
PackageManager packageManager = context.getPackageManager();
Signature[] signatureArrs;
try {
signatureArrs = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Package name inexistent.");
return "";
}
if (null == signatureArrs || 0 == signatureArrs.length) {
Log.e(TAG, "signature is null.");
return "";
}
Log.e("hashhms =>", signatureArrs[0].toCharsString());
return signatureArrs[0].toCharsString();
}
public String getHashCode(String packageName, MessageDigest messageDigest, String signature) {
String appInfo = packageName + " " + signature;
messageDigest.update(appInfo.getBytes(StandardCharsets.UTF_8));
byte[] hashSignature = messageDigest.digest();
hashSignature = Arrays.copyOfRange(hashSignature, 0, 9);
String base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING | Base64.NO_WRAP);
base64Hash = base64Hash.substring(0, 11);
return base64Hash;
}
}
Step 2: Start the consent from SMS Manager:
Code:
val task = ReadSmsManager.startConsent([email protected], null)
task.addOnCompleteListener { it ->
if (it.isSuccessful) {
// The service is enabled successfully. Perform other operations as needed.
tv_title.text = "Waiting for the OTP"
Toast.makeText(this, "SMS Retriever starts", Toast.LENGTH_LONG).show()
}else{
tv_title.text = "ReadSmsManager did not worked"
Toast.makeText(this, "SMS Retriever did not start", Toast.LENGTH_LONG).show()
}
}
Step 3: Prepare your Broadcast Receiver:
Java:
class MySMSBrodcastReceiverHms : BroadcastReceiver() {
private var otpReceiver: OTPReceiveListenerHMS? = null
fun initOTPListener(receiver: OTPReceiveListenerHMS) {
this.otpReceiver = receiver
Log.e("Firas", "initOTPListener: Done", )
}
override fun onReceive(context: Context, intent: Intent) {
intent?.let { it ->
val bundle = it.extras
bundle?.let { itBundle ->
if (ReadSmsConstant.READ_SMS_BROADCAST_ACTION == it.action) {
val status : Status? = itBundle.getParcelable(ReadSmsConstant.EXTRA_STATUS)
if (status?.statusCode == CommonStatusCodes.TIMEOUT) {
// The service has timed out and no SMS message that meets the requirements is read. The service process ends.
Log.i("Firas", "onReceive: TIMEOUT")
otpReceiver!!.onOTPTimeOutHMS()
}else if (status?.statusCode == CommonStatusCodes.SUCCESS){
if (bundle.containsKey(ReadSmsConstant.EXTRA_SMS_MESSAGE)) {
// An SMS message that meets the requirement is read. The service process ends.
var otp: String = bundle.getString(ReadSmsConstant.EXTRA_SMS_MESSAGE) as String
Log.i("Firas", "onReceive: ${otp}")
otp = otp.replace("[#] short message verification code is ", "").split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0]
otp = otp.split(" ").dropLastWhile { it.isEmpty() }.toTypedArray()[0]
Log.i("Firas", "onReceive: ${otp}")
otpReceiver!!.onOTPReceivedHMS(otp)
}
}
}
}
}
}
interface OTPReceiveListenerHMS {
fun onOTPReceivedHMS(otp: String)
fun onOTPTimeOutHMS()
}
}
*Add the broadcast receiver to the manifest*
XML:
<receiver
android:name=".MySMSBrodcastReceiverHms"
android:exported="true">
<intent-filter>
<action android:name="com.huawei.hms.support.sms.common.ReadSmsConstant.READ_SMS_BROADCAST_ACTION" />
</intent-filter>
</receiver>
Step 4: Prepare your Broadcast Receiver:
Implement the OTPReceiverListenerHMS interface from our MySMSBrodcastReceiverHms:
Code:
* class otp_read : AppCompatActivity(),MySMSBrodcastReceiverHms.OTPReceiveListenerHMS{}*
Then create and initiate the OTPListener
Code:
var smsBroadcast = MySMSBrodcastReceiverHms() as MySMSBrodcastReceiverHms
(smsBroadcast as MySMSBrodcastReceiverHms).initOTPListener(this)
Implement the functions of the interface:
Code:
override fun onOTPReceivedHMS(otp: String) {
Toast.makeText(this, " onOTPReceived", Toast.LENGTH_SHORT).show()
if (smsBroadcast != null) {
LocalBroadcastManager.getInstance(this).unregisterReceiver(smsBroadcast as MySMSBrodcastReceiverHms)
}
Toast.makeText(this, otp, Toast.LENGTH_SHORT).show()
tv_title.text = "$otp"
otp_view.setText(otp)
Log.e("OTP Received", otp)
}
override fun onOTPTimeOutHMS() {
tv_title.setText("Timeout")
Toast.makeText(this, " SMS retriever API Timeout", Toast.LENGTH_SHORT).show()
}
Step 5: Register your receiver:
Code:
val intentFilter = IntentFilter()
intentFilter.addAction(ReadSmsConstant.READ_SMS_BROADCAST_ACTION)
applicationContext.registerReceiver(
smsBroadcast as MySMSBrodcastReceiverHms,
intentFilter
)
Step 6: Run the application
Conclusion
This feature will help the user to be verified faster than the regular way and it will prevent the user from any typo mistake like writing the OTP, keep in mind this feature will work only if the user has the sim card on his phone other wais it will not trigger the broadcast receiver. From now not every app with READ SMS permission can access your personal data like messages. Usually, to auto-fill OTP we give access to an android app it’s better to off that permission after the process is completed (else they will have access to each & every message you have on the mobile), but how many will do that. With SMS Retriever API apps won’t ask for READ SMS permission to auto-fill OTP.
Tips & Tricks
Remove AppSignatureHelper class from your project before going to production.
Debug and Release APK’s might have different Hashcodes, make sure you get hashcode from release APK.
References
Automatically Reading an SMS Verification Code Without User Authorization:
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/readsmsmanager-0000001050050861
Automatically Reading an SMS Verification Code After User Authorization:
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/authotize-to-read-sms-0000001061481826#EN-US_TOPIC_0000001126286229__section1186673334918
ReadSmsManager Reference:
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/readsmsmanager-0000001050050861
Obtaining the Hash Value Reference:
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides-V5/obtaining-hash-value-0000001050194405-V5
Checkout in forum