The app still shipped under the identity of the DJI MSDK Flutter sample it was started from, so every install, log line and crash report named a DJI sample rather than PilotVault. Rename both namespaces: Android com.dji.flutter.dji_msdk_sample -> com.pilotvault.flyapp Dart dji_msdk_sample -> pilotvault_fly The Kotlin sources move under com/pilotvault/flyapp to match. The manifest's meta-data name stays com.dji.sdk.API_KEY — that string is fixed by the SDK's own lookup and is not ours to rename. A DJI App Key is bound to the application id, so the old key died with the old id and a new one was registered against com.pilotvault.flyapp. That forced the key to be touched anyway, so stop committing it: the Gradle property becomes PILOTVAULT_FLY_API_KEY and now lives in the developer's ~/.gradle/gradle.properties, which Gradle merges into every build. android/gradle.properties keeps the build flags — gitignoring it wholesale would have taken useAndroidX and the Flutter migrator flags out of version control with it — and documents where the key belongs. A missing key prints a banner rather than silently baking the placeholder into an APK that cannot register, which otherwise only surfaces as a registration failure once the tablet is out at the aircraft. That warning uses println because `flutter build` filters Gradle's warn-level output. The rename means Android treats this as a new app: uninstall com.dji.flutter.dji_msdk_sample before installing, or both will sit on the tablet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.6 KiB
DJI MSDK Sample (Flutter)
A sample app demonstrating how to drive the DJI Mobile SDK V4 from Flutter.
DJI does not ship an official Flutter SDK — the Mobile SDK is a native Android/iOS library. This project therefore puts a Flutter UI on top of a thin native Android (Kotlin) bridge that talks to the DJI MSDK over platform channels. It covers the core "sample app" flow: SDK registration, product connection, and live telemetry (battery, GPS, flight status).
Android only. The DJI MSDK V4 native libraries here are wired up for Android. iOS would need a parallel Swift/Obj-C bridge (and a Mac to build).
Architecture
┌────────────────────────┐ platform channels ┌─────────────────────────┐
│ Flutter (Dart) │ dji_msdk/methods (MethodChannel)│ Android (Kotlin) │
│ lib/main.dart │ ───────────────────────────────▶ │ DjiSdkBridge.kt │
│ lib/dji_service.dart │ dji_msdk/events (EventChannel) │ └─ DJI Mobile SDK V4 │
│ │ ◀─────────────────────────────── │ DjiApplication.kt │
└────────────────────────┘ └─────────────────────────┘
| File | Responsibility |
|---|---|
lib/dji_service.dart |
Dart wrapper over the method/event channels |
lib/main.dart |
UI: registration / connection / telemetry cards |
android/app/.../DjiApplication.kt |
Installs the Secneo Helper (required by MSDK V4) |
android/app/.../MainActivity.kt |
Hosts the bridge, requests runtime permissions |
android/app/.../DjiSdkBridge.kt |
Registration, product lifecycle, telemetry callbacks |
android/app/build.gradle |
DJI deps, native-lib packaging, multidex, ABI filters |
Prerequisites
- Flutter (stable) and Android SDK with a connected Android device (the DJI SDK does not work on emulators).
- A DJI drone + remote controller supported by MSDK V4 (Phantom 4, Mavic 2 / Air / Mini 1, Spark, Inspire 2, etc.). The RC connects to the phone over USB.
- A DJI App Key (see below).
Set your DJI App Key
SDK registration will fail without a valid App Key bound to this app's application id.
-
Sign in at https://developer.dji.com/user/apps/ and create a new app.
- Package name must be exactly:
com.pilotvault.flyapp - SDK: Mobile SDK
- Package name must be exactly:
-
Copy the generated App Key.
-
Put it in your user-global Gradle properties — not in the repo. Gradle merges this file into every build, so the key stays off version control:
- Linux/macOS:
~/.gradle/gradle.properties - Windows:
%USERPROFILE%\.gradle\gradle.properties
PILOTVAULT_FLY_API_KEY=your_real_app_key_hereFor a one-off build you can pass it inline instead:
flutter build apk --debug -PPILOTVAULT_FLY_API_KEY=your_real_app_key_hereThe key is injected into
AndroidManifest.xmlat build time via amanifestPlaceholder(com.dji.sdk.API_KEY). If it is missing the build still succeeds but prints a warning, and SDK registration fails on the aircraft — so watch for that warning. - Linux/macOS:
Run
flutter pub get
flutter run # device must be plugged in
# or just build the APK:
flutter build apk --debug
Using the app
- Launch it and grant the location / phone / mic permissions it requests.
- Tap Register app — needs internet on first run; status turns green on success.
- Connect the drone's remote controller to the phone over USB and power on the aircraft. The app auto-starts a connection on successful registration; you can also tap Connect to product.
- Once an aircraft connects, the Telemetry card streams battery %, GPS satellite count, flight mode, altitude, and position.
Notes & gotchas
- MSDK V4 version is pinned to
4.18(com.dji:dji-sdk/dji-sdk-provided). android.enableJetifier=trueis required — the SDK still uses legacy support libraries.- The native
.sofiles are kept unstripped and de-duplicated via thepackaging { }block inandroid/app/build.gradle; onlyarmeabi-v7aandarm64-v8aABIs are bundled (the only ABIs DJI provides). - This sample uses the core SDK, not the DJI UX SDK (its native UI widgets don't embed cleanly in Flutter).