Skip to content

Sync upstream location 10.x and keep STEM headless fixes - #6

Merged
DecSmith42 merged 164 commits into
mainfrom
sync-upstream-master
Aug 5, 2026
Merged

DecSmith42 merged 164 commits into
mainfrom
sync-upstream-master

Conversation

@bhavik-dodia-aub

Copy link
Copy Markdown
Collaborator
  • Sync with upstream flutter_location (incl. modern Android/iOS rewrite and SPM-ready layout)
  • Keep STEM behaviour: SharedEngine-only binding and activity-independent location for CarPlay / Android Auto / headless
  • Drop fork-only work already covered upstream (e.g. UIAlertController / null-safety)

sharkwedy and others added 30 commits October 18, 2025 18:49
…nitialValue

`value:` was deprecated after Flutter 3.33 in favour of `initialValue:`.
Restores a clean `flutter analyze --fatal-infos` across all packages.
Updates dev dependencies to their latest majors across location,
location_platform_interface and location_web. leancode_lint 24 flagged
one new lint (unnecessary_async on Location.getLocation), fixed here so
it matches its sibling forwarders.
The example's root build.gradle declared no repositories for its
subprojects, so Gradle could only resolve dependencies from Flutter's
storage repo and failed to find AndroidX transitive artifacts
(androidx.core, window-java, exifinterface, relinker). Adding the
google()/mavenCentral() repositories lets the example build again.
… 12.1.2

Flutter 3.44 pulls androidx.core 1.17.0, which requires AGP >= 8.9.1, and
Flutter warns that support for AGP < 8.11.1 and Kotlin < 2.2.20 will be
dropped. Bumps the plugin and example toolchain accordingly; ktlint-gradle
goes to 12.1.2 for Kotlin 2.2 compatibility. Example builds cleanly with
no remaining toolchain warnings.
… deps

Aligns the plugin with Flutter 3.44 (compileSdk/targetSdk 36) and bumps
core-ktx to 1.16.0. androidx.annotation stays at 1.8.1 to satisfy Gradle
consistent resolution with the transitive graph pulled by core 1.16.0.
Runs Flutter 3.44's automatic project migrations on the example:
- iOS moves to the UIScene app lifecycle (UIApplicationSceneManifest,
  FlutterSceneDelegate, implicit-engine AppDelegate) and an iOS 13 floor.
- Android gains the builtInKotlin/newDsl migrator flags.
Quiets the build-time deprecation warnings and keeps the example on
current templates. Background location mode is preserved.
Converts LocationPlugin, MethodCallHandlerImpl and StreamHandlerImpl to
idiomatic Kotlin and moves all Kotlin sources under src/main/kotlin so
Flutter's plugin loader resolves the main class. FlutterLocation stays
Java for now (converted next).

- Null-safe teardown in LocationPlugin.dispose()/detachActivity() so a
  detach after the engine already detached no longer throws NPE (Lyokone#1041).
- MethodCallHandlerImpl guards a null location with an error instead of
  crashing when a call arrives before the service is bound.
- Renames the notification default consts to SCREAMING_SNAKE_CASE to
  satisfy ktlint 12.
…ion APIs

Converts the last Java source, FlutterLocation, to Kotlin and moves off the
deprecated FusedLocationProvider APIs:

- LocationRequest is now built with LocationRequest.Builder and
  com.google.android.gms.location.Priority constants instead of the
  deprecated create()/setPriority()/PRIORITY_* API (Lyokone#1019, Lyokone#1023, Lyokone#1035).
- LocationResult.lastLocation is null-checked (it is now nullable).
- Mock detection uses Location.isMock on API 31+ and falls back to the
  deprecated isFromMockProvider below it (Lyokone#1016).
- Drops the dead pre-API-21 branches (minSdk is 21).

Behaviour is otherwise preserved. Example builds cleanly and ktlint passes.
Android 14 (API 34) throws when a foreground service starts without
declaring a type. Uses ServiceCompat.startForeground with
FOREGROUND_SERVICE_TYPE_LOCATION on API 29+ and declares the
FOREGROUND_SERVICE / FOREGROUND_SERVICE_LOCATION permissions in the plugin
manifest so background location works on modern Android (Lyokone#970).
Replaces the Objective-C LocationPlugin (duplicated across ios/, macos/
and an unused darwin/) with a single Swift implementation under darwin/,
wired through Flutter's sharedDarwinSource so both platforms compile the
same file. A single darwin/location.podspec replaces the two stub
podspecs (which still read "A new flutter plugin project" / "Your
Company") and sets real metadata, iOS 12 / macOS 10.15 floors and
swift_version 5.0.

Modernizations while porting:
- Uses the instance authorizationStatus and locationManagerDidChangeAuthorization
  on iOS 14 / macOS 11+, falling back to the deprecated class APIs below that.
- Drops UIAlertView (removed from modern SDKs) in favour of opening Settings.
- Replaces the NSException hard-crash on a missing usage description with a
  logged warning, so a misconfigured Info.plist no longer crashes at launch
  (Lyokone#1040, Lyokone#1042).
- Guards every FlutterResult callback against double or nil invocation.

Both example apps build for the iOS simulator and macOS.
Flutter 3.44 migrates the macOS example: minimum deployment target 10.15,
@NSApplicationMain to @main, applicationSupportsSecureRestorableState, and
the Xcode-compatibility pbxproj/scheme updates. Applied by building the
macOS example against the new Swift plugin.
Adds federated desktop support to the location plugin:

- Windows: a C++/WinRT plugin backed by Windows.Devices.Geolocation.
  getLocation and the location stream use Geolocator, permission maps to
  RequestAccessAsync, and results are marshalled back to the platform
  thread via apartment_context. Background mode is unsupported.
- Linux: a GObject plugin talking to GeoClue2 over GDBus (GIO), so no
  extra runtime dependency beyond glib/gio. Implements getLocation (answered
  on the next LocationUpdated), the stream, and service availability.

Both are registered in the plugin pubspec. They compile-verify in CI
(added separately) but still need on-device runtime testing.
Scaffolds the example's Linux and Windows runners and adds a
location-desktop workflow that compiles the example on ubuntu-latest and
windows-latest, giving the new native plugins CI coverage. Also adds a
macOS build job to location-prepare and drops the stale clang-format step
that pointed at the now-removed Objective-C ios/ sources.
The prepare-flutter job pinned Flutter 3.27.x, which predates the
DropdownButtonFormField.initialValue API the example now uses, and the
android/ios jobs referenced an undefined matrix version. Switches every
job to channel: stable and the latest Melos.
…S) location

Android (Lyokone#990/Lyokone#991): request both ACCESS_FINE_LOCATION and
ACCESS_COARSE_LOCATION, treat approximate-only grants as granted in
checkPermissions()/shouldShowRequestPermissionRationale() and in the
permission-result handler, so choosing "Approximate" no longer reports
denied. NMEA/MSL altitude is only registered when precise access is held.

iOS (Lyokone#984): when precise location is off the system delivers a single
reduced-accuracy update; skip the stale-location guard in that case so
getLocation still resolves.
C++/WinRT co_await on IAsyncOperation needs the C++20 <coroutine> header;
under C++17 MSVC fell back to the now-removed <experimental/coroutine> and
failed to compile. Sets the plugin target to C++20.
…able

Adds a supported-platforms table (Android, iOS, macOS, web, Windows, Linux),
Windows and Linux setup notes, and bumps the pubspec install snippet to ^8.0.0.
…e#1047)

Moves the shared Swift source into a SwiftPM package layout
(darwin/location/Sources/location) and adds Package.swift, so the plugin
is consumable via Swift Package Manager. The podspec is updated to the new
path and CocoaPods keeps working, so both integration paths are supported.

Verified: the iOS and macOS example apps build both with SwiftPM enabled and
with the classic CocoaPods flow.
MSVC rejects co_await inside a catch block. Records the error message in
the handler and responds after the try/catch instead.
Flutter's generated plugin registrant includes <location/location_plugin.h>
and calls LocationPluginRegisterWithRegistrar, but the plugin exposed the
_c_api variant. Consolidates the class and the C entry point into
location_plugin.cpp behind include/location/location_plugin.h with the
expected LocationPluginRegisterWithRegistrar symbol.
Major maintenance release: Kotlin/Swift rewrites, Windows and Linux support,
Swift Package Manager, modernized toolchain and a batch of issue fixes. See
CHANGELOG.md for the full list.
…nux, SPM

Full modernization: Kotlin + Swift rewrite, dependency bumps, Windows/Linux support
CLLocationManager.locationServicesEnabled() can block the calling thread
while location services start up. Apple warns against calling it on the
main thread; doing so triggered the "UI unresponsiveness" runtime warning
and could hang the app (Lyokone#782, Lyokone#789, Lyokone#909, Lyokone#1004, Lyokone#1027).

Run the check on a background queue and deliver the result back on the
main thread, where the CLLocationManager instance and the FlutterResult
must be used. getLocation, serviceEnabled, requestService and
changeSettings no longer stall the UI.
…ices-off-main-thread

fix(darwin): move locationServicesEnabled off the main thread
Apple requires third-party SDKs to ship a PrivacyInfo.xcprivacy declaring
their data use and any required-reason API access. This plugin only bridges
CoreLocation to the host app: it transmits nothing off-device, uses no
required-reason APIs, and does no tracking. The manifest declares exactly
that (all empty / false).

Bundled through both build systems: resource_bundles in the podspec for
CocoaPods, and a processed resource in Package.swift for Swift Package
Manager.

Fixes Lyokone#947
…fest

feat(darwin): add Apple privacy manifest
getLocation() could never complete when Core Location delivered fewer than
three updates. The stale-location guard swallowed the first two updates by
count to skip the cached "last known" fix, so a one-shot getLocation() only
resolved on the third update. When few updates arrive — a static iOS-simulator
"Custom Location" (Lyokone#657, Lyokone#955, Lyokone#1005, Lyokone#1013), reduced accuracy which emits a
single update (Lyokone#984), or a sparse first fix (Lyokone#798) — the Dart Future hung
forever with no error.

Skip stale fixes by age instead of by count: deliver the first update whose
timestamp is recent, which resolves getLocation() immediately while still
ignoring the instantly-delivered cached location. Verified on an iOS simulator
with a static Custom Location — an integration test that hangs (20s timeout)
on the old code passes on the new code.

Fixes Lyokone#798, fixes Lyokone#955, fixes Lyokone#1005, fixes Lyokone#657, fixes Lyokone#1013
…tale-guard-hang

fix(darwin): stop getLocation hanging on sparse location updates
The feature docs described an API that was never shipped (the abandoned v5
redesign): getLocation({LocationSettings? settings}), setLocationSettings(...),
a top-level getLocation()/onLocationChanged({inBackground}), getPermissionStatus,
requestPermissions, isGPSEnabled/isNetworkEnabled, updateBackgroundNotification
and the authorizedAlways/authorizedWhenInUse/notDetermined statuses. None of
these exist in the published package, so every code sample on the docs site
failed to compile.

Rewrite the examples and signatures against the real API, using package source
and the example app as the source of truth:

- getLocation() takes no arguments; configure via changeSettings.
- onLocationChanged is a Stream getter; background is enableBackgroundMode.
- Settings are global via changeSettings(accuracy/interval/distanceFilter/
  pausesLocationUpdatesAutomatically), not setLocationSettings.
- Permissions use hasPermission()/requestPermission() and the
  granted/grantedLimited/denied/deniedForever statuses.
- Services use serviceEnabled()/requestService().
- Notification uses changeNotificationOptions (fixes a stray
  changeBackgroundOptions call).
- All snippets call the API on a Location instance; bump getting-started to
  location: ^9.0.0.
Lyokone and others added 5 commits July 23, 2026 15:50
docs: revamp root README into a landing page
…tion

Upstream 10.x rewrote Android in Kotlin and binds the location service to an
Activity again. Restore the STEMLogic fork behaviors that upstream does not
cover: only attach against SharedEngine (avoid Firebase's background engine),
bind the service from application context, and keep fused location alive when
no Activity is present for headless / vehicle platforms.
Comment thread .github/workflows/deploy-web-demo.yaml Outdated
uses: actions/checkout@v4

- name: Set up Flutter
uses: subosito/flutter-action@v2
Comment thread .github/workflows/location-desktop.yaml Outdated
Comment on lines +10 to +37
name: Linux
runs-on: ubuntu-latest

steps:
- name: Clone repository
uses: actions/checkout@v4

- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable

- name: Install Linux build dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev

- name: Set up Melos
run: dart pub global activate melos

- name: melos bootstrap
run: melos bootstrap

- name: Build example app
working-directory: packages/location/example
run: flutter build linux --debug

build-windows:
Comment thread .github/workflows/location-desktop.yaml Outdated
uses: actions/checkout@v4

- name: Set up Flutter
uses: subosito/flutter-action@v2
Comment thread .github/workflows/location-desktop.yaml Outdated
Comment on lines +38 to +58
name: Windows
runs-on: windows-latest

steps:
- name: Clone repository
uses: actions/checkout@v4

- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable

- name: Set up Melos
run: dart pub global activate melos

- name: melos bootstrap
run: melos bootstrap

- name: Build example app
working-directory: packages/location/example
run: flutter build windows --debug
Comment thread .github/workflows/location-desktop.yaml Outdated
uses: actions/checkout@v4

- name: Set up Flutter
uses: subosito/flutter-action@v2
Comment thread .github/workflows/location-prepare.yaml Outdated
Comment thread .github/workflows/location-prepare.yaml Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Syncs the fork with upstream Location 10.x while retaining SharedEngine/headless behavior and adding desktop support.

Changes:

  • Modernizes Android and shared Darwin implementations.
  • Adds Linux/Windows plugins and example runners.
  • Expands APIs, documentation, tests, and CI for new platforms and features.

Reviewed changes

Copilot reviewed 116 out of 119 changed files in this pull request and generated 19 comments.

Show a summary per file
File Description
README.md Refreshes project overview and quick start.
packages/location/windows/location_plugin.cpp Implements Windows location support.
packages/location/windows/include/location/location_plugin.h Declares Windows plugin registration.
packages/location/windows/CMakeLists.txt Configures the Windows plugin build.
packages/location/test/location_test.mocks.dart Regenerates Location mocks.
packages/location/test/location_test.dart Tests last-known-location delegation.
packages/location/README.md Documents platforms and expanded API.
packages/location/pubspec.yaml Bumps version and registers desktop/Darwin platforms.
packages/location/macos/location.podspec Removes obsolete macOS podspec.
packages/location/macos/Classes/LocationPlugin.h Removes obsolete macOS header.
packages/location/linux/location_plugin.cc Implements Linux GeoClue support.
packages/location/linux/include/location/location_plugin.h Declares Linux plugin registration.
packages/location/linux/CMakeLists.txt Configures the Linux plugin build.
packages/location/lib/location.dart Exposes expanded platform APIs.
packages/location/ios/location.podspec Removes obsolete iOS podspec.
packages/location/ios/Classes/LocationPlugin.h Removes obsolete iOS header.
packages/location/ios/Assets/.gitkeep Retains the iOS assets directory.
packages/location/darwin/location/Sources/location/LocationPlugin.swift Provides shared Apple implementation.
packages/location/darwin/location/Sources/location/PrivacyInfo.xcprivacy Adds Apple privacy metadata.
packages/location/darwin/location/Package.swift Adds Swift Package support.
packages/location/darwin/location/.gitignore Ignores SwiftPM artifacts.
packages/location/darwin/location.podspec Adds shared Darwin CocoaPods support.
packages/location/darwin/Classes/LocationPlugin.h Removes obsolete Darwin header.
packages/location/android/src/main/kotlin/com/lyokone/location/FlutterLocation.kt Rewrites Android location handling.
packages/location/android/src/main/kotlin/com/lyokone/location/FlutterLocationService.kt Rewrites Android foreground service handling.
packages/location/android/src/main/kotlin/com/lyokone/location/StreamHandlerImpl.kt Implements Android stream dispatch.
packages/location/android/src/main/kotlin/com/lyokone/location/MethodCallHandlerImpl.kt Implements Android method dispatch.
packages/location/android/src/main/kotlin/com/lyokone/location/LocationPlugin.kt Adds SharedEngine-aware plugin binding.
packages/location/android/src/main/java/com/lyokone/location/StreamHandlerImpl.java Removes legacy Java stream handler.
packages/location/android/src/main/java/com/lyokone/location/MethodCallHandlerImpl.java Removes legacy Java method handler.
packages/location/android/src/main/java/com/lyokone/location/LocationPlugin.java Removes legacy Java plugin.
packages/location/android/src/main/java/com/lyokone/location/FlutterLocationService.kt Removes old service location.
packages/location/android/src/main/java/com/lyokone/location/FlutterLocation.java Removes old Java location implementation.
packages/location/android/src/main/AndroidManifest.xml Updates Android service permissions/configuration.
packages/location/android/build.gradle Modernizes Android and Kotlin builds.
packages/location/example/windows/runner/win32_window.h Adds Windows window abstraction.
packages/location/example/windows/runner/win32_window.cpp Implements the Windows window abstraction.
packages/location/example/windows/runner/utils.h Declares Windows runner utilities.
packages/location/example/windows/runner/utils.cpp Implements Windows runner utilities.
packages/location/example/windows/runner/Runner.rc Adds Windows application resources.
packages/location/example/windows/runner/runner.exe.manifest Adds Windows compatibility metadata.
packages/location/example/windows/runner/resource.h Defines Windows resource identifiers.
packages/location/example/windows/runner/main.cpp Adds Windows runner entry point.
packages/location/example/windows/runner/flutter_window.h Declares the Flutter host window.
packages/location/example/windows/runner/flutter_window.cpp Implements the Flutter host window.
packages/location/example/windows/runner/CMakeLists.txt Configures the Windows runner.
packages/location/example/windows/flutter/generated_plugins.cmake Registers Windows plugins.
packages/location/example/windows/flutter/generated_plugin_registrant.h Declares Windows plugin registration.
packages/location/example/windows/flutter/CMakeLists.txt Configures Flutter’s Windows build.
packages/location/example/windows/CMakeLists.txt Configures the Windows example.
packages/location/example/windows/.gitignore Ignores Windows build artifacts.
packages/location/example/web/index.html Adds configurable web base path.
packages/location/example/pubspec.yaml Adds Flutter test dependency.
packages/location/example/macos/Runner/AppDelegate.swift Modernizes macOS application startup.
packages/location/example/macos/Runner.xcworkspace/contents.xcworkspacedata Adds the macOS workspace.
packages/location/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme Updates macOS scheme settings.
packages/location/example/macos/Runner.xcodeproj/project.pbxproj Modernizes the macOS project.
packages/location/example/macos/Podfile Raises macOS deployment target.
packages/location/example/linux/runner/my_application.h Declares the Linux example application.
packages/location/example/linux/runner/my_application.cc Implements the Linux example application.
packages/location/example/linux/runner/main.cc Adds Linux runner entry point.
packages/location/example/linux/runner/CMakeLists.txt Configures the Linux runner.
packages/location/example/linux/flutter/generated_plugins.cmake Registers Linux plugins.
packages/location/example/linux/flutter/generated_plugin_registrant.h Declares Linux plugin registration.
packages/location/example/linux/flutter/CMakeLists.txt Configures Flutter’s Linux build.
packages/location/example/linux/CMakeLists.txt Configures the Linux example.
packages/location/example/linux/.gitignore Ignores Linux build artifacts.
packages/location/example/lib/service_enabled.dart Adds stable service-control keys.
packages/location/example/lib/permission_status.dart Adds stable permission-control keys.
packages/location/example/lib/listen_location.dart Improves stream teardown and testability.
packages/location/example/lib/get_location.dart Demonstrates last-known-location retrieval.
packages/location/example/lib/enable_in_background.dart Adds background-control keys.
packages/location/example/lib/change_settings.dart Demonstrates background intervals.
packages/location/example/lib/change_notification.dart Updates dropdown initialization.
packages/location/example/ios/Runner/Info.plist Modernizes iOS scene configuration.
packages/location/example/ios/Runner/AppDelegate.swift Registers plugins with implicit engines.
packages/location/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme Updates iOS build/debug setup.
packages/location/example/ios/Runner.xcodeproj/project.pbxproj Adds Swift Package plugin integration.
packages/location/example/ios/Podfile Updates documented iOS target.
packages/location/example/ios/Flutter/AppFrameworkInfo.plist Defers minimum OS metadata.
packages/location/example/android/settings.gradle Updates Android build plugins.
packages/location/example/android/gradle/wrapper/gradle-wrapper.properties Updates Gradle.
packages/location/example/android/gradle.properties Adds Flutter migration flags.
packages/location/example/android/build.gradle Adds dependency repositories.
packages/location/example/.metadata Records Flutter migration metadata.
packages/location/example/.gitignore Ignores test artifacts.
packages/location_web/README.md Fixes the package link.
packages/location_web/pubspec.yaml Bumps web package dependencies/version.
packages/location_web/lib/location_web.dart Expands web permission and error handling.
packages/location_web/CHANGELOG.md Documents web 7.0 changes.
packages/location_platform_interface/test/types_test.dart Tests serialization and accessory metadata.
packages/location_platform_interface/test/method_channel_location_test.dart Tests new channel methods.
packages/location_platform_interface/test/location_platform_interface_test.dart Tests default API behavior.
packages/location_platform_interface/pubspec.yaml Bumps platform-interface dependencies/version.
packages/location_platform_interface/lib/src/types.dart Expands and serializes LocationData.
packages/location_platform_interface/lib/src/method_channel_location.dart Adds new method-channel APIs.
packages/location_platform_interface/lib/location_platform_interface.dart Expands the public platform contract.
packages/location_platform_interface/CHANGELOG.md Documents platform-interface 7.0.
melos.yaml Scopes unit-test discovery.
docs/installation/windows.mdx Adds Windows installation guidance.
docs/installation/linux.mdx Adds Linux installation guidance.
docs/installation/android.mdx Improves Android snippet metadata.
docs/index.mdx Adds desktop support and correct usage.
docs/getting-started.mdx Updates version and desktop links.
docs/features/settings.mdx Rewrites settings documentation.
docs/features/services.mdx Rewrites service documentation.
docs/features/permissions.mdx Updates foreground/background permission guidance.
docs/features/notification.mdx Documents notification images and byte icons.
docs/features/listen-location.mdx Updates streaming/background examples.
docs/features/get-location.mdx Documents current and cached locations.
docs.json Adds desktop navigation links.
.github/workflows/location-prepare.yaml Modernizes Flutter preparation jobs.
.github/workflows/location-desktop.yaml Adds Linux and Windows CI builds.
.github/workflows/deploy-web-demo.yaml Adds GitHub Pages deployment.
Files not reviewed (1)
  • packages/location/example/macos/Runner.xcworkspace/contents.xcworkspacedata: Generated file
Comments suppressed due to low confidence (2)

packages/location/android/src/main/kotlin/com/lyokone/location/FlutterLocation.kt:713

  • This sends a method-channel error and then throws ActivityNotFoundException, allowing the exception to escape the handler after the result was already completed. A headless requestService() call should return the MISSING_ACTIVITY PlatformException only; remove the native throw.
    fun requestService(requestServiceResult: Result) {
        val activity = this.activity
        if (activity == null) {
            requestServiceResult.error("MISSING_ACTIVITY", "You should not requestService activation outside of an activity.", null)
            throw ActivityNotFoundException()

packages/location/windows/location_plugin.cpp:75

  • An unavailable WinRT speed is serialized as 0.0, which is also a valid stationary measurement. LocationData.speed is nullable specifically to represent unavailable data, so emit a null EncodableValue instead.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/location/windows/location_plugin.cpp
Comment thread packages/location/windows/location_plugin.cpp
Comment thread packages/location/windows/location_plugin.cpp
Comment thread packages/location/linux/location_plugin.cc
Comment thread packages/location/windows/location_plugin.cpp
Comment thread packages/location/linux/location_plugin.cc
Comment thread packages/location/windows/location_plugin.cpp
Stream listen no longer fails solely because Activity is null; start
updates when permission is granted (SharedEngine / AA / CarPlay). Also
return Flutter errors instead of throwing when permission/service UI
needs an Activity.
Copilot AI review requested due to automatic review settings July 30, 2026 11:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 116 out of 119 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • packages/location/example/macos/Runner.xcworkspace/contents.xcworkspacedata: Generated file
Comments suppressed due to low confidence (12)

packages/location/android/src/main/kotlin/com/lyokone/location/FlutterLocationService.kt:257

  • On Android 11+ foreground and background location permissions must not be requested together; the system ignores a combined request. This array always includes ACCESS_FINE_LOCATION with ACCESS_BACKGROUND_LOCATION, so the default enableBackgroundMode() flow cannot obtain the background grant on API 30+ even when foreground access was already granted. Request background access separately (and follow the settings flow required by the OS version).
                ActivityCompat.requestPermissions(
                    it,
                    arrayOf(
                        Manifest.permission.ACCESS_FINE_LOCATION,
                        Manifest.permission.ACCESS_BACKGROUND_LOCATION,
                    ),

packages/location/linux/location_plugin.cc:211

  • A second concurrent getLocation() clears the first retained method call without responding to it. The first Dart Future then hangs permanently. Keep all pending one-shot calls and resolve them together, as the Android and Darwin implementations do.
    packages/location/linux/location_plugin.cc:115
  • After a one-shot result is delivered, the GeoClue client remains started when no stream is active. This leaves location acquisition running after getLocation() completes, wasting power and continuing location access for the lifetime of the plugin. Stop the client after clearing the pending call when streaming is false.
    packages/location/windows/location_plugin.cpp:150
  • PositionChanged can invoke this delegate on a WinRT worker thread, but Flutter EventSink::Success must be called on the platform thread. Sending directly from this callback can race channel teardown or fail in the engine. Marshal the event back to the registrar/platform task runner before touching event_sink_.
    packages/location/windows/location_plugin.cpp:208
  • Unlike the getLocation coroutine, this fire_and_forget coroutine has no exception handling. RequestAccessAsync() can throw an hresult_error (for example when the API is unavailable or blocked by policy), and an unhandled exception in a C++/WinRT fire_and_forget coroutine terminates the process instead of completing the Dart call with an error.
    packages/location/windows/location_plugin.cpp:167
  • The new public getLastKnownLocation() call is not dispatched on Windows, so it reaches NotImplemented() and throws instead of returning cached data or null. This contradicts the API documentation, which identifies web—not Windows—as the platform that always returns null. Add a Windows handler with the documented nullable result.
    packages/location/linux/location_plugin.cc:201
  • The new public getLastKnownLocation() method has no Linux dispatch branch, so Linux callers receive MissingPluginException rather than the documented nullable result. Add a GeoClue-backed cached-location handler (or explicitly return null if no cache is available).
    README.md:78
  • Approximate location is a usable grant (grantedLimited), but this quick-start returns early for that status. Users who choose approximate location therefore never reach getLocation(), contrary to the permission documentation below.
if (await location.requestPermission() != PermissionStatus.granted) return;

packages/location/android/src/main/kotlin/com/lyokone/location/StreamHandlerImpl.kt:53

  • Service binding is asynchronous, so Dart can subscribe before initialize() supplies location. Returning here neither starts updates later nor reports an error; the subscription then stays silent indefinitely. Preserve the pending listener until the service connects, or fail it explicitly so callers can retry.
    docs/installation/linux.mdx:11
  • This is not out of the box on standard GeoClue installations. The implementation sets DesktopId from g_get_prgname() and notes that GeoClue requires a matching installed .desktop file, but the example/install CMake never installs one. Document that requirement (or bundle/install a matching desktop entry), otherwise Start is rejected on normal systems.
Linux is working out of the box! 🎉

The plugin talks to [GeoClue2](https://gitlab.freedesktop.org/geoclue/geoclue)
over D-Bus, so a running `geoclue` service is required (it ships with most
desktop distributions). No extra dependency needs to be bundled with your app.

docs/features/notification.mdx:17

  • The documented return type is incorrect: the API returns Future<AndroidNotificationData?>, and the newly added example later accesses notificationId/channelId from that value. Keeping Future<bool> here will mislead consumers and makes the page internally inconsistent.
  String? imageName,
  Uint8List? iconBytes,
  Uint8List? imageBytes,

packages/location/android/src/main/kotlin/com/lyokone/location/MethodCallHandlerImpl.kt:90

  • The public changeSettings signature permits explicit nulls, and the method channel always sends each key. These !! assertions therefore turn a valid call such as changeSettings(interval: null) into CHANGE_SETTINGS_ERROR. Either make these API parameters non-nullable or handle null by retaining/defaulting the corresponding setting.
            val locationAccuracy = location.mapFlutterAccuracy[call.argument<Int>("accuracy")!!]
            val updateIntervalMilliseconds = call.argument<Int>("interval")!!.toLong()
            val fastestUpdateIntervalMilliseconds = updateIntervalMilliseconds / 2
            val distanceFilter = call.argument<Double>("distanceFilter")!!.toFloat()

Comment thread packages/location/windows/location_plugin.cpp
DecSmith42
DecSmith42 previously approved these changes Jul 31, 2026
Queue method calls until the location service binds, complete pending
getLocation/stream waiters when Activity is missing, request background
location alone after foreground on API 29+, and fix web/platform_interface
imports plus Permissions-API-missing timeout handling.

Co-authored-by: Cursor <cursoragent@cursor.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 116 out of 119 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • packages/location/example/macos/Runner.xcworkspace/contents.xcworkspacedata: Generated file
Suppressed comments (8)

packages/location/windows/location_plugin.cpp:150

  • Geolocator.PositionChanged callbacks are not guaranteed to run on Flutter's platform thread, but EventSink::Success must be sent from that thread. Calling it directly here can race cancellation and invoke the binary messenger from the wrong thread. Capture the registrar/platform task runner and post the event back before touching event_sink_.
    packages/location/linux/location_plugin.cc:211
  • A second concurrent getLocation call clears the first retained FlMethodCall without responding to it, leaving the first Dart Future pending forever. Keep a collection of pending calls and resolve all of them on the next update, as the Darwin implementation does.
    packages/location/windows/location_plugin.cpp:151
  • Starting the Windows location stream subscribes immediately without first calling Geolocator::RequestAccessAsync(). A caller that listens before invoking another permission-requesting method will therefore not get the documented permission prompt and may receive no updates. Request access asynchronously on listen, register PositionChanged only when allowed, and report denial through the event sink.
    docs/features/permissions.mdx:38
  • This states that background permission is always required, but the new requireBackgroundPermission: false path intentionally supports Android foreground-service tracking without ACCESS_BACKGROUND_LOCATION. Qualify this requirement as iOS/Always and Android only when that option remains enabled, so this page does not contradict the listening guide.
To keep receiving location updates while the app is in the background, the user
must grant "Allow all the time" (Always) access on top of the foreground grant.

packages/location/windows/location_plugin.cpp:237

  • The Windows handler also omits the newly exposed getLastKnownLocation() and isBackgroundPermissionGranted() methods, so both throw MissingPluginException. Add explicit handlers; a null cached location and false background permission are valid fallbacks.
    packages/location/linux/location_plugin.cc:232
  • The new public getLastKnownLocation() and isBackgroundPermissionGranted() methods fall through to notImplemented on Linux, causing MissingPluginException rather than the documented nullable/boolean result. Handle these methods explicitly; returning null and false is a conforming fallback until native cached-location support is added.
    packages/location/darwin/location/Sources/location/LocationPlugin.swift:120
  • When location services are disabled, this guard returns without invoking result, so changeSettings() leaves its Dart Future pending forever. Complete the call with a SERVICE_STATUS_DISABLED error (and also complete it if self has already been released).
    README.md:78
  • This quick-start rejects PermissionStatus.grantedLimited, even though that status permits location access and is documented as usable. Users granting approximate location will return early and never request a fix.
if (await location.requestPermission() != PermissionStatus.granted) return;

Comment thread packages/location/darwin/location/Sources/location/LocationPlugin.swift Outdated
Without Info.plist location usage keys, Core Location never prompts, so
requestPermission/getLocation/stream callers hung; return a FlutterError
on all pending waiters instead of only logging.
Copilot AI review requested due to automatic review settings August 3, 2026 06:41

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 116 out of 119 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • packages/location/example/macos/Runner.xcworkspace/contents.xcworkspacedata: Generated file
Suppressed comments (10)

packages/location/android/src/main/kotlin/com/lyokone/location/StreamHandlerImpl.kt:84

  • Canceling the stream unconditionally stops the shared native request even when one or more concurrent getLocation() calls are still waiting for that request's next fix. Those Futures then remain unresolved. Clear the stream sink first, but stop updates only when there are no pending one-shot results.
    packages/location/windows/location_plugin.cpp:146
  • Subscribing directly to onLocationChanged never calls Geolocator::RequestAccessAsync; only getLocation and the permission methods do. This breaks the documented contract that the stream requests permission when needed: a first-use stream subscription can remain silent/denied. Request access asynchronously on the UI thread before registering PositionChanged, and report denial through the event sink.
    packages/location/windows/location_plugin.cpp:150
  • Geolocator.PositionChanged may invoke this delegate off the Flutter platform thread, but EventSink::Success must be sent on the platform thread. Calling it directly can race with cancellation/plugin destruction and violates the Windows embedder's channel threading requirements. Post the encoded event through the registrar's task runner (and re-check sink lifetime there).
    docs/features/permissions.mdx:38
  • This statement contradicts the new requireBackgroundPermission: false behavior documented elsewhere: an Android location foreground service can keep receiving updates without ACCESS_BACKGROUND_LOCATION. State the platform distinction so users are not told the stricter grant is universally mandatory.
To keep receiving location updates while the app is in the background, the user
must grant "Allow all the time" (Always) access on top of the foreground grant.

packages/location/android/src/main/kotlin/com/lyokone/location/LocationPlugin.kt:164

  • Queued method calls are flushed by setLocation, before setLocationService is assigned. A call made while bindService is pending—especially the newly documented standalone enableBackgroundMode—therefore sees a null service and incorrectly returns false (notification changes similarly return null). Assign the service first so the flush runs only after both dependencies are ready.
        methodCallHandler?.setLocation(service.location)
        methodCallHandler?.setLocationService(service)

packages/location/android/src/main/kotlin/com/lyokone/location/StreamHandlerImpl.kt:59

  • The event channel is registered before the asynchronous service binding completes, but unlike method calls, an immediate stream subscription is rejected instead of queued. Apps that subscribe during startup can nondeterministically receive SERVICE_NOT_READY and never start streaming. Retain the pending sink and start it from setLocation once binding completes.

This issue also appears on line 80 of the same file.
packages/location_platform_interface/lib/location_platform_interface.dart:110

  • The newly advertised Windows and Linux implementations do not handle the getLastKnownLocation method, so this public call falls through to NotImplemented and throws MissingPluginException on both desktop platforms. Add handlers in both native plugins; returning a null success is valid when no cache API is available.
    packages/location_platform_interface/lib/location_platform_interface.dart:145
  • Neither the Windows nor Linux native method handler recognizes isBackgroundPermissionGranted, despite both platforms now being registered by location. Calling this API there throws MissingPluginException instead of returning a boolean. Implement the method on both desktop plugins (typically false, since they expose no separate background grant).
    README.md:78
  • This rejects PermissionStatus.grantedLimited, even though approximate/reduced permission is sufficient for getLocation and the package documentation explicitly treats it as usable. Users choosing approximate location will therefore exit the quick-start flow without receiving a location.
if (await location.requestPermission() != PermissionStatus.granted) return;

docs/features/notification.mdx:17

  • The updated signature still documents Future<bool>, but the actual API returns Future<AndroidNotificationData?>; the new example below also accesses notificationId and channelId from that value. Correct the signature so consumers do not code against an incompatible return type.
  String? imageName,
  Uint8List? iconBytes,
  Uint8List? imageBytes,

@bhavik-dodia-aub
bhavik-dodia-aub marked this pull request as ready for review August 4, 2026 05:08
Copilot AI review requested due to automatic review settings August 5, 2026 03:48
@DecSmith42
DecSmith42 merged commit 36a2b7c into main Aug 5, 2026
2 of 3 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 120 out of 123 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • packages/location/example/macos/Runner.xcworkspace/contents.xcworkspacedata: Generated file
Suppressed comments (19)

packages/location/windows/location_plugin.cpp:150

  • PositionChanged may invoke this handler off the Flutter platform thread, but EventSink::Success must be sent on that thread. The method-call path explicitly captures and awaits ui_thread; do the same for stream events to avoid thread-unsafe messenger access and intermittent crashes.
    packages/location/windows/location_plugin.cpp:80
  • Converting through time_t truncates the WinRT timestamp to whole seconds before multiplying by 1000, so every Windows LocationData.time is rounded down to a second. Convert the WinRT duration directly to Unix milliseconds to preserve the timestamp precision promised by the API.
    packages/location/linux/location_plugin.cc:211
  • A second getLocation call clears the retained first call without sending any response, leaving the first Dart Future pending forever. Keep all pending one-shot calls (as the Android/Darwin implementations do) and resolve them together on the next fix.
    packages/location/linux/location_plugin.cc:112
  • After a one-shot request is fulfilled, the pending call is cleared but the GeoClue client is not stopped when no stream is active. A single getLocation() therefore leaves system location tracking running until plugin disposal; stop the client here when streaming is false.
    docs/features/permissions.mdx:38
  • This is not true for the Android foreground-service mode documented elsewhere on this page set: enableBackgroundMode(requireBackgroundPermission: false) intentionally works with foreground permission only. As written, this section tells those callers that “Allow all the time” is mandatory. Qualify the requirement by platform/mode and mention the foreground-service exemption.
## Background Permission

To keep receiving location updates while the app is in the background, the user
must grant "Allow all the time" (Always) access on top of the foreground grant.

.github/workflows/location-prepare.yaml:1

  • This deletion removes the repository's only PR validation workflow; there are no remaining files under .github/workflows, so formatting, analysis, Dart tests, Android lint/build, and iOS build checks will no longer run on pull requests. Keep or replace this workflow before merging the large platform rewrite.
    packages/location/windows/location_plugin.cpp:217
  • MethodChannelLocation always includes this key and the public parameter is nullable, so an explicit null still reaches the branch. std::get<int> on the null EncodableValue throws bad_variant_access; the same problem exists for distanceFilter and interval below. Use std::get_if and only apply non-null values.
    packages/location/windows/location_plugin.cpp:146
  • Subscribing to the Windows stream never calls Geolocator::RequestAccessAsync. On a first-use install this can fail to register or remain silent instead of showing the permission prompt, contrary to the onLocationChanged contract. Request access asynchronously and report denial through the event sink before attaching PositionChanged.
    packages/location/windows/location_plugin.cpp:237
  • The newly exposed getLastKnownLocation and isBackgroundPermissionGranted methods are not handled anywhere above, so both fall through to NotImplemented on Windows. Calls through the public API throw instead of returning a cached location/null and a permission boolean as documented.
    packages/location/linux/location_plugin.cc:232
  • Linux also falls through for the newly public getLastKnownLocation and isBackgroundPermissionGranted methods. Since Linux is registered as a supported implementation, these calls throw MissingPluginException instead of returning the documented nullable location and boolean.
    packages/location/android/src/main/kotlin/com/lyokone/location/LocationPlugin.kt:164
  • Queued method calls are flushed as soon as setLocation runs, but locationService is assigned only on the next line. Calls queued during bindService that need the service (enableBackgroundMode, isBackgroundModeEnabled, or notification updates) therefore execute with null and return a false failure. Set the service first so flushing only happens after both dependencies are ready.
    packages/location/android/src/main/kotlin/com/lyokone/location/MethodCallHandlerImpl.kt:132
  • The public API permits these arguments to be explicitly null, and the method channel forwards those nulls. The !! assertions then turn a valid call such as changeSettings(interval: null) into CHANGE_SETTINGS_ERROR; apply the documented defaults (or preserve current values) instead of force-unwrapping.
    packages/location/linux/location_plugin.cc:226
  • changeSettings reports success while ignoring every supplied setting; Linux remains hard-coded to exact accuracy and does not apply distance or interval filtering. This makes the cross-platform API silently lie to callers. Apply supported GeoClue/client-side settings, or return an explicit unsupported result rather than 1.
    packages/location/darwin/location/Sources/location/LocationPlugin.swift:413
  • Canceling the stream unconditionally stops Core Location even when one or more concurrent getLocation() calls are still waiting for a fix. Those one-shot futures then never complete. Only stop updates here when pendingLocationResults is empty.
    docs/installation/linux.mdx:11
  • The implementation itself notes that GeoClue requires DesktopId to match an installed .desktop file, but neither the example nor these installation steps install one. Standard GeoClue agents can therefore reject the client, so Linux is not reliably “out of the box.” Document the required desktop entry/GeoClue application setup (or bundle/install it).
Linux is working out of the box! 🎉

The plugin talks to [GeoClue2](https://gitlab.freedesktop.org/geoclue/geoclue)
over D-Bus, so a running `geoclue` service is required (it ships with most
desktop distributions). No extra dependency needs to be bundled with your app.

README.md:35

  • The Android implementation now skips plugin registration unless the host engine is cached under the literal SharedEngine key, so this standard quick-start/cross-platform claim leads ordinary Android apps to MissingPluginException. Document the fork-specific engine creation/cache requirement prominently, including that the default Flutter engine is unsupported.
## ✨ Why Location?

- 🌍 **Truly cross-platform** — the same code runs on all six Flutter targets, no per-platform branching.
- ⚡ **One-line to a fix** — `await location.getLocation()` and you're done.

packages/location/android/src/main/kotlin/com/lyokone/location/StreamHandlerImpl.kt:57

  • The event channel is registered before the asynchronous service bind completes, so an immediate onLocationChanged.listen can hit this branch and fail with SERVICE_NOT_READY. Method calls are queued for the same race; stream subscriptions need equivalent deferred startup rather than an error based only on bind timing.
    packages/location/darwin/location/Sources/location/LocationPlugin.swift:218
  • This starts a one-shot request, but the delegate never implements locationManager(_:didFailWithError:). If Core Location reports a terminal error after authorization, every pending result remains unresolved and streams receive no error. Add the delegate callback to complete pending results and notify the event sink while treating transient locationUnknown appropriately.
    packages/location_platform_interface/lib/src/types.dart:174
  • Because null means “keep the current value” for every nullable field, callers cannot clear fields such as accuracy, provider, or isMock once set. A copyWith for nullable state needs an omitted-value sentinel (or wrappers) so “not supplied” and “replace with null” are distinguishable.

Comment on lines +119 to +120
locationServicesEnabled { [weak self] enabled in
guard let self, enabled else { return }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants