Conversation
GMapView is only assigned in GMViewController.viewDidLoad, which only runs when the view is first touched -- and the only touch is inside the `if let target` branch of render(). When getTargetContainer() finds no match, that branch is skipped and GMapView stays nil for the lifetime of the map. getTargetContainer() matches a WKWebView sub-scroll view whose contentSize is an exact match for the element, so it misses whenever the page is still laying out (e.g. while a page transition is animating). Nothing recovers from that: onViewDidLoad never fires, so finishMapConfiguration() never runs and onMapReady is never emitted, and every later call from JS -- setCamera, enableCurrentLocation, addMarkers -- dereferences the nil implicitly-unwrapped optional and hard-crashes the app with EXC_BREAKPOINT. ionic-team#136 fixed this for the plugin's own configuration by deferring it to onViewDidLoad, but left the view load itself inside the `if let`, so caller-facing methods are still exposed. Call loadViewIfNeeded() when no container matched so GMapView always exists; rebindTargetContainer() already attaches the view on the next onResize/onDisplay pass.
Author
|
For context, we're currently applying a patch in our build pipeline to fix this issue. Thought it would be helpful for everyone and we would love to stop having to patch it manually for ourselves. Thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the long-standing iOS
Unexpectedly found nil while implicitly unwrapping an Optional valuecrash: #129, #131, #132, #135.The bug
GMapViewis assigned in exactly one place —GMViewController.viewDidLoad()— which only runs when the view controller's view is first touched. The only touch is inside theif let targetbranch ofrender():getTargetContainer()looks for aWKChildScrollView/WKScrollViewwhosecontentSizeis an exact floating-point match for the element's reported size:That misses whenever the page is still laying out — most commonly when the map is created while a page transition is animating. When it misses, the branch is skipped,
viewDidLoadnever runs, andGMapViewstays nil for the lifetime of the map.Nothing recovers from that state:
onViewDidLoadnever fires, sofinishMapConfiguration()never runs andonMapReadyis never emitted — so JS has no way to detect the failure either.setCamera,enableCurrentLocation,addMarkers, …) dereferences the nil implicitly-unwrapped optional and hard-crashes the app withEXC_BREAKPOINT/SIGTRAP.Symbolicated from a production crash (
@capacitor/google-maps8.0.1, iOS 26.6, iPhone 15):Registers confirm it: the
mapViewControllerpointer is valid,GMapViewis0. The instruction stream isldr x8,[x0,#192]→ldr x0,[x8,x9]→cbz x0→brk #1.Relationship to #136
#136 fixed this crash for the plugin's own configuration by moving
GMapView.delegate/ styles / zoom out ofrender()and deferring them to the newonViewDidLoadhook. That was the right mechanism, but it left the view load itself inside theif let targetbranch — so when no container matches,onViewDidLoadnever fires and every caller-facing method is still exposed to the same nil. That's consistent with #129/#131/#132/#135 still being open.This change is the remaining step of that fix.
The change
When no container matched, load the view anyway:
viewDidLoadruns,GMapViewis assigned,onViewDidLoadfires,finishMapConfiguration()runs andonMapReadyis emitted as normal. The view isn't attached to a container yet, butrebindTargetContainer()already handles that on the nextonResize/onDisplaypass — which is the existing recovery path, now reachable instead of dead.Net effect: a missed container lookup degrades to a map that attaches a moment later instead of a process that crashes on the next call.
Notes
else.