Files
tajniak81andClaude Opus 4.8 58655531f0 Give the Fly App its own identity instead of the DJI sample's
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>
2026-07-21 21:11:17 +02:00

103 lines
4.6 KiB
Markdown

# 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
1. **Flutter** (stable) and **Android SDK** with a connected **Android device**
(the DJI SDK does not work on emulators).
2. 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.
3. 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.
1. 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**
2. Copy the generated **App Key**.
3. 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`
```properties
PILOTVAULT_FLY_API_KEY=your_real_app_key_here
```
For a one-off build you can pass it inline instead:
```bash
flutter build apk --debug -PPILOTVAULT_FLY_API_KEY=your_real_app_key_here
```
The key is injected into `AndroidManifest.xml` at build time via a
`manifestPlaceholder` (`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.
## Run
```bash
flutter pub get
flutter run # device must be plugged in
# or just build the APK:
flutter build apk --debug
```
## Using the app
1. Launch it and grant the location / phone / mic permissions it requests.
2. Tap **Register app** — needs internet on first run; status turns green on
success.
3. 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**.
4. 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=true` is required — the SDK still uses legacy support
libraries.
- The native `.so` files are kept unstripped and de-duplicated via the
`packaging { }` block in `android/app/build.gradle`; only `armeabi-v7a` and
`arm64-v8a` ABIs 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).