Android SDK

Learn how to integrate the Android SDK below. You can also see the source and a detailed SDK reference.

Authentication

Authenticate using your publishable API keys, found on the Settings page. Use your Test Publishable key for testing and non-production environments. Use your Live Publishable key for production environments.

Note that you should always use your publishable API keys, which are restricted in scope, in the SDK. Do not use your secret API keys, which are unrestricted in scope, in any client-side code.

Configure Android Studio project

Radar uses the Play Services Location library. If you haven't already configured your project for Play Services, follow the instructions here.

Radar requires the following permissions, added automatically by the SDK manifest:

  • ACCESS_FINE_LOCATION, for location services
  • INTERNET and ACCESS_NETWORK_STATE, to send API requests
  • RECEIVE_BOOT_COMPLETED, to restore geofences on boot

If targeting API level 29 or higher, to track the user's location in the background, you must also add the new ACCESS_BACKGROUND_LOCATION permission to your manifest. Learn more about location permissions changes in Android 10.

Add Android SDK to project

The best way to add the SDK to your project is via Gradle and JCenter in Android Studio. Add the SDK to the dependencies section of your build.gradle file:

dependencies {
  implementation 'io.radar:sdk:3.0.0'
}

The SDK depends on AndroidX (to check location permissions) and Play Services Location library version 17.0.0 and higher (for location services). These libraries will be automatically included as transitive dependencies. Learn more about managing dependencies in Gradle here.

You can also add the SDK to your project manually, though this is not recommended. Download the current release and unzip the package. The package contains an aar file. In Android Studio, add the SDK as a module using File > New Module > Import .JAR/.AAR Package.

The SDK currently supports API level 16 and higher.

The SDK is small and typically adds less than 500 KB to your compiled app.

Integrate Android SDK into app

Initialize SDK

Import the SDK:

Java Kotlin

import io.radar.sdk.Radar;
import io.radar.sdk.Radar

Initialize the SDK in your Application class before calling any other Radar methods. In onCreate(), call:

Java Kotlin

Radar.initialize(this, publishableKey);
Radar.initialize(this, publishableKey)

where publishableKey is a string containing your publishable API key.

Identify user

Until you identify the user, Radar will automatically identify the user by deviceId (Android ID).

To identify the user when logged in, call:

Java Kotlin

Radar.setUserId(userId);
Radar.setUserId(userId)

where userId is a stable unique ID for the user.

Do not send any PII, like names, email addresses, or publicly available IDs, for userId. See privacy best practices for more information.

To set an optional dictionary of custom metadata for the user, call:

Java Kotlin

Radar.setMetadata(metadata);
Radar.setMetadata(metadata)

where metadata is a JSONObject with up to 16 keys and values of type string, boolean, or number.

Finally, to set an optional description for the user, displayed in the dashboard, call:

Java Kotlin

Radar.setDescription(description);
Radar.setDescription(description)

You only need to call these methods once, as these settings will be persisted across app sessions.

Request permissions

Radar respects standard Android location permissions. Before tracking the user's location, the user must have granted location permissions for the app if they haven't already.

To track the user's location in the foreground, Radar requires the ACCESS_FINE_LOCATION permission. Learn more about requesting permissions here.

If targeting API level 29 or higher, to track the user's location in the background, Radar also requires the new ACCESS_BACKGROUND_LOCATION permission. Learn more about location permissions changes in Android 10.

Java Kotlin

// foreground only or targeting API level 28 and lower
ActivityCompat.requestPermissions(activity, new String[] { Manifest.permission.ACCESS_FINE_LOCATION }, requestCode)

// background and targeting API level 29 and higher
ActivityCompat.requestPermissions(activity, new String[] { Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION }, requestCode)
// foreground only or targeting API level 28 and lower
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), requestCode)

// background and targeting API level 29 and higher
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION), requestCode)

Foreground tracking

Once you have initialized the SDK, you have identified the user, and the user has granted permissions, you can track the user's location in the foreground.

To track the user's location in the foreground, call:

Java Kotlin

Radar.trackOnce(new RadarCallback() {
  @Override
  public void onComplete(RadarStatus status, Location location, RadarEvent[] events, RadarUser user) {
    // do something with location, events, user
  }
});
Radar.trackOnce { status, location, events, user ->
  // do something with location, events, user
}

You may provide an optional instance of RadarCallback with an implementation of onComplete() that receives the request status, the user's location, the events generated, if any, and the user. The request status can be:

  • RadarStatus.SUCCESS: success
  • RadarStatus.ERROR_PUBLISHABLE_KEY: SDK not initialized
  • RadarStatus.ERROR_PERMISSIONS: location permissions not granted
  • RadarStatus.ERROR_LOCATION: location services error or timeout (10 seconds)
  • RadarStatus.ERROR_NETWORK: network error or timeout (10 seconds)
  • RadarStatus.ERROR_BAD_REQUEST: bad request (missing or invalid params)
  • RadarStatus.ERROR_UNAUTHORIZED: unauthorized (invalid API key)
  • RadarStatus.ERROR_PAYMENT_REQUIRED: payment required (organization disabled or usage exceeded)
  • RadarStatus.ERROR_FORBIDDEN: forbidden (insufficient permissions)
  • RadarStatus.ERROR_NOT_FOUND: not found
  • RadarStatus.ERROR_RATE_LIMIT: too many requests (rate limit exceeded)
  • RadarStatus.ERROR_SERVER: internal server error
  • RadarStatus.ERROR_UNKNOWN: unknown error

Note that these calls are subject to rate limits.

Background tracking

Once you have initialized the SDK and the user has granted permissions, you can start tracking the user's location in the background.

For background tracking, the SDK supports custom tracking options as well as three presets:

  • RadarTrackingOptions.EFFICIENT: A preset that updates as fast as every 6 minutes while moving, periodically when stopped, and only syncs stops and exits to the server. Must move a significant distance to start moving again after a stop. Lowest battery usage and will not exceed Android vitals bad behavior thresholds. Recommended for most use cases.
  • RadarTrackingOptions.RESPONSIVE: A preset that updates as fast as every 2.5 minutes while moving, shuts down when stopped, and only syncs stops and exits to the server. Must move at least 200 meters to start moving again after a stop. Low battery usage, but may exceed Android vitals bad behavior thresholds for excessive wakeups and excessive wi-fi scans.
  • RadarTrackingOptions.CONTINUOUS: A preset that updates every 30 seconds and syncs all location updates to the server. High battery usage. Should be used with a foreground service.

Note that location updates may be delayed significantly by Doze Mode, App Standby, and Background Location Limits, or if the device has connectivity issues, low battery, or wi-fi disabled.

To start tracking the user's location in the background with default tracking options, call one of:

Java Kotlin

// efficient
Radar.startTracking(RadarTrackingOptions.EFFICIENT);

// responsive
Radar.startTracking(RadarTrackingOptions.RESPONSIVE);

// continuous
Radar.startTracking(RadarTrackingOptions.CONTINUOUS);
// efficient
Radar.startTracking(RadarTrackingOptions.EFFICIENT)

// responsive
Radar.startTracking(RadarTrackingOptions.RESPONSIVE)

// continuous
Radar.startTracking(RadarTrackingOptions.CONTINUOUS)

You only need to call this method once, as these settings will be persisted across app sessions.

Though we recommend using presets for most use cases, you can modify the presets. See the tracking options reference.

To stop tracking the user's location in the background (e.g., when the user logs out), call:

Java Kotlin

Radar.stopTracking();
Radar.stopTracking()

You only need to call these methods once, as these settings will be persisted across app sessions.

Receiver

To listen for events, location updates, and errors client-side, create a class that extends RadarReceiver. Then, register the receiver by adding a receiver element to the application element in your manifest:

<application android:label="@string/app_name">
  <receiver
      android:name=".MyRadarReceiver"
      android:enabled="true"
      android:exported="false">
      <intent-filter>
          <action android:name="io.radar.sdk.RECEIVED" />
      </intent-filter>
  </receiver>
</application>

Your receiver should implement the following:

Java Kotlin

public class MyRadarReceiver extends RadarReceiver {

  @Override
  public void onEventsReceived(Context context, RadarEvent[] events, RadarUser user) {
    // do something with events, user
  }

  @Override
  public void onLocationUpdated(Context context, Location location, RadarUser user) {
    // do something with location, user
  }

  @Override
  public void onClientLocationUpdated(Context context, Location location, boolean stopped, RadarLocationSource source) {
    // do something with location, stopped, source
  }

  @Override
  public void onError(Context context, RadarStatus status) {
    // do something with status
  }

}
class MyRadarReceiver: RadarReceiver() {

  override fun onEventsReceived(context: Context, events: Array<RadarEvent>, user: RadarUser) {
    // do something with events, user
  }

  override fun onLocationUpdated(context: Context, location: Location, user: RadarUser) {
    // do something with location, user
  }

  override fun onClientLocationUpdated(context: Context, location: Location, stopped: Boolean, source: RadarLocationSource) {
    // do something with location, stopped, source
  }

  override fun onError(context: Context, status: RadarStatus) {
    // do something with status
  }

}

To listen for events server-side instead, add a webhook.

Manual tracking

If you want to manage location services yourself, you can manually update the user's location instead by calling:

Java Kotlin

Radar.trackOnce(
  location,
  new RadarCallback() {
    @Override
    public void onComplete(RadarStatus status, Location location, RadarEvent[] events, RadarUser user) {
      // do something with location, events, user
    }
  }
);
Radar.trackOnce(location) { status, location, events, user ->
  // do something with location, events, user
}

where location is a Location instance with a valid latitude, longitude, and accuracy.

Note that these calls are subject to rate limits.

Verify events

You can accept or reject events after user check-ins or other forms of verification. Event verifications will be used to improve the accuracy and confidence level of future Insights and Places events.

Java Kotlin

Radar.acceptEvent(event.getId(), event.alternatePlaces[0].getId());

Radar.rejectEvent(event.getId());
Radar.acceptEvent(event.id, event.alternatePlaces[0].id)

Radar.rejectEvent(event.id)

Other APIs

The Android SDK also exposes APIs for anonymous context, geocoding, search, and distance.

Get location

Get a single location update without sending it to the server:

Java Kotlin

Radar.getLocation(new RadarLocationCallback() {
  @Override
  public void onComplete(RadarStatus status, Location location, boolean stopped) {
    // do something with location
  }
});
Radar.getLocation { status, location, stopped ->
  // do something with location
}

Context

With the context API, get context for a location without sending device or user identifiers to the server:

Java Kotlin

Radar.getContext(new RadarContextCallback() {
  @Override
  public void onComplete(RadarStatus status, Location location, RadarContext context) {
    // do something with context
  }
});
Radar.getContext { status, location, context ->
  // do something with context
}

Geocoding

With the forward geocoding API, geocode an address, converting address to coordinates:

Java Kotlin

Radar.geocode(
  "20 jay street brooklyn ny", // query
  new RadarGeocodeCallback() {
    @Override
    public void onComplete(RadarStatus status, RadarAddress[] addresses) {
      // do something with addresses
    }
  }
);
Radar.geocode("20 jay street brooklyn ny") { status, addresses ->
  // do something with addresses
}

With the reverse geocoding API, reverse geocode a location, converting coordinates to address:

Java Kotlin

Radar.reverseGeocode(
  location,
  new RadarGeocodeCallback() {
    @Override
    public void onComplete(RadarStatus status, RadarAddress[] addresses) {
      // do something with addresses
    }
  }
);
Radar.reverseGeocode(location) { status, addresses ->
  // do something with addresses
}

With the IP geocoding API, geocode the device's current IP address, converting IP address to city, state, and country:

Java Kotlin

Radar.ipGeocode(new RadarIpGeocodeCallback() {
  @Override
  public void onComplete(RadarStatus status, RadarAddress address) {
    // do something with address
  }
});
Radar.ipGeocode { status, address ->
  // do something with address
}

With the autocomplete API, autocomplete partial addresses and place names, sorted by relevance:

Java Kotlin

Radar.autocomplete(
  "brooklyn roasting", // query
  near,
  10, // limit
  new RadarGeocodeCallback() {
    @Override
    public void onComplete(RadarStatus status, RadarAddress[] addresses) {
      // do something with addresses
    }
  }
);
Radar.autocomplete(
  "brooklyn roasting", // query
  near,
  10 // limit
) { status, addresses ->
  // do something with addresses
}

With the geofence search API, search for geofences near a location, sorted by distance:

Java Kotlin

Radar.searchGeofences(
  near,
  1000, // radius (meters)
  {"store"}, // tags
  nil, //metadata
  10, // limit
  new RadarSearchGeofencesCallback() {
    @Override
    public void onComplete(RadarStatus status, Location location, RadarGeofence[] geofences) {
      // do something with geofences
    }
  }
);
Radar.searchGeofences(
  near,
  1000, // radius (meters)
  arrayOf("store"), // tags
  nil, // metadata
  10 // limit
) { status, location, geofences ->
  // do something with geofences
}

With the places search API, search for places near a location, sorted by distance:

Java Kotlin

Radar.searchPlaces(
  near,
  1000, // radius (meters)
  {"starbucks"}, // chains
  null, // categories
  null, //groups
  10, // limit
  new RadarSearchPlacesCallback() {
    @Override
    public void onComplete(RadarStatus status, Location location, RadarPlace[] places) {
      // do something with places
    }
  }
);
Radar.searchPlaces(
  near,
  1000, // radius (meters)
  arrayOf("starbucks"), // chains
  null, // categories
  null, // groups
  10 // limit
) { status, location, places ->
  // do something with places
}

Distance

With the distance API, calculate the travel distance and duration between two locations:

Java Kotlin

Radar.getDistance(
  origin,
  destination,
  EnumSet.of(RadarRouteMode.FOOT, RadarRouteMode.CAR),
  RadarRouteUnits.IMPERIAL,
  new RadarRouteCallback() {
    @Override
    public void onComplete(RadarStatus status, RadarRoutes routes) {
      // do something with routes
    }
  }
);
Radar.getDistance(
  origin,
  destination,
  EnumSet.of(RadarRouteMode.FOOT, RadarRouteMode.CAR),
  RadarRouteUnits.IMPERIAL
) { status, routes ->
  // do something with routes
}