This document describes how to integrate Analytics Kit using the official Unity asset. After the integration, your app can use the services of this Kit on HMS mobile phones.
For details about Analytics Kit, please visit HUAWEI Developers.
1.1 Preparations1.1.1 Importing Unity Assets1.1.2 Generating .gradle Files1. Enable project gradle.
Go to Edit > Project Settings > Player in Unity, click the Android icon, and go to Publishing Settings > Build.
Enable Custom Base Gradle Template.
Enable Custom Launcher Gradle Template.
Enable Custom Main Gradle Template.
Enable Custom Main Manifest.
{
"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. Signature
You can use an existing keystore file or create a new one to sign your app.
Go to Edit > Project Settings > Player in Unity, click the Android icon, and go to Publishing Settings > Keystore Manager > Keystore... > Create New.
Enter the password when you open Unity. Otherwise, you cannot build the APK.
1.1.3 Configuring .gradle Files and the AndroidManifest.xml File1. Configure the BaseProjectTemplate.gradle file.
Code:
<p style="line-height: 1.5em;">Configure the Maven repository address.
buildscript {
repositories {**ARTIFACTORYREPOSITORY**
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' }
}
dependencies {
// If you are changing the Android Gradle Plugin version, make sure it is compatible with the Gradle version preinstalled with Unity.
// For the Gradle version preinstalled with Unity, please visit https://docs.unity3d.com/Manual/android-gradle-overview.html.
// For the official Gradle and Android Gradle Plugin compatibility table, please visit https://developer.android.com/studio/releases/gradle-plugin#updating-gradle.
// To specify a custom Gradle version in Unity, go do Preferences > External Tools, deselect Gradle Installed with Unity (recommended), and specify a path to a custom Gradle version.
classpath 'com.android.tools.build:gradle:3.4.0'
classpath 'com.huawei.agconnect:agcp:1.2.1.301'
**BUILD_SCRIPT_DEPS**
}
repositories {**ARTIFACTORYREPOSITORY**
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' }
flatDir {
dirs "${project(':unityLibrary').projectDir}/libs"
}
}</p>
2. Configure the launcherTemplate.gradle file.
Code:
<p style="line-height: 1.5em;">// Generated by Unity. Remove this comment to prevent overwriting when exporting again.
apply plugin: 'com.android.application'
apply plugin: 'com.huawei.agconnect'
dependencies {
implementation project(':unityLibrary')
implementation 'com.huawei.hms:hianalytics:5.1.0.300'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.huawei.agconnect:agconnect-core:1.2.0.300'
}</p>
3. Configure the mainTemplate.gradle file.
Code:
<p style="line-height: 1.5em;">apply plugin: 'com.android.library'
apply plugin: 'com.huawei.agconnect'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.huawei.agconnect:agconnect-core:1.2.0.300'
implementation 'com.huawei.hms:hianalytics:5.0.0.301'
**DEPS**}</p>
4. Configure the AndroidManifest.xml file.
Code:
<p style="line-height: 1.5em;"><?xml version="1.0" encoding="utf-8"?>
<!-- Generated by Unity. Remove this comment to prevent overwriting when exporting again. -->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
xmlns:tools="http://schemas.android.com/tools">
<application>
<activity android:name="com.hms.hms_analytic_activity.HmsAnalyticActivity"
android:theme="@style/UnityThemeSelector">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="unity.cn"
android:scheme="https" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
</application></p>
1.1.4 Adding the agconnect-services.json File1. Create an app by following instructions in Creating an AppGallery Connect Project and Adding an App to the Project.
Run keytool -list -v -keystore C:\TestApp.keyStore to generate the SHA-256 certificate fingerprint based on the keystore file of the app. Then, configure the fingerprint in AppGallery Connect.
2. Download the agconnect-services.json file and place it in the Assets/Plugins/Android directory of your Unity project.
1.1.5 Enabling HUAWEI AnalyticsFor details, please refer to the development guide.
1.1.6 Adding the HmsAnalyticActivity.java File1. Destination directory:
2. File content:
Code:
<p style="line-height: 1.5em;">package com.hms.hms_analytic_activity;
import android.os.Bundle;
import com.huawei.hms.analytics.HiAnalytics;
import com.huawei.hms.analytics.HiAnalyticsTools;
import com.unity3d.player.UnityPlayerActivity;
import com.huawei.agconnect.appmessaging.AGConnectAppMessaging;
import com.huawei.hms.aaid.HmsInstanceId;
import com.hw.unity.Agc.Auth.ThirdPartyLogin.LoginManager;
import android.content.Intent;
import java.lang.Boolean;
import com.unity3d.player.UnityPlayer;
import androidx.core.app.ActivityCompat;
public class HmsAnalyticActivity extends UnityPlayerActivity {
private AGConnectAppMessaging appMessaging;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
HiAnalyticsTools.enableLog();
HiAnalytics.getInstance(this);
appMessaging = AGConnectAppMessaging.getInstance();
if(appMessaging != null){
appMessaging.setFetchMessageEnable(true);
appMessaging.setDisplayEnable(true);
appMessaging.setForceFetch();
}
LoginManager.getInstance().initialize(this);
boolean pretendCallMain = false;
if(pretendCallMain == true){
main();
}
}
private static void callCrash() {
throwCrash();
}
private static void throwCrash() {
throw new NullPointerException();
}
public static void main(){
JavaCrash();
}
private static void JavaCrash(){
new Thread(new Runnable() {
@Override
public void run() { // Sub-thread.
UnityPlayer.currentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
callCrash();
}
});
}
}).start();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
LoginManager.getInstance().onActivityResult(requestCode, resultCode, data);
}
}</p>
1.2 App Development with the Official Asset1.2.1 Sample Code
Code:
<p style="line-height: 1.5em;">using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HuaweiHms;
public class AnalyticTest : MonoBehaviour
{
private HiAnalyticsInstance instance;
private int level = 0;
// Start() is called before the first frame update.
void Start()
{
}
// Update() is called once per frame.
void Update()
{
}
public AnalyticTest()
{
// HiAnalyticsTools.enableLog();
// instance = HiAnalytics.getInstance(new Context());
}
public void AnalyticTestMethod()
{
HiAnalyticsTools.enableLog();
instance = HiAnalytics.getInstance(new Context());
instance.setAnalyticsEnabled(true);
Bundle b1 = new Bundle();
b1.putString("test", "123456");
instance.onEvent("debug", b1);
}
public void SetUserId()
{
instance.setUserId("unity test Id");
// Util.showToast("userId set");
}
public void SendProductId()
{
Bundle b1 = new Bundle();
b1.putString(HAParamType.PRODUCTID, "123456");
instance.onEvent(HAEventType.ADDPRODUCT2CART, b1);
// Util.showToast("product id set");
}
public void SendAnalyticEnable()
{
enabled = !enabled;
instance.setAnalyticsEnabled(enabled);
// TestTip.Inst.ShowText(enabled ? "ENABLED" : "DISABLED");
}
public void CreateClearCache()
{
instance.clearCachedData();
// Util.showToast("Clear Cache");
}
public void SetFavoriteSport()
{
instance.setUserProfile("favor_sport", "running");
// Util.showToast("set favorite");
}
public void SetPushToken()
{
instance.setPushToken("fffff");
// Util.showToast("set push token as ffff");
}
public void setMinActivitySessions()
{
instance.setMinActivitySessions(10000);
// Util.showToast("setMinActivitySessions 10000");
}
public void setSessionDuration()
{
instance.setSessionDuration(900000);
// Util.showToast("setMinActivitySessions 900000");
}
public void getUserProfiles()
{
getUserProfiles(false);
getUserProfiles(true);
}
public void getUserProfiles(bool preDefined)
{
var profiles = instance.getUserProfiles(preDefined);
var keySet = profiles.keySet();
var keyArray = keySet.toArray();
foreach (var key in keyArray)
{
// TestTip.Inst.ShowText($"{key}: {profiles.getOrDefault(key, "default")}");
}
}
public void pageStart()
{
instance.pageStart("page test", "page test");
// TestTip.Inst.ShowText("set page start: page test, page test");
}
public void pageEnd()
{
instance.pageEnd("page test");
// TestTip.Inst.ShowText("set page end: page test");
}
public void enableLog()
{
HiAnalyticsTools.enableLog(level + 3);
// TestTip.Inst.ShowText($"current level {level + 3}");
level = (level + 1) % 4;
}
}</p>
1.2.2 Testing the APK1. Generate the APK.
Go to File > Build Settings > Android, click Switch Platform, and then Build And Run.
2. Enable the debug mode.
3. Go to the real-time overview page of Analytics Kit in AppGallery Connect.
Sign in to AppGallery Connect and click My projects. Select one of your projects and go to HUAWEI Analytics > Overview > Real-time overview.
4. Call AnalyticTestMethod() to display analysis events reported.
Our official website
Demo for Analytics Kit
Our Development Documentation page, to find the documents you need:
Android SDK
Web SDK
Quick APP SDK
If you have any questions about HMS Core, you can post them in the community on the HUAWEI Developers website or submit a ticket online.
We’re looking forward to seeing what you can achieve with HUAWEI Analytics!
More Information
To join in on developer discussion forums
To download the demo app and sample code
For solutions to integration-related issues
Checkout in forum
Related
More articles like this, you can visit HUAWEI Developer Forum.
In this article, we will build Android App Bundle (AAB).
In the previous article, we have learned about Huawei Dynamic Ability. Refer the URL:
https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201297090480680014&fid=0101187876626530001
If you have not read my previous article which is part 1 of this article. I would recommend you to kindly go through the link below:
https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201297090480680014&fid=0101187876626530001
1. Dynamic Ability:
Dynamic Ability is a service in which HUAWEI AppGallery implements dynamic loading based on the Android App Bundle technology.
Apps integrated with the Dynamic Ability SDK can dynamically download features or language packages from HUAWEI AppGallery as required, reducing the unnecessary consumption of network traffic and device storage space.
2. Android App Bundle:
It is a new upload format that includes all your apps compiled code and resources, but accepts APK generation and signing to AppGallery. Traditionally, Android apps are distributed using a special file called an Android Package (.apk).
Let’s start development:
We have created following project directory:
{
"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"
}
Let’s see the gradle file:
Code:
apply plugin: 'com.android.application'
apply plugin: 'com.huawei.agconnect'
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
dataBinding {
enabled = true
}
defaultConfig {
applicationId "com.hms.manoj.aab"
minSdkVersion 26
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
dynamicFeatures = [":repository", ":retrofit", ":viewmodel"]
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// Android MVVM Components
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
// Android Support Library
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.google.android.material:material:1.1.0-alpha04'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
//Huawei Dynamic ability
api 'com.huawei.hms:dynamicability:1.0.11.302'
}
Let’s see the manifest file:
Code:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hms.manoj.aab">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name="com.hms.manoj.aab.MyApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name="com.hms.manoj.aab.ui.ShowsActivity"
android:launchMode="singleTask"
android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustNothing">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.hms.manoj.aab.ui.ShowDetailActivity"
android:screenOrientation="fullSensor"
android:label="@string/app_name" />
<activity
android:name="com.hms.manoj.aab.ui.CastActivity"
android:screenOrientation="fullSensor"
android:label="@string/app_name" />
</application>
</manifest>
Let’s see the implementation of feature installation inside the code:
Code:
package com.hms.manoj.aab.ui;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.GridLayoutManager;
import com.hms.manoj.aab.R;
import com.hms.manoj.aab.apiconnector.response.Show;
import com.hms.manoj.aab.databinding.ActivityShowsBinding;
import com.hms.manoj.aab.ui.adapter.ShowAdapter;
import com.hms.manoj.aab.viewmodel.ShowsViewModel;
import com.huawei.hms.feature.install.FeatureInstallManager;
import com.huawei.hms.feature.install.FeatureInstallManagerFactory;
import com.huawei.hms.feature.listener.InstallStateListener;
import com.huawei.hms.feature.model.FeatureInstallException;
import com.huawei.hms.feature.model.FeatureInstallRequest;
import com.huawei.hms.feature.model.FeatureInstallSessionStatus;
import com.huawei.hms.feature.model.InstallState;
import com.huawei.hms.feature.tasks.FeatureTask;
import com.huawei.hms.feature.tasks.listener.OnFeatureCompleteListener;
import com.huawei.hms.feature.tasks.listener.OnFeatureFailureListener;
import com.huawei.hms.feature.tasks.listener.OnFeatureSuccessListener;
import java.util.List;
import static com.hms.manoj.aab.utils.Utils.KEY_SHOW_ID;
public class ShowsActivity extends AppCompatActivity {
public static final String TAG=ShowsActivity.class.getName();
private FeatureInstallManager mFeatureInstallManager;
private int sessionId = 10086;
private ActivityShowsBinding mBinding;
private ShowsViewModel mShowsViewModel;
private InstallStateListener mStateUpdateListener = new InstallStateListener() {
@Override
public void onStateUpdate(InstallState state) {
Log.d(TAG, "install session state " + state);
if (state.status() == FeatureInstallSessionStatus.REQUIRES_USER_CONFIRMATION) {
try {
mFeatureInstallManager.triggerUserConfirm(state, ShowsActivity.this, 1);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
return;
}
if (state.status() == FeatureInstallSessionStatus.REQUIRES_PERSON_AGREEMENT) {
try {
mFeatureInstallManager.triggerUserConfirm(state, ShowsActivity.this, 1);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
return;
}
if (state.status() == FeatureInstallSessionStatus.INSTALLED) {
Log.i(TAG, "installed success ,can use new feature");
return;
}
if (state.status() == FeatureInstallSessionStatus.UNKNOWN) {
Log.e(TAG, "installed in unknown status");
return;
}
if (state.status() == FeatureInstallSessionStatus.DOWNLOADING) {
long process = state.bytesDownloaded() * 100 / state.totalBytesToDownload();
Log.d(TAG, "downloading percentage: " + process);
return;
}
if (state.status() == FeatureInstallSessionStatus.FAILED) {
Log.e(TAG, "installed failed, errorcode : " + state.errorCode());
return;
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setTitle("All Shows");
mFeatureInstallManager = FeatureInstallManagerFactory.create(this);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_shows);
mShowsViewModel = ViewModelProviders.of(this).get(ShowsViewModel.class);
wait(true);
getShowList();
}
public void installFeature(View view) {
if (mFeatureInstallManager == null) {
return;
}
FeatureInstallRequest request = FeatureInstallRequest.newBuilder()
.addModule("repository")
.addModule("retrofit")
.addModule("viewmodel")
.build();
final FeatureTask<Integer> task = mFeatureInstallManager.installFeature(request);
task.addOnListener(new OnFeatureSuccessListener<Integer>() {
@Override
public void onSuccess(Integer integer) {
Log.d(TAG, "load feature onSuccess.session id:" + integer);
}
});
task.addOnListener(new OnFeatureFailureListener<Integer>() {
@Override
public void onFailure(Exception exception) {
if (exception instanceof FeatureInstallException) {
int errorCode = ((FeatureInstallException) exception).getErrorCode();
Log.d(TAG, "load feature onFailure.errorCode:" + errorCode);
} else {
exception.printStackTrace();
}
}
});
task.addOnListener(new OnFeatureCompleteListener<Integer>() {
@Override
public void onComplete(FeatureTask<Integer> featureTask) {
if (featureTask.isComplete()) {
Log.d(TAG, "complete to start install.");
if (featureTask.isSuccessful()) {
Integer result = featureTask.getResult();
sessionId = result;
Log.d(TAG, "succeed to start install. session id :" + result);
} else {
Log.d(TAG, "fail to start install.");
Exception exception = featureTask.getException();
exception.printStackTrace();
}
}
}
});
Log.d(TAG, "start install func end");
}
private void wait(boolean isLoading) {
if (isLoading) {
mBinding.loaderLayout.rootLoader.setVisibility(View.VISIBLE);
mBinding.layout.shows.setVisibility(View.GONE);
} else {
mBinding.loaderLayout.rootLoader.setVisibility(View.GONE);
mBinding.layout.shows.setVisibility(View.VISIBLE);
}
}
private void getShowList() {
mShowsViewModel.getShowsLiveData().observeForever(showList -> {
if (showList != null) {
wait(false);
String eventName = "Show Success";
Bundle bundle = new Bundle();
bundle.putInt("Show Size", showList.size());
setDataIntoAdapter(showList);
} else {
wait(false);
}
});
}
private void setDataIntoAdapter(List<Show> list) {
mBinding.layout.shows.setLayoutManager(new GridLayoutManager(this, 2));
mBinding.layout.shows.setAdapter(new ShowAdapter(list, (item) -> {
Intent intent = new Intent(getBaseContext(), ShowDetailActivity.class);
intent.putExtra(KEY_SHOW_ID, String.valueOf(item.getId()));
String eventName = "Choosed Show";
Bundle bundle = new Bundle();
bundle.putInt("Show ID", item.getId());
startActivity(intent);
}));
}
@Override
protected void onResume() {
super.onResume();
if (mFeatureInstallManager != null) {
mFeatureInstallManager.registerInstallListener(mStateUpdateListener);
}
}
@Override
protected void onPause() {
super.onPause();
if (mFeatureInstallManager != null) {
mFeatureInstallManager.unregisterInstallListener(mStateUpdateListener);
}
}
}
We will create 3 Dynamic Feature module under android project.
1. Repository Module
2. Network Module
3. ViewModel Module
Let’s create Repository Module:
In this module, we have created ShowRepository class which communicate between network and UI components.
Let’s see gradle file:
Code:
apply plugin: 'com.android.dynamic-feature'
android {
compileSdkVersion 29
defaultConfig {
minSdkVersion 27
targetSdkVersion 29
versionCode 1
versionName "1.0"
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':app')
// RxAndroid
implementation 'io.reactivex.rxjava2:rxjava:2.2.8'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
}
Note: Module should have this in the first line, as it is a dynamic feature:
Code:
apply plugin: 'com.android.dynamic-feature'
Let’s see manifest file of this module:
Code:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.hms.android.repository">
<dist:module
dist:instant="false"
dist:title="@string/title_repository">
<dist:delivery>
<dist:on-demand />
</dist:delivery>
<dist:fusing dist:include="true" />
</dist:module>
</manifest>
Let’s create Network Module:
In this module, we have implemented all business model.
Let’s see gradle file:
Code:
apply plugin: 'com.android.dynamic-feature'
android {
compileSdkVersion 29
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
defaultConfig {
minSdkVersion 27
targetSdkVersion 29
versionCode 1
versionName "1.0"
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':app')
// RxAndroid
implementation 'io.reactivex.rxjava2:rxjava:2.2.8'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
// Android MVVM Components
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
}
Let’s see manifest file of this module:
Code:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.hms.android.viewmodel">
<dist:module
dist:instant="false"
dist:title="@string/title_viewmodel">
<dist:delivery>
<dist:on-demand />
</dist:delivery>
<dist:fusing dist:include="true" />
</dist:module>
</manifest>
Let’s build Android App Bundle:
We need to follow the following steps to generate .aab file.
Follow the steps to generate aab file.
1. Step: Goto->Build->Build Bundle(s)/APK(s)->Build Bundle(s). Choose Build > Build Bundle(s)/APK(s) > Build Bundle(s)
2. After build success, following dialog-box displayed.
3. Click locate text and the output folder will be displayed.
Note: Singing the aab file carefully and upload on AppGallery portal.
4. Provide your project/app information in AppGallery portal:
5. Upload your aab/apk file in draft section.
Now We can download the application from app gallery(After approval).
Time being, we can run that apk in our mobile device.
Let's see the result.
If you have any doubts or queries. Leave your valuable comment below.
More information like this, you can visit HUAWEI Developer Forumhttps://forums.developer.huawei.com...l/en/home?channelname=HuoDong59&ha_source=xda
Introduction:
In this article, we will cover Integration of AGC App Linking in Unity Project using Official Plugin (Huawei HMS Core App Services).
Requirements:
1. Unity Editor
2. Huawei device
3. Visual Studio
Follows the steps.
Step 1. Create Unity Project.
Click unity icon.
Click NEW, select 3D, Project Name and Location.
Click CREATE, as follows.
{
"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"
}
Step 2. Click Asset Store, search Huawei HMS Core App Services and click Import, as follows.
Step 3. Once import is successful, verify directory in Assets > Huawei HMS Core App Services path, as follows.
Step 4. Click Console and create a New Project.
Step 5. Choose Project Settings > Player and edit the required options in Publishing Settings, as follows.
Step 6. Verify the files created in Step 5.
Step 7. Download agconnect-services.json and copy to Assets>Plugins>Android, as follows.
Step 8. Update the Package Name.
Step 9. Open LauncherTemplate.gradle and add below line
Code:
apply plugin: 'com.huawei.agconnect'
Step 10. Open "baseProjectTemplate.gradle" and add lines, as follows.
Code:
maven {url 'https://developer.huawei.com/repo/'}
Code:
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
Step 11. Open "mainTemplate.gradle" and add lines like shown below
Code:
apply plugin: 'com.huawei.agconnect'
Code:
implementation 'com.huawei.agconnect:agconnect-core:1.4.1.300'
implementation 'com.huawei.agconnect:agconnect-applinking:1.4.0.300'
implementation 'com.huawei.hms:hianalytics:5.0.3.300'
Step 12. Open AndroidManifest file and Add Activity like shown below.
Code:
<activity android:name="com.hms.hms_analytic_activity.TestAppLinksActivity"
android:theme="@style/UnityThemeSelector">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="developer.huawei.com" android:scheme="https" />
<data android:host="developer.huawei.com" android:scheme="http" />
</intent-filter>
</activity>
Step 13. Create TestAppLinksActivity.java, JavaCallBack.java and place it in Assets->Plugins->Android.
Code:
//package com.test.applinks;
package com.hms.hms_analytic_activity;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import com.unity3d.player.UnityPlayerActivity;
import android.widget.Toast;
import com.huawei.agconnect.applinking.AGConnectAppLinking;
import com.huawei.agconnect.applinking.AppLinking;
import com.huawei.agconnect.applinking.ShortAppLinking;
//import androidx.appcompat.app.AppCompatActivity;
import com.huawei.agconnect.applinking.AGConnectAppLinking;
public class TestAppLinksActivity extends UnityPlayerActivity {
public static JavaCallback callback;
private static String agcLink = null;
private static final String DOMAIN_URI_PREFIX = "https://testulink.dra.agconnect.link";
//private static final String DEEP_LINK = "rmOb2";
private static final String DEEP_LINK = "https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides?id=123";
private static String deepLinkData = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("TestAppLinksActivity", "TestAppLinksActivity onCreate>> @@");
mContext = this.getApplicationContext();
handleAppLinking(getIntent());
}
public static void setCallback(JavaCallback callback1) {
Log.e("TestAppLinksActivityl", "setCallback>> @@");
callback = callback1;
if(callback != null){
Log.e("TestAppLinksActivity", "update c # script >>>>");
callback.OnJavaCallback(deepLinkData);
}else{
Log.e("TestAppLinksActivity", "TestAppLinksActivity callback is null plz initialize >>>>");
}
}
private void handleAppLinking(Intent intent) {
AGConnectAppLinking.getInstance().getAppLinking(this, intent).addOnSuccessListener(resolvedLinkData -> {
Uri deepLink = null;
if (resolvedLinkData != null) {
deepLink = resolvedLinkData.getDeepLink();
Log.e("TestAppLinksActivity", " [email protected]!!!$$->"+deepLink.toString());
deepLinkData = deepLink.toString();
if(callback != null){
Log.e("TestAppLinksActivity", "update c # script");
callback.OnJavaCallback(deepLink.toString());
}else{
Log.e("TestAppLinksActivity", "callback is null plz initialize");
}
}
}).addOnFailureListener(e -> {
Log.e("TestAppLinksActivity", "getAppLinking:onFailure", e);
});
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
handleAppLinking(intent);
}
public static void createAppLinking() {
AppLinking.Builder builder = new AppLinking.Builder().setUriPrefix(DOMAIN_URI_PREFIX)
.setDeepLink(Uri.parse(DEEP_LINK));
//longTextView.setText(builder.buildAppLinking().getUri().toString());
Log.e("TestAppLinksActivity", "createAppLinking long -->"+builder.buildAppLinking().getUri().toString());
agcLink = builder.buildAppLinking().getUri().toString();
builder.buildShortAppLinking(ShortAppLinking.LENGTH.SHORT).addOnSuccessListener(shortAppLinking -> {
//shortTextView.setText(shortAppLinking.getShortUrl().toString());
Log.e("TestAppLinksActivity", "createAppLinking short -->"+shortAppLinking.getShortUrl().toString());
agcLink = shortAppLinking.getShortUrl().toString();
}).addOnFailureListener(e -> {
//Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
Log.e("TestAppLinksActivity", "createAppLinking failure -->"+e.getMessage());
});
}
//public void shareLink() {
public static void shareLink(Activity activity){
if (agcLink != null) {
Log.e("TestAppLinksActivity", "shareLink agcLink is not null start activity");
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, agcLink);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);
//startActivity(intent);
}else{
Log.e("TestAppLinksActivity", " shareLink agcLink is null");
}
}
private static Context mContext;
public static Context getAppContext(){
return mContext;
}
}
code explanation : https://developer.huawei.com/consumer/en/codelab/AppLinking/index.html#7
Code:
package com.hms.hms_analytic_activity;
public interface JavaCallback {
void OnJavaCallback(String index);
}
Note : Java classes are using package name com.hms.hms_analytic_activity & we dont create any folder structure, this is allowed.
For full content, you can visit https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0202361288668900258&fid=0101188387844930001
Introduction
This article is based on Multiple HMS services application. I have created Hotel Booking application using HMS Kits. We need mobile app for reservation hotels when we are traveling from one place to another place.
In this article, I am going to implement HMS Location Kit & Shared Preferences.
{
"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"
}
Flutter setup
Refer this URL to setup Flutter.
Software Requirements
1. Android Studio 3.X
2. JDK 1.8 and later
3. SDK Platform 19 and later
4. Gradle 4.6 and later
Steps to integrate service
1. We need to register as a developer account in AppGallery Connect.
2. Create an app by referring to Creating a Project and Creating an App in the Project
3. Set the data storage location based on current location.
4. Enabling Required Services: Location Kit.
5. Generating a Signing Certificate Fingerprint.
6. Configuring the Signing Certificate Fingerprint.
7. Get your agconnect-services.json file to the app root directory.
Important: While adding app, the package name you enter should be the same as your Flutter project’s package name.
Note: Before you download agconnect-services.json file, make sure the required kits are enabled.
Development Process
Create Application in Android Studio.
1. Create Flutter project.
2. App level gradle dependencies. Choose inside project Android > app > build.gradle.
Code:
apply plugin: 'com.android.application'
apply plugin: 'com.huawei.agconnect'
Root level gradle dependencies
Code:
maven {url 'https://developer.huawei.com/repo/'}
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
Add the below permissions in Android Manifest file.
Code:
<manifest xlmns:android...>
...
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="com.huawei.hms.permission.ACTIVITY_RECOGNITION" />
<application ...
</manifest>
3. Refer below URL for cross-platform plugins. Download required plugins.
https://developer.huawei.com/consum...y-V1/flutter-sdk-download-0000001050304074-V1
4. After completing all the steps above, you need to add the required kits’ Flutter plugins as dependencies to pubspec.yaml file. You can find all the plugins in pub.dev with the latest versions.
Code:
dependencies:
flutter:
sdk: flutter
shared_preferences: ^0.5.12+4
bottom_navy_bar: ^5.6.0
cupertino_icons: ^1.0.0
provider: ^4.3.3
huawei_location:
path: ../huawei_location/
flutter:
uses-material-design: true
assets:
- assets/images/
5. After adding them, run flutter pub get command. Now all the plugins are ready to use.
6. Open main.dart file to create UI and business logics.
Location kit
HUAWEI Location Kit assists developers in enabling their apps to get quick and accurate user locations and expand global positioning capabilities using GPS, Wi-Fi, and base station locations.
Fused location: Provides a set of simple and easy-to-use APIs for you to quickly obtain the device location based on the GPS, Wi-Fi, and base station location data.
Activity identification: Identifies user motion status through the acceleration sensor, cellular network information, and magnetometer, helping you adjust your app based on user behaviour.
Geofence: Allows you to set an interested area through an API so that your app can receive a notification when a specified action (such as leaving, entering, or lingering in the area) occurs.
Integration
Permissions
First of all we need permissions to access location and physical data.
Create a PermissionHandler instance,add initState() for initialize.
Code:
final PermissionHandler permissionHandler;
@override
void initState() {
permissionHandler = PermissionHandler(); super.initState();
}
Check Permissions
We need to check device has permission or not using hasLocationPermission() method.
Code:
void hasPermission() async {
try {
final bool status = await permissionHandler.hasLocationPermission();
if(status == true){
showToast("Has permission: $status");
}else{
requestPermission();
}
} on PlatformException catch (e) {
showToast(e.toString());
}
}
If device don’t have permission,then request for Permission to use requestLocationPermission() method.
Code:
void requestPermission() async {
try {
final bool status = await permissionHandler.requestLocationPermission();
showToast("Is permission granted");
} on PlatformException catch (e) {
showToast(e.toString());
}
}
Fused Location
Create FusedLocationPrvoiderClient instance using the init() method and use the instance to call location APIs.
Code:
final FusedLocationProviderClient locationService
@override
void initState() {
locationService = FusedLocationProviderClient(); super.initState();
}
getLastLocation()
Code:
void getLastLocation() async {
try {
Location location = await locationService.getLastLocation();
setState(() {
lastlocation = location.toString();
print("print: " + lastlocation);
});
} catch (e) {
setState(() {
print("error: " + e.toString());
});
}
}
getLastLocationWithAddress()
Create LocationRequest instance and set required parameters.
Code:
final LocationRequest locationRequest;
locationRequest = LocationRequest()
..needAddress = true
..interval = 5000;
void _getLastLocationWithAddress() async {
try {
HWLocation location =
await locationService.getLastLocationWithAddress(locationRequest);
setState(() {
String street = location.street;
String city = location.city;
String countryname = location.countryName;
currentAddress = '$street' + ',' + '$city' + ' , ' + '$countryname';
print("res: $location");
});
showToast(currentAddress);
} on PlatformException catch (e) {
showToast(e.toString());
}
}
Location Update using Call back
Create LocationCallback instance and create callback functions in initstate().
Code:
LocationCallback locationCallback;
@override
void initState() {
locationCallback = LocationCallback(
onLocationResult: _onCallbackResult,
onLocationAvailability: _onCallbackResult,
);
super.initState();
}
void requestLocationUpdatesCallback() async {
if (_callbackId == null) {
try {
final int callbackId = await locationService.requestLocationUpdatesExCb(
locationRequest, locationCallback);
_callbackId = callbackId;
} on PlatformException catch (e) {
showToast(e.toString());
}
} else {
showToast("Already requested location updates.");
}
}
void onCallbackResult(result) {
print(result.toString());
showToast(result.toString());
}
I have created Helper class to store user login information in locally using shared Preferences class.
Code:
class StorageUtil {
static StorageUtil _storageUtil;
static SharedPreferences _preferences;
static Future<StorageUtil> getInstance() async {
if (_storageUtil == null) {
var secureStorage = StorageUtil._();
await secureStorage._init();
_storageUtil = secureStorage;
}
return _storageUtil;
}
StorageUtil._();
Future _init() async {
_preferences = await SharedPreferences.getInstance();
}
// get string
static String getString(String key) {
if (_preferences == null) return null;
String result = _preferences.getString(key) ?? null;
print('result,$result');
return result;
}
// put string
static Future<void> putString(String key, String value) {
if (_preferences == null) return null;
print('result $value');
return _preferences.setString(key, value);
}
}
Result
Tips & Tricks
1. Download latest HMS Flutter plugin.
2. To work with mock location we need to add permissions in Manifest.XML.
3. Whenever you updated plugins, click on pug get.
Conclusion
We implemented simple hotel booking application using Location kit in this article. We have learned how to get Lastlocation, getLocationWithAddress and how to use callback method, in flutter how to store data into Shared Preferences in applications.
Thank you for reading and if you have enjoyed this article, I would suggest you to implement this and provide your experience.
Reference
Location Kit URL
Shared Preferences URL
Read full article
Goodjob
Thank you
I thought huawei doesn't support flutter. I guess it should as it is Android only.
good
Wow
Nice.
I thought its not doable
Interesting.
Like
This document describes how to integrate Ads Kit using the official Unity asset. After the integration, your app can use the services of this Kit on HMS mobile phones.
For details about Ads Kit, please visit HUAWEI Developers.
1.1 Restrictions
1.1.1 Ads Supported by the Official Unity Asset
The official asset of version 1.3.4 in Unity supports interstitial ads and rewarded ads of Ads Kit.
Note: To support other types of ads, you can use the Android native integration mode. This document will take the banner ad as an example to describe such integration.
1.1.2 Supported Devices and Unity Versions
{
"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"
}
Note: If the version is earlier than 2018.4.25, you can manually import assets. If there are any unknown build errors that are not caused by the AfterBuildToDo file, upgrade your Unity.
1.1 Preparations
1.1.1 Prerequisites
l HMS Core (APK) 4.0.0.300 or later has been installed on the device. Otherwise, the APIs of the HUAWEI Ads SDK, which depend on HMS Core (APK) 4.0.0.300 or later, cannot be used.
l You have registered as a Huawei developer and completed identity verification on HUAWEI Developers. For details, please refer to Registration and Verification.
You have created a project and add an app to the project in AppGallery Connect by referring to Creating an AppGallery Connect Project and Adding an App to the Project.
For details about applying for a formal ad slot, please visit HUAWEI Developers.
1.1.2 Importing Unity Assets
1. Open Asset Store in Unity.
Go to Window > Asset Store in Unity.
2. Search for the Huawei HMS AGC Services asset. Download and then import it.
3. Import the asset to My Assets, with all services selected.
4. Change the package name.
Go to Edit > Project Settings> Player > Android > Other Settings in Unity, and then set Package Name.
The default package name is com.${Company Name}.${Product Name}. You need to change the package name, and the app will be released to AppGallery with the new name.
1.2.3 Generating .gradle Files1. Enable project gradle.
Go to Edit > Project Settings > Player in Unity, click the Android icon, and go to Publishing Settings > Build.
Enable Custom Main Manifest.
Enable Custom Main Gradle Template.
Enable Custom Launcher Gradle Template.
Enable Custom Base Gradle Template.
2. Generate a signature.
You can use an existing keystore file or create a new one to sign your app.
Go to Edit > Project Settings > Player in Unity, click the Android icon, and go to Publishing Settings > Keystore Manager.
Then, go to Keystore... > Create New.
Enter the password when you open Unity. Otherwise, you cannot build the APK.
1.1.1 Configuring .gradle Files1. Configure the BaseProjectTemplate.gradle file.
Configure the Maven repository address.
Code:
<p style="line-height: 1.5em;">buildscript {
repositories {**ARTIFACTORYREPOSITORY**
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' }
}
repositories {**ARTIFACTORYREPOSITORY**
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' }
flatDir {
dirs "${project(':unityLibrary').projectDir}/libs"
}
}
2. Configure the launcherTemplate.gradle file.
Add dependencies.
apply plugin: 'com.android.application'
apply plugin: 'com.huawei.agconnect'
dependencies {
implementation project(':unityLibrary')
implementation 'com.huawei.hms:ads-lite:13.4.29.303'
}</p>
1.2 App Development with the Official Asset1.2.1 Rewarded AdsRewarded ads are full-screen video ads that allow users to view in exchange for in-app rewards.
1.2.1.1 Sample Code
Code:
<p style="line-height: 1.5em;">using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HuaweiHms;
namespace Demo
{
public class RewardDemo : MonoBehaviour
{
public void LoadRewardAds()
{
// Create a RewardAd object.
// "testx9dtjwj8hp" is the test ad slot. You can use it to perform a test. Replace the test slot with a formal one for official release.
RewardAd rewardAd = new RewardAd(new Context(), "testx9dtjwj8hp");
AdParam.Builder builder = new AdParam.Builder();
AdParam adParam = builder.build();
// Load the ad.
rewardAd.loadAd(adParam, new MRewardLoadListener(rewardAd));
}
}
// Listen for ad events.
public class MRewardLoadListener:RewardAdLoadListener
{
private RewardAd ad;
public rewardLoadListener(RewardAd _ad)
{
ad = _ad;
}
public override void onRewardAdFailedToLoad(int arg0)
{
}
public override void onRewardedLoaded()
{
ad.show(new Context(),new RewardAdStatusListener());
}
}
}</p>
1.3.1.2 Testing the APKGo to File > Build Settings > Android, click Switch Platform and then Build And Run.
1.3.2 Interstitial Ads1.3.2.1 Sample Code
Code:
<p style="line-height: 1.5em;">using UnityEngine;
using HuaweiService;
using HuaweiService.ads;
namespace Demo
{
public class interstitialDemo : MonoBehaviour
{
public void LoadImageAds()
{
// Create an ad object.
// "testb4znbuh3n2" and "teste9ih9j0rc3" are test ad slots. You can use them to perform a test. Replace the test slots with formal ones for official release.
InterstitialAd ad = new InterstitialAd(new Context());
ad.setAdId("teste9ih9j0rc3");
ad.setAdListener(new MAdListener(ad));
AdParam.Builder builder = new AdParam.Builder();
AdParam adParam = builder.build();
// Load the ad.
ad.loadAd(adParam);
}
public void LoadVideoAds()
{
InterstitialAd ad = new InterstitialAd(new Context());
ad.setAdId("testb4znbuh3n2");
ad.setAdListener(new MAdListener(ad));
AdParam.Builder builder = new AdParam.Builder();
ad.loadAd(builder.build());
}
public class MAdListener : AdListener
{
private InterstitialAd ad;
public MAdListener(InterstitialAd _ad) : base()
{
ad = _ad;
}
public override void onAdLoaded()
{
// Display the ad if it is successfully loaded.
ad.show();
}
public override void onAdFailed(int arg0)
{
}
public override void onAdOpened()
{
}
public override void onAdClicked()
{
}
public override void onAdLeave()
{
}
public override void onAdClosed()
{
}
}
}
}</p>
1.4 App Development with Android Studio1.4.1 Banner Ads1.4.1.1 Loading Banner Ads on a Page as RequiredAndroidJavaClass javaClass = new AndroidJavaClass("com.unity3d.player.UnityPlayerActivity");
javaClass.CallStatic("loadBannerAds");
1.4.1.2 Exporting Your Project from UnityGo to File > Build Settings > Android and click Switch Platform. Then, click Export Project, select your project, and click Export.
1.4.1.3 Integrating the Banner Ad Function in Android StudioOpen the exported project in Android Studio.
Add implementation 'com.huawei.hms:ads-lite:13.4.29.303' to build.gradle in the src directory.
1. Add code related to banner ads to UnityPlayerActivity.
a. Define the static variable bannerView.
Code:
<p style="line-height: 1.5em;">private static BannerView
bannerView
;</p>
b. Add the initialization of bannerView to the onCreate method.
Code:
<p style="line-height: 1.5em;">bannerView = new BannerView(this);
bannerView.setAdId("testw6vs28auh3");
bannerView.setBannerAdSize(BannerAdSize.BANNER_SIZE_360_57);
mUnityPlayer.addView(bannerView);</p>
c. Add the following static method for loading ads in the Android Studio project, and then build and run the project.
Code:
<p style="line-height: 1.5em;">public static void loadBannerAds()
{ // "testw6vs28auh3" is a dedicated test ad slot ID. Before releasing your app, replace the test ad slot ID with the formal one.
AdParam adParam = new AdParam.Builder().build();
bannerView.loadAd(adParam);
}</p>
d. If banner ads need to be placed at the bottom of the page, refer to the following code:
Code:
<p style="line-height: 1.5em;">// Set up activity layout.
@Override protected void onCreate(Bundle savedInstanceState)
{
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity"));
getIntent().putExtra("unity", cmdLine);
RelativeLayout relativeLayout = new RelativeLayout(this);
mUnityPlayer = new UnityPlayer(this, this);
setContentView(relativeLayout);
relativeLayout.addView(mUnityPlayer);
mUnityPlayer.requestFocus();
bannerView = new BannerView(this);
bannerView.setAdId("testw6vs28auh3");
bannerView.setBannerAdSize(BannerAdSize.BANNER_SIZE_360_57);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); relativeLayout.addView(bannerView,layoutParams);
}
public static void LoadBannerAd() {
// "testw6vs28auh3" is a dedicated test ad slot ID. Before releasing your app, replace the test ad slot ID with the formal one.
AdParam adParam = new AdParam.Builder().build();
bannerView.loadAd(adParam);
bannerView.setAdListener(new AdListener()
{
@Override
public void onAdFailed(int errorCode)
{
Log.d("BannerAds" ,"error" + errorCode);
}
});
}</p>
1.5 FAQs1. If an error indicating invalid path is reported when you export a project from Unity, change the export path to Downloads or Desktop.
2. Unity of a version earlier than 2018.4.25 does not support asset download from Asset Store. You can download the asset using Unity of 2018.4.25 or a later version, export it, and then import it to Unity of an earlier version.
More Information
To join in on developer discussion forums
To download the demo app and sample code
For solutions to integration-related issues
Checkout in forum
Audio Editor Kit from HMS Core provides the audio source separation function, which allows you to separate human voices, human voices from accompaniments, and human voices from musical instrument sounds. The image below shows the accompaniment separated from Dream it Possible.
{
"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"
}
Let's see how to implement this function.
Step 1 Prepare the File for Audio Source SeparationAn MP3 audio file is recommended. If this is not possible, follow the instructions in step 2 to convert your audio file to an MP3 file. What if the accompaniment to be separated is in a video file? No worries. Just extract the video's audio first by referring to the instructions in step 2.
Step 2 Integrate Audio Editor KitDevelopment PracticePreparations
1. Configure the Maven repository address in the project-level build.gradle file.
Code:
buildscript {
repositories {
google()
jcenter()
// Configure the Maven repository address for the HMS Core SDK.
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
...
// Add the AppGallery Connect plugin configuration.
classpath 'com.huawei.agconnect:agcp:1.4.2.300'
}
}
allprojects {
repositories {
google()
jcenter()
// Configure the Maven repository address for the HMS Core SDK.
maven {url 'https://developer.huawei.com/repo/'}
}
}
2. Add the following configuration under the declaration in the file header.
Code:
apply plugin: 'com.huawei.agconnect'
3. Add the build dependency on the Audio Editor SDK in the app-level build.gradle file.
Code:
dependencies{
implementation 'com.huawei.hms:audio-editor-ui:{version}'
}
4. Apply for the following permissions in the AndroidManifest.xml file:
Code:
<!-- Vibrate -->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- Microphone -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- Write into storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Read from storage -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Connect to Internet -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Obtain the network status -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Obtain the changed network connectivity state -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
Code Development1. Create your app's custom activity and use it for selecting one or more audio files. Return their paths to the Audio Editor SDK in the following way
Code:
// Return the audio file paths to the audio editing screen.
private void sendAudioToSdk() {
// Set filePath to the obtained audio file path.
String filePath = "/sdcard/AudioEdit/audio/music.aac";
ArrayList<String> audioList = new ArrayList<>();
audioList.add(filePath);
// Return the paths to the audio editing screen.
Intent intent = new Intent();
// Use HAEConstant.AUDIO_PATH_LIST provided by the Audio Editor SDK.
intent.putExtra(HAEConstant.AUDIO_PATH_LIST, audioList);
// Use HAEConstant.RESULT_CODE provided by the Audio Editor SDK as the result code.
this.setResult(HAEConstant.RESULT_CODE, intent);
finish();
}
2. Register the activity in the AndroidManifest.xml file as described in the following code. When you choose to import the selected audio files, the SDK will send an intent with the action value com.huawei.hms.audioeditor.chooseaudio to jump to the activity.
Code:
<activity android:name="Activity ">
<intent-filter>
<action android:name="com.huawei.hms.audioeditor.chooseaudio"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
3. Launch the audio editing screen. When you tap Add audio, the SDK will automatically call the activity defined earlier. Then you will be able to edit the audio and add special effects to the audio. After such operations are complete, the edited audio can be exported.
Code:
HAEUIManager.getInstance().launchEditorActivity(this);
4. Convert the audio file format that is not MP3 to MP3 (Optional)
Call transformAudioUseDefaultPath to convert the audio format and save the converted audio to the default directory.
Code:
// Convert the audio format.
HAEAudioExpansion.getInstance().transformAudioUseDefaultPath(context,inAudioPath, audioFormat, new OnTransformCallBack() {
// Called to receive the progress which ranges from 0 to 100.
@Override
public void onProgress(int progress) {
}
// Called when the conversion fails.
@Override
public void onFail(int errorCode) {
}
// Called when the conversion succeeds.
@Override
public void onSuccess(String outPutPath) {
}
// Called when the conversion is canceled.
@Override
public void onCancel() {
}
});
// Cancel format conversion.
HAEAudioExpansion.getInstance().cancelTransformAudio();
Call transformAudio to convert the audio format and save the converted audio to a specified directory.
Code:
// Convert the audio format.
HAEAudioExpansion.getInstance().transformAudio(context,inAudioPath, outAudioPath, new OnTransformCallBack(){
// Called to receive the progress which ranges from 0 to 100.
@Override
public void onProgress(int progress) {
}
// Called when the conversion fails.
@Override
public void onFail(int errorCode) {
}
// Called when the conversion succeeds.
@Override
public void onSuccess(String outPutPath) {
}
// Called when the conversion is canceled.
@Override
public void onCancel() {
}
});
// Cancel format conversion.
HAEAudioExpansion.getInstance().cancelTransformAudio();
5. Call extractAudio to extract audio from a video, which contains the accompaniment to be separated, to a specified directory. (Optional)
Code:
// outAudioDir (optional): path of the directory for storing the extracted audio.
// outAudioName (optional): name of the extracted audio, which does not contain the file name extension.
HAEAudioExpansion.getInstance().extractAudio(context,inVideoPath,outAudioDir, outAudioName,new AudioExtractCallBack() {
@Override
public void onSuccess(String audioPath) {
Log.d(TAG, "ExtractAudio onSuccess : " + audioPath);
}
@Override
public void onProgress(int progress) {
Log.d(TAG, "ExtractAudio onProgress : " + progress);
}
@Override
public void onFail(int errCode) {
Log.i(TAG, "ExtractAudio onFail : " + errCode);
}
@Override
public void onCancel() {
Log.d(TAG, "ExtractAudio onCancel.");
}
});
// Cancel audio extraction.
HAEAudioExpansion.getInstance().cancelExtractAudio();
6. Call getInstruments and startSeparationTasks for audio source separation.
Code:
// Obtain the accompaniment ID using getInstruments and pass the ID to startSeparationTasks.
HAEAudioSeparationFile haeAudioSeparationFile = new HAEAudioSeparationFile();
haeAudioSeparationFile.getInstruments(new SeparationCloudCallBack<List<SeparationBean>>() {
@Override
public void onFinish(List<SeparationBean> response) {
// Called to receive the separation data including the accompaniment ID.
}
@Override
public void onError(int errorCode) {
// Called when an error occurs during separation.
}
});
// Set the parameter for separation.
List instruments = new ArrayList<>();
instruments.add ("accompaniment ID")
haeAudioSeparationFile.setInstruments(instruments);
// Start separating.
haeAudioSeparationFile.startSeparationTasks(inAudioPath, outAudioDir, outAudioName, new AudioSeparationCallBack() {
@Override
public void onResult(SeparationBean separationBean) { }
@Override
public void onFinish(List<SeparationBean> separationBeans) {}
@Override
public void onFail(int errorCode) {}
@Override
public void onCancel() {}
});
// Cancel audio source separation.
haeAudioSeparationFile.cancel();
After completing these steps, you can get the accompaniment you desire. To create something similar to the demo, you can use a video editing program to synthesize the accompaniment with images and lyrics.
ReferencesFor more details, you can go to:
Audio Editor Kit official website
Audio Editor Kit Development Documentation page, to find the documents you need
Reddit to join our developer discussion
GitHub to download AudioEditor Kit sample codes
Stack Overflow to solve any integration problems
Thanks for sharing!!