Skip to content

[google_maps_flutter] Refactor the JavaScript interaction and verify integration tests - #1066

Open
seungsoo47 wants to merge 12 commits into
flutter-tizen:masterfrom
seungsoo47:google_maps_flutter-add-integration-tests
Open

[google_maps_flutter] Refactor the JavaScript interaction and verify integration tests#1066
seungsoo47 wants to merge 12 commits into
flutter-tizen:masterfrom
seungsoo47:google_maps_flutter-add-integration-tests

Conversation

@seungsoo47

@seungsoo47 seungsoo47 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor
  • Refactor the JavaScript interaction layer by introducing GoogleMapsJsBridge, replacing direct WebViewController calls.
  • Update webview_flutter to ^4.13.1 and webview_flutter_lwe to ^0.5.3.
  • Verify integration tests pass against upstream google_maps_flutter v2.17.0.

@seungsoo47
seungsoo47 force-pushed the google_maps_flutter-add-integration-tests branch from 370807c to 39802fe Compare July 15, 2026 12:09

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the JavaScript interaction layer of the google_maps_flutter_tizen plugin by introducing a GoogleMapsJsBridge to replace direct WebViewController calls. The review feedback highlights a critical serialization issue in the bridge where arguments are directly interpolated, potentially causing runtime crashes and security vulnerabilities. To resolve this, the reviewer suggests introducing a JsExpression class to handle raw JS code and properly encoding other arguments. Additionally, the feedback recommends marking MapsJsEvent as sealed for exhaustiveness, utilizing the new bridge.addListener abstraction across controllers instead of executing raw JavaScript, and wrapping JS references in JsExpression to prevent them from being treated as string literals.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/google_maps_flutter/lib/src/util.dart
Comment thread packages/google_maps_flutter/lib/src/util.dart
Comment thread packages/google_maps_flutter/lib/src/util.dart
Comment thread packages/google_maps_flutter/lib/src/google_maps_js_bridge.dart Outdated
Comment thread packages/google_maps_flutter/lib/src/util.dart
Comment thread packages/google_maps_flutter/lib/src/google_maps_js_bridge.dart
Comment thread packages/google_maps_flutter/lib/src/circle.dart
Comment thread packages/google_maps_flutter/lib/src/polygon.dart
Comment thread packages/google_maps_flutter/lib/src/google_maps_js_bridge.dart Outdated
Comment thread packages/google_maps_flutter/lib/src/ground_overlay.dart
@seungsoo47 seungsoo47 changed the title Google maps flutter add integration tests [google_maps_flutter] Refactor the JavaScript interaction and verify integration tests Jul 16, 2026

@JSUYA JSUYA left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please review gemini's review and modify the code.

@seungsoo47

Copy link
Copy Markdown
Contributor Author

Please review gemini's review and modify the code.

I will update the review and the code after merging #1071.

seungsoo47 added a commit to seungsoo47/plugins that referenced this pull request Aug 4, 2026
…dListener consistently

Address Gemini Code Assist review on PR flutter-tizen#1066.

- Fix a critical bug where callMethod/setProperty interpolated
  arguments via List.toString(), so a plain String like a marker
  title was spliced into the JS snippet unquoted (e.g. ['My Title']
  instead of ["My Title"]), breaking at runtime for any string
  containing whitespace or special characters and risking JS
  injection. Add JsExpression to mark raw JS code that must not be
  quoted, and JSON-encode plain String arguments so they're safely
  treated as string literals.
- Wrap the few call sites that relied on the old unquoted behavior
  (setMap's 'map' JS-global reference, setPosition's LatLng
  constructor, setPixelOffset's GSize object literal) in JsExpression
  so they keep working under the new serialization.
- Mark MapsJsEvent sealed so the exhaustive switch in
  GoogleMapsController._onJsEvent is statically checked when new
  event types are added.
- Use the bridge.addListener abstraction in polyline/circle/polygon/
  ground_overlay instead of hand-built runJavaScript strings, for
  consistency with the rest of the bridge.
@seungsoo47
seungsoo47 force-pushed the google_maps_flutter-add-integration-tests branch from 39802fe to 174d20a Compare August 4, 2026 10:52
…dListener consistently

Address Gemini Code Assist review on PR flutter-tizen#1066.

- Fix a critical bug where callMethod/setProperty interpolated
  arguments via List.toString(), so a plain String like a marker
  title was spliced into the JS snippet unquoted (e.g. ['My Title']
  instead of ["My Title"]), breaking at runtime for any string
  containing whitespace or special characters and risking JS
  injection. Add JsExpression to mark raw JS code that must not be
  quoted, and JSON-encode plain String arguments so they're safely
  treated as string literals.
- Wrap the few call sites that relied on the old unquoted behavior
  (setMap's 'map' JS-global reference, setPosition's LatLng
  constructor, setPixelOffset's GSize object literal) in JsExpression
  so they keep working under the new serialization.
- Mark MapsJsEvent sealed so the exhaustive switch in
  GoogleMapsController._onJsEvent is statically checked when new
  event types are added.
- Use the bridge.addListener abstraction in polyline/circle/polygon/
  ground_overlay instead of hand-built runJavaScript strings, for
  consistency with the rest of the bridge.
…JsEvent

Follow-up to 8b9c3079: GInfoWindowOptions.toString() still spliced the
info window content string directly into the JS snippet unquoted, the
same unsafe-serialization issue fixed elsewhere in that commit. Also
mark MessageJsEvent sealed, matching MapsJsEvent, so exhaustive
switches over its subclasses stay statically checked.
@seungsoo47
seungsoo47 force-pushed the google_maps_flutter-add-integration-tests branch from 174d20a to c04ae3a Compare August 6, 2026 00:49
@seungsoo47
seungsoo47 force-pushed the google_maps_flutter-add-integration-tests branch from c04ae3a to e8d9e43 Compare August 6, 2026 00:51
@JSUYA

JSUYA commented Aug 7, 2026

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e8d9e43a34

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/google_maps_flutter/pubspec.yaml
Comment thread packages/google_maps_flutter/lib/src/google_maps_js_bridge.dart
…we 0.5.3

webview_flutter_lwe 0.5.3 requires Dart ^3.8.0 and Flutter >=3.32.0,
but this package still advertised Dart >=3.4.0 and Flutter >=3.22.0.
Consumers on the lower range would fail dependency resolution since
the only version satisfying webview_flutter_lwe ^0.5.3 needs the
higher SDKs.

Address chatgpt-codex-connector review on PR flutter-tizen#1066.
dispose() closed the _events StreamController but left the
JavaScript channels registered, so a message from an in-flight JS
timer or postMessage call arriving after disposal would call
_events.add() on a closed controller and throw an uncaught
StateError. Route all channel callbacks through a helper that
ignores emissions once the controller is closed.

Address chatgpt-codex-connector review on PR flutter-tizen#1066.
@seungsoo47

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e36835317d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/google_maps_flutter/lib/src/util.dart
Comment thread packages/google_maps_flutter/lib/src/google_maps_controller.dart Outdated
Raising the SDK constraint to ^3.8.0 activates the new tall-style
dart format output, which the CI format check enforces.
_infoWindowOptionsFromMarker wrapped content in manual JS string quotes,
but its consumers (GInfoWindowOptions.toString and GInfoWindow._setContent)
already JSON-encode the value, causing literal apostrophes to render in
the InfoWindow.
The subscription to _bridge.events was never retained, so a JS event
queued just before dispose() could still invoke _onJsEvent afterward.
Handlers like _onIdle() add to _streamController unguarded, which
throws a StateError once the controller is closed.
final WebViewController controller = WebViewController();
/// The bridge mediating all interaction with the Google Maps JavaScript
/// API running inside the WebView.
final GoogleMapsJsBridge _bridge = WebViewGoogleMapsJsBridge();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Replacing the public GoogleMapsController.controller field with _bridge makes existing 0.1.14 consumers that use this field fail to compile. Since this is currently a 0.1.15 patch release, please preserve compatibility with a forwarding getter such as WebViewController get controller => _bridge.controller;, or release it as 0.2.0.

@@ -0,0 +1,464 @@
// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

2026 ?

/// This is the single seam through which JS commands are built and JS→Dart
/// events are dispatched, replacing ad hoc `runJavaScript` calls and
/// hand-built JS strings scattered across the plugin.
abstract class GoogleMapsJsBridge {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

GoogleMapsJsBridge has only one implementation, and GoogleMapsController constructs that implementation directly, so the interface currently provides neither substitutability.
How about collapse this into one concrete GoogleMapsJsBridge for now.


/// Base class for events dispatched from the Google Maps JavaScript runtime
/// back into Dart through a [GoogleMapsJsBridge].
sealed class MapsJsEvent {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These 15 event classes only carry an event kind and an optional String payload, with no type-specific behavior. A MapsJsEventType enum plus a ({MapsJsEventType type, String? message}) record preserves the same exhaustive switch without the class hierarchy. Please replace these subclasses and collapse the repetitive channel callbacks behind one registration helper.

Comment thread packages/google_maps_flutter/README.md Outdated
dependencies:
google_maps_flutter: ^2.16.0
google_maps_flutter_tizen: ^0.1.14
google_maps_flutter_tizen: ^0.1.15

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The interface has changed, 0.2.0 seems appropriate.

@JSUYA

JSUYA commented Aug 11, 2026

Copy link
Copy Markdown
Member

The integration_test was on standby for 14 hours. Please let me know if the CI is not working properly.
https://github.com/flutter-tizen/plugins/actions/runs/31377384649/attempts/1?pr=1066

Replace the sealed-class MapsJsEvent hierarchy and the
GoogleMapsJsBridge/WebViewGoogleMapsJsBridge interface split with a
single enum+record event type and one concrete bridge class, since
there was only ever one implementation. Also fixes the copyright
header year on the newly added bridge file and bumps the package to
0.2.0 since removing GoogleMapsController.controller is a breaking
change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants