Skip to content

[Bug] [v6] [iOS] Swipe up gesture on fullscreen fires exit events but does not exit fullscreen #4864

@phazei

Description

@phazei

This duplicates this ticket:
#4832 (comment)

Specifically for RNV 6.19.0

When going to full screen, a tiny swipe that isn't enough to close the video gets it stuck in a state where the are no screen controls and swiping no longer works. The only solution is to shutdown the app and start over.

Seems to be a UIKit bug in iOS 26 affecting AVPlayerViewController.

This is my solution which seems to work.

Fix: Patch react-native-video 6.19.0 — dismiss/re-present recovery for iOS 26

react-native-video+6.19.0.patch

Three files changed:

RCTVideoPlayerViewController.swift — Removed the viewDidDisappear override. This was firing dismiss callbacks (videoPlayerViewControllerWillDismiss / DidDismiss) on cancelled swipe gestures in iOS 26, causing the JS and native state to desync. Fullscreen dismissal is now handled exclusively through AVPlayerViewControllerDelegate methods, which is the Apple-recommended approach and what react-native-video v7 uses.

RCTVideo.swift — Moved the fullscreen teardown logic (resetting _fullscreenPlayerPresented, nullifying _playerViewController, removing observers, etc.) from the old viewDidDisappear-triggered path into handleDidExitFullScreen(). This method only fires when the AVPlayerViewControllerDelegate's transition coordinator confirms the dismiss was committed (!context.isCancelled). Observer removal was also moved here from handleWillExitFullScreen — removing observers during willExit was premature since the transition might be cancelled.

RCTPlayerObserver.swift — Added iOS 26 cancelled dismiss recovery. When the transition coordinator reports isCancelled: YES, the player view controller is dismissed and immediately re-presented (both non-animated) to force UIKit to create a fresh window and gesture recognizer state. This is necessary because iOS 26 has a UIKit bug where the system gesture window's touch targets become nil after a cancelled AVPlayerViewController dismiss transition. A re-entry guard (_isRecoveringFromCancelledDismiss) prevents the recovery from looping, since the re-present can itself trigger another cancelled transition callback. Playback position and play/pause state are preserved across the recovery.

With this solution in place, the user experiences a brief flash during the dismiss/re-present recovery on a partial swipe, but the player remains fully functional afterward — controls work, swipe-to-dismiss works, and subsequent partial swipes also recover correctly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    To Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions