App Store Rejection: Guideline 2.3.1 - Performance

Hi we got this rejection from Apple for mangled selectors to do with the Expo frameworks.

How do we solve this issue?


Guideline 2.3.1 - Performance

We discovered that your app contains obfuscated code, selector mangling, or features meant to subvert the App Review process by changing this app’s concept after approval to the App Store.

The next submission of this app may require a longer review time, and this app will not be eligible for an expedited review until this issue is resolved.


This app is verified to contain mangled selectors such as [u1CN1Q3F d6lIdAjX] and [q9PLGZUt f4bRioHQ]. We recommend that you use the “nm” tool or the command line tools “strings” or “otool -ov” to find the entities that are causing this rejection. It would be appropriate to remove all obfuscation from this app or to explain in detail the reason for its inclusion.

(these correspond to the expo frameworks)

is this in an ejected project or a managed workflow project?

This is an ejected project using ExpoKit

Here are the contents of our pod file:

source ‘GitHub - CocoaPods/Specs: The CocoaPods Master Repo
platform :ios, ‘10.0’

target ‘vine-health’ do
pod ‘ExpoKit’,
:git => “GitHub - expo/expo: An open-source platform for making universal native apps with React. Expo runs on Android, iOS, and the web.”,
:tag => “ios/2.10.2”,
:subspecs => [
“Core”
],
:inhibit_warnings => true
pod ‘Firebase/Core’, ‘~> 5.15.0’
pod ‘Firebase/Auth’, ‘~> 5.15.0’
pod ‘Firebase/Firestore’, ‘~> 5.15.0’
pod ‘Firebase/Messaging’, ‘~> 5.15.0’
pod ‘Fabric’
pod ‘Crashlytics’
pod ‘EXAdsAdMob’,
:path => “…/node_modules/expo-ads-admob/ios”
pod ‘EXAppAuth’,
:path => “…/node_modules/expo-app-auth/ios”
pod ‘EXAppLoaderProvider’,
:path => “…/node_modules/expo-app-loader-provider/ios”
pod ‘EXBackgroundFetch’,
:path => “…/node_modules/expo-background-fetch/ios”
pod ‘EXBarCodeScanner’,
:path => “…/node_modules/expo-barcode-scanner/ios”
pod ‘EXBarCodeScannerInterface’,
:path => “…/node_modules/expo-barcode-scanner-interface/ios”
pod ‘EXCamera’,
:path => “…/node_modules/expo-camera/ios”
pod ‘EXCameraInterface’,
:path => “…/node_modules/expo-camera-interface/ios”
pod ‘EXConstants’,
:path => “…/node_modules/expo-constants/ios”
pod ‘EXConstantsInterface’,
:path => “…/node_modules/expo-constants-interface/ios”
pod ‘EXContacts’,
:path => “…/node_modules/expo-contacts/ios”
pod ‘EXCore’,
:path => “…/node_modules/expo-core/ios”
pod ‘EXErrors’,
:path => “…/node_modules/expo-errors/ios”
pod ‘EXFaceDetectorInterface’,
:path => “…/node_modules/expo-face-detector-interface/ios”
pod ‘EXFileSystem’,
:path => “…/node_modules/expo-file-system/ios”
pod ‘EXFileSystemInterface’,
:path => “…/node_modules/expo-file-system-interface/ios”
pod ‘EXFont’,
:path => “…/node_modules/expo-font/ios”
pod ‘EXFontInterface’,
:path => “…/node_modules/expo-font-interface/ios”
pod ‘EXGoogleSignIn’,
:path => “…/node_modules/expo-google-sign-in/ios”
pod ‘EXGL’,
:path => “…/node_modules/expo-gl/ios”
pod ‘EXGL-CPP’,
:path => “…/node_modules/expo-gl-cpp/cpp”
pod ‘EXImageLoaderInterface’,
:path => “…/node_modules/expo-image-loader-interface/ios”
pod ‘EXLocalAuthentication’,
:path => “…/node_modules/expo-local-authentication/ios”
pod ‘EXLocalization’,
:path => “…/node_modules/expo-localization/ios”
pod ‘EXLocation’,
:path => “…/node_modules/expo-location/ios”
pod ‘EXMediaLibrary’,
:path => “…/node_modules/expo-media-library/ios”
pod ‘EXPermissions’,
:path => “…/node_modules/expo-permissions/ios”
pod ‘EXPermissionsInterface’,
:path => “…/node_modules/expo-permissions-interface/ios”
pod ‘EXPrint’,
:path => “…/node_modules/expo-print/ios”
pod ‘EXReactNativeAdapter’,
:path => “…/node_modules/expo-react-native-adapter/ios”
pod ‘EXSegment’,
:path => “…/node_modules/expo-analytics-segment/ios”
pod ‘EXSensors’,
:path => “…/node_modules/expo-sensors/ios”
pod ‘EXSensorsInterface’,
:path => “…/node_modules/expo-sensors-interface/ios”
pod ‘EXSMS’,
:path => “…/node_modules/expo-sms/ios”
pod ‘EXTaskManager’,
:path => “…/node_modules/expo-task-manager/ios”
pod ‘EXTaskManagerInterface’,
:path => “…/node_modules/expo-task-manager-interface/ios”

pod ‘React’,
:path => “…/node_modules/react-native”,
:inhibit_warnings => true,
:subspecs => [
“Core”,
“ART”,
“RCTActionSheet”,
“RCTAnimation”,
“RCTCameraRoll”,
“RCTGeolocation”,
“RCTImage”,
“RCTNetwork”,
“RCTText”,
“RCTVibration”,
“RCTWebSocket”,
“DevSupport”,
“CxxBridge”
]
pod ‘yoga’,
:path => “…/node_modules/react-native/ReactCommon/yoga”,
:inhibit_warnings => true
pod ‘DoubleConversion’,
:podspec => “…/node_modules/react-native/third-party-podspecs/DoubleConversion.podspec”,
:inhibit_warnings => true
pod ‘Folly’,
:podspec => “…/node_modules/react-native/third-party-podspecs/Folly.podspec”,
:inhibit_warnings => true
pod ‘glog’,
:podspec => “…/node_modules/react-native/third-party-podspecs/glog.podspec”,
:inhibit_warnings => true

post_install do |installer|
installer.pods_project.main_group.tab_width = ‘2’;
installer.pods_project.main_group.indent_width = ‘2’;

installer.pod_targets.each do |target|

if target.pod_name == 'ExpoKit'
  target.native_target.build_configurations.each do |config|
    config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)']
    config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'EX_DETACHED=1'

    # needed for GoogleMaps 2.x
    config.build_settings['FRAMEWORK_SEARCH_PATHS'] ||= []
    config.build_settings['FRAMEWORK_SEARCH_PATHS'] << '${PODS_ROOT}/GoogleMaps/Base/Frameworks'
    config.build_settings['FRAMEWORK_SEARCH_PATHS'] << '${PODS_ROOT}/GoogleMaps/Maps/Frameworks'
  end
end


if ['Amplitude-iOS','Analytics','AppAuth','Branch','CocoaLumberjack','FBSDKCoreKit','FBSDKLoginKit','FBSDKShareKit','GPUImage','JKBigInteger2'].include? target.pod_name
  target.native_target.build_configurations.each do |config|
    config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '10.0'
  end
end
# Can't specify this in the React podspec because we need
# to use those podspecs for detached projects which don't reference ExponentCPP.
if target.pod_name.start_with?('React')
  target.native_target.build_configurations.each do |config|
    config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '10.0'
    config.build_settings['HEADER_SEARCH_PATHS'] ||= ['$(inherited)']
  end
end
# Build React Native with RCT_DEV enabled and RCT_ENABLE_INSPECTOR and
# RCT_ENABLE_PACKAGER_CONNECTION disabled
next unless target.pod_name == 'React'
target.native_target.build_configurations.each do |config|
  config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)']
  config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'RCT_DEV=1'
  config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'RCT_ENABLE_INSPECTOR=0'
  config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'ENABLE_PACKAGER_CONNECTION=0'
end

end

end
end

We can’t tell what’s going on with the information here and other developers aren’t running into this issue. Do you have any of those “mangled selectors” in your source code? Have you looked into the binary to see where the selectors are coming from?