Drop home_widget + geolocator for native; unpin Flutter to 3.44.0#18
Conversation
The project pinned Flutter at 3.41.7 to keep AGP-9 built-in Kotlin (android.builtInKotlin=true), which rejects the legacy Kotlin Gradle Plugin (KGP) globally — so any plugin applying KGP broke the build on Flutter 3.44.0. Removing the last two native plugins eliminates KGP entirely, so built-in Kotlin and Flutter 3.44.0 now coexist. home_widget -> WidgetStore: - New lib/services/widget_store.dart: method-channel KV bridge over org.bortnik.meteogram/svg to the HomeWidgetPreferences file. - MainActivity ports home_widget's exact codec (home_widget.double.<key> sidecar + doubleToRawLongBits) so existing installs keep saved data. - MeteogramWidgetProvider extends AppWidgetProvider (opens prefs in onUpdate). - Removed the dead HomeWidget background receiver/service from the manifest. geolocator -> native: - New LocationProvider.kt (android.location.LocationManager) + Dart LocationBridge; runtime-permission flow in MainActivity. No new deps, no Google Play Services. GPS fixes are foreground-only. Result: GeneratedPluginRegistrant is empty (zero native plugins); also dropped path_provider/jni/jni_flutter and uuid from the tree. Unpin: CI flutter-version 3.41.7 -> 3.44.0; CLAUDE.md / docs / gradle comments updated. Verified on 3.44.0: analyze clean, 115 Dart + Kotlin tests pass, debug + release APKs build, emulator run (grant -> GPS, deny -> Berlin fallback), Android Lint NewApi clean for the new native code (minSdk 24). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR migrates widget persistence and location services from the Flutter ChangesNative Method Channel Migration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
android/app/src/main/kotlin/org/bortnik/meteogram/MainActivity.kt (1)
237-244: 💤 Low valueMinor:
runOnUiThreadis redundant here.
LocationProvider.getCurrentPositionalready invokes its callback on the main thread viaHandler(Looper.getMainLooper()). TherunOnUiThreadcall is harmless (it will detect it's already on the UI thread and execute directly), but it's unnecessary indirection.Not a blocking issue—leaving it won't cause problems, but removing it simplifies the code.
♻️ Optional simplification
"getCurrentPosition" -> { val timeoutMs = (call.argument<Int>("timeoutMs") ?: 15000).toLong() LocationProvider.getCurrentPosition(this, timeoutMs) { coords -> - runOnUiThread { - result.success(coords?.let { mapOf("latitude" to it[0], "longitude" to it[1]) }) - } + result.success(coords?.let { mapOf("latitude" to it[0], "longitude" to it[1]) }) } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@android/app/src/main/kotlin/org/bortnik/meteogram/MainActivity.kt` around lines 237 - 244, The callback passed to LocationProvider.getCurrentPosition is already delivered on the main thread, so remove the redundant runOnUiThread wrapper; inside the "getCurrentPosition" branch use the existing callback lambda to call result.success directly (preserve the timeoutMs computation and the null-safe mapping of coords to mapOf("latitude" to it[0], "longitude" to it[1]) so behavior is unchanged). Update the lambda body in MainActivity's "getCurrentPosition" case to call result.success(...) without runOnUiThread.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@android/app/src/main/kotlin/org/bortnik/meteogram/MainActivity.kt`:
- Around line 237-244: The callback passed to
LocationProvider.getCurrentPosition is already delivered on the main thread, so
remove the redundant runOnUiThread wrapper; inside the "getCurrentPosition"
branch use the existing callback lambda to call result.success directly
(preserve the timeoutMs computation and the null-safe mapping of coords to
mapOf("latitude" to it[0], "longitude" to it[1]) so behavior is unchanged).
Update the lambda body in MainActivity's "getCurrentPosition" case to call
result.success(...) without runOnUiThread.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: eea0e27f-e94e-4559-8cf5-a5b6b0778b21
⛔ Files ignored due to path filters (1)
pubspec.lockis excluded by!**/*.lock
📒 Files selected for processing (24)
.github/workflows/codeql-default.yml.github/workflows/release.yml.github/workflows/test.ymlCLAUDE.mdandroid/app/src/main/AndroidManifest.xmlandroid/app/src/main/kotlin/org/bortnik/meteogram/LocationProvider.ktandroid/app/src/main/kotlin/org/bortnik/meteogram/MainActivity.ktandroid/app/src/main/kotlin/org/bortnik/meteogram/MeteogramWidgetProvider.ktandroid/gradle.propertiesdocs/ai/architecture.mddocs/ai/widget.mdlib/main.dartlib/screens/home_screen.dartlib/services/location_bridge.dartlib/services/location_service.dartlib/services/material_you_service.dartlib/services/native_svg_service.dartlib/services/theme_service.dartlib/services/widget_service.dartlib/services/widget_store.dartpubspec.yamltest/home_screen_test.darttest/location_service_test.darttest/theme_service_test.dart
💤 Files with no reviewable changes (2)
- lib/main.dart
- android/app/src/main/AndroidManifest.xml
LocationProvider.getCurrentPosition already invokes its callback on the main thread — requestLocationUpdates is registered with the main Looper, the timeout uses a main-Looper Handler, and the early-return paths run synchronously on the calling (main) thread. Wrapping result.success in runOnUiThread was therefore unnecessary indirection. Per CodeRabbit review on #18. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Removes the last two Flutter plugins with native code —
home_widgetandgeolocator— replacing both with native implementations over the existingmethod channel. With zero KGP-applying plugins left, AGP-9 built-in Kotlin
(
android.builtInKotlin=true) is finally compatible with current Flutter, sothis also unpins Flutter 3.41.7 → 3.44.0.
Why: AGP-9 built-in Kotlin rejects the legacy Kotlin Gradle Plugin (KGP)
globally — a single KGP-applying plugin breaks the build on Flutter 3.44.0.
The project had pinned Flutter at 3.41.7 specifically to keep built-in Kotlin.
Going plugin-free removes the conflict at its root.
Changes
home_widget→WidgetStore(native key-value)lib/services/widget_store.dart: method-channel KV bridge overorg.bortnik.meteogram/svgto theHomeWidgetPreferencesfile.MainActivityports home_widget's exact SharedPreferences codec — thehome_widget.double.<key>boolean sidecar +doubleToRawLongBitsfordoubles — so existing installs keep their saved data.
MeteogramWidgetProvidernow extendsAppWidgetProvider(opens prefs inonUpdate); removed the deadHomeWidgetBackgroundReceiver/Servicefromthe manifest.
path_provider/jni/jni_flutterfrom the tree.geolocator→ nativeLocationProviderLocationProvider.kt(android.location.LocationManager) + DartLocationBridge; runtime-permission flow handled inMainActivity(
onRequestPermissionsResult).foreground-only (the widget's background refresh reuses cached coords).
Drops
uuid.Unpin Flutter
flutter-version3.41.7→3.44.0(test / release / codeql workflows).CLAUDE.md,docs/ai/*, andgradle.propertiescomments updated to the newstate, including the "keep the plugin set KGP-free" constraint.
Net result:
GeneratedPluginRegistrantis now empty (no native plugins).Verification (Flutter 3.44.0 / Dart 3.12.0)
make analyzeclean; 115 Dart tests + Kotlin tests pass.renders ("Mountain View · GPS"); deny → Berlin fallback renders
("Berlin · Manual"). 0 crashes / SecurityExceptions.
NewApiclean for the new native code atminSdk 24.Notes & follow-ups
Applying the Kotlin Android Plugin (KGP) was unsuccessful…— Flutter 3.44.0's caught force-apply on:app;the build succeeds ([AGP 9] Remove Support for KGP flutter/flutter#184837).
flutter clean(staleDart-kernel caches otherwise cause spurious
dot-shorthandsframework errors).Use a native method-channel impl, or fall back to legacy KGP
(
builtInKotlin=false+ re-addkotlin-android).res/values/styles.xml'sWidgetThemeusesTheme.DeviceDefault.DayNight(API 29) at minSdk 24 —worth a separate fix (move to
values-v29/with an API-24 fallback).devices). The
AbstractMethodErrorrisk is eliminated in code (all fourLocationListenermethods are overridden).🤖 Generated with Claude Code
Summary by CodeRabbit
Chores
Refactor
Documentation