[Huawei Developers] muraliameakula:
In this article, we will develop an app for Huawei + Non-Huawei Android phones using Huawei Map Kit and Site Kit Widget. As you know previously Huawei Map could only be used in an HMS device but after the Map update version 5.1.0.300 (2020-12-31) Map Kit can be used on non-Huawei Android phones and in other scenarios where HMS Core (APK) is not required. Meanwhile, to use HMS Core in non-Huawei Android phones we will install the HMS Core App programmatically.

Huawei Map Kit:

Huawei Map kit allows can easily integrate map-based functions into your apps and make location-based services work better for you.

Huawei Site Kit:

Directing users to the location-based service they need makes your app accessible to more people. Give your users the power to explore their world.

Pre-Requisites

1. Integrate HMS Core in project.

2. Enable Scan and Map Kit from AGC Console.

3. Add agconnet-service.json file in the app level directory.

1. Add Dependencies & Permission:

1.1: Add the following dependencies in the app level build.gradle file:

dependencies {
//Map
implementation 'com.huawei.hms:maps:5.2.0.301'

//Map callback dependencies for using Huawei Map on Non-Huawei Devices
implementation 'com.huawei.hms:maproute-fallback:5.2.0.301'
implementation 'com.huawei.hms:hwmaps-fallback:5.2.0.301'

//Site
implementation 'com.huawei.hms:site:5.2.0.300'
}

1.2: Add the following permissions in the AndroidManifest.xml:

<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"/>

// To programmatically allow user to install HMS Core App
<meta-data
android:name="com.huawei.hms.client.channel.androidMarket"
android:value="false" />

2. Add Layout Files:

2.1: Add the activity_map.xml layout file in the layout folder of the res. This is the layout view of the MapActivity in the application, which contains the Site Kit Widget and a Mapview.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<!--Site Kit Widget-->
<fragment
android:id="@+id/widget_fragment"
android:name="com.huawei.hms.site.widget.SearchFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<!--Map Kit -->
<com.huawei.hms.maps.MapView
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:mapType="normal"
map:uiCompass="true"
map:uiZoomControls="true"/>

</LinearLayout>

3. Add Classes

3.1: Add the MapActivity.java file in the App. This class extends AppCompayActivity and implements OnMapReadyCallback. Meanwhile, Site Fragment is added.

public class MapActivity extends AppCompatActivity implements OnMapReadyCallback {

private static final String TAG = "MapViewDemoActivity";

private static final String MAPVIEW_BUNDLE_KEY = "MapViewBundleKey";

private static final int REQUEST_CODE = 100;

private static final LatLng LAT_LNG = new LatLng(31.5204, 74.3587);

private HuaweiMap hmap;

private MapView mMapView;

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};

@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "map onCreate:");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);

//Check for required Permissions
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);
}

AGConnectServicesConfig config = AGConnectServicesConfig.fromContext(this);
MapsInitializer.setApiKey(config.getString("client/api_key"));
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(this);

SearchFragment fragment = (SearchFragment) getSupportFragmentManager().findFragmentById(R.id.widget_fragment);
try {
fragment.setApiKey(URLEncoder.encode(config.getString("client/api_key"), "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}

fragment.setOnSiteSelectedListener(new SiteSelectionListener() {
@Override
public void onSiteSelected(Site data) {
if (hmap != null) {
hmap.clear();

MarkerOptions markerOptions = new MarkerOptions()
.position(new LatLng(data.getLocation().getLat(), data.getLocation().getLng()))
.title(data.getName()).snippet(data.getFormatAddress());
hmap.addMarker(markerOptions);
hmap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(data.getLocation().getLat(), data.getLocation().getLng()), 11));
}
}
@Override
public void onError(SearchStatus status) {
Toast.makeText(getApplication(), status.getErrorCode() + "\n" + status.getErrorMessage(),
Toast.LENGTH_LONG)
.show();
}
});
}

@Override
protected void onStart() {
super.onStart();
mMapView.onStart();
}

@Override
protected void onStop() {
super.onStop();
mMapView.onStop();
}

@Override
protected void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}

@Override
public void onMapReady(HuaweiMap map) {
Log.d(TAG, "onMapReady: ");

hmap = map;
hmap.setMyLocationEnabled(true);

// move camera by CameraPosition param ,latlag and zoom params can set here
CameraPosition build = new CameraPosition.Builder().target(LAT_LNG).zoom(11).build();

CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(build);
hmap.animateCamera(cameraUpdate);

}

@Override
protected void onPause() {
mMapView.onPause();
super.onPause();
}

@Override
protected void onResume() {
super.onResume();
mMapView.onResume();
}

@Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}

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;
}
}

4. Application Logic:

When the app is used in an HMS phone, the Map will be loaded and the Site Kit Widget will be used to search for the places and a marker will be added to the Map. Meanwhile, when the App will be used in a Non-Huawei Android phone, the Map will work fine as two of the callback dependencies have been added in the gradle file but Site Kit widget will not work therefore an HMS Core installation popup is displayed for the user to install the HMS Core App in the phone to enable the required Huawei Mobile Services.

** For Huawei Map, HMS Core App is not required in the Non-Huawei phone (Huawei Map User location doesn't work on Non-Huawei Device).

** For Site Kit Widget, HMS Core App is required in the Non-Huawei phone.

5: Run the Application:

Once all code has been added to the project, you can run the application on any Huawei or Non-Huawei android phone.

6: Demo:

7: Tips and Tricks:

1. hmap.setMyLocationEnabled(true); doesn't work in non-Huawei Android phone therefore respective Location services will be used to get the user's current location on Map.

2. Check for the permission on runtime to load the Map.

3. Map on non-Huawei Android phone will work in Map version 5.1.0.300 and onwards.

4. Encode the API Key before setting it for Site widget Fragment using URLEncoder.encode(config.getString("client/api_key"), "UTF-8")

8: Conclusion:

Huawei Map use on Non-Huawei Android phones will reduce the support cost, development efforts, and maintenance of using two different Map services for Huawei/Non-Huawei devices.

9: References:

9.1: Map Kit: click here

9.2: Site Kit: click here

Original Source