About this codelab
The faster your user signs in to your app, the faster they adopt it. There's no quicker and safer way to do this than with their HUAWEI IDs based on two-factor authentication. Access the Huawei ecosystem of users with seamless sign-ins from different devices and grow your user base.
What You Will Create
In this codelab, you will use the demo project that has been created for you to experience Account Kit APIs. Through the demo project, you will experience developing a sign in form feature with;
- Login with Huawei ID
- Complex desing implements real life examples of sign in form and registry form with email and Huawei ID login using Shared Preferences as an extra
- Simple desing implements Huawei ID login with fully implemented log background on visual Flutter screen layout.
What You Will Learn
In this codelab, you will learn how to:
- How to integrate Huawei ID on Flutter projects
- How to implement Sign-in and Register forms using Huawei ID and email
Hardware Requirements
- One PC with Android Studio installed
- One mobile phone with a USB data cable for running developed apps
Software Requirements
- Android Studio 3.x or later version(Download)
- Java JDK 1.8 or later version(Download)
- Setup a Flutter Environment(Download)
- EMUI 3.0 or later
- HMS Core (APK) 5.0.0.300 or later
Required Knowledge
- Android development basics
- Basic Dart knowledge
Before you get started, complete the following preparations:
- Create an app in AppGallery Connect.
- Create an Android Studio project.
- Generate a signing certificate.
- Generate a signing certificate fingerprint.
- Configure the signing certificate fingerprint.
- Add the app package name and save the configuration file.
- Configure the Maven repository address and AppGallery Connect gradle plug-in.
- Configure the signature file in Android Studio.
For details, please refer to Preparations for Integrating HUAWEI HMS.
You can download the codelab project from: https://github.com/Onurcan-Keskin/onurcan-keskin.github.io/tree/master
Creating a Project
Step 1: Start Android Studio.
Step 2: Choose File > Open, go to the directory where the sample project is decompressed, and click OK.
Step 3: Configure the AppGallery Connect plug-in, Maven repository address, build dependencies, obfuscation scripts, and permissions. (These items have been configured in the sample code. If any of them does not meet your requirements, change it in your own project.)
1. Configure the Maven repository address and AppGallery Connect plug-in in the project's build.gradle file.
- Go to allprojects > repositories and configure the Maven repository address for the HMS Core SDK.
allprojects { repositories { maven { url 'https://developer.huawei.com/repo/' } ... } } - Go to buildscript > repositories and configure the Maven repository address for the HMS Core SDK.
buildscript { repositories { maven {url 'https://developer.huawei.com/repo/'} ... } ... } - Go to buildscript > dependencies and add build dependencies.
buildscript { dependencies { //Replace {agconnect_version} with the actual AGC plugin version number. //Example: classpath 'com.huawei.agconnect:agcp: 1.4.1.300' classpath 'com.huawei.agconnect:agcp:{agconnect_version}' } }
2. Configure the dependency package in the app's pubsec.yaml file.
- Add a dependency package to the dependencies section in the build.gradle file.
dependencies : ... //Account Kit huawei_account: ^5.0.3+303 ...For Video Kit, please refer to latest version.
- Add the following information under apply plugin: 'com.android.application' in the file header:
apply plugin: 'com.huawei.agconnect'
3. Configure obfuscation scripts.
- Configure the following information in the app/proguard-rules.pro file:
-ignorewarnings -keepattributes *Annotation* -keepattributes Exceptions -keepattributes InnerClasses -keepattributes Signature -keepattributes SourceFile,LineNumberTable -keep class com.hianalytics.android.**{*;} -keep class com.huawei.updatesdk.**{*;} -keep class com.huawei.hms.**{*;} - If you are using AndResGuard, add it to the allowlist in the obfuscation script file.
"R.string.hms*", "R.string.connect_server_fail_prompt_toast", "R.string.getting_message_fail_prompt_toast", "R.string.no_available_network_prompt_toast", "R.string.third_app_*", "R.string.upsdk_*", "R.layout.hms*", "R.layout.upsdk_*", "R.drawable.upsdk*", "R.color.upsdk*", "R.dimen.upsdk*", "R.style.upsdk*", "R.string.agc*"
4. Configure permissions in the AndroidManifest.xml file.
<uses-permission android:name="android.permission.INTERNET"/>
Step 4: In the Android Studio window, choose File > Sync Project with Gradle Files to synchronize the project.
1. Create Auth Buttons to guide user thorugh Login processes.
import 'package:flutter/material.dart';
Widget authButton(String text, Function function) {
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(vertical: 1, horizontal: 15),
child: RaisedButton(
color: Colors.blue,
textColor: Colors.white,
highlightColor: Colors.amber,
splashColor: Colors.amber,
elevation: 0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(7)),
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 25),
child: Text(text.toUpperCase()),
onPressed: function,
),
);
}
2. Create Rich Buttons with images to guide users to which build they might choose.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
Widget authRichButton(String textBold, String textStandart, Function function) {
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(vertical: 1, horizontal: 15),
child: RaisedButton(
color: Colors.blue,
textColor: Colors.white,
highlightColor: Colors.amber,
splashColor: Colors.amber,
elevation: 0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(7)),
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 25),
child: RichText(
text: TextSpan(
children: [
TextSpan(text: textBold, style: TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: textStandart),
]
)),
onPressed: function,
),
);
}
3. Create the Sign in as async fuction
_signIn() async {
// BUILD DESIRED PARAMS
AuthParamHelper authParamHelper = new AuthParamHelper();
authParamHelper
..setIdToken()
..setAuthorizationCode()
..setAccessToken()
..setProfile()
..setEmail()
..setId()
..addToScopeList([Scope.openId])..setRequestCode(8888);
// GET ACCOUNT INFO FROM PLUGIN
try {
final AuthHuaweiId accountInfo = await HmsAccount.signIn(authParamHelper);
setState(() {
logs.add(accountInfo.displayName);
});
} on Exception catch(exception) {
print(exception.toString());
}
/// TO VERIFY ID TOKEN, AuthParamHelper()..setIdToken()
//performServerVerification(accountInfo.idToken);
}
4. Create the Sign out as async function
_signOut() async {
final signOutResult = await HmsAccount.signOut();
if (signOutResult) {
setState(() {
logs.add("Sign out success");
});
} else {
setState(() {
logs.add("Sign out failed");
});
}
}
5. Set Silent Sign in as async function
_silentSignIn() async {
AuthParamHelper authParamHelper = new AuthParamHelper();
try {
final AuthHuaweiId accountInfo = await HmsAccount.silentSignIn(authParamHelper);
setState(() {
logs.add(accountInfo.displayName);
});
} on Exception catch(exception) {
print(exception.toString());
}
}
6. Set Revoke Authorization as async function.
_revokeAuthorization() async {
final bool revokeResult = await HmsAccount.revokeAuthorization();
if (revokeResult) {
setState(() {
logs.add("Revoked Auth Successfuly");
});
} else {
setState(() {
logs.add("Failed to Revoked Auth");
});
}
}
7. Set Authorization sign in codes async funtion
_signInWithAuthorizationCode() async {
AuthParamHelper authParamHelper = new AuthParamHelper();
authParamHelper..setAuthorizationCode()..setRequestCode(1002);
try {
final AuthHuaweiId accountInfo = await HmsAccount.signInWithAuthorizationCode(authParamHelper);
setState(() {
logs.add(accountInfo.authorizationCode);
});
} on Exception catch(exception) {
print(exception.toString());
}
}
8. Set SMS Verifaction as async function.
_smsVerification() async{
HmsAccount.smsVerification(({errorCode, message}){
if (message != null) {
setState(() {
logs.add(message);
});
print("Received message: $message");
} else {
print("Error: $errorCode");
}
});
}
9. For this screen we recommed you to use StatelWidgets.
class AuthScreen extends StatefulWidget {
@override
_AuthScreenState createState() => _AuthScreenState();
}
10. We will conduct our interactions inside our Auth Screen State.
class _AuthScreenState extends State {
final GlobalKey _scaffoldKey = new GlobalKey();
List logs = [];
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text('Sign In With Huawei ID'),
),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.white10, Colors.black87],
begin: Alignment.topCenter,
end: Alignment.bottomCenter
)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
textBaseline: TextBaseline.ideographic,
children: [
HuaweiIdAuthButton(onPressed: _signIn, buttonColor: AuthButtonBackground.RED),
authButton("SIGN IN WITH AUTHORIZATION CODE", _signInWithAuthorizationCode),
authButton("SILENT SIGN IN", _silentSignIn),
authButton("SIGN OUT", _signOut),
authButton("REVOKE AUTHORIZATION", _revokeAuthorization),
authButton("SMS VERIFICATION", _smsVerification),
],
),
Expanded(
child: GestureDetector(
onDoubleTap: () {
setState(() {
logs.clear();
});
},
child: Container(
child: ListView.builder(
itemCount: logs.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(15),
child: Text(logs[index], style: TextStyle(color: Colors.white)),
);
},
),
),
)
),
],
),
));
}

Navigation changing:
Complex Build and Runnable:
UI Building
With the feature MaterialPageRoute we can change our screens if they are all based on Stateful Widgets.
1. Let's create a new async function to navigate our previously built HwID screen.
_navigateHWID() async {
Navigator.push(
context, MaterialPageRoute(builder: (context) => AuthScreen()));
}
2. Let's create another fully formed classical login form named Email.
_navigateEmail() async {
Navigator.push(
context, MaterialPageRoute(builder: (context) => EmailScreen()));
}
3. Under our Welcome Screen State lets call our routes.
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
title: Text('Welcome'),
),
body: Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.white10, Colors.black],
begin: Alignment.topCenter,
end: Alignment.bottomCenter)),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
textBaseline: TextBaseline.ideographic,
children: [
Container(
padding: EdgeInsets.all(5.0),
child: Text(
'Continue to your sign in process with:',
textAlign: TextAlign.justify,
style: TextStyle(fontSize: 17.0, color: Colors.amber),
),
),
authRichButton("Simple Build", " - Huawei ID", _navigateHWID),
authRichButton(
"Complex Build", " - Email + Huawei ID", _navigateEmail),
])
],
),
),
);
}
4. Under our main.dart let us call our Welcome Screen as our main.
class _MyAppState extends State {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Huawei Auth Service',
theme: ThemeData(),
darkTheme:ThemeData.dark(),
home: WelcomeScreen(),
);
}
}
AWithin this complex build we will investigate building the classical complex form of login and registries followed by login with Huaawei ID Authorization Button.
1. Starting with our util let's started building Shared Preferences.
//Under pubsec.yaml
dependencies:
shared_preferences: ^0.5.6
//Under util/shared_prefs.dart
import 'package:shared_preferences/shared_preferences.dart';
class SharedPrefs {
static SharedPreferences _sharedPrefs;
init() async {
if (_sharedPrefs == null) {
_sharedPrefs = await SharedPreferences.getInstance();
}
}
bool getBool(String sharedPrefParam) {
return _sharedPrefs.getBool(sharedPrefParam);
}
void setBool(String sharedPrefParam, bool value) {
_sharedPrefs.setBool(sharedPrefParam, value);
}
int getInt(String sharedPrefParam) {
return _sharedPrefs.getInt(sharedPrefParam);
}
void setInt(String sharedPrefParam, int value) {
_sharedPrefs.setInt(sharedPrefParam, value);
}
String getString(String sharedPrefParam) {
return _sharedPrefs.getString(sharedPrefParam);
}
void setString(String sharedPrefParam, String value) {
_sharedPrefs.setString(sharedPrefParam, value);
}
}
final sharedPrefs = SharedPrefs();
3. Validator for our email fields.
Validator {
static bool isValidEmail(String str) {
return RegExp(
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$')
.hasMatch(str);
}
}
4. Implement the Global UI controllers and states.
bool isLoginPage;
bool isLoading;
final _signInFormKey = GlobalKey();
TextEditingController signInEmail = TextEditingController();
TextEditingController signInPassword = TextEditingController();
final _signUpFormKey = GlobalKey();
TextEditingController signUpName = TextEditingController();
TextEditingController signUpEmail = TextEditingController();
TextEditingController signUpPassword = TextEditingController();
5. Implement the initial state.
@override
void initState() {
super.initState();
isLoading = false;
isLoginPage = true;
}
6. Implement the sign in as async function.
_signIn() async {
// BUILD DESIRED PARAMS
AuthParamHelper authParamHelper = new AuthParamHelper();
authParamHelper
..setIdToken()
..setAuthorizationCode()
..setAccessToken()
..setProfile()
..setEmail()
..setId()
..addToScopeList([Scope.openId])..setRequestCode(8888);
// GET ACCOUNT INFO FROM PLUGIN
try {
final AuthHuaweiId accountInfo = await HmsAccount.signIn(authParamHelper);
setState(() {
});
} on Exception catch(exception) {
print(exception.toString());
}
/// TO VERIFY ID TOKEN, AuthParamHelper()..setIdToken()
//performServerVerification(accountInfo.idToken);
}
7. Implement the handler or request handler.
requestSignUpHandler(response) {
if (response != null && response.statusCode == 200) {
var json = jsonDecode(response.body);
if (json['result'] == true) {
loginProcedure(json['token']);
}
else {
_alreadyTakenEmailError();
}
}
else {
// another error occured
_someErrorHappenedAlert();
}
}
8. Implement the login procedure.
void loginProcedure(token) {
sharedPrefs.setString("token", token);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => WelcomeScreen()));
}
9. Implement the error informer.
Future _someErrorHappenedAlert() async {
setState(() {
isLoading = !isLoading;
});
return showDialog(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Something Went Wrong!', style: TextStyle(
fontSize: 16,
)),
content: SingleChildScrollView(
child: ListBody(
children: [
Text('An error occurred during request.'),
Text('Please check your connection.'),
],
),
),
actionsPadding: EdgeInsets.symmetric(horizontal: 30),
actions: [
FlatButton(
child: Text('OK', style: TextStyle(color: Colors.blue),),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
10. Implement error state if email is already taken.
Future _alreadyTakenEmailError() async {
setState(() {
isLoading = !isLoading;
});
return showDialog(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Email Address is in Use!', style: TextStyle(
fontSize: 16,
)),
content: SingleChildScrollView(
child: ListBody(
children: [
Text('Please enter another email address.'),
],
),
),
actionsPadding: EdgeInsets.symmetric(horizontal: 30),
actions: [
FlatButton(
child: Text(
'Change Address', style: TextStyle(color: Colors.blue),),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
11. Implement the error state that will inform if authetication encounters some error.
Future _authenticationError() async {
setState(() {
isLoading = !isLoading;
});
return showDialog(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Authentication Failed', style: TextStyle(
fontSize: 16,
)),
content: SingleChildScrollView(
child: ListBody(
children: [
Text('Please check your email and password.'),
],
),
),
actionsPadding: EdgeInsets.symmetric(horizontal: 30),
actions: [
FlatButton(
child: Text('OK', style: TextStyle(color: Colors.blue),),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Now that we have completed functionality we'll now build UI for our functions and screens.
1. Let us implement our divider.
// Divider
@override
Widget build(BuildContext context) {
var divider = Container(
margin: EdgeInsets.symmetric(vertical: 6),
child: Row(children: [
Expanded(
child: new Container(
margin: const EdgeInsets.only(left: 10.0,right: 20.0),
child: Divider(
color: Colors.white24,
height: 36,
thickness: 0.7
)),
),
Text("or", style: TextStyle(color: Colors.white24, fontSize: 24),),
Expanded(
child: new Container(
margin: const EdgeInsets.only(left: 20.0,right: 10.0),
child: Divider(
color: Colors.white24,
height: 36,
thickness: 0.7
)),
)
]),
);
//...sign in
//...sign up
}
2. Let us implement our sign up.
@override
Widget build(BuildContext context) {
//...divider
var signInPage = Container(
alignment: Alignment.center,
margin: EdgeInsets.symmetric(horizontal: 30, vertical: 0),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: SingleChildScrollView(
child: AbsorbPointer(
absorbing: isLoading,
child: Form(
key: _signInFormKey,
child: Column(
children: [
SizedBox(height: 50),
Text("Flutter Log In Reference", style: TextStyle(
fontSize: 30,
color: Colors.amber
),),
SizedBox(height: 60),
TextFormField(
textCapitalization: TextCapitalization.words,
textAlignVertical: TextAlignVertical.center,
textAlign: TextAlign.left,
controller: signInEmail,
obscureText: false,
autofocus: false,
maxLines: 1,
autocorrect: true,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.emailAddress,
validator: (input) {
if(Validator.isValidEmail(input.toString())) {
return null;
} else {
return "Please enter a valid email.";
}
},
onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
cursorColor: Colors.amber,
style: TextStyle(fontSize: 16, color: Colors.white,),
decoration: InputDecoration(
enabled: true,
prefixIcon: Icon(Icons.email, color: Colors.amber,size: 18,),
focusColor: Colors.amber,
contentPadding: EdgeInsets.all(10),
border: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.amber, width: 2),
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.amber, width: 2),
),
hintText: "Email Address",
hintStyle: TextStyle(color: Colors.white54)
),
),
SizedBox(height: 30,),
TextFormField(
textCapitalization: TextCapitalization.words,
textAlignVertical: TextAlignVertical.center,
textAlign: TextAlign.left,
controller: signInPassword,
obscureText: true,
autofocus: false,
maxLines: 1,
autocorrect: false,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.text,
validator: (input) {
if(input.toString().length >= 6) {
return null;
} else {
return "Please enter your password.";
}
},
cursorColor: Colors.amber,
style: TextStyle(fontSize: 16, color: Colors.white),
decoration: InputDecoration(
enabled: true,
prefixIcon: Icon(Icons.lock, color: Colors.amber,size: 18),
focusColor: Colors.amber,
contentPadding: EdgeInsets.all(10),
border: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.amber, width: 2),
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.amber, width: 2),
),
hintText: "Password",
hintStyle: TextStyle(color: Colors.white54)
),
),
Container(
margin: EdgeInsets.only(bottom: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap: () => {
// Navigator.pushNamed(context, ForgotPasswordPage.route),
},
splashColor: Colors.amber,
child: Container(
margin: EdgeInsets.symmetric(vertical: 12),
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 5),
child: Text('Forgot Password', style: TextStyle(
color: Colors.white70,
fontSize: 13,
)),
),
)
],
)
),
Container(
height: 36,
margin: EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
//side: BorderSide(color: Colors.red)
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
isLoading ? SizedBox() : Icon(Icons.email, color: Colors.white70.withOpacity(0.4), size: 22),
isLoading ? SizedBox(height:22, width:22,child: CircularProgressIndicator(strokeWidth: 4,)) : Text('Sign in with Email', style: TextStyle(
color: Colors.white70,
fontSize: 16,
),),
isLoading ? SizedBox() : SizedBox(width: 26,),
],
),
color: Colors.white12,
focusColor: Colors.amber,
splashColor: Colors.amber,
onPressed: () {
if (_signInFormKey.currentState.validate()) {
setState(() {
isLoading = !isLoading;
});
//requestSignIn().then((response) => (requestSignInHandler(response)));
}
},
),
),
divider,
Container(
margin: EdgeInsets.symmetric(horizontal: 0, vertical: 4),
height: 36,
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
//side: BorderSide(color: Colors.red)
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Image.asset('assets/images/hw_24x24_logo.png', width: 24, height: 24),
Text('Sign in with HUAWEI ID', style: TextStyle(
color: Colors.white,
fontSize: 16,
)),
SizedBox(width: 20,),
],
),
color: Color(0xffef484b),
focusColor: Colors.amber,
splashColor: Colors.amber,
onPressed: () {
_signIn();
},
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 10, vertical: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Don\'t have an account yet?', style: TextStyle(
color: Colors.white70,
fontSize: 14,
),),
InkWell(
onTap: () => {
setState(() {
isLoginPage = !isLoginPage;
})
},
focusColor: Colors.amber,
splashColor: Colors.amber,
child: Container(
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 5),
child: Text('Register', style: TextStyle(
color: Colors.white70,
fontSize: 14,
fontWeight: FontWeight.bold,
decoration: TextDecoration.underline,
decorationThickness: 1.2,
)),
),
)
],
),
),
]),
),
),
),
)
],
),
);
//...sign up
}
2. Let us implement our sign in.
@override
Widget build(BuildContext context) {
//...divider
//...sign in
var signUpPage = Container(
alignment: Alignment.center,
margin: EdgeInsets.symmetric(horizontal: 30, vertical: 0),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: SingleChildScrollView(
child: AbsorbPointer(
absorbing: isLoading,
child: Form(
key: _signUpFormKey,
child: Column(
children: [
SizedBox(height: 50,),
Text("Flutter Sign In Reference", style: TextStyle(
fontSize: 30,
color: Colors.amber,
),),
SizedBox(height: 60,),
TextFormField(
textCapitalization: TextCapitalization.words,
textAlignVertical: TextAlignVertical.center,
textAlign: TextAlign.left,
controller: signUpName,
obscureText: false,
autofocus: false,
maxLines: 1,
autocorrect: true,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.text,
validator: (input) {
if(input.toString().length >= 3) {
return null;
} else {
return "Please enter your name.";
}
},
onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
cursorColor: Colors.amber,
style: TextStyle(fontSize: 16, color: Colors.white,),
decoration: InputDecoration(
enabled: true,
prefixIcon: Icon(Icons.account_box, color: Colors.amber,size: 18,),
focusColor: Colors.amber,
contentPadding: EdgeInsets.all(10),
border: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.amber, width: 2),
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.amber, width: 2),
),
hintText: "Enter your Name",
hintStyle: TextStyle(color: Colors.white54)
),
),
SizedBox(height: 30,),
TextFormField(
textCapitalization: TextCapitalization.words,
textAlignVertical: TextAlignVertical.center,
textAlign: TextAlign.left,
controller: signUpEmail,
obscureText: false,
autofocus: false,
maxLines: 1,
autocorrect: true,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.emailAddress,
validator: (input) {
if(Validator.isValidEmail(input.toString())) {
return null;
} else {
return "Please enter a valid email.";
}
},
onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
cursorColor: Colors.amber,
style: TextStyle(fontSize: 16, color: Colors.white,),
decoration: InputDecoration(
enabled: true,
prefixIcon: Icon(Icons.email, color: Colors.amber,size: 18,),
focusColor: Colors.amber,
contentPadding: EdgeInsets.all(10),
border: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.amber, width: 2),
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.amber, width: 2),
),
hintText: "Enter your Email",
hintStyle: TextStyle(color: Colors.white54)
),
),
SizedBox(height: 30,),
TextFormField(
textCapitalization: TextCapitalization.words,
textAlignVertical: TextAlignVertical.center,
textAlign: TextAlign.left,
controller: signUpPassword,
obscureText: true,
autofocus: false,
maxLines: 1,
autocorrect: false,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.text,
validator: (input) {
if(input.toString().length >= 6) {
return null;
} else {
return "Your password must contain at least 6 characters.";
}
},
cursorColor: Colors.amber,
style: TextStyle(fontSize: 16, color: Colors.white,),
decoration: InputDecoration(
enabled: true,
prefixIcon: Icon(Icons.lock, color: Colors.amber,size: 18),
focusColor: Colors.amber,
contentPadding: EdgeInsets.all(10),
border: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.amber, width: 2),
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.amber, width: 2),
),
hintText: "Enter your a Password",
hintStyle: TextStyle(color: Colors.white54)
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 10, vertical: 18),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Already have an account?', style: TextStyle(
color: Colors.white70,
fontSize: 14,
),),
InkWell(
onTap: () => {
setState(() {
isLoginPage = !isLoginPage;
})
},
splashColor: Colors.amber,
child: Container(
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 5),
child: Text('Sign In', style: TextStyle(
color: Colors.white70,
fontSize: 14,
fontWeight: FontWeight.bold,
decoration: TextDecoration.underline,
decorationThickness: 1.5,
)),
),
)
],
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 0, vertical: 4),
height: 36,
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
//side: BorderSide(color: Colors.red)
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
isLoading ? SizedBox(height:22, width:22,child: CircularProgressIndicator(strokeWidth: 4,)) : Text('Sign Up'.toUpperCase(), style: TextStyle(
color: Colors.white70,
fontSize: 16,
)),
]),
color: Colors.white24,
focusColor: Colors.amber,
splashColor: Colors.amber,
onPressed: () {
if (_signUpFormKey.currentState.validate()) {
setState(() {
isLoading = !isLoading;
});
// requestSignUp().then((response) => (requestSignUpHandler(response)));
}
},
),
),
divider,
Container(
height: 36,
margin: EdgeInsets.symmetric(horizontal:0,vertical: 4),
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
//side: BorderSide(color: Colors.red)
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Image.asset('assets/images/hw_24x24_logo.png', width: 24, height: 24),
Text('Sign in with HUAWEI ID', style: TextStyle(
color: Colors.white,
fontSize: 16,
),),
SizedBox(width: 20,),
],
),
color: Color(0xffef484b),
onPressed: () {
},
),
),
]),
),
),
),
)
],
),
);
}
Test and Verification
Upon completing the essential parts of the code, connect your mobile device to the PC and enable the USB debugging mode. In the Android Studio window, click
icon to run the project you have created in Android Studio to generate an APK. Then install the APK on the mobile device.
- Open the app upon installing it to your device
- Select either simple build or complex build.
- Complete the sign in processes.

Well done. You have successfully completed this Codelab and learned:
- How to initialize account Kit
- How to use Huaweu Kit SDK features
- How to implement Sign-in and Register forms using Huawei ID and email.
- How to use Shared Preferences to save that matters for the application.