Manage Tracking Permissions
Introduction
HyperTrack powers location-based logistics using app location and activity with permissions from app users. To protect user privacy, it is imperative that location be used during working hours. Ensuring that location is used only during business hours results in better compliance from app users and improves tracking rate for the mobile fleet.
Tracking rate is the percentage of duration tracked relative to the time that the business intended to track. In cases of outages in tracking, HyperTrack provides granular and actionable information about outage reasons.
HyperTrack recommends the use of REST APIs to track work done by fleet during working hours. Tracking may be controlled through Devices or Trips APIs. Tracking may optionally be controlled through the app as well, so users have additional privacy controls.
Driver permissions
HyperTrack requires both location and motion permissions to generate accurate ground truth data from app user movement.
Motion permission is required for the following reasons:
- It allows to automatically and accurately detect activities such as stops, drives, and walks. Accurate activity detection is crucial for accurate app user history timeline which in turn is used as ground truth;
- This permission allows to saves battery life and adapts location collection and delivery based on the app user's current activity;
- Achieves faster time to get first location once tracking starts;
- It allows to provide accurate reporting for steps counts, which are also helpful in activity detection.
Configure silent push notifications
HyperTrack uses silent push notifications to communicate with the device and wake it up if for some reason the app was stopped by the OS.
Setup and manage app users
Tracking business assets on the move requires identification of your app users and their physical devices. To achieve this goal, HyperTrack uses a unique, randomly generated device_id
in order to track app user's physical device.
Location data generated by your app user is sent to HyperTrack platform and stored together with the unique device_id
which identifies your app user.
With this unique device_id
, HyperTrack gives you the power of its APIs to manage tracking of your business assets.
Once you integrated HyperTrack SDK into your app, you can use HyperTrack REST APIs with device_id
to start and stop tracking of your app user's device from your server, track trips to fulfill orders, track arrivals and exits at geofences, and add geotags to the timeline when users perform actions in the app.
Understand Device ID
HyperTrack SDKs use random generated universally unique ids (UUIDs) that are stored in the device for future use once your SDK instance is initialized.
This device_id
is different for each physical device, is different for different apps on the same device, and is typically not persistent across uninstalls or re-installs of your app to ensure user's privacy.
Get and store Device ID
Once you integrate HyperTrack SDK in your app, you may get device_id
from your SDK instance.
Check the instructions for your platform:
Get device ID
iOS / Android / React Native / Flutter / Cordova / Ionic Capacitor
Once you obtain a device ID you should store this device identifier together with your app user identity in your own data store for future usage with HyperTrack API. You will need to map your own app user identity to HyperTrack device id to manage tracking of your app user's devices.
When you dispatch someone for a gig job, tracking a mobile worker via your app, creating an order for an on-demand delivery, or tracking a driver via a logistics app, you need to use HyperTrack device_id
to track location of physical devices used by your app users.
Set device name and metadata
While HyperTrack uses a device id to track your app with HyperTrack SDK integration, convenience methods are provided to help set device name and metadata as an option to help display, sort, manage, and organize large fleets of devices in your account.
While HyperTrack device id is a unique identifier for all of your app user's devices in your HyperTrack account, HyperTrack APIs do not enforce uniqueness constraints on name and metadata.
See an example of device name and metadata that are set for three devices with device_id
such as 7BEEABA4-4890-4AFA-916A-AA80FE659C5A
and D5FCE235-4650-476F-9871-59AC7F9BE48B
.
{ "device_id": "D5FCE235-4650-476F-9871-59AC7F9BE48B",
"name": "Kishan E",
"metadata": {
"vehicle_type": "scooter",
"group_id": 1
}
},
{ "device_id": "7BEEABA4-4890-4AFA-916A-AA80FE659C5A",
"name": "Alex K",
"metadata": {
"vehicle_type": "bike",
"group_id": 2
}
}
Device name is used to conveniently show your app user's device, filter, and search for it in HypeTrack dashboard.
Your device metadata can be any valid JSON string and be used for filtering purposes to help identify a group of devices that share common or distinct properties of your choosing. For example, please review how device metadata can be used to create hierarchical embedded views.
Once you set a name for your physical device, it will be used to display your app user's device in your account HyperTrack dashboard.
If you do not set a name for your app user's device, alternatively, its device_id
will be shown. As mentioned earlier, there is no requirement for device names to be unique. For example, if your app has a name for an app user in your user management system, you may as well use it to set the device name as well for the HyperTrack device_id
to create a consistent user experience for your customers.
As a developer, you have an option of being able to set and change device name and metadata via the SDK in your mobile app as well as via Devices API from your app server backend.
Set using Playground
To get a hands-on experience of setting and changing device name and metadata without writing a single line of code, please visit HyperTrack Playground. Once you select your app user's device in the list inside Playground, you will be presented with device name and metadata entry forms. As you change them, please observe how your changes get reflected in HyperTrack Dashboard.
Set using SDK
When you develop your app with HyperTrack location tracking, you may already have a requirement or preference to set your app user's device name and/or metadata once the app user started and logged into your app.
In this case, inside your mobile app, you may be able to set device name and metadata as shown in tutorial for your platform:
Set name and metadata
iOS / Android / React Native / Flutter / Cordova / Ionic Capacitor
Set using Devices API
In addition to SDK methods above, HyperTrack provides you Devices API where you may be able to set device name and/or metadata.
You may need this when you have a business workflow that requires updating your app user's device name, or a change for your app user which may have to be reflected in your metadata.
For example, you want to restrict viewing of an operations team to their manager which, in turn, can be done by specifying an attribute to which your app users belong to, such as group_id
from the example above.
Once you have used Devices API to set device name or device metadata, you can no longer use SDK methods to change them.
# Set your app user device name
curl -X PATCH \
-u {AccountId}:{SecretKey} \
https://v3.api.hypertrack.com/devices/D5FCE235-4650-476F-9871-59AC7F9BE48B \
-H 'Content-Type: application/json' \
-d '{"name":"Kishan E"}'
# Set your app user device metadata
curl -X PATCH \
-u {AccountId}:{SecretKey} \
https://v3.api.hypertrack.com/devices/D5FCE235-4650-476F-9871-59AC7F9BE48B \
-H 'Content-Type: application/json' \
-d '{ "metadata": {"vehicle_type":"scooter","group_id":1} }'
// Use Node.js helper library to set device metadata
const accountId = "your_account_id"
const secretKey = "your_secret_key"
// Instantiate Node.js helper library instance
const hypertrack = require('hypertrack')(accountId, secretKey)
const deviceName = "Kishan E"
// Set name for the device
hypertrack.devices.changeName(deviceId, deviceName).then(() => {
// Name changed
}).catch(error => {
// Error handling
})
const metadata = {"vehicle_type": "scooter", group_id":1}
hypertrack.devices.patchMetadata(deviceId, metadata).then(() => {
// Metadata set
}).catch(error => {
// Error handling
})
# Use Python helper library to set device name and metadata
from hypertrack.rest import Client
from hypertrack.exceptions import HyperTrackException
account_id = "your account id"
secret_key = "your secret key"
device_id = "D5FCE235-4650-476F-9871-59AC7F9BE48B"
hypertrack = Client(account_id, secret_key})
hypertrack.devices.change_name({device_id}, "Kishan E")
metadata = {"vehicle_type": "scooter", group_id":1}
hypertrack.devices.patch_metadata(device_id, metadata)
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n "
+ "\"name\": \"Kishan E\",\n "
+ " \"metadata\": {\n"
+ " \"vehicle_type\": \"scooter\"\n"
+ " \"group_id\": 1\n"
+ " }\n"
+ "}");
String authString = "Basic " +
Base64.getEncoder().encodeToString(
String.format("%s:%s", "account_id_value","secret_key_value")
.getBytes()
);
Request request = new Request.Builder()
.url("https://v3.api.hypertrack.com/devices/{device_id}")
.patch(body)
.addHeader("Authorization", authString)
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
<?php
$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/devices/{device_id}');
$request->setMethod(HTTP_METH_PATCH);
$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');
$request->setHeaders(array(
'Authorization' => $basicAuth
));
$request->setBody('{
"name": "Kishan E",
"metadata": {
"vehicle_type": "scooter",
"group_id": 1
}
}');
try {
$response = $request->send();
echo $response->getBody();
} catch (HttpException $ex) {
echo $ex;
}
?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'
url = URI("https://v3.api.hypertrack.com/devices/{device_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp
request.body = {
"name": "Kishan E",
"metadata": {
"vehicle_type": "scooter",
"group_id": 1
}
}.to_json
response = http.request(request)
puts response.read_body
Understand app updates, uninstalls and reinstalls
As your user performs an app update with your next release, HyperTrack device_id
does not change. HyperTrack keeps track of your app user's device id in this case, as well as updating relevant fields inside device info returned to you by Devices API GET call.
Once your app user uninstalls your app, mobile OS requires that all data associated with your app are removed to protect user's privacy. If your app user's device was actively tracking at the time, HyperTrack will detect and mark it's tracking status as disconnected.
In case if your app user uninstalls and subsequently installs your app again, the new installation will result in creation of a new device_id
even though it's the same physical device that belongs to your app user. Depending on your app workflow, if you expect a single physical device for each user, you may take advantage of either device name and/or metadata to determine a new installation and update your data store accordingly to keep track of new device_id
in your system.
Manage app user turnover
Sometimes you may have a case where an app user leaves your organization or you want to permanently stop this app user from being tracked.
In order to remove the physical device associated with this app user, you may use delete API method to delete this device and stop tracking it permanently. At the same time, after deleting this device_id
, HyperTrack will retain and provide tracking history of the device in dashboard views as well via API.
The device will stop tracking further and you will be unable to start tracking the same device_id
again.
Once a new monthly billing cycle begins, you will not be charged for this device moving forward. Devices are billable only if they were active for any duration during the month.
Please see code snippets explaining device deletion below.
curl -X DELETE \
-u {AccountId}:{SecretKey} \
https://v3.api.hypertrack.com/devices/{device_id}
// Instantiate Node.js helper library instance
const hypertrack = require("hypertrack")(accountId, secretKey);
hypertrack.devices
.delete(deviceId)
.then(() => {
// Device deleted
})
.catch((error) => {
// Error handling
});
py
from hypertrack.rest import Client
from hypertrack.exceptions import HyperTrackException
hypertrack = Client({AccountId}, {SecretKey})
hypertrack.devices.delete({deviceId})
OkHttpClient client = new OkHttpClient();
String authString = "Basic " +
Base64.getEncoder().encodeToString(
String.format("%s:%s", "{AccountId}","{SecretKey}")
.getBytes()
);
Request request = new Request.Builder()
.url("https://v3.api.hypertrack.com/devices/{device_id}")
.delete(null)
.addHeader("Authorization", authString)
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
<?php
$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/devices/{device_id}');
$request->setMethod(HTTP_METH_DELETE);
$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');
$request->setHeaders(array(
'Authorization' => $basicAuth
));
try {
$response = $request->send();
echo $response->getBody();
} catch (HttpException $ex) {
echo $ex;
}
?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'
url = URI("https://v3.api.hypertrack.com/devices/{device_id}/start")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp
response = http.request(request)
puts response.read_body
To get a deleted device back into your account and start tracking, please use Devices Undelete API documentation.
Handle outages and inactive devices
HyperTrack devices can be in one of the following states:
active
: Device is tracking.activity
value shows the current activity (drive
,walk
orstop
)inactive
: Device is not tracking with known reasonsdisconnected
: HyperTrack lost connectivity with this device
When device is in the inactive state HyperTrack APIs, webhooks, views, scoreboards and insights provide a type and a code to uniquely identify the outage.
List of outage codes
Here is the list of all possible outage types and their codes.
Location permission denied
HyperTrack SDK requires precise location permissions for location tracking.
Error Code | Description |
---|---|
OL1 | Android Permissions either were explicitly denied by the user or were never asked before tracking event started (in which case it's an integration error). Change location permission to "Allow" in App Info > Permissions > Location iOS User explicitly denied permissions in response to a system prompt or in Settings > Your App Name > Location. Change location permission to "Always" in Settings > Your App Name > Location |
OL2 | Android To start tracking remotely (REST API or Trips) the app needs background permissions on Android 11+. This can be a sign of an integration error if the app doesn't ask the user background permissions. Change location permission to "Allow all the time" in App Info > Permissions > Location iOS To start tracking remotely (REST API or Trips) the app needs "Always" permissions. This can be a sign of an integration error if the app only asks for "When In Use" permissions. Change location permission to "Always" in Settings > Your App Name > Location |
OL3 | The app asked for Always permissions without first asking for When In Use permissions. This puts an app in Provisional Always authorization where OS doesn't return a location when the app is in background (not showing on the screen). The OS is waiting to present the user with a second prompt asking to choose "Always" or "When In Use" before returning location data to the SDK. In this instance the user needs to go to Settings > App Name > Location and switch permissions to When In Use. The app should then switch to asking When In Use permissions first and then Always permissions right after user granted When In Use to avoid an outage in location data. Change location permission to "Always" in Settings > Your App Name > Location |
OL4 | iOS The app didn't ask for location permissions or they were reset. Possible reasons: - The app didn't ask for permissions before starting tracking which is an integration error. Please make sure that your app asks for location permissions before there is a possibility that the user can be tracked. - The user chose Allow Once in the previous app session's location permission dialog. Every time a user chooses Allow Once, the OS resets the permissions to not granted state after the app finishes execution. - The user executed a premissions reset in Settings > General > Reset > Reset Location & Privacy. - The user changed permissions to Ask Next Time in Settings > App Name > Location before launching the app. On iOS 11 or iOS 12 open the app and allow location access choosing "Always" On iOS 13 and later open the app and allow location access choosing "Allow While in Use" then choose "Change to Always Allow" on the next step or go to Settings > Your App Name > Location and choose "Always" |
OL5 | iOS Location permissions were restricted: - By the user in Settings > Screen Time > Content & Privacy Restrictions > Location Services. - By administrator if the phone is part of an enterprise account. - Using parental controls. Remove location services restriction in Settings > Screen Time > Content & Privacy Restrictions > Location Services |
OL6 | User didn't grant precise location permissions or downgraded permissions to imprecise. Android Turn on Use precise location in App Info > Permissions > Location iOS Turn on Precise Location in Settings > Your App Name > Location |
:::note
OL6 error code will be available in the future Android SDK release.
:::
Location service disabled
Error Code | Description |
---|---|
OS1 | Location services disabled globally in the phone. Android Turn location services on in Settings > Location > Use location iOS Turn location services on in Settings > Privacy > Location Services |
OS3 | When the battery saver is turned on and the screen is locked, Android OS automatically disables location services. User needs to disable the battery saver when actively tracking. Android Turn off Battery Saver in Settings > Battery > Battery saver |
OS4 | Android Location services are unavailable on this device |
Activity permission denied
Error Code | Description |
---|---|
OA1 | Android Permissions either were explicitly denied by the user or were never asked before tracking event occured (in which case it's an integration error) Change physical activity to "Allow..." in App Info > Permissions > Physical activity iOS User explicitly denied permissions in response to system prompt or in Settings > App Name > Motion & Fitness. Enable activity permission in Settings > App Name > Motion & Fitness |
OA2 | iOS The app didn't ask for activity permissions or they were reset. Possible reasons: - The app didn't ask for permissions before starting tracking which is an integration error. Please make sure that your app asks for activity permissions before there is a possibility that the user can be tracked. - The user executed a premissions reset in Settings > General > Reset > Reset Location & Privacy. Open the app and allow activity access |
Activity service disabled
Error Code | Description |
---|---|
OS2 | iOS User disabled motion activity services in Settings.app > Privacy > Motion & Fitness > Fitness Tracking Enable motion & fitness tracking in Settings.app > Privacy > Motion & Fitness > Fitness Tracking |
Motion sensor missing
Error Code | Description |
---|---|
OM1 | iOS The iOS didn't respond with current motion activity status for this iPhone. This can happen if motion activity services were disabled systemwide for a long time (more than a month) or if motion activity chip is faulty. If this is a persistent error, the hardware explanation is more likely. Make sure that Fitness Tracking is always enabled on this iPhone in Settings > Privacy > Motion & Fitness. If this issue persists please contact Apple or your local repair shop for service. |
Notification permission denied
Error Code | Description |
---|---|
OH1 | Android Notification permission wasn't granted. |
GPS signal lost
Error Code | Description |
---|---|
OG1 | GPS satellites are not in view. Move outdoors to get better GPS signal |
OG2 | Android Aiplane mode being on introduces a significant delay for device to get first location fix on device with assisted GPS chips. Turn off Airplane mode |
No exemption from background start restrictions
Error Code | Description |
---|---|
OE1 | Android The app is not allowed to start tracking in background because it doesn't met required conditions for that (see Google documentation). The tracking will be started the next time it is possible. |
Service lost by OS
Error Code | Description |
---|---|
OB1 | Android Location service stopped sending location data to the app. This can happen when device is tracking for a long time (more than 24 hours in a row). Make sure to only start and stop tracking during work hours. Restart the app by opening home screen, long pressing the app's icon and selecting "App info" > "Force stop". Then open the app. |
Service suspended by OS
Error Code | Description |
---|---|
OP1 | Android The Android OS paused executing app's code. This can happen during Doze mode, usually when the driver is not moving and the phone is locked. Removing battery optimizations and restrictions reduces the chance of OS restricting the app during Doze. Long press the app icon, choose App info > Battery, select "Unrestricted". Go to Settings > Battery > Battery Saver, make sure "Use Battery Saver" is off iOS The iOS paused executing app's code. This can happen in rare cases due to device being low on battery or when device has Provisional Always Authorization on iOS 13 and up. Make sure to first request "When In Use" permissions and when they are granted to request "Always" permissions to avoid Provisional Always Authorization. Make sure that battery is sufficiently charged, "Low Power Mode" is off in Settings > Battery and permissions are "Always" in Settings > App Name > Location |
Service terminated
Error Code | Description |
---|---|
OT1 | The app was killed by the by either user or OS. |
Service terminated by user
Error Code | Description |
---|---|
OU1 | The app was killed by user. |
Service terminated by OS
Error Code | Description |
---|---|
OO1 | Android Changing location permissions in settings killed the app. |
OO2 | iOS Changing activity permissions in settings killed the app. |
OO3 | OS ran low on memory and killed the app to free up memory. |
OO4 | iOS App update killed the app. |
OO5 | iOS OS update killed the app. |
OO6 | Android OS reboot killed the app. |
OO7 | iOS Phone turned off because of low battery. |
OO8 | Android The app crashed. |
OO9 | Android App was unresponsive and OS killed it. |
OO10 | Android App was excessively using CPU and OS killed it. |
Device deleted by admin
Error Code | Description |
---|---|
OD1 | This device was deleted using the DELETE /devices API. If you want this device to be tracked undelete it in dashboard or using the undelete API. |
OD2 | This device was automatically deleted because it was disconnected for a long period of time. If you want this device to be tracked undelete it in dashboard or using the undelete API. |
App uninstalled
Error Code | Description |
---|---|
OR1 | The user uninstalled the app. |
App unreachable by server
Error Code | Description |
---|---|
ON1 | iOS The user explicitly disabled background behavior for this app or for the whole system. The app doesn't receive silent push notifications and in turn can't receive a command to start tracking. Enable "Background App Refresh" in Settings > App Name and set "Background App Refresh" to "Wi-Fi & Cellular Data" in Settings > General > Background App Refresh |
ON2 | iOS Background updates are unavailable and the user cannot enable them again. For example, this status can happen when parental controls are in effect for the current user. The app doesn't receive silent push notifications and in turn can't receive a command to start tracking. Turn off Content & Privacy Restrictions in Settings > Screen Time > Content & Privacy Restrictions |
ON3 | HyperTrack can't reach this device to start tracking using push notifications because the OS didn't supply the app with device messaging token. Please make sure that push notifications are integrated based on the integration guide. |
ON4 | HyperTrack sent a push notification to start tracking but it didn't reach this device. Use visual push notifications as a fallback when you receive this inactive outage or a disconnected outage in webhooks. |
Setup incomplete
Error Code | Description |
---|---|
OI1 | Silent push notifications were not integrated. HyperTrack can't remotely start tracking this device. iOS Please follow this guide to complete the integration. Android Please follow this guide to complete the integration. |
Location is mocked
Error Code | Description |
---|---|
OF1 | User enabled mock location app while mocking locations is prohibited for his SDK instance. Check this blogpost for details |
Get outage details with Device API
As explained in this section, you can get device status with Device API.
Please see device_status
example below to review outage details for an outage caused by the user denying location permission:
"device_status" : {
"data" : {
"inactive_reason" : {
"code" : "OL1",
"description" : " User explicitly denied permissions in response to system prompt or in Settings > App Name > Location.",
"name" : "Location permission denied",
"type" : "location_permission_denied",
"user_action_required" : "Change location permission to \"Always\" in Settings > App Name > Location"
},
"recorded_at" : "2021-10-27T00:40:53.811Z"
},
"value" : "inactive"
}
Get outage details with webhooks
As explained in this section, you can get device status with webhooks.
Please this webhook payload example below to review outage details for an outage caused by the user denying location permission:
{
"device_id": "AAAAAAAA-7101-48A9-86C4-B762993ACC5A",
"recorded_at": "2021-10-27T00:40:53.811Z",
"metadata": {
"invite_id": "https://hypertrack-logistics.app.link/xxxx",
"email": "[email protected]"
},
"version": "2.0.0",
"location": {
"type": "Point",
"coordinates": [
-122.503655,
37.76097,
24.98
]
},
"created_at": "2021-10-27T00:42:01.166509Z",
"name": "Alex",
"data": {
"value": "inactive",
"inactive_reason": {
"name": "Location permission denied",
"description": " User explicitly denied permissions in response to system prompt or in Settings > App Name > Location.",
"code": "OL1",
"user_action_required": "Change location permission to \"Always\" in Settings > App Name > Location",
"type": "location_permission_denied"
}
},
"type": "device_status"
}
Manage permissions
iOS and Android mobile operating systems require applications request app user's location and motion activity permissions to track their location.
Request permissions in app
Since tracking can only be started if permissions are granted, your app needs to receive them in advance. OS guidelines also recommend to show an explanation why the location data access is required followed by a permissions request screen.
You can use SDK helper methods to request the permissions:
sdkInstance.requestPermissionsIfNeeded();
sdkInstance.requestPermissionsIfNeeded()
// TODO Eugene
// TODO Eugene
Your app user will be presented with permission dialogs to accept or reject location and motion permissions.
On Android 11+. Background location access permission, that is required to start tracking with device's screen being turned off, cannot be asked directly, but user needs to manually flip that switch in Settings widget.
Request permissions on custom Android
Custom Android hardware manufacturers often tweak Android operating systems' power management software with stricter battery management control.
To prevent being suspended in the background add special whitelisting option in order to add your app to the list of power optimization exceptions. See code examples below:
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);
}
try {
val intent = Intent().also {
when (Build.MANUFACTURER.toLowerCase(Locale.ROOT)) {
"xiaomi" -> it.component = ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")
"oppo" -> it.component = ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")
"vivo" -> it.component = ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")
}
}
if (context.packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).isNotEmpty()) {
context.startActivity(intent)
}
} catch (e: Exception) {
Crashlytics.logException(e)
}
Another approach is to use a third-party library like Autostarter or similar.
Show permissions status in app
iOS and Android allow app user to change permission status at any time. Implement an approach to show visual notifications with hints about changed permissions.
Review this article that discusses permissions for iOS as well as this article to understand Android permissions model.
Control app user tracking
You can track your mobile app users during working hours with calling HyperTrack API from your server.
Track with Devices API
In order to start tracking you need to execute POST request to device's REST API endpoint which looks like https://v3.api.hypertrack.com/devices/{device_id}/start
where device_id
is the UUID string that you got from the SDK above.
curl -X POST \
-u {AccountId}:{SecretKey} \
https://v3.api.hypertrack.com/devices/{device_id}/start
// Instantiate Node.js helper library instance
const hypertrack = require("hypertrack")(accountId, secretKey);
// Use Node.js helper library method to start tracking
hypertrack.devices
.startTracking(deviceId)
.then(() => {
// Tracking started
})
.catch((error) => {
// Error handling
});
python
from hypertrack.rest import Client
from hypertrack.exceptions import HyperTrackException
hypertrack = Client({AccountId}, {SecretKey})
hypertrack.devices.start_tracking({device_id})
```java
public class BasicAuthInterceptor implements Interceptor {
private String credentials;
public BasicAuthInterceptor(String user, String password) {
this.credentials = Credentials.basic(user, password);
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request authenticatedRequest = request.newBuilder()
.header("Authorization", credentials).build();
return chain.proceed(authenticatedRequest);
}
}
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new BasicAuthInterceptor("{AccountId}","{SecretKey}"))
.build();
Request request = new Request.Builder()
.url("https://v3.api.hypertrack.com/devices/{device_id}/start")
.post(null)
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
<?php
$url = 'https://v3.api.hypertrack.com/devices/{device_id}/start';
$basicAuth = "Authorization: Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');
$context = stream_context_create([
"http" => [
"method" => "POST",
"header" => $basicAuth
]
]);
$response = file_get_contents($url, false, $context);
echo $response;
?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'
url = URI("https://v3.api.hypertrack.com/devices/{device_id}/start")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp
response = http.request(request)
puts response.read_body
With Device start API The expected response is 200 status code with {"message": "Device tracking started"}
body.
Once you've done with tracking during business hours you can use Device stop API to terminate the tracking session.
curl -X POST \
-u {AccountId}:{SecretKey} \
https://v3.api.hypertrack.com/devices/{device_id}/stop
// Instantiate Node.js helper library instance
const hypertrack = require("hypertrack")(accountId, secretKey);
// Use Node.js helper library method to start tracking
hypertrack.devices
.stopTracking(deviceId)
.then(() => {
// Tracking started
})
.catch((error) => {
// Error handling
});
from hypertrack.rest import Client
from hypertrack.exceptions import HyperTrackException
hypertrack = Client({AccountId}, {SecretKey})
hypertrack.devices.stop_tracking({device_id})
public class BasicAuthInterceptor implements Interceptor {
private String credentials;
public BasicAuthInterceptor(String user, String password) {
this.credentials = Credentials.basic(user, password);
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request authenticatedRequest = request.newBuilder()
.header("Authorization", credentials).build();
return chain.proceed(authenticatedRequest);
}
}
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new BasicAuthInterceptor("{AccountId}","{SecretKey}"))
.build();
Request request = new Request.Builder()
.url("https://v3.api.hypertrack.com/devices/{device_id}/stop")
.post(null)
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
<?php
$url = 'https://v3.api.hypertrack.com/devices/{device_id}/stop';
$basicAuth = "Authorization: Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');
$context = stream_context_create([
"http" => [
"method" => "POST",
"header" => $basicAuth
]
]);
$response = file_get_contents($url, false, $context);
echo $response;
?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'
url = URI("https://v3.api.hypertrack.com/devices/{device_id}/stop")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp
response = http.request(request)
puts response.read_body
Track with Trips API
You can also manage app user location tracking with Trips API. Please refer to this guide to learn more.
Track with SDK
HyperTrack recommends to use Driers or Orders APIs to track work done by fleet. We also have SDK methods to control tracking directly in the app - however SDK based tracking is almost never the recommended approach.
Please email us if your use case requires tracking with SDK.
String publishableKey = "your-publishable-key-here"
HyperTrack sdkInstance = HyperTrack.getInstance(MyActivity.this, publishableKey);
sdkInstance.start();
val publishableKey = "your-publishable-key-here"
val sdkInstance = HyperTrack.getInstance(this, publishableKey)
sdkInstance.start()
swift
let key = HyperTrack.PublishableKey(hypertrackKey)!
switch HyperTrack.makeSDK(publishableKey: key) {
case let .success(hypertrack):
hyperTrack = hypertrack
hyperTrack.start()
case let .failure(error):
// handle errors here
}
`
NSString *publishableKey = @"your-publishable-key-here";
HTResult *result = [HTSDK makeSDKWithPublishableKey:publishableKey];
if (result.hyperTrack != nil) {
NSLog(@"Successfully set publishableKey and created SDK instance");
self.hyperTrack = result.hyperTrack;
[result.hyperTrack start];
} else {
// Handle errors here
}
The invocation above will start the tracking and either provides device's location or a reason why the device can't be tracked.
You must always stop tracking, when your app user completes work, using the below command:
sdkInstance.stop();
sdkInstance.stop()
hyperTrack.stop()
[hyperTrack stop];
Managing app user tracking
Depending on a use case, you might have to use more than one option to manage app user tracking as explained in examples below.
-
If an app user is on a trip, tracking for the app user will stop only if the trip is completed and if there are no other active trips taking place for the same app user. Device stop API and SDK stop tracking method will not take effect if the app user's device has one or more active trips.
-
If app user tracking started with an SDK start method, Device stop API will stop tracking for the app user's device. Similarly, if app user tracking started with Device start API, you may be able to stop app user tracking with the SDK stop method called on the app user's device.
-
If app user tracking started with either SDK start method or Device start API, you may still be able to create a single trip or multiple for the app user's device. Once all app user's trips are completed, the app user's device still continues tracking until either SDK stop method or Device stop API are called.
Do not hesitate to send email us to discuss possible app user tracking use cases to put together the best solution for you.
Consume tracked data
API
To get the status of any device you can use the following query:
curl \
-u {AccountId}:{SecretKey} \
https://v3.api.hypertrack.com/devices/00112233-4455-6677-8899-AABBCCDDEEFF
// Instantiate Node.js helper library instance
const hypertrack = require("hypertrack")(accountId, secretKey);
hypertrack.devices
.get("00112233-4455-6677-8899-AABBCCDDEEFF")
.then((device) => {
// Process device
})
.catch((error) => {
// Error handling
});
from hypertrack.rest import Client
from hypertrack.exceptions import HyperTrackException
hypertrack = Client({AccountId}, {SecretKey})
device = hypertrack.devices.get('00112233-4455-6677-8899-AABBCCDDEEFF')
print(device)
OkHttpClient client = new OkHttpClient();
String authString = "Basic " +
Base64.getEncoder().encodeToString(
String.format("%s:%s", "{AccountId}","{SecretKey}")
.getBytes()
);
Request request = new Request.Builder()
.url("https://v3.api.hypertrack.com/devices/00112233-4455-6677-8899-AABBCCDDEEFF")
.get()
.addHeader("Authorization", authString)
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
<?php
$url = 'https://v3.api.hypertrack.com/devices/00112233-4455-6677-8899-AABBCCDDEEFF';
$basicAuth = "Authorization: Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');
$context = stream_context_create([
"http" => [
"method" => "GET",
"header" => $basicAuth
]
]);
$response = file_get_contents($url, false, $context);
echo $response;
?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'
url = URI("https://v3.api.hypertrack.com/devices/00112233-4455-6677-8899-AABBCCDDEEFF")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp
response = http.request(request)
puts response.read_body
The response is 200 status code with body like follows:
{
"device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
// Last known location for the device
"location": {
"speed": 4.20,
"accuracy": 14.09,
"bearing": 193.12,
"geometry": {
"type": "Point",
"coordinates": [ 35.1016383, 47.8391314, 65.40 ]
},
"recorded_at": "2019-07-18T18:01:59.064000Z",
},
"device_status": {
"data": {
"recorded_at": "2019-07-30T01:38:45.610000Z",
"activity": "stop"
},
"value": "active" // could also be `inactive` or `disconnected`
},
"battery": "normal",
"device_info": {
"timezone": "America/Los_Angeles",
"os_name": "iOS",
"device_brand": "Apple",
"sdk_version": "3.3.2",
"device_model": "iPhone X",
"network_operator": "T-Mobile",
"name": "Alexβs Phone", // the name you've assigned from the mobile SDK or via API
"os_version": "12.4"
},
"registered_at": "2019-07-10T01:38:45.610000Z",
"metadata": { ... } // key-value datastructure that you can assign for device for grouping or tagging
}
This response delivers your app user's device most recently known recorded location, its current device status, device's name, metadata, as well as device_info
field as shown above along with it's registration UTC timestamp in registered_at
.
This Devices API is not intended to be used to continually update location data on your server.
Please use webhooks to send location data to your server or Views SDK to implement real-time location updates on your app users device without needing to deploy server infrastructure.
Additionally, HyperTrack Devices API provides you ability to query all registered devices in your account.
The devices API above requires a device_id
to obtain its location and status.
Additionally, you can retrieve device data and status by their grouping. For example, you want to find devices that show vehicle_type
as scooter
per example above.
HyperTrack Devices API provides you an option to use a metadata_filter
query parameter to help you conveniently retrieve this data:
GET /devices?metadata_filter=<url_encoded_json>
with an example JSON as shown:
{
"vehicle_type": "scooter"
}
Once you perform URL encoding for the string above, you Devices GET API call will be executed as follows:
GET /devices?metadata_filter=%7B%27vehicle_type%27%3A+%27scooter%27%7D
Thus, this API call will only return entries that match this metadata. Note that the metadata filter will look for any matching subsets of JSON data that match correspoding keys and values you send in this API call.
Webhooks
You can subscribe to webhook notifications about your app users' device status. Please refer to this section to integrate and receive device status updates in real-time.
Views
Devices API response provides you with embed_url
. This provides you an ability to create a customizeable real-time device tracking view. Please see this guide to learn more on how to quikly build your own real-time tracking dashboards.
Understand and improve tracking rate
The ability to track your app users is essential to gather accurate location data.
While HyperTrack applies sophisticated technologies to ensure devices get tracked when intended,
there are scenarios ranging from an empty battery to denying permissions that prevent us from tracking a device.
To give you a quick overview of the coverage of tracking,
we calculate tracking rate for your account and individual devices.
Tracking rate is the ratio of time tracked to the total time you intended to track.
Tracking rate is available through Scoreboard,
Insights and
Devices History API.
Scoreboard
The scoreboard displays current and historic tracking rates among other key metrics, to show you how your operations are progressing. Visualizations provide a clear indication of trends based on key metrics while focusing on a current dayβs status.

The overall tracking rate above gives you an overview of how well you are tracking your app users today.
To understand why the remaining time devices were not tracked, HyperTrack shows you the breakdown of the outages in a pie chart and the actions you need to take to correct them.
Addressing all inactive reasons in the chart would get you to 100% tracking rate.
Insights
Insights gives you tracking rate, outages and other key metrics per app user.

Insights data shows you tracking rate for all app users in the Activity column (shades of green mean tracked, grey not tracked) and the outage reasons.
Besides tracking rate, Insights give you an overview for you operations. The data can be exported to csv files.
Please check out Insights guide for more information.
Devices API
To get tracking rate programmatically, HyperTrack provides the Devices History API
curl \
-u {AccountId}:{SecretKey} \
https://v3.api.hypertrack.com/devices/00112233-4455-6677-8899-AABBCCDDEEFF
Returns the tracking rate relevant data here:
...
"tracking_rate": 50.0,
"inactive_reasons": ["location.permission_denied"],
"inactive_duration": 3600,
"active_duration": 3600,
...
How to improve tracking rate
If the tracking rate is low ( less than 80% account wide), there are typically various policy and technical solutions you can apply to increase tracking rate.
Only track your app users when they expect to be tracked
Android and iOS give users excellent controls over privacy, and the data that is shared with apps.
The controls allow for fine-grained permissions to notifications that an app is tracking your location.

If your users see tracking notifications while not working, they will deny permissions or try to kill the app/location services due to privacy and battery concerns.
While doing this during off hours might not impact your business right away, but it will impact the ability to properly track the device next time you intend to track the device.
For instance, the denied permission will have to be granted again before tracking can resume.
To avoid this, start tracking at the beginning of the shift and stop tracking right at the end of the shift.
Clearly communicate the benefits of location tracking to your users
As described in the previous sections, users have all the control over their devices.
To ensure proper tracking, clearly communicated the benefits of location tracking to your user base. Examples include:
- Location is required to Automate distance-based payouts
- Location is required to get the next Nearest job assigned
- Location is needed to share ETA of orders customers (see Trips)
Detect outages in real time and reach out to your app users
HyperTrack sends status update webhooks in real time when an outage happens.
Use this notification to reach out to your app users to address the problem or block particular flows till outages are resolved.
The list of outages can be found in the API references.
Handle aggressive power saving modes of custom Android versions/ROMs
Custom Android versions/ROMs apply aggressive power saving that leads to the app being killed.
To avoid this, whitelist the application to eliminate the consequences of aggressive power saving.
See our FAQ for more info.
Updated 10 days ago