Expert: Google Firebase and AppGallery Connect Integration in HMS Core Based Expense Android App

Manoj Kumar
6 min readJan 21, 2022

--

Overview

In this article, we will learn how to create Firebase and HMS Core Android app which highlights use case of Google Analytics and HMS Analytics in Expense Android App. I have given full demo that how to integrate Huawei Analytics and Google Analytics which highlights the capabilities of HMS Core and Google Firebase in Single Android App.

Huawei Analytics Introduction

Analytics kit is powered by Huawei which allows rich analytics models to understand user behavior and gain in-depth insights into users, products, and content. As such, you can carry out data-driven operations and make strategic decisions about app marketing and product optimization.

Analytics Kit implements the following functions using data collected from apps:

1. Provides data collection and reporting APIs for collection and reporting custom events.

2. Sets up to 25 user attributes.

3. Supports automatic event collection and session calculation as well as predefined event IDs and parameters

Google Analytics Introduction

Google Analytics collects usage and behaviour data for your app. The SDK logs two primary types of information:

Events: What is happening in your app, such as user actions, system events, or errors?

User properties: Attributes you define to describe segments of your user base, such as language preference or geographic location.

Analytics automatically logs some events and user properties, you don’t need to add any code to enable them.

Prerequisite

1. Huawei Phone

2. Android Studio

3. Google Firebase Account

4. AppGallery Account

App Gallery Integration process

1. Sign In and Create or Choose a project on AppGallery Connect portal.

2. Navigate to Project settings and download the configuration file.

3. Navigate to General Information, and then provide Data Storage location.

4. Enable Huawei Analytics.

Firebase Integration Process

1. Create a Firebase project.

2. Choose Android as Platform.

3. Add App in your Firebase Project.

4. Download Configuration file.

5. Enable Google Analytics(Firebase)

App Development

1. Create A New Project.

2. Configure Project Gradle.

classpath 'com.android.tools.build:gradle:3.1.4'classpath 'com.huawei.agconnect:agcp:1.3.1.300'classpath 'com.google.gms:google-services:4.3.5'

3. Configure App Gradle.

//HMS Kitsapi 'com.huawei.hms:dynamicability:1.0.11.302'implementation 'com.huawei.agconnect:agconnect-auth:1.4.1.300'implementation 'com.huawei.hms:hwid:5.3.0.302'implementation 'com.huawei.hms:ads-lite:13.4.30.307'implementation 'com.huawei.agconnect:agconnect-remoteconfig:1.6.0.300'implementation 'com.huawei.hms:hianalytics:5.0.3.300'implementation 'com.huawei.agconnect:agconnect-crash:1.4.1.300'//Google Tag Manager with Analyticsimplementation platform('com.google.firebase:firebase-bom:26.8.0')implementation 'com.google.firebase:firebase-analytics'implementation 'com.google.android.gms:play-services-tagmanager:17.0.0'

4. Configure AndroidManifest.

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.hms.expensedemo">    <application        android:allowBackup="true"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:roundIcon="@mipmap/ic_launcher_round"        android:supportsRtl="true"        android:theme="@style/AppTheme">        <activity            android:name="com.hms.expensedemo.activities.MainActivity"            android:label="@string/app_name"            android:theme="@style/AppTheme.NoActionBar">        </activity>        <activity android:name="com.hms.expensedemo.activities.AddExpenseActivity" />        <activity android:name="com.hms.expensedemo.activities.SplashScreen"            android:theme="@style/SplashTheme">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>

5. Code Implementation

LoginActivity:

package com.hms.expensedemo.activities;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.hms.expensedemo.R;
import com.huawei.agconnect.crash.AGConnectCrash;
import com.huawei.hmf.tasks.Task;
import com.huawei.hms.ads.banner.BannerView;
import com.huawei.hms.analytics.HiAnalytics;
import com.huawei.hms.analytics.HiAnalyticsInstance;
import com.huawei.hms.analytics.HiAnalyticsTools;
import com.huawei.hms.common.ApiException;
import com.huawei.hms.support.hwid.HuaweiIdAuthManager;
import com.huawei.hms.support.hwid.request.HuaweiIdAuthParams;
import com.huawei.hms.support.hwid.request.HuaweiIdAuthParamsHelper;
import com.huawei.hms.support.hwid.result.AuthHuaweiId;
import com.huawei.hms.support.hwid.service.HuaweiIdAuthService;


public class LoginActivity extends AppCompatActivity implements View.OnClickListener {

private static final int REQUEST_SIGN_IN_LOGIN = 1002;
private static String TAG = LoginActivity.class.getName();
private HuaweiIdAuthService mAuthManager;
private HuaweiIdAuthParams mAuthParam;
private BannerView hwBannerView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
Button view = findViewById(R.id.btn_sign);
view.setOnClickListener(this);

AGConnectCrash.getInstance().enableCrashCollection(false);
//Crash application
AGConnectCrash.getInstance().testIt(this);
}


private void signIn() {
mAuthParam = new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM)
.setIdToken()
.setAccessToken()
.createParams();
mAuthManager = HuaweiIdAuthManager.getService(this, mAuthParam);
startActivityForResult(mAuthManager.getSignInIntent(), REQUEST_SIGN_IN_LOGIN);
}

@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_sign) {
signIn();
}
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_SIGN_IN_LOGIN) {
Task<AuthHuaweiId> authHuaweiIdTask = HuaweiIdAuthManager.parseAuthResultFromIntent(data);
if (authHuaweiIdTask.isSuccessful()) {
AuthHuaweiId huaweiAccount = authHuaweiIdTask.getResult();
Log.i(TAG, huaweiAccount.getDisplayName() + " signIn success ");
Log.i(TAG, "AccessToken: " + huaweiAccount.getAccessToken());

Bundle bundle = new Bundle();
bundle.putString(TAG, huaweiAccount.getDisplayName() + " signIn success ");
String eventName = "Login";

bundle.putDouble("ID", 999);
bundle.putLong("Details", 100L);
Analystics.getInstance(this).setEvent("login", bundle);

HiAnalyticsInstance instance = HiAnalytics.getInstance(this);
HiAnalyticsTools.enableLog();


if (instance != null) {
instance.onEvent(eventName, bundle);
}

Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("user", huaweiAccount.getDisplayName());
startActivity(intent);
this.finish();

} else {
Log.i(TAG, "signIn failed: " + ((ApiException) authHuaweiIdTask.getException()).getStatusCode());
}
}

}
}

AddExpenseActivity:

package com.hms.expensedemo.activities;

import android.app.DatePickerDialog;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TextInputEditText;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.DatePicker;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;

import com.hms.expensedemo.R;
import com.hms.expensedemo.transactionDb.AppDatabase;
import com.hms.expensedemo.transactionDb.AppExecutors;
import com.hms.expensedemo.transactionDb.TransactionEntry;
import com.hms.expensedemo.transactionDb.TransactionViewModel;
import com.hms.expensedemo.utils.Constants;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

public class AddExpenseActivity extends AppCompatActivity {


TextInputEditText amountTextInputEditText;
TextInputEditText descriptionTextInputEditText;
TextInputLayout amountTextInputLayout;
TextInputLayout descriptionTextInputLayout;
TextView dateTextView;
LinearLayout dateLinearLayout;
Spinner categorySpinner;
ArrayList<String> categories;
Calendar myCalendar;

String description;
Date dateOfExpense;

private DatePickerDialog datePickerDialog;
private static AppDatabase appDatabase;


private static final String LOG_TAG = AddExpenseActivity.class.getSimpleName();


//These variables contain data which will be stored permanently on hitting save button
int amount;
String categoryOfExpense; //This parameter is to decide category in a transaction
String categoryOfTransaction; //This parameter to decide whether it is income and expense

//Variable to keep track from where it came to this activity
String intentFrom;

TransactionViewModel transactionViewModel;

int transactionid;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_expense);

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

amountTextInputEditText = findViewById(R.id.amountTextInputEditText);
descriptionTextInputEditText = findViewById(R.id.descriptionTextInputEditText);
amountTextInputLayout = findViewById(R.id.amountTextInputLayout);
descriptionTextInputLayout = findViewById(R.id.descriptionTextInputLayout);
dateTextView = findViewById(R.id.dateTextView);
dateLinearLayout = findViewById(R.id.dateLinerLayout);
categorySpinner = findViewById(R.id.categorySpinner);

appDatabase = AppDatabase.getInstance(getApplicationContext());


transactionViewModel = ViewModelProviders.of(this)
.get(TransactionViewModel.class);

categories = new ArrayList<>();

myCalendar = Calendar.getInstance();
setDateToTextView();

//First task here is to determine from where this activity is launched from the 4 possibilities

Intent intent = getIntent();

intentFrom = intent.getStringExtra("from");

if (intentFrom.equals(Constants.addIncomeString)) {
categoryOfTransaction = Constants.incomeCategory;
setTitle("Add Income");
categories.add("Income");
categorySpinner.setClickable(false);
categorySpinner.setEnabled(false);
categorySpinner.setAdapter(new ArrayAdapter<>(AddExpenseActivity.this, android.R.layout.simple_list_item_1, categories));

} else if (intentFrom.equals(Constants.addExpenseString)) {
categoryOfTransaction = Constants.expenseCategory;
setTitle("Add Expense");
categories.add("Food");
categories.add("Travel");
categories.add("Clothes");
categories.add("Movies");
categories.add("Health");
categories.add("Grocery");
categories.add("Other");
categorySpinner.setAdapter(new ArrayAdapter<>(AddExpenseActivity.this,
android.R.layout.simple_list_item_1, categories));

} else if (intentFrom.equals(Constants.editIncomeString)) {
setTitle("Edit Income");

amountTextInputEditText.setText(String.valueOf(intent.getIntExtra("amount", 0)));
amountTextInputEditText.setSelection(amountTextInputEditText.getText().length());
descriptionTextInputEditText.setText(intent.getStringExtra("description"));
descriptionTextInputEditText.setSelection(descriptionTextInputEditText.getText().length());
transactionid=intent.getIntExtra("id",-1);

SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
try {
Date date = sdf.parse(intent.getStringExtra("date"));
myCalendar.setTime(date);
} catch (ParseException e) {
e.printStackTrace();
}
dateTextView.setText(intent.getStringExtra("date"));

categoryOfTransaction = Constants.incomeCategory;
categories.add("Income");
categorySpinner.setClickable(false);
categorySpinner.setEnabled(false);
categorySpinner.setAdapter(new ArrayAdapter<>(AddExpenseActivity.this, android.R.layout.simple_list_item_1, categories));

} else if (intentFrom.equals(Constants.editExpenseString)) {
categoryOfTransaction = Constants.expenseCategory;
setTitle("Edit Expense");
amountTextInputEditText.setText(String.valueOf(intent.getIntExtra("amount", 0)));
amountTextInputEditText.setSelection(amountTextInputEditText.getText().length());
descriptionTextInputEditText.setText(intent.getStringExtra("description"));
descriptionTextInputEditText.setSelection(descriptionTextInputEditText.getText().length());
dateTextView.setText(intent.getStringExtra("date"));
transactionid=intent.getIntExtra("id",-1);


SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
try {
Date date = sdf.parse(intent.getStringExtra("date"));
myCalendar.setTime(date);
} catch (ParseException e) {
e.printStackTrace();
}

categories.add("Food");
categories.add("Travel");
categories.add("Clothes");
categories.add("Movies");
categories.add("Health");
categories.add("Grocery");
categories.add("Other");
categorySpinner.setAdapter(new ArrayAdapter<>(AddExpenseActivity.this, android.R.layout.simple_list_item_1, categories));
categorySpinner.setSelection(categories.indexOf(intent.getStringExtra("category")));
}

dateLinearLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showDatePicker();
}
});

}


public void showDatePicker() {


DatePickerDialog.OnDateSetListener dateSetListener=new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
myCalendar.set(Calendar.YEAR, year);
myCalendar.set(Calendar.MONTH, month);
myCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
setDateToTextView();
}
};

DatePickerDialog datePickerDialog=new DatePickerDialog(AddExpenseActivity.this,dateSetListener,
myCalendar.get(Calendar.YEAR), myCalendar.get(Calendar.MONTH), myCalendar.get(Calendar.DAY_OF_MONTH));

datePickerDialog.getDatePicker().setMaxDate(System.currentTimeMillis());
datePickerDialog.show();


}








public void setDateToTextView() {
Date date = myCalendar.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
String dateToBeSet = sdf.format(date);
dateTextView.setText(dateToBeSet);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {

MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.add_expense_activty_menu, menu);
return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

switch (item.getItemId()) {
case android.R.id.home:
finish();
break;
case R.id.saveButton:
// COMPLETED: 10-09-2018 1.Retrieve and Save data to database and also update the recycler view


if (amountTextInputEditText.getText().toString().isEmpty()
|| descriptionTextInputEditText.getText().toString().isEmpty()) {

if (amountTextInputEditText.getText().toString().isEmpty())
amountTextInputEditText.setError("Amount cannot be empty");
if (descriptionTextInputEditText.getText().toString().isEmpty())
descriptionTextInputEditText.setError("Please write some description");

} else {
amount = Integer.parseInt(amountTextInputEditText.getText().toString());
description = descriptionTextInputEditText.getText().toString();
dateOfExpense = myCalendar.getTime();

if (intentFrom.equals(Constants.addIncomeString)
|| intentFrom.equals(Constants.editIncomeString))
categoryOfExpense = "Income";
else
categoryOfExpense = categories.get(categorySpinner.getSelectedItemPosition());

final TransactionEntry mTransactionEntry = new TransactionEntry(amount,
categoryOfExpense,
description,
dateOfExpense,
categoryOfTransaction
);

if(intentFrom.equals(Constants.addIncomeString)||intentFrom.equals(Constants.addExpenseString)) {


AppExecutors.getInstance().diskIO().execute(new Runnable() {
@Override
public void run() {
appDatabase.transactionDao().insertExpense(mTransactionEntry);
}
});

InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);

Snackbar.make(getCurrentFocus(),"Transaction Added",Snackbar.LENGTH_LONG).show();
}
else{
mTransactionEntry.setId(transactionid);
AppExecutors.getInstance().diskIO().execute(new Runnable() {
@Override
public void run() {
appDatabase.transactionDao().updateExpenseDetails(mTransactionEntry);

}
});

InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);

Snackbar.make(getCurrentFocus(),"Transaction Updated",Snackbar.LENGTH_LONG).show();

}
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
finish();
}
}, 1000);

}
break;
}
return true;


}


}

MainActivity:

package com.hms.expensedemo.activities;

import android.support.design.widget.TabLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;

import android.support.v4.view.ViewPager;
import android.os.Bundle;
import android.view.View;

import com.hms.expensedemo.R;
import com.hms.expensedemo.adapters.SectionsPageAdapter;
import com.hms.expensedemo.fragments.BalanceFragment;
import com.hms.expensedemo.fragments.CustomBottomSheetDialogFragment;
import com.hms.expensedemo.fragments.ExpenseFragment;

public class MainActivity extends AppCompatActivity {

private ViewPager mViewPager;

public static FloatingActionButton fab;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


mViewPager=findViewById(R.id.container);
setupViewPager(mViewPager);

TabLayout tabLayout=findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);


fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new CustomBottomSheetDialogFragment().show(getSupportFragmentManager(), "Dialog");

}
});

}




private void setupViewPager(ViewPager viewPager){
SectionsPageAdapter adapter=new SectionsPageAdapter(getSupportFragmentManager());
adapter.addFragment(new ExpenseFragment(),"Expenses");
adapter.addFragment(new BalanceFragment(),"Balance");
viewPager.setAdapter(adapter);
}



}

App Build Result

Tips and Tricks

1. 5.2.0 or later. If HMS Core (APK) is not installed or its version is earlier than 5.2.0, DTM functions can be normally used but the DTM SDK version cannot be updated automatically.

2. Ensure that Analytics Kit has been enabled, and the API management permission (enabled by default) has been enabled on the Manage APIs tab page in AppGallery Connect.

3. Ensure that the agconnect-services.json file is the original one without any modification.

Conclusion

In this article, we have learned how to integrate Google Firebase Analytics in HMS Core based Expense Demo Android app.

Thanks for reading this article. Be sure to like and comments to this article, if you found it helpful. It means a lot to me.

References

HMS Docs

https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/introduction-0000001050043907

Google Docs

https://console.firebase.google.com/u/0/

--

--