react-native: RCT_EXTERN_MODULE Swift modules broken in Xcode 10.2
š Bug Report
It appears Obj-C runtime got more strict with Swift ABI stability in Xcode 10.2 and now causes a crash at runtime when trying to load modules that have Swift implementations. This is the crash error:
Swift class extensions and categories on Swift classes are not allowed to have +load methods
To Reproduce
Create a RN NativeModule e.g.
BadgeHandler.m
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(BadgeHandler, NSObject)
RCT_EXTERN_METHOD(setBadgeNumber:(int *)badgeNumber)
@end
BadgeHandler.swift
import UIKit
@objc(BadgeHandler)
class BadgeHandler: NSObject, RCTBridgeModule {
static func moduleName() -> String! {
return "BadgeHandler";
}
static func requiresMainQueueSetup() -> Bool {
return true
}
@objc func setBadgeNumber(_ badgeNumber: Int) {
DispatchQueue.main.async {
UIApplication.shared.applicationIconBadgeNumber = badgeNumber
}
}
}
AppName-Bridging-Header.h
#ifndef AppName_Bridging_Header_h
#define AppName_Bridging_Header_h
#import <React/RCTBridgeModule.h>
#endif /* AppName_Bridging_Header_h */
Expected Behavior
The NativeModule would load fine at runtime like it did in previous versions of Xcode
Code Example
See above ^
Environment
React Native Environment Info:
System:
OS: macOS 10.14.3
CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
Memory: 31.36 MB / 32.00 GB
Shell: 5.3 - /bin/zsh
Binaries:
Node: 11.6.0 - /usr/local/bin/node
Yarn: 1.13.0 - /usr/local/bin/yarn
npm: 6.5.0 - /usr/local/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
iOS SDK:
Platforms: iOS 12.2, macOS 10.14, tvOS 12.2, watchOS 5.2
Android SDK:
API Levels: 23, 25, 26, 27, 28
Build Tools: 27.0.3, 28.0.2, 28.0.3
System Images: android-28 | Google APIs Intel x86 Atom
IDEs:
Xcode: 10.2/10E125 - /usr/bin/xcodebuild
npmPackages:
react: 16.8.3 => 16.8.3
react-native: 0.59.1 => 0.59.1
Other
This seems to point to this macro in RCTBridgeModule.h
:
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 77
- Comments: 65 (7 by maintainers)
Commits related to this issue
- Use constructor attribute instead of +load objc method (#24155) Summary: Xcode 10.2 forbids creating categories for swift class that uses `+load` method. In react-native categories like this are used... — committed to facebook/react-native by zienag 5 years ago
- Use constructor attribute instead of +load objc method (#24155) Summary: Xcode 10.2 forbids creating categories for swift class that uses `+load` method. In react-native categories like this are used... — committed to zhongwuzw/react-native by zienag 5 years ago
- Rebase Expose collapsable as React Prop in LayoutShadowNode Summary: This diff exposes the collapsable prop as part of LayoutShadowNode, fixing the bug of the collapsable prop being filtered by JS i... — committed to zhongwuzw/react-native by mdvacca 5 years ago
- mobile/node_modules/react-native: Backport #24155 - https://github.com/facebook/react-native/pull/24155 - https://github.com/facebook/react-native/issues/24139 - Occurred during upgrade: xcode 10 -> ... — committed to jdanbrown/birdgram by jdanbrown 5 years ago
- mobile/node_modules/react-native: Backport #24155 - https://github.com/facebook/react-native/pull/24155 - https://github.com/facebook/react-native/issues/24139 - Occurred during upgrade: xcode 10 -> ... — committed to jdanbrown/birdgram by jdanbrown 5 years ago
- Use constructor attribute instead of +load objc method (#24155) Summary: Xcode 10.2 forbids creating categories for swift class that uses `+load` method. In react-native categories like this are used... — committed to ethul/react-native by zienag 5 years ago
Hi! Iām not very familiar with react-native, but I found myself here because Iām blocked from upgrading to 10.2 by one of dependency that uses react-native.
I have an idea for a fix though:
The problem with this is that
RCT_EXPORT_MODULE
macro will require objc_name parameter now. As I understand, this is not very convenient, as it is used in many places by users. So another solution is to introduce another macro:And replace call in RCT_EXTERN_REMAP_MODULE to new macro:
Iām ok to make a pr, but it will take some time until I figure out how to setup everything.
Hey everyone - two things:
writing comments like āsame issueā doesnāt help at all. There are reactions for that. To prevent more spam, Iāll lock the issue for now
if you want to help, ideal case would be to submit a PR to fix the issue. Feel free to @ me in the PR so that we can try to have it reviewād and merged quickly.
Please make sure you are using RN 0.59.2 because thatās the only version we are going to patch once the PR with the fix lands - at least for now. To upgrade please refer to the documentation -> https://facebook.github.io/react-native/docs/upgrading#react-native-projects (if you are upgrading from an earlier version than 0.59.0 refer to https://github.com/pvinis/rn-diff-purge)
Weāll write more comments when we have more info on this.
Iāve implemented a (temporary) workaround, but Iām not sure how to fix it properly in React.
In your (Swift based) bridge modules, use the marco
RCT_EXPORT_PRE_REGISTERED_MODULE()
instead ofRCT_EXPORT_MODULE
. This prevents the+ (void)load
method to be implemented on it.Then, in your
main.m
, just register the Swift modules manually:If you canāt update your react-native version to get this fix when it is merged because you are using the Expo fork of react-native. Then add this code ( based on above PR ) to a header file:
Then in your module .m objective C file import that header file you just created and use
RCT_EXTERN_MODULE_2
instead ofRCT_EXTERN_MODULE
Example:
Fixed in 0.59.3 for me (Xcode 10.2, iOS 12.2)
The (semi) quick fix is to downgrade to Xcode 10.1.
Youāll find the download here: https://developer.apple.com/download/more/
After upgrading I had trouble with my simulators so I nuked them. The below will delete all simulators. You may then add back the ones you need. Use with care though.
xcrun simctl list | grep -oh '[A-Z0-9]\{8\}-[A-Z0-9]\{4\}-[A-Z0-9]\{4\}-[A-Z0-9]\{4\}-[A-Z0-9]\{12\}' | xargs -n1 xcrun simctl delete
Hi, guys. I solved this problem adding this 12.2 folder ( https://github.com/iGhibli/iOS-DeviceSupport/blob/master/DeviceSupport/12.2 (16E226).zip ) to Xcode(in applications) -> Show Package Contents -> Contents -> Developer -> iPhoneIOs.platform -> Device Support (you will see list of folders: 8.0, 8.1, 8.2 etcā¦). After you will add folder named 12.2 here - everything will work fine!
@mrTuomoK it looks like a PR with the fix landed (https://github.com/facebook/react-native/commit/ff66600224e78fec5d0e902f8a035b78ed31a961), Iāll see if we can cherry-pick it for 0.59.3 but if itās not possible it will be out in 0.60
I found a similar issue in one of the iconic-team repo. They just deleted all āloadā methods in their code to avoid this problem. I searched inside the react-native folder and found THREE files with +(void)load method for ios. They are: React/Base/RCTBridgeModule.h Libraries/WebSocket/RCTReconnectingWebSocket.m RNTester/Swizzle_RCTFabricSurface.m
Hope it helps.
@brenwell Iāve overwritten the whole node_modules/react-native/React/Base/RCTBridgeModule.h with the one coming from the pull requestā¦
My current workaround was to install iOS 12.1 simulator from xcode => preferences => components, and after that just launched the app with older simulator. It seems that the newer simulators use a lower-case second letter and the older ones capital. for example Xs => XS
Specifically, the error doesnāt happen on devices/simulators prior to 12.2. So it doesnāt seem xcode version related. It seems more tied to swift version.
@zienag a PR would be super appreciated š Iāve tried to raise this with the FB team but they are all in US atm so it will take them a few more hours to reply to me.
@kelset are there any expectations on release dates (approximately) for 0.59.3 and 0.60?
Sure. Have done. XD
Sorry about closing the issue here, looks like GitHub autoclose issues based on private references as well. š
(letās keep this open until the PR lands)
@omatrot zienagās proposed fix will automatically fix third part modules, because it modifies RCT_EXTERN_MODULE, which is how all Swift modules export themselves! If you simply include zienagās fix manually it will allow you to keep working using iOS 12.2.
Alternatively using a simulator for iOS 12.1 will cause this not to be an error as the issue is caused by the iOS version, not the XCode version š
Iād like to clarify that I donāt get this error on a physical device.
same issue, and I see the 0.59.2, + (void)load { RCTRegisterModule(self); } , has not changed Now I have reinstalled XCode 10.1 and xcode-select my env to XCode 10.1
update: I update RN to 0.59.3 and XCode 10.2. It work for me.