Skip to content

Repository files navigation

Sky Overhead

Tap a button to identify the aircraft flying overhead, using public OpenSky Network and ADSBDB data.

Sky Overhead reads your current location, queries live ADS-B traffic near you, ranks the candidates by how close they are to being directly overhead, and shows the best match enriched with route and registration details.

Sky Overhead screenshot

Download & install (Android)

Prebuilt Android APKs are published on the repository's Releases page, built automatically by GitHub Actions.

  1. Open the latest release and download app-release.apk (the universal build that works on any device). Advanced users can instead pick the smaller ABI-specific APK matching their phone (arm64-v8a, armeabi-v7a, or x86_64).
  2. On the phone, allow Install unknown apps for your browser or file manager when prompted.
  3. Open the downloaded APK and confirm installation.
  4. Launch the app and allow location permission so the observer position can be resolved.

iPhone: direct downloads are not available. Apple does not permit installing apps outside the App Store, so iOS requires building from source on a Mac (see below) or App Store distribution.

How it works

  1. Resolve the observer's position via device GPS (geolocator).
  2. Query OpenSky for aircraft states within a bounding box around you.
  3. Rank candidates by elevation angle, keeping those above a minimum elevation (default 18°) so only aircraft that are genuinely overhead are considered.
  4. Enrich the top match with callsign/route/registration data from ADSBDB.
  5. Present the result — or a friendly "Clear skies" message when nothing qualifies.

In the result card you can tap the aircraft type to open a Google search for that model, handy for reading up on an unfamiliar airframe.

Route plausibility

ADSBDB's route (origin → destination) is looked up by callsign alone, so a reused or stale flight number can return a route that has nothing to do with where the aircraft actually is. Sky Overhead sanity-checks each route against your observing position: it measures how far you are from the great-circle corridor between the two airports, and if that gap is implausibly large (over 300 km) the result card shows a caveat that the route may be inaccurate. Routes without airport coordinates are left unflagged.

Altitude: geometric vs. barometric

OpenSky reports two altitudes for each aircraft, and Sky Overhead shows both when they're available:

  • Altitude — the geometric (GPS) altitude, i.e. the aircraft's true height above mean sea level. This is what the app prefers for ranking and records, falling back to the barometric value only when GPS altitude is missing.
  • Baro alt. — the barometric (pressure) altitude. This is the reading the pilot sees on the instruments, derived from air pressure relative to a standard reference. It can differ from the geometric altitude by hundreds of metres depending on the local weather and pressure setting.

Collect & Medals

By default Sky Overhead simply identifies what's overhead and remembers nothing. Turn on Collector mode in Settings to opt in to a lightweight collector loop:

  • Logbook — every successful identification is saved as a sighting you can browse and revisit. Repeat identifications of the same aircraft within a short window are treated as duplicates and skipped, and you can delete any entry (swipe a row or use the delete action on its detail screen) to remove an accidental sighting and its stored data.
  • Collections — unique destinations, origins, airlines, aircraft types, manufacturers, registrations and countries you've spotted.
  • Medals — a tiered ace ladder (Cadet → Air Marshal) plus themed achievements like High Roller, Speed Demon, Right Overhead and Globe Trotter.
  • Stats — personal-best records (highest, fastest, farthest, closest), top-5 destinations and origins (each showing the airport code and full name), an activity chart, and a compass rose of where you look. A filter lets you hide dominant airports (e.g. your nearby home airport) from the top lists.

Unlocking something shows an instant toast on the Sky tab. Collector mode is fully opt-in: pausing stops new logging without touching your data, and turning it off deletes the stored sightings, returning the app to its identify-only default.

Sky Overhead screenshot 2

Observer location

On startup the app seeds the observer position with a hard-coded default of central Stockholm (59.3293, 18.0686, defined as kDefaultConfig in lib/src/state/config_provider.dart). This is just a placeholder shown in the location chip before any location is set — it is not derived from your device, IP, or locale. Replace it at runtime by tapping Use my location (device GPS) or Enter location (manual coordinates).

Project structure

lib/src/
  config/   App configuration (min elevation, search radius, endpoints).
  data/     HTTP transport + OpenSky/ADSBDB clients, aircraft & location services.
  domain/   Pure models, geospatial math (geo.dart), and ranking logic.
  state/    Riverpod controllers (identify, location) and providers.
  ui/       Screens and widgets (home screen, result card, location bar).

Tech stack

  • Flutter (Material 3) — Dart SDK ^3.12.0
  • flutter_riverpod — state management
  • http — REST calls to OpenSky and ADSBDB
  • geolocator — device location with permission handling
  • mocktail + integration_test — unit and end-to-end tests

Getting started

Fetch dependencies:

flutter pub get

Run on a connected device or emulator:

flutter run                # auto-selects a device
flutter run -d <deviceId>  # target a specific device (see: flutter devices)

Running on a physical Android phone

  1. Enable Developer options on the phone: Settings → About phone → tap Build number seven times.

  2. Enable USB debugging: Settings → System → Developer options → USB debugging on.

  3. Connect the phone to the computer with a data-capable USB cable (charge-only cables will not work). Plug directly into the machine rather than through a hub or dock.

  4. Set the USB mode on the phone to File transfer / MTP via the USB notification — some phones default to charge-only, which blocks the data connection.

  5. Authorize the computer: unlock the phone and accept the Allow USB debugging? prompt (tick Always allow from this computer to skip it next time).

  6. Verify the device is detected:

    # platform-tools ships with the Android SDK, e.g.
    #   macOS:  $HOME/Library/Android/sdk/platform-tools
    adb devices -l     # should list your phone with state "device"
    flutter devices    # should show the phone

    If it shows unauthorized, re-accept the on-phone prompt. If it does not appear at all, the connection is physical — try another cable/port and re-check the USB mode.

  7. Build, install, and launch on the phone:

    flutter run -d <deviceId>   # deviceId from `flutter devices`, e.g. 56041FDCH00CDN

    Flutter builds the debug APK, installs it, and starts a live debug session (hot reload with r, hot restart with R). The app also stays installed in the app drawer after you quit the session.

On first launch the app will ask for location permission — allow it so the observer position can be resolved.

Running on a physical iOS phone

Deploying to an iPhone requires a Mac with Xcode installed (plus its command-line tools and CocoaPods).

  1. Sign in with an Apple ID in Xcode: Xcode → Settings → Accounts → add your Apple ID. A free Apple ID works for on-device development (with a 7-day signing validity); a paid Apple Developer account removes that limit.

  2. Set the signing team for the app. Either open the iOS project in Xcode:

    open ios/Runner.xcworkspace

    then select the Runner target → Signing & Capabilities → pick your Team and let Xcode manage signing. Xcode will assign a unique bundle identifier if the default is taken.

  3. Connect the iPhone with a cable and trust the computer: on the phone, tap Trust on the Trust This Computer? prompt and enter your passcode.

  4. Enable Developer Mode (iOS 16+): Settings → Privacy & Security → Developer Mode → on, then restart the phone when prompted.

  5. Verify the device is detected:

    flutter devices    # should list your iPhone
  6. Build, install, and launch on the phone:

    flutter run -d <deviceId>   # deviceId from `flutter devices`

    The first build is slower (CocoaPods + native compile) and starts a live debug session (hot reload with r, hot restart with R).

  7. Trust the developer certificate on the phone the first time you launch a build signed with a personal team: Settings → General → VPN & Device Management → tap your developer profile → Trust. Then reopen the app.

On first launch the app will ask for location permission — allow it so the observer position can be resolved.

Testing

flutter analyze lib test integration_test
flutter test                   # unit and widget tests
flutter test integration_test  # end-to-end integration test

Release signing

Release APKs are signed with a persistent keystore so that updates can be installed over previous versions without conflicts. The signing key is stored as GitHub Actions secrets and decoded at build time.

Repository secrets required (Settings → Secrets and variables → Actions):

Secret Value
KEYSTORE_BASE64 The release keystore, base64-encoded: base64 -i android/release-keystore.jks
KEYSTORE_PASSWORD Password for both the keystore and the key alias

The Gradle build reads android/key.properties when present; the workflow creates that file from secrets before building. Locally, if key.properties does not exist, the build falls back to the debug signing key.

Generating a new keystore (only needed if the original is lost):

keytool -genkey -v \
  -keystore android/release-keystore.jks \
  -keyalg RSA -keysize 2048 -validity 10000 \
  -alias release

Important: If you replace the keystore, users must uninstall the old app before installing a new build (the signatures will no longer match).

Permissions

The app requests location access at first launch to determine the observer position, and requires internet access for the OpenSky and ADSBDB APIs. Both are declared in the Android and iOS platform manifests.

Data sources

Related project

The elevation-angle geometry and candidate-ranking logic mirror the aircraft_id Erlang library, which answers the same "which aircraft is overhead?" question as an embeddable, dependency-free library.

License

MPL-2.0.

About

Identify the aircraft flying overhead

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages