This article is originally from HUAWEI Developer Forum
Forum link: https://forums.developer.huawei.com/forumPortal/en/home
As Flutter grows, we would get lot of plugins . If your project needs a specific dependency that does not exist on flutter you can define it in native code (IOS and android) and create a communication link between your flutter code and native code.
Contents
· Download Flutter SDK
· Set up flutter in Android studio
· Understanding the structure
· Running the demo project
· Understanding UI Components
· Threading concepts in flutter
· Integrating HMS to a flutter app
· Using hot reload
· Flutter inspector
Download Flutter SDK
Visit the following url to download the latest flutter SDK for your operating system.
https://flutter.dev/docs/get-started/install
Open Android studio and go to Plugin market place and search flutter and download the flutter plugin and restart your ID to show changes to your IDE, which enables us to create and manage a Flutter 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"
}
Set up flutter in Android studio
To create a new Flutter application select File->New Flutter project and follow the steps mentioned below.
Specify the path of your Flutter SDK that you downloaded in your Flutter SDK path as shown below and click next.
Understanding the structure
Pubspec.yaml : Here you will find the app’s dependencies. This includes configuration files, images and other assets. Enter the package name and the version under the dependencies: section of the pubspec.yaml. Run the command flutter packages get to install these packages, enter the package name and version under the dependencies section.
Main.dart : main.dart is the entry point of any flutter application, this is found under lib folder as shown above, this contains all the dart classes. During creation the main.dart file comes with a simple pre written code. Connect your device to the system or start the emulator and run the project to see the result of the sample project.
Adding images in flutter:
Create an assets folder in the directory that contains the pubspec.yaml file and move all your Images to this folder.
Use pub.get to sync all the files and use the images.
All native flutter dependencies are also added to pubspec.yaml file as shown below
Running Demo project
When we create a new flutter project, we get a simple app with floating action button and a counter, if you change text from the sample project above the counter text and click save it is immediately shown on the screen, this feature is called Hot reload and will be used extensively during flutter development.
We will be creating a simple UI with a click event which helps us to send messages to our native code.
UI Components in Flutter
Scaffold
Container
Material app
Stateful and stateless widget
Scaffold: The foundation for most projects on Android are an App bar, a body which holds our app design and a floating action button as highlighted below.
Create a structure for the design remains simple with a scaffold as most of the commonly used components are defined and supported by Scaffold.
As shown in the program below we have the following properties
· Appbar with a title
· Body with a text at the center of the screen
· Floating action button with onPressed click event
Code:
Widget build(BuildContext context){
Return Scaffold(
appBar:AppBar(
title: const Text(‘Sample Code’),
),
Body: Center(child: Text(‘You have pressed the button $_count times.’)),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => _count++),
tooltip: ‘Increment Counter’,
child: const Icon(Icons.add),
),
);
}}
Container: allows us to add background padding and design to different elements available on flutter. The diagram shows an example on using Container where we have a child text and color.
MaterialApp: MaterialApp is required when we use Material components and follow material design in your app
Stateful widget: Stateful widgets are mutable and are used when the UI can change dynamically, flutter creates a state object during build process of a stateful widget, this is the place where mutable state for that widget is saved.
Stateless widget: A stateless widget has no internal state to manage. Icon, IconButton, and Text are examples of stateless widgets, which are a subclass of StatelessWidget and are expected to remain static.
Threading concepts in Flutter
Async: function is asynchronous and you might need to wait a bit to get its result.
Await: wait until this function is finished and you will get its return value.
Future: is a type that ‘comes from the future’ and returns value from your asynchronous function. It can complete with success (.then) or with an error(.catchError).
Then ((value){…}): is a callback that’s called when future completes successfully(with a value).
Difference between Const and final in Flutter
Const: it is initialized during the compilation. Whenever you compile the program the value of PI will be initialized and memory will be allocated. It does not matter if you are using this variable or not.
Final: If you use the final variable in your program only then the value is initialized and memory location is allocated. And if you never use the final variable the value will never be initialized in your program.
Let us use the design and threading concepts to create project which updates location on a click event.
Integrating HMS to a Flutter app
Add a channel name in MyHomePage stateful widget, which will be added to our native code for message passing.
Code:
static const Locationplatform = const MethodChannel("samples.flutter.dev/Location");
We will be adding an Icon button and adding a click event to create a class which extends stateful widget as shown
Code:
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() {
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage> {
static const Locationplatform = const MethodChannel("samples.flutter.dev/Location");
@override
Widget build(BuildContext context) {
}
}
We have a stateful widget which will hold our click event to pass the message to native code using method channel. The program for the design of the button and click event is defined in the overridden method build in MyHomePageState class.
We have a text element which will be placed below the icon and all of this would be at the center of the screen. We define a Scaffold with app bar and body which would eb the important material design components of our app.
We define tooltip and icon button and center align them and create a text at the top of the screen.
Here is the complete main.dart file
Code:
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() {
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage> {
static const Locationplatform = const MethodChannel("samples.flutter.dev/Location");
@override
Widget build(BuildContext context) {
}
}
Using hot reload
One of the best feature of flutter is hot reload, make changes to your UI and click save while your device is connected to pc and click Ctrl + S on windows and see changes instantly on your screen.
Hot reload helps you see code and user interface changes instantly on your virtual device or mobile device. This is an extremely useful feature for the developer as it saves development time.
To see the changes instantly on your device change the title of your material app as shown above and click ctrl+S on windows and cmd+S on Mac.
It is important to know that any editing that will be performed in gradle or your JAVA/Kotlin files have to be opened for editing in a new window as editing it in the same files could show errors, which cannot be corrected.
After selecting open for editing in android studio as show below, we can follow the mentioned steps to add HMS location kit dependency, the process remains the same as adding any other kit to your project.
Please follow these steps
Creating an AGC Application.
Creating an Android Studio Project.
Generating a signature certificate.
Generating a signature certificate fingerprint.
Configuring the signature certificate fingerprint.
Adding the application package name and save the configuration file.
Configure the Maven address and AGC gradle plug-in.
Configure the signature file in Android Studio.
For more information please check the following link:
https://developer.huawei.com/consumer/en/codelab/HMSLocationKit/index.html#0
Define the Method channel in MainActivity file as shown below and this name should match the channel name in your main.dart file
Code:
private static final String ShowLocationchannel = "samples.flutter.dev/Location";
Extend your MainActivity class with FlutterActivity and override configureFlutterEngine to handle click event.
Code:
@Override
public void configureFlutterEngine(FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), ShowLocationchannel)
.setMethodCallHandler(
(call, result) -> {
if(call.method.equals("ShowLocation"))
{
ShowLocation();
result.success(0);
}
}
);
}
Create a method ShowLocation() and create an Intent to move to LocationActivity class
Code:
private int ShowLocation() {
startActivity(new Intent(MainActivity.this, LocationActivity.class));
return 0;
} Create LocationActivity class that uses FusedLocationProviderClient object to requestLocationUpdates and settingsClient object to call checkLocationSettings method to check device settings.
public class LocationActivity extends AppCompatActivity implements View.OnClickListener {
public static final String TAG = "LocationUpdatesCallback";
// the callback of the request
LocationCallback mLocationCallback;
LocationRequest mLocationRequest;
private FusedLocationProviderClient fusedLocationProviderClient;
private SettingsClient settingsClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location);
findViewById(R.id.location_requestLocationUpdatesWithCallback).setOnClickListener(this);
findViewById(R.id.location_removeLocationUpdatesWithCallback).setOnClickListener(this);
// create fusedLocationProviderClient
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
// create settingsClient
settingsClient = LocationServices.getSettingsClient(this);
mLocationRequest = new LocationRequest();
// Set the interval for location updates, in milliseconds.
mLocationRequest.setInterval(10000);
// set the priority of the request
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (null == mLocationCallback) {
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
List<Location> locations = locationResult.getLocations();
if (!locations.isEmpty()) {
for (Location location : locations) {
Toast.makeText(LocationActivity.this,
"onLocationResult location[Longitude,Latitude,Accuracy]:" + location.getLongitude()
+ "," + location.getLatitude() + "," + location.getAccuracy(),Toast.LENGTH_LONG);
}
}
}
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
if (locationAvailability != null) {
boolean flag = locationAvailability.isLocationAvailable();
Log.i(TAG, "onLocationAvailability isLocationAvailable:" + flag);
}
}
};
}
// check location permisiion
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "sdk < 28 Q");
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
String[] strings =
{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
ActivityCompat.requestPermissions(this, strings, 1);
}
} else {
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
"android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) {
String[] strings = {android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"};
ActivityCompat.requestPermissions(this, strings, 2);
}
}
}
private void requestLocationUpdatesWithCallback() {
try {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
// check devices settings before request location updates.
settingsClient.checkLocationSettings(locationSettingsRequest)
.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
Log.i(TAG, "check location settings success");
// request location updates
fusedLocationProviderClient
.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.i(TAG, "requestLocationUpdatesWithCallback onSuccess");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG,
"requestLocationUpdatesWithCallback onFailure:" + e.getMessage());
}
});
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "checkLocationSetting onFailure:" + e.getMessage());
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
ResolvableApiException rae = (ResolvableApiException) e;
rae.startResolutionForResult(LocationActivity.this, 0);
} catch (IntentSender.SendIntentException sie) {
Log.e(TAG, "PendingIntent unable to execute request.");
}
break;
}
}
});
} catch (Exception e) {
Log.e(TAG, "requestLocationUpdatesWithCallback exception:" + e.getMessage());
}
}
@Override
protected void onDestroy() {
// don't need to receive callback
removeLocationUpdatesWithCallback();
super.onDestroy();
}
/**
* remove the request with callback
*/
private void removeLocationUpdatesWithCallback() {
try {
fusedLocationProviderClient.removeLocationUpdates(mLocationCallback)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.i(TAG, "removeLocationUpdatesWithCallback onSuccess");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "removeLocationUpdatesWithCallback onFailure:" + e.getMessage());
}
});
} catch (Exception e) {
Log.e(TAG, "removeLocationUpdatesWithCallback exception:" + e.getMessage());
}
}
@Override
public void onClick(View v) {
try {
switch (v.getId()) {
case R.id.location_requestLocationUpdatesWithCallback:
requestLocationUpdatesWithCallback();
break;
case R.id.location_removeLocationUpdatesWithCallback:
removeLocationUpdatesWithCallback();
break;
default:
break;
}
} catch (Exception e) {
Log.e(TAG, "RequestLocationUpdatesWithCallbackActivity Exception:" + e);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
if (grantResults.length > 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSION successful");
} else {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSSION failed");
}
}
if (requestCode == 2) {
if (grantResults.length > 2 && grantResults[2] == PackageManager.PERMISSION_GRANTED
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION successful");
} else {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION failed");
}
}
}
}
Code:
<span style="font-family: arial , helvetica , sans-serif;font-size: 18.0px;"><strong>Please add the following permissions to your manifest file to request Location updates</strong></span><strong>
</strong>
Code:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
Flutter inspector
We can use the Flutter inspector to find the nesting of all your widgets making it very easy to edit or find the widget you are looking for, improving design or changes to your UI is extremely simple in flutter using Enable select widget module.
Click select widget module to use he feature as shown below, after you click the select widget module, click on any widget on your screen and you will see changes to your flutter inspector widget tab. The widget selected on your device is highlighted and changes can be made this makes it simpler to find the widget if you a lot of widgets in your widget tree.
Click on the find Icon as shown in the figure to repeat the process again to find a widget.
Conclusion
An existing HMS project can be linked to a flutter screen using a method channel.
This completes the flutter tutorial, please comment like and share.
Stay tuned for more updates
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"
}
What is it?
Huawei Games is a group of APIs from Huawei to simplify some games basic features like leaderboards, achievements, Events and online matches.
Gaming technologies are constantly evolving. Nevertheless, a lot of core gameplay elements have remained unchanged for decades. High scores, leaderboards, quests, achievements, and multiplayer support are examples. If you are developing a game for the Android platform, you don't have to implement any of those elements manually. You can simply use the Huawei Game services APIs instead.
Features of Huawei Game services
· HUAWEI ID sign-in
· Real-name authentication
· Bulletins
· Achievements
· Events
· Leaderboard
· Saved games
· Player statistics
Let’s start!
You should follow the steps
1) Create an android project in android studio.
2) Get the SHA Key. Create SHA key
3) Create a Game App in the Huawei app galley connect (AGC)
4) Provide the SHA key in the information section.
5) Provide storage location.
6) Enable Game service.
7) After all the steps need to download the agconnect-services.json from the app information section. Copy and paste the json file in the app folder of the android project.
8) Copy and paste the below maven url inside the repositories of buildscript and allprojects ( project build.gradle file )
maven { url 'http://developer.huawei.com/repo/'
Add the classpath in the dependencies path
classpath 'com.huawei.agconnect:agcp:1.2.1.300'
9) Copy and paste the below plugin in the app build.gradle file dependencies section.
apply plugin: 'com.huawei.agconnect'
Add the below dependencies.
implementation 'com.huawei.hms:base:4.0.4.301'
implementation 'com.huawei.hms:hwid:4.0.4.300'
implementation 'com.huawei.hms:iap:4.0.4.300'
implementation 'com.huawei.hms:game:4.0.3.301'
Note: if you are not using the In-App purchase then no need add the following dependency.
1. implementation 'com.huawei.hms:iap:4.0.4.300'
10) Sync App.
In this series of article we will build Tic Tac Toe game. In this article will see the following features.
· Sign In.
· Initialization.
· Getting player info.
· Saving player info.
Sign In
User can sign-in with Huawei account. They can play game.
Code:
public void signIn() {
Task<AuthHuaweiId> authHuaweiIdTask = HuaweiIdAuthManager.getService(this, getHuaweiIdParams()).silentSignIn();
authHuaweiIdTask.addOnSuccessListener(new OnSuccessListener<AuthHuaweiId>() {
@Override
public void onSuccess(AuthHuaweiId authHuaweiId) {
showLog("signIn success");
showLog("display:" + authHuaweiId.getDisplayName());
welcomeTv.setVisibility(View.VISIBLE);
welcomeTv.setText("Welcome back " + authHuaweiId.getDisplayName());
signIn.setVisibility(View.INVISIBLE);
showLog("AT:" + authHuaweiId.getAccessToken());
mAuthid = authHuaweiId;
SignInCenter.get().updateAuthHuaweiId(authHuaweiId);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException) {
signIn.setVisibility(View.VISIBLE);
welcomeTv.setVisibility(View.INVISIBLE);
ApiException apiException = (ApiException) e;
showLog("signIn failed:" + apiException.getStatusCode());
showLog("start getSignInIntent");
signInNewWay();
}
}
});
}
public HuaweiIdAuthParams getHuaweiIdParams() {
return new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM_GAME).createParams();
}
public void signInNewWay() {
Intent intent = HuaweiIdAuthManager.getService(SignInActivity.this, getHuaweiIdParams()).getSignInIntent();
startActivityForResult(intent, SIGN_IN_INTENT);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (SIGN_IN_INTENT == requestCode) {
handleSignInResult(data);
} else {
showLog("unknown requestCode in onActivityResult");
}
}
private void handleSignInResult(Intent data) {
if (null == data) {
showLog("signIn inetnt is null");
return;
}
// HuaweiIdSignIn.getSignedInAccountFromIntent(data);
String jsonSignInResult = data.getStringExtra("HUAWEIID_SIGNIN_RESULT");
if (TextUtils.isEmpty(jsonSignInResult)) {
showLog("SignIn result is empty");
return;
}
try {
HuaweiIdAuthResult signInResult = new HuaweiIdAuthResult().fromJson(jsonSignInResult);
if (0 == signInResult.getStatus().getStatusCode()) {
showLog("Sign in success.");
showLog("Sign in result: " + signInResult.toJson());
SignInCenter.get().updateAuthHuaweiId(signInResult.getHuaweiId());
} else {
showLog("Sign in failed: " + signInResult.getStatus().getStatusCode());
}
} catch (JSONException var7) {
showLog("Failed to convert json from signInResult.");
}
}
The above show the sign in with Huawei account.
Initialization
Key steps to launch the game
Add the following code to the onCreate method of the Application to register the callback listening function of the activity.
Code:
package com.android.huawei.tictactoe;
import android.app.Application;
import com.huawei.hms.api.HuaweiMobileServicesUtil;
public class TicTacToeApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
HuaweiMobileServicesUtil.setApplication(this);
}
}
Call JosApps.getJosAppsClient to initialize the JosAppsClient object and JosAppsClient.init to initialize the game.
Code:
private void init() {
JosAppsClient appsClient = JosApps.getJosAppsClient(this, null);
appsClient.init();
Log.i(TAG, "init success");
}
Getting player info
Code:
public void getCurrentPlayer() {
PlayersClientImpl client = (PlayersClientImpl) Games.getPlayersClient(this, getAuthHuaweiId());
Task<Player> task = client.getCurrentPlayer();
task.addOnSuccessListener(new OnSuccessListener<Player>() {
@Override
public void onSuccess(Player player) {
String result = "display:" + player.getDisplayName() + "\n"
+ "playerId:" + player.getPlayerId() + "\n"
+ "playerLevel:" + player.getLevel() + "\n"
+ "timestamp:" + player.getSignTs() + "\n"
+ "playerSign:" + player.getPlayerSign();
showLog(result);
playerId = player.getPlayerId();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException) {
String result = "rtnCode:" + ((ApiException) e).getStatusCode();
showLog(result);
}
}
});
}
The above code gives the player info like playerId, Player name, player level, in which level he/she is playing.
Saving player info.
Player info can be updated using AppPlayerInfo. Player level, role, rank etc. The following code show the saving player info.
To save player info playerId is mandatory.
Code:
public void savePlayerInfo() {
if (TextUtils.isEmpty(playerId)) {
Toast.makeText(this, "Get the current user first", Toast.LENGTH_SHORT).show();
return;
}
PlayersClient client = Games.getPlayersClient(this, getAuthHuaweiId());
AppPlayerInfo appPlayerInfo = new AppPlayerInfo();
appPlayerInfo.area = "2";
appPlayerInfo.rank = "56";
appPlayerInfo.role = "Pro";
appPlayerInfo.sociaty = "Red Cliff III";
appPlayerInfo.playerId = playerId;
Task<Void> task = client.savePlayerInfo(appPlayerInfo);
task.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void v) {
Toast.makeText(SignInActivity.this, "Player info saved successfully ", Toast.LENGTH_SHORT).show();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException) {
String result = "rtnCode:" + ((ApiException) e).getStatusCode();
Toast.makeText(SignInActivity.this, result, Toast.LENGTH_SHORT).show();
}
}
});
}
Result
Nice, thank you
Can be useful for online games.
Freemind R said:
More information like this, you can visit HUAWEI Developer Forum
What is it?
Huawei Games is a group of APIs from Huawei to simplify some games basic features like leaderboards, achievements, Events and online matches.
Gaming technologies are constantly evolving. Nevertheless, a lot of core gameplay elements have remained unchanged for decades. High scores, leaderboards, quests, achievements, and multiplayer support are examples. If you are developing a game for the Android platform, you don't have to implement any of those elements manually. You can simply use the Huawei Game services APIs instead.
Features of Huawei Game services
· HUAWEI ID sign-in
· Real-name authentication
· Bulletins
· Achievements
· Events
· Leaderboard
· Saved games
· Player statistics
Let’s start!
You should follow the steps
1) Create an android project in android studio.
2) Get the SHA Key. Create SHA key
3) Create a Game App in the Huawei app galley connect (AGC)
4) Provide the SHA key in the information section.
5) Provide storage location.
6) Enable Game service.
7) After all the steps need to download the agconnect-services.json from the app information section. Copy and paste the json file in the app folder of the android project.
8) Copy and paste the below maven url inside the repositories of buildscript and allprojects ( project build.gradle file )
maven { url 'http://developer.huawei.com/repo/'
Add the classpath in the dependencies path
classpath 'com.huawei.agconnect:agcp:1.2.1.300'
9) Copy and paste the below plugin in the app build.gradle file dependencies section.
apply plugin: 'com.huawei.agconnect'
Add the below dependencies.
implementation 'com.huawei.hms:base:4.0.4.301'
implementation 'com.huawei.hms:hwid:4.0.4.300'
implementation 'com.huawei.hms:iap:4.0.4.300'
implementation 'com.huawei.hms:game:4.0.3.301'
Note: if you are not using the In-App purchase then no need add the following dependency.
1. implementation 'com.huawei.hms:iap:4.0.4.300'
10) Sync App.
In this series of article we will build Tic Tac Toe game. In this article will see the following features.
· Sign In.
· Initialization.
· Getting player info.
· Saving player info.
Sign In
User can sign-in with Huawei account. They can play game.
Code:
public void signIn() {
Task<AuthHuaweiId> authHuaweiIdTask = HuaweiIdAuthManager.getService(this, getHuaweiIdParams()).silentSignIn();
authHuaweiIdTask.addOnSuccessListener(new OnSuccessListener<AuthHuaweiId>() {
@Override
public void onSuccess(AuthHuaweiId authHuaweiId) {
showLog("signIn success");
showLog("display:" + authHuaweiId.getDisplayName());
welcomeTv.setVisibility(View.VISIBLE);
welcomeTv.setText("Welcome back " + authHuaweiId.getDisplayName());
signIn.setVisibility(View.INVISIBLE);
showLog("AT:" + authHuaweiId.getAccessToken());
mAuthid = authHuaweiId;
SignInCenter.get().updateAuthHuaweiId(authHuaweiId);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException) {
signIn.setVisibility(View.VISIBLE);
welcomeTv.setVisibility(View.INVISIBLE);
ApiException apiException = (ApiException) e;
showLog("signIn failed:" + apiException.getStatusCode());
showLog("start getSignInIntent");
signInNewWay();
}
}
});
}
public HuaweiIdAuthParams getHuaweiIdParams() {
return new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM_GAME).createParams();
}
public void signInNewWay() {
Intent intent = HuaweiIdAuthManager.getService(SignInActivity.this, getHuaweiIdParams()).getSignInIntent();
startActivityForResult(intent, SIGN_IN_INTENT);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (SIGN_IN_INTENT == requestCode) {
handleSignInResult(data);
} else {
showLog("unknown requestCode in onActivityResult");
}
}
private void handleSignInResult(Intent data) {
if (null == data) {
showLog("signIn inetnt is null");
return;
}
// HuaweiIdSignIn.getSignedInAccountFromIntent(data);
String jsonSignInResult = data.getStringExtra("HUAWEIID_SIGNIN_RESULT");
if (TextUtils.isEmpty(jsonSignInResult)) {
showLog("SignIn result is empty");
return;
}
try {
HuaweiIdAuthResult signInResult = new HuaweiIdAuthResult().fromJson(jsonSignInResult);
if (0 == signInResult.getStatus().getStatusCode()) {
showLog("Sign in success.");
showLog("Sign in result: " + signInResult.toJson());
SignInCenter.get().updateAuthHuaweiId(signInResult.getHuaweiId());
} else {
showLog("Sign in failed: " + signInResult.getStatus().getStatusCode());
}
} catch (JSONException var7) {
showLog("Failed to convert json from signInResult.");
}
}
The above show the sign in with Huawei account.
Initialization
Key steps to launch the game
Add the following code to the onCreate method of the Application to register the callback listening function of the activity.
Code:
package com.android.huawei.tictactoe;
import android.app.Application;
import com.huawei.hms.api.HuaweiMobileServicesUtil;
public class TicTacToeApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
HuaweiMobileServicesUtil.setApplication(this);
}
}
Call JosApps.getJosAppsClient to initialize the JosAppsClient object and JosAppsClient.init to initialize the game.
Code:
private void init() {
JosAppsClient appsClient = JosApps.getJosAppsClient(this, null);
appsClient.init();
Log.i(TAG, "init success");
}
Getting player info
Code:
public void getCurrentPlayer() {
PlayersClientImpl client = (PlayersClientImpl) Games.getPlayersClient(this, getAuthHuaweiId());
Task<Player> task = client.getCurrentPlayer();
task.addOnSuccessListener(new OnSuccessListener<Player>() {
@Override
public void onSuccess(Player player) {
String result = "display:" + player.getDisplayName() + "\n"
+ "playerId:" + player.getPlayerId() + "\n"
+ "playerLevel:" + player.getLevel() + "\n"
+ "timestamp:" + player.getSignTs() + "\n"
+ "playerSign:" + player.getPlayerSign();
showLog(result);
playerId = player.getPlayerId();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException) {
String result = "rtnCode:" + ((ApiException) e).getStatusCode();
showLog(result);
}
}
});
}
The above code gives the player info like playerId, Player name, player level, in which level he/she is playing.
Saving player info.
Player info can be updated using AppPlayerInfo. Player level, role, rank etc. The following code show the saving player info.
To save player info playerId is mandatory.
Code:
public void savePlayerInfo() {
if (TextUtils.isEmpty(playerId)) {
Toast.makeText(this, "Get the current user first", Toast.LENGTH_SHORT).show();
return;
}
PlayersClient client = Games.getPlayersClient(this, getAuthHuaweiId());
AppPlayerInfo appPlayerInfo = new AppPlayerInfo();
appPlayerInfo.area = "2";
appPlayerInfo.rank = "56";
appPlayerInfo.role = "Pro";
appPlayerInfo.sociaty = "Red Cliff III";
appPlayerInfo.playerId = playerId;
Task<Void> task = client.savePlayerInfo(appPlayerInfo);
task.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void v) {
Toast.makeText(SignInActivity.this, "Player info saved successfully ", Toast.LENGTH_SHORT).show();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException) {
String result = "rtnCode:" + ((ApiException) e).getStatusCode();
Toast.makeText(SignInActivity.this, result, Toast.LENGTH_SHORT).show();
}
}
});
}
Result
Click to expand...
Click to collapse
Whtat is the difference between sign in and Silent Sign in
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
Real-time locating is a core function for many apps, allowing them to quickly and accurately locate users' real time locations.
HUAWEI Location Kit enables apps to quickly obtain precise user locations and build up global locating capabilities, helping you implement personalized map display and interaction, as well as improve overall location-based service experience.
This article demonstrates how to use HUAWEI Location Kit and Map Kit to implement the real-time locating capability in an app.
ExpectationsAn app can obtain and display a user's real-time location on the map, especially when the app is launched for the first time. The map display changes in accordance to the user's actual location.
{
"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"
}
Involved CapabilitiesLocation Kit: basic locating
Map Kit: map display
Implementation PrincipleAn app uses Location Kit to obtain a user's real-time location and uses Map Kit to display the My Location button on the in-app map that the user can tap to determine their real-time location.
PreparationsRegister as a developer and create a project in AppGallery Connect.
Click here to register as a developer.
Create an app, add the SHA-256 signing certificate fingerprint, enable Map Kit and Site Kit, and download the agconnect-services.json file of the app. For detailed instructions, please visit the official website of HUAWEI Developers.
Configure the Android Studio project.
Copy the agconnect-services.json file to the app directory of the project.
Go to allprojects > repositories and configure the Maven repository address for the HMS Core SDK.
Go to buildscript > repositories and configure the Maven repository address for the HMS Core SDK.
If the agconnect-services.json file has been added to the app, go to buildscript > dependencies and add the AppGallery Connect plugin configuration.
Code:
buildscript {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.huawei.agconnect:agcp:1.3.1.300'
}
}
allprojects {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
}
}
Add build dependencies in the dependencies block.
Code:
dependencies {
implementation 'com.huawei.hms:maps:{version}'
implementation 'com.huawei.hms:location:{version}'
}
Add the following configuration to the file header.
Code:
apply plugin: 'com.huawei.agconnect'
Copy the signing certificate generated in Generating a Signing Certificate to the app directory of your project, and configure the signing certificate in android in the build.gradle file.
Code:
signingConfigs {
release {
// Signing certificate.
storeFile file("**.**")
// KeyStore password.
storePassword "******"
// Key alias.
keyAlias "******"
// Key password.
keyPassword "******"
v2SigningEnabled true
v2SigningEnabled true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
debuggable true
}
debug {
debuggable true
}
}
Key Code Implementation(1) Compile a service to obtain a user's real-time location.
Java:
public class LocationService extends Service {
private final String TAG = this.getClass().getSimpleName();
List<ILocationChangedLister> locationChangedList = new ArrayList<>();
// Location
private FusedLocationProviderClient fusedLocationProviderClient;
private LocationRequest mLocationRequest;
private final LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
locationResult.getLocations();
Log.d(TAG, "onLocationResult: " + locationResult);
Location location = locationResult.getLocations().get(0);
Log.w(TAG, "onLocationResult:Latitude " + location.getLatitude());
Log.w(TAG, "onLocationResult:Longitude " + location.getLongitude());
for (ILocationChangedLister locationChanged : locationChangedList) {
locationChanged.locationChanged(new LatLng(location.getLatitude(), location.getLongitude()));
}
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
super.onLocationAvailability(locationAvailability);
Log.d(TAG, "onLocationAvailability: " + locationAvailability.toString());
}
};
private final MyBinder binder = new MyBinder();
private final Random generator = new Random();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
Log.i("DemoLog", "TestService -> onCreate, Thread: " + Thread.currentThread().getName());
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("DemoLog",
"TestService -> onStartCommand, startId: " + startId + ", Thread: " + Thread.currentThread().getName());
return START_NOT_STICKY;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i("DemoLog", "TestService -> onUnbind, from:" + intent.getStringExtra("from"));
return false;
}
@Override
public void onDestroy() {
Log.i("DemoLog", "TestService -> onDestroy, Thread: " + Thread.currentThread().getName());
super.onDestroy();
}
public int getRandomNumber() {
return generator.nextInt();
}
public void addLocationChangedlister(ILocationChangedLister iLocationChangedLister) {
locationChangedList.add(iLocationChangedLister);
}
public void getMyLoction() {
Log.d(TAG, "getMyLoction: ");
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
mLocationRequest = new LocationRequest();
builder.addLocationRequest(mLocationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
// Location setting
settingsClient.checkLocationSettings(locationSettingsRequest)
.addOnSuccessListener(locationSettingsResponse -> fusedLocationProviderClient
.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener(aVoid -> Log.d(TAG, "onSuccess: " + aVoid)))
.addOnFailureListener(Throwable::printStackTrace);
}
public class MyBinder extends Binder {
public LocationService getService() {
return LocationService.this;
}
}
public interface ILocationChangedLister {
/**
* Update the location information
*
* @param latLng The new location information
*/
public void locationChanged(LatLng latLng);
}
}
(2) Add a map in the activity to monitor a user's real-time location.
Add a map using the XML layout file:
XML:
<com.huawei.hms.maps.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Add a map in the activity:
XML:
mapView.onCreate(null);
mapView.getMapAsync(this);
Tap My Location button to display the current location on the map:
XML:
@Override
public void onMapReady(HuaweiMap huaweiMap) {
hMap = huaweiMap;
hMap.setMyLocationEnabled(true);
}
Bind Location Kit to listen to location changing events:
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
isBound = true;
if (binder instanceof LocationService.MyBinder) {
LocationService.MyBinder myBinder = (LocationService.MyBinder) binder;
locationService = myBinder.getService();
Log.i(TAG, "ActivityA onServiceConnected");
locationService.addLocationChangedlister(iLocationChangedLister);
locationService.getMyLoction();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
locationService = null;
Log.i(TAG, "ActivityA onServiceDisconnected");
}
};
Bind the activity to LocationService:
private void bindLocationService() {
Intent intent = new Intent(mActivity, LocationService.class);
intent.putExtra("from", "ActivityA");
Log.i(TAG, "-------------------------------------------------------------");
Log.i(TAG, "bindService to ActivityA");
mActivity.bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
Process the location changing events in the location changing listener:
LocationService.ILocationChangedLister iLocationChangedLister = new LocationService.ILocationChangedLister() {
@Override
public void locationChanged(LatLng latLng) {
Log.d(TAG, "locationChanged: " + latLng.latitude);
Log.d(TAG, "locationChanged: " + latLng.longitude);
updateLocation(latLng);
}
};
Update map view:
private void updateLocation(LatLng latLng) {
mLatLng = latLng;
hMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 1));
}
Testing the AppYou can use a mock location app to change your current location and see how the map view and My Location button alter accordingly.
To learn more, please visit:
HUAWEI Developers official website
Development Guide
Reddit to join developer discussions
GitHub or Gitee to download the demo and sample code
Stack Overflow to solve integration problems
Follow our official account for the latest HMS Core-related news and updates.
Original Source
{
"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 Scene detection using Huawei HiAI. We will build the Pets cart where we can sell pets online and filter pets by scene detection using Huawei HiAI.
What is Scene Detection?
Scene detection can quickly classify images by identifying the type of scene to which the image content belongs, such as animals, green plants, food, buildings, and automobiles. Scene detection can also add smart classification labels to images, facilitating smart album generation and category-based image management.
Features
Fast: This algorithm is currently developed based on the deep neural network, to fully utilize the neural processing unit (NPU) of Huawei mobile phones to accelerate the neural network, achieving an acceleration of over 10 times.
Lightweight: This API greatly reduces the computing time and ROM space the algorithm model takes up, making your app more lightweight.
Abundant: Scene detection can identify 103 scenarios such as Cat, Dog, Snow, Cloudy sky, Beach, Greenery, Document, Stage, Fireworks, Food, Sunset, Blue sky, Flowers, Night, Bicycle, Historical buildings, Panda, Car, and Autumn leaves. The detection average accuracy is over 95% and the average recall rate is over 85% (lab data).
How to integrate Scene Detection
1. Configure the application on the AGC.
2. Apply for HiAI Engine Library
3. Client application development process.
Configure application on the AGC
Follow the steps
Step 1: We need to register as a developer account in AppGallery Connect. If you are already a developer ignore this step.
Step 2: Create an app by referring to Creating a Project and Creating an App in the Project
Step 3: Set the data storage location based on the current location.
Step 4: Generating a Signing Certificate Fingerprint.
Step 5: Configuring the Signing Certificate Fingerprint.
Step 6: Download your agconnect-services.json file, paste it into the app root directory.
Apply for HiAI Engine Library
What is Huawei HiAI?
HiAI is Huawei’s AI computing platform. HUAWEI HiAI is a mobile terminal–oriented artificial intelligence (AI) computing platform that constructs three layers of ecology: service capability openness, application capability openness, and chip capability openness. The three-layer open platform that integrates terminals, chips, and the cloud brings more extraordinary experience for users and developers.
How to apply for HiAI Engine?
Follow the steps
Step 1: Navigate to this URL, choose App Service > Development, and click HUAWEI HiAI.
Step 2: Click Apply for the HUAWEI HiAI kit.
Step 3: Enter required information like Product name and Package name, click the Next button.
Step 4: Verify the application details and click Submit button.
Step 5: Click the Download SDK button to open the SDK list.
Step 6: Unzip downloaded SDK and add to your android project under the libs folder.
Step 7: Add jar files dependencies into app build.gradle file.
Code:
implementation fileTree(include: ['*.aar', '*.jar'], dir: 'libs')
implementation 'com.google.code.gson:gson:2.8.6'
repositories {
flatDir {
dirs 'libs'
}
}Copy code
Client application development process
Follow the steps
Step 1: Create an Android application in the Android studio (Any IDE which is your favorite).
Step 2: Add the 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'
Step 3: Add permission in AndroidManifest.xml
Code:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- CAMERA -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
Step 4: Build application.
First request run time permission
Code:
private void requestPermissions() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int permission = ActivityCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 0x0010);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}Copy code
Initialize vision base
private void initVisionBase() {
VisionBase.init(SceneDetectionActivity.this, new ConnectionCallback() {
[USER=439709]@override[/USER]
public void onServiceConnect() {
//This callback method is called when the connection to the service is successful.
//Here you can initialize the detector class, mark the service connection status, and more.
Log.i(LOG, "onServiceConnect ");
Toast.makeText(SceneDetectionActivity.this, "Service Connected", Toast.LENGTH_SHORT).show();
}
[USER=439709]@override[/USER]
public void onServiceDisconnect() {
//This callback method is called when disconnected from the service.
//You can choose to reconnect here or to handle exceptions.
Log.i(LOG, "onServiceDisconnect");
Toast.makeText(SceneDetectionActivity.this, "Service Disconnected", Toast.LENGTH_SHORT).show();
}
});
}
Build Async class for scene detection.
Code:
class SceneDetectionAsync extends AsyncTask<Bitmap, Void, JSONObject> {
[USER=439709]@override[/USER]
protected JSONObject doInBackground(Bitmap... bitmaps) {
//Bitmap bitmap = BitmapFactory.decodeFile(imgPath);//Obtain the Bitmap image. (Note that the Bitmap must be in the ARGB8888 format, that is, bitmap.getConfig() == Bitmap.Config.ARGB8888.)
Frame frame = new Frame();//Construct the Frame object
frame.setBitmap(bitmaps[0]);
SceneDetector sceneDetector = new SceneDetector(SceneDetectionActivity.this);//Construct Detector.
JSONObject jsonScene = sceneDetector.detect(frame, null);//Perform scene detection.
Scene sc = sceneDetector.convertResult(jsonScene);//Obtain the Java class result.
if (sc != null) {
int type = sc.getType();//Obtain the identified scene type.
Log.d(LOG, "Type:" + type);
}
Log.d(LOG, "Json data:" + jsonScene.toString());
return jsonScene;
}
[USER=439709]@override[/USER]
protected void onPostExecute(JSONObject data) {
super.onPostExecute(data);
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
adapter = new MyListAdapter(getPetsFilteredDataList(data));
recyclerView.setAdapter(adapter);
Toast.makeText(SceneDetectionActivity.this, "Data filtered successfully", Toast.LENGTH_SHORT).show();
}
}Copy code
Show select image dialog.
private void selectImage() {
try {
PackageManager pm = getPackageManager();
int hasPerm = pm.checkPermission(Manifest.permission.CAMERA, getPackageName());
if (hasPerm == PackageManager.PERMISSION_GRANTED) {
final CharSequence[] options = {"Take Photo", "Choose From Gallery", "Cancel"};
androidx.appcompat.app.AlertDialog.Builder builder = new androidx.appcompat.app.AlertDialog.Builder(this);
builder.setTitle("Select Option");
builder.setItems(options, new DialogInterface.OnClickListener() {
[USER=439709]@override[/USER]
public void onClick(DialogInterface dialog, int item) {
if (options[item].equals("Take Photo")) {
dialog.dismiss();
fileUri = getOutputMediaFileUri();
Log.d(LOG, "end get uri = " + fileUri);
Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
i.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(i, REQUEST_IMAGE_TAKE);
} else if (options[item].equals("Choose From Gallery")) {
dialog.dismiss();
Intent i = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, REQUEST_IMAGE_SELECT);
} else if (options[item].equals("Cancel")) {
dialog.dismiss();
}
}
});
builder.show();
} else
Toast.makeText(this, "Camera Permission error", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Toast.makeText(this, "Camera Permission error", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
/**
* Create a file Uri for saving an image or video
*/
private Uri getOutputMediaFileUri() {
//return Uri.fromFile(getOutputMediaFile(type));
Log.d(LOG, "authority = " + getPackageName() + ".provider");
Log.d(LOG, "getApplicationContext = " + getApplicationContext());
return FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", getOutputMediaFile());
}
/**
* Create a File for saving an image
*/
private static File getOutputMediaFile() {
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "LabelDetect");
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d(LOG, "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_" + timeStamp + ".jpg");
Log.d(LOG, "mediaFile " + mediaFile);
return mediaFile;
}
When user select image start detecting.
Code:
@override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if ((requestCode == REQUEST_IMAGE_TAKE || requestCode == REQUEST_IMAGE_SELECT) && resultCode == RESULT_OK) {
String imgPath;
if (requestCode == REQUEST_IMAGE_TAKE) {
imgPath = Environment.getExternalStorageDirectory() + fileUri.getPath();
} else {
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = SceneDetectionActivity.this.getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
imgPath = cursor.getString(columnIndex);
cursor.close();
}
Log.d(LOG, "imgPath = " + imgPath);
bmp = BitmapFactory.decodeFile(imgPath);
if (bmp != null) {
//Toast.makeText(this, "Bit map is not null", Toast.LENGTH_SHORT).show();
dialog = ProgressDialog.show(SceneDetectionActivity.this,
"Predicting...", "Wait for one sec...", true);
SceneDetectionAsync async = new SceneDetectionAsync();
async.execute(bmp);
} else {
Toast.makeText(this, "Bit map is null", Toast.LENGTH_SHORT).show();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
Data set
Code:
private MyListData[] getPetsList() {
MyListData[] listData = new MyListData[]{
new MyListData("Labrador Retriever", "20000INR", "Age: 1yr", R.drawable.labrador_retriever),
new MyListData("Bengal Cat", "8000INR", "Age: 1 month", R.drawable.bengal_cat),
new MyListData("Parrot", "2500INR", "Age: 3months", R.drawable.parrot),
new MyListData("Rabbit", "1500INR", "Age: 1 month", R.drawable.rabbit_image),
new MyListData("Beagle", "20500INR", "Age:6months", R.drawable.beagle),
new MyListData("Bulldog", "19000INR", "1yr", R.drawable.bulldog),
new MyListData("German Shepherd", "18000INR", "Age: 2yr", R.drawable.german_shepherd_dog),
new MyListData("German Shorthaired Pointer", "20000INR", "Age: 8 months", R.drawable.german_shorthaired_pointer),
new MyListData("Golder retriever", "12000INR", "Age: 7months", R.drawable.golden_retriever),
new MyListData("Pembroke Welsh corgi", "9000INR", "Age: 10months", R.drawable.pembroke_welsh_corgi),
new MyListData("Pomeranian", "25000INR", "Age: 10months", R.drawable.pomeranian),
new MyListData("Poodle", "15000INR", "Age: 3months", R.drawable.poodle),
new MyListData("Rottweiler", "1700INR", "Age:2yr", R.drawable.rottweiler),
new MyListData("Shihtzu", "18000INR", "Age: 5months", R.drawable.shih_tzu),
};
return listData;
}
private MyListData[] getPetsFilteredDataList(JSONObject jsonObject) {
MyListData[] listData = null;
try {
//{"resultCode":0,"scene":"{\"type\":13}"}
String scene = jsonObject.getString("scene");
JSONObject object = new JSONObject(scene);
int type = object.getInt("type");
switch (type) {
case 1:
break;
case 12:
//Get Cats filtered data here
break;
case 13:
listData = getDogsData();
break;
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return listData;
}
private MyListData[] getDogsData() {
MyListData[] dogsList = new MyListData[]{
new MyListData("Labrador Retriever", "20000INR", "Age: 1yr", R.drawable.labrador_retriever),
new MyListData("Beagle", "20500INR", "Age:6months", R.drawable.beagle),
new MyListData("Bulldog", "19000INR", "1yr", R.drawable.bulldog),
new MyListData("German Shepherd", "18000INR", "Age: 2yr", R.drawable.german_shepherd_dog),
new MyListData("German Shorthaired Pointer", "20000INR", "Age: 8 months", R.drawable.german_shorthaired_pointer),
new MyListData("Golder retriever", "12000INR", "Age: 7months", R.drawable.golden_retriever),
new MyListData("Pembroke Welsh corgi", "9000INR", "Age: 10months", R.drawable.pembroke_welsh_corgi),
new MyListData("Pomeranian", "25000INR", "Age: 10months", R.drawable.pomeranian),
new MyListData("Poodle", "15000INR", "Age: 3months", R.drawable.poodle),
new MyListData("Rottweiler", "1700INR", "Age:2yr", R.drawable.rottweiler),
new MyListData("Shihtzu", "18000INR", "Age: 5months", R.drawable.shih_tzu),
};
return dogsList;
}
Result
Before Filter.
After filter
Tips and Tricks
Check dependencies downloaded properly.
Latest HMS Core APK is required.
Min SDK is 21. Otherwise we get Manifest merge issue.
Run detect() background thread otherwise app will crash with error.
If you are taking image from a camera or gallery make sure your app has camera and storage permission.
Add the downloaded huawei-hiai-vision-ove-10.0.4.307.aar, huawei-hiai-pdk-1.0.0.aar file to libs folder.
If device does not supports you will get 601 code in the result code
Maximum 20MB image
Conclusion
In this article, we have learnt the following concepts.
What is Scene detection?
Features of scene detection
How to integrate scene detection using Huawei HiAI
How to Apply Huawei HiAI
How to build the application
How to filter data by scene
Reference
Scene detection
Apply for Huawei HiAI
Filling in addresses is a task that users of lifestyle apps and mini programs that provide services such as group buying, takeout, package delivery, housekeeping, logistics, and moving services often have to perform. Generally, this requires users to manually fill in their address information, for example, selecting California, Los Angeles, and Hollywood Blvd in sequence using several drop-down list boxes and then manually entering their names and phone numbers. This process usually takes some time and is prone to input error.
Wouldn't it be handy if there was an automatic way for users to fill in addresses quickly and accurately? With HMS Core Location Kit's fused location and geocoding capabilities, a lifestyle app can automatically pinpoint the current location of a user or obtain the street address of a map location, and fill that information in the address box. Thanks to this, users are freed from the hassle of having to manually enter addresses, as well preventing human error. In this article, I will explain how you can easily integrate this feature into your app and provide you with sample code.
Demo
{
"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"
}
Development ProcedurePrepare for the development1. Sign in to AppGallery Connect and click My projects. Find your project, go to Project settings > Manage APIs, and toggle on the Location Kit switch. Then, click the app for which you need to configure the signing certificate fingerprint, and go to Project settings > General information. In the App information area, click Add next to SHA-256 certificate fingerprint, and enter the SHA-256 certificate fingerprint.
2. Go to Project settings > General information. In the App information area, click agconnect-services.json to download the configuration file. Then, copy the configuration file to the app's root directory.
3. Configure the project-level build.gradle file.
Java:
buildscript {
repositories {
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' }
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.2'
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
}
}
allprojects {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
mavenCentral()
}
}
Configure the app-level build.gradle file.
Java:
plugins {
id 'com.android.application'
id 'com.huawei.agconnect'
}
Add the following build dependency in the dependencies block in the app-level build.gradle file:
Java:
implementation 'com.huawei.hms:location:6.3.0.300'
Check permissions1. Declare the ACCESS_COARSE_LOCATION (approximate location permission), ACCESS_FINE_LOCATION (precise location permission), and ACCESS_BACKGROUND_LOCATION permissions in the AndroidManifest.xml file.
Java:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
2. Dynamically apply for related location permissions (according to requirements for dangerous permissions in Android 6.0 or later).
Java:
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "android sdk < 28 Q");
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
String[] strings =
{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
ActivityCompat.requestPermissions(this, strings, 1);
}
} else {
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
"android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) {
String[] strings = {Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"};
ActivityCompat.requestPermissions(this, strings, 2);
}
}
Obtain the location result1. Set location parameters, including the location update interval and location type
Java:
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
mSettingsClient = LocationServices.getSettingsClient(this);
mLocationRequest = new LocationRequest();
// Set the location update interval, in milliseconds.
mLocationRequest.setInterval(5000);
// Set the priority.
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
2. Call the getSettingsClient() method to obtain a SettingsClient instance, and call checkLocationSettings() to check the device location settings.
Java:
LocationSettingsRequest locationSettingsRequest = builder.build();
// Before requesting location updates, call checkLocationSettings to check the device location settings.
Task<LocationSettingsResponse> locationSettingsResponseTask =
mSettingsClient.checkLocationSettings(locationSettingsRequest);
After checking that the device location function is enabled, call requestLocationUpdates() to request location updates.
Java:
locationSettingsResponseTask.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
Log.i(TAG, "check location settings success");
mFusedLocationProviderClient
.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.i(TAG, "requestLocationUpdatesWithCallback onSuccess");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "requestLocationUpdatesWithCallback onFailure:" + e.getMessage());
}
});
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "checkLocationSetting onFailure:" + e.getMessage());
int statusCode = 0;
if (e instanceof ApiException) {
statusCode = ((ApiException) e).getStatusCode();
}
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
// When startResolutionForResult is called, a popup will
// appear, asking the user to grant relevant permissions.
if (e instanceof ResolvableApiException) {
ResolvableApiException rae = (ResolvableApiException) e;
rae.startResolutionForResult(MainActivity.this, 0);
}
} catch (IntentSender.SendIntentException sie) {
Log.e(TAG, "PendingIntent unable to execute request.");
}
break;
default:
break;
}
}
});
Obtain the address of the current location through reverse geocodingAfter obtaining the longitude and latitude of a location, pass them to the geocoding service (GeocoderService) to obtain a geocoding request object. Then, call the getFromLocation method and set request (GetFromLocationRequest) parameters to obtain the address of the location.
Java:
if (null == mLocationCallback) {
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
List<Location> locations = locationResult.getLocations();
if (!locations.isEmpty()) {
ExecutorUtil.getInstance().execute(new Runnable() {
@Override
public void run() {
Locale locale = new Locale("zh", "CN");
GeocoderService geocoderService = LocationServices.getGeocoderService(MainActivity.this, locale);
GetFromLocationRequest getFromLocationRequest = new GetFromLocationRequest(locations.get(0).getLatitude(), locations.get(0).getLongitude(), 1);
geocoderService.getFromLocation(getFromLocationRequest)
.addOnSuccessListener(new OnSuccessListener<List<HWLocation>>() {
@Override
public void onSuccess(List<HWLocation> hwLocation) {
printGeocoderResult(hwLocation);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.i(TAG, e.getMessage());
}
});
}
});
}
}
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
if (locationAvailability != null) {
boolean flag = locationAvailability.isLocationAvailable();
Log.i(TAG, "onLocationAvailability isLocationAvailable:" + flag);
}
}
};
}
Finally, display the obtained address on the screen to complete the implementation.
References>> Location Kit official website
>> Location Kit Development Guide
>> Reddit to join developer discussions
>> GitHub to download the sample code
>> Stack Overflow to solve integration problems