Skip to main content

Installation

Setup

  1. Ensure your device has Android 7.1 or higher
  2. Ensure that mavenCentral() is in the project-level build.gradle file like so:
buildscript {    repositories {        mavenCentral()    }}
  1. In the individual module build.gradle file add:
dependencies {  // ...  implementation "live.ditto:ditto:1.1.9"}
android {  // ...
  compileOptions {      sourceCompatibility JavaVersion.VERSION_1_8      targetCompatibility JavaVersion.VERSION_1_8  }}
  1. Configure your manifest with the following permissions. Ditto's required permissions have changed since Android 12. Refer to Android Platform Permissions for details.
    <uses-permission android:name="android.permission.BLUETOOTH"        android:maxSdkVersion="30" />    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"        android:maxSdkVersion="30" />    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"        android:usesPermissionFlags="neverForLocation" />    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"        android:maxSdkVersion="30" />    <uses-permission android:name="android.permission.INTERNET" />    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />    <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
  1. Access the portal to create a new app. Apps created on the portal will automatically sync data between them and also to the Ditto Big Peer. Each app created on the portal has a unique appID which can be seen on your app's settings page once the app has been created. This ID is used in subsequent sections to configure your Ditto instance.

  2. Create your Ditto instance as below. We recommend placing this in your Application.onCreate method:

try {    val androidDependencies = AndroidDittoDependencies(context)    val identity = DittoIdentity.OnlinePlaygroundV2(androidDependencies, appID = "REPLACE_ME_WITH_YOUR_APP_ID", token = "REPLACE_ME_WITH_YOUR_PLAYGROUND_TOKEN")    val ditto = Ditto(androidDependencies, identity)    ditto.tryStartSync()} catch(e: DittoError) {    Log.e("Ditto error", e.message!!)}

Android Platform Permissions

The Android operating system restricts access to some functionality for the sake of user control and privacy. Therefore, to unlock the full capabilities of Ditto, it is essential to configure your app so that it requests all the permissions that it needs.

First you must add the following permissions to your app's AndroidManifest.xml file.

Then at runtime your app must prompt the user to request certain permissions.

Modern Manifest (API Level > 30)

AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH"    android:maxSdkVersion="30" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN"    android:maxSdkVersion="30" /><uses-permission android:name="android.permission.BLUETOOTH_SCAN"    android:usesPermissionFlags="neverForLocation" /><uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /><uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"    android:maxSdkVersion="30" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /><uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />

Since the Ditto SDK does not use BLE to locate the user physically it assumes you are using the neverForLocation flag on BLUETOOTH_SCAN. On Android 12, this means that ACCESS_FINE_LOCATION is no longer required. If you wish to use ACCESS_FINE_LOCATION on an app targeting API level 31+, you must check for and request this permission on your own. Refer to the Android Documentation for details.

Legacy Manifest (API Level <= 30)

The following manifest is sufficient for apps that are not yet targeting Android 12.

AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /><uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />

In these older Android versions, ACCESS_FINE_LOCATION is mandatory and Ditto will check that it is present.

Runtime Permissions

Your apps must ensure all required permissions for sync have been requested from the user. The Android Ditto SDK provides a DittoSyncPermissions helper which makes this easy. For example, a fragment can use a method like this:

In Kotlin, DittoSyncPermissions requires a Context. You can get the context by invoking getApplicationContext(), getContext(), getBaseContext() or this when in a class that extends from Context, such as the Application, Activity, Service and IntentService classes.

fun checkPermissions() {    val missing = DittoSyncPermissions(this).missingPermissions()    if (missing.isNotEmpty()) {        this.requestPermissions(missing, 0)    }}

Alternatively, requireActivity() is a way to force the code to only work on a Fragment that has a Context.

fun checkPermissions() {    val activity = requireActivity()    val missing = DittoSyncPermissions(activity).missingPermissions()    if (missing.isNotEmpty()) {        activity.requestPermissions(missing, 0)    }}

For more information about requesting permissions in a user-friendly way refer to Android's documentation: Request App Permissions.

On Android there may be a noticeable delay between when the user grants location access and when Ditto notices the new permission. For this reason it is recommended to call refreshPermissions() whenever a relevant permission might have changed. This will force an immediate check. If a permission has become available your app can begin syncing as quickly as possible.

override fun onRequestPermissionsResult(    requestCode: Int,    permissions: Array<out String>,    grantResults: IntArray) {    super.onRequestPermissionsResult(requestCode, permissions, grantResults)    // Regardless of the outcome, tell Ditto that permissions maybe changed    ditto?.refreshPermissions()}