Install SDK on Android

Add Hypertrack SDK

Add following lines to your applications build.gradle:

// Import the SDK within your repositories block
repositories {
maven {
name 'hypertrack'
url 'https://s3-us-west-2.amazonaws.com/m2.hypertrack.com/'
}
...
}
//Add HyperTrack as a dependency
dependencies {
implementation 'com.hypertrack:hypertrack:4.2.0'
...
}

Set up silent push notifications

Set up silent push notifications to manage on-device tracking using HyperTrack cloud APIs from your server. This requires Firebase push notification. If you do not yet have push notifications enabled, please proceed to setup Firebase Cloud Messaging.

Next step is to specify HyperTrackMessagingService as push messages receiver by adding the following snippet to your app's Android manifest:

...
<service android:name="com.hypertrack.sdk.HyperTrackMessagingService" android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>

If you already use Firebase push notifications you can extend HyperTrackMessagingService instead of Firebase, or declare two receivers side by side, if you wish (don't forget to call super.onNewToken and super.onMessageReceived in that case).

The last step is to add your Firebase API key to your HyperTrack Dashboard Setup Page under Server to Device communication section.

note

Push notifications have delays so if you're looking for more instant channel you can use syncDeviceSettings sdk method to speed up command propagation.

Initialize SDK

Obtain an SDK instance, when you wish to use SDK, by passing your publishable key from the Setup page.

val sdkInstance = HyperTrack.getInstance(this, "your-publishable-key-here")

Also make sure you've requested permissions somewhere in your app. HyperTrack accesses location and activity data, so exact set of permissions depends on an Android version. You may use HyperTrack.requestPermissionsIfNecessary() convenience method to request permissions and make SDK integration simpler.

Identify your devices

HyperTrack uses string device identifiers that could be obtained from the SDK instance

val deviceId = sdkInstance.deviceID

Make sure you've saved this device identifier as it is required when calling HyperTrack Devices and Trips APIs.

Tracking your device

Once you integrated the SDK into your app, you can start tracking your device.

In order to test and verify your SDK integration, you can use either PlayGround in the Dashboard or call Devices and Trips APIs from your server.

Dashboard

Once your app is running, go to the Dashboard where you can see a list of all your devices and their live location with ongoing activity on the map.

Advanced integration

Add SDK state listener to catch events.

You can subscribe to SDK status changes addTrackingListener and handle them in the appropriate methods onError(TrackingError) onTrackingStart() onTrackingStop()

Customize foreground service notification

HyperTrack tracking runs as a separate foreground service, so when it is running, your users will see a persistent notification. By default, it displays your app icon with text {app name} is running but you can customize it anytime after initialization by calling:

sdkInstance.setTrackingNotificationConfig(
ServiceNotificationConfig.Builder()
.setContentTitle("Tap to stop tracking")
.build()
)

Check out other configurable properties in ServiceNotificationConfig reference

Create trip marker

Use this optional method if you want to associate data with specific place in your trip. E.g. user marking a task as done, user tapping a button to share location, user accepting an assigned job, device entering a geofence, etc.

sdkInstance.addTripMarker(mapOf(
"item" to "Martin D-18",
"price" to 7.75,
"previousOwners" to emptyList<String>()
))

Look into documentation for more details.

You are all set

You can now run the app and start using HyperTrack. You can see your devices on the dashboard.

SDK integration examples

To learn more about SDK integration examples, you may visit these resources:

Frequently Asked Questions


What API levels (Android versions) are supported?

Currently we do support all of the Android versions starting from API 19 (Android 4.4 Kit Kat).


Why do I have NoClassDefFoundError?

I've added SDK and my app started failing with message like:

Fatal Exception: java.lang.NoClassDefFoundError

This takes place because on Android API level 19 and below you cannot have more than 65536 methods in your app (including methods in libraries).

Please check this StackOverflow answer for solutions.


Why do I have dependencies conflicts?
SDK dependencies graph looks like below:

+--- com.android.volley:volley:1.1.1
+--- com.google.code.gson:gson:2.8.6
+--- org.greenrobot:eventbus:3.1.1
+--- com.parse.bolts:bolts-tasks:1.4.0
+--- net.grandcentrix.tray:tray:0.12.0
+--- com.google.android.gms:play-services-location:15.0.1
| +--- com.google.android.gms:play-services-base:[15.0.1,16.0.0) -> 15.0.1
| | +--- com.google.android.gms:play-services-basement:[15.0.1] -> 15.0.1
| | | \--- com.android.support:support-v4:26.1.0
| | | +--- com.android.support:support-compat:26.1.0
| | | | +--- com.android.support:support-annotations:26.1.0
| | | | \--- android.arch.lifecycle:runtime:1.0.0
| | | | +--- android.arch.lifecycle:common:1.0.0
| | | | \--- android.arch.core:common:1.0.0
| | | +--- com.android.support:support-media-compat:26.1.0
| | | | +--- com.android.support:support-annotations:26.1.0
| | | | \--- com.android.support:support-compat:26.1.0 (*)
| | | +--- com.android.support:support-core-utils:26.1.0
| | | | +--- com.android.support:support-annotations:26.1.0
| | | | \--- com.android.support:support-compat:26.1.0 (*)
| | | +--- com.android.support:support-core-ui:26.1.0
| | | | +--- com.android.support:support-annotations:26.1.0
| | | | \--- com.android.support:support-compat:26.1.0 (*)
| | | \--- com.android.support:support-fragment:26.1.0
| | | +--- com.android.support:support-compat:26.1.0 (*)
| | | +--- com.android.support:support-core-ui:26.1.0 (*)
| | | \--- com.android.support:support-core-utils:26.1.0 (*)
| | \--- com.google.android.gms:play-services-tasks:[15.0.1] -> 15.0.1
| | \--- com.google.android.gms:play-services-basement:[15.0.1] -> 15.0.1 (*)
| +--- com.google.android.gms:play-services-basement:[15.0.1,16.0.0) -> 15.0.1 (*)
| +--- com.google.android.gms:play-services-places-placereport:[15.0.1,16.0.0) -> 15.0.1
| | \--- com.google.android.gms:play-services-basement:[15.0.1,16.0.0) -> 15.0.1 (*)
| \--- com.google.android.gms:play-services-tasks:[15.0.1,16.0.0) -> 15.0.1 (*)
+--- com.android.support:support-annotations:26.1.0
+--- com.google.firebase:firebase-messaging:17.1.0
| +--- com.google.android.gms:play-services-basement:15.0.1 (*)
| +--- com.google.android.gms:play-services-tasks:15.0.1 (*)
| +--- com.google.firebase:firebase-common:16.0.0
| | +--- com.google.android.gms:play-services-basement:15.0.1 (*)
| | \--- com.google.android.gms:play-services-tasks:15.0.1 (*)
| +--- com.google.firebase:firebase-iid:[16.2.0] -> 16.2.0
| | +--- com.google.android.gms:play-services-basement:15.0.1 (*)
| | +--- com.google.android.gms:play-services-stats:15.0.1
| | | \--- com.google.android.gms:play-services-basement:[15.0.1] -> 15.0.1 (*)
| | +--- com.google.android.gms:play-services-tasks:15.0.1 (*)
| | +--- com.google.firebase:firebase-common:16.0.0 (*)
| | \--- com.google.firebase:firebase-iid-interop:16.0.0
| | +--- com.google.android.gms:play-services-base:15.0.1 (*)
| | \--- com.google.android.gms:play-services-basement:15.0.1 (*)
| \--- com.google.firebase:firebase-measurement-connector:16.0.0
| \--- com.google.android.gms:play-services-basement:15.0.1 (*)

Common problem here is depending on different versions of com.android.support library components. You can explicitly specify required version by adding it as a dependency in your app's build.gradle, e.g.:

implementation `com.android.support:support-v4:28.0.0`

and explicitly force SDK pick app's dependencies

implementation("com.hypertrack:hypertrack:4.2.0") {transitive = false}

That will take precedence over SDK version and you'll have one version of support library on your classpath.


Why do I have persistent notification on my app?
HyperTrack SDK by default runs as a foreground service. This is to ensure that the location tracking works reliably even when your app is minimized.

A foreground service is a service that the user is actively aware of and isn't a candidate for the system to kill when it is low on memory. Android mandates that a foreground service provides a persistent notification in the status bar. This means that the notification cannot be dismissed by the user.

persistent-notification


How do I handle custom ROMs?
Smartphones are getting more and more powerful, but the battery capacity is lagging behind. Device manufactures are always trying to squeeze some battery saving features into the firmware with each new Android release. Manufactures like Xiaomi, Huawei and OnePlus have their own battery savers that kills the services running in the background.

To avoid OS killing the service, users of your app need to override the automatic battery management and set it manual.

To inform your users and direct them to the right setting page, you may add the following code in your app. This would intent out your user to the right settings page on the device.

try {
Intent intent = new Intent();
String manufacturer = android.os.Build.MANUFACTURER;
if ("xiaomi".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity"));
}
else if ("oppo".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity"));
}
else if ("vivo".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity"));
}
List<ResolveInfo> list = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (list.size() > 0) {
context.startActivity(intent);
}
}
catch (Exception e) {
Crashlytics.logException(e);
}

You may also try out open source libraries like AutoStarter.

Some manufacturers don't allow to whitelist apps programmatically.

In that case the only way to achieve service reliability is manual setup. E.g. for Oxygen OS (OnePlus) you need to select Lock menu item from app options button in Recent Apps view:

one-plus-example


Why does HyperTrack notification show even after my app is terminated?

The HyperTrack service runs as a separate component and it is still running when the app that started it is terminated. That is why you can observe that notification. When you tracking is stopped, the notification goes away.


How does tracking work in Doze mode?

Doze mode requires device to be stationary, so before OS starts imposing power management restrictions, exact device location is obtained. When device starts moving, Android leaves Doze mode and works regularly, so no special handling of Doze mode required with respect to location tracking.


What is AAPT: error: attribute android:foregroundServiceType not found?

If build fails with error like AAPT: error: attribute android:foregroundServiceType not found that means that you're targeting your app for Android P or earlier.


Starting from Android 10 Google imposes additional restrictions on services, that access location data while phone screen is turned off. Possible workaround here is to remove declared service property by adding following element to your app's manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hypertrack.quickstart"
xmlns:tools="http://schemas.android.com/tools">
...
<application>
...
<service android:name="com.hypertrack.sdk.service.HyperTrackSDKService"
tools:remove="android:foregroundServiceType" />

Although you'll be able to avoid targeting API 29, but tracking service won't work properly on Android Q devices with screen been turned off or locked.


Why doesn't setting device metadata and name work in SDK?

Devices API or in PlayGround take precedence over SDK methods in setting device name and metadata. If you used either Devices API or PlayGround, these SDK methods setDeviceMetadata and setDeviceName will not modify device metadata and name.