The author should update their experience to a newer Expo SDK version

Hey there!

I’m using ExpoKit in a detached app.

I’ve already read through The experience you requested uses Expo SDK v26.0.0, but requires v27.0.0 - #5

But that didn’t help.

We need to update the logo and screenshots in the App Store, so I needed to create a new build, but because XCode had changed, I needed to upgrade from 27 to 29 (Build errors when trying to use expokit with Xcode 10 - Objective C related [Fixed] · Issue #2002 · expo/expo · GitHub).

I managed to get everything working fine locally using simulator or physical device, but once I pushed the archive to the app store from XCode and tested with Test Flight, I get:

The experience you requested uses Expo SDK v27.0.0, but this copy of Expo Client requires at least v29.0.0. The author should update their experience to a newer Expo SDK version.

I’m pretty sure I diligently followed the upgrade from 27 to 28 and then 28 to 29.

For 27->28 I followed:

For 28->29 I followed:

My app.json:

{
  "expo": {
    "name": "***",
    "description": "***",
    "slug": "***",
    "privacy": "unlisted",
    "sdkVersion": "29.0.0",
    "platforms": [
      "ios",
      "android"
    ],
    "version": "0.4.1",
    "icon": "./assets/icon.png",
    "primaryColor": "#FFFFFF",
    "scheme": "***",
    "splash": {
      "image": "./assets/splash.png",
      "resizeMode": "contain",
      "backgroundColor": "#ffffff"
    },
    "assetBundlePatterns": [
      "**/*"
    ],
    "ios": {
      "bundleIdentifier": "***",
      "publishBundlePath": "ios/***/Supporting/shell-app.bundle",
      "publishManifestPath": "ios/***/Supporting/shell-app-manifest.json"
    },
    "android": {
      "package": "***",
      "versionCode": 4,
      "publishBundlePath": "android/app/src/main/assets/shell-app.bundle",
      "publishManifestPath": "android/app/src/main/assets/shell-app-manifest.json"
    },
    "isDetached": true,
    "detach": {
      "scheme": "expb663efa42680460faaf9e6ada29c060e",
      "iosExpoViewUrl": "https://s3.amazonaws.com/exp-exponent-view-code/ios-v2.2.1-sdk24.0.0-36ff2264-629d-44df-a819-8c982454e5e8.tar.gz",
      "androidExpoViewUrl": "https://s3.amazonaws.com/exp-exponent-view-code/android-v2.2.0-sdk24.0.0-16620828-4df4-4e2d-b0af-5dc1352b82cb.tar.gz"
    }
  }
}

My package.json

{
  "main": "node_modules/expo/AppEntry.js",
  "private": true,
  "dependencies": {
    "@expo/vector-icons": "^6.2.2",
    "analytics-react-native": "^1.2.0",
    "axios": "^0.17.0",
    "babel-preset-es2015": "^6.24.1",
    "expo": "^29.0.0",
    "expokit": "1.5.0",
    "firebase": "4.6.1",
    "history": "^4.7.2",
    "jwt-decode": "^2.2.0",
    "moment": "^2.18.1",
    "prismic-dom": "^2.0.0",
    "prismic-javascript": "^1.2.0",
    "prismic-reactjs": "^0.1.0",
    "prop-types": "^15.5.10",
    "query-string": "^5.0.1",
    "react": "16.3.1",
    "react-native": "https://github.com/expo/react-native/archive/sdk-29.0.0.tar.gz",
    "react-native-elements": "^0.18.5",
    "react-native-iap": "^0.3.23",
    "react-native-status-bar-height": "^1.0.1",
    "react-redux": "^5.0.6",
    "react-router": "^4.2.0",
    "react-router-dom": "^4.2.2",
    "react-router-native": "^4.2.0",
    "react-router-redux": "^5.0.0-alpha.6",
    "react-timeout": "^1.0.1",
    "redux": "^3.7.2",
    "redux-saga": "^0.16.0",
    "whatwg-fetch": "^2.0.4"
  },
  "devDependencies": {
    "reactotron-react-native": "^1.14.0",
    "reactotron-redux": "^1.13.0",
    "remote-redux-devtools": "^0.5.12"
  }
}

My Podfile:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'

target '***' do
  pod 'ExpoKit',
    :git => "http://github.com/expo/expo.git",
    :tag => "ios/2.7.8",
    :subspecs => [
      "Core"
    ],
    :inhibit_warnings => true
  pod 'EXGL',
    :path => "../node_modules/expo-gl/ios",
    :inhibit_warnings => true
  pod 'EXCore',
    :path => "../node_modules/expo-core/ios",
    :inhibit_warnings => true
  pod 'EXCamera',
    :path => "../node_modules/expo-camera/ios",
    :inhibit_warnings => true
  pod 'EXSensors',
    :path => "../node_modules/expo-sensors/ios",
    :inhibit_warnings => true
  pod 'EXConstants',
    :path => "../node_modules/expo-constants/ios",
    :inhibit_warnings => true
  pod 'EXFileSystem',
    :path => "../node_modules/expo-file-system/ios",
    :inhibit_warnings => true
  pod 'EXPermissions',
    :path => "../node_modules/expo-permissions/ios",
    :inhibit_warnings => true
  pod 'EXCameraInterface',
    :path => "../node_modules/expo-camera-interface/ios",
    :inhibit_warnings => true
  pod 'EXSensorsInterface',
    :path => "../node_modules/expo-sensors-interface/ios",
    :inhibit_warnings => true
  pod 'EXConstantsInterface',
    :path => "../node_modules/expo-constants-interface/ios",
    :inhibit_warnings => true
  pod 'EXReactNativeAdapter',
    :path => "../node_modules/expo-react-native-adapter/ios",
    :inhibit_warnings => true
  pod 'EXFileSystemInterface',
    :path => "../node_modules/expo-file-system-interface/ios",
    :inhibit_warnings => true
  pod 'EXPermissionsInterface',
    :path => "../node_modules/expo-permissions-interface/ios",
    :inhibit_warnings => true
  pod 'EXFaceDetectorInterface',
    :path => "../node_modules/expo-face-detector-interface/ios",
    :inhibit_warnings => true
  pod 'EXSMS',
    :path => "../node_modules/expo-sms/ios",
    :inhibit_warnings => true
  pod 'EXGL-CPP',
    :path => "../node_modules/expo-gl-cpp/cpp",
    :inhibit_warnings => true

  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'] = '9.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['HEADER_SEARCH_PATHS'] ||= ['$(inherited)']
        config.build_settings['HEADER_SEARCH_PATHS'] << "${PODS_ROOT}/Headers/Public/${EXPO_CPP_HEADER_DIR}"
      end
    end
    # Build React Native with RCT_DEV enabled
    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'
    end

    end
  end
end

I removed my node_modules and re-installed. I removed Pods and re-installed those. I’m not sure what else to do :confused:

Hi @ec_raphael - have you by any chance run expo publish at least once since upgrading? The build step to embed a local copy of your JS bundle in your IPA grabs the version you last published, which in your case sounds like it may still be on SDK 27.

This is different from a plain react-native app, which creates a new JS bundle from source at build-time, so it’s up-to-date with your working copy. We know our workflow isn’t great, and we’re working on it, but in the meantime apologies for the inconvenience :disappointed:

1 Like

Heya @esamelson! Thanks for the response :slight_smile: I actually got it working, and that’s pretty much what was up.

I had a hunch it might have something to do with the published version, so what I ended up doing because I wasn’t completely clear on how the published bundles are accessed/loaded is changing the release channel, publishing to the new one, and switching our new iOS and Android builds to the new release channel.

Out of curiosity, though, why doesn’t the build process just build it from scratch? Seems a bit counterintuitive that a bundle that will be embedded in the build has to be published.

@ec_raphael - honestly, it’s that way because it was easiest for us to build that way. The current ExpoKit workflow was sort of an afterthought to the original build process, of which publish is a step, and it was easier to just keep as many elements of the original process as possible. We’ve since realized that ExpoKit sees more use than we originally thought, and so we’re in the middle of rethinking and reworking ExpoKit to be more of a first-class citizen and have a more intuitive workflow. I hope that makes sense!

Totally makes sense, @esamelson. Exciting blog post, too!
Cheers :slight_smile:

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.