[Huawei Developers] shikkerimath:
View attachment 5540155

Introduction

In this article, we will be integrating Huawei Account, Analytics and Ads kit in StoryApp. Flutter plugin provides simple and convenient way to experience authorization of users. Flutter Account Plugin allows users to connect to the Huawei ecosystem using their Huawei IDs from the different devices such as mobiles phones and tablets, added users can login quickly and conveniently sign in to apps with their Huawei IDs after granting initial access permission.

Huawei Ads kit provides access to range of development capabilities. You can promote your apps quickly and more efficiently to Huawei’s vast users. Ads kit helps your app to be monetize quickly and start generating revenue.

Huawei supports following Ads types

Banner

Interstitial

Native

Reward

Splash

Instream(Roll)

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.

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.

View attachment 5540157

View attachment 5540159

Step 2: Add the App level gradle dependencies. Choose inside project Android > app > build.gradle.

apply plugin: 'com.android.application'

apply plugin: 'com.huawei.agconnect'

Root level gradle dependencies

maven {url 'https://developer.huawei.com/repo/'}

classpath 'com.huawei.agconnect:agcp:1.4.1.300'

Step 3: Add the below permissions in Android Manifest file.

<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: Download flutter plugins

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.

View attachment 5540165

View attachment 5540167

Let's start coding

loginScreen.dart

class LoginScreen extends StatelessWidget {

const LoginScreen({Key? key}) : super(key: key);

@override

Widget build(BuildContext context) {

return MaterialApp(

debugShowCheckedModeBanner: false,

home: LoginDemo(),

);

}

}

class LoginDemo extends StatefulWidget {

@override

_LoginDemoState createState() => _LoginDemoState();

}

class _LoginDemoState extends State<LoginDemo> {

final HMSAnalytics _hmsAnalytics = new HMSAnalytics();

@override

void initState() {

// TODO: implement initState

HwAds.init();

_enableLog();

_predefinedEvent();

showBannerAd();

super.initState();

}

Future<void> _enableLog() async {

_hmsAnalytics.setUserId("TestUserStoryApp");

await _hmsAnalytics.enableLog();

}

void _predefinedEvent() async {

String name = HAEventType.SIGNIN;

dynamic value = {HAParamType.ENTRY: 06534797};

await _hmsAnalytics.onEvent(name, value);

print("Event posted");

}

@override

Widget build(BuildContext context) {

return Scaffold(

backgroundColor: Colors.white,

appBar: AppBar(

title: Text("Login Page"),

backgroundColor: Colors.grey[850],

),

body: RefreshIndicator(

onRefresh: showToast,

child: SingleChildScrollView(

child: Column(

children: <Widget>[

Padding(

padding: const EdgeInsets.only(top: 60.0),

child: Center(

child: Container(

width: 200,

height: 150,

decoration: BoxDecoration(

color: Colors.red,

borderRadius: BorderRadius.circular(60.0)),

child: Image.asset('images/logo_huawei.png')),

),

),

Padding(

padding: EdgeInsets.symmetric(horizontal: 15),

child: TextField(

decoration: InputDecoration(

border: OutlineInputBorder(),

labelText: 'Email',

hintText: 'Enter valid email id '),

),

),

Padding(

padding: const EdgeInsets.only(

left: 15.0, right: 15.0, top: 15, bottom: 0),

child: TextField(

obscureText: true,

decoration: InputDecoration(

border: OutlineInputBorder(),

labelText: 'Password',

hintText: 'Enter password'),

),

),

FlatButton(

onPressed: () {

//TODO FORGOT PASSWORD SCREEN GOES HERE

},

child: Text(

'Forgot Password',

style: TextStyle(color: Colors.blue, fontSize: 15),

),

),

Container(

height: 50,

width: 270,

decoration: BoxDecoration(

color: Colors.red, borderRadius: BorderRadius.circular(20)),

child: FlatButton(

onPressed: () async {

try {

try {

final bool result = await AccountAuthService.signOut();

if (result) {

final bool response =

await AccountAuthService.cancelAuthorization();

}

} on Exception catch (e) {

print(e.toString());

}

} on Exception catch (e) {

print(e.toString());

}

},

child: GestureDetector(

onTap: () async {

try {

final bool response =

await AccountAuthService.cancelAuthorization();

} on Exception catch (e) {

print(e.toString());

}

},

child: Text(

'Login',

style: TextStyle(color: Colors.white, fontSize: 25),

),

),

),

),

SizedBox(

height: 5,

),

Container(

height: 50,

width: 270,

decoration: BoxDecoration(

color: Colors.red, borderRadius: BorderRadius.circular(20)),

child: HuaweiIdAuthButton(

theme: AuthButtonTheme.FULL_TITLE,

buttonColor: AuthButtonBackground.RED,

borderRadius: AuthButtonRadius.MEDIUM,

onPressed: () {

signInWithHuaweiAccount();

}),

),

SizedBox(

height: 30,

),

GestureDetector(

onTap: () {

showBannerAd();

},

child: Text('New User? Create Account'),

),

],

),

),

),

);

}

void showBannerAd() {

BannerAd _bannerAd;

_bannerAd = createBannerAd();

_bannerAd

..loadAd()

..show(gravity: Gravity.bottom, offset: 5);

}

//Create BannerAd

static BannerAd createBannerAd() {

BannerAd banner = BannerAd(

adSlotId: "testw6vs28auh3",

size: BannerAdSize.sSmart,

adParam: AdParam());

banner.setAdListener = (AdEvent event, {int? errorCode}) {

print("Banner Ad event : $event");

};

return banner;

}

void signInWithHuaweiAccount() async {

AccountAuthParamsHelper helper = new AccountAuthParamsHelper();

helper.setAuthorizationCode();

try {

// The sign-in is successful, and the user's ID information and authorization code are obtained.

Future<AuthAccount> account = AccountAuthService.signIn(helper);

account.then((value) => Fluttertoast.showToast(

msg: "Welcome " + value.displayName.toString(),

toastLength: Toast.LENGTH_SHORT,

gravity: ToastGravity.CENTER,

timeInSecForIosWeb: 1,

backgroundColor: Colors.red,

textColor: Colors.white,

fontSize: 16.0));

Navigator.push(context, MaterialPageRoute(builder: (_) => Main1()));

} on Exception catch (e) {

print(e.toString());

}

}

Future<void> showToast() async {

Fluttertoast.showToast(

msg: "Refreshing.. ",

toastLength: Toast.LENGTH_SHORT,

gravity: ToastGravity.CENTER,

timeInSecForIosWeb: 1,

backgroundColor: Colors.lightBlue,

textColor: Colors.white,

fontSize: 16.0);

}

BannerAd createAd() {

return BannerAd(

adSlotId: "testw6vs28auh3",

size: BannerAdSize.s468x60,

adParam: AdParam(),

);

}

}

Main.dart

class Main extends StatefulWidget {

@override

_Main1State createState() => _Main1State();

}

var cardAspectRation = 12.0 / 20.0;

var widgetAspectRatio = cardAspectRation * 1.2;

var verticalInset = 20.0;

class _Main1State extends State<Main1> {

var currentPage = images.length - 1.0;

bool isMenuClosed = true;

late double screenWidth;

final HMSAnalytics _hmsAnalytics = new HMSAnalytics();

@override

void dispose() {

// SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);

super.dispose();

}

@override

initState() {

// SystemChrome.setEnabledSystemUIOverlays([]);

super.initState();

_enableLog();

}

Future<void> _enableLog() async {

_hmsAnalytics.setUserId("TestUserStoryApp");

await _hmsAnalytics.enableLog();

}

@override

Widget build(BuildContext context) {

// The initial todos

PageController controller = PageController(initialPage: images.length - 1);

controller.addListener(() {

setState(() {

currentPage = controller.page!;

});

});

Size size = MediaQuery.of(context).size;

screenWidth = size.width;

return Scaffold(

backgroundColor: Colors.grey[850],

body: Stack(

children: <Widget>[

menu(context),

dashboard(context),

],

),

);

}

Widget menu(context) {

return Padding(

padding: EdgeInsets.fromLTRB(0, 0, screenWidth * 0.15, 0),

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

crossAxisAlignment: CrossAxisAlignment.start,

children: <Widget>[

Flexible(

flex: 4,

child: Container(

color: Colors.grey[850],

child: Align(

alignment: Alignment.center,

child: circularImage(),

),

),

),

Flexible(

flex: 6,

child: Container(

child: Row(

children: <Widget>[

Flexible(

child: Column(

children: <Widget>[

Flexible(

child: GestureDetector(

onTap: () {

print("Clicked on Ads");

Navigator.push(

context,

MaterialPageRoute(

builder: (_) => SecondScreen()));

},

child: Container(

decoration: new BoxDecoration(

color: Color.fromRGBO(218, 107, 107, 1),

borderRadius: new BorderRadius.only(

topLeft: const Radius.circular(80.0))),

child: Align(

alignment: Alignment.center,

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: <Widget>[

Icon(

Icons.headset,

color: Colors.white,

size: 50,

),

Text('Ads',

style: TextStyle(

color: Colors.white, fontSize: 22))

],

),

),

),

),

),

Flexible(

child: GestureDetector(

onTap: () {

print("Clicked on browse");

},

child: Container(

color: Color.fromRGBO(211, 96, 96, 1),

child: Align(

alignment: Alignment.center,

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: <Widget>[

Icon(

Icons.satellite,

color: Colors.white,

size: 50,

),

Text('Browse',

style: TextStyle(

color: Colors.white, fontSize: 22))

],

),

),

),

),

)

],

),

),

Flexible(

child: Column(

children: <Widget>[

Flexible(

child: GestureDetector(

onTap: () {

print("Clicked on Analytics");

sendCustomEvent();

},

child: Container(

decoration: new BoxDecoration(

color: Color.fromRGBO(211, 96, 96, 1),

borderRadius: new BorderRadius.only(

topRight: const Radius.circular(80.0))),

child: Align(

alignment: Alignment.center,

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: <Widget>[

Icon(

Icons.assignment,

color: Colors.white,

size: 50,

),

Text('Analytics',

style: TextStyle(

color: Colors.white, fontSize: 22))

],

),

),

),

),

),

Flexible(

child: GestureDetector(

onTap: () {

print("Clicked on settings");

},

child: Container(

color: Color.fromRGBO(218, 107, 107, 1),

child: Align(

alignment: Alignment.center,

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: <Widget>[

Icon(

Icons.settings,

color: Colors.white,

size: 50,

),

Text('Settings',

style: TextStyle(

color: Colors.white, fontSize: 22))

],

),

),

),

),

)

],

),

)

],

),

),

)

],

),

);

}

Widget dashboard(context) {

return AnimatedPositioned(

//top: isMenuClosed? 0 : 100,

//bottom: isMenuClosed? 0 : 100,

top: 0,

bottom: 0,

left: isMenuClosed ? 0 : screenWidth - screenWidth * 0.15,

right: isMenuClosed ? 0 : -90,

duration: Duration(milliseconds: 300),

child: Material(

elevation: 8,

color: Colors.grey[850],

child: Padding(

padding: EdgeInsets.fromLTRB(10, 30, 10, 10),

child: Column(

children: <Widget>[

Row(

mainAxisAlignment: MainAxisAlignment.spaceBetween,

children: <Widget>[

InkWell(

child: Icon(

Icons.segment,

color: Colors.white,

size: 40,

),

onTap: () {

setState(() {

isMenuClosed = !isMenuClosed;

});

},

),

Icon(

Icons.search_outlined,

color: Colors.white,

size: 40,

),

],

),

Text("Trending",

style: TextStyle(fontSize: 28, color: Colors.white)),

CardScrollWidget(currentPage),

],

),

),

),

);

}

Widget circularImage() {

return Container(

width: 200.0,

height: 200.0,

decoration: new BoxDecoration(

shape: BoxShape.circle,

border: Border.all(

color: Colors.teal, width: 10.0, style: BorderStyle.solid),

image: new DecorationImage(

fit: BoxFit.cover, image: AssetImage("images/logo_huawei.png"))),

);

}

void sendCustomEvent() async {

String value = "This is custom event from app";

dynamic eventData = {'Message': value};

await _hmsAnalytics.onEvent("CustomEvent", eventData);

print("Event posted");

}

}

class CardScrollWidget extends StatelessWidget {

var currentPage;

var padding = 20.0;

CardScrollWidget(this.currentPage);

@override

Widget build(BuildContext context) {

return AspectRatio(

aspectRatio: widgetAspectRatio,

child: LayoutBuilder(

builder: (context, constraints) {

var width = constraints.maxWidth;

var height = constraints.maxHeight;

var safeWidth = width - 2 * padding;

var safeHeight = height - 2 * padding;

var heightOfPrimaryCard = safeHeight;

var widthOfPrimaryCard = heightOfPrimaryCard * cardAspectRation;

var primaryCardLeft = safeWidth - widthOfPrimaryCard;

var horizontalInset = primaryCardLeft / 2;

List<Widget> cardList = [];

for (var i = 0; i < images.length; i++) {

var delta = i - currentPage;

bool isOnRight = delta > 0;

var start = padding +

max(

primaryCardLeft -

horizontalInset * -delta * (isOnRight ? 15 : 1),

0.0);

var cardItem = Positioned.directional(

top: padding + verticalInset * max(-delta, 0.0),

bottom: padding + verticalInset * max(-delta, 0.0),

start: start,

textDirection: TextDirection.rtl,

child: ClipRRect(

borderRadius: BorderRadius.circular(16.0),

child: Container(

decoration: BoxDecoration(color: Colors.white, boxShadow: [

BoxShadow(

color: Colors.black12,

offset: Offset(3.0, 6.0),

blurRadius: 10.0)

]),

child: AspectRatio(

aspectRatio: cardAspectRation,

child: Stack(

fit: StackFit.expand,

children: <Widget>[

Image.asset(images[i], fit: BoxFit.cover),

Align(

alignment: Alignment.bottomLeft,

child: Column(

mainAxisSize: MainAxisSize.min,

crossAxisAlignment: CrossAxisAlignment.start,

children: <Widget>[

Container(

decoration: BoxDecoration(

color: Colors.black45,

borderRadius: BorderRadius.circular(20.0)),

child: Padding(

padding: EdgeInsets.symmetric(

horizontal: 16.0, vertical: 8.0),

child: Text(title[i],

style: TextStyle(

color: Colors.white,

fontSize: 25.0,

fontFamily: "SF-Pro-Text-Regular")),

),

),

SizedBox(

height: 10.0,

),

Padding(

padding: const EdgeInsets.only(

left: 12.0, bottom: 12.0),

child: Container(

padding: EdgeInsets.symmetric(

horizontal: 22.0, vertical: 6.0),

decoration: BoxDecoration(

color: Colors.blueAccent,

borderRadius:

BorderRadius.circular(20.0)),

child: GestureDetector(

onTap: () {

print("FFFFFF");

},

child: Text(

"Read more..",

style: TextStyle(color: Colors.white),

),

),

),

)

],

),

)

],

),

),

),

),

);

cardList.add(cardItem);

}

return Stack(

children: cardList,

);

},

),

);

}

}

Result

View attachment 5540177

View attachment 5540179

View attachment 5540181

View attachment 5540183

View attachment 5540185

Tricks and Tips

Make sure that downloaded plugin is unzipped in parent directory of project.

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 Account kit, Analytics and Ads kit into Huawei StoryApp for flutter. Once Account kit integrated, users can login quickly and conveniently sign in to apps with their Huawei IDs after granting initial access permission. Analytics helps you to analyse the user behaviour and Ads kit helps you to monetize the app.

Thank you so much for reading, I hope thiis article helps you to understand the integration of Huawei Account kit, Ads kit and Analytics kit in flutter.

Reference

Ads Kit

Analytics Kit

Ads Kit – Training Video

Analytics Kit – Training Video

Checkout in forum