Writing a Serverless Android app (ft. Huawei's AppGallery Connect) - Part 1 - Auth
Not read part 0? Read it first!
Writing a Serverless Android app (ft. Huawei's AppGallery Connect) - Part 0
Zachary Powell ・ Jun 28 '21 ・ 3 min read
Over the next couple of months I will be releasing a complete end to end guide to creating an Android app using serverless functionality to completely remove the need for any backend server/hosting etc.
This weeks Video is below
And at the bottom of this post you will find my twitch channel where we live stream every Thursday at 2pm BST and the github repo for this project!.
But for those that would rather a written guide, lets get into it!
Project Setup
Starting with a brand new project (or one that has never used Huawei services) we will need to start by setting up a new app. (If you haven't setup your developer account yet sign up!)
If you would like the complete step by step guide on how to get setup check out the Official Documentation, but below is a summery.
Navigate to the the AppGallery Connect area of the developer portal, here you need to create a new project.
Follow the new project guide, giving that project a name. Once completed on the left hand menu find the Auth service under the build menu.
Click the enable now button in the top right corner to enable this service for your project. Set a default data processing location, depending on your physical location will most likely help decide which to use. For us we have selected Germany as this is the closest location and within the EU.
From here you are presented with the list of authentication modes, Huawei supports a wide range of services from Facebook login to AppleID. However today we are focusing on the email auth method. Click the enable button next to this.
Now that everything is setup in the project, its time to setup the app! At this point I will assume you have created a new blank project in Android Studio and given it a package name etc.
From the project settings top screen, select the Add app button to setup a new app under this project.
Fill in the add app form, setting the platform, app name, package etc so that it can be added to the created project. Its worth noting at this point, that while we are focusing on Android today many of these services can be used across multiple platforms including iOS and web.
Once completed you will be told to download the agconnect-services.json file and presented with a code to get the core services setup. As we are already focusing on a specific service for today the setup at this point is a little different.
Start by placing your nearly downloaded agconnect-services.json
file into the app directory of your project.
Next we will get gradle configured correctly. In your top level gradle build file add the below to your repositories both under buildscript and allprojects
maven {
url 'https://developer.huawei.com/repo/'
}
And to your dependencies add classpath 'com.huawei.agconnect:agcp:1.4.1.300'
Your file should now look a little like
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
maven {
url 'https://developer.huawei.com/repo/'
}
}
dependencies {
classpath "com.android.tools.build:gradle:4.2.2"
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
mavenCentral()
jcenter() // Warning: this repository is going to shut down soon
maven {
url 'https://developer.huawei.com/repo/'
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Next open your app build.gradle file
Start by adding the agconnect plugin into your plugins list
plugins {
id 'com.android.application'
id 'com.huawei.agconnect'
}
Make sure to set your midSdkVersion to at least 17
(this is required for any Huawei AppGallery Connect services.
And then in dependencies we are going to add the core and auth services
implementation 'com.huawei.agconnect:agconnect-core:1.4.1.300'
implementation 'com.huawei.agconnect:agconnect-auth:1.4.1.300'
So your file should now look something like
plugins {
id 'com.android.application'
id 'com.huawei.agconnect'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "site.zpweb.barker"
minSdkVersion 17
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'com.huawei.agconnect:agconnect-core:1.4.1.300'
implementation 'com.huawei.agconnect:agconnect-auth:1.4.1.300'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
And thats it! let gradle sync up and we are all good to go!
Registration
As I mentioned before there are a wide range of ways a user can authenticate using the Auth service, but here we are looking at the email service. Email authenticate the user by sending them a code via (your guessed it) Email. The user then inputs this code back into the app to confirm that they are who the say they are, and that they have access to that contact method. We will assume you have setup some kind of register view that will capture a users email.
We start by requesting an authentication code be set to the user, the code to do this looks like
VerifyCodeSettings settings = VerifyCodeSettings.newBuilder()
.action(VerifyCodeSettings.ACTION_REGISTER_LOGIN)
.sendInterval(30)
.locale(Locale.ENGLISH)
.build();
Task<VerifyCodeResult> task = EmailAuthProvider.requestVerifyCode(emailString, settings);
task.addOnSuccessListener(TaskExecutors.uiThread(), new OnSuccessListener<VerifyCodeResult>() {
@Override
public void onSuccess(VerifyCodeResult verifyCodeResult) {
authCodeDialog();
}
}).addOnFailureListener(TaskExecutors.uiThread(), new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Toast.makeText(RegisterActivity.this,
"Error, code sending failed: " + e,
Toast.LENGTH_LONG).show();
}
});
Lets break this down, we start by defining a VerifyCodeSettings
object, this holds all the settings relating to the sending of the code. Here we define what locale should be used for the message text that is sent, what kind of code it is and the send interval.
Next we create a task to be run
Task<VerifyCodeResult> task = EmailAuthProvider.requestVerifyCode(emailString, settings);
Using the EmailAuthProvider, where emailString
is the email address the user has entered, as a string and the settings object is the VerifyCodeSettings object we just created.
Next we setup an OnSucessListener which will be called if the code was successfully sent to the user. In this example we are calling the method authCodeDialog();
to display a dialog to enter the code, which will see in a moment.
We also setup an OnFailureListener which simply create a toast on screen to display what ever error is sent back.
Now that we have sent the user a code we should display some view for them to enter that code, in my instance I have the method below, but of course this could be what ever view you wanted.
private void authCodeDialog() {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
final EditText authCodeField = new EditText(this);
alert.setMessage("Enter your auth code below");
alert.setTitle("Authentication Code");
alert.setView(authCodeField);
alert.setPositiveButton("Register", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String authCode = authCodeField.getText().toString();
register(authCode);
}
});
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(RegisterActivity.this,
"Registration Cancelled",
Toast.LENGTH_LONG).show();
}
});
alert.show();
}
Finally once the user has inputted the code we can register them as you can see above we have a register method that is called, this has the below code:
EmailUser emailUser = new EmailUser.Builder()
.setEmail(emailString)
.setVerifyCode(authCode)
.build();
AGConnectAuth.getInstance().createUser(emailUser).addOnSuccessListener(new OnSuccessListener<SignInResult>() {
@Override
public void onSuccess(SignInResult signInResult) {
Toast.makeText(RegisterActivity.this,
"Register Successful: " + signInResult.getUser().getUid(),
Toast.LENGTH_LONG);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Toast.makeText(RegisterActivity.this,
"Registering failed " + e,
Toast.LENGTH_LONG);
}
});
So we start by creating an EmailUser
using the email address we captured earlier and the authCode that the user has entered. Using that EmailUser
we then attempt to register. Note that we can also set a password against the EmailUser
, if we do this when they go to login they do not need to verify their email address again. They can just enter their email and password.
As you can see we pass the created object into the createUser method, attaching OnSuccess and OnFailure Listeners. If the user is successfully registered, i.e the code they entered matches what was sent we are returned a SignInResult
this object containes the user. So in this example we simply print out the registered users UID to confirm it completed successfully.
Login
Now that we have covered the sign up process lets look at how we might handle a login process. This would assume that the user has already registered via the above method and is now logging into the app, perhaps after installing it on a new phone.
As I mentioned before if the user signed up without a password then start by sending a verify code, in just the same way as we did during the sign up process. Once we have the code we can generate a AGCOnnectAuthCredential
object
AGConnectAuthCredential credential = credential = EmailAuthProvider.credentialWithVerifyCode(
email.getText().toString().trim(),
null,
authCode);
Here we get the email that the user entered (email
being an EditText
object). We pass null for the password as we haven't used this, and finally the authCode which the user has entered into the app.
Now we can attempt the sign the user in:
AGConnectAuth.getInstance().signIn(credential)
.addOnSuccessListener(new OnSuccessListener<SignInResult>() {
@Override
public void onSuccess(SignInResult signInResult) {
Toast.makeText(MainActivity.this, "Sign in successful: " +
signInResult.getUser().getUid(), Toast.LENGTH_LONG);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Toast.makeText(MainActivity.this, "sign in failed:" + e, Toast.LENGTH_LONG);
}
});
We pass the credential object into the signIn method, if the code and email matched and was correct the OnSuccessListener will return the SignInResult object just as it did during the sign up, from here we have access to the users detials.
If for any reason the login fails we will get an Exception in the OnFailureListener.
And thats it! We have setup the application to use Huawei services and configured the app to use email authentication during sign up and log in.
For more information on the Auth service, full documentation can be found here https://developer.huawei.com/consumer/en/doc/development/AppGallery-connect-Guides/agc-auth-introduction-0000001053732605
Twitch Acccount
Github Repo
devwithzachary / Barker
Project init
Barker - A Serverless Twitter Clone
Barker is a simple twitter style social network written to demostrate the serverless services provided by Huawei's AppGallery Connect platform.
This app is written during live streams over at https://www.twitch.tv/devwithzachary The streams are then edited down into videos which you can watch https://www.youtube.com/channel/UC63PqG8ZnWC4JWYrNJKocMA
Finally there is also a written copy of the guide found on dev.to https://dev.to/devwithzachary
Each episodes code is commited as a single commit to make it easy to step along with the code, simply checkout the specific commit and follow along!
We will be back with the next part next week!