Introduction
Search!! It’s a sought-after word through the entire software evolution and industry.
What is searching?
Searching is a process of locating a particular element present in a given set of elements. The element may be a record, a table, or a file or a keyword.
What is Search Engine?
A program that searches for and identifies items in a database that correspond to keywords or characters specified by the user, used especially for finding particular sites on the World Wide Web.
“Archie” was the first search engine and it was introduced in 1990 by Alan Entage.
In today’s technical era, search engines has been drastically evolved and it is not limited to only big systems and laptops, their reach is now on your small mobile phone as well.
In fact, you can create your own search engine to have the upper hand on your business in this competitive era.
Huawei Search Kit offers API’s to build your own search platform in Android environment
Huawei Search Kit leverage developers to use the Petal Search capabilities by providing the device-side SDK and cloud side API’s to efficiently enable the search operation on the mobile app.
Note: Petal Search is a mobile search engine of Huawei powered by such cutting-edge technologies as big data, AI, and NLP.
In a typical scenario, any search engine works on the same principles shown in following image.
{
"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"
}
Huawei Search Kit uses the Petal Search engine capabilities in similar fashion by feeding the URL’s to engine’s scheduler which further do the parsing and indexing using Petal search and provide the search results which can be handled the mobile application.
Advantages
1. Speedy application development
2. Efficient search response
3. Cost effective
Note: Huawei Search Kit provides Client and Server side API’s to implement the search platform for your websites.
Responsibilities
To develop end to end solution and implement your own mobile search engine application, following would be your responsibilities:
1. Sites/Websites needs to be developed and maintained by the developers.
2. Receiving and handling the search queries from the end users and transporting them to Huawei for further search operation.
3. Developers are responsible to handle all the communication, modification or removal of the search queries raised by user regarding your website.
4. All the queries sent from your website to the Huawei search kit/engine shall comply all the technical guidelines provided by Huawei.
Development Overview
Prerequisite
1. Must have a Huawei Developer Account
2. Must have Android Studio 3.0 or later
3. Must have a Huawei phone with HMS Core 4.0.2.300 or later
4. EMUI 3.0 or later
Software Requirements
1. Java SDK 1.7 or later
2. Android 5.0 or later
Preparation
1. Create an app or project in the Huawei App Gallery Connect.
2. Provide the SHA Key and App Package name of the project in App Information Section and enable the Search Kit API.
3. Download the agconnect-services.json file.
4. Create an Android project.
Integration
1. Add below to build.gradle (project)file, under buildscript/repositories and allprojects/repositories.
Code:
Maven {url 'http://developer.huawei.com/repo/'}
2. Add below to build.gradle (app) file, under dependencies to use the search kit SDK.
Code:
dependencies{
// Import the SDK.
implementation com.huawei.hms:searchkit:5.0.4.303.
}
Tip: Android minimum version supported by Search kit is 24.
Configuring Network Permissions
To allow HTTP network requests on devices with target version 28 or later, configure the following information in the AndroidManifest.xml file:
Code:
<application
android:usesCleartextTraffic="true">
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Development Process
This article focuses on demonstrating the capabilities of Huawei Search Kit using device side SDK and API’s only.
We will understand the server/website configuration and Search Kit capabilities in next article.
Use Case: The application developed and explained is a very simple mobile search application to web search the products on a associated application.
This article explains client side search capabilities by implementing a mobile search application which only uses the web search API’s and return the search results from the website.
Client Side Development
Initializing Search Kit
You can call SearchKitInstance.init() in an Activity to initialize the SDK.
Code:
import com.huawei.hms.searchkit.SearchKitInstance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
// appID is obtained after your app is created in AppGallery Connect. Its value is of the string type.
// appID is the second parameter that requires to be passed to the init API to initialize Search Kit.
SearchKitInstance.init(this, "103029525");
}
}
Search Activity
Search activity is responsible for:
1 Creating WebSearchRequest() for custom search
Code:
public static final WebSearchRequest webRequest = new WebSearchRequest(); webRequest.setQ(query);
webRequest.setLang(Language.ENGLISH);
webRequest.setLang(Language.FRENCH);
webRequest.setSregion(Region.INDIA);
webRequest.setPn(1);
webRequest.setPs(10);
webRequest.setWithin("www.fragrancespecialities.com");
commonRequest.setQ(query);
commonRequest.setLang(Language.ENGLISH);
commonRequest.setLang(Language.FRENCH);
commonRequest.setSregion(Region.INDIA);
commonRequest.setPn(1);
commonRequest.setPs(10);
2 Setting request token for the calling the search results through website
setInstanceCredential() is used to set a global token, which is accessible to all methods. The token is used to verify a search request on the server. Search results of the request are returned only after the verification is successful.
Code:
if (tokenResponse.getAccess_token() != null) {
SearchKitInstance.getInstance().setInstanceCredential(tokenResponse.getAccess_token());
}
3 Setting request token for web search
getWebSearcher() api is used to search for the web results.
Code:
SearchKitInstance.getInstance().getWebSearcher().search(webRequest);
4 Start a web page search
webSearchRequest() is used as parameter which was constructed in Step 1 to the search method.
Code:
BaseSearchResponse<List<WebItem>> webResponse =
SearchKitInstance.getInstance().getWebSearcher().search(webRequest);
Complete Code
Code:
import android.content.Context;
import com.google.android.material.tabs.TabLayout;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
public class SearchActivity extends AppCompatActivity {
private static final String TAG = SearchActivity.class.getSimpleName();
private EditText editSearch;
private LinearLayout linearSpellCheck, linearViewPager;
private RecyclerView recyclerSuggest, recyclerContent;
private ViewPager viewPager;
private TabLayout tabLayout;
private ViewPagerAdapter viewPagerAdapter;
private SuggestAdapter suggestAdapter;
private TextView tvSpellCheck;
public static int mCurrentPage = 0;
public static final WebSearchRequest webRequest = new WebSearchRequest();
public static final CommonSearchRequest commonRequest = new CommonSearchRequest();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
SearchKitInstance.enableLog();
SearchKitInstance.init(this, "103029525");
initRetrofit();
initView();
}
private void initView() {
editSearch = findViewById(R.id.search_view);
linearSpellCheck = findViewById(R.id.linear_spell_check);
recyclerSuggest = findViewById(R.id.suggest_list);
recyclerContent = findViewById(R.id.content_list);
tvSpellCheck = findViewById(R.id.tv_spell_check);
viewPager = findViewById(R.id.view_pager);
tabLayout = findViewById(R.id.tab_layout);
linearViewPager = findViewById(R.id.linear_view_pager);
LinearLayoutManager layoutManager = new LinearLayoutManager(SearchActivity.this);
recyclerSuggest.setLayoutManager(layoutManager);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(SearchActivity.this);
recyclerContent.setLayoutManager(linearLayoutManager);
FragmentManager fm = getSupportFragmentManager();
if (null == viewPagerAdapter) {
viewPagerAdapter = new ViewPagerAdapter(fm, this);
}
viewPager.setAdapter(viewPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
viewPager.setOffscreenPageLimit(3);
initViewPagerListener();
onEditTextListener();
}
private void initViewPagerListener() {
viewPager.addOnPageChangeListener(
new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
@Override
public void onPageSelected(int position) {
mCurrentPage = position;
}
@Override
public void onPageScrollStateChanged(int state) {}
});
}
private void onEditTextListener() {
editSearch.addTextChangedListener(
new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
recyclerSuggest.setVisibility(View.VISIBLE);
linearSpellCheck.setVisibility(View.GONE);
linearViewPager.setVisibility(View.GONE);
if (!TextUtils.isEmpty(s.toString())) {
getSuggest(s.toString());
} else {
recyclerSuggest.setVisibility(View.GONE);
linearViewPager.setVisibility(View.VISIBLE);
if (TextUtils.isEmpty(tvSpellCheck.getText().toString())) {
linearSpellCheck.setVisibility(View.GONE);
} else {
linearSpellCheck.setVisibility(View.VISIBLE);
}
if (suggestAdapter != null) {
suggestAdapter.clear();
}
}
}
@Override
public void afterTextChanged(Editable s) {}
});
editSearch.setOnEditorActionListener(
new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
recyclerSuggest.setVisibility(View.GONE);
linearViewPager.setVisibility(View.VISIBLE);
hintSoftKeyboard();
getSpellCheck(v.getText().toString());
return true;
}
return false;
}
});
}
private void getSpellCheck(final String query) {
Observable.create(
new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
SpellCheckResponse response =
SearchKitInstance.getInstance()
.getSearchHelper()
.spellCheck(query, Language.ENGLISH);
if (response != null && response.getCorrectedQuery() != null) {
emitter.onNext(response.getCorrectedQuery());
} else {
Log.e(TAG, "spell error");
emitter.onNext("");
}
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
if (TextUtils.isEmpty(s)) {
linearSpellCheck.setVisibility(View.GONE);
} else {
linearSpellCheck.setVisibility(View.VISIBLE);
tvSpellCheck.setText(s);
}
doSearch(query);
}
},
StaticUtils.consumer);
}
private void getSuggest(final String query) {
Observable.create(
new ObservableOnSubscribe<List<String>>() {
@Override
public void subscribe(ObservableEmitter<List<String>> emitter) throws Exception {
AutoSuggestResponse response =
SearchKitInstance.getInstance()
.getSearchHelper()
.suggest(query, Language.ENGLISH);
List<String> list = new ArrayList<String>();
if (response != null) {
if (response.getSuggestions() != null && !response.getSuggestions().isEmpty()) {
for (int i = 0; i < response.getSuggestions().size(); i++) {
list.add(response.getSuggestions().get(i).getName());
}
emitter.onNext(list);
}
}
emitter.onComplete();
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Consumer<List<String>>() {
@Override
public void accept(List<String> list) throws Exception {
if (suggestAdapter != null) {
suggestAdapter.clear();
}
suggestAdapter = new SuggestAdapter(list);
recyclerSuggest.setAdapter(suggestAdapter);
suggestAdapter.setOnClickListener(
new SuggestAdapter.OnItemClickListener() {
@Override
public void click(String text) {
doSearch(text);
editSearch.setText(text);
hintSoftKeyboard();
recyclerSuggest.setVisibility(View.GONE);
linearViewPager.setVisibility(View.VISIBLE);
}
});
}
},
StaticUtils.consumer);
}
private void doSearch(String query) {
webRequest.setQ(query);
webRequest.setLang(Language.ENGLISH);
webRequest.setLang(Language.FRENCH);
webRequest.setSregion(Region.INDIA);
webRequest.setPn(1);
webRequest.setPs(10);
webRequest.setWithin("www.fragrancespecialities.com");
commonRequest.setQ(query);
commonRequest.setLang(Language.ENGLISH);
commonRequest.setLang(Language.FRENCH);
commonRequest.setSregion(Region.INDIA);
commonRequest.setPn(1);
commonRequest.setPs(10);
Observable.create(StaticUtils.observable)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Consumer<BaseSearchResponse>() {
@Override
public void accept(BaseSearchResponse baseSearchResponse) throws Exception {
if (baseSearchResponse != null && baseSearchResponse.getData() != null) {
if (mCurrentPage == 0) {
WebFragment webFragment =
(WebFragment) viewPagerAdapter.getFragments().get(mCurrentPage);
webFragment.setValue((List<WebItem>) baseSearchResponse.getData());
}
}
}
},
StaticUtils.consumer);
}
private void hintSoftKeyboard() {
InputMethodManager imm = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null && imm.isActive() && this.getCurrentFocus() != null) {
if (this.getCurrentFocus().getWindowToken() != null) {
imm.hideSoftInputFromWindow(
this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
}
public void initRetrofit() {
ApplicationInfo appInfo = null;
String baseUrl = "";
try {
appInfo = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
baseUrl = appInfo.metaData.getString("baseUrl");
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "get meta data error: " + e.getMessage());
}
QueryService service = NetworkManager.getInstance().createService(this, baseUrl);
service.getRequestToken(
"client_credentials",
"103029525",
"6333c6fa883a91f8b0bd783d43edfb5695cb9d4612a481e2d55e6f80c2d870b")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<TokenResponse>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(TokenResponse tokenResponse) {
if (tokenResponse != null) {
if (tokenResponse.getAccess_token() != null) {
// Log.e(TAG, response.getBody().getAccess_token());
SearchKitInstance.getInstance().setInstanceCredential(tokenResponse.getAccess_token());
} else {
Log.e(TAG, "get responseBody token is null");
}
} else {
Log.e(TAG, "get responseBody is null");
}
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "get token error: " + e.getMessage());
}
@Override
public void onComplete() {
}
});
}
private static class StaticUtils {
private static class MyConsumer implements Consumer<Throwable> {
@Override
public void accept(Throwable throwable) throws Exception {
Log.e(TAG, "do search error: " + throwable.getMessage());
}
}
private static Consumer<Throwable> consumer = new MyConsumer();
private static class MyObservable implements ObservableOnSubscribe<BaseSearchResponse> {
@Override
public void subscribe(ObservableEmitter<BaseSearchResponse> emitter) throws Exception {
if (mCurrentPage == 0) {
BaseSearchResponse<List<WebItem>> webResponse =
SearchKitInstance.getInstance().getWebSearcher().search(webRequest);
emitter.onNext(webResponse);
}
}
}
private static ObservableOnSubscribe<BaseSearchResponse> observable = new MyObservable();
}
}
Tips & Tricks
The parameter in the setQ method of WebSearchRequest cannot be empty or exceed 1024 characters. (If the parameter passed exceeds 1024 characters, only the first 1024 characters will be used.) Otherwise, the search fails.
Results
Reference
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/introduction-0000001055591730
Conclusion
This article focuses on web search for mobile application which query the website and demonstrate the client side API’s to initiate the search process, communicate with Huawei search API’s, customize the query and handle the results on the mobile application sent through the website.
Well explained, can we customize the search items using this search service?
Related
More information like this, you can visit HUAWEI Developer Forum
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
In this tutorial, I will show you how to develop an Earthquake application with Android Studio using retrofit and Huawei mobile services (HMS Core). We will use the Huawei account kit and map kit.
With this application, users will be able to see earthquakes that happened in Turkey inside huawei map. Also they will be authenticated with their huawei ID.
1. Integrate Your Application
To start developing an app with Huawei mobile services, you need to integrate your application to HMS core. Check out this link to integrate your application. After finished your integration don’t forget to enable the account kit and map kit from App Gallery Connect.
Note: Before we start if you don't have a Huawei device for testing. Please check this link to install the HMS Core toolkit. With this plug-in, you can use Huawei emulators for testing. (After download, select HMS and Cloud Debugging from top of the android studio)
2. Dependencies
Let’s start by adding our dependencies to the project.
3.Preparations for API
Finally, we are ready to start coding. First, start with our API structure.
Note: This endpoint used for the earthquakes that happened in Turkey. If you want to use a global API for your project this link might help you.
For model classes, check out my GitHub link. You will see 2 classes named TR_ApiModel and TR_APiModel_Result. (if you are using the global API, classes named ApiModel is your model classes.)
4. API Call with Retrofit
After we created our model classes successfully, let’s create our interface and make our first API call.
Code:
public interface ApiInterface {
String URL_GET="https://api.orhanaydogdu.com.tr/deprem/";
//latest 100 earthquakes
@GET("live.php?limit=100")
Call<TR_ApiModel> getDynamicTr();
//give url as parameter
@GET
Call<ApiModel> getDynamic(@Url String url);
}
Code:
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(ApiInterface.URL_GET)
.client( new OkHttpClient())
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
ApiInterface userClient = retrofit.create(ApiInterface.class);
Call<TR_ApiModel> call = userClient.getDynamicTr();
call.enqueue(new Callback<TR_ApiModel>() {
@Override
public void onResponse(Call<TR_ApiModel> call, Response<TR_ApiModel> response) {
TR_ApiModel myTrData = response.body();
if (myTrData != null) {
// Send this data to your mapActivity
}
else {
Toast.makeText(YourActivity.this, "data null", Toast.LENGTH_LONG).show();
}
}
@Override
public void onFailure(Call<TR_ApiModel> call, Throwable t) {
Toast.makeText(YourActivity.this, t.toString(), Toast.LENGTH_LONG).show();
}
});
5. Huawei Account Kit
Now we are getting our earthquake data without any problem. Let’s continue with integrating kits into our application. We will start with the Account kit.
There are 2 methods to authenticate with Huawei ID. We will be using the ID token method because this method doesn't require an App server and has simpler integration. If you want to learn more about these methods check this page.
Let’s see the code for authentication with Huawei ID.
Code:
public class AccountActivity extends AppCompatActivity {
private HuaweiIdAuthParams authParams;
private HuaweiIdAuthService service;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.wellcome);
authParams = new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM)
.setIdToken().createParams();
service= HuaweiIdAuthManager.getService(AccountActivity.this, authParams);
Task<AuthHuaweiId> task = service.silentSignIn();
task.addOnSuccessListener(new OnSuccessListener<AuthHuaweiId>() {
@Override
public void onSuccess(AuthHuaweiId authHuaweiId) {
String uri = authHuaweiId.getAvatarUriString();
String name = authHuaweiId.getGivenName();
String familyName = authHuaweiId.getFamilyName(
Intent intent = new Intent (YourActivity.this, NextActivity.class);
intent.putExtra("uri",uri);
intent.putExtra("name",name);
intent.putExtra("familyname",familyName
startActivity(intent);
}
});
task.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
startActivityForResult(service.getSignInIntent(), 1111);
}
});
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1111) {
Task<AuthHuaweiId> authHuaweiIdTask = HuaweiIdAuthManager.parseAuthResultFromIntent(data);
if (authHuaweiIdTask.isSuccessful()) {
AuthHuaweiId huaweiAccount = authHuaweiIdTask.getResult();
String uri = huaweiAccount.getAvatarUriString();
String name = huaweiAccount.getGivenName();
String familyName = huaweiAccount.getFamilyName();
Intent intent = new Intent (YourClass.this, YourActivity.class);
intent.putExtra("uri",uri);
intent.putExtra("name",name);
intent.putExtra("familyname",familyName);
startActivity(intent);
}
}
}
The code above has 2 parts. First, it tries to silent sign in. (if the user signed in before and not signed out, you can directly get user’s data and change your activity) If this task fails the second part of the code (onActivityResult) gets sign-in intent for you and the user enters account information to intent. If the task is successful the same as the first part you get users' information and change your activity.
Note: If you want to get the user's information as I did, be careful about getting this information because the user might not have a name, family name, or profile photo value associated with their account. In this situation, these values will be null.
Code:
Task<Void> signOutTask = service.signOut();
signOutTask.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(Task<Void> task) {
//Processing after the sign-out.
Log.i(TAG, "signOut complete");
}
});
To sign-out, you need to create a sign-out task like this. Service is the instance of HuaweiIdAuthService.
6. Huawei Map Kit
The final part is the map kit integration. In this part, I will use the data we get from API calls and add custom markers inside the Huawei map.
Code:
<com.huawei.hms.maps.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:mapType="normal"
map:uiCompass="true"
map:uiZoomControls="true"
map:cameraTargetLat="39.3799497"
map:cameraTargetLng="34.0919603"
map:cameraZoom="4.8" />
This is our XML file for map view just add this code to your layout file. You can also use Map fragment check this link for more information.
TargetLat , TargetLng, and camera zoom values set the starting location and starting zoom of your map.
Code:
public class MapFragment extends Fragment implements OnMapReadyCallback {
private HomeViewModel homeViewModel;
HuaweiMap hMap;
MapView mMapView;
TR_ApiModel myTrData;
private static final String MAPVIEW_BUNDLE_KEY = "MapViewBundleKey";
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
homeViewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
View root = inflater.inflate(R.layout.fragment_home, container, false);
mMapView = root.findViewById(R.id.mapp);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY);
}
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(this);
return root;
}
@Override
public void onStart() {
super.onStart();
mMapView.onStart();
}
@Override
public void onStop() {
super.onStop();
mMapView.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
@Override
public void onPause() {
mMapView.onPause();
super.onPause();
}
@Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
@Override
public void onMapReady(HuaweiMap huaweiMap) {
hMap = huaweiMap;
Bitmap icon = BitmapFactory.decodeResource(getActivity().getResources(),
R.drawable.icons8y);
List<TR_ApiModel_Result> markerData = myTrData.getResult();
for (TR_ApiModel_Result result : markerData) {
hMap.addMarker(new MarkerOptions().position(new LatLng(result.getLat(), result.getLng())).title(result.getTitle() + " Magnitude : " + result.getMag().toString()).draggable(false)
.icon(BitmapDescriptorFactory.fromBitmap(icon)).clusterable(true));
}
}
}
This is our MapActivity. I used fragment to show the map but if you don't use fragment just add inside onCreate method instead of onCreateView.
The important part is onMapReady method. This method starts after map creation finished. First I created an icon for my markers. Then I added markers for the data I get from CallExample.java. Also, I used clusterable value true to avoid showing too many markers on my map.
If you want to update your map you can call “hmap.clear()” and add markers again with the updated data.
outlaw1985 said:
Thanks for this information. It is great!
Click to expand...
Click to collapse
Thanks, bro. Hope to help u a lot.
More information like this, you can visit HUAWEI Developer Forum
Original link: https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201319969591990258&fid=0101187876626530001
Hello everyone,
In this article we are going to take a look at Huawei Mobile Services (HMS) integration Plugin for Unity. This article not going through the details of kits, we will focus on integration part.
{
"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"
}
We will use account, In App purchases and push kit for this article. This plugin for now support five main kits.
Plugin Features :
1- Account Kit: Its provides developers with simple, secure, and quick sign-in and authorization functions. Instead of entering accounts and passwords and waiting for authorization, users can just tap the Sign In with HUAWEI ID button to quickly and securely sign in to your app. For details you read this article.
2- In App purchases: This service allows you to offer in-app purchases and facilitates in-app payment. Users can purchase a variety of virtual products, including one-time virtual products and subscriptions, directly within your app. For details you can read this article. Plugin supports the following types of products: Consumables, Non-consumables, Subscriptions
3- Huawei Ads: This Publisher Service utilizes Huawei’s vast user base and extensive data capabilities to deliver targeted, high quality ad content to users. With this service, your app will be able to generate revenues while bringing your users content which is relevant to them. For details you can read this article. Plugin supports the following types: Interstitial and rewarded videos
4- Push notifications: HUAWEI Push Kit is a messaging service provided by Huawei for developers. It establishes a messaging channel from the cloud to devices. By integrating HUAWEI Push Kit, developers can send messages to apps on users’ devices in real time. For details you can read this article.
5- Game kit: This kit provide player info, leaderboards and achievements.For details you can read this article.
HMS Plugin Work Flow:
Prerequisites
Step 1
Create an application on HUAWEI Developer(use this link for details).
Enable the HUAWEI services.
Step 2
This plugin have two branch for Unity versions.(version 2019 used)
Download plugin from this for Unity version 2019.x.
Download plugin from this for Unity version 2018.x .
Step 3
Import package to unity.
Step 4
Update “AndroidManifest file” and “agconnect.json” file.
1- Open project_path\Assets\Plugins\Android\ AndoridManifest.
Update App ID, CP ID and package name, this informations exist in agconnect.json file.
2- Open project_path\Assets\Huawei\agconnect.json replace with you downloanded from AGC.
Integration
This plugin have some demos scenes. You can drictly use this scenes. We will create empty scene, after that we will add objects.
1. Account kit:
Create empty object and add account manager script from Huawei package component.
(Object name is important, if you want to give diffrent name from “AccountManager” update ~~\Assets\Huawei\Account\AccountManager.cs -> line 11)
Add new script “AccountSignIn” to this object.
On AccountSignIn.cs:
Code:
using HuaweiMobileServices.Id;
using HuaweiMobileServices.Utils;
using UnityEngine;
using UnityEngine.UI;
using HmsPlugin;
public class AccountSignIn : MonoBehaviour
{
private const string NOT_LOGGED_IN = "No user logged in";
private const string LOGGED_IN = "{0} is logged in";
private const string LOGIN_ERROR = "Error or cancelled login";
private Text loggedInUser;
private AccountManager accountManager;
// Start is called before the first frame update
void Start()
{
loggedInUser = GameObject.Find("LoggedUserText").GetComponent<Text>();
loggedInUser.text = NOT_LOGGED_IN;
accountManager = AccountManager.GetInstance();
accountManager.OnSignInSuccess = OnLoginSuccess;
accountManager.OnSignInFailed = OnLoginFailure;
LogIn();
}
public void LogIn()
{
accountManager.SignIn();
}
public void LogOut()
{
accountManager.SignOut();
loggedInUser.text = NOT_LOGGED_IN;
}
public void OnLoginSuccess(AuthHuaweiId authHuaweiId)
{
loggedInUser.text = string.Format(LOGGED_IN, authHuaweiId.DisplayName);
}
public void OnLoginFailure(HMSException error)
{
loggedInUser.text = LOGIN_ERROR;
}
}
We can create sign in and sign out buttons, this buttons call “AccountSignIn” functions.
2. In App purchases:
Create empty object ( Object name is important, if you want to give diffrent name from “IapManager” update ~~\Assets\Huawei\IAP\IapManager.cs -> line 11).
Add new script “IapController.cs” to this object.
Add Account kit manager to IapManager object, its needed for using IAP services.
In App Purchases have three type of product.
1- Type 0: Consumables
Description:Consumables are used once, are depleted, and can be purchased again.
Example:Extra lives and gems in a game.
Getting Consumables products from Huawei AGC with HMS Unity plugin:
Code:
public void ObtainProductConsumablesInfo(IList<string> productIdConsumablesList)
{
if (iapAvailable != true)
{
OnObtainProductInfoFailure?.Invoke(IAP_NOT_AVAILABLE);
return;
}
ProductInfoReq productInfoReq = new ProductInfoReq
{
PriceType = 0,
ProductIds = productIdConsumablesList
};
iapClient.ObtainProductInfo(productInfoReq).AddOnSuccessListener((type0) =>
{
Debug.Log("[HMSPlugin]:" + type0.ErrMsg + type0.ReturnCode.ToString());
Debug.Log("[HMSPlugin]: Found " + type0.ProductInfoList.Count + "consumable products");
OnObtainProductInfoSuccess?.Invoke(new List<ProductInfoResult> { type0});
}).AddOnFailureListener((exception) =>
{
Debug.Log("[HMSPlugin]: ERROR Consumable ObtainInfo" + exception.Message);
OnObtainProductInfoFailure?.Invoke(exception);
});
}
2- Type 1: Non-consumables
Description: Non-consumables are purchased once and do not expire.
Example:Extra game levels in a game or permanent membership of an app
3- Type 2: Subscriptions
Description:Users can purchase access to value-added functions or content in a specified period of time. The subscriptions are automatically renewed on a recurring basis until users decide to cancel.
Example:Non-permanent membership of an app, such as a monthly video membership
On IAPController.cs
Code:
# define DEBUG
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HuaweiConstants;
using HuaweiMobileServices.Base;
using HuaweiMobileServices.IAP;
using System;
using UnityEngine.Events;
using HuaweiMobileServices.Id;
using HmsPlugin;
public class IapController : MonoBehaviour
{
public string[] ConsumableProducts;
public string[] NonConsumableProducts;
public string[] SubscriptionProducts;
[HideInInspector]
public int numberOfProductsRetrieved;
List<ProductInfo> productInfoList = new List<ProductInfo>();
List<string> productPurchasedList = new List<string>();
private IapManager iapManager;
private AccountManager accountManager;
UnityEvent loadedEvent;
void Awake()
{
Debug.Log("[HMSPlugin]: IAPP manager Init");
loadedEvent = new UnityEvent();
}
// Start is called before the first frame update
/// <summary>
///
/// </summary>
void Start()
{
Debug.Log("[HMS]: Started");
accountManager = GetComponent<AccountManager>();
Debug.Log(accountManager.ToString());
accountManager.OnSignInFailed = (error) =>
{
Debug.Log($"[HMSPlugin]: SignIn failed. {error.Message}");
};
accountManager.OnSignInSuccess = SignedIn;
accountManager.SignIn();
Debug.Log("[HMS]: Started2");
}
private void SignedIn(AuthHuaweiId authHuaweiId)
{
Debug.Log("[HMS]: SignedIn");
iapManager = GetComponent<IapManager>();
iapManager.OnCheckIapAvailabilitySuccess = LoadStore;
iapManager.OnCheckIapAvailabilityFailure = (error) =>
{
Debug.Log($"[HMSPlugin]: IAP check failed. {error.Message}");
};
iapManager.CheckIapAvailability();
}
private void LoadStore()
{
Debug.Log("[HMS]: LoadStorexxx");
// Set Callback for ObtainInfoSuccess
iapManager.OnObtainProductInfoSuccess = (productInfoResultList) =>
{
Debug.Log("[HMS]: LoadStore1");
if (productInfoResultList != null)
{
Debug.Log("[HMS]: LoadStore2");
foreach (ProductInfoResult productInfoResult in productInfoResultList)
{
foreach (ProductInfo productInfo in productInfoResult.ProductInfoList)
{
productInfoList.Add(productInfo);
}
}
}
loadedEvent.Invoke();
};
// Set Callback for ObtainInfoFailure
iapManager.OnObtainProductInfoFailure = (error) =>
{
Debug.Log($"[HMSPlugin]: IAP ObtainProductInfo failed. {error.Message},,, {error.WrappedExceptionMessage},,, {error.WrappedCauseMessage}");
};
// Call ObtainProductInfo
if (!IsNullOrEmpty(ConsumableProducts))
{
iapManager.ObtainProductConsumablesInfo(new List<string>(ConsumableProducts));
}
if (!IsNullOrEmpty(NonConsumableProducts))
{
iapManager.ObtainProductNonConsumablesInfo(new List<string>(NonConsumableProducts));
}
if (!IsNullOrEmpty(SubscriptionProducts))
{
iapManager.ObtainProductSubscriptionInfo(new List<string>(SubscriptionProducts));
}
}
private void RestorePurchases()
{
iapManager.OnObtainOwnedPurchasesSuccess = (ownedPurchaseResult) =>
{
productPurchasedList = (List<string>)ownedPurchaseResult.InAppPurchaseDataList;
};
iapManager.OnObtainOwnedPurchasesFailure = (error) =>
{
Debug.Log("[HMS:] RestorePurchasesError" + error.Message);
};
iapManager.ObtainOwnedPurchases();
}
public ProductInfo GetProductInfo(string productID)
{
return productInfoList.Find(productInfo => productInfo.ProductId == productID);
}
public void showHidePanelDynamically(GameObject yourObject)
{
Debug.Log("[HMS:] showHidePanelDynamically");
var getCanvasGroup = yourObject.GetComponent<CanvasGroup>();
if (getCanvasGroup.alpha == 0)
{
getCanvasGroup.alpha = 1;
getCanvasGroup.interactable = true;
}
else
{
getCanvasGroup.alpha = 0;
getCanvasGroup.interactable = false;
}
}
public void BuyProduct(string productID)
{
iapManager.OnBuyProductSuccess = (purchaseResultInfo) =>
{
// Verify signature with purchaseResultInfo.InAppDataSignature
// If signature ok, deliver product
// Consume product purchaseResultInfo.InAppDataSignature
iapManager.ConsumePurchase(purchaseResultInfo);
};
iapManager.OnBuyProductFailure = (errorCode) =>
{
switch (errorCode)
{
case OrderStatusCode.ORDER_STATE_CANCEL:
// User cancel payment.
Debug.Log("[HMS]: User cancel payment");
break;
case OrderStatusCode.ORDER_STATE_FAILED:
Debug.Log("[HMS]: order payment failed");
break;
case OrderStatusCode.ORDER_PRODUCT_OWNED:
Debug.Log("[HMS]: Product owned");
break;
default:
Debug.Log("[HMS:] BuyProduct ERROR" + errorCode);
break;
}
};
var productInfo = productInfoList.Find(info => info.ProductId == productID);
var payload = "test";
iapManager.BuyProduct(productInfo, payload);
}
public void addListener(UnityAction action)
{
if (loadedEvent != null)
{
loadedEvent.AddListener(action);
}
}
public bool IsNullOrEmpty(Array array)
{
return (array == null || array.Length == 0);
}
}
After getting all product informations from AGC, user can buy product with “BuyProduct” function with send product ids.
Buy Product Button Settings:
Select Prefab:
Select Function:
Add Parameter:
IapManager.cs:
Code:
# define DEBUG
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HuaweiConstants;
using HuaweiMobileServices.Base;
using HuaweiMobileServices.IAP;
using System;
using UnityEngine.Events;
using HuaweiMobileServices.Id;
using HmsPlugin;
public class IapController : MonoBehaviour
{
public string[] ConsumableProducts;
public string[] NonConsumableProducts;
public string[] SubscriptionProducts;
[HideInInspector]
public int numberOfProductsRetrieved;
List<ProductInfo> productInfoList = new List<ProductInfo>();
List<string> productPurchasedList = new List<string>();
private IapManager iapManager;
private AccountManager accountManager;
UnityEvent loadedEvent;
void Awake()
{
Debug.Log("[HMSPlugin]: IAPP manager Init");
loadedEvent = new UnityEvent();
}
// Start is called before the first frame update
/// <summary>
///
/// </summary>
void Start()
{
Debug.Log("[HMS]: Started");
accountManager = GetComponent<AccountManager>();
Debug.Log(accountManager.ToString());
accountManager.OnSignInFailed = (error) =>
{
Debug.Log($"[HMSPlugin]: SignIn failed. {error.Message}");
};
accountManager.OnSignInSuccess = SignedIn;
accountManager.SignIn();
Debug.Log("[HMS]: Started2");
}
private void SignedIn(AuthHuaweiId authHuaweiId)
{
Debug.Log("[HMS]: SignedIn");
iapManager = GetComponent<IapManager>();
iapManager.OnCheckIapAvailabilitySuccess = LoadStore;
iapManager.OnCheckIapAvailabilityFailure = (error) =>
{
Debug.Log($"[HMSPlugin]: IAP check failed. {error.Message}");
};
iapManager.CheckIapAvailability();
}
private void LoadStore()
{
Debug.Log("[HMS]: LoadStorexxx");
// Set Callback for ObtainInfoSuccess
iapManager.OnObtainProductInfoSuccess = (productInfoResultList) =>
{
Debug.Log("[HMS]: LoadStore1");
if (productInfoResultList != null)
{
Debug.Log("[HMS]: LoadStore2");
foreach (ProductInfoResult productInfoResult in productInfoResultList)
{
foreach (ProductInfo productInfo in productInfoResult.ProductInfoList)
{
productInfoList.Add(productInfo);
}
}
}
loadedEvent.Invoke();
};
// Set Callback for ObtainInfoFailure
iapManager.OnObtainProductInfoFailure = (error) =>
{
Debug.Log($"[HMSPlugin]: IAP ObtainProductInfo failed. {error.Message},,, {error.WrappedExceptionMessage},,, {error.WrappedCauseMessage}");
};
// Call ObtainProductInfo
if (!IsNullOrEmpty(ConsumableProducts))
{
iapManager.ObtainProductConsumablesInfo(new List<string>(ConsumableProducts));
}
if (!IsNullOrEmpty(NonConsumableProducts))
{
iapManager.ObtainProductNonConsumablesInfo(new List<string>(NonConsumableProducts));
}
if (!IsNullOrEmpty(SubscriptionProducts))
{
iapManager.ObtainProductSubscriptionInfo(new List<string>(SubscriptionProducts));
}
}
private void RestorePurchases()
{
iapManager.OnObtainOwnedPurchasesSuccess = (ownedPurchaseResult) =>
{
productPurchasedList = (List<string>)ownedPurchaseResult.InAppPurchaseDataList;
};
iapManager.OnObtainOwnedPurchasesFailure = (error) =>
{
Debug.Log("[HMS:] RestorePurchasesError" + error.Message);
};
iapManager.ObtainOwnedPurchases();
}
public ProductInfo GetProductInfo(string productID)
{
return productInfoList.Find(productInfo => productInfo.ProductId == productID);
}
public void showHidePanelDynamically(GameObject yourObject)
{
Debug.Log("[HMS:] showHidePanelDynamically");
var getCanvasGroup = yourObject.GetComponent<CanvasGroup>();
if (getCanvasGroup.alpha == 0)
{
getCanvasGroup.alpha = 1;
getCanvasGroup.interactable = true;
}
else
{
getCanvasGroup.alpha = 0;
getCanvasGroup.interactable = false;
}
}
public void BuyProduct(string productID)
{
iapManager.OnBuyProductSuccess = (purchaseResultInfo) =>
{
// Verify signature with purchaseResultInfo.InAppDataSignature
// If signature ok, deliver product
// Consume product purchaseResultInfo.InAppDataSignature
iapManager.ConsumePurchase(purchaseResultInfo);
};
iapManager.OnBuyProductFailure = (errorCode) =>
{
switch (errorCode)
{
case OrderStatusCode.ORDER_STATE_CANCEL:
// User cancel payment.
Debug.Log("[HMS]: User cancel payment");
break;
case OrderStatusCode.ORDER_STATE_FAILED:
Debug.Log("[HMS]: order payment failed");
break;
case OrderStatusCode.ORDER_PRODUCT_OWNED:
Debug.Log("[HMS]: Product owned");
break;
default:
Debug.Log("[HMS:] BuyProduct ERROR" + errorCode);
break;
}
};
var productInfo = productInfoList.Find(info => info.ProductId == productID);
var payload = "test";
iapManager.BuyProduct(productInfo, payload);
}
public void addListener(UnityAction action)
{
if (loadedEvent != null)
{
loadedEvent.AddListener(action);
}
}
public bool IsNullOrEmpty(Array array)
{
return (array == null || array.Length == 0);
}
}
3. Push notifications:
First add your project PushKitManager prefab, this prefab using PushKitManager.cs for creating tokens.
For push kit, we have a two choice,
We can send notification to all devices without token.
We can get tokens from devices and we can use this token to send notification sepicified devices.
AGC server Push Scope for sending notification:
On PushKitManager.cs
Code:
using HuaweiMobileServices.Base;
using HuaweiMobileServices.Id;
using HuaweiMobileServices.Push;
using HuaweiMobileServices.Utils;
using System;
using UnityEngine;
using UnityEngine.UI;
namespace HmsPlugin
{
public class PushKitManager : MonoBehaviour, IPushListener
{
public Action<string> OnTokenSuccess { get; set; }
public Action<Exception> OnTokenFailure { get; set; }
public Action<RemoteMessage> OnMessageReceivedSuccess { get; set; }
// Start is called before the first frame update
void Start()
{
PushManager.Listener = this;
var token = PushManager.Token;
Debug.Log($"[HMS] Push token from GetToken is {token}");
if (token != null)
{
OnTokenSuccess?.Invoke(token);
}
}
public void OnNewToken(string token)
{
Debug.Log($"[HMS] Push token from OnNewToken is {token}");
if (token != null)
{
OnTokenSuccess?.Invoke(token);
}
}
public void OnTokenError(Exception e)
{
Debug.Log("Error asking for Push token");
Debug.Log(e.StackTrace);
OnTokenFailure?.Invoke(e);
}
public void OnMessageReceived(RemoteMessage remoteMessage)
{
OnMessageReceivedSuccess?.Invoke(remoteMessage);
}
}
}
Push Notification result:
Thank you reading this article.
I hope this gives you a starting point for Huawei Mobile Services and Unity integration.
Introduction
This article is based on Huawei Mobile Services application. I have developed Trip Booking Android app. We can provide the solution for HMS based multiple kits such as Account Kit, Huawei Ads, Huawei Map, and Huawei Analysts to use in Trip Booking. So users can book any trip.
In this application, users can plan trips and book their trips. It will provide the ongoing trip cities wise with weather forecasting so that user can easily plan a trip.
In this article, I will integrate Weather API, Huawei Map, and Huawei Map Direction API, so that users can check the route and plan their trips, and book with the trip weather forecast.
Huawei Map
HMS Core Map SDK is a set of APIs for map development in Android. The map data covers most countries outside China and supports multiple languages. The Map SDK uses the WGS 84 GPS coordinate system, which can meet most requirements of map development outside China. You can easily add map-related functions in your Android app, including:
1. Map display: Displays buildings, roads, water systems, and Points of Interest (POIs).
2. Map interaction: Controls the interaction gestures and buttons on the map.
3. Map drawing: Adds location markers, map layers, overlays, and various shapes.
Prerequisite
1. A computer (desktop or laptop)
2. A Huawei phone, which is used to debug the developed app
3. HUAWEI Analytics Kit 5.0.3
4. Android SDK applicable to devices using Android API-Level 19 (Android 4.4 KitKat) or higher
5. Android Studio
6. Java JDK 1.7 or later (JDK 1.8 recommended).
Things Need To Be Done
To integrate HUAWEI HMS Core services, you must complete the following preparations:
1. Create an app in AppGallery Connect.
2. Create an Android Studio project.
3. Add the app package name and save the configuration file.
4. Configure the Maven repository address and AppGallery Connect gradle plug-in.
Integration
1. Sign in to AppGallery Connect and select my projects.
2. Navigate to app to enable Map Kit.
{
"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"
}
3. Navigate to project setting and download the configuration file.
4. Add the Maven repository address to repositories.
Code:
buildscript {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:4.0.1"
classpath 'com.huawei.agconnect:agcp:1.2.0.300'
}
}
allprojects {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
}
}
5. Add the AppGallery Connect dependency to dependencies.
Code:
//map
implementation 'com.huawei.hms:maps:4.0.0.301'
6. I have created the following class in which I have implemented Map Kit.
Code:
public class PolylineActivity extends AppCompatActivity implements OnMapReadyCallback {
public static final String TAG = "PolylineActivity";
private static final String MAPVIEW_BUNDLE_KEY = "MapViewBundleKey";
private HuaweiMap hmap;
private MapView mMapView;
private Marker mMarker;
private List<LatLng> latLngList;
private MapApiViewModel mapApiViewModel;
@Override
protected void onStart() {
super.onStart();
mMapView.onStart();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_polyline);
mapApiViewModel = ViewModelProviders.of(this).get(MapApiViewModel.class);
mMapView = findViewById(R.id.mapview_mapviewdemo);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY);
}
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(PolylineActivity.this);
}
@Override
protected void onResume() {
super.onResume();
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mMapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mMapView.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
@Override
public void onMapReady(HuaweiMap map) {
hmap = map;
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
return;
}
hmap.setMyLocationEnabled(false);
hmap.setTrafficEnabled(true);
hmap.getUiSettings().setRotateGesturesEnabled(true);
hmap.getUiSettings().setCompassEnabled(false);
hmap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLngList.get(0), 12.0f));
hmap.addMarker(new MarkerOptions().position(latLngList.get(0)));
mapApiViewModel.getPolylineLiveData(getPolylineBody()).observe(this, result -> {
Log.d(TAG, result.toString());
getPolylineData(result);
});
}
Huawei Map Direction API
Huawei Map provides Direction API, so that user can access all the information related to Map in RESTful API.
Huawei has provide the following API endpoint to access Direction API.
https://mapapi.cloud.huawei.com/mapApi/v1
Huawei provide the following direction API:
1. Walking Route Planning
2. Bicycling Route Planning
3. Driving Route Planning
I have implemented the Driving Route API with the help of Retrofit and MVVM.
Retrofit Client
I have created MapApiClient class for accessing the Direction API.
Code:
public class MapApiClient {
private final static HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
private static OkHttpClient okHttpClient;
public static Service getClient() {
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
if (okHttpClient == null) {
okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Consants.BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
return retrofit.create(Service.class);
}
public interface Service {
@POST("mapApi/v1/routeService/driving")
Single<PolylineResponse> getPolylines(
@Query("key") String apiKey,
@Body PolylineBody polylineBody);
}
}
API Repository
I have created MapApiRepo class for accessing the API client.
Code:
public class MapApiRepo {
private MapApiClient.Service mService;
public MapApiRepo() {
this.mService = MapApiClient.getClient();
}
public Single<PolylineResponse> executeMapApi(PolylineBody polylineBody) {
return mService.getPolylines(Consants.API_KEY, polylineBody);
}
}
ViewModel
I have created MapApiViewModel class for handling the API calls.
Code:
public class MapApiViewModel extends ViewModel {
private final CompositeDisposable disposables = new CompositeDisposable();
private MapApiRepo mapApiRepo = new MapApiRepo();
private MutableLiveData<PolylineResponse> mPolylineLiveData = new MutableLiveData<>();
public LiveData<PolylineResponse> getPolylineLiveData(PolylineBody body) {
disposables.add(mapApiRepo.executeMapApi(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> mPolylineLiveData.setValue(result),
throwable -> mPolylineLiveData.setValue(null)
));
return mPolylineLiveData;
}
@Override
protected void onCleared() {
disposables.clear();
}
}
Drawing Polyline
I have implemented this functionality in the following activity.
Code:
mapApiViewModel.getPolylineLiveData(getPolylineBody()).observe(this, result -> {
Log.d(TAG, result.toString());
getPolylineData(result);
}); private PolylineBody getPolylineBody() {
PolylineBody polylineBody = new PolylineBody();
Origin origin = new Origin();
origin.setLat("30.0444");
origin.setLng("31.2357");
Destination destination = new Destination();
destination.setLat("30.0131");
destination.setLng("31.2089");
polylineBody.setDestination(destination);
polylineBody.setOrigin(origin);
return polylineBody;
}
public void getPolylineData(PolylineResponse polylineResponse) {
List<Routes> routesList = polylineResponse.getRoutes();
List<Paths> paths = new ArrayList<>();
List<Steps> steps = new ArrayList<>();
List<Polyline> polylines = new ArrayList<>();
latLngList = new ArrayList<>();
for (int x = 0; x < routesList.size(); x++) {
//here we can access each array list with main.get(x).
for (Paths paths1 : routesList.get(x).getPaths()) {
paths.add(paths1);
}
for (int y = 0; y < paths.size(); y++) {
for (Steps step :
paths.get(y).getSteps()) {
steps.add(step);
}
}
for (int i = 0; i < steps.size(); i++) {
for (Polyline polyline :
steps.get(i).getPolyline()) {
polylines.add(polyline);
}
}
}
for (int i = 0; i < polylines.size(); i++) {
latLngList.add(new LatLng(Double.valueOf(polylines.get(i).getLat())
, Double.valueOf(polylines.get(i).getLng())));
}
hmap.addPolyline(new PolylineOptions()
.addAll(latLngList)
.color(Color.BLUE)
.width(3));
}
Weather API
I have used weatherstack api to get city weather condition.
https://api.weatherstack.com/
WeatherRetrofit Client
I have implemented Weather API using retrofit library with RxJava2.
Code:
public class Client {
private final static HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
private static OkHttpClient okHttpClient;
public static Service getClient() {
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
if (okHttpClient == null) {
okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Utils.BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
return retrofit.create(Service.class);
}
public interface Service {
@GET("current")
Single<CurrentWeather> getCurrentWeather(
@Query("access_key") String apiKey,
@Query("query") String cityName);
@GET("forecast")
Single<ForcastWeather> getForecastWeather(
@Query("access_key") String apiKey,
@Query("query") String cityName,
@Query("forecast_days") String days);
}
}
App Development
I have created the following package inside the project. In which I have integrated Huawei Id Login, Huawei Analytics, Huawei Banner Ads, Weather API, Huawei Map, and Huawei Direction APIs.
LoginActivity
In this screen, I have integrated login functionality with Huawei Id along with Analytics Kit which logs the event.
Code:
if (authHuaweiIdTask.isSuccessful()) {
AuthHuaweiId huaweiAccount = authHuaweiIdTask.getResult();
Log.i(TAG, huaweiAccount.getDisplayName() + " signIn success ");
Log.i(TAG, "AccessToken: " + huaweiAccount.getAccessToken());
Bundle bundle = new Bundle();
bundle.putString(TAG,huaweiAccount.getDisplayName() + " signIn success ");
Analystics.getInstance(this).setEvent("login",bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("user", huaweiAccount.getDisplayName());
startActivity(intent);
this.finish();
}
HomeFragment
In this screen, I have implemented Huawei Ads and Analytics kit.
Which helps to log the user activity and shown banner ads.
Loading Banner Ads
Code:
private void initAds(View view) {
HwAds.init(getActivity());
hwBannerView = view.findViewById(R.id.huawei_banner_view);
hwBannerView.setVisibility(View.VISIBLE);
AdParam adParam = new AdParam.Builder().build();
hwBannerView.loadAd(adParam);
hwBannerView.setAdListener(adListener);
}
Log User Events
Code:
Bundle bundle = new Bundle();
bundle.putString(TAG,"City loaded");
Analystics.getInstance(getActivity()).setEvent("City",bundle);
cityList.setLayoutManager(new GridLayoutManager(getActivity(), 2));
cityList.setAdapter(new CityAdapter(cities, (item) -> {
Bundle bundle1 = new Bundle();
bundle.putString(TAG,"City Clicked"+item.getCityName());
Analystics.getInstance(getActivity()).setEvent("City",bundle1);
PopularCity popularCity = item;
Intent intent = new Intent(getActivity(), CityInfoDetailActivity.class);
intent.putExtra("name", popularCity.getCityName());
intent.putExtra("url", popularCity.getImageUrl());
startActivity(intent);
}));
CityInfoDetailActivity
In this screen, I have implemented the Huawei Banner ads and Huawei Analytics.
Loading Banner Ads
Code:
HwAds.init(this);
hwBannerView = findViewById(R.id.huawei_banner_view);
hwBannerView.setVisibility(View.VISIBLE);
AdParam adParam = new AdParam.Builder().build();
hwBannerView.loadAd(adParam);
hwBannerView.setAdListener(adListener);
Log User Events
Code:
if (extras != null) {
String name = extras.getString("name");
String imageUrl = extras.getString("url");
setTitle(name);
Glide.with(this).load(imageUrl).into(cityImage);
Bundle bundle = new Bundle();
bundle.putString(TAG,"City Info");
Analystics.getInstance(this).setEvent("City Details",bundle);
}
AllTripActivity
Code:
public class AllTripActivity extends AppCompatActivity {
private RecyclerView tripList;
private static final String TAG= AllTripActivity.class.getName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alltrips);
init();
}
private void init() {
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
tripList.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true));
tripList.setAdapter(new TripAdapter(list, (item) -> {
Intent intent = new Intent(this, PolylineActivity.class);
startActivity(intent);
}));
}
}
TripAdapter
Code:
public class TripAdapter extends RecyclerView.Adapter<TripAdapter.ViewHolder> {
private List<TripModel> list;
private ItemTripBinding mBinding;
private OnItemClickListener<TripModel> mOnItemClickListener;
public TripAdapter(List<TripModel> list, OnItemClickListener<TripModel> onItemClickListener) {
this.list = list;
this.mOnItemClickListener = onItemClickListener;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
mBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
R.layout.item_trip, parent, false);
return new ViewHolder(mBinding);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.bind(list.get(position), mOnItemClickListener);
}
@Override
public int getItemCount() {
return list.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
private ItemTripBinding cityBinding;
public ViewHolder(@NonNull ItemTripBinding cityBinding) {
super(cityBinding.getRoot());
this.cityBinding = cityBinding;
}
public void bind(TripModel item, OnItemClickListener<TripModel> listener) {
cityBinding.setData(item);
itemView.setOnClickListener(v -> listener.onItemClick(item));
}
}
}
WeatherDetailActivity
In this screen, I have implemented the weather related information so that users can identify the city weather condition.
Code:
public class WeatherDetailActivity extends AppCompatActivity {
private ActivityWeatherBinding mMainBinding;
private WeatherViewModel mWeatherViewModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_weather);
mWeatherViewModel = ViewModelProviders.of(this).get(WeatherViewModel.class);
Bundle extras = getIntent().getExtras();
if (extras != null) {
String name = extras.getString("name");
mMainBinding.txtCityName.setText(name);
mMainBinding.txtTemperature.setText("21" + "\u00B0");
fetchWeatherDetails(name, false);
setForcastData();
}
}
@SuppressLint("SetTextI18n")
private void fetchWeatherDetails(String cityName, boolean isSearching) {
mWeatherViewModel.getCurrentWeatherLiveData(cityName).observeForever(result -> {
if (result != null) {
mMainBinding.txtCityName.setText(result.getLocation().getName());
mMainBinding.txtTemperature.setText(result.getCurrent().getTemperature() + "\u00B0");
}
});
}
private void setForcastData() {
List<CurrentWeather.Current> currents = new ArrayList<>();
for (int i = 1; i <= 7; i++) {
CurrentWeather.Current current = new CurrentWeather().new Current();
current.setObservationTime("Day");
current.setTemperature(21);
current.setIsDay(url);
currents.add(current);
}
mMainBinding.recycleWeeklyWeather.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true));
mMainBinding.recycleWeeklyWeather.setAdapter(new ForcastAdapter(currents));
}
}
WeatherViewModel
Code:
public class WeatherViewModel extends ViewModel {
private WeatherRepository mWeatherRepository = new WeatherRepository();
private final CompositeDisposable disposables = new CompositeDisposable();
private MutableLiveData<CurrentWeather> mWeatherLiveData = new MutableLiveData<>();
private MutableLiveData<ForcastWeather> mForcastWeatherLiveData = new MutableLiveData<>();
public LiveData<CurrentWeather> getCurrentWeatherLiveData(String city) {
disposables.add(mWeatherRepository.executeCurrentWeatherApi(city)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> mWeatherLiveData.setValue(result),
throwable -> mWeatherLiveData.setValue(null)
));
return mWeatherLiveData;
}
public LiveData<ForcastWeather> getForcastWeatherLiveData(String city) {
disposables.add(mWeatherRepository.executeForcastWeatherApi(city)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> mForcastWeatherLiveData.setValue(result),
throwable -> mForcastWeatherLiveData.setValue(null)
));
return mForcastWeatherLiveData;
}
@Override
protected void onCleared() {
disposables.clear();
}
}
Launch the application
Let us launch our application, see the result
More information like this, you can visit HUAWEI Developer Forum
In this article, I will mention about HMS Ads Kit Integration into Solar2D (Corona) project.
Corona provides a handy template to start. Copy \Native\Project Template\App from your Corona install directory and paste it somewhere writable. On Windows, Corona would usually be installed to \Program Files (x86)\Corona Labs\Corona.
{
"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"
}
And rename App to your project name.
The contents of App folder are as follows. In App folder, we need only Android and Corona folders.
In Corona folder, there is a sample project. When you open main.lua file, you can see how to call methods from android side. For example : library.init()
You can delete all of files in Corona folder and you can put our own codes. But you need to import our android library into our own main.lua folder to call method from android.
Code:
local library = require "plugin.library"
Open android folder with Android studio.
Let’s make the configuration settings;
1- Add maven repository into build.gradle.
2- Change coronaMinSdkVersion to 19.
3- Add HMS Ads Kit SDK and change minSdkVersion to 19.
implementation ‘com.huawei.hms:ads-lite:13.4.32.300’
And we will use LuaLoader class and write code into LuaLoader class in plugin.
Now plugin side is ready to use HMS Ads Kit. In android project, we need to create wrapper for Ads Kit methods.
If you don`t have enough information about HMS Ads kit, i recommend to read this documentation
https://developer.huawei.com/consumer/en/hms/huawei-adskit
In this article i will show banner ad integration. So let’s start.
Before we begin, let’s define these variables in LuaLoader.class.
Code:
public AdParam adParam;
private BannerView bannerView;
private FrameLayout layout;
public String bannarAdId = "testw6vs28auh3";
For banner ad, we need to create a wrapper. (e.g BannerWrapper). And we need to add into invoke method.
Code:
@Override
public int invoke(LuaState L) {
// Register this plugin into Lua with the following functions.
NamedJavaFunction[] luaFunctions = new NamedJavaFunction[]{
new InitWrapper(),
new ShowWrapper(),
new BannerWrapper(),
// new InterstitialAdWrapper(),
};
String libName = L.toString(1);
L.register(libName, luaFunctions);
// Returning 1 indicates that the Lua require() function will return the above Lua library.
return 1;
}
And then let`s create BannerWrapper class.
Code:
@SuppressWarnings("unused")
private class BannerWrapper implements NamedJavaFunction {
@Override
public String getName() {
return "showBanner";
}
@Override
public int invoke(LuaState L) {
return showBanner(L);
}
}
Invoke method which in BannerWrapper class, returns a method (e.g showBanner()).
Let`s create showBanner() method.
Code:
@SuppressWarnings({"WeakerAccess"})
public int showBanner(LuaState L) {
CoronaActivity activity = CoronaEnvironment.getCoronaActivity();
if (activity == null) {
return 0;
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
CoronaActivity activity = CoronaEnvironment.getCoronaActivity();
if (activity == null) {
return;
}
HwAds.init(CoronaEnvironment.getApplicationContext());
adParam = new AdParam.Builder().build();
if (layout == null) {
layout = new FrameLayout(activity);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
activity.getOverlayView().addView(layout, layoutParams);
}
if (bannerView == null) {
bannerView = new BannerView(CoronaEnvironment.getCoronaActivity());
bannerView.setAdId(bannarAdId);
bannerView.setBannerAdSize(BannerAdSize.BANNER_SIZE_320_50);
bannerView.loadAd(adParam);
layout.addView(bannerView);
}
}
});
return 0;
}
In this method firstly, we create an activity with using CoronaEnvironemnt.getCoronaAcitivty() method.
We call HyAds.init(context) method to initialize the HUAWEI Ads SDK and we initialize Param.Builder() to construct an ad request builder.
And then if layout is null, we initialize layout.
Lastly, If bannerView is null, we should initialize it. And we load this ads with loadAd() method, add this bannerView into layout.
That’s all.
When you call the showBanner() method on main.lua file, you see the banner ad.
Code:
local library = require "plugin.library"
library.showBanner()
When we run the android project, you should see the banner ads.
Let`s define AdListener to monitor the status of the ad.
Code:
private AdListener adListener = new AdListener() {
@Override
public void onAdLoaded() {
dispatchEvent("++Ad Loaded", false, "Loaded", "", "Banner");
}
@Override
public void onAdFailed(int errorCode) {
dispatchEvent(errorCode + "", true, "Loaded", "", "Banner");
}
@Override
public void onAdOpened() {
dispatchEvent("", false, "Openeed", "", "Banner");
}
@Override
public void onAdClicked() {
dispatchEvent("", false, "Clicked", "", "Banner");
}
@Override
public void onAdLeave() {
dispatchEvent("", false, "Leaved", "", "Banner");
}
@Override
public void onAdClosed() {
dispatchEvent("", false, "Closed", "", "Banner");
}
};
We use the dispatchEvent() method to send an information to the lua side. And the dispatchEvent() method takes only 1 parameter by default. I changed it to send more detailed information. I added some more parameters as follow.
Code:
public void dispatchEvent(final String data, final Boolean isError, final String phase, final String response, final String type) {
CoronaEnvironment.getCoronaActivity().getRuntimeTaskDispatcher().send(new CoronaRuntimeTask() {
@Override
public void executeUsing(CoronaRuntime runtime) {
LuaState L = runtime.getLuaState();
CoronaLua.newEvent(L, EVENT_NAME);
L.pushBoolean(isError);
L.setField(-2, "isError");
L.pushString(phase);
L.setField(-2, "phase");
L.pushString(response);
L.setField(-2, "response");
L.pushString(type);
L.setField(-2, "type");
L.pushString(data);
L.setField(-2, "message");
L.pushString("amazonAds");
L.setField(-2, "provider");
try {
CoronaLua.dispatchEvent(L, fListener, 0);
} catch (Exception ignored) {
}
}
});
}
And then we need to set listener into bannerView in showBanner method.
Code:
@SuppressWarnings({"WeakerAccess"})
public int showBanner(LuaState L) {
CoronaActivity activity = CoronaEnvironment.getCoronaActivity();
if (activity == null) {
return 0;
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
CoronaActivity activity = CoronaEnvironment.getCoronaActivity();
if (activity == null) {
return;
}
HwAds.init(CoronaEnvironment.getApplicationContext());
adParam = new AdParam.Builder().build();
if (layout == null) {
layout = new FrameLayout(activity);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
activity.getOverlayView().addView(layout, layoutParams);
}
if (bannerView == null) {
bannerView = new BannerView(CoronaEnvironment.getCoronaActivity());
bannerView.setAdId(bannarAdId);
bannerView.setBannerAdSize(BannerAdSize.BANNER_SIZE_320_50);
bannerView.setAdListener(adListener);
bannerView.loadAd(adParam);
layout.addView(bannerView);
}
}
});
return 0;
}
Now, on android side everything is ready. We need to update lua part. We should import json lib because we send more than one value via dispatchEvent(). And in listener method, we use json.prettify(event) method.
Code:
local library = require "plugin.library"
local json = require("json")
local function listener( event )
print( "Received event from Library plugin " , json.prettify(event))
end
library.init( listener )
library.showBanner()
Let’s run it and see the logs.
As you can see, we integrated the HMS Ads Kit into the corona project and we can see the status of the advertisement.
You can add all the features of the HMS ads kit to your project in this way.
You can find the sample project from github. And Interstitial ad has been added in this sample project.
https://github.com/kayahanbaskeser/hms-ads-kit-integration-into-corona-project
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Introduction
In this article, we will learn how to integrate Huawei ML kit in Android application. ML Kit provides many text service, you can check these services in the link provided in the reference section , in this sample we will be integrating one of its text service I.e. On-device translation, it translates text from the source language into the target language with the support of an on-device model, even when no Internet service is available.
Supported Devices
Development Overview
You need to install Android Studio IDE and I assume that you have prior knowledge of Android application development.
Hardware Requirements
A computer (desktop or laptop) running Windows 10.
Android phone (with the USB cable), which is used for debugging.
Software Requirements
Java JDK 1.8 or later.
Android Studio software installed.
HMS Core (APK) 4.X or later
Integration steps
Step 1. Huawei developer account and complete identity verification in Huawei developer website, refer to register Huawei ID.
Step 2. Create project in AppGallery Connect
Step 3. Adding HMS Core SDK
Let's start coding
How do I call sign in method?
Java:
private void signInWithHuaweiID() {
AccountAuthParams authParams = new AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setAuthorizationCode().createParams();
service = AccountAuthManager.getService(ClientActivity.this, authParams);
startActivityForResult(service.getSignInIntent(), 1212);
}
How do I get sign in result?
Java:
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
// Process the authorization result to obtain the authorization code from AuthAccount.
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1212) {
Task<AuthAccount> authAccountTask = AccountAuthManager.parseAuthResultFromIntent(data);
if (authAccountTask.isSuccessful()) {
// The sign-in is successful, and the user's ID information and authorization code are obtained.
AuthAccount authAccount = authAccountTask.getResult();
Log.i("TAG", "serverAuthCode:" + authAccount.getAuthorizationCode());
userName = authAccount.getDisplayName();
makeConnect();
} else {
// The sign-in failed.
Log.e("TAG", "sign in failed:" + ((ApiException) authAccountTask.getException()).getStatusCode());
}
}
}
How do I start server?
Java:
wManager = (WifiManager) getSystemService(WIFI_SERVICE);
serverIP = Formatter.formatIpAddress(wManager.getConnectionInfo().getIpAddress());
ip_txt.setText(serverIP);
class ServerThread implements Runnable {
@Override
public void run() {
try {
while (true) {
serverSocket = new ServerSocket(POST_NUMBER);
socket = serverSocket.accept();
output = new PrintWriter(socket.getOutputStream());
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Log.d("TAG", " here ");
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_status.setText("Waiting for conn at " + POST_NUMBER);
}
});
handler.post(new Runnable() {
@Override
public void run() {
tv_status.setText("Connected");
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
How do I send message using socket?
Java:
class SendMessage implements Runnable {
private String message;
SendMessage(String message) {
this.message = message;
}
@Override
public void run() {
output.write(message+"\r");
output.flush();
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_chat.append("\n New Message: " + message);
ed_message.setText("");
}
});
Thread.interrupted();
}
}
How do I receive message using socket?
Java:
private class ReadMessage implements Runnable {
@Override
public void run() {
while (true) {
try {
// Log.d("TAG","Server: Listening for message");
if(input!=null){
final String message = input.readLine();
if (message != null) {
handler.post(new Runnable() {
@Override
public void run() {
tv_chat.append("\n" + message );
}
});
}
}
} catch (IOException e) {
// Log.e("TAG","Error while receiving message");
e.printStackTrace();
}
}
}
}
Close the Socket and other connections
Java:
@Override
protected void onPause() {
super.onPause();
if (socket != null) {
try {
output.close();
input.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
How do I revoke auth permission?
Java:
if(service!=null){
// service indicates the AccountAuthService instance generated using the getService method during the sign-in authorization.
service.cancelAuthorization().addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(Task<Void> task) {
if (task.isSuccessful()) {
// Processing after a successful authorization cancellation.
Log.i("TAG", "onSuccess: ");
} else {
// Handle the exception.
Exception exception = task.getException();
if (exception instanceof ApiException){
int statusCode = ((ApiException) exception).getStatusCode();
Log.i("TAG", "onFailure: " + statusCode);
}
}
}
});
}
How do I translate message using ML Text Service?
Java:
private void translateMessage(String text) {
MLApplication.getInstance().setApiKey(API_KEY);
// create an offline translator.
MLLocalTranslateSetting setting = new MLLocalTranslateSetting.Factory()
// Set the source language code. The ISO 639-1 standard is used. This parameter is mandatory. If this parameter is not set, an error may occur.
.setSourceLangCode("en")
// Set the target language code. The ISO 639-1 standard is used. This parameter is mandatory. If this parameter is not set, an error may occur.
.setTargetLangCode("hi")
.create();
myLocalTranslator = MLTranslatorFactory.getInstance().getLocalTranslator(setting);
// Set the model download policy.
MLModelDownloadStrategy downloadStrategy = new MLModelDownloadStrategy.Factory()
.needWifi()// It is recommended that you download the package in a Wi-Fi environment.
.create();
// Create a download progress listener.
MLModelDownloadListener modelDownloadListener = new MLModelDownloadListener() {
@Override
public void onProcess(long alreadyDownLength, long totalLength) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// Display the download progress or perform other operations.
}
});
}
};
myLocalTranslator.preparedModel(downloadStrategy, modelDownloadListener).
addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
// Called when the model package is successfully downloaded.
// input is a string of less than 5000 characters.
final Task<String> task = myLocalTranslator.asyncTranslate(text);
// Before translation, ensure that the models have been successfully downloaded.
task.addOnSuccessListener(new OnSuccessListener<String>() {
@Override
public void onSuccess(String translated) {
// Processing logic for detection success.
Log.d("TAG", "Text : " + translated);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
e.printStackTrace();
}
});
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
e.printStackTrace();
}
});
}
Result
Tricks and Tips
Makes sure that agconnect-services.json file added.
Make sure required dependencies are added
Make sure that service is enabled in AGC
Make sure that languages are supported
Conclusion
In this article, we have learnt how to integrate Huawei ML kit service i.e. text translation(message) in Client Server messaging using Socket in Android application. You can check the desired result in the result section. Hoping Huawei ML kit capabilities are helpful to you as well, like this sample, you can make use of ML services as per your requirement.
Thank you so much for reading. I hope this article helps you to understand the integration of Huawei ML kit in Android application.
Reference
Huawei ML Kit – Training video
Checkout in forum