The Android SDK Guide Follow
The Meridian Android SDK has all the tools you’ll need to embed the Meridian Editor’s maps, turn-by-turn navigation, indoor location awareness, and notifications into your own custom Android app.
Once you’ve added maps, routes, and placemarks to the Meridian Editor, you can use the Meridian SDK to integrate that content into your Meridian-powered Android app.
Go here for the Meridian Android SDK Reference documentation.
Go here to download the latest version of the Android SDK.
The Meridian Samples App
The Meridian Samples app is included with the Android SDK to demonstrate common Meridian features and workflows.
Add the SDK to Your Project
In order to simplify using the Meridian SDK library with your Android project, we’ve bundled our SDK code into a binary distribution of the Android Library Project (AAR) file.
The Meridian SDK supports devices with Android 11, API Level 30 and higher.
The Meridian SDK targets the latest version of Android
Add the AAR Relative Path
Complete these steps to add the AAR file to your Android project.
-
Choose a location for
meridian-x.y.z.aar. -
Edit your app’s
build.gradlefile to add the relative path to themeridian-x-y-z.aarfile location insideflatDir { }, where our app will look for dependencies. Intorepositories { }, insert:
repositories {
google()
mavenCentral()
// Tell gradle to look in our parent directory for the meridian AAR package.
flatDir {
dirs '[relative file path to the AAR directory]'
}
}
Add Dependencies
To use the Meridian SDK classes in your project, add the implementation information for the dependencies to the build.gradle file. These are the meridian-x.y.z.aar file and two required external dependencies.
To find the project’s current dependencies, look in build.gradle in the MeridianSamples directory.
In the build.gradle file inside dependencies { }, insert implementation for the meridian-x.y.z.aar file and the three required external dependencies:
dependencies {
implementation 'com.arubanetworks.meridian:meridian:x.y.z@aar'
// Google Support Libraries
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.4.0'
// Required for GPS on newer Android devices.
implementation 'com.google.android.gms:play-services-location:18.0.0'
implementation 'com.google.android.material:material:1.7.0'
// The SDK also has these external dependencies that you'll need to include:
implementation 'com.android.volley:volley:1.2.1'
implementation 'com.squareup:otto:1.3.8'
implementation 'org.conscrypt:conscrypt-android:2.5.2'
implementation 'org.greenrobot:eventbus:3.3.1'
implementation 'com.lemmingapex.trilateration:trilateration:1.0.2'
}
Import Packages
When this is done, you’ll be able to import the com.arubanetworks.meridian packages to your project and use Meridian classes in your source files.
The SDK’s MeridianSamples/app project folder has an example of what the finished build.gradle file should look like.
Add Permissions
To enable the Meridian SDK’s location-awareness features, add the following permissions to your project’s AndroidManifest.xml file:
<!-- For using GPS and Location in general -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- For using location derived from bluetooth beacons -->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!-- For using location derived from bluetooth beacons on Android 12 and later -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN/>
To enable Meridian SDK's location-aware features (e.g. location sharing) in the background, add the following permission to your project’s AndroidManifest.xml file and request the permission from the user as required for the Android version:
<!-- For using bluetooth in the background -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
Configure the SDK
Before you can use the features of the Meridian SDK, you’ll need to create an instance of MeridianConfig. This will configure the SDK.
Meridian uses token-based authentication. In order for your Meridian-powered app to communicate with the Editor, you’ll need to specify a Meridian token when initializing the SDK.
Put the following line in the onCreate method of your Application class or main activity.
// Configure Meridian
Meridian.configure(this, YOUR_EDITOR_TOKEN);
Using Editor Keys
Use instances of EditorKey to specify apps, maps, and placemarks that have been created in the Meridian Editor. Most of the Meridian SDK classes require a valid key during initialization.
// Create a key representing your app in the Meridian Editor.
EditorKey appKey = new EditorKey("5809862863224832");
// Create a key representing a map in the Meridian Editor.
EditorKey mapKey = EditorKey.forMap("5668600916475904", appKey.getId());
// Create a key representing a placemark.
EditorKey placemarkKey = EditorKey.forPlacemark("5668600916475904_5709068098338816", mapKey);
When you create an EditorKey to represent a map, the app identifier you provide becomes the parent of the map key. Likewise, when you create a placemarkKey, the map you specify becomes the parent of that placemark.
EditorKey placemarkKey = EditorKey.forPlacemark("375634485771", someMapKey);
EditorKey mapKey = placemarkKey.getParent();
Log.i(TAG, "My map ID: " + mapKey.getId());
EditorKey appKey = mapKey.getParent();
Log.i(TAG, "My app ID: " + appKey.getId());
Display Maps
You can use MapFragment to provide a self-contained interface for maps and directions. Simply initialize the fragment with a valid EditorKey:
// Create a key representing your app in the Meridian Editor.
EditorKey appKey = new EditorKey("5809862863224832");
// Create a key representing a map in the Meridian Editor.
EditorKey mapKey = EditorKey.forMap("5668600916475904", appKey.getId());
MapFragment mapFragment = new MapFragment.Builder().setMapKey(mapKey).build();
MapFragment hosts a MapView and implements the MapView.MapViewListener interface, handling the basic tasks delegated by MapView.
You can also use MapView directly in your own activity or fragment, optionally implementing methods defined by the MapView.MapViewListener interface so that your activity can respond to MapView events.
Call the setMapKey() method to choose the map to display.
NOTE: We strongly advise using MapFragment whenever possible. If you decide to use a MapView independently, you must always pass your activity’s pause/resume/destroy events to the MapView to ensure resources are managed properly.
// Using pause/resume/destroy events with a MapView in your activity
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EditorKey appKey = new EditorKey("5809862863224832");
mapView = new MapView(this);
mapView.setAppKey(appKey);
// If you want to handle MapView events
mapView.setListener(this);
// Set the map to load
mapView.setMapKey(EditorKey.forMap("5668600916475904", appKey.getId()));
// Assume myLayout is this activity's root view
myLayout.addView(mapView);
}
@Override
protected void onResume() {
super.onResume();
// MapView needs to know when its host activity is resumed
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
// MapView needs to know when its host activity is paused
mapView.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
// MapView needs to know when its host activity is destroyed
mapView.onDestroy();
}
Load Directions
MapFragment handles loading and presenting directions in response to user interaction. When you create the map fragment, include the pendingDestination parameter to present directions to a placemark when direction-finding resumes.
If you’re using MapView directly in your activity, you’ll need to load the directions manually with the Directions class.
To do so, first ensure that your activity implements the Directions.DirectionsRequestListener interface so that it can handle the results of the directions request. Use a Directions.Builder instance to configure the details of the desired route. To do this, specify the start and end points for the route using instances of DirectionsSource and DirectionsDestination, which contain information about a point or placemark on a map.
Next, call build() to create the Directions object from the builder.
Finally, call calculate() to start the directions process.
The Directions object will call onDirectionsComplete() after successful completion or onDirectionsError() if something went wrong.
In the following code example, MeridianLocation is the source of the directions.
A new route is calculated when the user’s blue dot location is approximately 10 meters from the route. To customize the reroute distance, you can use
Meridian.getShared().setRerouteDistance().
Related to this, you can also use
Meridian.getShared().setRouteSnapDistance()to configure the distance from the route at which the user's blue dot will be "snapped" to the determined route. This value is 5 meters by default.
// In your Activity
private static final EditorKey appKey = new EditorKey("YOUR_APP_KEY");
private void getDirections(MeridianLocation source, Placemark destination) {
Directions.Builder directionsBuilder = new Directions.Builder()
.setAppKey(appKey)
.setSource(DirectionsSource.forMapPoint(source.getMap(), source.getPoint()))
.setDestination(DirectionsDestination.forPlacemarkKey(destination.getKey()))
.setTransportType(TransportType.WALKING)
.setListener(this);
Directions directions = directionsBuilder.build();
directions.calculate();
}
@Override
public void onDirectionsComplete(DirectionsResponse response) {
if (response.getRoutes().size() 0) {
// Normally only one route will be returned
Route route = response.getRoutes().get(0);
// If we have a MapView we can tell it to display this route
myMapView.setRoute(route);
}
}
If a current location isn’t available, you may want to prompt the user to choose a starting location with SearchActivity.
In the example, SearchActivity and startActivityForResult() will prompt the user to choose a starting placemark.
// In your Activity
private Directions.Builder directionsBuilder;
private static final EditorKey appKey = new EditorKey("5085468668573440");
public static final int PLACEMARK_PICKER_CODE = 42;
private void getDirections(Placemark placemark) {
directionsBuilder = new Directions.Builder()
.setContext(this)
.setAppKey(appKey)
.setDestination(DirectionsDestination.forPlacemark(placemark))
.setTransportType(TransportType.WALKING)
.setListener(this);
// start a search Activity to get the starting point for the route
startActivityForResult(SearchActivity.createIntent(this, appKey), PLACEMARK_PICKER_CODE);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// Now that the user picked a placemark to start from, we can calculate the route
if (requestCode == PLACEMARK_PICKER_CODE) {
if (resultCode == Activity.RESULT_OK) {
LocalSearchResult result = (LocalSearchResult) data.getSerializableExtra(SearchActivity.SEARCH_RESULT_KEY);
Placemark source = result.getPlacemark();
directionsBuilder.setSource(DirectionsSource.forPlacemark(source));
directions = directionsBuilder.build();
directions.calculate();
}
}
}
Get a User’s Location
A user’s most recent location can be retrieved with the LocationRequest class. This request is asynchronous.
private LocationRequest request = null;
private static final EditorKey appKey = new EditorKey("5809862863224832");
@Override
public void onResume() {
super.onResume();
request = LocationRequest.requestCurrentLocation(getActivity(), appKey, new LocationRequest.LocationRequestListener() {
@Override
public void onResult(MeridianLocation location) {
// Update UI with new Location
}
@Override
public void onError(LocationRequest.ErrorType location) {
// Notify user that there was an error retrieving the location
}
});
}
@Override
public void onPause() {
if (request != null && request.isRunning()) {
request.cancel();
request = null;
}
super.onPause();
}
Get Continuous Updates About a User’s Location
MeridianLocationManager determines the user’s location by gathering all available location data for your Meridian-powered app. Implement the MeridianLocationManager.LocationUpdateListener interface to get callbacks as new locations are gathered.
// In an Activity that implements the LocationUpdateListener interface
private static final EditorKey appKey = new EditorKey("5809862863224832");
private MeridianLocationManager locationHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
locationHelper = new MeridianLocationManager(this, appKey, this);
// Build out the UI ...
}
@Override
protected void onStart() {
locationHelper.startListeningForLocation();
super.onStart();
}
@Override
protected void onStop() {
locationHelper.stopListeningForLocation();
super.onStop();
}
@Override
public void onLocationUpdate(MeridianLocation location) {
// Update the UI with the new location
}
@Override
public void onLocationError(Throwable tr) {
// Update the UI to inform the user that their location could not be determined.
}
Location Sharing
Location sharing lets users share their location with each other.
Prerequisites
Location Sharing requires a blue dot subscription.
If you haven’t already done so, you’ll need to generate a valid token in the Editor. To generate one, in the sidebar menu click Permissions, and then click Application Tokens. Click Add Application + to generate a token for your app. You can name it anything.
When configuring the Meridian SDK, set the application token you generated in the Editor:
LocationSharing.init("kd84hf83ck93k39dyi3nxo3mf94");
For best results, call init from your Application class.
LocationSharing
LocationSharing is the main access point to the Location Sharing API. Use the User, Friend, Invite, and Location classes to get the Location Sharing data.
Create Accounts
// Creates a location sharing user. All users require a first name. Last name is optional.
User sampleUser = new User();
sampleUser.setFirstName("Sample User");
LocationSharing.shared().createUser(sampleUser, new LocationSharing.Callback
Start Location Sharing
LocationSharing.shared().startPostingLocationUpdates(applicationContext);
Stop Location Sharing
LocationSharing.shared().stopPostingLocationUpdates(applicationContext);
Check Location Sharing Status
LocationSharing.shared().isUploadingServiceRunning()
// example: button that performs start and stop sharing location
if (LocationSharing.shared().isUploadingServiceRunning()) {
LocationSharing.shared().stopPostingLocationUpdates(applicationContext);
} else {
LocationSharing.shared().startPostingLocationUpdates(applicationContext);
}
Start and Stop Location Sharing Listener
LocationSharing.shared().addListener(new LocationSharing.Listener() {
@Override
public void onPostingLocationUpdatesStarted() {
// ...
}
@Override
public void onFriendsUpdated(List
Create an Invite
Invitations expire after 7 days.
LocationSharing.shared().createInvite(new LocationSharing.Callback
Get the Current Friend List
LocationSharing.shared().getFriends(new LocationSharing.Callback
createInvite and getFriends
LocationSharing keeps a copy of the current user, for use by calls like createInvite and getFriends. The implementor is responsible for storing the current user and setting it to the LocationSharing object.
When an account is created, the new user is automatically set to the current user.
Store the New User
After creating the new user, store it:
LocationSharing.shared().createUser(newUser, new LocationSharing.Callback
Set the Current User
If a user restarts the app, the current user needs to be set again. This is equivalent to a login operation.
LocationSharing.shared().setCurrentUser(OurOwnStorage.retrieveLocationSharingUser());
Using Local Search
You can use the LocalSearch classes to find points of interest near a user’s location. You’ll usually use this in conjunction with MeridianLocationManager so that you can provide a location and nearby placemarks.
For best performance, limit local search results to 20 or less.
// This Activity implements the LocalSearch.LocalSearchListener interface
private void findNearbyCafe() {
LocalSearch localSearch = new LocalSearch.Builder()
.setQuery("Cafe")
.setApp(appKey)
.setLocation(locationManager.getLocation())
.setListener(this)
.setLimit(20)
.build();
localSearch.start();
}
@Override
public void onSearchComplete(LocalSearchResponse response) {
for (LocalSearchResult result : response.getResults()) {
Log.i(TAG, String.format("%s is %f seconds away", result.getPlacemark().name, result.time / 1000));
}
}
@Override
public void onSearchError(Throwable tr) {
Log.e(TAG, "Search error", tr);
}
Asset Tracking
Asset Tracking is a feature that uses BLE Tags hardware to track valuable locations on a map. You can use the SDK to get Tag location updates and render Tag locations on a map.
Get Tag Updates
Before you can get Tag updates, you’ll need to create an instance of Asset Tracking’s main class, TagStream.
First, create your own instance of TagStream using its Builder:
tagStream = new TagStream.Builder()
.setMapKey(yourMapKeyHere)
.setListener(this)
.build();
With the TagStream instance created, call the following method to get updates on your tagged assets:
tagStream.startUpdatingTags();
To stop getting updates:
tagStream.stopUpdatingTags();
The TagStream builder class takes a listener that will be used to pass information about Tags to your code. The listener must implement two methods:
void onTagsUpdated(List
The first method will be called when we get information about new Tags or when existing Tags are updated. This list of Tags will contain all Tags.
The second method will get called when a Tag is removed. This list of Tags will contain the deleted Tags.
To dispose of the TagStream:
tagStream.dispose();
Render Tags on the Map
Use the marker TagMarker to render your Tags on a map. It will show a generic asset icon. Create a marker in the following way:
tagMarker = new TagMarker(getContext(), tag);
The marker gets the name and position of the marker from the tag object. At that point, you can add it to your map.
You can find working examples of this in the Samples app with TagsFragment and SingleTagFrament.
Comments
0 comments
Please sign in to leave a comment.