Skip to content

Commit

Permalink
[ios][updates][tools] fix swift casting runtime exception (expo#23132)
Browse files Browse the repository at this point in the history
# Why

close ENG-9094

# How

- this is again the swift runtime exception for casting versioned class to unversioned class like expo#23012 (comment). this time it's the `EXUpdatesUpdate` and solved by the `object_setClass` too.
- moving the `object_setClass` to expo-go only `EXUpdatesBinding` class which is a proper place to do the casting. however, this requires more swift <-> objc interop like adding swift compatibility header to search paths and adding `-fmodule-map`.
- some refactoring for the expokit podspec

# Test Plan

- ci passed
- test local expo-go to load sdk 49 updates (both classic updates and eas updates)
  • Loading branch information
Kudo authored Jun 27, 2023
1 parent c87ab94 commit 79294b5
Show file tree
Hide file tree
Showing 11 changed files with 88 additions and 66 deletions.
16 changes: 6 additions & 10 deletions ios/ExpoKit.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@

# generated from template-files/ios/ExpoKit.podspec

folly_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1'
folly_compiler_flags = folly_flags + ' ' + '-Wno-comma -Wno-shorten-64-to-32'
boost_compiler_flags = '-Wno-documentation'

Pod::Spec.new do |s|
s.name = "ExpoKit"
s.version = "49.0.0"
Expand All @@ -14,18 +18,10 @@ Pod::Spec.new do |s|
s.swift_version = '5.4'
s.default_subspec = "Core"
s.source = { :git => "http://github.com/expo/expo.git" }
s.xcconfig = {
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17',
'SYSTEM_HEADER_SEARCH_PATHS' => "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/Headers/Private/React-Core\"",
'OTHER_CPLUSPLUSFLAGS' => [
"$(OTHER_CFLAGS)",
"-DFOLLY_NO_CONFIG",
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1"
]
}
s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags

s.pod_target_xcconfig = {
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17',
'USE_HEADERMAP' => 'YES',
'DEFINES_MODULE' => 'YES',
}
Expand Down
20 changes: 18 additions & 2 deletions ios/Exponent/Versioned/Core/UniversalModules/EXUpdatesBinding.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

#import "EXUpdatesBinding.h"

#import <objc/runtime.h>

#import "ExpoModulesCore-Swift.h"
#if __has_include(<EXUpdatesInterface/EXUpdatesInterface-Swift.h>)
#import <EXUpdatesInterface/EXUpdatesInterface-Swift.h>
#else
#import "EXUpdatesInterface-Swift.h"
#endif
#import "EXUpdates-Swift.h"

NS_ASSUME_NONNULL_BEGIN

@interface EXUpdatesBinding ()
Expand Down Expand Up @@ -34,7 +44,10 @@ - (instancetype)initWithScopeKey:(NSString *)scopeKey updatesKernelService:(id<E

- (nullable EXUpdatesConfig *)config
{
return [_updatesKernelService configForScopeKey:_scopeKey];
EXUpdatesConfig *config = [_updatesKernelService configForScopeKey:_scopeKey];
// Ensures the universal UpdatesConfig can cast to versioned UpdatesConfig without exception in Swift
object_setClass(config, [EXUpdatesConfig class]);
return config;
}

- (EXUpdatesDatabase *)database
Expand All @@ -59,7 +72,10 @@ - (nullable EXUpdatesUpdate *)embeddedUpdate

- (nullable EXUpdatesUpdate *)launchedUpdate
{
return [_updatesKernelService launchedUpdateForScopeKey:_scopeKey];
EXUpdatesUpdate *update = [_updatesKernelService launchedUpdateForScopeKey:_scopeKey];
// Ensures the universal UpdatesUpdate can cast to versioned UpdatesUpdate without exception in Swift
object_setClass(update, [EXUpdatesUpdate class]);
return update;
}

- (nullable NSDictionary *)assetFilesMap
Expand Down
4 changes: 2 additions & 2 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4801,7 +4801,7 @@ SPEC CHECKSUMS:
ABI49_0_0ExpoImagePicker: 8355e9cf4fdc820f8cfa26add2a423dbd49d70cc
ABI49_0_0ExpoInsights: d4433e3114fc7fd01edbc82aa8cb72c0e346f40d
ABI49_0_0ExpoKeepAwake: 5508e162548e92d0087811d63218030135ad45e0
ABI49_0_0ExpoKit: fa5acd90ed671ccf3fa62fc70ae8b8a8502041ce
ABI49_0_0ExpoKit: 10bd3eaf309f90689d5e783712d9c903eeae45f2
ABI49_0_0ExpoLinearGradient: 98f9ba2f1b8bf7cc3974c1681114d58a2c07341f
ABI49_0_0ExpoLocalAuthentication: fbc31ba5781a6b74fe8cd4f4dbbac4200ff8b076
ABI49_0_0ExpoLocalization: ecce53a514e89c84e43ce3ed9fe38bf30258c99b
Expand Down Expand Up @@ -4949,7 +4949,7 @@ SPEC CHECKSUMS:
EXSplashScreen: 76a140851af574dfe1d22d7ec189cd183f28ab49
EXStructuredHeaders: 324cc3130571d2696357fafd8be7fd9a0b5fdf6e
EXTaskManager: f1730c315eb6fe457a3a2ee4ed899a51d717f302
EXUpdates: 5e7b88f34f110798fdd759a057a4d3749d62fd10
EXUpdates: 0c0c896ef50a67ea38f3348fe0053b4e205dcc69
EXUpdatesInterface: 65a425322c67e3c96952b47ac110df3fef65c6b3
FBAEMKit: c7efe06720a8b15b1d25b68921ba46dee20996e0
FBAudienceNetwork: e0fcc9091fced34910ed0b6da06f129db46ac9e6
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,29 @@ Pod::Spec.new do |s|
s.swift_version = '5.4'
s.default_subspec = "Core"
s.source = { :git => "http://github.com/expo/expo.git" }
s.xcconfig = {
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17',
'SYSTEM_HEADER_SEARCH_PATHS' => "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/Headers/Private/React-Core\"",
'OTHER_CPLUSPLUSFLAGS' => [
"$(OTHER_CFLAGS)",
"-DFOLLY_NO_CONFIG",
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1"
]
}
s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags

s.pod_target_xcconfig = {
'USE_HEADERMAP' => 'YES',
'DEFINES_MODULE' => 'YES',
}


header_search_paths = [
'"$(PODS_ROOT)/boost"',
'"$(PODS_ROOT)/glog"',
'"$(PODS_ROOT)/DoubleConversion"',
'"$(PODS_ROOT)/RCT-Folly"',
'"$(PODS_ROOT)/Headers/Private/ABI49_0_0React-Core"',
'"$(PODS_CONFIGURATION_BUILD_DIR)/ABI49_0_0ExpoModulesCore/Swift Compatibility Header"',
'"$(PODS_CONFIGURATION_BUILD_DIR)/ABI49_0_0EXUpdatesInterface/Swift Compatibility Header"',
'"$(PODS_CONFIGURATION_BUILD_DIR)/ABI49_0_0EXUpdates/Swift Compatibility Header"',
]
s.pod_target_xcconfig = {
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
"USE_HEADERMAP" => "YES",
"DEFINES_MODULE" => "YES",
"HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_TARGET_SRCROOT)\" \"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/Headers/Private/ABI49_0_0React-Core\" \"$(PODS_CONFIGURATION_BUILD_DIR)/ABI49_0_0ExpoModulesCore/Swift Compatibility Header\""
}
s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags
s.xcconfig = {
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
"HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/glog\" \"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/Headers/Private/ABI49_0_0React-Core\" \"$(PODS_CONFIGURATION_BUILD_DIR)/ABI49_0_0ExpoModulesCore/Swift Compatibility Header\"",
"OTHER_CFLAGS" => "$(inherited)" + " " + folly_flags
"HEADER_SEARCH_PATHS" => header_search_paths.join(' '),
}

s.subspec "Expo" do |ss|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

#import "ABI49_0_0EXUpdatesBinding.h"

#import <objc/runtime.h>

#import "ABI49_0_0ExpoModulesCore-Swift.h"
#if __has_include(<ABI49_0_0EXUpdatesInterface/ABI49_0_0EXUpdatesInterface-Swift.h>)
#import <ABI49_0_0EXUpdatesInterface/ABI49_0_0EXUpdatesInterface-Swift.h>
#else
#import "ABI49_0_0EXUpdatesInterface-Swift.h"
#endif
#import "ABI49_0_0EXUpdates-Swift.h"

NS_ASSUME_NONNULL_BEGIN

@interface ABI49_0_0EXUpdatesBinding ()
Expand Down Expand Up @@ -34,7 +44,10 @@ - (instancetype)initWithScopeKey:(NSString *)scopeKey updatesKernelService:(id<A

- (nullable ABI49_0_0EXUpdatesConfig *)config
{
return [_updatesKernelService configForScopeKey:_scopeKey];
ABI49_0_0EXUpdatesConfig *config = [_updatesKernelService configForScopeKey:_scopeKey];
// Ensures the universal UpdatesConfig can cast to versioned UpdatesConfig without exception in Swift
object_setClass(config, [ABI49_0_0EXUpdatesConfig class]);
return config;
}

- (ABI49_0_0EXUpdatesDatabase *)database
Expand All @@ -59,7 +72,10 @@ - (nullable ABI49_0_0EXUpdatesUpdate *)embeddedUpdate

- (nullable ABI49_0_0EXUpdatesUpdate *)launchedUpdate
{
return [_updatesKernelService launchedUpdateForScopeKey:_scopeKey];
ABI49_0_0EXUpdatesUpdate *update = [_updatesKernelService launchedUpdateForScopeKey:_scopeKey];
// Ensures the universal UpdatesUpdate can cast to versioned UpdatesUpdate without exception in Swift
object_setClass(update, [ABI49_0_0EXUpdatesUpdate class]);
return update;
}

- (nullable NSDictionary *)assetFilesMap
Expand Down
2 changes: 2 additions & 0 deletions ios/versioned-react-native/ABI49_0_0/postinstalls.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
-DgNodeInstanceCount=ABI49_0_0ReactgNodeInstanceCount
-fmodule-map-file="${PODS_ROOT}/Headers/Public/ABI49_0_0React-Core/ABI49_0_0React/ABI49_0_0React-Core.modulemap"
-fmodule-map-file="${PODS_ROOT}/Headers/Public/ABI49_0_0ExpoModulesCore/ABI49_0_0ExpoModulesCore.modulemap"
-fmodule-map-file="${PODS_ROOT}/Headers/Public/ABI49_0_0EXUpdates/ABI49_0_0EXUpdates.modulemap"
-fmodule-map-file="${PODS_ROOT}/Headers/Public/ABI49_0_0EXUpdatesInterface/ABI49_0_0EXUpdatesInterface.modulemap"
]
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)']
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'ABI49_0_0RCT_DEV=1'
Expand Down
2 changes: 0 additions & 2 deletions ios/versioned/sdk49/EXUpdates/EXUpdates/UpdatesModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ public final class UpdatesModule: Module {

public required init(appContext: AppContext) {
updatesService = appContext.legacyModule(implementing: ABI49_0_0EXUpdatesModuleInterface.self)
// Ensures the universal UpdatesConfig can cast to versioned UpdatesConfig without exception in Swift
object_setClass(updatesService?.config, UpdatesConfig.self)
super.init(appContext: appContext)
}

Expand Down
3 changes: 3 additions & 0 deletions packages/expo-updates/ios/EXUpdates.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ Pod::Spec.new do |s|
'OTHER_CFLAGS[config=Debug]' => other_c_flags,
'OTHER_SWIFT_FLAGS[config=Debug]' => other_swift_flags
}
s.user_target_xcconfig = {
'HEADER_SEARCH_PATHS' => '"${PODS_CONFIGURATION_BUILD_DIR}/EXUpdates/Swift Compatibility Header"',
}

if !ex_updates_native_debug && !$ExpoUseSources&.include?(package['name']) && ENV['EXPO_USE_SOURCE'].to_i == 0 && File.exist?("#{s.name}.xcframework") && Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.10.0')
s.source_files = "#{s.name}/**/*.h"
Expand Down
2 changes: 0 additions & 2 deletions packages/expo-updates/ios/EXUpdates/UpdatesModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ public final class UpdatesModule: Module {

public required init(appContext: AppContext) {
updatesService = appContext.legacyModule(implementing: EXUpdatesModuleInterface.self)
// Ensures the universal UpdatesConfig can cast to versioned UpdatesConfig without exception in Swift
object_setClass(updatesService?.config, UpdatesConfig.self)
super.init(appContext: appContext)
}

Expand Down
16 changes: 6 additions & 10 deletions template-files/ios/ExpoKit.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@

# generated from template-files/ios/ExpoKit.podspec

folly_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1'
folly_compiler_flags = folly_flags + ' ' + '-Wno-comma -Wno-shorten-64-to-32'
boost_compiler_flags = '-Wno-documentation'

Pod::Spec.new do |s|
s.name = "ExpoKit"
s.version = "${IOS_EXPONENT_CLIENT_VERSION}"
Expand All @@ -14,18 +18,10 @@ Pod::Spec.new do |s|
s.swift_version = '5.4'
s.default_subspec = "Core"
s.source = { :git => "http://github.com/expo/expo.git" }
s.xcconfig = {
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17',
'SYSTEM_HEADER_SEARCH_PATHS' => "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/Headers/Private/React-Core\"",
'OTHER_CPLUSPLUSFLAGS' => [
"$(OTHER_CFLAGS)",
"-DFOLLY_NO_CONFIG",
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1"
]
}
s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags

s.pod_target_xcconfig = {
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17',
'USE_HEADERMAP' => 'YES',
'DEFINES_MODULE' => 'YES',
}
Expand Down
39 changes: 20 additions & 19 deletions tools/src/versioning/ios/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -629,29 +629,27 @@ async function generateExpoKitPodspecAsync(
fileString = fileString.replace(/(?<=s.version = ").*?(?=")/g, versionNumber);

// add Reanimated V2 RCT-Folly dependency
fileString = fileString
.replace(
/(?=Pod::Spec.new do \|s\|)/,
`
folly_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1'
folly_compiler_flags = folly_flags + ' ' + '-Wno-comma -Wno-shorten-64-to-32'
boost_compiler_flags = '-Wno-documentation'\n\n`
)
.replace(
/(?= s.subspec "Expo" do \|ss\|)/g,
`
fileString = fileString.replace(
/(?= s.subspec "Expo" do \|ss\|)/g,
`
header_search_paths = [
'"$(PODS_ROOT)/boost"',
'"$(PODS_ROOT)/glog"',
'"$(PODS_ROOT)/DoubleConversion"',
'"$(PODS_ROOT)/RCT-Folly"',
'"$(PODS_ROOT)/Headers/Private/${versionName}React-Core"',
'"$(PODS_CONFIGURATION_BUILD_DIR)/${versionName}ExpoModulesCore/Swift Compatibility Header"',
'"$(PODS_CONFIGURATION_BUILD_DIR)/${versionName}EXUpdatesInterface/Swift Compatibility Header"',
'"$(PODS_CONFIGURATION_BUILD_DIR)/${versionName}EXUpdates/Swift Compatibility Header"',
]
s.pod_target_xcconfig = {
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
"USE_HEADERMAP" => "YES",
"DEFINES_MODULE" => "YES",
"HEADER_SEARCH_PATHS" => "\\"$(PODS_TARGET_SRCROOT)/ReactCommon\\" \\"$(PODS_TARGET_SRCROOT)\\" \\"$(PODS_ROOT)/RCT-Folly\\" \\"$(PODS_ROOT)/boost\\" \\"$(PODS_ROOT)/DoubleConversion\\" \\"$(PODS_ROOT)/Headers/Private/${versionName}React-Core\\" \\"\$(PODS_CONFIGURATION_BUILD_DIR)/${versionName}ExpoModulesCore/Swift Compatibility Header\\""
"HEADER_SEARCH_PATHS" => header_search_paths.join(' '),
}
s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags
s.xcconfig = {
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
"HEADER_SEARCH_PATHS" => "\\"$(PODS_ROOT)/boost\\" \\"$(PODS_ROOT)/glog\\" \\"$(PODS_ROOT)/RCT-Folly\\" \\"$(PODS_ROOT)/Headers/Private/${versionName}React-Core\\" \\"\$(PODS_CONFIGURATION_BUILD_DIR)/${versionName}ExpoModulesCore/Swift Compatibility Header\\"",
"OTHER_CFLAGS" => "$(inherited)" + " " + folly_flags
}\n\n`
);
\n\n`
);

return fileString;
});
Expand Down Expand Up @@ -828,6 +826,9 @@ if pod_name.start_with?('${versionedPodNames.React}') || pod_name == '${versione
${configValues.join(`\n${indent}`)}
-fmodule-map-file="\${PODS_ROOT}/Headers/Public/${versionName}React-Core/${versionName}React/${versionName}React-Core.modulemap"
-fmodule-map-file="\${PODS_ROOT}/Headers/Public/${versionName}ExpoModulesCore/${versionName}ExpoModulesCore.modulemap"
-fmodule-map-file="\${PODS_ROOT}/Headers/Public/${versionName}ExpoModulesCore/${versionName}ExpoModulesCore.modulemap"
-fmodule-map-file="\${PODS_ROOT}/Headers/Public/${versionName}EXUpdates/${versionName}EXUpdates.modulemap"
-fmodule-map-file="\${PODS_ROOT}/Headers/Public/${versionName}EXUpdatesInterface/${versionName}EXUpdatesInterface.modulemap"
]
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)']
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << '${versionName}RCT_DEV=1'
Expand Down

0 comments on commit 79294b5

Please sign in to comment.