More articles like this, you can visit HUAWEI Developer Forum and Medium.
How to integrate Text Recognition ML Kit ?
How to extract text from image of receipts, business cards, and documents?
{
"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"
}
1.Add dependencies in build.gradle file
Code:
implementation 'com.huawei.hms:ml-computer-vision-ocr:1.0.3.300' // Import the base SDK.
implementation 'com.huawei.hms:ml-computer-vision-ocr-cn-model:1.0.3.300' // Import the Chinese and English model package.
implementation 'com.huawei.hms:ml-computer-vision-ocr-jk-model:1.0.3.300' // Import the Japanese and Korean model package.
implementation 'com.huawei.hms:ml-computer-vision-ocr-latin-model:1.0.3.300' // Import the Latin-based language model package.
2.In MainActivity.click btn_detect to AndroidCameraApi to capture photo
Code:
btn_detect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent cameraActivity = new Intent(MainActivity.this, AndroidCameraApi.class);
startActivity(cameraActivity);
}
});
3.Create an AndroidCameraApi Activity to capture photo and get result with bytearray of image.
convert the bytearray to bitmap and save in sharedpreference pref.
Code:
Intent intent = new Intent(AndroidCameraApi.this, MainActivity.class);
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
String temp = Base64.encodeToString(b, Base64.DEFAULT);
SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", 0); // 0 - for private mode
SharedPreferences.Editor editor = pref.edit();
editor.putString("data", temp);
editor.commit();
startActivity(intent);
4.Back to MainActivity.use the bitmap string and convert to bitmap by Base64 decode and set the bitmap in localAnalyzer function
Code:
SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", 0); // 0 - for private mode
String data = pref.getString("data", null);
if (data != null) {
byte[] encodeByte = Base64.decode(data, Base64.DEFAULT);
Bitmap bitmap = BitmapFactory.decodeByteArray(encodeByte, 0,
encodeByte.length);
Log.d("Bitmap", bitmap.toString());
imageView.setImageBitmap(bitmap);
localAnalyzer(bitmap);
}
5.Pass bitmap in localAnalyzer(Local text recognition). Create the text analyzer MLTextAnalyzer to recognize text in images.
You can set MLLocalTextSetting to specify languages that can be recognized.
Create an MLFrame object using android.graphics.Bitmap. Support JPG, JPEG, PNG, and BMP .
The success convert text will return in onSuccess callback.
Code:
private MLTextAnalyzer analyzer;
Code:
private void localAnalyzer(Bitmap bitmaps) {
MLLocalTextSetting setting = new MLLocalTextSetting.Factory()
.setOCRMode(MLLocalTextSetting.OCR_DETECT_MODE)
.setLanguage("en")
.create();
this.analyzer = MLAnalyzerFactory.getInstance()
.getLocalTextAnalyzer(setting);
MLFrame frame = MLFrame.fromBitmap(bitmaps);
Task<MLText> task = this.analyzer.asyncAnalyseFrame(frame);
task.addOnSuccessListener(new OnSuccessListener<MLText>() {
@Override
public void onSuccess(MLText text) {
MainActivity.this.displaySuccess(text);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
MainActivity.this.displayFailure();
}
});
}
6.make use the return MLText and display on your textfield.(Block,line)
Code:
private void displaySuccess(MLText mlText) {
String result = "";
List<MLText.Block> blocks = mlText.getBlocks();
for (MLText.Block block : blocks) {
for (MLText.TextLine line : block.getContents()) {
result += line.getStringValue() + "\n";
}
}
this.mTextView.setText(result);
}
7 and also permission in manifest
Code:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
8.Text Recognition from the capture image on the Cloud Result* (more accurate!)
Code:
private void remoteAnalyzer(Bitmap bitmaps) {
MLRemoteTextSetting setting =
new MLRemoteTextSetting.Factory()
.setTextDensityScene(MLRemoteTextSetting.OCR_COMPACT_SCENE)
.setLanguageList(new ArrayList<String>() {{
this.add("zh");
this.add("en");
}})
.setBorderType(MLRemoteTextSetting.ARC)
.create();
this.analyzer = MLAnalyzerFactory.getInstance().getRemoteTextAnalyzer(setting);
MLFrame frame = MLFrame.fromBitmap(bitmaps);
Task<MLText> task = this.analyzer.asyncAnalyseFrame(frame);
task.addOnSuccessListener(new OnSuccessListener<MLText>() {
@Override
public void onSuccess(MLText text) {
MainActivity.this.remoteDisplaySuccess(text);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
MainActivity.this.displayFailure();
}
});
}
Reference:
https://developer.huawei.com/consumer/en/doc/HMSCore-Guides-V5/text-recognition-0000001050040053-V5
What languages are supported ?
Can you please share me the official document of Huawei ML Kit.
Thank you
Related
More articles 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"
}
Introduction
Now days, most of the application integrate an Maps. This article I will give you the process on how to do. Millions of users look up directions, plan their commutes, catch a ride.as well as touch on the many things available through maps to enhance the user experience in mobile apps.
Let’s Start how to Integrate Map:
Step1: create a new project in Android studio.
Step 2: Configure your app into AGC.
Step 3: Enable required Api & add SHA-256.
Step 4: Download the agconnect-services.json from AGC. Paste into app directory.
Step 5: Add the below dependency in app.gradle file.
Code:
implementation 'com.huawei.hms:maps:4.0.0.301'
Step 6: Add the below dependency in root.gradle file
Code:
maven { url 'http://developer.huawei.com/repo/' }
Step 7: Add appId & permissions in AndoridManifest.xml file
Code:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<meta-data
android:name="com.huawei.hms.client.appid"
android:value="appid=*******" />
Step 8: Sync your Project
Let’s Discuss functionality:
1.OnMapReady()
2.OnMapClick()
3.OnMarkerClick()
4.Create Circle
5.Create Custom Marker
1. OnMapReady: This Callback interface for when map is ready to be used
Code:
@Override
public void onMapReady(HuaweiMap map) {
mHuaweiMap = map;
enableUiSettings();
mHuaweiMap.setMaxZoomPreference(15);
mHuaweiMap.setMinZoomPreference(2);
}
2. OnMapClick : This callback interface when the user makes tap on the map.
Code:
@Override
public void onMapClick(LatLng latLng) {
try {
createMarker(latLng);
} catch (IOException e) {
e.printStackTrace();
}
}
3. OnMarkerClick : This callback interface when a marker is clicked
Code:
@Override
public boolean onMarkerClick(Marker marker) {
marker.showInfoWindow();
return true;
}
4. How to create circle on map:
Code:
private void addCircleToCurrentLocation() {
mHuaweiMap.addCircle(new CircleOptions()
.center(new LatLng(12.9716, 77.5946))
.radius(1000)
.strokeWidth(10)
.strokeColor(Color.GREEN)
.fillColor(Color.argb(128, 255, 0, 0))
.clickable(true));
}
5. How to create marker:
Code:
private void createMarker(LatLng latLng) throws IOException {
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.snippet("Address : " + featchAddress(latLng))
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_location));
mHuaweiMap.addMarker(markerOptions);
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(latLng) // Sets the center of the map to location user
.zoom(20) // Sets the zoom
.bearing(90) // Sets the orientation of the camera to east
.tilt(40) // Sets the tilt of the camera to 30 degrees
.build(); // Creates a CameraPosition from the builder
mHuaweiMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
mHuaweiMap.setOnMarkerClickListener(this);
}
In this article I covered few basics callbacks. below is the final code
Code:
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback, HuaweiMap.OnMapClickListener, HuaweiMap.OnMarkerClickListener {
private static final String MAPVIEW_BUNDLE_KEY = "MapViewBundleKey";
private static final int REQUEST_CODE = 100;
private static final LatLng LAT_LNG = new LatLng(12.9716, 77.5946);
private HuaweiMap mHuaweiMap;
private MapView mMapView;
private Button btnCustom;
private static final String[] RUNTIME_PERMISSIONS = {Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.INTERNET};
private Marker marker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnCustom = findViewById(R.id.btn_custom);
if (!hasPermissions(this, RUNTIME_PERMISSIONS)) {
ActivityCompat.requestPermissions(this, RUNTIME_PERMISSIONS, REQUEST_CODE);
}
mMapView = findViewById(R.id.mapView);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY);
}
init(mapViewBundle);
btnCustom.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mHuaweiMap.setOnMapClickListener(MainActivity.this);
}
});
}
private void init(Bundle mapViewBundle) {
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(this);
}
@Override
public void onMapReady(HuaweiMap map) {
mHuaweiMap = map;
enableUiSettings();
mHuaweiMap.setMaxZoomPreference(15);
mHuaweiMap.setMinZoomPreference(2);
addCircleToCurrentLocation();
}
/*
Enable Ui Settings
*/
private void enableUiSettings() {
mHuaweiMap.setMyLocationEnabled(true);
mHuaweiMap.getUiSettings().setMyLocationButtonEnabled(true);
mHuaweiMap.getUiSettings().setCompassEnabled(true);
mHuaweiMap.getUiSettings().setZoomControlsEnabled(true);
mHuaweiMap.getUiSettings().setMyLocationButtonEnabled(true);
}
/*
Create Circle to current location
*/
private void addCircleToCurrentLocation() {
mHuaweiMap.addCircle(new CircleOptions()
.center(new LatLng(12.9716, 77.5946))
.radius(1000)
.strokeWidth(10)
.strokeColor(Color.GREEN)
.fillColor(Color.argb(128, 255, 0, 0))
.clickable(true));
}
/*
Create Marker when you click on map
*/
private void createMarker(LatLng latLng) throws IOException {
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.snippet("Address : " + featchAddress(latLng))
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_location));
mHuaweiMap.addMarker(markerOptions);
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(latLng) // Sets the center of the map to location user
.zoom(20) // Sets the zoom
.bearing(90) // Sets the orientation of the camera to east
.tilt(40) // Sets the tilt of the camera to 30 degrees
.build(); // Creates a CameraPosition from the builder
mHuaweiMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
mHuaweiMap.setOnMarkerClickListener(this);
}
/*
Convert from latlong to Address
*/
private String featchAddress(LatLng latLng) throws IOException {
Geocoder geocoder = new Geocoder(this, Locale.ENGLISH);
List<Address> addresses = geocoder.getFromLocation(latLng.latitude, latLng.latitude, 1);
Toast.makeText(this, addresses.get(0).getLocality() + ", "
+ addresses.get(0).getAdminArea() + ", "
+ addresses.get(0).getCountryName(), Toast.LENGTH_SHORT).show();
return addresses.get(0).getLocality() + ", "
+ addresses.get(0).getAdminArea() + ", "
+ addresses.get(0).getCountryName();
}
private static boolean hasPermissions(Context context, String... permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
@Override
public void onMapClick(LatLng latLng) {
try {
createMarker(latLng);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public boolean onMarkerClick(Marker marker) {
marker.showInfoWindow();
return true;
}
Output:
Conclusion:
In this article you’ve learned how to create custom markers, how callbacks will work, as well as new ways for users to interact with the map.
https://developer.huawei.com/consumer/en/doc/development/HMS-References/hms-map-cameraupdate
Reference:
More information like this, you can visit HUAWEI Developer Forum
Introduction
HMS ML kit service searches in pre-established product image library for the same or similar products based on a product image taken by a customer, and returns the IDs of those products and related information.
{
"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"
}
Use Case
We will capture the product image using device camera from our developed shopping application.
We will show the returned products list in recycle view.
Prerequisite
Java JDK 1.8 or higher is recommended.
Android Studio is recommended.
Huawei android device with HMS core 4.0.0.300 or higher.
Before developing an app, you will need to register as a HUAWEI developer. Refer to Register a HUAWEI ID.
Integrating app gallery connect SDK. Refer to AppGallery Connect Service Getting Started.
Implementation
Enable ML kit in Manage APIs. Refer to Service Enabling.
Integrate following dependencies in app-level build.gradle.
Code:
// Import the product visual search SDK.
implementation 'com.huawei.hms:ml-computer-vision-cloud:2.0.1.300'
3. Add agc plugin in the top of app.gradle file.
Code:
apply plugin: 'com.huawei.agconnect'
4. Add the following permission in manifest.
Camera permission android.permission.CAMERA: Obtains real-time images or videos from a camera.
Internet access permission android.permission.INTERNET: Accesses cloud services on the Internet.
Storage write permission android.permission.WRITE_EXTERNAL_STORAGE: Upgrades the algorithm version.
Storage read permission android.permission.READ_EXTERNAL_STORAGE: Reads photos stored on a device.
5. To request camera permission in realtime.
Code:
private void requestCameraPermission() {
final String[] permissions = new String[] {Manifest.permission.CAMERA};
if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
ActivityCompat.requestPermissions(this, permissions, this.CAMERA_PERMISSION_CODE);
return;
}
}
6. Add following code in Application class
Code:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
MLApplication.getInstance().setApiKey("API KEY");
}
}
API key can be obtained either from AGC or integrated agcconnect-services.json.
7. To create an analyzer for product visual search.
Code:
private void initializeProductVisionSearch() {
MLRemoteProductVisionSearchAnalyzerSetting settings = new MLRemoteProductVisionSearchAnalyzerSetting.Factory()
// Set the maximum number of products that can be returned.
.setLargestNumOfReturns(16)
// Set the product set ID. (Contact [email protected] to obtain the configuration guide.)
// .setProductSetId(productSetId)
// Set the region.
.setRegion(MLRemoteProductVisionSearchAnalyzerSetting.REGION_DR_CHINA)
.create();
analyzer
= MLAnalyzerFactory.getInstance().getRemoteProductVisionSearchAnalyzer(settings);
}
8. To capture image from camera.
Code:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, REQ_CAMERA_CODE);
9. Once image has been captured, onActivityResult() method will be executed.
Code:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult");
if(requestCode == 101) {
if (resultCode == RESULT_OK) {
Bitmap bitmap = (Bitmap) data.getExtras().get("data");
if (bitmap != null) {
// Create an MLFrame object using the bitmap, which is the image data in bitmap format.
MLFrame mlFrame = new MLFrame.Creator().setBitmap(bitmap).create();
mlImageDetection(mlFrame);
}
}
}
}
private void mlImageDetection(MLFrame mlFrame) {
Task> task = analyzer.asyncAnalyseFrame(mlFrame);
task.addOnSuccessListener(new OnSuccessListener>() {
public void onSuccess(List products) {
// Processing logic for detection success.
displaySuccess(products);
}})
.addOnFailureListener(new OnFailureListener() {
public void onFailure(Exception e) {
// Processing logic for detection failure.
// Recognition failure.
try {
MLException mlException = (MLException)e;
// Obtain the result code. You can process the result code and customize respective messages displayed to users.
int errorCode = mlException.getErrCode();
// Obtain the error information. You can quickly locate the fault based on the result code.
String errorMessage = mlException.getMessage();
} catch (Exception error) {
// Handle the conversion error.
}
}
});
}
private void displaySuccess(List productVisionSearchList) {
List productImageList = new ArrayList();
String prodcutType = "";
for (MLProductVisionSearch productVisionSearch : productVisionSearchList) {
Log.d(TAG, "type: " + productVisionSearch.getType() );
prodcutType = productVisionSearch.getType();
for (MLVisionSearchProduct product : productVisionSearch.getProductList()) {
productImageList.addAll(product.getImageList());
Log.d(TAG, "custom content: " + product.getCustomContent() );
}
}
StringBuffer buffer = new StringBuffer();
for (MLVisionSearchProductImage productImage : productImageList) {
String str = "ProductID: " + productImage.getProductId() + "
ImageID: " + productImage.getImageId() + "
Possibility: " + productImage.getPossibility();
buffer.append(str);
buffer.append("
");
}
Log.d(TAG , "display success: " + buffer.toString());
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.main_fragment_container, new SearchResultFragment(productImageList, prodcutType ));
transaction.commit();
}
onSuccess() callback will give us list of MLProductVisionSearch objects, which can be used to get product id and image URL of each product. Also we can get the product type using productVisionSearch.getType(). getType() returns number which can be mapped.
10. We can achieve the product type mapping with following code.
Code:
private String getProductType(String type) {
switch(type) {
case "0":
return "Others";
case "1":
return "Clothing";
case "2":
return "Shoes";
case "3":
return "Bags";
case "4":
return "Digital & Home appliances";
case "5":
return "Household Products";
case "6":
return "Toys";
case "7":
return "Cosmetics";
case "8":
return "Accessories";
case "9":
return "Food";
}
return "Others";
}
11. To get product id and image URL from MLVisionSearchProductImage.
Code:
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final MLVisionSearchProductImage mlProductVisionSearch = productVisionSearchList.get(position);
holder.tvTitle.setText(mlProductVisionSearch.getProductId());
Glide.with(context)
.load(mlProductVisionSearch.getImageId())
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(holder.imageView);
}
Images
Reference
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides-V5/sdk-data-security-0000001050040129-V5
In this post, I will describe how to load and show the Interstitial Ad.
Creating an Interstitial Ad Object
To create an InterstitialAd object, you need to initialize an InterstitialAd object of the AndroidJavaObject type and set the slot ID for the interstitial ad.
In the InterstitialTest.cs script, the interstitial ad proxy class mHwInterstitialAd in Android is instantiated through reflection to initialize the interstitial ad object InterstitialAd in the Ads SDK.
Code:
public class InterstitialTest : MonoBehaviour
{
...
private AndroidJavaObject mHwInterstitialAd;
// testb4znbuh3n2 indicates a test ad slot ID.
private const string adId = "testb4znbuh3n2";
...
private void handleRequestAd()
{
// Processing after clicking.
...
AndroidJavaClass playerClass = new AndroidJavaClass(Constant.UnityActivityClassName);
AndroidJavaObject activity = playerClass.GetStatic<AndroidJavaObject>("currentActivity");
mHwInterstitialAd = new AndroidJavaObject(Constant.InterstitialName, activity);
...
mHwInterstitialAd.Call("setAdId", adId);
...
}
...
}
...
From the Android project, you can define InstertialAdProxy class to provide methods for setting ad id.
Code:
class InterstitialAdProxy(private val context: context) {
private val mInterstitialAd: InterstitialAd
private var mAdListener: IAdStatusListener? = null
private val mMainThreadHandler = Handler(Looper.getMainLooper())
init {
mInterstitialAd = InterstitialAd(mContext)
}
fun setAdId(adId: String?) {
mInterstitialAd.setAdId(adId)
}
...
}
To call an Android API, you need to specify the path of the package name InterstitialName in the Android library project. The following shows the InterstitialName setting.
Code:
public class Constant
{
...
public const string InterstitialName = "com.huawei.hms.ads.unityhwadlib.adproxy.InterstitialAdProxy";
...
}
Setting an Ad Event Listener
We need to define a callback interface AdStatusListener that inherits AndroidJavaProxy in Unity to implement the interaction between the Unity callback function and Android. The event types of this interface are the same as those of the callback function interface IAdStatusListener in the Android project.
Code:
public class AdLoadErrorCodeEventArgs : EventArgs
{
public int ErrorCode { get; set; }
}
public class AdStatusListener : AndroidJavaProxy
{
public event EventHandler<EventArgs> mOnAdClosed;
public event EventHandler<AdLoadErrorCodeEventArgs> mOnAdFailed;
public event EventHandler<EventArgs> mOnAdLeftApp;
public event EventHandler<EventArgs> mOnAdOpened;
public event EventHandler<EventArgs> mOnAdLoaded;
public event EventHandler<EventArgs> mOnAdClicked;
public event EventHandler<EventArgs> mOnAdImpression;
public AdStatusListener() : base(Constant.AdStatusListenerName) {}
public void onAdClosed()
{
if (mOnAdClosed != null)
{
mOnAdClosed(this, EventArgs.Empty);
}
}
public void onAdFailed(int errorCode)
{
if (mOnAdFailed != null)
{
AdLoadErrorCodeEventArgs args = new AdLoadErrorCodeEventArgs()
{
ErrorCode = errorCode
};
mOnAdFailed(this, args);
}
}
public void onAdLeftApp()
{
if (mOnAdLeftApp != null)
{
mOnAdLeftApp(this, EventArgs.Empty);
}
}
public void onAdOpened()
{
if (mOnAdOpened != null)
{
mOnAdOpened(this, EventArgs.Empty);
}
}
public void onAdLoaded()
{
if (mOnAdLoaded != null)
{
mOnAdLoaded(this, EventArgs.Empty);
}
}
public void onAdClicked()
{
if (mOnAdClicked != null)
{
mOnAdClicked(this, EventArgs.Empty);
}
}
public void onAdImpression()
{
if (mOnAdImpression != null)
{
mOnAdImpression(this, EventArgs.Empty);
}
}
}
Then call setAdListener to set a listener to listen for the life cycle events of an interstitial ad and implement the callback events
Code:
public class InterstitialTest : MonoBehaviour
{
...
private AndroidJavaObject mHwInterstitialAd;
...
private void handleRequestAd()
{
...
// Set the ad listener.
AdStatusListener adStatusListener = new AdStatusListener();
adListener.mOnAdLoaded += onAdLoadSuccess;
adListener.mOnAdFailed += onAdLoadFail;
mHwInterstitialAd.Call("setAdListener", adStatusListener);
...
}
private void onAdLoadSuccess(object sender, EventArgs args)
{
...
}
private void onAdLoadFail(object sender, AdLoadErrorCodeEventArgs args)
{
...
}
}
Creating a sample scene to load and show Interstitial Ad
In Scenes of Unity Editor, create a RequestAd button for loading an ad and create a ShowAd button for displaying an ad.
{
"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"
}
Define a click event for each button to specify the processing after each button is clicked.
Code:
public class InterstitialTest : MonoBehaviour
{
...
private GameObject mLoadButton;
private AndroidJavaObject mHwInterstitialAd;
...
void Start()
{
mLoadButton = GameObject.Find("RequestAd");
mLoadButton.GetComponent<Button>().onClick.AddListener(handleRequestAd);
mShowButton = GameObject.Find("ShowAd");
mShowButton.GetComponent<Button>().onClick.AddListener(handleShowAd);
}
...
private void handleRequestAd()
{
...
}
...
private void handleShowAd()
{
...
}
...
}
Loading an Interstitial Ad
Implement the loadAd method in your Android project's InterstitialAdProxy class as below
Code:
class InterstitialAdProxy(private val context: context) {
...
private val mInterstitialAd: InterstitialAd
...
fun loadAd(adRequest: AdParam?) {
mInterstitialAd.loadAd(adRequest)
}
...
}
Then call this method from Unity script as below
Code:
public class InterstitialTest : MonoBehaviour
{
...
private AndroidJavaObject mHwInterstitialAd;
...
private void handleRequestAd()
{
...
// Load an ad.
UnityHwAdRequest adRequest = new UnityHwAdRequest.Builder().build();
mHwInterstitialAd.Call("loadAd", adRequest.getAdRequestJavaObject());
...
}
...
}
The request parameter class UnityHwAdRequest also needs to be defined in the Unity project and the reflection class of the Ads SDK needs to be obtained to pass ad request parameters.
Code:
public class UnityHwAdRequest
{
...
public AndroidJavaObject getAdRequestJavaObject()
{
AndroidJavaObject adRequestBuilder = new AndroidJavaObject(Constant.AdRequestBuilderName);
foreach (string keyword in mKeyWords)
{
adRequestBuilder.Call<AndroidJavaObject>("addKeyword", keyword);
}
if (mTargetingContentUrl != null)
{
adRequestBuilder.Call<AndroidJavaObject>("setTargetingContentUrl", mTargetingContentUrl);
}
...
}
}
The following shows the AdRequestBuilderName setting.
Code:
public class Constant
{
...
public const string AdRequestBuilderName = "com.huawei.hms.ads.AdParam$Builder";
...
}
Displaying an Interstitial Ad
Implement isLoaded and show methods in your Android project's InterstitialAdProxy class as below
Code:
class InterstitialAdProxy(private val context: context) {
...
private val mInterstitialAd: InterstitialAd
...
val isLoaded: Boolean
get() = mInterstitialAd.isLoaded()
fun show() {
mInterstitialAd.show()
}
...
}
When the button for displaying an interstitial ad is clicked, handleShowAd is called to display the ad. In the handleShowAd method, the isLoaded method of the proxy object of the AndroidJavaObject type can be used to determine whether the ad loading is complete. If the returned value of the method is true, the ad loading is complete. In this case, the show method of the AndroidJavaObject object can be called to display the interstitial ad.
Code:
public class InterstitialTest : MonoBehaviour
{
...
private void handleShowAd()
{
if(mHwInterstitialAd != null && mHwInterstitialAd.Call<bool>("isLoaded"))
{
mHwInterstitialAd.Call("show");
}
else
{
...
}
}
}
Demo result
The ad display will be as follow
I will describe how to load and display a Rewarded Ad in the next post.
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
More information like this, you can visit HUAWEI Developer Forum
Introduction
Flight booking app allows user to search and book flight. In this article, we will integrate app messaging and analytics into demo flight booking application.
For prerequisite and set up, refer to part 1.
Usecase
We will show the marker and dotted polyline between source and destination airport using Huawei Map kit.
Huawei Map Kit
1. Enable Map kit in AGC. Refer Service Enabling.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
2. In order to use Huawei map kit, we need to integrate following code in app-level build.gradle.
Code:
implementation 'com.huawei.hms:maps:5.0.1.300'
3. Add following permissions in Manifest.
Code:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA"/>
//To obtain current device location
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
4. To provide real time permission.
Code:
private void requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.i(TAG, "sdk >= 23 M");
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);
}
}
}
5. Add following code to in your xml file to set the map attributes.
Code:
<com.huawei.hms.maps.MapView
android:id="@+id/mapview_huawei"
android:layout_width="match_parent"
android:layout_height="200dp" />
6. To use map in your app, you need to implement OnMapReadyCallback.
Code:
public class PolylineholderFragment extends Fragment implements OnMapReadyCallback {
@Override
public void onMapReady(HuaweiMap huaweiMap) {
}
}
7. Load MapView in the onCreate() or onCreateView() method and call getMapAsync() to register the callback.
Code:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flight_details);
mMapView = findViewById(R.id.mapview_huawei);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle("MapViewBundleKey");
}
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(this);
}
8. To draw marker at source and destination airport.
Code:
LatLng origin = new LatLng(HelperUtilities.originAirport.getLatitude(), HelperUtilities.originAirport.getLongitude());
LatLng destination = new LatLng(HelperUtilities.destinationAirport.getLatitude(), HelperUtilities.destinationAirport.getLongitude());
huaweiMap.addMarker(new MarkerOptions().position(origin).icon(BitmapDescriptorFactory.fromResource(R.drawable.htl_location_accent)));
huaweiMap.addMarker(new MarkerOptions().position(destination).icon(BitmapDescriptorFactory.fromResource(R.drawable.htl_location_accent)));
9. To specify the camera position of specific location.
Code:
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLng(origin);
huaweiMap.moveCamera(cameraUpdate);
10. To draw dotted polyline between origin and destination airport, we need to create a list of PatternItem and call method addPoyline() and pass the source and destination LatLng object.
Code:
int PATTERN_GAP_LENGTH_PX = 2;
final PatternItem DOT = new Dot();
PatternItem GAP = new Gap(PATTERN_GAP_LENGTH_PX);
int PATTERN_DASH_LENGTH_PX = 2;
PatternItem DASH = new Dash(PATTERN_DASH_LENGTH_PX);
List<PatternItem> PATTERN_POLYGON_BETA =
Arrays.asList(DOT, GAP, DASH, GAP);
mPolyline = huaweiMap.addPolyline(new PolylineOptions()
.add(origin, destination)
.color(Color.RED).pattern(PATTERN_POLYGON_BETA)
.width(2));
11. OnMapReady() imlementation looks like this.
Code:
int PATTERN_GAP_LENGTH_PX = 2;
int PATTERN_DASH_LENGTH_PX = 2;
@Override
public void onMapReady(HuaweiMap huaweiMap) {
if (null == huaweiMap) {
return;
}
if (null != mPolyline) {
mPolyline.remove();
mPolyline = null;
}
final PatternItem DOT = new Dot();
PatternItem GAP = new Gap(PATTERN_GAP_LENGTH_PX);
PatternItem DASH = new Dash(PATTERN_DASH_LENGTH_PX);
List<PatternItem> PATTERN_POLYGON_BETA =
Arrays.asList(DOT, GAP, DASH, GAP);
LatLng origin = new LatLng(HelperUtilities.originAirport.getLatitude(), HelperUtilities.originAirport.getLongitude());
LatLng destination = new LatLng(HelperUtilities.originAirport.getLatitude(), HelperUtilities.destinationAirport.getLongitude());
mPolyline = huaweiMap.addPolyline(new PolylineOptions()
.add(origin, destination)
.color(Color.RED).pattern(PATTERN_POLYGON_BETA)
.width(2));
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLng(origin);
huaweiMap.moveCamera(cameraUpdate);
huaweiMap.addMarker(new MarkerOptions().position(origin).icon(BitmapDescriptorFactory.fromResource(R.drawable.htl_location_accent)));
huaweiMap.addMarker(new MarkerOptions().position(destination).icon(BitmapDescriptorFactory.fromResource(R.drawable.htl_location_accent)));
}
Conclusion
In this article, we have shown how Huawei Map kit can be used to draw dotted polyline between origin and destination airport in flight detail screen.
References
For detailed guide, refer to this link.