How to set up DJI Mobile SDK V5 in an empty Android project

Add the DJI Mobile SDK V5 (5.17.0) to a new Android Studio project: exact versions, Gradle, manifest, Application class and a first-run checklist.

Written for
MSDK V5 5.17.0
Last updated

This guide starts with a brand-new Android Studio project and adds the DJI Mobile SDK V5 (MSDK V5) step by step, until the app starts and registers with DJI’s servers.

Most of the work is matching versions. The SDK is picky: a Gradle, plugin or Kotlin version that is too new can break the build. So the first thing to do is use the versions DJI recommends.

Before you start

You need:

  • Android Studio, version Narwhal 3 Feature Drop (2025.1.3) or the one you use for DJI work.
  • Java 17, set as the Gradle JDK.
  • A DJI developer account and an app key from the developer portal.
  • A DJI supported remote controller, and a physical arm64 Android device. The SDK does not run on an emulator.

When you create the project, choose Groovy DSL as the build configuration language. The code in this guide uses Groovy build files (build.gradle). If you use Kotlin DSL (build.gradle.kts), the ideas are the same but the syntax is different.

Versions used in this guide

Tool or setting Version
Android Studio Narwhal 3 Feature Drop (2025.1.3)
Java runtime 17
Kotlin 2.1.0
Gradle 8.12
Android Gradle Plugin 8.7.0
minSdk 24
targetSdk, compileSdk 35
DJI MSDK V5 5.17.0

These are the versions DJI recommends for MSDK V5. A newer Android Gradle Plugin or Gradle version can cause build failures.

1. Gradle and toolchain setup

1.1 Gradle wrapper: 8.12

In gradle/wrapper/gradle-wrapper.properties:

distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip

You can also change this in File → Project Structure → Project → Gradle version.

1.2 Android Gradle Plugin: 8.7.0

In gradle/libs.versions.toml, under [versions]:

agp = "8.7.0"

1.3 Kotlin plugin: 2.1.0

In the same file, under [versions]:

kotlin = "2.1.0"

1.4 Java runtime: 17

DJI recommends Java 17. Go to Settings → Build, Execution, Deployment → Build Tools → Gradle and set:

Gradle JDK = 17   (or "Embedded JDK" if it is already version 17)

2. Build configuration

2.1 compileSdk, targetSdk and minSdk

In app/build.gradle:

android {
    compileSdk 35

    defaultConfig {
        applicationId "com.example.myapplication"
        minSdk 24
        targetSdk 35
        // ...
    }
}

DJI recommends compileSdk 35. Version 36 may work, but it is not tested with this SDK version.

2.2 Use older versions of two core libraries

Newer versions of these libraries can conflict with the SDK. In gradle/libs.versions.toml:

coreKtx = "1.15.0"
activity = "1.9.3"

2.3 Turn on kotlin-kapt

The SDK uses annotation processors, so kapt must be enabled. In the plugins block of app/build.gradle:

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    id("org.jetbrains.kotlin.kapt")       // add this line
}

Sync the project now, then continue.

2.4 Use only the arm64-v8a ABI

DJI ships native libraries for arm64 only. Limiting the build to one ABI avoids packaging problems and makes builds faster:

android {
    defaultConfig {
        ndk {
            abiFilters += "arm64-v8a"
        }
    }
}

3. Packaging and native libraries

The SDK contains many .so files (native libraries). Without the rules below you get duplicate entry errors at build time and missing symbols at run time.

In app/build.gradle, inside the android block:

android {
    packaging {
        jniLibs {
            // Several DJI libraries bring their own libc++_shared.so. Keep the first one.
            pickFirsts.add("lib/arm64-v8a/libc++_shared.so")

            // Keep the debug symbols of the DJI native libraries
            keepDebugSymbols.addAll([
                "**/libconstants.so",
                "**/libdji_innertools.so",
                "**/libdjibase.so",
                "**/libDJICSDKCommon.so",
                "**/libDJIFlySafeCore-CSDK.so",
                "**/libdjifs_jni-CSDK.so",
                "**/libDJIRegister.so",
                "**/libdjisdk_jni.so",
                "**/libDJIUpgradeCore.so",
                "**/libDJIUpgradeJNI.so",
                "**/libDJIWaypointV2Core-CSDK.so",
                "**/libdjiwpv2-CSDK.so",
                "**/libFlightRecordEngine.so",
                "**/libvideo-framing.so",
                "**/libwaes.so",
                "**/libagora-rtsa-sdk.so",
                "**/libc++.so",
                "**/libc++_shared.so",
                "**/libmrtc_28181.so",
                "**/libmrtc_agora.so",
                "**/libmrtc_core.so",
                "**/libmrtc_core_jni.so",
                "**/libmrtc_data.so",
                "**/libmrtc_log.so",
                "**/libmrtc_onvif.so",
                "**/libmrtc_rtmp.so",
                "**/libmrtc_rtsp.so"
            ])
        }
    }
}

4. DJI SDK dependencies

4.1 Add the SDK version

In gradle/libs.versions.toml, under [versions]:

djiSdk = "5.17.0"

4.2 Declare the library aliases

In the same file, under [libraries]:

dji-sdk-v5-aircraft = { group = "com.dji", name = "dji-sdk-v5-aircraft", version.ref = "djiSdk" }
dji-sdk-v5-aircraft-provided = { group = "com.dji", name = "dji-sdk-v5-aircraft-provided", version.ref = "djiSdk" }

What the two libraries are:

  • dji-sdk-v5-aircraft is the real SDK. It ships inside your app.
  • dji-sdk-v5-aircraft-provided has compile-time stubs only. It works like compileOnly.

4.3 Use them in app/build.gradle

dependencies {
    implementation(libs.dji.sdk.v5.aircraft)             // the SDK at run time
    compileOnly(libs.dji.sdk.v5.aircraft.provided)       // compile-time stubs only

    // your other app dependencies...
}

Sync the project now, then continue.

5. The UX SDK module

The line implementation project(":android-sdk-v5-uxsdk") is not a Maven dependency. It points to a local Gradle module inside your project, so you have to add that module by hand.

Step 1: Get the UX SDK source

Clone the official DJI sample project and copy its android-sdk-v5-uxsdk folder into the root folder of your project:

https://github.com/dji-sdk/Mobile-SDK-Android-V5

Step 2: Register the module in settings.gradle

include(":android-sdk-v5-uxsdk")

Step 3: Add the module to your app

In app/build.gradle:

dependencies {
    implementation(project(":android-sdk-v5-uxsdk"))
    // ...
}

Step 4: Set the properties in gradle.properties

These let the UX SDK module use the right versions:

android.enableJetifier=true

ANDROID_COMPILE_SDK_VERSION=35
ANDROID_MIN_SDK_VERSION=24
ANDROID_TARGET_SDK_VERSION=35

KOTLIN_VERSION=2.1.0
SDK_VERSION=5.17.0

Step 5: Create dependencies.gradle

Create a file named dependencies.gradle next to your root build.gradle. Paste in the content of the same file from the DJI sample project:

https://github.com/dji-sdk/Mobile-SDK-Android-V5/blob/dev-sdk-main/SampleCode-V5/android-sdk-v5-as/dependencies.gradle

Step 6: Apply it from the root build.gradle

At the very bottom of the root build.gradle (the project-level one):

apply from: rootProject.file("dependencies.gradle")

Sync the project after all the UX SDK steps.

6. AndroidManifest configuration

6.1 Permissions

Add these inside <manifest>:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />

6.2 USB hardware features

These are needed to connect to the DJI remote controller over USB. Add them inside <manifest>:

<uses-feature
    android:name="android.hardware.usb.host"
    android:required="false"/>
<uses-feature
    android:name="android.hardware.usb.accessory"
    android:required="true"/>

6.3 The application tag

Add these attributes to the <application> tag:

<application
    android:name=".MyApplication"
    android:extractNativeLibs="true"
    ... >

android:extractNativeLibs="true" tells Android to unpack the native libraries when the app is installed. Recent Android Gradle Plugin versions leave them packed inside the APK by default, and the DJI SDK needs them unpacked.

6.4 Your DJI app key

Get an app key on the DJI developer portal. Then add it inside the <application> tag:

<meta-data
    android:name="com.dji.sdk.API_KEY"
    android:value="YOUR_APP_KEY_HERE"/>

The package name of your app must match the one you gave the portal when you created the key.

6.5 USB accessory intent filter

Add this inside your main <activity> tag. It starts your app when a DJI remote controller is plugged in over USB:

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<meta-data
    android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
    android:resource="@xml/accessory_filter" />

Make sure res/xml/accessory_filter.xml exists. Copy it from the DJI sample project.

7. The Application class

Create MyApplication.kt in your main source set:

import android.app.Application
import android.content.Context
import android.util.Log
import dji.v5.common.error.IDJIError
import dji.v5.common.register.DJISDKInitEvent
import dji.v5.manager.SDKManager
import dji.v5.manager.interfaces.SDKManagerCallback
import dji.ux.beta.core.util.Helper

class MyApplication : Application() {

    companion object {
        private const val TAG = "MyApplication"
    }

    // Runs before onCreate. The DJI Helper must be installed here.
    override fun attachBaseContext(base: Context?) {
        super.attachBaseContext(base)
        Helper.install(this)
    }

    override fun onCreate() {
        super.onCreate()

        SDKManager.getInstance().init(this, object : SDKManagerCallback {

            override fun onInitProcess(event: DJISDKInitEvent?, totalProcess: Int) {
                Log.i(TAG, "onInitProcess: $event")
                // When initialization is complete, register with the DJI servers
                if (event == DJISDKInitEvent.INITIALIZE_COMPLETE) {
                    SDKManager.getInstance().registerApp()
                }
            }

            override fun onRegisterSuccess() {
                Log.i(TAG, "onRegisterSuccess: SDK registered successfully")
            }

            override fun onRegisterFailure(error: IDJIError?) {
                Log.i(TAG, "onRegisterFailure: $error")
            }

            override fun onProductConnect(productId: Int) {
                Log.i(TAG, "onProductConnect: productId=$productId")
            }

            override fun onProductDisconnect(productId: Int) {
                Log.i(TAG, "onProductDisconnect: productId=$productId")
            }

            override fun onProductChanged(productId: Int) {
                Log.i(TAG, "onProductChanged: productId=$productId")
            }

            override fun onDatabaseDownloadProgress(current: Long, total: Long) {
                Log.i(TAG, "onDatabaseDownloadProgress: ${current * 100 / total}%")
            }
        })
    }
}

Why two lifecycle methods?

  • attachBaseContext: Helper.install() must run before any DJI class is loaded, so it belongs here.
  • onCreate: SDKManager.init() starts the SDK. When initialization is complete, registerApp() registers your app key with DJI.

8. First-run checklist

Check these before you build and run on a device:

  • Gradle wrapper is 8.12, the Android Gradle Plugin is 8.7.0, Kotlin is 2.1.0.
  • The Gradle JDK is Java 17.
  • compileSdk and targetSdk are 35, and minSdk is 24.
  • The kapt plugin is applied in app/build.gradle.
  • The ABI filter is arm64-v8a.
  • dji-sdk-v5-aircraft is an implementation dependency, and dji-sdk-v5-aircraft-provided is compileOnly.
  • The android-sdk-v5-uxsdk module is copied into the project, included in settings.gradle, and listed as a dependency.
  • dependencies.gradle exists and is applied at the bottom of the root build.gradle.
  • gradle.properties has all five UX SDK properties.
  • All permissions and USB features are in AndroidManifest.xml.
  • android:extractNativeLibs="true" is on the <application> tag.
  • Your real DJI app key is in the com.dji.sdk.API_KEY meta-data.
  • res/xml/accessory_filter.xml exists.
  • MyApplication.kt exists and is named in the manifest as android:name=".MyApplication".
  • You test on a physical arm64 device, not an emulator.

9. Troubleshooting

Duplicate class or libc++_shared.so conflict. Make sure the pickFirsts.add(...) rule from section 3 is in packaging.jniLibs.

A crash at startup in Helper.install(). Make sure Helper.install(this) is called in attachBaseContext, not in onCreate.

Registration fails (onRegisterFailure). Check your app key. Check that the INTERNET permission is declared. Check that your app’s package name is the one registered on the DJI developer portal.

Build error: “Unsupported class file major version”. Your Gradle JDK is not Java 17. Change it in Settings → Build Tools → Gradle → Gradle JDK.

Execution failed for task ':app:mergeNativeLibs'. The ABI filter is missing, or pickFirsts is not set. Review sections 2.4 and 3.

References