Skip to content

Present alerts on the window that exists, not the first one - #141

Open
cortfritz wants to merge 1 commit into
GenericJam:masterfrom
cortfritz:fix/ios-alert-never-presents
Open

Present alerts on the window that exists, not the first one#141
cortfritz wants to merge 1 commit into
GenericJam:masterfrom
cortfritz:fix/ios-alert-never-presents

Conversation

@cortfritz

Copy link
Copy Markdown

On iOS 26, Mob.Alert.alert/2 and Mob.Alert.action_sheet/2 never show anything. No error, no log — the dialog is silently dropped.

Cause

nif_alert_show and nif_action_sheet_show resolve their presenting controller through a private root_vc() that hand-rolls the window lookup:

UIWindow *win = scene.windows.firstObject;
UIViewController *vc = win.rootViewController;

That assumes the app's window sorts first in the scene's window set. On iOS 26 it does not, rootViewController is nil, and the if (vc) guard downstream discards the alert.

Core already has the correct lookup one file over, in mob_root_vc, which tries keyWindow before falling back to windows.firstObject and skips any window with no root controller. The scanner and camera plugins each carry a copy of it (scan_root_vc, cam_root_vc).

That asymmetry is what isolates the cause: on the same device, in the same scene, the QR scanner and the camera present fine while the alert never does. The window lookup is the only structural difference between them.

Change

root_vc() now delegates to mob_root_vc() and keeps only the part that was doing real work — walking to the topmost presented controller. The activationState == UISceneActivationStateForegroundActive filter goes with the hand-rolled loop, matching mob_root_vc and both plugin copies.

Verification

Rung 1 of the ladder, plus the field report that started it.

  • xcrun clang-format --dry-run -Werror ios/mob_nif.m — clean.
  • clang -fsyntax-only against the iOS 26.5 SDK — no diagnostics introduced (identical output before and after).
  • Symptom, not the fix: observed on a physical iPhone 16 Pro, iOS 26.6.1, where an app's only confirm dialog could not be made to appear while mob_scanner and mob_camera presented normally in the same app. I attributed it to this function by inspection; I have not yet instrumented root_vc() returning nil, and I have not run the patched build on the device. Happy to do that if you want it before merging.

Related: issues.md §9 describes Mob.Test.dismiss_alert/2 failing on the simulator, which implies alerts do present there — so this may be device- or iOS-26-specific rather than universal.

The companion PR fixes a use-after-free in the same two functions' button handlers, which bites as soon as a dialog does appear.

https://claude.ai/code/session_01FGHFA67yQndR78WYAU9DM7

nif_alert_show and nif_action_sheet_show resolve their presenting
controller through a private root_vc() that takes
`scene.windows.firstObject` and reads its rootViewController. That
assumes the app's window sorts first in the scene's window set. On iOS 26
it does not: the property comes back nil, root_vc() returns nil, the
`if (vc)` guard drops the dialog, and nothing is logged. An alert simply
never appears — on a physical iPhone 16 Pro (iOS 26.6.1) no confirm
dialog could be shown at all.
Core already has the right lookup in mob_root_vc, which tries `keyWindow`
first and falls back to windows.firstObject, and the scanner and camera
plugins each carry a copy of it (scan_root_vc, cam_root_vc). Those
present fine on the same device and the same scene, which is what
isolates the window lookup as the difference. Route root_vc through
mob_root_vc and keep only the part that was doing real work — walking to
the topmost presented controller.
The activationState == ForegroundActive filter goes with it, matching
mob_root_vc and the two plugin copies.
Sign up for freeto 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.

1 participant

@cortfritz