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>
This commit is contained in:
tajniak81
2026-07-21 21:11:17 +02:00
co-authored by Claude Opus 4.8
parent 6ef15a9e80
commit 58655531f0
18 changed files with 66 additions and 30 deletions
+16 -4
View File
@@ -46,17 +46,29 @@ SDK registration will fail without a valid App Key bound to this app's
application id. application id.
1. Sign in at <https://developer.dji.com/user/apps/> and create a new app. 1. Sign in at <https://developer.dji.com/user/apps/> and create a new app.
- **Package name** must be exactly: `com.dji.flutter.dji_msdk_sample` - **Package name** must be exactly: `com.pilotvault.flyapp`
- SDK: **Mobile SDK** - SDK: **Mobile SDK**
2. Copy the generated **App Key**. 2. Copy the generated **App Key**.
3. Paste it into [`android/gradle.properties`](android/gradle.properties): 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 ```properties
DJI_API_KEY=your_real_app_key_here 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 The key is injected into `AndroidManifest.xml` at build time via a
`manifestPlaceholder` (`com.dji.sdk.API_KEY`). `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 ## Run
+20 -5
View File
@@ -6,7 +6,7 @@ plugins {
} }
android { android {
namespace = "com.dji.flutter.dji_msdk_sample" namespace = "com.pilotvault.flyapp"
compileSdk = 35 compileSdk = 35
// DJI MSDK V4 ships prebuilt native (.so) libraries; pin a known-good NDK. // DJI MSDK V4 ships prebuilt native (.so) libraries; pin a known-good NDK.
ndkVersion = flutter.ndkVersion ndkVersion = flutter.ndkVersion
@@ -21,7 +21,7 @@ android {
} }
defaultConfig { defaultConfig {
applicationId = "com.dji.flutter.dji_msdk_sample" applicationId = "com.pilotvault.flyapp"
// DJI MSDK V4 requires Android 5.0+ (API 21). // DJI MSDK V4 requires Android 5.0+ (API 21).
minSdkVersion = flutter.minSdkVersion minSdkVersion = flutter.minSdkVersion
targetSdk = 34 targetSdk = 34
@@ -37,9 +37,24 @@ android {
} }
// The DJI App Key is injected into AndroidManifest.xml at build time. // The DJI App Key is injected into AndroidManifest.xml at build time.
// Set DJI_API_KEY in android/gradle.properties (or pass -PDJI_API_KEY=...). // It is deliberately not stored in the repo — see android/gradle.properties
manifestPlaceholders["DJI_API_KEY"] = // for where to put it (~/.gradle/gradle.properties, or -P on the command
(project.findProperty("DJI_API_KEY") ?: "PASTE_YOUR_DJI_APP_KEY_HERE") // line). Warn loudly when it is missing: the build still succeeds, but the
// resulting APK fails DJI SDK registration once it is on the aircraft.
// println, not logger.warn: `flutter build` filters Gradle's warn-level
// output, so a logger.warn here is never seen by the person building.
def djiAppKey = project.findProperty("PILOTVAULT_FLY_API_KEY")
if (!djiAppKey) {
println(
"\n**************************************************************\n" +
"WARNING: PILOTVAULT_FLY_API_KEY is not set.\n" +
"The APK will build, but DJI SDK registration will FAIL at\n" +
"runtime. Set the key in ~/.gradle/gradle.properties - see\n" +
"android/gradle.properties for details.\n" +
"**************************************************************\n")
}
manifestPlaceholders["PILOTVAULT_FLY_API_KEY"] =
(djiAppKey ?: "PASTE_YOUR_DJI_APP_KEY_HERE")
} }
buildTypes { buildTypes {
@@ -48,10 +48,12 @@
android:name="org.apache.http.legacy" android:name="org.apache.http.legacy"
android:required="false" /> android:required="false" />
<!-- DJI App Key. The value is injected from gradle.properties (DJI_API_KEY). --> <!-- DJI App Key. The value is injected from gradle.properties
(PILOTVAULT_FLY_API_KEY). The meta-data name below is fixed by the
DJI SDK and must stay "com.dji.sdk.API_KEY". -->
<meta-data <meta-data
android:name="com.dji.sdk.API_KEY" android:name="com.dji.sdk.API_KEY"
android:value="${DJI_API_KEY}" /> android:value="${PILOTVAULT_FLY_API_KEY}" />
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
@@ -1,4 +1,4 @@
package com.dji.flutter.dji_msdk_sample package com.pilotvault.flyapp
import dji.common.error.DJIError import dji.common.error.DJIError
import dji.common.useraccount.UserAccountState import dji.common.useraccount.UserAccountState
@@ -1,4 +1,4 @@
package com.dji.flutter.dji_msdk_sample package com.pilotvault.flyapp
import dji.common.camera.ExposureSettings import dji.common.camera.ExposureSettings
import dji.common.camera.SettingsDefinitions import dji.common.camera.SettingsDefinitions
@@ -1,4 +1,4 @@
package com.dji.flutter.dji_msdk_sample package com.pilotvault.flyapp
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
@@ -1,4 +1,4 @@
package com.dji.flutter.dji_msdk_sample package com.pilotvault.flyapp
import android.content.Context import android.content.Context
import android.os.Handler import android.os.Handler
@@ -1,4 +1,4 @@
package com.dji.flutter.dji_msdk_sample package com.pilotvault.flyapp
import android.content.Context import android.content.Context
import android.graphics.SurfaceTexture import android.graphics.SurfaceTexture
@@ -1,4 +1,4 @@
package com.dji.flutter.dji_msdk_sample package com.pilotvault.flyapp
import dji.common.flightcontroller.FlightControllerState import dji.common.flightcontroller.FlightControllerState
import dji.sdk.base.BaseProduct import dji.sdk.base.BaseProduct
@@ -1,4 +1,4 @@
package com.dji.flutter.dji_msdk_sample package com.pilotvault.flyapp
import dji.common.gimbal.Rotation import dji.common.gimbal.Rotation
import dji.common.gimbal.RotationMode import dji.common.gimbal.RotationMode
@@ -1,4 +1,4 @@
package com.dji.flutter.dji_msdk_sample package com.pilotvault.flyapp
import android.Manifest import android.Manifest
import android.content.pm.PackageManager import android.content.pm.PackageManager
@@ -1,4 +1,4 @@
package com.dji.flutter.dji_msdk_sample package com.pilotvault.flyapp
import android.graphics.Bitmap import android.graphics.Bitmap
import dji.common.camera.SettingsDefinitions import dji.common.camera.SettingsDefinitions
@@ -1,4 +1,4 @@
package com.dji.flutter.dji_msdk_sample package com.pilotvault.flyapp
import android.graphics.RectF import android.graphics.RectF
import dji.common.mission.activetrack.ActiveTrackMission import dji.common.mission.activetrack.ActiveTrackMission
+12 -5
View File
@@ -3,11 +3,18 @@ android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
# DJI Mobile SDK # DJI Mobile SDK
# Register the application id "com.dji.flutter.dji_msdk_sample" at # Register the application id "com.pilotvault.flyapp" at
# https://developer.dji.com/user/apps/ to obtain an App Key, then paste it below. # https://developer.dji.com/user/apps/ to obtain an App Key. The key is injected
# This value is injected into AndroidManifest.xml via a manifestPlaceholder. # into AndroidManifest.xml via a manifestPlaceholder.
# DJI_API_KEY=PASTE_YOUR_DJI_APP_KEY_HERE #
DJI_API_KEY=e427e182254c91013ba591e9 # The key is deliberately NOT stored in this file, because this file is tracked
# in git. Put it in your user-global Gradle properties instead, which Gradle
# merges into every build:
#
# ~/.gradle/gradle.properties (Windows: %USERPROFILE%\.gradle\)
# PILOTVAULT_FLY_API_KEY=your_app_key_here
#
# Or pass it per-invocation: -PPILOTVAULT_FLY_API_KEY=your_app_key_here
# This builtInKotlin flag was added automatically by Flutter migrator # This builtInKotlin flag was added automatically by Flutter migrator
android.builtInKotlin=false android.builtInKotlin=false
# This newDsl flag was added automatically by Flutter migrator # This newDsl flag was added automatically by Flutter migrator
@@ -1,4 +1,4 @@
name: dji_msdk_sample name: pilotvault_fly
description: "DJI Mobile SDK V4 sample app built with Flutter" description: "DJI Mobile SDK V4 sample app built with Flutter"
# The following line prevents the package from being accidentally published to # The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages. # pub.dev using `flutter pub publish`. This is preferred for private packages.
+1 -1
View File
@@ -82,7 +82,7 @@ class _MapPageState extends State<MapPage> {
children: <Widget>[ children: <Widget>[
TileLayer( TileLayer(
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
userAgentPackageName: 'com.dji.flutter.dji_msdk_sample', userAgentPackageName: 'com.pilotvault.flyapp',
), ),
if (_waypoints.length >= 2) if (_waypoints.length >= 2)
PolylineLayer<Object>(polylines: <Polyline<Object>>[ PolylineLayer<Object>(polylines: <Polyline<Object>>[
+1 -1
View File
@@ -1,4 +1,4 @@
name: dji_msdk_sample name: pilotvault_fly
description: "PilotVault Fly App — drone telemetry client built with Flutter (DJI Mobile SDK V4)" description: "PilotVault Fly App — drone telemetry client built with Flutter (DJI Mobile SDK V4)"
# The following line prevents the package from being accidentally published to # The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages. # pub.dev using `flutter pub publish`. This is preferred for private packages.
+1 -1
View File
@@ -1,6 +1,6 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:dji_msdk_sample/main.dart'; import 'package:pilotvault_fly/main.dart';
void main() { void main() {
testWidgets('Shows the login screen when signed out', testWidgets('Shows the login screen when signed out',