Related
{
"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"
}
Hello everyone.
This article about Huawei Map Kit and Site Kit. I will explain how to use site kit with map. Firstly I would like to give some detail about Map Kit and site Kit.
Map Kit provides an SDK for map development. It covers map data of more than 200 countries and regions, and supports dozens of languages. With this SDK, you can easily integrate map-based functions into your apps. Map kit supports only .Huawei devices. Thanks to Map Kit, you can add markers and shapes on your custom map. Also, Map kit provides camera movements and two different map type.
Site Kit provides the following core capabilities you need to quickly build apps with which your users can explore the world around them. Thanks to site kit, both you can search places and provides to you nearby places. Site Kit not only list places but also provide places detail.
Development Preparation
Step 1 : Register as Developer
Firstly, you have to register as developer on AppGallery Connect and create an app. You can find the guide of registering as a developer here :
Step 2 : Generating a Signing Certificate Fingerprint
Firstly, create a new project on Android Studio. Secondly, click gradle tab on the right of the screen. Finally, click Task > android > signingReport. And you will see on console your projects SHA-256 key.
Copy this fingerprint key and go AppGallery Console > My Apps > select your app > Project Settings and paste “SHA-256 certificate fingerprint” area. Don’t forget click the tick on the right.
Step 3 : Enabling Required Services
In HUAWEI Developer AppGallery Connect, go to Develop > Overview > Manage APIs.
Enable Huawei Map Kit and Site Kit on this page.
Step 4 : Download agconnect-services.json
Go to Develop > Overview > App information. Click agconnect-services.json to download the configuration file. Copy the agconnect-services.json file to the app root directory.
Step 5: Adding Dependecies
Open the build.gradle file in the root directory of your Android Studio project. Go to buildscript > repositories and allprojects > repositories, and configure the Maven repository address for the HMS SDK.
Code:
buildscript {
repositories {
maven { url 'http://developer.huawei.com/repo/' }
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.2'
classpath 'com.huawei.agconnect:agcp:1.2.1.301'
}
}
allprojects {
repositories {
google()
jcenter()
maven {url 'http://developer.huawei.com/repo/'}
}
}
Add dependencies in build.gradle file in app directory.
Code:
dependencies {
implementation 'com.huawei.hms:maps: 4.0.1.302 ' //For Map Kit
implementation 'com.huawei.hms:site:4.0.2.301' //For Site Kit
implementation 'com.jakewharton:butterknife:10.1.0' //Butterknife Library is optional.
annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0'
}
Add the AppGallery Connect plug-in dependency to the file header.
Code:
apply plugin: 'com.huawei.agconnect'
Configure the signature in android. Copy the signature file generated in Generating a Signing Certificate Fingerprint to the app directory of your project and configure the signature in the build.gradle file.
Code:
android {
signingConfigs {
release {
storeFile file("**.**") //Signing certificate.
storePassword "******" //Keystore password.
keyAlias "******" //Alias.
keyPassword "******" //Key password.
v2SigningEnabled true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug {
signingConfig signingConfigs.release}
}
}
}
Open the modified build.gradle file again. You will find a Sync Now link in the upper right corner of the page. Click Sync Now and wait until synchronization is complete.
Step 6: Adding Permissions
To call capabilities of HUAWEI Map Kit, you must apply for the following permissions for your app:
Code:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA"/>
To obtain the current device location, you need to add the following permissions in the AndroidManifest file. In Android 6.0 and later, you need to apply for these permissions dynamically.
Code:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Development Process
Step 1 : Create Fragment XML File
I used fragment for this app. But you can use in the activity. Firstly You have to create a XML file for page design. My page looks like this screenshot.
Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="10dp">
<EditText
android:id="@+id/editText_search"
android:layout_width="0dp"
android:layout_height="35dp"
android:layout_weight="1"
android:textSize="15dp"
android:hint="Search..."
android:background="@drawable/input_model_selected"
android:fontFamily="@font/muli_regular"
android:inputType="textEmailAddress"
android:layout_marginTop="10dp"
android:layout_marginRight="25dp"
android:layout_marginLeft="25dp"/>
<Button
android:id="@+id/btn_search"
android:layout_width="0dp"
android:layout_height="35dp"
android:layout_marginTop="10dp"
android:background="@drawable/orange_background"
android:layout_weight="1"
android:layout_marginRight="5dp"
android:onClick="search"
android:layout_marginLeft="5dp"
android:text="Search"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<com.huawei.hms.maps.MapView
android:id="@+id/mapview_mapviewdemo"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:cameraTargetLat="48.893478"
map:cameraTargetLng="2.334595"
map:cameraZoom="10" />
</LinearLayout>
Step 2 : Create Java File and Implement CallBacks
Now, create a java file called MapFragment and implement to this class OnMapReadyCallback. After this implementation onMapReady method will override on your class.
Secondy, you have to bind Map View, Edit Text and search button. Also, map object, permissions and search service should be defined.
Code:
View rootView;
@BindView(R.id.mapview_mapviewdemo)
MapView mMapView;
@BindView(R.id.editText_search)
EditText editText_search;
@BindView(R.id.btn_search)
Button btn_search;
private HuaweiMap hMap;
private static final String[] RUNTIME_PERMISSIONS = {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.INTERNET
};
private static final int REQUEST_CODE = 100;
//Site Kit
private SearchService searchService;
Step 3 : onCreateView and onMapReady Methods
First of all, XML should be bound. onCreateView should start view binding and onCreateView should end return view. All codes should be written between view binding and return lines.
Secondly permissions should be checked. For this you have to add hasPermissions method like this:
Code:
private static boolean hasPermissions(Context context, String... permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
Thirdliy, onClick event should be defined for search button like this:
Code:
btn_search.setOnClickListener(this);
Next, search service should be created. When creating search service, API Key should be given as a parameter. You can access your API Key from console.
Code:
searchService = SearchServiceFactory.create(getContext(), “API KEY HERE”);
Finally, mapView should be created like this :
Code:
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(“MapViewBundleKey”);
}
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(this);
On the onMapReady method should be include a map object. With this object you can add camera zoom and current location. If you want to zoom in on a specific coordinate when the page is opened, moveCamera should be added. And ıf you want to show current location on map, please add hMap.setMyLocationEnabled(true);
All of onCreateView should be like this :
Code:
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_map, container, false);
ButterKnife.bind(this,rootView);
if (!hasPermissions(getContext(), RUNTIME_PERMISSIONS)) {
ActivityCompat.requestPermissions(getActivity(), RUNTIME_PERMISSIONS, REQUEST_CODE);
}
btn_search.setOnClickListener(this);
searchService = SearchServiceFactory.create(getContext(), "API KEY HERE");
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle("MapViewBundleKey");
}
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(this);
return rootView;
}
@Override
public void onMapReady(HuaweiMap huaweiMap) {
hMap = huaweiMap;
hMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng2, 13));
hMap.setMyLocationEnabled(true);
}
Finally map is ready. Now we will search with Site Kit and show the results as a marker on the map.
Step 4 : Make Search Request And Show On Map As Marker
Now, a new method should be created for searching. TextSearchRequest object and a specific coordinate must be created within the search method. These coordinates will be centered while searching.
Coordinates and keywords should be set on the TextSearchRequest object.
On the onSearchResult method, you have to clear map. Because in the new search results, old markers shouldn’t appear. And create new StringBuilder AddressDetail objects.
Get all results with a for loop. On this for loop markers will be created. Some parameters should be given while creating the marker. Creating a sample marker can be defined as follows.
Code:
hMap.addMarker(new MarkerOptions()
.position(new LatLng(site.getLocation().getLat(), site.getLocation().getLng())) //For location
.title(site.getName()) // Marker tittle
.snippet(site.getFormatAddress())); //Will show when click to marker.
All of the search method should be like this :
Code:
public void search(){
TextSearchRequest textSearchRequest = new TextSearchRequest();
Coordinate location = new Coordinate(currentLat, currentLng);
textSearchRequest.setQuery(editText_search.getText().toString());
textSearchRequest.setLocation(location);
searchService.textSearch(textSearchRequest, new SearchResultListener<TextSearchResponse>() {
@Override
public void onSearchResult(TextSearchResponse textSearchResponse) {
hMap.clear();
StringBuilder response = new StringBuilder("\n");
response.append("success\n");
int count = 1;
AddressDetail addressDetail;
for (Site site :textSearchResponse.getSites()){
addressDetail = site.getAddress();
response.append(String.format(
"[%s] name: %s, formatAddress: %s, country: %s, countryCode: %s \r\n",
"" + (count++), site.getName(), site.getFormatAddress(),
(addressDetail == null ? "" : addressDetail.getCountry()),
(addressDetail == null ? "" : addressDetail.getCountryCode())));
hMap.addMarker(new MarkerOptions().position(new LatLng(site.getLocation().getLat(), site.getLocation().getLng())).title(site.getName()).snippet(site.getFormatAddress()));
}
Log.d("SEARCH RESULTS", "search result is : " + response);
}
@Override
public void onSearchError(SearchStatus searchStatus) {
Log.e("SEARCH RESULTS", "onSearchError is: " + searchStatus.getErrorCode());
}
});
}
Now your app that searches on the map using the Site Kit is ready. Using the other features of Map Kit, you can create a more advanced, more specific application. You can get directions on the map. Or you can draw lines on the map. There are many features of Map Kit. You can add them to your project collectively by examining all of them at the link below.
Good job
Can we customize search list.
sujith.e said:
Can we customize search list.
Click to expand...
Click to collapse
Sure, we can customize search parameters. You can add
textSearchRequest.setPoiType(***LocationType.***HOSPITAL);
in the search() method. Also, LocationType object include so many different types. For eg. Museums, hospitals, banks, art gallery, airport, atm, bus station, gym etc.
Can I share my live location to other peoples?
Can we show customized view on the marker click?
ProManojKumar said:
Can I share my live location to other peoples?
Click to expand...
Click to collapse
Unfortunately site kit and map kit don't allow share your live location to other people. If you want to share your live location, you have to create a background location service and create a server&client system.
ask011 said:
Can we show customized view on the marker click?
Click to expand...
Click to collapse
Sure, you can create a customized view for marker click action. You can create a view and set it on "OnMarkerClickListener" override method.
Introduction
1. Easy integration: You only need two file transmission APIs to integrate Nearby Service, and it doesn't require any complex network protocols.
2. Ultra-fast transmission: It achieves file transmission rate of up to 60 MB/s, so transmitting a 1 GB file takes only 20 seconds.
3. Offline transmission: Nearby Service doesn't require routers or any other network devices. Data is transmitted through Bluetooth and Wi-Fi, so it doesn't consume the user's mobile data.
4. Platform support: The service supports all Android platforms, and will work with other platforms soon.
Demo (NearbyFileTransfer)
Here, take NearbyFileTransfer as an example. You can see how NearbyFileTransfer uses QR codes to transmit files between devices. NearbyFileTransfer has integrated with Nearby Service and Scan Kit.
NearbyTransfer Development
You can find the open source code for NearbyFileTransferon GitHub.
Now, I'll show you how to create the demo based on the source code, so that you can better understand the implementation process.
Preparations
Tools
Two Huawei phones (recommended).
Android Studio (3.X or later).
Register as a Developer
Register as a Huawei developer.
Create an App
Create an app on Huawei AppGallery. For details, please refer to Nearby Service Getting Started Tutorial.
Create a Demo
Download the agconnect-services.json file from AppGallery Connect, and put it into the the app directory (\app) of the demo project.
Sync and build the demo project.
Run the Demo
3. Install the demo on test devices A and B.
4. Tap Send File on device A and select the file you want to transmit. A QR code will be generated.
5. Tap Receive File on device B.
6. Wait until the file transmission is complete.
Code Development
Add Huawei Maven Repository to the Project-Level build.gradle File of Your Project
Add the following Maven address to the build.gradle file in the root directory of
the demo project:
Code:
buildscript {
repositories {
maven { url 'http://developer.huawei.com/repo/'}
} }allprojects {
repositories {
maven { url 'http://developer.huawei.com/repo/'}
}}
Add SDK Dependencies to the App-Level build.gradle File
Code:
dependencies {
implementation 'com.huawei.hms:nearby:5.0.2.300'
implementation 'com.huawei.hms:scan:1.2.3.300'
}
Please always use the newest version of Nearby Service listed on the version change history page.
Declare the System Permission in the AndroidManifest.xml File
This demo needs Bluetooth, Wi-Fi, storage, and location permission to transfer files, and needs camera permission to scan QR codes.
Code:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!--Camera permission-->
<uses-permission android:name="android.permission.CAMERA" />
1. Sending a file.
The sender selects a file and calls nearbyAgent.sendFile to send the file.
Code:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case FILE_SELECT_CODE:
if (resultCode == RESULT_OK) {
// Get the URI of the selected file.
Uri uri = data.getData();
nearbyAgent.sendFile(new File(uri.getPath()));
}
break;
case NearbyAgent.REQUEST_CODE_SCAN_ONE:
nearbyAgent.onScanResult(data);
default:
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
2. Receiving a file.
The receiver calls nearbyAgent.onScanResult(data) to receive a file.
Code:
recvBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
nearbyAgent.receiveFile();
}
});
References
Our official website
Development Guide
Reddit to join our developer discussion
GitHub to download demos and sample codes
Stack Overflow to solve any integration problems
For more information like this, you can check https://forums.developer.huawei.com/forumPortal/en/topic/0201386494098350507
Does it uses BT or WIFI to transfer data ?
Which medium it uses to transfer the data?
is network permission required?
View attachment 5237385
Overview
Translation service can translate text from the source language into the target language. It supports online and offline translation.
In this article, I will show how user can understand the text using ML Kit Plugin.
The text translation service can be widely used in scenarios where translation between different languages is required.
For example, travel apps can integrate this service to translate road signs or menus in other languages to tourists' native languages, providing those considerate services; educational apps can integrate this service to eliminate language barriers, make content more accessible, and improve learning efficiency. In addition, the service supports offline translation, allowing users to easily use the translation service even if the network is not available.
Create Project in Huawei Developer Console
Before you start developing an app, configure app information in App Gallery Connect.
Register as a Developer
Before you get started, you must register as a Huawei developer and complete identity verification on HUAWEI Developers. For details, refer to Registration and Verification.
Create an App
Follow the instructions to create an app Creating an App Gallery Connect Project and Adding an App to the Project. Set the data storage location to Germany.
React Native setup
Requirements
Huawei phone with HMS 4.0.0.300 or later.
React Native environment with Android Studio, NodeJs and Visual Studio code.
Dependencies
Gradle Version: 6.3
Gradle Plugin Version: 3.5.2
React-native-hms-ml gradle dependency
React Native CLI: 2.0.1
1. Environment set up, refer below link.
2. Create project using below command.
Code:
react-native init project name
3. You can install react native command line interface on npm, using the install -g react-native-cli command as shown below.
Code:
npm install –g react-native-cli
Generating a Signing Certificate Fingerprint
Signing certificate fingerprint is required to authenticate your app to Huawei Mobile Services. Make sure JDK is installed. To create one, navigate to JDK directory’s bin folder and open a terminal in this directory. Execute the following command:
Code:
keytool -genkey -keystore <application_project_dir>\android\app\<signing_certificate_fingerprint_filename>.jks -storepass <store_password> -alias <alias> -keypass <key_password> -keysize 2048 -keyalg RSA -validity 36500
This command creates the keystore file in application_project_dir/android/app
The next step is obtain the SHA256 key which is needed for authenticating your app to Huawei services, for the key store file. To obtain it, enter following command in terminal:
Code:
keytool -list -v -keystore <application_project_dir>\android\app\<signing_certificate_fingerprint_filename>.jks
After an authentication, the SHA256 key will be revealed as shown below.
View attachment 5237389
Adding SHA256 Key to the Huawei project in App Gallery
Copy the SHA256 key and visit AppGalleryConnect/ <your_ML_project>/General Information. Paste it to the field SHA-256 certificate fingerprint.
View attachment 5237391
Enable the ML kit from ManageAPIs.
Download the agconnect-services.json from App Gallery and place the file in android/app directory from your React Native Project.
Follow the steps to integrate the ML plugin to your React Native Application.
Integrate the Hms-ML plugin
Code:
npm i @hmscore/react-native-hms-ml
Download the Plugin from the Download Link
Download ReactNative ML Plugin under node_modules/@hmscore of your React Native project, as shown in the directory tree below:
Code:
project-dir
|_ node_modules
|_ ...
|_ @hmscore
|_ ...
|_ react-native-hms-ml
|_ ...
|_ ...
Navigate to android/app/build.gradle directory in your React Native project. Follow the steps:
Add the AGC Plugin dependency
Code:
apply plugin: 'com.huawei.agconnect'
Add to dependencies in android/app/build.gradle:
Code:
implementation project(':react-native-hms-ml')
Navigate to App level android/build.gradle directory in your React Native project. Follow the steps:
Add to buildscript/repositories
Code:
maven {url 'http://developer.huawei.com/repo/'}
Add to buildscript/dependencies
Code:
classpath 'com.huawei.agconnect:agcp:1.3.1.300')
Navigate to android/settings.gradle and add the following:
Code:
include ':react-native-hms-ml'
project(':react-native-hms-ml').projectDir = new File(rootProject.projectDir, '../node_modules/@hmscore/react-native-hms-ml/android')
Use case:
Huawei ML kit’s HMSTranslate API can be integrate for different applications and to translation between different languages.
Set API Key:
Before using HUAWEI ML in your app, set Api key first.
Copy the api_key value in your agconnect-services.json file.
Call setApiKey with the copied value.
Code:
HMSApplication.setApiKey("api_key").then((res) => {console.log(res);})
catch((err) => {console.log(err);})
Add below permission under AndroidManifest.xml file.
XML:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Translation
Text translation is implemented in either asynchronous or synchronous mode. For details, please refer to HMSTranslate.
JavaScript:
async asyncTranslate(sentence) {
try {
if (sentence !== "") {
var result = await HMSTranslate.asyncTranslate(this.state.isEnabled, true, sentence, this.getTranslateSetting());
console.log(result);
if (result.status == HMSApplication.SUCCESS) {
this.setState({ result: result.result });
}
else {
this.setState({ result: result.message });
if (result.status == HMSApplication.NO_FOUND) {
this.setState({ showPreparedModel: true });
ToastAndroid.showWithGravity("Download Using Prepared Button Below", ToastAndroid.SHORT, ToastAndroid.CENTER);
}
}
}
} catch (e) {
console.log(e);
this.setState({ result: "This is an " + e });
}
}
Obtaining Languages
Obtains language codes in on-cloud and on-device translation services. For details, please refer to HMSTranslate.
JavaScript:
async getAllLanguages() {
try {
var result = await HMSTranslate.getAllLanguages(this.state.isEnabled);
console.log(result);
if (result.status == HMSApplication.SUCCESS) {
this.setState({ result: result.result.toString() });
}
else {
this.setState({ result: result.message });
}
} catch (e) {
console.log(e);
}
}
Downloading Prepared Model
A prepared model is provided for on-device analyzer to translate text. You can download the on-device analyzer model. You can translate the text in offline using the download Model. For details, please refer to HMSTranslate.
JavaScript:
async preparedModel() {
try {
var result = await HMSTranslate.preparedModel(this.getStrategyConfiguration(), this.getTranslateSetting());
console.log(result);
if (result.status == HMSApplication.SUCCESS) {
this.setState({ result: "Model download Success. Now you can use local analyze" });
}
else {
this.setState({ result: result.message });
}
} catch (e) {
console.log(e);
this.setState({ result: "This is an " + e });
}
}
Read full article continue reading
Output:
View attachment 5237403
Tips and Tricks
Download latest HMS ReactNativeML plugin.
Copy the api_key value in your agconnect-services.json file and set API key.
Add the languages to translate in Translator Setting.
For project cleaning, navigate to android directory and run the below command.
Code:
gradlew clean
Conclusion:
In this article, we have learnt to integrate ML kit in React native project.
Educational apps can integrate this service to eliminate language barriers, make content more accessible, and improve learning efficiency. In addition, the service supports offline translation, allowing users to easily use the translation service even if the network is not available.
Reference
https://developer.huawei.com/consum...uides-V1/text-translation-0000001051086162-V1
Read full article link
XDARoni said:
View attachment 5237385
Overview
Translation service can translate text from the source language into the target language. It supports online and offline translation.
In this article, I will show how user can understand the text using ML Kit Plugin.
The text translation service can be widely used in scenarios where translation between different languages is required.
For example, travel apps can integrate this service to translate road signs or menus in other languages to tourists' native languages, providing those considerate services; educational apps can integrate this service to eliminate language barriers, make content more accessible, and improve learning efficiency. In addition, the service supports offline translation, allowing users to easily use the translation service even if the network is not available.
Create Project in Huawei Developer Console
Before you start developing an app, configure app information in App Gallery Connect.
Register as a Developer
Before you get started, you must register as a Huawei developer and complete identity verification on HUAWEI Developers. For details, refer to Registration and Verification.
Create an App
Follow the instructions to create an app Creating an App Gallery Connect Project and Adding an App to the Project. Set the data storage location to Germany.
React Native setup
Requirements
Huawei phone with HMS 4.0.0.300 or later.
React Native environment with Android Studio, NodeJs and Visual Studio code.
Dependencies
Gradle Version: 6.3
Gradle Plugin Version: 3.5.2
React-native-hms-ml gradle dependency
React Native CLI: 2.0.1
1. Environment set up, refer below link.
2. Create project using below command.
Code:
react-native init project name
3. You can install react native command line interface on npm, using the install -g react-native-cli command as shown below.
Code:
npm install –g react-native-cli
Generating a Signing Certificate Fingerprint
Signing certificate fingerprint is required to authenticate your app to Huawei Mobile Services. Make sure JDK is installed. To create one, navigate to JDK directory’s bin folder and open a terminal in this directory. Execute the following command:
Code:
keytool -genkey -keystore <application_project_dir>\android\app\<signing_certificate_fingerprint_filename>.jks -storepass <store_password> -alias <alias> -keypass <key_password> -keysize 2048 -keyalg RSA -validity 36500
This command creates the keystore file in application_project_dir/android/app
The next step is obtain the SHA256 key which is needed for authenticating your app to Huawei services, for the key store file. To obtain it, enter following command in terminal:
Code:
keytool -list -v -keystore <application_project_dir>\android\app\<signing_certificate_fingerprint_filename>.jks
After an authentication, the SHA256 key will be revealed as shown below.
View attachment 5237389
Adding SHA256 Key to the Huawei project in App Gallery
Copy the SHA256 key and visit AppGalleryConnect/ <your_ML_project>/General Information. Paste it to the field SHA-256 certificate fingerprint.
View attachment 5237391
Enable the ML kit from ManageAPIs.
Download the agconnect-services.json from App Gallery and place the file in android/app directory from your React Native Project.
Follow the steps to integrate the ML plugin to your React Native Application.
Integrate the Hms-ML plugin
Code:
npm i @hmscore/react-native-hms-ml
Download the Plugin from the Download Link
Download ReactNative ML Plugin under node_modules/@hmscore of your React Native project, as shown in the directory tree below:
Code:
project-dir
|_ node_modules
|_ ...
|_ @hmscore
|_ ...
|_ react-native-hms-ml
|_ ...
|_ ...
Navigate to android/app/build.gradle directory in your React Native project. Follow the steps:
Add the AGC Plugin dependency
Code:
apply plugin: 'com.huawei.agconnect'
Add to dependencies in android/app/build.gradle:
Code:
implementation project(':react-native-hms-ml')
Navigate to App level android/build.gradle directory in your React Native project. Follow the steps:
Add to buildscript/repositories
Code:
maven {url 'http://developer.huawei.com/repo/'}
Add to buildscript/dependencies
Code:
classpath 'com.huawei.agconnect:agcp:1.3.1.300')
Navigate to android/settings.gradle and add the following:
Code:
include ':react-native-hms-ml'
project(':react-native-hms-ml').projectDir = new File(rootProject.projectDir, '../node_modules/@hmscore/react-native-hms-ml/android')
Use case:
Huawei ML kit’s HMSTranslate API can be integrate for different applications and to translation between different languages.
Set API Key:
Before using HUAWEI ML in your app, set Api key first.
Copy the api_key value in your agconnect-services.json file.
Call setApiKey with the copied value.
Code:
HMSApplication.setApiKey("api_key").then((res) => {console.log(res);})
catch((err) => {console.log(err);})
Add below permission under AndroidManifest.xml file.
XML:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Translation
Text translation is implemented in either asynchronous or synchronous mode. For details, please refer to HMSTranslate.
JavaScript:
async asyncTranslate(sentence) {
try {
if (sentence !== "") {
var result = await HMSTranslate.asyncTranslate(this.state.isEnabled, true, sentence, this.getTranslateSetting());
console.log(result);
if (result.status == HMSApplication.SUCCESS) {
this.setState({ result: result.result });
}
else {
this.setState({ result: result.message });
if (result.status == HMSApplication.NO_FOUND) {
this.setState({ showPreparedModel: true });
ToastAndroid.showWithGravity("Download Using Prepared Button Below", ToastAndroid.SHORT, ToastAndroid.CENTER);
}
}
}
} catch (e) {
console.log(e);
this.setState({ result: "This is an " + e });
}
}
Obtaining Languages
Obtains language codes in on-cloud and on-device translation services. For details, please refer to HMSTranslate.
JavaScript:
async getAllLanguages() {
try {
var result = await HMSTranslate.getAllLanguages(this.state.isEnabled);
console.log(result);
if (result.status == HMSApplication.SUCCESS) {
this.setState({ result: result.result.toString() });
}
else {
this.setState({ result: result.message });
}
} catch (e) {
console.log(e);
}
}
Downloading Prepared Model
A prepared model is provided for on-device analyzer to translate text. You can download the on-device analyzer model. You can translate the text in offline using the download Model. For details, please refer to HMSTranslate.
JavaScript:
async preparedModel() {
try {
var result = await HMSTranslate.preparedModel(this.getStrategyConfiguration(), this.getTranslateSetting());
console.log(result);
if (result.status == HMSApplication.SUCCESS) {
this.setState({ result: "Model download Success. Now you can use local analyze" });
}
else {
this.setState({ result: result.message });
}
} catch (e) {
console.log(e);
this.setState({ result: "This is an " + e });
}
}
Read full article continue reading
Output:
View attachment 5237403
Tips and Tricks
Download latest HMS ReactNativeML plugin.
Copy the api_key value in your agconnect-services.json file and set API key.
Add the languages to translate in Translator Setting.
For project cleaning, navigate to android directory and run the below command.
Code:
gradlew clean
Conclusion:
In this article, we have learnt to integrate ML kit in React native project.
Educational apps can integrate this service to eliminate language barriers, make content more accessible, and improve learning efficiency. In addition, the service supports offline translation, allowing users to easily use the translation service even if the network is not available.
Reference
https://developer.huawei.com/consum...uides-V1/text-translation-0000001051086162-V1
Read full article link
Click to expand...
Click to collapse
Currently, real-time translation how many language support
huawei is not accepting new account. any other possible solution? thanks in advance
{
"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
Hi everyone, In this article, we’ll take a look at the Huawei Network Kit and how to use it with Rest APIs. Then, we will develop a demo app using Kotlin in the Android Studio. Finally, we’ll talk about the most common types of errors when making network operations on Android and how you can avoid them.
Huawei Network Kit
Network Kit is a service suite that allows us to perform our network operations quickly and safely. It provides a powerful interacting with Rest APIs and sending synchronous and asynchronous network requests with annotated parameters. Also, it allows us to quickly and easily upload or download files with additional features such as multitasking, multithreading, resumable uploads, and downloads. Lastly, we can use it with other Huawei kits such as hQUIC Kit and Wireless Kit to get faster network traffic.
Our Sample Project
In this application, we'll get a user list from a Rest Service and show the user information on the list. When we are developing the app, we'll use these libraries
RecyclerView
DiffUtil
Kotlinx Serialization
ViewBinding
To make it simple, we don't use an application architecture like MVVM and a progress bar to show the loading status of the data.
The file structure of our sample app:
Website for Rest API
JsonPlaceHolder is a free online Rest API that we can use whenever we need some fake data. We’ll use the fake user data from the below link. And, it gives us the user list as Json.
https://jsonplaceholder.typicode.com/users
Why we are going to use Kotlin Serialization instead of Gson ?
Firstly, we need a serialization library to convert JSON data to objects in our app. Gson is a very popular library for serializing and deserializing Java objects and JSON. But, we are using the Kotlin language and Gson is not suitable for Kotlin. Because Gson doesn’t respect non-null types in Kotlin.
If we try to parse such as a string with GSON, we’ll find out that it doesn’t know anything about Kotlin default values, so we’ll get the NullPointerExceptions as an error. Instead of Kotlinx Serialization, you can also use serialization libraries that offer Kotlin-support, like Jackson or Moshi. We will go into more detail on the implementation of the Kotlinx Serialization.
Setup the Project
We’re not going to go into the details of integrating Huawei HMS Core into a project. You can follow the instructions to integrate HMS Core into your project via official docs or codelab. After integrating HMS Core, let’s add the necessary dependencies.
Add the necessary dependencies to build.gradle (app level)
Java:
plugins {
id 'com.huawei.agconnect' // HUAWEI agconnect Gradle plugin'
id 'org.jetbrains.kotlin.plugin.serialization' // Kotlinx Serialization
}
android {
buildFeatures {
// Enable ViewBinding
viewBinding true
}
}
dependencies {
// HMS Network Kit
implementation 'com.huawei.hms:network-embedded:5.0.1.301'
// Kotlinx Serialization
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1'
}
We’ll use viewBinding instead of findViewById. It generates a binding class for each XML layout file present in that module. With the instance of a binding class, we can access the view hierarchy with type and null safety.
We used the kotlinx-servialization-json:1.01 version instead of the latest version 1.1.0 in our project. If you use version 1.1.0 and your Kotlin version is smaller than 1.4.30-M1, you will get an error like this:
Code:
Your current Kotlin version is 1.4.10, while kotlinx.serialization core runtime 1.1.0 requires at least Kotlin 1.4.30-M1.
Therefore, if you want to use the latest version of Kotlinx Serialization, please make sure that your Kotlin version is higher than 1.4.30-M1.
Add the necessary dependencies to build.gradle (project level)
Java:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
dependencies {
classpath 'com.huawei.agconnect:agcp:1.4.1.300' // HUAWEI Agcp plugin
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" // Kotlinx Serialization
}
}
Declaring Required Network Permissions
To use functions of Network Kit, we need to declare required permissions in the AndroidManifest.xml file.
XML:
<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" />
Initialize the Network Kit
Let’s create an Application class and initialize the Network Kit here.
Java:
class App : Application() {
private val TAG = "Application"
override fun onCreate() {
super.onCreate()
initNetworkKit()
}
private fun initNetworkKit() {
NetworkKit.init(applicationContext, object : NetworkKit.Callback() {
override fun onResult(result: Boolean) {
if (result) {
Log.i(TAG, "NetworkKit init success")
} else {
Log.i(TAG, "NetworkKit init failed")
}
}
})
}
}
Note: Don’t forget to add the App class to the Android Manifest file.
XML:
<manifest ...>
...
<application
android:name=".App"
...
</application>
</manifest>
ApiClient
getApiClient() -> It returns the RestClient instance as a Singleton. We can set the connection time out value here. Also, we specified the base URL.
Java:
const val BASE_URL = "https://jsonplaceholder.typicode.com/"
class ApiClient {
companion object {
private var restClient: RestClient? = null
fun getApiClient(): RestClient {
val httpClient = HttpClient.Builder()
.callTimeout(1000)
.connectTimeout(10000)
.build()
if (restClient == null) {
restClient = RestClient.Builder()
.baseUrl(BASE_URL)
.httpClient(httpClient)
.build()
}
return restClient!!
}
}
}
ApiInterface
We specified the request type as GET and pass the relative URL as “users”. And, it returns us the results as String.
Java:
interface ApiInterface {
@GET("users")
fun fetchUsers(): Submit<String>
}
User — Model Class
As I mentioned earlier, we get the data as a string. Then, we’ll convert data to User object help of the Kotlinx Serialization library. To perform this process, we have to add some annotations to our data class.
@serializable -> We can make a class serializable by annotating it.
@SerialName() -> The variable name in our data must be the same as we use in the data class. If we want to set different variable names, we should use @SerialName annotation.
Java:
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class User(
@SerialName("id")
val Id: Int = 0,
val name: String = "",
val username: String = "",
val email: String = "",
)
UserDiffUtil
To tell the RecyclerView that an item in the list has changed, we’ll use the DiffUtil instead of the notifyDataSetChanged().
DiffUtil is a utility class that can calculate the difference between two lists and output a list of update operations that converts the first list into the second one. And, it uses The Myers Difference Algorithm to do this calculation.
What makes notifyDataSetChanged() inefficient is that it forces to recreate all visible views as opposed to just the items that have changed. So, it is an expensive operation.
Java:
class UserDiffUtil(
private val oldList: List<User>,
private val newList: List<User>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldList.size
}
override fun getNewListSize(): Int {
return newList.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition].Id == newList[newItemPosition].Id
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
}
row_user.xml
We have two TextView to show userId and the userName. We’ll use this layout in the RecylerView.
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="60dp">
<TextView
android:id="@+id/tv_userId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:textColor="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="1" />
<View
android:id="@+id/divider_vertical"
android:layout_width="1dp"
android:layout_height="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="@android:color/darker_gray"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/tv_userId"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_userName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:textColor="@android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/divider_vertical"
app:layout_constraintTop_toTopOf="parent"
tools:text="Antonio Vivaldi" />
<View
android:id="@+id/divider_horizontal"
android:layout_width="0dp"
android:layout_height="1dp"
android:background="@android:color/darker_gray"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
UserAdapter
It contains the adapter and the ViewHolder class.
Java:
class UserAdapter : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
private var oldUserList = emptyList<User>()
class UserViewHolder(val binding: RowUserBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
return UserViewHolder(
RowUserBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.binding.tvUserId.text = oldUserList[position].Id.toString()
holder.binding.tvUserName.text = oldUserList[position].name
}
override fun getItemCount(): Int = oldUserList.size
fun setData(newUserList: List<User>) {
val diffUtil = UserDiffUtil(oldUserList, newUserList)
val diffResults = DiffUtil.calculateDiff(diffUtil)
oldUserList = newUserList
diffResults.dispatchUpdatesTo(this)
}
}
activity_main.xml
It contains only a recyclerview to show the user list.
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=".ui.MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity
userAdapter - We create a adapter for the RecyclerView.
apiClient - We create a request API object using the RestClient object (ApiClient).
Network Kit provides two ways to send network request: synchronous and asynchronous.
Synchronous requests block the client until the operation completes. We can only get data after it finishes its task.
An asynchronous request doesn’t block the client and we can receive a callback when the data has been received.
getUsersAsSynchronous() - We use synchronous requests here. Firstly, we get the response from RestApi. Then, we need to convert the JSON data to User objects. We use the decodeFromString function to do this. Also, we set ignoreUnknownKeys = true, because we don’t use all user information inside the JSON file. We just get the id, name, username, and email. If you don’t put all information inside your Model Class (User), you have to set this parameter as true. Otherwise, you will get an error like:
Code:
Use ‘ignoreUnknownKeys = true’ in ‘Json {}’ builder to ignore unknown keys.
We call this function inside the onCreate. But, we are in the main thread, and we cannot call this function directly from the main thread. If we try to do this, it will crash and give an error like:
Code:
Caused by: android.os.NetworkOnMainThreadException
We should change our thread. So, we call getUsersAsSynchronous() function inside the tread. Then, we get the data successfully. But, there is still one problem. We changed our thread and we cannot change any view without switching to the main thread. If we try to change a view before switching the main thread, it will give an error:
Code:
D/MainActivity: onFailure: Only the original thread that created a view hierarchy can touch its views.
So, we use the runOnUiThread function to run our code in the main thread. Finally, we send our data to the recyclerview adapter to show on the screen as a list.
getUsersAsAsynchronous() - We use asynchronous requests here. We send a network request and wait for the response without blocking the thread. When we get the response, we can show the user list on the screen. Also, we don’t need to call our asynchronous function inside a different thread. But, if we want to use any view, we should switch to the main thread. So, we use the runOnUiThread function to run our code in the main thread again.
Java:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val TAG = "MainActivity"
private val userAdapter by lazy { UserAdapter() }
private val apiClient by lazy {
ApiClient.getApiClient().create(ApiInterface::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
binding.recyclerView.apply {
layoutManager = LinearLayoutManager([email protected])
adapter = userAdapter
}
getUsersAsAsynchronous()
/*
thread(start = true) {
getUsersAsSynchronous()
}
*/
}
private fun getUsersAsSynchronous() {
val response = apiClient.fetchUsers().execute()
if (response.isSuccessful) {
val userList =
Json { ignoreUnknownKeys = true }.decodeFromString<List<User>>(response.body)
runOnUiThread {
userAdapter.setData(userList)
}
}
}
private fun getUsersAsAsynchronous() {
apiClient.fetchUsers().enqueue(object : Callback<String>() {
override fun onResponse(p0: Submit<String>?, response: Response<String>?) {
if (response?.isSuccessful == true) {
val userList = Json {
ignoreUnknownKeys = true
}.decodeFromString<List<User>>(response.body)
runOnUiThread {
userAdapter.setData(userList)
}
}
}
override fun onFailure(p0: Submit<String>?, p1: Throwable?) {
Log.d(TAG, "onFailure: ${p1?.message.toString()}")
}
})
}
}
Tips & Tricks
You can use Coroutines to manage your thread operations and perform your asynchronous operations easily.
You can use Sealed Result Class to handle the network response result based on whether it was a success or failure.
Before sending network requests, you can check that you’re connected to the internet using the ConnectivityManager.
Conclusion
In this article, we have learned how to use Network Kit in your network operations. And, we’ve developed a sample app that lists user information obtained from the REST Server. In addition to sending requests using either an HttpClient object or a RestClient object, Network Kit offers file upload and download featuring. Please do not hesitate to ask your questions as a comment.
Thank you for your time and dedication. I hope it was helpful. See you in other articles.
References
Huawei Network Kit Official Documentation
Huawei Network Kit Official Codelab
which permission are required?
AbdurrahimCillioglu said:
View attachment 5273549
Introduction
Hi everyone, In this article, we’ll take a look at the Huawei Network Kit and how to use it with Rest APIs. Then, we will develop a demo app using Kotlin in the Android Studio. Finally, we’ll talk about the most common types of errors when making network operations on Android and how you can avoid them.
Huawei Network Kit
Network Kit is a service suite that allows us to perform our network operations quickly and safely. It provides a powerful interacting with Rest APIs and sending synchronous and asynchronous network requests with annotated parameters. Also, it allows us to quickly and easily upload or download files with additional features such as multitasking, multithreading, resumable uploads, and downloads. Lastly, we can use it with other Huawei kits such as hQUIC Kit and Wireless Kit to get faster network traffic.
Our Sample Project
In this application, we'll get a user list from a Rest Service and show the user information on the list. When we are developing the app, we'll use these libraries
RecyclerView
DiffUtil
Kotlinx Serialization
ViewBinding
To make it simple, we don't use an application architecture like MVVM and a progress bar to show the loading status of the data.
View attachment 5273551
The file structure of our sample app:
View attachment 5273553
Website for Rest API
JsonPlaceHolder is a free online Rest API that we can use whenever we need some fake data. We’ll use the fake user data from the below link. And, it gives us the user list as Json.
https://jsonplaceholder.typicode.com/users
View attachment 5273555
Why we are going to use Kotlin Serialization instead of Gson ?
Firstly, we need a serialization library to convert JSON data to objects in our app. Gson is a very popular library for serializing and deserializing Java objects and JSON. But, we are using the Kotlin language and Gson is not suitable for Kotlin. Because Gson doesn’t respect non-null types in Kotlin.
If we try to parse such as a string with GSON, we’ll find out that it doesn’t know anything about Kotlin default values, so we’ll get the NullPointerExceptions as an error. Instead of Kotlinx Serialization, you can also use serialization libraries that offer Kotlin-support, like Jackson or Moshi. We will go into more detail on the implementation of the Kotlinx Serialization.
Setup the Project
We’re not going to go into the details of integrating Huawei HMS Core into a project. You can follow the instructions to integrate HMS Core into your project via official docs or codelab. After integrating HMS Core, let’s add the necessary dependencies.
Add the necessary dependencies to build.gradle (app level)
Java:
plugins {
id 'com.huawei.agconnect' // HUAWEI agconnect Gradle plugin'
id 'org.jetbrains.kotlin.plugin.serialization' // Kotlinx Serialization
}
android {
buildFeatures {
// Enable ViewBinding
viewBinding true
}
}
dependencies {
// HMS Network Kit
implementation 'com.huawei.hms:network-embedded:5.0.1.301'
// Kotlinx Serialization
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1'
}
We’ll use viewBinding instead of findViewById. It generates a binding class for each XML layout file present in that module. With the instance of a binding class, we can access the view hierarchy with type and null safety.
We used the kotlinx-servialization-json:1.01 version instead of the latest version 1.1.0 in our project. If you use version 1.1.0 and your Kotlin version is smaller than 1.4.30-M1, you will get an error like this:
Code:
Your current Kotlin version is 1.4.10, while kotlinx.serialization core runtime 1.1.0 requires at least Kotlin 1.4.30-M1.
Therefore, if you want to use the latest version of Kotlinx Serialization, please make sure that your Kotlin version is higher than 1.4.30-M1.
Add the necessary dependencies to build.gradle (project level)
Java:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
dependencies {
classpath 'com.huawei.agconnect:agcp:1.4.1.300' // HUAWEI Agcp plugin
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" // Kotlinx Serialization
}
}
Declaring Required Network Permissions
To use functions of Network Kit, we need to declare required permissions in the AndroidManifest.xml file.
XML:
<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" />
Initialize the Network Kit
Let’s create an Application class and initialize the Network Kit here.
Java:
class App : Application() {
private val TAG = "Application"
override fun onCreate() {
super.onCreate()
initNetworkKit()
}
private fun initNetworkKit() {
NetworkKit.init(applicationContext, object : NetworkKit.Callback() {
override fun onResult(result: Boolean) {
if (result) {
Log.i(TAG, "NetworkKit init success")
} else {
Log.i(TAG, "NetworkKit init failed")
}
}
})
}
}
Note: Don’t forget to add the App class to the Android Manifest file.
XML:
<manifest ...>
...
<application
android:name=".App"
...
</application>
</manifest>
ApiClient
getApiClient() -> It returns the RestClient instance as a Singleton. We can set the connection time out value here. Also, we specified the base URL.
Java:
const val BASE_URL = "https://jsonplaceholder.typicode.com/"
class ApiClient {
companion object {
private var restClient: RestClient? = null
fun getApiClient(): RestClient {
val httpClient = HttpClient.Builder()
.callTimeout(1000)
.connectTimeout(10000)
.build()
if (restClient == null) {
restClient = RestClient.Builder()
.baseUrl(BASE_URL)
.httpClient(httpClient)
.build()
}
return restClient!!
}
}
}
ApiInterface
We specified the request type as GET and pass the relative URL as “users”. And, it returns us the results as String.
Java:
interface ApiInterface {
@GET("users")
fun fetchUsers(): Submit<String>
}
User — Model Class
As I mentioned earlier, we get the data as a string. Then, we’ll convert data to User object help of the Kotlinx Serialization library. To perform this process, we have to add some annotations to our data class.
@serializable -> We can make a class serializable by annotating it.
@SerialName() -> The variable name in our data must be the same as we use in the data class. If we want to set different variable names, we should use @SerialName annotation.
Java:
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class User(
@SerialName("id")
val Id: Int = 0,
val name: String = "",
val username: String = "",
val email: String = "",
)
UserDiffUtil
To tell the RecyclerView that an item in the list has changed, we’ll use the DiffUtil instead of the notifyDataSetChanged().
DiffUtil is a utility class that can calculate the difference between two lists and output a list of update operations that converts the first list into the second one. And, it uses The Myers Difference Algorithm to do this calculation.
What makes notifyDataSetChanged() inefficient is that it forces to recreate all visible views as opposed to just the items that have changed. So, it is an expensive operation.
Java:
class UserDiffUtil(
private val oldList: List<User>,
private val newList: List<User>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldList.size
}
override fun getNewListSize(): Int {
return newList.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition].Id == newList[newItemPosition].Id
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
}
row_user.xml
We have two TextView to show userId and the userName. We’ll use this layout in the RecylerView.
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="60dp">
<TextView
android:id="@+id/tv_userId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:textColor="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="1" />
<View
android:id="@+id/divider_vertical"
android:layout_width="1dp"
android:layout_height="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="@android:color/darker_gray"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/tv_userId"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_userName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:textColor="@android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/divider_vertical"
app:layout_constraintTop_toTopOf="parent"
tools:text="Antonio Vivaldi" />
<View
android:id="@+id/divider_horizontal"
android:layout_width="0dp"
android:layout_height="1dp"
android:background="@android:color/darker_gray"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
UserAdapter
It contains the adapter and the ViewHolder class.
Java:
class UserAdapter : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
private var oldUserList = emptyList<User>()
class UserViewHolder(val binding: RowUserBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
return UserViewHolder(
RowUserBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.binding.tvUserId.text = oldUserList[position].Id.toString()
holder.binding.tvUserName.text = oldUserList[position].name
}
override fun getItemCount(): Int = oldUserList.size
fun setData(newUserList: List<User>) {
val diffUtil = UserDiffUtil(oldUserList, newUserList)
val diffResults = DiffUtil.calculateDiff(diffUtil)
oldUserList = newUserList
diffResults.dispatchUpdatesTo(this)
}
}
activity_main.xml
It contains only a recyclerview to show the user list.
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=".ui.MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity
userAdapter - We create a adapter for the RecyclerView.
apiClient - We create a request API object using the RestClient object (ApiClient).
Network Kit provides two ways to send network request: synchronous and asynchronous.
Synchronous requests block the client until the operation completes. We can only get data after it finishes its task.
An asynchronous request doesn’t block the client and we can receive a callback when the data has been received.
getUsersAsSynchronous() - We use synchronous requests here. Firstly, we get the response from RestApi. Then, we need to convert the JSON data to User objects. We use the decodeFromString function to do this. Also, we set ignoreUnknownKeys = true, because we don’t use all user information inside the JSON file. We just get the id, name, username, and email. If you don’t put all information inside your Model Class (User), you have to set this parameter as true. Otherwise, you will get an error like:
Code:
Use ‘ignoreUnknownKeys = true’ in ‘Json {}’ builder to ignore unknown keys.
We call this function inside the onCreate. But, we are in the main thread, and we cannot call this function directly from the main thread. If we try to do this, it will crash and give an error like:
Code:
Caused by: android.os.NetworkOnMainThreadException
We should change our thread. So, we call getUsersAsSynchronous() function inside the tread. Then, we get the data successfully. But, there is still one problem. We changed our thread and we cannot change any view without switching to the main thread. If we try to change a view before switching the main thread, it will give an error:
Code:
D/MainActivity: onFailure: Only the original thread that created a view hierarchy can touch its views.
So, we use the runOnUiThread function to run our code in the main thread. Finally, we send our data to the recyclerview adapter to show on the screen as a list.
getUsersAsAsynchronous() - We use asynchronous requests here. We send a network request and wait for the response without blocking the thread. When we get the response, we can show the user list on the screen. Also, we don’t need to call our asynchronous function inside a different thread. But, if we want to use any view, we should switch to the main thread. So, we use the runOnUiThread function to run our code in the main thread again.
Java:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val TAG = "MainActivity"
private val userAdapter by lazy { UserAdapter() }
private val apiClient by lazy {
ApiClient.getApiClient().create(ApiInterface::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
binding.recyclerView.apply {
layoutManager = LinearLayoutManager([email protected])
adapter = userAdapter
}
getUsersAsAsynchronous()
/*
thread(start = true) {
getUsersAsSynchronous()
}
*/
}
private fun getUsersAsSynchronous() {
val response = apiClient.fetchUsers().execute()
if (response.isSuccessful) {
val userList =
Json { ignoreUnknownKeys = true }.decodeFromString<List<User>>(response.body)
runOnUiThread {
userAdapter.setData(userList)
}
}
}
private fun getUsersAsAsynchronous() {
apiClient.fetchUsers().enqueue(object : Callback<String>() {
override fun onResponse(p0: Submit<String>?, response: Response<String>?) {
if (response?.isSuccessful == true) {
val userList = Json {
ignoreUnknownKeys = true
}.decodeFromString<List<User>>(response.body)
runOnUiThread {
userAdapter.setData(userList)
}
}
}
override fun onFailure(p0: Submit<String>?, p1: Throwable?) {
Log.d(TAG, "onFailure: ${p1?.message.toString()}")
}
})
}
}
Tips & Tricks
You can use Coroutines to manage your thread operations and perform your asynchronous operations easily.
You can use Sealed Result Class to handle the network response result based on whether it was a success or failure.
Before sending network requests, you can check that you’re connected to the internet using the ConnectivityManager.
Conclusion
In this article, we have learned how to use Network Kit in your network operations. And, we’ve developed a sample app that lists user information obtained from the REST Server. In addition to sending requests using either an HttpClient object or a RestClient object, Network Kit offers file upload and download featuring. Please do not hesitate to ask your questions as a comment.
Thank you for your time and dedication. I hope it was helpful. See you in other articles.
References
Huawei Network Kit Official Documentation
Huawei Network Kit Official Codelab
Click to expand...
Click to collapse
Can we get All network Information?
ProManojKumar said:
which permission are required?
Click to expand...
Click to collapse
Hello, Network Kit requires the following permission:
XML:
<!--To obtain the network status-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<!--To access the Internet-->
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<!--To obtain the Wi-Fi status-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
But, If you want to use the upload and download functions of the Network Kit, you should also add the storage permissions:
XML:
<!--To read data from the memory on user devices-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
<!--To write data to the memory on user devices-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
Does it support Flutter?
Basavaraj.navi said:
Does it support Flutter?
Click to expand...
Click to collapse
Hi, Flutter doesn't support Flutter yet.
Overview
In this article, I will create an Android Demo app that highlights use case of Google Tag Manager and Dynamic Tag Manager in a Single Android App. I have integrated Huawei Analytics and Google Analytics.
I will create an AppGallery project and deploy AppGallery into the application. I will fire a basic event, so we can debug the hits sent from AppGallery to Huawei Analytics.
I will create a Google Tag Manager container for Firebase, and I will install that in application. I will use that container to take the event when we configured Firebase and will send the data to a (non-Firebase) Google Analytics property as well.
Huawei Analytics Introduction
Analytics kit is powered by Huawei which allows rich analytics models to understand user behaviour and gain in-depth insights into users, products, and content. As such, you can carry out data-driven operations and make strategic decisions about app marketing and product optimization.
Analytics Kit implements the following functions using data collected from apps:
1. Provides data collection and reporting APIs for collection and reporting custom events.
2. Sets up to 25 user attributes.
3. Supports automatic event collection and session calculation as well as predefined event IDs and parameters.
Google Analytics Introduction
Google Analytics collects usage and behaviour data for your app. The SDK logs two primary types of information:
Events: What is happening in your apps, such as user actions, system events, or errors?
User properties: Attributes you define to describe segments of your user base, such as language preference or geographic location.
Analytics automatically logs some events and user properties, you don't need to add any code to enable them.
Dynamic Tag Manager Introduction
Dynamic Tag Manager is a concept of improving collaboration between developers and marketers. It eliminates the need for restructuring application code as a result of new marketing intelligence requirements.
Dynamic Tag Manager console allows you to define different tags and manage the rules that trigger them. One specific tag type is the Universal Analytics tag, which enables you to integrate your Huawei Analytics project with Dynamic Tag Manager. This tag is easily set up by associating it with your Analytics key. This will expose the tags you are firing to your Analytics project in their raw form. From that point, you can define what data is sent to your Analytics project, when and how, without the need of changing your application’s code-of course, assuming you have smartly integrated the Huawei Dynamic Tag Manager’s SDK into your app in the first place.
Google Tag Manager
Google Tag Manager enables developers to change configuration values in their mobile application using the Google Tag Manager interface without having to rebuild and resubmit application binaries to app marketplaces.
This is useful for managing any configuration values or flags in your application that you may need to change in the future, including:
Various UI settings and display strings.
Sizes, locations, or types of ads served in your application.
Various Game settings.
Configuration values may also be evaluated at runtime using rules, enabling dynamic configurations such as:
Using screen size to determine ad banner size.
Using language and location to configure UI elements.
Google TagManager also enables the dynamic implementation of tracking tags and pixels in applications. Developers can push important events into a data layer and decide later which is tracking tags or pixels should be fired.
Prerequisite
1. Android Studio
2. Huawei phone
3. Firebase Account
4. AppGallery 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 > Data Storage location.
4. Navigate to Manage APIs > Enable APIs.
5. Enable Huawei Analytics.
6. Enable Dynamic Tag Manager.
7. Create Tag.
8. Configure Tag.
9. Pause or Delete Tag.
Firebase Integration Process
1. Create a Firebase project.
2. Choose Android as a Platform.
3. Add App to your Firebase Project.
4. Download Configuration file.
5. Navigate to Google Tag Manager Console.
Create New Tag, then click Submit.
6. Choose tag type.
7. Choose a Variable
8. Tag Configure.
9. Publish Tag
10. Download the Tag and Add in your Android App.
(Your Project)Android App > Assets > Container > tag_file.
App Development
1. Create A New Project.
2. Configure Project Gradle.
Java:
buildscript {
repositories {
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' }
}
dependencies {
classpath "com.android.tools.build:gradle:4.0.1"
classpath 'com.google.gms:google-services:4.3.5'
classpath 'com.huawei.agconnect:agcp:1.3.1.300'
}
}
allprojects {
repositories {
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
3. Configure App Gradle.
Java:
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.huawei.agconnect'
android {
compileSdkVersion 30
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.gtm.dtm"
minSdkVersion 27
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
//Google Tag Manager with Analytics
implementation platform('com.google.firebase:firebase-bom:26.8.0')
implementation 'com.google.firebase:firebase-analytics'
implementation 'com.google.android.gms:play-services-tagmanager:17.0.0'
//Dynamic Tag Manager with Huawei Analytics
implementation "com.huawei.hms:hianalytics:5.2.0.300"
implementation "com.huawei.hms:dtm-api:5.2.0.300"
implementation 'in.shadowfax:proswipebutton:1.2.2'
}
4. Configure AndroidManifest.
XML:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gtm.dtm">
<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">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.google.android.gms.tagmanager"
android:noHistory="true">
<intent-filter>
<data android:scheme="tagmanager.c.com.example.app" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
<meta-data
android:name="com.huawei.hms.client.channel.androidMarket"
android:value="false" />
</application>
</manifest>
5. Create an Activity class with XML UI.
MainActivity:
This activity performs all the operation of Huawei Analytics and Google Analytics based on button click events.
Java:
package com.gtm.dtm;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.huawei.hms.analytics.HiAnalytics;
import com.huawei.hms.analytics.HiAnalyticsInstance;
import in.shadowfax.proswipebutton.ProSwipeButton;
public class MainActivity extends AppCompatActivity {
private HiAnalyticsInstance instance;
private FirebaseAnalytics mFirebaseAnalytics;
private ProSwipeButton btnGTM;
private ProSwipeButton btnDTM;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFirebaseAnalytics=FirebaseAnalytics.getInstance(this);
instance = HiAnalytics.getInstance(this);
btnGTM = (ProSwipeButton) findViewById(R.id.btn_gtm);
btnGTM.setOnSwipeListener(new ProSwipeButton.OnSwipeListener() {
@Override
public void onSwipeConfirm() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
btnGTM.showResultIcon(true);
sendGTMEvent();
}
}, 2000);
}
});
btnDTM = (ProSwipeButton) findViewById(R.id.btn_dtm);
btnDTM.setOnSwipeListener(new ProSwipeButton.OnSwipeListener() {
@Override
public void onSwipeConfirm() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
btnDTM.showResultIcon(true);
sendDTMEvent();
}
}, 2000);
}
});
}
private void sendDTMEvent() {
String eventName = "DTM";
Bundle bundle = new Bundle();
bundle.putString("Click", "Pressed button");
if (instance != null) {
instance.onEvent(eventName, bundle);
Log.d("DTM-Test","log event.");
}
}
private void sendGTMEvent(){
Bundle bundle = new Bundle();
bundle.putString("Click", "Pressed button");
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.ADD_TO_CART, bundle);
}
}
main_activity.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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/bg">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:gravity="center_horizontal"
android:text="Google Tag Manager \n vs \n Dynamic Tag Manager"
android:textColor="#fff"
android:textSize="30dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="10dp">
<in.shadowfax.proswipebutton.ProSwipeButton
android:id="@+id/btn_dtm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:arrow_color="#33FFFFFF"
app:bg_color="@android:color/holo_red_dark"
app:btn_radius="2"
app:btn_text="Send DTM Event"
app:text_color="@android:color/white"
app:text_size="14sp" />
<in.shadowfax.proswipebutton.ProSwipeButton
android:id="@+id/btn_gtm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_marginTop="10dp"
app:arrow_color="#33FFFFFF"
app:bg_color="@android:color/holo_green_dark"
app:btn_radius="2"
app:btn_text="Send GTM Event"
app:text_color="@android:color/white"
app:text_size="14sp" />
</LinearLayout>
</RelativeLayout>
App Build Result
1. Google Analytics Debug View.
2. Huawei Analytics Overview.
3. App Result.
Tips and Tricks
1. 5.2.0 or later. If HMS Core (APK) is not installed or its version is earlier than 5.2.0, DTM functions can be normally used but the DTM SDK version cannot be updated automatically.
2. ICustomVariable and ICustomTag contain custom extensible variables and templates. You can also customize variables and templates in DTM to meet specific requirements.
Conclusion
In this article, we have learned how to integrate DTM and GTM in application. In this application, I have explained use case of Google tag manager with Dynamic Tag manager in a single application.
Thanks for reading this article. Be sure to like and comments on this article, if you found it helpful. It means a lot to me.
References
1. Huawei Tag Manager
2. Google Tag Manager Console
3. Google Firebase Console