Android Deep Link Using Huawei App Gallery Ability - Huawei Developers

HMS App Linking Introduction
{
"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"
}
HMS App Linking allows you to create cross-platform links that can work as defined regardless of whether your app has been installed by a user. When a user taps the link on an Android or iOS device, the user will be redirected to the specified in-app content. If a user taps the link in a browser, the user will be redirected to the same content of the web version.
To identify the source of a user, you can set tracing parameters for various channels when creating a link of App Linking to trace traffic sources. By analyzing the link performance of each traffic source based on the tracing parameters, you can find the platform that can achieve better promotion effect for your app:
Deferred deep link: Directs a user who has not installed your app to AppGallery to download your app first and then navigate to the link in-app content directly, without requiring the user to tap the link again.
Link display in card form: Uses a social Meta tag to display a link of App Linking as a card, which will attract more users from social media.
Statistics: Records the data of all link-related events, such as numbers of link taps, first app launches, and non-first app launches for you to conduct analysis.
API Overview
1. (Mandatory) Call AppLinking.Builder to create a Builder object.
2. (Mandatory) Call AppLinking.Builder.setUriPrefix to set the URL prefix that has been applied for in Applying for a URL Prefix.
3. (Mandatory) Call AppLinking.Builder.setDeepLink to set a deep link.
4. Call AppLinking.Builder.setAndroidLinkInfo to set Android app parameters. In this method, Android app parameters are contained in an AppLinking.AndroidLinkInfo instance, which can be built by calling AppLinking.AndroidLinkInfo.Builder. If this method is not called, the link will be opened in the browser by default.
5. Call AppLinking.Builder.setIOSLinkInfo to set iOS app parameters. In this method, iOS app parameters are contained in an AppLinking.IOSLinkInfo instance, which can be built by calling AppLinking.IOSLinkInfo.Builder. If this method is not called, the link will be opened in the browser by default.
6. Call AppLinking.IOSLinkInfo.Builder.setITunesConnectCampaignInfo to set App Store Connect campaign parameters. In this method, App Store Connect campaign parameters are contained in an AppLinking.ITunesConnectCampaignInfo instance, which can be built by calling AppLinking.ITunesConnectCampaignInfo.Builder.
7. Call AppLinking.Builder.setPreviewType to set the link preview type. If this method is not called, the preview page with app information is displayed by default.
8. Call AppLinking.Builder.setSocialCardInfo to set social Meta tags. In this method, social Meta tags are contained in an AppLinking.SocialCardInfo instance, which can be built by calling AppLinking.SocialCardInfo.Builder. If this method is not called, links will not be displayed as cards during social sharing.
9. Call AppLinking.Builder.setCampaignInfo to set ad tracing parameters. In this method, campaign parameters are contained in an AppLinking.CampaignInfo instance, which can be built by calling AppLinking.CampaignInfo.Builder.
Key Concepts
URL prefix
The URL prefix is the domain name contained in a link, which is in https://Domain name format. You can use the domain name provided by AppGallery Connect for free.
Long link
A long link is a link of App Linking in its entirety. follows this format:
URL prefix+Deep link+Android app parameters+iOS app parameters+[Preview type]+[Social meta tag]+[Tracing parameters]+[Landing page display parameter]+[Site ID].
An example of a long link is as follows:
https://yourapp.drcn.agconnect.link/?deeplink=https%3A%2F%2Fyourdeeplink.com&android_deeplink=https%3A%2F%2Fyourdeeplink.com&android_open_type=1&android_package_name=tiantian.huawei&campaign_channel=huawei&campaign_medium=pic&campaign_name=%E4%BF%83%E9%94%80&ios_link=https%3A%2F%2Fyourdeeplink.com&ios_bundle_id=aapp.huawei&at=1234&pt=212&ct=1234&mt=1&preview_type=2&social_title=%E6%8E%A5%E5%85%A5%E4%BF%83%E9%94%80&landing_page_type=1&&region_id=0
Short link
If a long link is too long, it can be converted to a short link. A short link follows this format:
URL prefix+Random suffix of the string type
Prerequisite
Huawei Phone
Android Studio
AppGallery Account
App Development
Create a New Project.
Configure Project Gradle.
Code:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
//TODO
maven { url 'https://developer.huawei.com/repo/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
//TODO
classpath 'com.huawei.agconnect:agcp:1.4.2.301'
}
}
allprojects {
repositories {
google()
jcenter()
//TODO
maven { url 'https://developer.huawei.com/repo/' }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
3. Configure App Gradle.
Code:
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.cardview:cardview:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
//TODO
implementation 'com.huawei.agconnect:agconnect-applinking:1.4.2.301'
implementation 'com.huawei.hms:hianalytics:5.0.5.301'
4. Configure AndroidManifest.
Code:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hms.applinkandroid">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<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=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".applinking.DetailActivity"
android:configChanges="orientation|keyboardHidden|screenSize" />
<activity
android:name=".applinking.SettingActivity"
android:configChanges="orientation|keyboardHidden|screenSize" />
</application>
</manifest>
5. Create Activity class with XML UI.
MainActivity.java:
This activity performs all the operation of AppLinking with short and long url with Share card.
Code:
package com.hms.applinkandroid;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.hms.applinkandroid.applinking.DetailActivity;
import com.hms.applinkandroid.applinking.SettingActivity;
import com.huawei.agconnect.applinking.AGConnectAppLinking;
import com.huawei.agconnect.applinking.AppLinking;
import com.huawei.agconnect.applinking.ShortAppLinking;
public class MainActivity extends AppCompatActivity {
private static final String DOMAIN_URI_PREFIX = "https://applinkingtest.drcn.agconnect.link";
private static final String DEEP_LINK = "https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides";
private TextView shortTextView;
private TextView longTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
shortTextView = findViewById(R.id.shortLinkText);
longTextView = findViewById(R.id.longLinkText);
findViewById(R.id.create)
.setOnClickListener(
view -> {
createAppLinking();
});
findViewById(R.id.shareShort)
.setOnClickListener(
view -> {
shareLink((String) shortTextView.getText());
});
findViewById(R.id.shareLong)
.setOnClickListener(
view -> {
shareLink((String) longTextView.getText());
});
AGConnectAppLinking.getInstance()
.getAppLinking(this)
.addOnSuccessListener(
resolvedLinkData -> {
Uri deepLink = null;
if (resolvedLinkData != null) {
deepLink = resolvedLinkData.getDeepLink();
}
TextView textView = findViewById(R.id.deepLink);
textView.setText(deepLink != null ? deepLink.toString() : "");
if (deepLink != null) {
String path = deepLink.getLastPathSegment();
if ("detail".equals(path)) {
Intent intent = new Intent(getBaseContext(), DetailActivity.class);
for (String name : deepLink.getQueryParameterNames()) {
intent.putExtra(name, deepLink.getQueryParameter(name));
}
startActivity(intent);
}
if ("setting".equals(path)) {
Intent intent = new Intent(getBaseContext(), SettingActivity.class);
for (String name : deepLink.getQueryParameterNames()) {
intent.putExtra(name, deepLink.getQueryParameter(name));
}
startActivity(intent);
}
}
})
.addOnFailureListener(
e -> {
Log.w("MainActivity", "getAppLinking:onFailure", e);
});
}
private void createAppLinking() {
AppLinking.Builder builder = new AppLinking.Builder()
.setUriPrefix(DOMAIN_URI_PREFIX)
.setDeepLink(Uri.parse(DEEP_LINK))
.setAndroidLinkInfo(new AppLinking.AndroidLinkInfo.Builder().build())
.setSocialCardInfo(new AppLinking.SocialCardInfo.Builder()
.setTitle("华为开发者大会")
.setImageUrl("https://developer.huawei.com/consumer/cn/events/hdc2020/img/kv-pc-cn.png?v0808")
.setDescription("Description").build())
.setCampaignInfo(new AppLinking.CampaignInfo.Builder()
.setName("HDC")
.setSource("AGC")
.setMedium("App").build());
longTextView.setText(builder.buildAppLinking().getUri().toString());
builder.buildShortAppLinking().addOnSuccessListener(shortAppLinking -> {
shortTextView.setText(shortAppLinking.getShortUrl().toString());
}).addOnFailureListener(e -> {
Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
});
}
private void shareLink(String appLinking) {
if (appLinking != null) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, appLinking);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
private void showError(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
main_activity.xml:
Code:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/ic_bg"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/TitleView"
android:layout_width="281dp"
android:layout_height="51dp"
android:text="Android Deep Link"
android:textColor="@android:color/white"
android:textSize="30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.061" />
<androidx.cardview.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
card_view:cardElevation="5dp"
card_view:cardUseCompatPadding="true"
card_view:contentPadding="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/textView5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Deeplink"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/deepLink"
android:layout_width="match_parent"
android:layout_height="59dp"
android:textColor="@android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.241" />
<Button
android:id="@+id/create"
android:layout_width="230dp"
android:layout_height="50dp"
android:text="Create App Linking"
android:textAllCaps="false"
android:textSize="19sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.324" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
card_view:cardElevation="5dp"
card_view:cardUseCompatPadding="true"
card_view:contentPadding="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="Long App Linking:"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/longLinkText"
android:layout_width="match_parent"
android:layout_height="80dp"
android:gravity="center_horizontal" />
<Button
android:id="@+id/shareLong"
android:layout_width="230dp"
android:layout_height="50dp"
android:text="Share long App Linking"
android:textAllCaps="false"
android:textSize="19sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
card_view:cardElevation="5dp"
card_view:cardUseCompatPadding="true"
card_view:contentPadding="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="Short App Linking:"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/shortLinkText"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center_horizontal" />
<Button
android:id="@+id/shareShort"
android:layout_width="230dp"
android:layout_height="50dp"
android:text="Share short App Linking"
android:textAllCaps="false"
android:textSize="19sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
</ScrollView>
App Gallery Integration process
Sign In and Create or Choose a project on AppGallery Connect portal.
Navigate to Project settings and download the configuration file.
Navigate to General Information, and then provide Data Storage location.
Navigate to Manage APIs and enable APIs which is required by application.
Navigate to AppLinking and Enable.
Add New link.
Navigate to App Linking and select Set domain name.
Copy Domain Name and add in your project.
App Build Result
Tips and Tricks
Since HUAWEI Analytics Kit 4.0.3.300, the SDK for Android has been significantly improved in the stability, security, and reliability. If the SDK you have integrated is earlier than 4.0.3.300, please upgrade it to 4.0.3.300 or later before April 30, 2021. From May 1, 2021, HUAWEI Analytics will not receive data reported by SDK versions earlier than 4.0.3.300. If you have integrated App Linking, you also need to upgrade its SDK to 1.4.1.300 or later for Android before April 30, 2021. Otherwise, functions that depend on HUAWEI Analytics will become unavailable.
Huawei strictly conforms to the General Data Protection Regulation (GDPR) in providing services and is dedicated to helping developers achieve business success under the principles of the GDPR. The GDPR stipulates the obligations of the data controller and data processor. When using our service, you act as the data controller, and Huawei is the data processor. Huawei solely processes data within the scope of the data processor's obligations and rights, and you must assume all obligations of the data controller as specified by the GDPR.
Conclusion
In this article, we have learned how to integrate AppLinking in application. In this application, I have explained that how to deep link our application with URL.
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 AppLinking Doc: Link
Original Source

Related

Intermediate: OneSignal Email APIs Integration in Xamarin (Android)

Overview
In this article, I will create a demo app along with the integration of OneSignal Email APIs which is based on Cross platform Technology Xamarin. It provides an easy-to-use email building interface that allow user to construct fantastic templates for all your emails.
OneSignal Service Introduction
OneSignal supports email as a messaging channel to provide you with more ways to reach users.
Single SDK- User won't need to manage separate SDKs for email and push, and it will be able to use the same familiar methods and syntax that already used for push.
Single API - User can use the same APIs, segments, and other features that may use for push notifications to send your emails as well.
Prerequisite
1. Xamarin Framework
2. Huawei phone
3. Visual Studio 2019
4. OneSignal Account
App Gallery Integration process
1. Sign In and Create or Choose a project on AppGallery Connect portal.
{
"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"
}
2. Navigate to Project settings and download the configuration file.
3. Navigate to General Information, and then provide Data Storage location.
OneSignal SDK Integration process
1. Choose Huawei Android (HMS) and provide app name.
2. Choose Xamarin then click Next: Install and Test.
3. Copy your App Id.
4. Navigate to One Signal’s Dashboard > Messages > New Email.
5. Enter Email Details.
Installing the Huawei ML NuGet package
1. Navigate to Solution Explore > Project > Right Click > Manage NuGet Packages.
2. Search on Browser Com.OneSignal and Install the package.
Xamarin App Development
1. Open Visual Studio 2019 and Create A New Project.
2. Configure Manifest file and add following permissions and tags.
Code:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="com.hms.onesignalemail">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" ></uses-sdk>
<permission android:name="${applicationId}.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<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">
<receiver android:name="com.onesignal.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
3. Create Activity class with XML UI.
MainActivity.cs
This activity performs email send operation with help of OneSignal’s Email APIs.
Code:
using System;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Support.Design.Widget;
using Android.Support.V7.App;
using Android.Views;
using Android.Widget;
using Com.OneSignal;
using Com.OneSignal.Abstractions;
namespace OneSignalDemo
{
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme.NoActionBar", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
private Android.App.AlertDialog sendingDialog;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
SetContentView(Resource.Layout.activity_main);
Android.Support.V7.Widget.Toolbar toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
Button button = FindViewById<Button>(Resource.Id.buttonSend);
button.Click += delegate {
ShowProgressBar("Sending Email");
};
}
public void sendEmail()
{
OneSignal.Current.SetEmail("[email protected]");
string email = "[email protected]";
string emailAuthHash = null; // Auth hash generated from your server
OneSignal.Current.SetEmail(email, emailAuthHash, () => {
//Successfully set email
}, (error) => {
//Encountered error setting email
});
}
public void logoutEmail()
{
OneSignal.Current.LogoutEmail();
// Optionally, you can also use callbacks
OneSignal.Current.LogoutEmail(() => {
//handle success
}, (error) => {
//handle failure
});
}
private void setUpOneSignal()
{
OneSignal.Current.SetLogLevel(LOG_LEVEL.VERBOSE, LOG_LEVEL.NONE);
OneSignal.Current.StartInit("83814abc-7aad-454a-9d20-34e3681efcd1")
.InFocusDisplaying(OSInFocusDisplayOption.Notification)
.EndInit();
}
public void ShowProgressBar(string message)
{
Android.App.AlertDialog.Builder dialogBuilder = new Android.App.AlertDialog.Builder(this);
var inflater = (LayoutInflater)GetSystemService(Context.LayoutInflaterService);
var dialogView = inflater.Inflate(Resource.Layout.dialog, null);
dialogBuilder.SetView(dialogView);
dialogBuilder.SetCancelable(false);
var tvMsg = dialogView.FindViewById<TextView>(Resource.Id.tvMessage);
tvMsg.Text = message;
sendingDialog = dialogBuilder.Create();
sendingDialog.Show();
}
public void HideProgressBar()
{
if (sendingDialog != null)
{
sendingDialog.Dismiss();
}
}
public override bool OnCreateOptionsMenu(IMenu menu)
{
MenuInflater.Inflate(Resource.Menu.menu_main, menu);
return true;
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
int id = item.ItemId;
if (id == Resource.Id.action_settings)
{
return true;
}
return base.OnOptionsItemSelected(item);
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
email_activity.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main">
<TextView
android:text="Recipient Email"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/editTextEmail" />
<TextView
android:text="Subject"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/editTextSubject" />
<TextView
android:text="Message"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:lines="4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/editTextMessage" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/buttonSend"
android:text="Send"/>
</LinearLayout>
sent_activity.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main">
<ImageView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerInParent="true"
android:src="@drawable/ok"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="30sp
"
android:gravity="center"
android:text="Email Sent Successfully" />
</LinearLayout>
progress_dialog.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<TableRow
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ProgressBar
android:id="@+id/progressbar"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
<TextView
android:gravity="center|left"
android:id="@+id/tvMessage"
android:layout_width="match_parent"
android:text="Sending Email"
android:layout_height="match_parent"
android:layout_marginLeft="16dp" />
</TableRow>
</RelativeLayout>
Xamarin App Build Result
1. Navigate to Build > Build Solution.
2. Navigate to Solution Explore > Project > Right Click > Archive/View Archive to generate SHA-256 for build release and Click on Distribute.
3. Choose Archive > Distribute.
4. Choose Distribution Channel > Ad Hoc to sign apk.
5. Choose Demo keystore to release apk.
6. Build succeed and click Save.
7. Result.
Tips and Tricks
1. OneSignal does not act as its own email service provider, you will need to sign up for one.
2. Email and push subscribers will have separate OneSignal Player IDs. This is to manage the case where a user opts-out of one you can still send them messages to the other.
3. To configure email, you will need to modify your domain's DNS records. Different email service providers have different requirements for which records need modifying, which likely include MX, CNAME, and TXT types.
Conclusion
In this article, we have learned how to integrate OneSignal Push Notification in Xamarin based Android application. Developer can send OneSignal’s Push Message to users for new updates or any other information.
Thanks for reading this article. Be sure to like and comment to this article, if you found it helpful. It means a lot to me.
References
OneSignal Email API https://documentation.onesignal.com/docs/email-overview
Original Source

Expert: BestPal (Chatting) application using Huawei CloudDB, Auth service, Cloud Function, Location, Site, Map and Push Kits - Part 2

{
"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"
}
In previous article, we have developed one to one text sending application. Now in this article, we will work on sent location in chat.
Previous article link: https://forum.xda-developers.com/t/...-service-cloud-function-and-push-kit.4398203/
Huawei Kits Used​
Huawei Cloud DB
Huawei Auth Service
Huawei Cloud function.
Huawei Push Kit
Location kit
Site kit
Map kit
Huawei API Used​
Huawei Cloud Storage - Cloud storage is used to store users files like user profile image and images shared on the chat. Once files are uploaded successfully on storage we get the downloadable URL will act like the profile URL or the image content.
Huawei CloudDB API - Cloud DB is used to store users data, users chat and also used to manage users chat history with other users.
a) Upsert
i) Insert data of the users from the profile.
ii) Create and insert room id, room id is consider as a reference between two users chat. Using room id we will store all the respective chat data in the DB.
iii) Insert Chat data between two users based on the room id.
b) Query
i) Get list of Contacts for chat.
ii) Get list of user with whom logged in user chatted before.
ii) Get details of the chat screen with all the chat messages which include, images, text and location.
3.Huawei Auth Service – Using the Auth Service we are registering the user on the Ecosystem. We are using the Phone number auth service for the same to receive the OTP and verify the user here.
4.Huawei Cloud function – We are triggering the Huawei Push notification system using cloud function for the same.
5.Huawei Location kit - Using location kit we will get users current location, so that they can share with other users. Using the same location co-ordinate, we will try to receive the nearby service shows the nearby landmark.
6.Huawei Map kit –
a. Map kit is used to show users shared location and nearby landmarks on the map.
b. Static Map Query after the getting the location we will query the map static with the marker and create the link and upload that link to the webview to show the current location being shared.
7.Huawei Site Kit –To show the landmark on the map which can be shared with different users at the given time of request for this we have used the nearby service from the site kit.
8.Huawei Push kit - Push kit is used to push notification of message to other user. So when one user send message we will notify other user via push notification only.
Used the rest end point for the cloud function to send the push notification once the message is end trigger from the device.
On HMSMessage Received This is once parsing the data as per our need on the implementation wherein we will need to parse and image and location when shared by other success.
Let’s start send location in chat
Enable Location Kit , Site Kit and Map Kit on console as shown in below image.
Add dependencies
Code:
// HMS dependencies
implementation "com.huawei.hms:site:$rootProject.ext.sitekit"
implementation "com.huawei.hms:maps:$rootProject.ext.mapkit"
implementation "com.huawei.hms:location:$rootProject.ext.locationkit"
Add run time location permission
Java:
private boolean checkLocationPermission() {
int location_permission = ContextCompat.checkSelfPermission(this.getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION);
int course_permission = ContextCompat.checkSelfPermission(this.getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION);
return location_permission == PackageManager.PERMISSION_GRANTED && course_permission == PackageManager.PERMISSION_GRANTED;
}
Let's design the page
We divided page into two parts one is for map view and other half is for showing nearby places.
XML
XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="2">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight=".15"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageLocation"
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:padding="5dp"
android:src="@drawable/ic_baseline_arrow_back" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_centerVertical="true"
android:text="@string/send_loc"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<ImageView
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_marginEnd="10dp"
android:padding="5dp"
android:src="@drawable/hwsearchview_ic_public_input_search"
android:visibility="gone" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight=".8"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.huawei.hms.maps.MapView xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:cameraTargetLat="51"
map:cameraTargetLng="10"
map:cameraZoom="8.5"
map:mapType="normal"
map:uiCompass="true"
map:uiZoomControls="true" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btnHospital"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:text="@string/btnHospital" />
<Button
android:id="@+id/btnAtm"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/btnHospital"
android:layout_weight="1"
android:text="@string/btnAtm" />
<Button
android:id="@+id/btnPetrolBunk"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/btnAtm"
android:layout_weight="1"
android:text="@string/btnPetrol" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.05"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_gravity="bottom"
android:background="#D3D3D3"
android:gravity="center_vertical"
android:paddingStart="5dp"
android:text="@string/nearby_places"
android:textColor="@color/black"
android:textSize="16sp" />
<RelativeLayout
android:id="@+id/rlSendCurrentLocation"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginStart="20dp"
android:paddingStart="5dp">
<ImageView
android:id="@+id/currentlocation_icon_iv"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerVertical="true"
android:scaleType="fitXY"
android:src="@drawable/ic_baseline_location"
android:tint="@color/colorPrimary"
tools:ignore="UseAppTint" />
<TextView
android:id="@+id/currnet_location_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="8dp"
android:layout_toEndOf="@id/currentlocation_icon_iv"
android:text="@string/send_location"
android:textColor="@color/black"
android:textSize="18sp" />
<TextView
android:id="@+id/currnet_location_accurecy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/currnet_location_title"
android:layout_marginStart="10dp"
android:layout_marginTop="1dp"
android:layout_toEndOf="@id/currentlocation_icon_iv"
android:text="@string/accuracy"
android:textColor="@color/grey"
android:textSize="14sp" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvNearByLocation"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/response_text_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="true" />
</LinearLayout>
</LinearLayout>
It's time to start coding
Get Current location
Java:
FusedLocationProviderClient mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context);
SettingsClient mSettingsClient = LocationServices.getSettingsClient(context);
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mFusedLocationProviderClient.getLastLocation().addOnSuccessListener(location -> {
AppLog.logD(TAG,
"Lat long--->Fushed" + location.getLongitude()
+ "," + location.getLatitude() + "," + location.getAccuracy());
if (location != null) {
locationMutableLiveData.postValue(location);
}
}).addOnFailureListener(e -> {
AppLog.logE(TAG, "error" + e);
Toast.makeText(context, "Location not found", Toast.LENGTH_SHORT).show();
});
Get Nearby location
Java:
public void getNearbyData(double latitude, double longitude, SearchService searchService, String locationType) {
NearbySearchRequest request = new NearbySearchRequest();
Coordinate location = new Coordinate(latitude, longitude);
request.setLocation(location);
request.setQuery(locationType);
request.setRadius(5);
request.setHwPoiType(HwLocationType.ADDRESS);
request.setLanguage("en");
request.setPageIndex(1);
request.setPageSize(10);
request.setStrictBounds(false);
SearchResultListener<NearbySearchResponse> resultListener = new SearchResultListener<NearbySearchResponse>() {
@Override
public void onSearchResult(NearbySearchResponse results) {
arrayListMutableLiveData.postValue(new ArrayList<>(results.getSites()));
}
@Override
public void onSearchError(SearchStatus status) {
AppLog.logE("TAG", "Error : " + status.getErrorCode() + " " + status.getErrorMessage());
}
};
searchService.nearbySearch(request, resultListener);
}
Set up Map and showing nearby places
Java:
@Override
public void onMapReady(HuaweiMap huaweiMap) {
hMap = huaweiMap;
hMap.setMyLocationEnabled(true);
hMap.getUiSettings().setMyLocationButtonEnabled(true);
Util.showProgressBar(LocationActivity.this);
locationViewModel.getCurrentLocation(LocationActivity.this);
locationViewModel.locationMutableLiveData.observe(LocationActivity.this, location -> {
if (location != null) {
this.location = location;
updateDetails(location);
}
});
locationViewModel.arrayListMutableLiveData.observe(LocationActivity.this, this::recyclerView);
}
private void updateDetails(Location location) {
float zoom = 14.0f;
LatLng latLng1 = new LatLng(location.getLatitude(), location.getLongitude());
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng1, zoom);
hMap.animateCamera(cameraUpdate);
currentLocationAccuracy.setText(String.format("Accurate to %s meters", location.getAccuracy()));
locationViewModel.getNearbyData(location.getLatitude(), location.getLongitude(), searchService, Constants.LOCATION_TYPE_HOSPITAL);
}
Send chat massage
Java:
private void setMessage(String messageType) {
ChitChatSharedPref.initializeInstance(MessageActivity.this);
Util.showProgressBar(MessageActivity.this);
UserChat userChat = new UserChat();
userChat.setRoom_id(roomId);
userChat.setMessage_timestamp(Long.parseLong(Util.getTimeStamp()));
userChat.setChat_id(Util.getRandomNumber());
userChat.setReceiver_name(receiverText);
userChat.setReceiver_phone(receiverPhoneNumber);
userChat.setSender_name(ChitChatSharedPref.getInstance().getString(Constants.USER_NAME, ""));
userChat.setSender_phone(ChitChatSharedPref.getInstance().getString(Constants.PHONE_NUMBER, ""));
userChat.setMessage_type(messageType);
switch (messageType) {
case Constants.MESSAGE_TYPE_MAP:
userChat.setMessage_data(jsonMapModel);
messageViewModel.saveUserChat(userChat);
messageViewModel.userUpdatedSuccessfully.observe(MessageActivity.this, aBoolean -> {
if (aBoolean) {
Util.stopProgressBar();
getChatList();
Toast.makeText(MessageActivity.this, getString(R.string.showMessageSuccess), Toast.LENGTH_SHORT).show();
} else {
Util.stopProgressBar();
Toast.makeText(MessageActivity.this, getString(R.string.showMessageFailed), Toast.LENGTH_SHORT).show();
}
});
break;
case Constants.MESSAGE_TYPE_TEXT:
userChat.setMessage_data(textSend.getText().toString());
messageViewModel.saveUserChat(userChat);
messageViewModel.userUpdatedSuccessfully.observe(MessageActivity.this, aBoolean -> {
if (aBoolean) {
Util.stopProgressBar();
getChatList();
} else {
Util.stopProgressBar();
}
});
break;
}
messageViewModel.queryForToken(receiverPhoneNumber, MessageActivity.this);
}
Send push notification
Java:
PushApis pushApis = new PushApis(MessageActivity.this);
if (messageType.equalsIgnoreCase(Constants.MESSAGE_TYPE_MAP)) {
pushApis.sendPushNotification(roomId, messageType, "104739093", jsonMapModel, s);
} else if (messageType.equalsIgnoreCase(Constants.MESSAGE_TYPE_TEXT)) {
pushApis.sendPushNotification(roomId, messageType, "104739093", MessageActivity.this.textSend.getText().toString(), s);
textSend.setText("");
}
Conclusion
In this article, we have learned how we can create a simple messaging application with Cloud DB, Auth Service, Push Kit , Location Kit , Site Kit and Map Kit. We can also use cloud storage to store profile picture, location, documents or audio and video files.
Thanks for reading this article. Be sure to like and comment to this article, if you found it helpful. It means a lot to me.
Reference
https://developer.huawei.com/consumer/en/agconnect/cloud-base/
https://developer.huawei.com/consum...-Guides/service-introduction-0000001050040060
https://developer.huawei.com/consumer/en/hms/huawei-locationkit/
https://developer.huawei.com/consumer/en/hms/huawei-MapKit/
https://developer.huawei.com/consumer/en/hms/huawei-sitekit/

Manage the Budget using Room Database in Money Management Android app (Kotlin) – Part 3

{
"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 can learn how to manage your money using this Money Management app. User can add Income and Expenses in this app, so the data will be saved in room database, it can access in offline also. User can easily track their daily spending's and can take the preventive actions on the unnecessary expenses, so that they can save money and can invest in profitable return ways. In this app, user can add, update, delete and fetch operations.
So, I will provide the series of articles on this Money Management App, in upcoming articles I will integrate other Huawei Kits.
If you are new to this application, follow my previous articles.
Beginner: Find the introduction Sliders and Huawei Account Kit Integration in Money Management Android app (Kotlin) - Part 1
Beginner: Integration of Huawei Ads Kit and Analytics Kit in Money Management Android app (Kotlin) – Part 2
Components of Room DB
1. Entity
2. Dao
3. Database
1. Entity
Represents a table within the database. Room creates a table for each class that has @entity annotation, the fields in the class correspond to columns in the table. Therefore, the entity classes tend to be small model classes that does not contain any logic.
2. Dao
DAOs(Data Access Objects) are responsible for defining the methods that access the database. In the initial SQLite, we use the Cursor objects. With Room, we do not need all the Cursor related code and can simply define our queries using annotations in the Dao class.
3. Database
Contains the database holder and serves as the main access point for the underlying connection to your app's persisted, relational data.
To create a database, we need to define an abstract class that extends RoomDatabase. This class is annotated with @database, lists the entities contained in the database, and the DAOs which access them.
Requirements
1. Any operating system (MacOS, Linux and Windows).
2. Must have a Huawei phone with HMS 4.0.0.300 or later.
3. Must have a laptop or desktop with Android Studio, Jdk 1.8, SDK platform 26 and Gradle 4.6 and above installed.
4. Minimum API Level 24 is required.
5. Required EMUI 9.0.0 and later version devices.
How to integrate HMS Dependencies
1. First register as Huawei developer and complete identity verification in Huawei developers website, refer to register a Huawei ID.
2. Create a project in android studio, refer Creating an Android Studio Project.
3. Generate a SHA-256 certificate fingerprint.
4. To generate SHA-256 certificate fingerprint. On right-upper corner of android project click Gradle, choose Project Name > Tasks > android, and then click signingReport, as follows.
Note: Project Name depends on the user created name.
5. Create an App in AppGallery Connect.
6. Download the agconnect-services.json file from App information, copy and paste in android Project under app directory, as follows.
7. Enter SHA-256 certificate fingerprint and click Save button, as follows.
Note: Above steps from Step 1 to 7 is common for all Huawei Kits.
8. Add the below maven URL in build.gradle(Project) file under the repositories of buildscript, dependencies and allprojects, refer Add Configuration.
Java:
maven { url 'http://developer.huawei.com/repo/' }
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
9. Add the below plugin and dependencies in build.gradle(Module) file.
Java:
apply plugin: id 'com.huawei.agconnect'
apply plugin: id 'kotlin-kapt'
// Huawei AGC
implementation 'com.huawei.agconnect:agconnect-core:1.6.0.300'
// Room Database
implementation "androidx.room:room-runtime:2.4.2"
kapt "androidx.room:room-compiler:2.4.2"
implementation "androidx.room:room-ktx:2.4.2"
androidTestImplementation "androidx.room:room-testing:2.4.2"
// Lifecycle components
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
// Recyclerview
implementation 'androidx.recyclerview:recyclerview:1.2.1'
10. Now Sync the gradle.
Let us move to development
I have created a project on Android studio with empty activity let us start coding.
Create a Transaction.kt class annotated with @entity to create a table for each class.
Java:
@Entity(tableName = "transactions")
data class Transaction(
@PrimaryKey(autoGenerate = true)
val id: Int,
val label: String,
val amount: Double,
val description: String): Serializable{}
Create a TransactionDao o.kt interface class annotated with @dao and responsible for defining the methods that access the database.
Java:
@Dao
interface TransactionDao {
@Query("SELECT * from transactions")
fun getAll(): List<Transaction>
@Insert
fun insertAll(vararg transaction: Transaction)
@Delete
fun delete(vararg transaction: Transaction)
@Update
fun update(vararg transaction: Transaction)
}
Create a AppDatabase.kt abstract class that extends RoomDatabase annotated with @database to lists the entities contained in the database, and the DAOs which access them.
Java:
@Database(entities = [Transaction::class], version = 2)
abstract class AppDatabase : RoomDatabase() {
abstract fun transactionDao(): TransactionDao
}
In the TransactionActivity.kt activity to find the business logic for entire dashboard.
Java:
class TransactionActivity : AppCompatActivity() {
private lateinit var deletedTransaction: Transaction
private lateinit var oldtransactions: List<Transaction>
private lateinit var transactions: List<Transaction>
private lateinit var transactionAdapter: TransactionAdapter
private lateinit var linearLayoutManager: LinearLayoutManager
private lateinit var db: AppDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_transcation)
transactions = arrayListOf()
transactionAdapter = TransactionAdapter(transactions)
linearLayoutManager = LinearLayoutManager(this)
trans_recycler_view.apply {
adapter = transactionAdapter
layoutManager = linearLayoutManager
}
// Swipe to remove
val itemTouchHelper = object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT){
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
deleteTransaction(transactions[viewHolder.adapterPosition])
}
}
val swipeHelper = ItemTouchHelper(itemTouchHelper)
swipeHelper.attachToRecyclerView(trans_recycler_view)
btn_float.setOnClickListener {
val intent = Intent(this, AddTransactionActivity::class.java)
startActivity(intent)
}
// Room database
db = Room.databaseBuilder(this,AppDatabase::class.java,"transactions").build()
}
@SuppressLint("SetTextI18n")
private fun updateAmount(){
val totalAmount: Double = transactions.map {it.amount}.sum()
val budgetAmount: Double = transactions.filter {it.amount > 0}.map {it.amount}.sum()
val expenseAmount: Double = totalAmount - budgetAmount
balance.text = "RS %.2f".format(totalAmount)
budget.text = "RS %.2f".format(budgetAmount)
expense.text = "RS %.2f".format(expenseAmount)
}
// Fetch Transactions form Room Database
private fun fetchAll(){
GlobalScope.launch {
transactions = db.transactionDao().getAll()
runOnUiThread {
updateAmount()
transactionAdapter.setData(transactions)
}
}
}
private fun deleteTransaction(transaction: Transaction){
deletedTransaction = transaction
oldtransactions = transactions
GlobalScope.launch {
db.transactionDao().delete(transaction)
transactions = transactions.filter {it.id != transaction.id}
runOnUiThread {
updateAmount()
transactionAdapter.setData(transactions)
}
}
Toast.makeText(this, "Item Deleted", Toast.LENGTH_SHORT).show()
}
override fun onResume() {
super.onResume()
fetchAll()
}
}
Create a TransactionAdapter.kt adapter class to hold the list.
Java:
class TransactionAdapter(private var transactions: List<Transaction>):
RecyclerView.Adapter<TransactionAdapter.TransactionViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.transcation_list, parent, false)
return TransactionViewHolder(itemView)
}
override fun onBindViewHolder(holder: TransactionViewHolder, position: Int) {
val transaction: Transaction = transactions[position]
val context: Context = holder.amount.context
if(transaction.amount >= 0){
holder.amount.text = " RS %.2f".format(transaction.amount)
holder.amount.setTextColor(ContextCompat.getColor(context,R.color.Green))
} else {
holder.amount.text = " RS %.2f".format(transaction.amount)
holder.amount.setTextColor(ContextCompat.getColor(context,R.color.Red))
}
holder.label.text = transaction.label
holder.itemView.setOnClickListener {
val intent = Intent(context, DetailedActivity::class.java)
intent.putExtra("transaction", transaction)
context.startActivity(intent)
}
}
override fun getItemCount(): Int {
return transactions.size
}
inner class TransactionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val label: TextView = itemView.findViewById(R.id.txt_label)
val amount: TextView = itemView.findViewById(R.id.txt_amount)
}
fun setData(transactions: List<Transaction>){
this.transactions = transactions
notifyDataSetChanged()
}
}
In the AddTransactionActivity.kt activity to find the business logic to add items.
Java:
class AddTransactionActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_transaction)
btn_add.setOnClickListener {
val label = edt_label.text.toString()
val amount = edt_amount.text.toString().toDoubleOrNull()
val description = edt_desc.text.toString()
if(label.isBlank()) {
Toast.makeText(this, "Enter the label", Toast.LENGTH_SHORT).show()
}
else if(amount == null) {
Toast.makeText(this, "Enter the valid amount", Toast.LENGTH_SHORT).show()
}
else {
val transaction = Transaction(0, label, amount, description)
insert(transaction)
Toast.makeText(this, "Saved Content", Toast.LENGTH_SHORT).show()
}
}
}
private fun insert(transaction: Transaction) {
val db: AppDatabase = Room.databaseBuilder(this,AppDatabase::class.java,"transactions").build()
GlobalScope.launch {
db.transactionDao().insertAll(transaction)
finish()
}
}
}
In the DetailedActivity.kt activity to find the business logic for updating the items.
Java:
class DetailedActivity : AppCompatActivity() {
private lateinit var transaction: Transaction
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detailed)
transaction = intent.getSerializableExtra("transaction") as Transaction
update_label.setText(transaction.label)
update_amount.setText(transaction.amount.toString())
btn_update.setOnClickListener {
val label = update_label.text.toString()
val amount = update_amount.text.toString().toDoubleOrNull()
val description = update_desc.text.toString()
if(label.isBlank()) {
Toast.makeText(this, "Enter the label", Toast.LENGTH_SHORT).show()
}
else if(amount == null) {
Toast.makeText(this, "Enter the valid amount", Toast.LENGTH_SHORT).show()
}
else {
val transaction = Transaction(transaction.id, label, amount, description)
update(transaction)
Toast.makeText(this, "Saved Content", Toast.LENGTH_SHORT).show()
}
}
}
private fun update(transaction: Transaction) {
val db: AppDatabase = Room.databaseBuilder(this,AppDatabase::class.java,"transactions").build()
GlobalScope.launch {
db.transactionDao().update(transaction)
finish()
}
}
}
In the activity_transcation.xml we can create the UI screen for Dashboard.
XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".room.TransactionActivity">
<LinearLayout
android:id="@+id/balance_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_marginStart="10dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Total Balance:"
android:textAllCaps="false"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/balance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RS.xx"
android:textColor="@color/black"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
app:cardCornerRadius="12dp"
android:layout_below="@+id/balance_layout">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="0.5"
android:layout_gravity="center">
<TextView
android:id="@+id/budget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RS.xx"
android:textAllCaps="false"
android:textSize="24sp"
android:textColor="@color/Green"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Budget "
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center"
android:layout_weight="0.5">
<TextView
android:id="@+id/expense"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RS.xx"
android:textColor="@color/Red"
android:textAllCaps="false"
android:textSize="24sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Expense "
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Transcations"
android:textAllCaps="false"
android:textSize="18sp"
android:layout_marginTop="14dp"
android:layout_marginStart="10dp"
android:layout_below="@+id/cardview"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/trans_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/title"
android:layout_marginTop="10dp"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btn_float"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:backgroundTint="@color/Red"
android:clickable="true"
android:contentDescription="TODO"
app:borderWidth="0dp"
app:srcCompat="@android:drawable/ic_input_add" />
</RelativeLayout>
In the activity_add_transaction.xml we can create the UI screen for adding items.
XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".room.AddTransactionActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:ignore="MissingConstraints">
<EditText
android:id="@+id/edt_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:hint="Label "
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/edt_amount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Amount: "
android:inputType="numberSigned"
app:layout_constraintTop_toBottomOf="@id/edt_label" />
<EditText
android:id="@+id/edt_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Description: "
app:layout_constraintTop_toBottomOf="@id/edt_amount" />
<Button
android:id="@+id/btn_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:textSize="18sp"
android:layout_gravity="center"
android:text="Add"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/edt_desc" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
In the activity_detailed.xml we can create the UI screen for updating items.
XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".room.DetailedActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:ignore="MissingConstraints">
<EditText
android:id="@+id/update_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:hint="Label "
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/update_amount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Amount: "
android:inputType="numberSigned"
app:layout_constraintTop_toBottomOf="@id/edt_label" />
<EditText
android:id="@+id/update_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Description: "
app:layout_constraintTop_toBottomOf="@id/edt_amount" />
<Button
android:id="@+id/btn_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:textSize="18sp"
android:layout_gravity="center"
android:text="Update"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/edt_desc" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
In the transcation_list.xml we can create the UI screen for customized items.
XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="center_vertical">
<TextView
android:id="@+id/txt_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Food"
android:textAllCaps="false"
android:layout_marginStart="6dp"
android:textSize="20sp"
android:layout_weight="1"/>
<TextView
android:id="@+id/txt_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RS.12"
android:layout_marginEnd="12dp"
android:textSize="20sp"/>
</LinearLayout>
Demo
Tips and Tricks
1. Make sure you are already registered as Huawei developer.
2. Set minSDK version to 24 or later, otherwise you will get AndriodManifest merge issue.
3. Make sure you have added the agconnect-services.json file to app folder.
4. Make sure you have added SHA-256 fingerprint without fail.
5. Make sure all the dependencies are added properly.
Conclusion
In this article, we have learned the integration of Room database.
We, have learnt about the room database and its components such as DAO, Entity and Database. How to create, read, update and delete the content in room database and which helps the user to access the data when they are in offline.
I hope you have read this article. If you found it is helpful, please provide likes and comments.
Reference
Room Database
Find the Original document - https://forums.developer.huawei.com/forumPortal/en/topic/0202860048259200218?fid=0101187876626530001

Expert: Courier App MVVM Jetpack (HMS Push Kit Uplink Message) in Android using Kotlin- Part-4

Overview
In this article, I will create a Courier android application using Kotlin in which I will integrate HMS Core kits such as HMS Account, Push, CloudDB, AuthService and Push Kit Uplink Message.
We have integrated HMS Account and AuthService Kit in part-1 and Push Notification Using HMS Push Kit in Part-2 and Cloud DB Kit in Part-3 of this series. Kindly go through the link below-
Part-1 https://forums.developer.huawei.com/forumPortal/en/topic/0202841957497640128
Part-2 https://forums.developer.huawei.com/forumPortal/en/topic/0201847982965230092
part-3 https://forums.developer.huawei.com/forumPortal/en/topic/0201854022878900124?fid=0101187876626530001
App will make use of android MVVM clean architecture using Jetpack components such as DataBinding, AndroidViewModel, Observer, LiveData and much more.
In this article, we are going to implement DataBinding using Observable pattern.
Huawei Push Kit Introduction
Push Kit is a messaging service provided by Huawei for developers. Push Kit establishes a messaging channel from the cloud to devices. By integrating HUAWEI Push Kit, developers can send messages to apps on users’ devices in real time. Push Kit helps developers rapidly to reach the target audience. Push notification can be sent to everyone or to a specific person individually. For send notification, user’s token is required. You can send messages to a device group or specific user. Push Kit has two different notification type. Text only style (Shows longer text messages) and big picture style (Shows large text and image messages).
Prerequisite
Huawei Phone EMUI 3.0 or later.
Non-Huawei phones Android 4.4 or later (API level 19 or higher).
HMS Core APK 4.0.0.300 or later
Android Studio
AppGallery Account
App Gallery Integration process
Sign In and Create or Choose a project on AppGallery Connect portal.
Navigate to Project settings and download the configuration file.
Navigate to General Information, and then provide Data Storage location.
App Development
Add Required Dependencies:
Launch Android studio and create a new project. Once the project is ready.
Navigate to the Gradle scripts folder and open build.gradle (module: app).
Code:
//HMS Kits
implementation 'com.huawei.agconnect:agconnect-core:1.5.0.300'
implementation 'com.huawei.hms:hwid:5.3.0.302'
implementation 'com.huawei.hms:push:4.0.3.301'
implementation 'com.huawei.agconnect:agconnect-cloud-database:1.5.0.300'
implementation "com.huawei.agconnect:agconnect-auth-huawei:1.6.0.300"
implementation 'com.huawei.agconnect:agconnect-auth:1.5.0.300'
Navigate to the Gradle scripts folder and open build.gradle (project: app).
Code:
ext.kotlin_version = "1.4.21"
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
classpath "com.android.tools.build:gradle:4.0.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.huawei.agconnect:agcp:1.4.2.300'
Code Implementation
Created following package model, push, viewmodel.
Model: In your primary folder, create a new package and name it model.
ShippingCheckoutActivity:
Code:
package com.hms.corrierapp
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.hms.corrierapp.databinding.ActivityAddressBinding
import com.hms.corrierapp.push.*
import com.huawei.agconnect.config.AGConnectServicesConfig
import com.huawei.hms.aaid.HmsInstanceId
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class ShippingCheckoutAddressActivity : AppCompatActivity() {
private lateinit var pushToken: String
private var accessToken: String? = null
private lateinit var binding: ActivityAddressBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_address)
getToken()
getAccessToken()
binding.btnCheckout.setOnClickListener {
sendNotification(pushToken)
}
}
private fun getToken() {
object : Thread() {
override fun run() {
try {
val appId: String =
AGConnectServicesConfig.fromContext([email protected])
.getString("client/app_id")
pushToken =
HmsInstanceId.getInstance([email protected])
.getToken(appId, "HCM")
if (!TextUtils.isEmpty(pushToken)) {
Log.i("Push", "get token:$pushToken")
}
} catch (e: Exception) {
Log.i("Push", "getToken failed, $e")
}
}
}.start()
}
private fun getAccessToken() {
AccessTokenClient.getClient().create(AccessTokenInterface::class.java)
.createAccessToken(
"client_credentials",
"a3c3072ecb38e7c58f3ad8ee48ed5a8e31a2f6bcddf5c094a00329fdd77c8f50",
"105919003"
)
.enqueue(object : Callback<AccessTokenModel> {
override fun onFailure(call: Call<AccessTokenModel>, t: Throwable) {
Log.d("Push", "ERROR : " + t.message)
}
override fun onResponse(
call: Call<AccessTokenModel>,
response: Response<AccessTokenModel>
) {
if (response.isSuccessful) {
Log.d("Push", "Token " + response.body()?.access_token)
accessToken = response.body()?.access_token
}
}
})
}
private fun sendNotification(pushToken: String) {
val notifMessageBody: NotificationMessageBody = NotificationMessageBody.Builder(
"Your Courier is Booked", "We will notify you once your courier dispatch",
arrayOf(pushToken)
)
.build()
NotificationClient.getClient().create(NotificationInterface::class.java)
.createNotification(
"Bearer $accessToken",
notifMessageBody
)
.enqueue(object : Callback<NotificationMessageModel> {
override fun onFailure(call: Call<NotificationMessageModel>, t: Throwable) {
Log.d("Push", "ERROR : " + t.message)
}
override fun onResponse(
call: Call<NotificationMessageModel>,
response: Response<NotificationMessageModel>
) {
if (response.isSuccessful) {
Log.d("Push", "Response " + response.body())
Toast.makeText(
[email protected],
"Sent For Track",
Toast.LENGTH_SHORT
)
.show()
}
}
})
}
}
activity_shipping_checkout_activity:
Code:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="addressViewmODEL"
type="com.hms.corrierapp.viewmodel.AddressViewModel" />
</data>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/profileLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="20dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="@string/fill_shipping"
android:textAlignment="center"
android:textColor="@color/colorPrimaryDark"
android:textSize="34sp"
android:textStyle="bold" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:textColor="@color/colorPrimaryDark">
<EditText
android:id="@+id/fullNameEdt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Full Name"
android:imeOptions="actionNext"
android:singleLine="true"
android:textSize="14sp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:textColor="@color/colorPrimaryDark">
<EditText
android:id="@+id/mobEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Mobile Number *"
android:imeOptions="actionNext"
android:inputType="number"
android:paddingLeft="6dp"
android:singleLine="true"
android:textSize="14sp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:textColor="@color/colorPrimaryDark">
<EditText
android:id="@+id/cityEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="City *"
android:imeOptions="actionNext"
android:paddingLeft="6dp"
android:singleLine="true"
android:textSize="14sp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:textColor="@color/colorPrimaryDark">
<EditText
android:id="@+id/areaEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Locality, area or street *"
android:imeOptions="actionNext"
android:paddingLeft="6dp"
android:singleLine="true"
android:textSize="14sp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:textColor="@color/colorPrimaryDark">
<EditText
android:id="@+id/buildingEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Flat no., Building name *"
android:imeOptions="actionNext"
android:paddingLeft="6dp"
android:singleLine="true"
android:textSize="14sp" />
</com.google.android.material.textfield.TextInputLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/relativeLayout2"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:paddingLeft="6dp">
<EditText
android:id="@+id/pincodeEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Pincode *"
android:imeOptions="actionNext"
android:inputType="number"
android:paddingLeft="6dp"
android:singleLine="true"
android:textSize="14sp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginLeft="52dp"
android:layout_toRightOf="@+id/relativeLayout2">
<EditText
android:id="@+id/stateEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="State *"
android:imeOptions="actionNext"
android:singleLine="true"
android:textSize="14sp"
/>
</com.google.android.material.textfield.TextInputLayout>
</RelativeLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="6dp"
android:paddingRight="6dp">
<EditText
android:id="@+id/landmarkEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Landmark(Optional)"
android:imeOptions="actionDone"
android:paddingLeft="6dp"
android:singleLine="true"
android:textSize="14sp" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btn_checkout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:backgroundTint="@color/colorPrimary"
android:text="Checkout"
android:textColor="@color/white"
android:textSize="17sp" />
</LinearLayout>
</RelativeLayout>
</ScrollView>
</layout>
App Build Result
GIF
{
"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"
}
GIF
GIF
Tips and Tricks
Identity Kit displays the HUAWEI ID registration or sign-in page first. The user can use the functions provided by Identity Kit only after signing in using a registered HUAWEI ID.
Push Kit supports cross-region messaging, but the messaging performance may be affected. To minimize cross-region messaging, it is recommended that you deploy servers in regions where users gather.
Make sure you have added SHA-256 fingerprint without fail.
Set minSDK version to 24 or later, otherwise you will get AndriodManifest merge issue.
Conclusion
In this article, we have learned how to integrate Huawei ID and Push Kit in Android application. After completely read this article user can easily implement Huawei ID and Client Side Push Notification in the Courier android application using Kotlin.
Thanks for reading this article. Be sure to like and comment to this article, if you found it helpful. It means a lot to me.
References
HMS Docs:
https://developer.huawei.com/consum.../HMSCore-Guides/introduction-0000001050048870
https://developer.huawei.com/consum...-Guides/service-introduction-0000001050040060
Push Kit Training Video:
https://developer.huawei.com/consumer/en/training/course/video/101583005582480166
Push Kit Code Lab:
https://developer.huawei.com/consumer/en/codelabsPortal/carddetails/HMSPushKit

Check the similar words using Text Embedding feature by Huawei ML Kit in Android (Kotlin)

{
"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 can learn how to check similar words and sentences using Text Embedding feature of Huawei ML Kit. This Huawei ML Kit provides Text Embedding feature which helps to get matching vector value of words or sentences. Using this feature, we can improve our research based on the result. It provides similarity between two words or sentences and similar words of a particular word searched. We can also improve searching and browsing efficiency using after getting results related to search text.
Use Cases
This service can be used in text search scenarios. A user can enter a keyword in your news app to return hot news related to the word, improving the search and browsing efficiency.
Precautions
Text embedding depends on the on-cloud API for recognition. During commissioning and usage, ensure that the device can access the Internet.
Requirements
1. Any operating system (MacOS, Linux and Windows).
2. Must have a Huawei phone with HMS 4.0.0.300 or later.
3. Must have a laptop or desktop with Android Studio, Jdk 1.8, SDK platform 26 and Gradle 4.6 and above installed.
4. Minimum API Level 21 is required.
5. Required EMUI 9.0.0 and later version devices.
How to integrate HMS Dependencies
1. First register as Huawei developer and complete identity verification in Huawei developers website, refer to register a Huawei ID.
2. Create a project in android studio, refer Creating an Android Studio Project.
3. Generate a SHA-256 certificate fingerprint.
4. To generate SHA-256 certificate fingerprint. On right-upper corner of android project click Gradle, choose Project Name > Tasks > android, and then click signingReport, as follows.
Note: Project Name depends on the user created name.
5. Create an App in AppGallery Connect.
6. Download the agconnect-services.json file from App information, copy and paste in android Project under app directory, as follows.
7. Enter SHA-256 certificate fingerprint and click Save button, as follows.
Note: Above steps from Step 1 to 7 is common for all Huawei Kits.
8. Click Manage APIs tab and enable ML Kit.
9. Add the below maven URL in build.gradle(Project) file under the repositories of buildscript, dependencies and allprojects, refer Add Configuration.
Java:
maven { url 'http://developer.huawei.com/repo/' }
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
10. Add the below plugin and dependencies in build.gradle(Module) file.
Java:
apply plugin: 'com.huawei.agconnect'
// Huawei AGC
implementation 'com.huawei.agconnect:agconnect-core:1.5.0.300'
// ML Kit Text Embedding
implementation 'com.huawei.hms:ml-nlp-textembedding:2.0.4.300'
11. Now Sync the gradle.
12. Add the required permission to the AndroidManifest.xml file.
Java:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Let us move to development
I have created a project on Android studio with empty activity let us start coding.
In the MainActivity.kt we can find the business logic for buttons.
Java:
class MainActivity : AppCompatActivity() {
var wordSimilar: Button? = null
var sentenceSimilar:Button? = null
var similarWords:Button? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
MLApplication.getInstance().apiKey = getString(R.string.api_key)
wordSimilar = findViewById(R.id.word_similar)
sentenceSimilar = findViewById(R.id.sentence_similar)
similarWords = findViewById(R.id.similar_words)
wordSimilar!!.setOnClickListener(View.OnClickListener {
startActivity(Intent([email protected], WordSimilarActivity::class.java)) })
sentenceSimilar!!.setOnClickListener(View.OnClickListener {
startActivity(Intent([email protected], SentenceSimilarActivity::class.java)) })
similarWords!!.setOnClickListener(View.OnClickListener {
startActivity(Intent([email protected], SimilarWordsActivity::class.java)) })
}
}
In the WordSimilarActivity.kt we can find the business logic for similar words.
Java:
class WordSimilarActivity : AppCompatActivity() {
private var analyzer: MLTextEmbeddingAnalyzer? = null
private var checkWordSimilarity: Button? = null
var resultTextView: TextView? = null
var similarWord1: EditText? = null
var similarWord2:EditText? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_word_similar)
resultTextView = findViewById(R.id.similar_word_value)
checkWordSimilarity = findViewById(R.id.check_word_similarity)
similarWord1 = findViewById(R.id.similar_word1)
similarWord2 = findViewById(R.id.similar_word2)
checkWordSimilarity!!.setOnClickListener(View.OnClickListener { getWordSimillarityApi() })
analyzer = UtilForAnalyzer.getAnalyzer()
}
private fun getWordSimillarityApi() {
val wordsSimilarityTask = analyzer!!.analyseWordsSimilarity(
similarWord1!!.text.toString(), similarWord2!!.text.toString() )
wordsSimilarityTask.addOnSuccessListener { wordsSimilarity ->
resultTextView!!.text = "The similarity value is $wordsSimilarity"
}.addOnFailureListener { e -> onFailure(e) }
}
private fun onFailure(e: Exception?) {
if (e is MLTextEmbeddingException) {
val embeddingException = e
embeddingException.errCode
embeddingException.message
} else {
}
}
}
Create a class for analyzer UtilForAnalyzer.kt.
Java:
class UtilForAnalyzer {
companion object{
private var analyzer: MLTextEmbeddingAnalyzer? = null
var setting: MLTextEmbeddingSetting? = null
fun getAnalyzer(): MLTextEmbeddingAnalyzer? {
if (analyzer == null) {
setting = MLTextEmbeddingSetting.Factory()
.setLanguage(MLTextEmbeddingSetting.LANGUAGE_EN)
.create()
analyzer = MLTextEmbeddingAnalyzerFactory.getInstance().getMLTextEmbeddingAnalyzer(setting)
}
return analyzer
}
}
}
In the SentenceSimilarActivity.kt we can find the business logic for similar sentence.
Java:
class SentenceSimilarActivity : AppCompatActivity() {
private var analyzer: MLTextEmbeddingAnalyzer? = null
private var checkSentenceSimilarity: Button? = null
private var sentence_1: EditText? = null
private var sentence_2: EditText? = null
var resultTextView: TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sentence_similar)
sentence_1 = findViewById(R.id.sentence1)
sentence_2 = findViewById(R.id.sentence2)
resultTextView = findViewById(R.id.similar_word_value)
checkSentenceSimilarity = findViewById(R.id.check_sentence_similarity)
checkSentenceSimilarity!!.setOnClickListener(View.OnClickListener { getSentenceSimilarityApi() })
analyzer = UtilForAnalyzer.getAnalyzer()
}
private fun getSentenceSimilarityApi() {
val sentencesSimilarityTask = analyzer!!.analyseSentencesSimilarity(
sentence_1!!.text.toString(), sentence_2!!.text.toString()
)
sentencesSimilarityTask.addOnSuccessListener { sentencesSimilarity ->
resultTextView!!.text = "The similarity value is $sentencesSimilarity"
}.addOnFailureListener { e -> onFailure(e) }
}
private fun onFailure(e: Exception?) {
if (e is MLTextEmbeddingException) {
val embeddingException = e
embeddingException.errCode
embeddingException.message
} else {
}
}
}
In the SimilarWordsActivity.kt we can find the business logic for similar words count.
Java:
class SimilarWordsActivity : AppCompatActivity() {
private var findSimilarWords: Button? = null
private var word_1: EditText? = null
private var word_2:EditText? = null
private var analyzer: MLTextEmbeddingAnalyzer? = null
var resultTextView: TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_similar_words)
word_1 = findViewById(R.id.word1)
word_2 = findViewById(R.id.word2)
resultTextView = findViewById(R.id.similar_word_value)
findSimilarWords = findViewById(R.id.check_word_similarity)
findSimilarWords!!.setOnClickListener(View.OnClickListener { noOfSimilarWords() })
analyzer = UtilForAnalyzer.getAnalyzer()
}
private fun noOfSimilarWords() {
val multipleSimilarityWordsTask = analyzer!!.analyseSimilarWords(
word_1!!.text.toString(), word_2!!.text.toString().toInt() )
multipleSimilarityWordsTask.addOnSuccessListener { words ->
val stringBuilder = StringBuilder()
for (word in words) {
stringBuilder.append(word)
stringBuilder.append("\t")
}
resultTextView!!.text = stringBuilder.toString()
}.addOnFailureListener { e -> onFailure(e) }
}
private fun onFailure(e: Exception?) {
if (e is MLTextEmbeddingException) {
val embeddingException = e
embeddingException.errCode
embeddingException.message
} else {
}
}
}
In the activity_main.xml we can create the UI screen.
XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/word_similar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check Word Similarity"
android:textAllCaps="false"
android:textSize="17sp"
app:layout_constraintBottom_toTopOf="@+id/sentence_similar"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/sentence_similar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check Sentence Similarity"
android:textAllCaps="false"
android:textSize="17sp"
app:layout_constraintBottom_toTopOf="@+id/similar_words"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/word_similar" />
<Button
android:id="@+id/similar_words"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Get Similar Words"
android:textAllCaps="false"
android:textSize="17sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/word_similar" />
</androidx.constraintlayout.widget.ConstraintLayout>
In the activity_word_similar.xml we can create the UI screen for sentences.
Java:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".WordSimilarActivity">
<EditText
android:id="@+id/similar_word1"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="17sp"
app:layout_constraintBottom_toTopOf="@+id/similar_word2"
android:background="@drawable/edittext_bg"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/similar_word2"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="17sp"
android:background="@drawable/edittext_bg"
app:layout_constraintBottom_toTopOf="@+id/similar_word_value"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/similar_word1" />
<TextView
android:id="@+id/similar_word_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/check_word_similarity"
android:textColor="@color/black"
android:textSize="20dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/similar_word2" />
<Button
android:id="@+id/check_word_similarity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check word Similarity"
android:textAllCaps="false"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/similar_word_value" />
</androidx.constraintlayout.widget.ConstraintLayout>
In the activity_sentence_similar.xml we can create the UI screen for sentences.
XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SentenceSimilarActivity">
<EditText
android:id="@+id/sentence1"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:gravity="center"
android:background="@drawable/edittext_bg"
app:layout_constraintBottom_toTopOf="@+id/sentence2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/sentence2"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:gravity="center"
android:background="@drawable/edittext_bg"
app:layout_constraintBottom_toTopOf="@+id/similar_word_value"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/sentence1" />
<TextView
android:id="@+id/similar_word_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/check_sentence_similarity"
android:textColor="@color/purple_500"
android:textSize="20dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/sentence2" />
<Button
android:id="@+id/check_sentence_similarity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check Sentence Similarity"
android:textSize="17sp"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/similar_word_value" />
</androidx.constraintlayout.widget.ConstraintLayout>
In the activity_similar_words.xml we can create the UI screen for words count.
XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SimilarWordsActivity">
<EditText
android:id="@+id/word1"
android:gravity="center"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:textSize="17sp"
app:layout_constraintBottom_toTopOf="@+id/word2"
android:background="@drawable/edittext_bg"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/word2"
android:gravity="center"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:hint="enter number"
android:textSize="17sp"
android:inputType="number"
android:background="@drawable/edittext_bg"
app:layout_constraintBottom_toTopOf="@+id/similar_word_value"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/word1" />
<TextView
android:id="@+id/similar_word_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
app:layout_constraintBottom_toTopOf="@+id/check_word_similarity"
android:textColor="@color/black"
android:textSize="15dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/word2" />
<Button
android:id="@+id/check_word_similarity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Check Similar Words"
android:textSize="17sp"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/similar_word_value" />
</androidx.constraintlayout.widget.ConstraintLayout>
Demo
Tips and Tricks
1. Make sure you are already registered as Huawei developer.
2. Set minSDK version to 21 or later, otherwise you will get AndriodManifest merge issue.
3. Make sure you have added the agconnect-services.json file to app folder.
4. Make sure you have added SHA-256 fingerprint without fail.
5. Make sure all the dependencies are added properly.
Conclusion
In this article, we can learn how to check similar words and sentences using Text Embedding feature of Huawei ML Kit. This Huawei ML Kit provides Text Embedding feature which helps to get matching vector value of words or sentences. Using this feature, we can improve our research based on the result. It provides similarity between two words or sentences and similar words of a particular word searched. We can also improve searching and browsing efficiency using after getting results related to search text.
I hope you have read this article. If you found it is helpful, please provide likes and comments.
Reference
ML Kit – Text Embedding
ML Kit – Training Video

Categories

Resources