{
"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
Related
More information like this, you can visit HUAWEI Developer Forum
This guide describes how to write custom platform-specific code. Some platform-specific functionality is available through existing packages
Flutter uses a flexible system that allows you to call platform-specific APIs whether available in Kotlin or Java code on Android, or in Swift or Objective-C code on iOS.
Flutter’s platform-specific API support does not rely on code generation, but rather on a flexible message passing style:
The Flutter portion of the app sends messages to its host, the iOS or Android portion of the app, over a platform channel.
The host listens on the platform channel, and receives the message. It then calls into any number of platform-specific APIs—using the native programming language—and sends a response back to the client, the Flutter portion of the app.
Architectural overview: platform channels
Messages are passed between the client (UI) and host (platform) using platform channels as illustrated in this diagram:
{
"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"
}
Messages and responses are passed asynchronously, to ensure the user interface remains responsive.
Step 1: Create a new app project
Start by creating a new app:
In a terminal run: flutter create flutterhmsgmscheck
Step 2: Create the Flutter platform client
The app’s State class holds the current app state. Extend that to hold the current battery state.
First, construct the channel. Use a MethodChannel with a single platform method that returns the battery level.
The client and host sides of a channel are connected through a channel name passed in the channel constructor. All channel names used in a single app must be unique; prefix the channel name with a unique ‘domain prefix’, for example: com.salman.flutter.hmsgmscheck/isHmsGmsAvailable.
Code:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class HmsGmsCheck extends StatelessWidget {
HmsGmsCheck();
@override
Widget build(BuildContext context) {
return HmsGmsCheckStateful(
title: "HMS/GMS Check",
);
}
}
class HmsGmsCheckStateful extends StatefulWidget {
HmsGmsCheckStateful({Key key, this.title}) : super(key: key);
final String title;
@override
_HmsGmsCheckState createState() => _HmsGmsCheckState();
}
class _HmsGmsCheckState extends State<HmsGmsCheckStateful> {
static const MethodChannel methodChannel =
MethodChannel('com.salman.flutter.hmsallkitsflutter/isHmsGmsAvailable');
bool _isHmsAvailable;
bool _isGmsAvailable;
@override
void initState() {
checkHmsGms();
}
void checkHmsGms() async {
await _isHMS();
await _isGMS();
}
Future<void> _isHMS() async {
bool status;
try {
bool result = await methodChannel.invokeMethod('isHmsAvailable');
status = result;
print('status : ${status.toString()}');
} on PlatformException {
print('Failed to get _isHmsAvailable.');
}
setState(() {
_isHmsAvailable = status;
});
}
Future<void> _isGMS() async {
bool status;
try {
bool result = await methodChannel.invokeMethod('isGmsAvailable');
status = result;
print('status : ${status.toString()}');
} on PlatformException {
print('Failed to get _isGmsAvailable.');
}
setState(() {
_isGmsAvailable = status;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: <Widget>[
new Container(
padding: EdgeInsets.all(20),
child: new Column(
children: <Widget>[
Text(
"HMS Available: $_isHmsAvailable",
style: Theme.of(context).textTheme.headline6,
),
Text(
"GMS Available: $_isGmsAvailable",
style: Theme.of(context).textTheme.headline6,
)
],
),
)
],
));
}
}
Step 3: Update your gradle
Open your gradle in Android Studio and apply huawei repo:
Project-level build.gradle
Code:
buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' }
}
}
allprojects {
repositories {
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' }
}
}
App-level build.gradle
Code:
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "com.huawei.hms:hwid:4.0.0.300"
implementation "com.google.android.gms:play-services-base:17.3.0"
}
Step 4: Add an Android platform-specific implementation
Start by opening the Android host portion of your Flutter app in Android Studio:
Start Android Studio
Select the menu item File > Open…
Navigate to the directory holding your Flutter app, and select the android folder inside it. Click OK.
Open the file MainActivity.kt located in the kotlin folder in the Project view. (Note: If editing with Android Studio 2.3, note that the kotlin folder is shown as if named java.)
Inside the configureFlutterEngine() method, create a MethodChannel and call setMethodCallHandler(). Make sure to use the same channel name as was used on the Flutter client side.
Code:
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.salman.flutter.hmsgmscheck/isHmsGmsAvailable"
var concurrentContext = [email protected]
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, result ->
// Note: this method is invoked on the main thread.
if (call.method.equals("isHmsAvailable")) {
result.success(isHmsAvailable());
} else if (call.method.equals("isGmsAvailable")) {
result.success(isGmsAvailable());
} else {
result.notImplemented()
}
}
}
private fun isHmsAvailable(): Boolean {
var isAvailable = false
val context: Context = concurrentContext
if (null != context) {
val result = HuaweiApiAvailability.getInstance().isHuaweiMobileServicesAvailable(context)
isAvailable = ConnectionResult.SUCCESS == result
}
Log.i("MainActivity", "isHmsAvailable: $isAvailable")
return isAvailable
}
private fun isGmsAvailable(): Boolean {
var isAvailable = false
val context: Context = concurrentContext
if (null != context) {
val result: Int = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context)
isAvailable = com.google.android.gms.common.ConnectionResult.SUCCESS === result
}
Log.i("MainActivity", "isGmsAvailable: $isAvailable")
return isAvailable
}
}
After completing above all steps compile your project you will get the following output.
Conclusion:
With the help of this article we can able to access platform specific native code under our flutter application. For further more details you can check offical flutter platform channels guide.
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?
{
"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
Flutter Analytics Plugin provides wider range of predefined analytics models to get more insight into your application users, products, and content. With this insight, you can prepare data-driven approach to market your apps and optimize your products based on the analytics.
With Analytics Kit's on-device data collection SDK, you can:
Collect and report custom events.
Set a maximum of 25 user attributes.
Automate event collection and session calculation.
Pre-set event IDs and parameters.
Restrictions
1. Devices:
a. Analytics Kit depends on HMS Core (APK) to automatically collect the following events: INSTALLAPP (app installation), UNINSTALLAPP (app uninstallation), CLEARNOTIFICATION (data deletion), INAPPPURCHASE (in-app purchase), RequestAd (ad request), DisplayAd (ad display), ClickAd (ad tapping), ObtainAdAward (ad award claiming), SIGNIN (sign-in), and SIGNOUT (sign-out). These events cannot be automatically collected on third-party devices where HMS Core (APK) is not installed (including but not limited to OPPO, vivo, Xiaomi, Samsung, and OnePlus).
b. Analytics Kit does not work on iOS devices.
2. Number of events:
A maximum of 500 events are supported.
3. Number of event parameters:
You can define a maximum of 25 parameters for each event, and a maximum of 100 event parameters for each project.
4. Supported countries/regions
The service is now available only in the countries/regions listed in Supported Countries/Regions.
Integration process
1. Create flutter project
Step 2: Add the App level gradle dependencies. Choose inside project Android > app > build.gradle
Java:
apply plugin: 'com.android.application'
apply plugin: 'com.huawei.agconnect'
Add root level gradle dependencies
Java:
maven {url 'https://developer.huawei.com/repo/'}
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
Add app level gradle dependencies
Java:
implementation 'com.huawei.hms:hianalytics:5.1.0.300'
Step 3: Add the below permissions in Android Manifest file.
XML:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA"/>
Step 4: Flutter plugin for Huawei analytics kit.
Unzip downloaded plugin in the parent directory of the project.
Step 5: Declare plugin path in pubspec.yaml file under dependencies.
Step 5 : Create a project in AppGallery Connect.
pubspec.yaml
YAML:
<p style="margin-top: 20.0px;white-space: normal;">name: flutter_app
</p><p style="margin-top: 20.0px;white-space: normal;">description: A new Flutter application.
# The following line prevents the package from being accidentally published to
# pub.dev using `pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
huawei_analytics:
path: ../huawei_analytics/
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
dev_dependencies:
flutter_test:
sdk: flutter
# The following section is specific to Flutter.
flutter:</p>
main.dart
Code:
import 'package:flutter/material.dart';
import 'package:flutter_app/result.dart';
import 'package:huawei_analytics/huawei_analytics.dart';
import './quiz.dart';
import './result.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
var _questionIndex = 0;
int _totalScore = 0;
final HMSAnalytics _hmsAnalytics = new HMSAnalytics();
@override
void initState() {
_enableLog();
_predefinedEvent();
super.initState();
}
Future<void> _enableLog() async {
_hmsAnalytics.setUserId("TestUser123");
await _hmsAnalytics.enableLog();
}
void _restartQuiz() {
setState(() {
_questionIndex = 0;
_totalScore = 0;
});
}
void _predefinedEvent() async {
String name = HAEventType.SIGNIN;
dynamic value = {HAParamType.ENTRY: 06534797};
await _hmsAnalytics.onEvent(name, value);
print("Event posted");
}
void _customEvent(int index, int score) async {
String name = "Question$index";
dynamic value = {'Score': score};
await _hmsAnalytics.onEvent(name, value);
print("Event posted");
}
static const _questions = [
{
'questionText': 'What\'s you favorite color?',
'answers': [
{'text': 'Black', 'Score': 10},
{'text': 'White', 'Score': 1},
{'text': 'Green', 'Score': 3},
{'text': 'Red', 'Score': 5},
]
},
{
'questionText': 'What\'s your favorite place?',
'answers': [
{'text': 'India', 'Score': 1},
{'text': 'Rassia', 'Score': 5},
{'text': 'US', 'Score': 4},
{'text': 'Singapore', 'Score': 7},
]
},
{
'questionText': 'What\'s your childwood nick name?',
'answers': [
{'text': 'Bunty', 'Score': 2},
{'text': 'Binto', 'Score': 1},
{'text': 'Tom', 'Score': 5},
{'text': 'Ruby', 'Score': 3},
]
},
{
'questionText': 'What\'s your favorite subject?',
'answers': [
{'text': 'Math', 'Score': 5},
{'text': 'Physics', 'Score': 1},
{'text': 'Chemistry', 'Score': 3},
{'text': 'Biology', 'Score': 2},
]
}
];
Future<void> _answerQuestion(int score) async {
_totalScore += score;
if (_questionIndex < _questions.length) {
print('Iside if $_questionIndex');
setState(() {
_questionIndex = _questionIndex + 1;
});
print('Current questionIndex $_questionIndex');
} else {
print('Inside else $_questionIndex');
}
_customEvent(_questionIndex, score);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('QuizApp'),
),
body: _questionIndex < _questions.length
? Quiz(
answerQuestion: _answerQuestion,
questionIndex: _questionIndex,
questions: _questions,
)
: Result(_totalScore, _restartQuiz),
));
}
}
question.dart
Code:
import 'package:flutter/material.dart';
class Question extends StatelessWidget {
final String questionText;
Question(this.questionText);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
margin: EdgeInsets.all(30.0),
child: Text(
questionText,
style: TextStyle(
fontSize: 28,
),
textAlign: TextAlign.center,
),
);
}
}
answer.dart
Code:
import 'package:flutter/material.dart';
class Answer extends StatelessWidget {
final Function selectHandler;
final String answerText;
Answer(this.selectHandler, this.answerText);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
margin: EdgeInsets.fromLTRB(20, 10, 20, 10),
child: RaisedButton(
child: Text(answerText),
color: Colors.blue,
textColor: Colors.white,
onPressed: selectHandler,
),
);
}
}
quiz.dart
Code:
import 'package:flutter/material.dart';
import './answer.dart';
import './question.dart';
class Quiz extends StatelessWidget {
final List<Map<String, Object>> questions;
final int questionIndex;
final Function answerQuestion;
Quiz({
@required this.answerQuestion,
@required this.questions,
@required this.questionIndex,
});
@override
Widget build(BuildContext context) {
return Column(
children: [
Question(
questions[questionIndex]['questionText'],
),
...(questions[questionIndex]['answers'] as List<Map<String, Object>>)
.map((answer) {
return Answer(() => answerQuestion(answer['Score']), answer['text']);
}).toList()
],
);
}
}
result.dart
Code:
import 'package:flutter/material.dart';
class Result extends StatelessWidget {
final int resulScore;
final Function restarthandler;
Result(this.resulScore, this.restarthandler);
String get resultPhrase {
String resultText;
if (resulScore <= 8) {
resultText = 'You are awesome and innocent!.';
} else if (resulScore <= 12) {
resultText = 'Pretty likable!.';
} else if (resulScore <= 12) {
resultText = 'You are .. strange!.';
} else {
resultText = 'You are so bad!';
}
return resultText;
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
children: [
Text(
resultPhrase,
style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
FlatButton(
child: Text('Restart again', style: TextStyle(fontSize: 22)),
textColor: Colors.blue,
onPressed: restarthandler,
),
],
),
);
}
}
Result
Tricks and Tips
Make sure that downloaded plugin is added in specified directory.
Makes sure that agconnect-services.json file added.
Make sure dependencies are added yaml file.
Run flutter pug get after adding dependencies.
Generating SHA-256 certificate fingerprint in android studio and configure in Ag-connect.
Enable debug mode using following command
Code:
adb shell setprop debug.huawei.hms.analytics.app package_name
Conclusion
In this article, we have learnt how to integrate Huawei Analytics Kit into Flutter QuizApp, which lets you to app analytics like users, predefined events and Custom events in the Ag-connect.
Thank you so much for reading, I hope this article helps you to understand the Huawei Analytics Kit in flutter.
Reference
Official plugin guide for flutter :
Document
developer.huawei.com
Flutter plugin :
Document
developer.huawei.com
HMS Core :
Document
developer.huawei.com
Read In Forum
Does it supports real time analytics?
{
"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 be integrating Huawei Remote Configuration Service in Flutter QuizApp. Here we will fetch the remote data which is questions and answers JSON data from Ag-console. Huawei provides Remote Configuration service to manage parameters online, with this service you can control or change the behaviour and appearance of you app online without requiring user’s interaction or update to app. By implementing the SDK you can fetch the online parameter values delivered on the AG-console to change the app behaviour and appearance.
Functional features
1. Parameter management: This function enables user to add new parameter, delete, update existing parameter and setting conditional values.
2. Condition management: This function enables user to adding, deleting and modifying conditions, and copy and modify existing conditions. Currently, you can set the following conditions version, country/region, audience, user attribute, user percentage, time and language. You can expect more conditions in the future.
3. Version management: This feature function supports user to manage and rollback up to 90 days of 300 historical versions for parameters and conditions.
4. Permission management: This feature function allows account holder, app administrator, R&D personnel, and administrator and operations personals to access Remote Configuration by default.
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.
A Huawei 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.
Java:
apply plugin: 'com.android.application'
apply plugin: 'com.huawei.agconnect'
Add root level gradle dependencies
Java:
maven {url 'https://developer.huawei.com/repo/'}
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
Add app level gradle dependencies
Java:
implementation 'com.huawei.agconnect:agconnect-remoteconfig:1.4.2.301'
Step 3: Add the below permissions in Android Manifest file.
XML:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Step 4: Add below path in pubspec.yaml file under dependencies.
Step 5 : Create a project in AppGallery Connect
Preparations for Integrating HUAWEI HMS Core(Android)
developer.huawei.com
pubspec.yaml
YAML:
name: flutter_app
description: A new Flutter application.
# The following line prevents the package from being accidentally published to
# pub.dev using `pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
huawei_account:
path: ../huawei_account/
huawei_analytics:
path: ../huawei_analytics/
huawei_location:
path: ../huawei_location/
huawei_ads:
path: ../huawei_ads/
huawei_push:
path: ../huawei_push
huawei_map:
path: ../huawei_map
huawei_scan:
path: ../huawei_scan
agconnect_crash: ^1.0.0
http: ^0.12.2
fluttertoast: ^7.1.6
agconnect_remote_config: ^1.0.0
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
dev_dependencies:
flutter_test:
sdk: flutter
main.dart
Code:
[CODE=java]import 'dart:convert';
import 'dart:developer';
import 'package:agconnect_remote_config/agconnect_remote_config.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/login.dart';
import 'package:flutter_app/menuscreen.dart';
import 'package:flutter_app/myquestion.dart';
import 'package:flutter_app/result.dart';
import 'package:huawei_account/hmsauthservice/hms_auth_service.dart';
import 'package:huawei_ads/adslite/ad_param.dart';
import 'package:huawei_ads/adslite/banner/banner_ad.dart';
import 'package:huawei_ads/adslite/banner/banner_ad_size.dart';
import 'package:huawei_ads/hms_ads.dart';
import 'package:huawei_analytics/huawei_analytics.dart';
import './quiz.dart';
import './result.dart';
void main() {
runApp(
MaterialApp(
title: 'TechQuizApp',
// Start the app with the "/" named route. In this case, the app starts
// on the FirstScreen widget.
initialRoute: '/',
routes: {
// When navigating to the "/" route, build the FirstScreen widget.
'/': (context) => MenuScreen(),
// When navigating to the "/second" route, build the SecondScreen widget.
'/second': (context) => MyApp('', null),
},
),
);
}
class MyApp extends StatefulWidget {
final String userName;
List<MyQuestion> _questions;
MyApp(this.userName, this._questions);
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _MyAppState(_questions);
}
}
class _MyAppState extends State<MyApp> {
var _questionIndex = 0;
int _totalScore = 0;
String name;
List<MyQuestion> _questions;
final HMSAnalytics _hmsAnalytics = new HMSAnalytics();
_MyAppState(this._questions);
@override
void initState() {
_enableLog();
_predefinedEvent();
super.initState();
}
Future<void> _enableLog() async {
_hmsAnalytics.setUserId(widget.userName);
await _hmsAnalytics.enableLog();
}
void _restartQuiz() {
setState(() {
_questionIndex = 0;
_totalScore = 0;
});
}
void _logoutQuiz() async {
final signOutResult = await HmsAuthService.signOut();
if (signOutResult) {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => LoginDemo()));
print('You are logged out');
} else {
print('signOut failed');
}
}
//Predefined
void _predefinedEvent() async {
String name = HAEventType.SIGNIN;
dynamic value = {HAParamType.ENTRY: 06534797};
await _hmsAnalytics.onEvent(name, value);
print("Event posted");
}
void _customEvent(int index, int score) async {
String name = "Question$index";
dynamic value = {'Score': score};
await _hmsAnalytics.onEvent(name, value);
print("_customEvent posted");
}
Future<void> _answerQuestion(int score) async {
_totalScore += score;
if (_questionIndex < _questions.length) {
print('Iside if $_questionIndex');
setState(() {
_questionIndex = _questionIndex + 1;
});
print('Current questionIndex $_questionIndex');
} else {
print('Inside else $_questionIndex');
}
_customEvent(_questionIndex, score);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Wel come ' + widget.userName),
),
body: callme2()));
}
}
myqueston.dart
Code:
class MyQuestion {
String questionText;
List<Answers> answers;
MyQuestion({this.questionText, this.answers});
MyQuestion.fromJson(Map<String, dynamic> json) {
questionText = json['questionText'];
if (json['answers'] != null) {
answers = new List<Answers>();
json['answers'].forEach((v) {
answers.add(new Answers.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['questionText'] = this.questionText;
if (this.answers != null) {
data['answers'] = this.answers.map((v) => v.toJson()).toList();
}
return data;
}
}
class Answers {
String text;
int score;
Answers({this.text, this.score});
Answers.fromJson(Map<String, dynamic> json) {
text = json['text'];
score = json['Score'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['text'] = this.text;
data['Score'] = this.score;
return data;
}
}
login.dart
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'package:agconnect_remote_config/agconnect_remote_config.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/main.dart';
import 'package:flutter_app/myquestion.dart';
import 'package:huawei_account/helpers/hms_auth_param_helper.dart';
import 'package:huawei_account/helpers/hms_scope.dart';
import 'package:huawei_account/hmsauthservice/hms_auth_service.dart';
import 'package:huawei_account/model/hms_auth_huawei_id.dart';
class LoginDemo extends StatefulWidget {
@override
_LoginDemoState createState() => _LoginDemoState();
}
class _LoginDemoState extends State<LoginDemo> {
TextEditingController emailController = new TextEditingController();
TextEditingController passwordController = new TextEditingController();
String email, password, user;
List<MyQuestion> _questions;
@override
void initState() {
// TODO: implement initState
fetchAndActivateImmediately();
super.initState();
}
@override
void dispose() {
// Clean up the controller when the widget is disposed.
emailController.dispose();
passwordController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Account Login'),
),
body: Center(
child: InkWell(
onTap: signInWithHuaweiAccount,
child: Ink.image(
image: AssetImage('assets/images/icon.jpg'),
// fit: BoxFit.cover,
width: 110,
height: 110,
),
),
)),
);
}
void signInWithHuaweiAccount() async {
HmsAuthParamHelper authParamHelper = new HmsAuthParamHelper();
authParamHelper
..setIdToken()
..setAuthorizationCode()
..setAccessToken()
..setProfile()
..setEmail()
..setScopeList([HmsScope.openId, HmsScope.email, HmsScope.profile])
..setRequestCode(8888);
try {
final HmsAuthHuaweiId accountInfo =
await HmsAuthService.signIn(authParamHelper: authParamHelper);
print('accountInfo ==>' + accountInfo.email);
setState(() {
String accountDetails = accountInfo.displayName;
print("account name: " + accountInfo.displayName);
print("accountDetails: " + accountDetails);
user = accountInfo.displayName;
if (_questions != null) {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => MyApp(user, _questions)));
}
});
} on Exception catch (exception) {
print(exception.toString());
print("error: " + exception.toString());
}
}
Future signOut() async {
final signOutResult = await HmsAuthService.signOut();
if (signOutResult) {
//Route route = MaterialPageRoute(builder: (context) => SignInPage());
// Navigator.pushReplacement(context, route);
print('You are logged out');
} else {
print('Login_provider:signOut failed');
}
}
fetchAndActivateImmediately() async {
await AGCRemoteConfig.instance.fetch().catchError((error) => log(error()));
await AGCRemoteConfig.instance.applyLastFetched();
Map value = await AGCRemoteConfig.instance.getMergedAll();
for (String key in value.keys) {
if (key == 'questions') {
var st = value[key].toString().replaceAll('\\', '');
var myquestionJson = jsonDecode(st) as List;
_questions =
myquestionJson.map((val) => MyQuestion.fromJson(val)).toList();
}
}
print('=================*********************======================');
print(jsonEncode(_questions));
}
}[/CODE]
quiz.dart
Code:
import 'package:flutter/material.dart';
import 'package:flutter_app/myquestion.dart';
import './answer.dart';
import './question.dart';
class Quiz extends StatelessWidget {
final List<MyQuestion> questions;
final int questionIndex;
final Function answerQuestion;
Quiz({
@required this.answerQuestion,
@required this.questions,
@required this.questionIndex,
});
@override
Widget build(BuildContext context) {
return Column(
children: [
Question(
questions[questionIndex].questionText,
),
...(questions[questionIndex].answers).map<Widget>((answer) {
return Answer(() => answerQuestion(answer.score), answer.text);
}).toList()
],
);
}
}
menuscreen.dart
Code:
import 'dart:convert';
import 'dart:developer';
import 'package:agconnect_crash/agconnect_crash.dart';
import 'package:agconnect_remote_config/agconnect_remote_config.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/AdsDemo.dart';
import 'package:flutter_app/CrashService.dart';
import 'package:flutter_app/locationdata.dart';
import 'package:flutter_app/login.dart';
import 'package:flutter_app/pushdata.dart';
import 'package:flutter_app/remotedata.dart';
class MenuScreen extends StatefulWidget {
@override
_MenuScreenState createState() => _MenuScreenState();
}
class _MenuScreenState extends State<MenuScreen> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Menu'),
),
body: Center(
child: Column(
children: [
SizedBox(
width: 320,
child: RaisedButton(
color: Colors.red, // background
textColor: Colors.white, // foreground
child: Text('Enter Quiz'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => LoginDemo()));
},
),
)
],
),
),
),
);
}
}
Result
Tricks and Tips
Makes sure that agconnect-services.json file added.
Make sure dependencies are added build file.
Run flutter pug get after adding dependencies.
Generating SHA-256 certificate fingerprint in android studio and configure in Ag-connect.
Conclusion
In this article, we have learnt how to integrate Huawei Remote Configuration Service in Flutter QuizApp, Where json data of questions and answers are fetched from remote configurations i.e. Ag-console. Likewise you can configure other parameters like app theme, language, style and country etc. to change the app behaviour and appearance.
Thank you so much for reading, I hope this article helps you to understand the Huawei Remote Configuration Service in flutter.
Reference
Remote configuration service :
Document | Huawei Developers
developer.huawei.com
Original Source
Hi, Using Remote configuration can handle UI related functionality like visible/hide
{
"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 make use of 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
[/B][/B][/B]
maven {url 'https://developer.huawei.com/repo/'}
classpath 'com.huawei.agconnect:agcp:1.5.2.300'
[B][B][B]
Step 3: Add the below permissions in Android Manifest file.
<uses-permission android:name="android.permission.INTERNET" />
Step 5: Add downloaded file into parent directory of the project. Declare plugin path in pubspec.yaml file under dependencies.
Add path location for asset image.
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]
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 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. In part-2 we will learn the actual Cloud Functions as Chatbot service.
Thank you so much for reading. I hope this article helps you to understand the integration of Huawei Account kit and Analytics kit in flutter ChatBotApp.
Reference
Cloud Functions
Checkout in forum