From 899bbf3e86351c3af7b3a1907aa2c42d44262d58 Mon Sep 17 00:00:00 2001 From: zaksorel Date: Wed, 15 Jul 2026 18:01:29 +0700 Subject: [PATCH] fix: guard nativeId lookup for UIKit responders --- .../project.pbxproj | 2 ++ .../KeyboardControllerNativeTests.swift | 36 +++++++++++++++++++ ios/extensions/UIResponder.swift | 1 + 3 files changed, 39 insertions(+) diff --git a/ios/KeyboardControllerNative/KeyboardControllerNative.xcodeproj/project.pbxproj b/ios/KeyboardControllerNative/KeyboardControllerNative.xcodeproj/project.pbxproj index c80a0bd66d..d076fd315f 100644 --- a/ios/KeyboardControllerNative/KeyboardControllerNative.xcodeproj/project.pbxproj +++ b/ios/KeyboardControllerNative/KeyboardControllerNative.xcodeproj/project.pbxproj @@ -593,6 +593,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.keyboardcontroller.KeyboardControllerNativeTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) KEYBOARD_CONTROLLER_NEW_ARCH_ENABLED"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -613,6 +614,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.keyboardcontroller.KeyboardControllerNativeTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) KEYBOARD_CONTROLLER_NEW_ARCH_ENABLED"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/ios/KeyboardControllerNative/KeyboardControllerNativeTests/KeyboardControllerNativeTests.swift b/ios/KeyboardControllerNative/KeyboardControllerNativeTests/KeyboardControllerNativeTests.swift index 90c4c324c3..b6e68b2629 100644 --- a/ios/KeyboardControllerNative/KeyboardControllerNativeTests/KeyboardControllerNativeTests.swift +++ b/ios/KeyboardControllerNative/KeyboardControllerNativeTests/KeyboardControllerNativeTests.swift @@ -8,6 +8,19 @@ @testable import KeyboardControllerNative import XCTest +#if KEYBOARD_CONTROLLER_NEW_ARCH_ENABLED +extension NSObject { + func safeValue(forKey key: String) -> Any? { + return value(forKey: key) + } +} + +@objcMembers +private final class ReactSuperview: UIView { + dynamic var nativeId: String? +} +#endif + extension XCTestCase { func waitForFocusChange( to textField: TestableInput, @@ -94,6 +107,29 @@ final class KeyboardControllerNativeTests: XCTestCase { // Put teardown code here. This method is called after the invocation of each test method in the class. } + #if KEYBOARD_CONTROLLER_NEW_ARCH_ENABLED + func testNativeIDReturnsNilForUIKitSuperviewWithoutNativeID() { + let superview = UIView() + let textField = UITextField() + superview.addSubview(textField) + + let responder: UIResponder? = textField + + XCTAssertNil(responder.nativeID) + } + + func testNativeIDReadsReactSuperviewNativeID() { + let superview = ReactSuperview() + let textField = UITextField() + superview.nativeId = "react-view" + superview.addSubview(textField) + + let responder: UIResponder? = textField + + XCTAssertEqual(responder.nativeID, "react-view") + } + #endif + func testSetFocusToNextShouldSetFocusToNextField() { let textInput1 = textFields[0] FocusedInputHolder.shared.set(textInput1) diff --git a/ios/extensions/UIResponder.swift b/ios/extensions/UIResponder.swift index 205a5fb060..f59c5bcac9 100644 --- a/ios/extensions/UIResponder.swift +++ b/ios/extensions/UIResponder.swift @@ -30,6 +30,7 @@ public extension Optional where Wrapped == UIResponder { guard let superview = (self as? UIView)?.superview else { return nil } #if KEYBOARD_CONTROLLER_NEW_ARCH_ENABLED + guard superview.responds(to: NSSelectorFromString("nativeId")) else { return nil } return superview.safeValue(forKey: "nativeId") as? String #else return superview.nativeID