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
Related
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
In this article I will show the basics of deep linking for Flutter, using Huawei Push Kit Plugin along with uni_links package.
Here are the links for those packages:
https://pub.dev/packages/huawei_push
https://pub.dev/packages/uni_links
Deep Linking
The most basic definition for a deep link is: “A link that sends users to related content on an application”.
Okay but why is this important ?
For improving the User Experience (UX) of course. By utilizing custom uniform resource identifiers (URIs), developers can create funnels in their apps for landing users to the specific content and make the user experience better.
We can validate this with an example: An e-commerce application on your phone has sent you a notification that there will be a discount on stickers. Would you prefer going to the stickers page by tapping the notification or rather navigate by yourself through the enourmous menus like Home > Products > Handmade Products > Stationery & Party Supplies > Stationery Stickers. I am assuming you would choose the first aproach.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Huawei Push Kit allows developers to send push notifications that can include custom intents or actions. This is well suited for our case. So let’s get started for the sake of our users’ experience.
Before we begin, there are prerequisites that need to be completed.
Huawei Developer Account: you must have this account to use the Push Kit Service. Click here to sign up if you don’t have an account already.
HMS Core SDK setup: For using the Push Kit we have to make some configurations on Huawei Developer Console and in our application. Refer to this medium post for installation and if you have any trouble doing so you can also check this post for a more in-depth setup.
The project
The project will be a very simple app that will display information about Huawei Mobile Services. Here is the project’s Github link if you want to follow from there.
Project Setup
As I’ve mentioned before we will use uni_links and Huawei Push Kit plugins in our project. We will also add flutter_webview_plugin into the mix for displaying the website content of the service. So let’s start by adding these to our pubspec.yaml file
Code:
dependencies:
flutter:
sdk: flutter
huawei_push: 4.0.4+300
uni_links: 0.4.0
flutter_webview_plugin: 0.3.11
To listen for intents, uni_links package needs a configuration in the AndroidManifest.xml file. Add an intent filter inside <activity> tag like below.
Code:
<application
<!-- . . .
Other Configurations
. . . -->
<activity/>
<!-- . . .
Other Configurations
. . . -->
<!-- Add the intent filter below.(inside the application and activity tags) -->
<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="app"/>
</intent-filter>
</activity>
</application
Here we have used a scheme called “app”. You can also use your own custom scheme. For more information on this subject refer to this document.
Now that we are done with the installation let’s get started with coding. The project is very simple, you can check the file hierarchy below.
We have two app pages. Home page will show various Huawei Mobile Services and the content page will display the service information inside a webview. We will navigate to this page if a notification with custom intent is tapped.
Main.dart
Code:
import 'package:deep_linking_demo/router.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Deep Linking Demo',
theme: ThemeData(
primarySwatch: Colors.red,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
onGenerateRoute: Router.generateRoute,
initialRoute: '/',
);
}
}
This main.dart file is almost identical with what you get for default except for the named route generation. Here, I have defined the onGenerateRoute and initialRoute properties of the MaterialApp and I have passed Router’s generateRoute method. Let’s look at the router.dart file to see what’s going on.
Router.dart
I used named routes because they contain less boilerplate and easier to use with custom intents. For using the named routes in Flutter we should set the names for our routes and return the corresponding MaterialPageRoute based on the name. Here, I am also getting the arguments needed for the content page and passing to its widget. (We put these arguments when we call the navigator)
Code:
import 'package:deep_linking_demo/screens/content_page.dart';
import 'package:deep_linking_demo/screens/home_page.dart';
import 'package:flutter/material.dart';
class Router {
static const String HomePageRoute = '/';
static const String ContentPageRoute = '/ContentPage';
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case HomePageRoute:
return MaterialPageRoute(builder: (context) => HomePage());
case ContentPageRoute:
final ContentPageArguments args = settings.arguments;
return MaterialPageRoute(
builder: (context) => ContentPage(
serviceName: args.serviceName,
serviceUrl: args.serviceUrl,
),
);
default:
// Error the named route doesn't exist
return MaterialPageRoute(builder: (context) => HomePage());
}
}
}
Hms.dart
This class’ mere purpose is to hold the data for the names and URLs for the HMS services that will be displayed on our home page.
Code:
class HMS {
final String name;
final String url;
final HMSGroup hmsGroup;
const HMS(this.name, this.url, this.hmsGroup);
static const Map<HMSGroup, List<HMS>> HMSMap = {
HMSGroup.AI : _aiServicesList,
HMSGroup.SECURITY : _securityServicesList,
// ...Rest of the mappings
};
static const List<HMS> _aiServicesList = [
HMS('ML Kit','https://developer.huawei.com/consumer/en/hms/huawei-mlkit',HMSGroup.AI),
HMS('HUAWEI HiAI Foundation','https://developer.huawei.com/consumer/en/hiai#Foundation',HMSGroup.AI),
HMS('HUAWEI HiAI Engine','https://developer.huawei.com/consumer/en/hiai#Engine',HMSGroup.AI),
HMS('HUAWEI HiAI Service','https://developer.huawei.com/consumer/en/hiai#Service',HMSGroup.AI)
];
static const List<HMS> _securityServicesList = [
HMS('FIDO','https://developer.huawei.com/consumer/en/hms/huawei-fido',HMSGroup.SECURITY),
HMS('Safety Detect','https://developer.huawei.com/consumer/en/hms/huawei-safetydetectkit/',HMSGroup.SECURITY)
];
// ...Rest of the list definitions
}
enum HMSGroup {
APP_SERVICES,
MEDIA,
GRAPHICS,
AI,
SMART_DEVICE,
SECURITY,
SYSTEM
}
extension HMSGroupExtension on HMSGroup {
String get text {
switch (this) {
case HMSGroup.APP_SERVICES:
return "App Services";
case HMSGroup.MEDIA:
return "Media";
case HMSGroup.GRAPHICS:
return "Graphics";
case HMSGroup.AI:
return "AI";
case HMSGroup.SMART_DEVICE:
return "Smart Device";
case HMSGroup.SECURITY:
return "Security";
case HMSGroup.SYSTEM:
return "System";
default:
return "Other";
}
}
}
I’ve deleted some of the definitions to not bother you with details. Check the github repo for the full code.
Home_page.dart
This is the widget that the most important functions occur so I will split into parts and get into some details for a better explanation.
You can refer to this part for creating your own custom intent navigations for the purpose of deep linking.
Obtaining a push token
For sending push notifications we need to obtain a push token for our device.
Under the state of the widget, define an EventChannel that will listen for the push token and a string variable to hold the token.
Code:
class _HomePageState extends State<HomePage> {
String _token = '';
static const EventChannel TokenEventChannel =
EventChannel(Channel.TOKEN_CHANNEL);
. . .
}
Initialize functions below for obtaining the push token.
Code:
Future<void> initPlatformState() async {
if (!mounted) return;
TokenEventChannel.receiveBroadcastStream()
.listen(_onTokenEvent, onError: _onTokenError);
await Push.getToken();
}
void _onTokenEvent(Object event) {
// This function gets called when we receive the token successfully
setState(() {
_token = event;
});
print('Push Token: ' + _token);
}
void _onTokenError(Object error) {
setState(() {
_token = error;
});
print(_token);
}
Call the initPlatformState function on the widget’s initState method. You should now see your token printed on the debug console.
Code:
@override
void initState() {
super.initState();
initPlatformState();
}
Obtaining a push token is the most crucial part when using the push kit. If you run into any errors while obtaining the token here is checklist that could help:
1. Check your SHA-256 signature and package name on the Huawei Developer Console
2. Make sure the Push Kit is enabled on the console (Manage APIs tab)
3. Whenever you change something on the console, download the agconnect-services.json file again.
Deep linking
We will need two functions to listen for the custom intents: One is for when our app is on foreground (active) and the other one is for when the app is not active and it is opened by an intent.
Code:
Future<Null> initLinkStream() async {
if (!mounted) return;
_sub = getLinksStream().listen((String link) {
print(link);
var uri = Uri.dataFromString(link);
String page = uri.path.split('://')[1];
String serviceName = uri.queryParameters['name'];
String serviceUrl = uri.queryParameters['url'];
Navigator.of(context).pushNamed(
page,
arguments: ContentPageArguments(serviceName, serviceUrl),
); // Navigate to the page from the intent
}, onError: (err) {
print("Error while listening for the link stream: " + err.toString());
});
}
Future<void> initInitialLinks() async {
// Platform messages may fail, so we use a try/catch PlatformException.
try {
String initialLink = await getInitialLink();
print(initialLink ?? 'NO LINK');
if (initialLink != null) {
print(initialLink);
var uri = Uri.dataFromString(initialLink);
String page = uri.path.split('://')[1];
String serviceName = uri.queryParameters['name'];
String serviceUrl = uri.queryParameters['url'];
try {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Navigator.of(context).pushNamed(
page,
arguments: ContentPageArguments(serviceName, serviceUrl),
); // Navigate to the page from the intent
});
} catch (e) {
Push.showToast(e);
}
}
} on PlatformException {
print('Error: Platform Exception');
}
}
Call these functions on the widgets initState
Code:
@override
void initState() {
super.initState();
initPlatformState();
initInitialLinks();
initLinkStream();
}
Our custom intent inside the push notification looks like this:
Code:
app:///ContentPage?name=Push Kit&url=https://developer.huawei.com/consumer/en/hms/huawei-pushkit
By adding query params, we can utilize the Uri class’ queryParameters method to easily obtain the values we need and not worry about string parsing.
Now for the final part of home_page.dart here is the UI code below.
Code:
Widget serviceButton(HMS service) {
return ListTile(
title: Text(service.name),
onTap: () => Navigator.of(context).pushNamed(
'/ContentPage',
arguments: ContentPageArguments(service.name, service.url),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Huawei Mobile Services"),
centerTitle: true,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * 0.8,
child: ListView.builder(
itemCount: HMS.HMSMap.length,
itemBuilder: (context, idx) => ExpansionTile(
title: Text(
'${HMS.HMSMap.keys.elementAt(idx).text}',
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 25),
),
children: HMS.HMSMap[HMS.HMSMap.keys.elementAt(idx)]
.map((e) => serviceButton(e))
.toList(),
),
),
)
],
),
);
}
Content_page.dart
The last file is content_page.dart. This widget is very simple since it’s only purpose is to display the related service content inside a webview.
Code:
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
class ContentPageArguments {
final String serviceName;
final String serviceUrl;
ContentPageArguments(this.serviceName, this.serviceUrl);
}
class ContentPage extends StatelessWidget {
final String serviceName;
final String serviceUrl;
ContentPage({Key key, @required this.serviceName, @required this.serviceUrl})
: super(key: key) {
assert(serviceName != null);
assert(serviceUrl != null);
}
@override
Widget build(BuildContext context) {
return WebviewScaffold(
url: serviceUrl,
appBar: AppBar(
title: Text(serviceName),
),
withZoom: true,
withLocalStorage: true,
hidden: true,
initialChild: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Center(
child: Text('Loading.....'),
),
SizedBox(
height: 10,
),
Center(child: CircularProgressIndicator())
],
),
),
);
}
}
Sending Push Notifications with Custom Intent
Now for the last part let’s head over to Huawei Developer Console and create a push notification that include a custom intent. Enter the details like in the image below and press “Test Effect” button or submit your push notification from top right corner.
You can find the custom intent uri entered here on the deep linking section of this article
If you press “Test Effect” button console will prompt you to enter the token you obtained earlier.
Enter the push token obtained earlier in the app
Deep Linking while app is on foreground.
Deep linking is working as expected. Kudos to you if you got this far!
Conclusion
Push notifications and deep linking is a must for a mobile application nowadays since their use can boost up user retention and experience if used properly. Huawei Push Kit’s notifications include custom intent and custom action features for the use of deep linking but they aren’t limited with these ones only. If you want to check all the features click here.
I hope this tutorial was helpful for you. If you have any questions regarding this article feel free to ask them on the comment section.
You can also check our other articles about using Huawei Mobile Services on Flutter below.
https://medium.com/huawei-developers/integrating-huawei-analytics-kit-to-flutter-projects-and-sending-events-3dcc4c4f03f
https://medium.com/huawei-developers/using-huawei-map-kit-on-flutter-applications-f83b2a5668bc
https://medium.com/huawei-developers/sending-push-notifications-on-flutter-with-huawei-push-kit-plugin-534787862b4d
Reference
Github demo project: https://github.com/HMS-Core/hms-flutter-plugin/tree/master/flutter-hms-push
In this article, I am going to use 3 Huawei kits in one project:
· Map Kit, for personalizing how your map displays and interact with your users, also making location-based services work better for your users.
· Location Kit, for getting the user’s current location with fused location function, also creating geofences.
· Site Kit, for searching and exploring the nearby places with their addresses.
What is a Geo-fence?
Geofence literally means a virtual border around a geographic area. Geofencing technology is the name of the technology used to trigger an automatic alert when an active device enters a defined geographic area (geofence).
As technology developed, brands started to reach customers. Of course, at this point, with digital developments, multiple new marketing terms started to emerge. Geofencing, a new term that emerged with this development, entered the lives of marketers.
Project Setup
HMS Integration
Firstly, you need a Huawei Developer account and add an app in Projects in AppGallery Connect console. So that you can activate the Map, Location and Site kits and use them in your app. If you don’t have an Huawei Developer account and don’t know the steps please follow the links below.
· Register Huawei developer website
· Configuring app information in AppGallery Connect
· Integrating Map Kit Flutter Plugin
· Integrating Location Kit Flutter Plugin
· Integrating Site Kit Flutter Plugin
Important: While adding app, the package name you enter should be the same as your Flutter project’s package name.
Note: Before you install agconnect-services.json file, make sure the required kits are enabled.
Permissions
In order to make your kits work perfectly, you need to add the permissions below in AndroidManifest.xml file.
Code:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
Creating Flutter Application
Add Dependencies to ‘pubspec.yaml’
After completing all the steps above, you need to add the required kits’ Flutter plugins as dependencies to pubspec.yaml file. You can find all the plugins in pub.dev with the latest versions. You can follow the steps in installing section of the following links.
· Map Kit Plugin for Flutter
· Location Kit Plugin for Flutter
· Site Kit Plugin for Flutter
Code:
dependencies:
flutter:
sdk: flutter
huawei_location: ^5.0.0+301
huawei_site: ^5.0.1+300
huawei_map: ^4.0.4+300
After adding them, run flutter pub get command.
All the plugins are ready to use!
Request Location Permission and Get Current Location
Create a PermissionHandler instance and initialize it in initState to ask for permission. Also, follow the same steps for FusedLocationProviderClient. With locationService object, we can get the user’s current location by calling getLastLocation() method.
Code:
LatLng center;
PermissionHandler permissionHandler;
FusedLocationProviderClient locationService;
@override
void initState() {
permissionHandler = PermissionHandler();
locationService = FusedLocationProviderClient();
getCurrentLatLng();
super.initState();
}
getCurrentLatLng() async {
await requestPermission();
Location currentLocation = await locationService.getLastLocation();
LatLng latLng = LatLng(currentLocation.latitude, currentLocation.longitude);
setState(() {
center = latLng;
});
}
In requestPermission() method, you can find both Location Permission and Background Location Permission.
Code:
requestPermission() async {
bool hasPermission = await permissionHandler.hasLocationPermission();
if (!hasPermission) {
try {
bool status = await permissionHandler.requestLocationPermission();
print("Is permission granted $status");
} catch (e) {
print(e.toString());
}
}
bool backgroundPermission =
await permissionHandler.hasBackgroundLocationPermission();
if (!backgroundPermission) {
try {
bool backStatus =
await permissionHandler.requestBackgroundLocationPermission();
print("Is background permission granted $backStatus");
} catch (e) {
print(e.toString);
}
}
}
When you launch the app for the first time, the location permission screen will appear.
{
"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"
}
Add HuaweiMap
Huawei Map is the main layout of this project. It will cover all the screen and also we will add some buttons on it, so we should put HuaweiMap and other widgets into a Stack widget. Do not forget to create a Huawei map controller.
Code:
static const double _zoom = 16;
Set<Marker> _markers = {};
int _markerId = 1;
Set<Circle> _circles = {};
int _circleId = 1;
_onMapCreated(HuaweiMapController controller) {
mapController = controller;
}
Stack(
fit: StackFit.expand,
children: <Widget>[
HuaweiMap(
onMapCreated: _onMapCreated,
initialCameraPosition:
CameraPosition(target: center, zoom: _zoom),
mapType: MapType.normal,
onClick: (LatLng latLng) {
placeSearch(latLng);
selectedCoordinates = latLng;
_getScreenCoordinates(latLng);
setState(() {
clicked = true;
addMarker(latLng);
addCircle(latLng);
});
},
markers: _markers,
circles: _circles,
tiltGesturesEnabled: true,
buildingsEnabled: true,
compassEnabled: true,
zoomControlsEnabled: true,
rotateGesturesEnabled: true,
myLocationButtonEnabled: true,
myLocationEnabled: true,
trafficEnabled: false,
),
],
)
We have got the current location with Location service’s getLastLocation() method and assigned it to center variables as longitude and latitude. While creating the HuaweiMap widget, assign that center variable to HuaweiMap’s target property, so that the app opens with a map showing the user’s current location.
Code:
placeSearch(LatLng latLng) async {
NearbySearchRequest request = NearbySearchRequest();
request.location = Coordinate(lat: latLng.lat, lng: latLng.lng);
request.language = "en";
request.poiType = LocationType.ADDRESS;
request.pageIndex = 1;
request.pageSize = 1;
request.radius = 100;
NearbySearchResponse response = await searchService.nearbySearch(request);
try {
print(response.sites);
site = response.sites[0];
} catch (e) {
print(e.toString());
}
}
When onClick method of HuaweiMap is triggered, call placeSearch using the Site Kit’s nearbySearch method. Thus, you will get a Site object to assign to the new geofence you will add.
Create Geofence
When the user touch somewhere on the map; a marker, a circle around the marker, a Slider widget to adjust the radius of the circle, and a button named “Add Geofence” will show up on the screen. So we will use a boolean variable called clicked and if it’s true, the widgets I have mentioned in the last sentence will be shown.
Code:
addMarker(LatLng latLng) {
if (marker != null) marker = null;
marker = Marker(
markerId: MarkerId(_markerId.toString()), //_markerId is set to 1
position: latLng,
clickable: true,
icon: BitmapDescriptor.defaultMarker,
);
setState(() {
_markers.add(marker);
});
selectedCoordinates = latLng;
_markerId++; //after a new marker is added, increase _markerId for the next marker
}
_drawCircle(Geofence geofence) {
this.geofence = geofence;
if (circle != null) circle = null;
circle = Circle(
circleId: CircleId(_circleId.toString()),
fillColor: Colors.grey[400],
strokeColor: Colors.red,
center: selectedCoordinates,
clickable: false,
radius: radius,
);
setState(() {
_circles.add(circle);
});
_circleId++;
}
Create a Slider widget wrapped with a Positioned widget and put them into Stack widget as shown below.
Code:
if (clicked)
Positioned(
bottom: 10,
right: 10,
left: 10,
child: Slider(
min: 50,
max: 200,
value: radius,
onChanged: (newValue) {
setState(() {
radius = newValue;
_drawCircle(geofence);
});
},
),
),
After implementing addMarker and drawCircle methods and adding Slider widget, now we will create AddGeofence Screen and it will appear as a ModalBottomSheet when AddGeofence button is clicked.
Code:
RaisedButton(
child: Text("Add Geofence"),
onPressed: () async {
geofence.uniqueId = _fenceId.toString();
geofence.radius = radius;
geofence.latitude = selectedCoordinates.lat;
geofence.longitude = selectedCoordinates.lng;
_fenceId++;
final clickValue = await showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: AddGeofenceScreen(
geofence: geofence,
site: site,
),
),
),
);
updateClicked(clickValue);
//When ModalBottomSheet is closed, pass a bool value in Navigator
//like Navigator.pop(context, false) so that clicked variable will be
//updated in home screen with updateClicked method.
},
),
void updateClicked(bool newValue) {
setState(() {
clicked = newValue;
});
}
In the new stateful AddGeofenceScreen widget’s state class, create GeofenceService and SearchService instances and initialize them in initState.
Code:
GeofenceService geofenceService;
int selectedConType = Geofence.GEOFENCE_NEVER_EXPIRE;
SearchService searchService;
@override
void initState() {
geofenceService = GeofenceService();
searchService = SearchService();
super.initState();
}
To monitor address, radius and also to select conversion type of the geofence, we will show a ModalBottomSheet with the widgets shown below.
Code:
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
"Address",
style: boldStyle,
),
Text(site.formatAddress),
Text(
"\nRadius",
style: boldStyle,
),
Text(geofence.radius.toInt().toString()),
Text(
"\nSelect Conversion Type",
style: boldStyle,
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
RadioListTile<int>(
dense: true,
title: Text(
"Enter",
style: TextStyle(fontSize: 14),
),
value: Geofence.ENTER_GEOFENCE_CONVERSION,
groupValue: selectedConType,
onChanged: (int value) {
setState(() {
selectedConType = value;
});
},
),
RadioListTile<int>(
dense: true,
title: Text("Exit"),
value: Geofence.EXIT_GEOFENCE_CONVERSION,
groupValue: selectedConType,
onChanged: (int value) {
setState(() {
selectedConType = value;
});
},
),
RadioListTile<int>(
dense: true,
title: Text("Stay"),
value: Geofence.DWELL_GEOFENCE_CONVERSION,
groupValue: selectedConType,
onChanged: (int value) {
setState(() {
selectedConType = value;
});
},
),
RadioListTile<int>(
dense: true,
title: Text("Never Expire"),
value: Geofence.GEOFENCE_NEVER_EXPIRE,
groupValue: selectedConType,
onChanged: (int value) {
setState(() {
selectedConType = value;
});
},
),
],
),
Align(
alignment: Alignment.bottomRight,
child: FlatButton(
child: Text(
"SAVE",
style: TextStyle(
color: Colors.blue, fontWeight: FontWeight.bold),
),
onPressed: () {
geofence.conversions = selectedConType;
addGeofence(geofence);
Navigator.pop(context, false);
},
),
)
],
),
For each conversion type, add a RadioListTile widget.
When you click SAVE button, addGeofence method will be called to add new Geofence to the list of Geofences, then return to the Home screen with false value to update clicked variable.
In addGeofence, do not forget to call createGeofenceList method with the list you have just added the geofence in.
Code:
void addGeofence(Geofence geofence) {
geofence.dwellDelayTime = 10000;
geofence.notificationInterval = 100;
geofenceList.add(geofence);
GeofenceRequest geofenceRequest = GeofenceRequest(geofenceList:
geofenceList);
try {
int requestCode = await geofenceService.createGeofenceList
(geofenceRequest);
print(requestCode);
} catch (e) {
print(e.toString());
}
}
To listen to the geofence events, you need to use onGeofenceData method in your code.
Code:
GeofenceService geofenceService;
StreamSubscription<GeofenceData> geofenceStreamSub;
@override
void initState() {
geofenceService = GeofenceService();
geofenceStreamSub = geofenceService.onGeofenceData.listen((data) {
infoText = data.toString(); //you can use this infoText to show a toast message to the user.
print(data.toString);
});
super.initState();
}
Search Nearby Places
In home screen, place a button onto the map to search nearby places with a keyword and when it is clicked a new alertDialog page will show up.
Code:
void _showAlertDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Search Location"),
content: Container(
height: 150,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
TextField(
controller: searchQueryController,
),
MaterialButton(
color: Colors.blue,
child: Text(
"Search",
style: TextStyle(color: Colors.white),
),
onPressed: () async {
Navigator.pop(context);
_markers =
await nearbySearch(center, searchQueryController.text);
setState(() {});
},
)
],
),
),
actions: [
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.pop(context);
},
),
],
);
},
);
}
After you enter the keyword and click Search button, there will be markers related to the keyword will appear on the map.
Conclusion
In this article you have learnt how to use some of the features of Huawei Map, Location and Site kits in your projects. Also, you have learnt the geofencing concept. Now you can add geofences to your app and with geofencing, you can define an audience based on a customer’s behavior in a specific location. With location information, you can show suitable ads to the right people simultaneously, wherever they are.
Thank you for reading this article, I hope it was useful and you enjoyed it!
Huawei is the best Android smartphone devices making company. I don't know why Android creating a so much of issues. I feel bad
Can we show GIF image on huawei map at predefined locaation?
In this article, we can learn to get current and nearby places of user’s device using a Huawei Nearby Place Search API and also to implement it in Huawei Map.
If you want to provide a feature in your app that should display a list of places such as Restaurant, GYM, Banks, Hospitals, Business, Parks, Transport, etc. near the current location of user device, then you need to use Huawei Nearby place search API, MAP and Location Kit to implement it.
Environment Requirement
1) Node JS and Visual Studio.
2) The JDK version must be 1.8 or later.
3) React Native Location, Map and Site Plugin is not supported by Expo CLI. Use React Native CLI instead.
Project Setup
1) Creating New Project.
Code:
react-native init project name
2) Generating a Signing Certificate Fingerprint.
Use following command for generating certificate.
Code:
keytool -genkey -keystore <application_project_dir>\android\app\<signing_certificate_fingerprint_filename>.jks -storepass <store_password> -alias <alias> -keypass <key_password> -keysize 2048 -keyalg RSA -validity 36500
This command creates the keystore file in application_project_dir/android/app.
The next step is to obtain the SHA256 key.
To obtain it, enter the following command in terminal:
Code:
keytool -list -v -keystore <application_project_dir>\android\app\<signing_certificate_fingerprint_filename>.jks
After an authentication, user can see SHA256 in below picture
{
"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"
}
3) Create an app in the Huawei AppGallery Connect.
4) Provide the SHA256 Key in App Information section.
5) Enable Map and Site kit service under Manage APIs section.
6) Download and add the agconnect-services.json file in your project.
7) Copy and paste the below maven url inside the repositories of build script and all projects (project build.gradle file):
Java:
maven { url 'http://developer.huawei.com/repo/' }
8) Copy and paste the below AppGallery Connect plugin for the HMS SDK inside dependencies (project build.gradle file):
Java:
classpath 'com.huawei.agconnect:agcp:1.4.2.301'
9) Make sure that the minSdkVersion for your application project is 19 or higher.
10) Download the Huawei Location, Map and Site kit plugin using the following command.
Code:
npm i @hmscore/react-native-hms-location
npm i @hmscore/react-native-hms-map
npm i @hmscore/react-native-hms-site
11) Add Permissions in Android Manifest file.
XML:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
Nearby Places Example
Now let’s see how to use places API to get list of nearby places based on user’s current location, display them in Map and show the current location along with address on Huawei maps.
Step 1: Using the Places API requires ACCESS_FINE_LOCATION permission, so you need to request that in your JS file:
JavaScript:
HMSLocation.FusedLocation.Native.hasPermission()
.then((result) => setHasLocationPermission(result))
.catch(HMSLocation.FusedLocation.Native.requestPermission());
Step 2: Finding Current Location and Address:
JavaScript:
HMSLocation.FusedLocation.Native.getLastLocation()
.then((pos) => (position ? null : setPosition(pos)))
.catch((err) => console.log('Failed to get last location', err));
HMSLocation.FusedLocation.Native.getLastLocationWithAddress(locationRequest)
.then((pos) => (address ? null : setAddress(pos)))
.catch((err) => console.log('Failed to get last location address', err));
Step 3: Initialize the Site kit and get list of places such as Restaurant near the current location of user device:
JavaScript:
Position ? RNHMSSite.initializeService(config)
.then(() => {
nearbySearchReq = {
location: {
lat: position.latitude,
lng: position.longitude,
},
radius: 5000,
hwPoiType: RNHMSSite.HwLocationType.RESTAURANT,
poiType: RNHMSSite.LocationType.GYM,
countryCode: 'IN',
language: 'en',
pageIndex: 1,
pageSize: 20,
politicalView: 'en',
};
site.length === 0
? RNHMSSite.nearbySearch(nearbySearchReq)
.then((res) => {
setSite(res.sites);
console.log(JSON.stringify(res));
mapView.setCameraPosition({
target: {
latitude: site[0].location.lat,
longitude: site[0].location.lng,
},
zoom: 17,
});
})
.catch((err) => {
console.log(JSON.stringify(err));
})
: null;
})
.catch((err) => {
console.log('Error : ' + err);
})
Step 4: Display a list of places on Map such as Restaurant near the current location of user device:
JavaScript:
<MapView
style={{ height: 590 }}
camera={{
target: {
latitude: position.latitude,
longitude: position.longitude,
},
zoom: 15,
}}
ref={(e) => (mapView = e)}
myLocationEnabled={true}
markerClustering={true}
myLocationButtonEnabled={true}
rotateGesturesEnabled={true}
scrollGesturesEnabled={true}
tiltGesturesEnabled={true}
zoomGesturesEnabled={true}>
{site != null
? Object.keys(site).map(function (key, i) {
return (
<Marker
visible={true}
coordinate={{
latitude: site[i].location.lat,
longitude: site[i].location.lng,
}}
clusterable>
<InfoWindow
style={{
alignContent: 'center',
justifyContent: 'center',
borderRadius: 8,
}}>
<View style={style.markerSelectedHms}>
<Text
style={style.titleSelected}>{`${site[i].name}`}</Text>
</View>
</InfoWindow>
</Marker>
);
})
: null}
</MapView>
Step 5: Get Current location address:
JavaScript:
address ? (
<View style={style.bottomView,{ backgroundColor: "white"}}>
<View style={{ flexDirection: "row" ,marginStart: 10}}>
<Image source={require('../assets/home.png')} style={{ width: 40, height: 40 }}/>
<Text style={{ marginTop: 10 ,marginStart: 10 }}>My Address</Text>
</View>
<Text style={style.textStyle}> {address.featureName + ", " +address.city+", Postal Code = "+address.postalCode} </Text>
</View>
)
Nearby Places Example Output:
Complete Code:
Copy and paste following code in your App.js file:
JavaScript:
import 'react-native-gesture-handler';
import * as React from 'react';
import { StyleSheet} from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import MapComponent from './components/MapComponent';
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home"
component={MapComponent}
options={{ title: 'Huawei Map' }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
MainContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
text: {
textAlign: 'center',
margin: 12,
fontSize: 22,
fontWeight: "100",
},
});
export default App;
Copy and paste following code in your MapComponent.js file:
1. Create folder components inside components, create a file called MapComponent.js.
2. Add the generated API key.
JavaScript:
import React, { Component, useState, useEffect } from 'react';
import { ActivityIndicator, SafeAreaView, View, Text , Image} from 'react-native';
import RNHMSSite from '@hmscore/react-native-hms-site';
import HMSLocation from '@hmscore/react-native-hms-location';
import MapView, { Marker, InfoWindow } from '@hmscore/react-native-hms-map';
let mapView, nearbySearchReq;const
config = {
apiKey: 'YOUR API KEY',
};
const GetPermssions = () => {
const [hasLocationPermission, setHasLocationPermission] = useState(false);
const [position, setPosition] = useState();
const [site, setSite] = useState([]);
const [address, setAddress] = useState();
locationRequest = {
priority: HMSLocation.FusedLocation.PriorityConstants.PRIORITY_HIGH_ACCURACY,
interval: 3,
numUpdates: 10,
fastestInterval: 1000.0,
expirationTime: 1000.0,
expirationTimeDuration: 1000.0,
smallestDisplacement: 0.0,
maxWaitTime: 10000.0,
needAddress: true,
language: "en",
countryCode: "en",
};
useEffect(() => {
HMSLocation.FusedLocation.Native.hasPermission()
.then((result) => setHasLocationPermission(result))
.catch(HMSLocation.FusedLocation.Native.requestPermission());
}, []);
if (hasLocationPermission) {
HMSLocation.FusedLocation.Native.getLastLocation()
.then((pos) => (position ? null : setPosition(pos)))
.catch((err) => console.log('Failed to get last location', err));
HMSLocation.FusedLocation.Native.getLastLocationWithAddress(locationRequest)
.then((pos) => (address ? null : setAddress(pos)))
.catch((err) => console.log('Failed to get last location address', err));
position
? RNHMSSite.initializeService(config)
.then(() => {
nearbySearchReq = {
location: {
lat: position.latitude,
lng: position.longitude,
},
radius: 5000,
hwPoiType: RNHMSSite.HwLocationType.RESTAURANT,
poiType: RNHMSSite.LocationType.GYM,
countryCode: 'IN',
language: 'en',
pageIndex: 1,
pageSize: 20,
politicalView: 'en',
};
site.length === 0
? RNHMSSite.nearbySearch(nearbySearchReq)
.then((res) => {
setSite(res.sites);
console.log(JSON.stringify(res));
mapView.setCameraPosition({
target: {
latitude: site[0].location.lat,
longitude: site[0].location.lng,
},
zoom: 17,
});
})
.catch((err) => {
console.log(JSON.stringify(err));
})
: null;
})
.catch((err) => {
console.log('Error : ' + err);
})
: null;
} else {
HMSLocation.FusedLocation.Native.requestPermission();
}
return (
<SafeAreaView
style={{
flex: 1,
}}>
{position ? (
<View>
<MapView
style={{ height: 590 }}
camera={{
target: {
latitude: position.latitude,
longitude: position.longitude,
},
zoom: 15,
}}
ref={(e) => (mapView = e)}
myLocationEnabled={true}
markerClustering={true}
myLocationButtonEnabled={true}
rotateGesturesEnabled={true}
scrollGesturesEnabled={true}
tiltGesturesEnabled={true}
zoomGesturesEnabled={true}>
{site != null
? Object.keys(site).map(function (key, i) {
return (
<Marker
visible={true}
coordinate={{
latitude: site[i].location.lat,
longitude: site[i].location.lng,
}}
clusterable>
<InfoWindow
style={{
alignContent: 'center',
justifyContent: 'center',
borderRadius: 8,
}}>
<View style={style.markerSelectedHms}>
<Text
style={style.titleSelected}>{`${site[i].name}`}</Text>
</View>
</InfoWindow>
</Marker>
);
})
: null}
</MapView>
</View>
) : (
<ActivityIndicator size="large" color="#0000ff" />
)}
{address ? (
<View style={style.bottomView,{ backgroundColor: "white"}}>
<View style={{ flexDirection: "row" ,marginStart: 10}}>
<Image source={require('../assets/home.png')} style={{ width: 40, height: 40 }}/>
<Text style={{ marginTop: 10 ,marginStart: 10 }}>My Address</Text>
</View>
<Text style={style.textStyle}> {address.featureName + ", " +address.city+", Postal Code = "+address.postalCode} </Text>
</View>
) : (
<ActivityIndicator s size="large" color="#0000ff" />
)}
</SafeAreaView>
);
};
export default class MapComponent extends Component {
render() {
return <GetPermssions />;
}
}
const style = (base) => ({
markerSelectedHms: {
flexDirection: 'row',
height: 50,
borderRadius: base.radius.default,
overflow: 'hidden',
alignSelf: 'center',
alignItems: 'center',
alignContent: 'center',
justifyContent: 'space-between',
},
bottomView: {
width: '100%',
height: 50,
backgroundColor: 'white',
position: 'absolute', //Here is the trick
bottom: 0, //Here is the trick
},
textStyle: {
color: '#000',
fontSize: 18,
}
});
Run the application:
Code:
react-native run-android
Tips and Tricks:
1) Do not forget to add API key in MapComponent.JS file.
2) Do not forget to enable Map and Site kit service in AGC console APP Gallery connect > Manage APIs section.
Conclusion:
In this article, you have learned to setting up your react native project for Huawei Nearby place API, getting list of places near current location of device, displaying list of places in Map with markers and displaying current location on Map with address.
Reference:
1) React native Plugin
2) Site Kit
3) Location Kit
4) Map Kit
Read In Forum
Can we search multiple POI in one requrest?
{
"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
In this article, we will learn how to use Huawei Cloud Functions service as Chatbot service in ChatBotApp in flutter. Cloud Functions enables serverless computing.
It provides the Function as a Service (FaaS) capabilities to simplify app development and O&M by splitting service logic into functions and offers the Cloud Functions SDK that works with Cloud DB and Cloud Storage so that your app functions can be implemented more easily. Cloud Functions automatically scales in or out functions based on actual traffic, freeing you from server resource management and helping you reduce costs.
Key Functions
Key Concepts
How the Service Works
To use Cloud Functions, you need to develop cloud functions that can implement certain service functions in AppGallery Connect and add triggers for them, for example, HTTP triggers for HTTP requests, and Cloud DB triggers for data deletion or insertion requests after Cloud DB is integrated. After your app that integrates the Cloud Functions SDK meets conditions of specific function triggers, your app can call the cloud functions, which greatly facilitates service function building.
Platform Support
Development Overview
You need to install Flutter and Dart plugin in IDE and I assume that you have prior knowledge about the Flutter and Dart.
Hardware Requirements
A computer (desktop or laptop) running Windows 10.
Android phone (with the USB cable), which is used for debugging.
Software Requirements
Java JDK 1.7 or later.
Android studio software or Visual Studio or Code installed.
HMS Core (APK) 4.X or later.
Integration process
Step 1: Create Flutter project.
Step 2: Add the App level gradle dependencies. Choose inside project Android > app > build.gradle.
[/B][/B]
apply plugin: 'com.android.application'
apply plugin: 'com.huawei.agconnect'
[B][B]
Root level gradle dependencies
maven {url 'https://developer.huawei.com/repo/'}
classpath 'com.huawei.agconnect:agcp:1.5.2.300'
Step 3: Add the below permissions in Android Manifest file.
<uses-permission android:name="android.permission.INTERNET" />
Step 4: Add downloaded file into parent directory of the project. Declare plugin path in pubspec.yaml file under dependencies.
Add path location for asset image.
Prevoius article
Using Huawei Cloud Functions as Chatbot Service in Flutter ChatBotApp Part-1
Let's start coding
main.dart
[/B]
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ChatBotService',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'ChatBotService'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool isLoggedIn = false;
String str = 'Login required';
final HMSAnalytics _hmsAnalytics = new HMSAnalytics();
List<String> gridItems = ['Email Service', 'Call Center', 'FAQ', 'Chat Now'];
@override
void initState() {
_enableLog();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child:
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Visibility(
visible: true,
child: Card(
child: Padding(
padding: EdgeInsets.all(20),
child: Text(
str,
style: const TextStyle(color: Colors.teal, fontSize: 22),
),
),
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
if (!isLoggedIn) {
setState(() {
isLoggedIn = true;
signInWithHuaweiID();
});
print('$isLoggedIn');
} else {
setState(() {
isLoggedIn = false;
signOutWithID();
});
print('$isLoggedIn');
}
},
tooltip: 'Login/Logout',
child: isLoggedIn ? const Icon(Icons.logout) : const Icon(Icons.login),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
void signInWithHuaweiID() async {
try {
// The sign-in is successful, and the user's ID information and authorization code are obtained.
Future<AuthAccount> account = AccountAuthService.signIn();
account.then(
(value) => setLoginSuccess(value),
);
} on Exception catch (e) {
print(e.toString());
}
}
Future<void> _enableLog() async {
_hmsAnalytics.setUserId("ChatBotServiceApp");
await _hmsAnalytics.enableLog();
}
void setLoginSuccess(AuthAccount value) {
setState(() {
str = 'Welcome ' + value.displayName.toString();
});
showToast(value.displayName.toString());
print('Login Success');
}
Future<void> signOutWithID() async {
try {
final bool result = await AccountAuthService.signOut();
if (result) {
setState(() {
str = 'Login required';
showToast('You are logged out.');
});
}
} on Exception catch (e) {
print(e.toString());
}
}
Future<void> showToast(String name) async {
Fluttertoast.showToast(
msg: "$name",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.lightBlue,
textColor: Colors.white,
fontSize: 16.0);
}
}
[B]
ChatPage.dart
[/B][/B]
class ChatPage extends StatefulWidget {
const ChatPage({Key? key}) : super(key: key);
@override
_ChatPageState createState() => _ChatPageState();
}
class _ChatPageState extends State<ChatPage> {
List<types.Message> _messages = [];
final _user = const types.User(id: '06c33e8b-e835-4736-80f4-63f44b66666c');
final _bot = const types.User(id: '06c33e8b-e835-4736-80f4-63f54b66666c');
void _addMessage(types.Message message) {
setState(() {
_messages.insert(0, message);
});
}
void _handleSendPressed(types.PartialText message) {
final textMessage = types.TextMessage(
author: _user,
createdAt: DateTime.now().millisecondsSinceEpoch,
id: const Uuid().v4(),
text: message.text,
);
_addMessage(textMessage);
callCloudFunction2(message.text);
}
void _loadMessages() async {
final response = await rootBundle.loadString('assets/messages.json');
final messages = (jsonDecode(response) as List)
.map((e) => types.Message.fromJson(e as Map<String, dynamic>))
.toList();
setState(() {
_messages = messages;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Chat(
messages: _messages,
onAttachmentPressed: null,
onMessageTap: null,
onPreviewDataFetched: null,
onSendPressed: _handleSendPressed,
user: _user,
),
);
}
Future<void> callCloudFunction2(String msg) async {
try {
RequestData data = RequestData(msg);
List<Map<String, Object>> params = <Map<String, Object>>[data.toMap()];
var input = data.toMap();
FunctionCallable functionCallable =
FunctionCallable('test-funnel-\$latest');
FunctionResult functionResult = await functionCallable.call(input);
print("Input " + input.toString());
var result = functionResult.getValue();
final textMessage = types.TextMessage(
author: _bot,
createdAt: DateTime.now().millisecondsSinceEpoch,
id: const Uuid().v4(),
text: jsonDecode(result)['response'].toString(),
);
_addMessage(textMessage);
} on PlatformException catch (e) {
print(e.message);
}
}
}
[B][B]
handler.js
[/B][/B][/B]
let myHandler = function(event, context, callback, logger) {
try {
var _body = JSON.parse(event.body);
var reqData = _body.message;
var test = '';
if(reqData == '1'){
test = "Thank you for choosing, you will get callback in 10 min.";
}else if(reqData == '2'){
test = "Please click on the link https://feedback.com/myfeedback";
}else if(reqData == '3'){
test = "Please click on the link https://huawei.com/faq";
}
else if(reqData == 'Hi'){
test = " Welcome to ChatBot Service.";
}else{
test = "Enter 1. For call back. 2. For send feedback. 3. For FAQ ";
}
let res = new context.HTTPResponse({"response": test}, {
"res-type": "simple example",
"faas-content-type": "json"
}, "application/json", "200");
callback(res);
} catch (error) {
let res = new context.HTTPResponse({"response": error}, {
"res-type": "simple example",
"faas-content-type": "json"
}, "application/json", "300");
callback(res);
}
};
module.exports.myHandler = myHandler;
[B][B][B]
Result
Tricks and Tips
Makes sure that agconnect-services.json file added.
Make sure dependencies are added yaml file.
Run flutter pug get after adding dependencies.
Make sure that service is enabled in agc.
Makes sure images are defined in yaml file.
Conclusion
In this article, we have learnt how to integrate Huawei Account kit, analytics kit and ChatBot function using Cloud Functions in flutter ChatBotApp. Once Account kit integrated, users can login quickly and conveniently sign in to apps with their Huawei IDs after granting initial access permission.
Thank you so much for reading. I hope this article helps you to understand the integration of Huawei Account kit, Analytics kit and Huawei Cloud Functions in flutter ChatBotApp.
Reference
Cloud Functions
Training Videos
Checkout in forum