Failing to upgrade ExpoKit SDK from 30 to 33 (Android)

Hello.

I’m on my second try of upgrading Expo/ExpoKit from SDK 30 to 34.

For both 1st and 2nd try I first follow the steps for upgrading the JS part of the project here: Expo SDK v33.0.0 is now available | by Eric Samelson | Exposition.

For the first try, of upgrading ExpoKit, I think I got a bit confused, I started from the bottom of https://docs.expo.io/versions/latest/expokit/expokit/#upgrading-expokit, and worked my way up. Now, trying to a second time from the top, doing steps under “If upgrading from SDK31 or below” seems to have already been overwritten in the above steps. What is the intended order of following these docs? Top to bottom? Bottom to top? Something in between? It seems like the “If upgrading from” should be reversed and at the top?

I can manage to get the iOS project working, but the Android project fails to initialize in Android Studio.

I get the error:

The module 'expo-gl-cpp' is an Android project without build variants, and cannot be built.
Please fix the module's configuration in the build.gradle file and sync the project again.

If I manually install it with

yarn add expo-gl-cpp

It doesn’t do anything other than changing ‘expo-gl-cpp’ to ‘android-expo-gl-cpp’ in the above error message.

If I unload the module and try to build to the emulator I get:

Could not run build action using Gradle distribution 'https://services.gradle.org/distributions/gradle-4.4-all.zip'.

I’m not able to Google any of these errors in relation to Expo, so I’m guessing I messed up somewhere, but it’s difficult to determine where.

Here are my relevant files:
package.json

{
  "name": "pj-nativeapp",
  "version": "0.1.0",
  "private": true,
  "devDependencies": {
    "axios-debug": "0.0.4",
    "babel-plugin-module-resolver": "^3.1.1",
    "babel-plugin-transform-inline-environment-variables": "^0.4.3",
    "babel-plugin-transform-remove-console": "^6.9.4",
    "eslint": "^3.19.0",
    "eslint-config-prettier": "^4.0.0",
    "eslint-config-standard": "^10.2.1",
    "eslint-plugin-import": "^2.10.0",
    "eslint-plugin-node": "^4.2.2",
    "eslint-plugin-prettier": "^3.0.1",
    "eslint-plugin-promise": "^3.5.0",
    "eslint-plugin-react": "^7.0.1",
    "eslint-plugin-react-native": "^3.2.1",
    "eslint-plugin-standard": "^3.0.1",
    "jest-expo": "33.0.0",
    "plop": "^1.9.1",
    "prettier": "^1.16.4",
    "react-native-scripts": "1.11.1",
    "react-native-unimodules": "^0.4.0",
    "react-test-renderer": "16.2.0",
    "remote-redux-devtools": "^0.5.12"
  },
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "eject": "expo eject",
    "android": "expo android",
    "ios": "expo ios",
    "test": "node node_modules/jest/bin/jest.js",
    "remotedev": "remotedev --hostname=localhost --port=19000 --injectserver=reactnative",
    "remotedev-revert": "remotedev --revert=reactnative"
  },
  "jest": {
    "preset": "jest-expo"
  },
  "dependencies": {
    "counterpart": "^0.18.5",
    "events": "^2.0.0",
    "exp": "^57.2.1",
    "expo": "^33.0.0",
    "expokit": "^33.0.4",
    "fuse.js": "^3.2.1",
    "moment": "^2.22.2",
    "react": "16.8.3",
    "react-native": "https://github.com/expo/react-native/archive/sdk-33.0.0.tar.gz",
    "react-native-autolink": "^1.4.0",
    "react-native-card-flip": "^1.0.4",
    "react-native-expo-image-cache": "^3.2.0",
    "react-native-fbsdk": "^0.8.0",
    "react-native-gifted-chat": "^0.4.3",
    "react-native-iap": "^2.3.26",
    "react-native-keyboard-aware-scrollview": "^2.0.0",
    "react-native-keyboard-spacer": "^0.4.1",
    "react-native-onesignal": "^3.2.12",
    "react-native-sidebar": "^0.3.0",
    "react-native-stopwatch-timer": "^0.0.20",
    "react-native-tabs": "^1.0.9",
    "react-redux": "^6.0.0",
    "react-router-native": "^4.2.0",
    "reactotron-react-native": "^2.2.0",
    "reactotron-redux": "^2.1.3",
    "redux": "^3.7.2",
    "redux-thunk": "^2.2.0",
    "sentry-expo": "~1.13.0",
    "throttle-debounce": "^1.0.1",
    "util": "^0.10.3"
  }
}

build.gradle

buildscript {
  repositories {
    google()
    maven { url 'https://maven.fabric.io/public' }
    maven { url 'https://plugins.gradle.org/m2/' }
  }

  dependencies {
    classpath 'io.fabric.tools:gradle:1.+'
    classpath 'gradle.plugin.com.onesignal:onesignal-gradle-plugin:[0.12.1, 0.99.99]'
  }
}
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
apply plugin: 'com.onesignal.androidsdk.onesignal-gradle-plugin'

repositories {
  maven { url 'https://maven.fabric.io/public' }
}

android {
  compileSdkVersion 28
  buildToolsVersion '27.0.3'

  defaultConfig {
    applicationId 'com.plantjammer.plantjammer'
    targetSdkVersion 26
    versionCode 256
    versionName '2.48.2'
    ndk {
      abiFilters 'armeabi-v7a', 'x86'
    }
    multiDexEnabled true
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    // Deprecated. Used by net.openid:appauth
    manifestPlaceholders = [
      'appAuthRedirectScheme': 'host.exp.exponent'
    ]
  }
  dexOptions {
    javaMaxHeapSize System.getenv("DISABLE_DEX_MAX_HEAP") ? null : "8g"
  }
  buildTypes {
    debug {
      debuggable true
      ext.enableCrashlytics = false
    }
    release {
      minifyEnabled true
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
      zipAlignEnabled true
    }
  }
  signingConfigs {
    debug {
      storeFile file('../debug.keystore')
    }
  }
  lintOptions {
    abortOnError false
  }
  packagingOptions {
    pickFirst "**"
  }
  configurations.all {
    resolutionStrategy.force 'com.android.support:design:28.0.0'
  }
  compileOptions {
    sourceCompatibility 1.8
    targetCompatibility 1.8
  }
}

// Don't use modern jsc-android since it still has some critical bugs that
// crash applications when the string for the JS bundle is loaded and when
// locale-specific date functions are called.
// configurations.all {
//   resolutionStrategy {
//     force 'org.webkit:android-jsc:r216113'
//   }
// }


apply from: 'expo.gradle'

apply from: "../../node_modules/react-native-unimodules/gradle.groovy"

dependencies {
  compile project(':react-native-iap')
  compile project(':react-native-fbsdk')
  compile project(':react-native-onesignal')
  implementation fileTree(dir: 'libs', include: ['*.jar'])

  implementation 'com.android.support:multidex:1.0.1'

  // Our dependencies
  implementation 'com.android.support:appcompat-v7:28.0.0'

  // Our dependencies from ExpoView
  // DON'T ADD ANYTHING HERE THAT ISN'T IN EXPOVIEW. ONLY COPY THINGS FROM EXPOVIEW TO HERE.
  implementation 'com.android.support:appcompat-v7:28.0.0'
  implementation 'com.facebook.android:facebook-android-sdk:4.34.0'
  implementation('com.facebook.android:audience-network-sdk:4.99.0') {
    exclude module: 'play-services-ads'
  }
  compileOnly 'org.glassfish:javax.annotation:3.1.1'
  implementation 'com.jakewharton:butterknife:8.4.0'
  implementation 'de.greenrobot:eventbus:2.4.0'
  implementation 'com.amplitude:android-sdk:2.9.2' // Be careful when upgrading! Upgrading might break experience scoping. Check with Jesse. See Analytics.resetAmplitudeDatabaseHelper
  implementation 'com.squareup.picasso:picasso:2.5.2'
  implementation 'com.google.android.gms:play-services-gcm:15.0.1'
  implementation 'com.google.android.gms:play-services-analytics:16.0.1'
  implementation 'com.google.android.gms:play-services-maps:15.0.1'
  implementation 'com.google.android.gms:play-services-auth:15.0.1'
  implementation 'com.google.android.gms:play-services-location:15.0.1'
  implementation 'com.google.android.gms:play-services-ads:15.0.1'
  annotationProcessor 'com.raizlabs.android:DBFlow-Compiler:2.2.1'
  implementation "com.raizlabs.android:DBFlow-Core:2.2.1"
  implementation "com.raizlabs.android:DBFlow:2.2.1"
  implementation "com.madgag.spongycastle:core:1.53.0.0"
  implementation "com.madgag.spongycastle:prov:1.53.0.0"
  debugImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta1'
  // debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.4-beta1'
  releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta1'
  implementation 'com.facebook.device.yearclass:yearclass:1.0.1'
  implementation 'commons-io:commons-io:1.3.2'
  implementation 'me.leolin:ShortcutBadger:1.1.4@aar'
  implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
  implementation 'com.theartofdev.edmodo:android-image-cropper:2.4.7'
  implementation 'com.yqritc:android-scalablevideoview:1.0.1'
  implementation 'commons-codec:commons-codec:1.10'
  implementation 'com.segment.analytics.android:analytics:4.3.0'
  implementation 'com.google.zxing:core:3.2.1'
  implementation 'net.openid:appauth:0.4.1'
  implementation('com.airbnb.android:lottie:2.5.5')  {
      exclude group: 'com.android.support', module: 'appcompat-v7'
  }
  implementation 'io.branch.sdk.android:library:2.17.1'
  implementation('io.nlopez.smartlocation:library:3.2.11') {
    transitive = false
  }
  implementation 'com.android.support:exifinterface:28.0.0'
  implementation 'com.squareup.okio:okio:1.9.0'

  // Testing
  androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
  // We use a modified build of com.android.support.test:runner:1.0.1. Explanation in maven-test/README
  androidTestImplementation 'com.android.support.test:runner:1.0.1'
  androidTestImplementation 'com.android.support:support-annotations:28.0.0'
  androidTestImplementation 'com.google.code.findbugs:jsr305:3.0.0'
  androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
  androidTestImplementation 'com.azimolabs.conditionwatcher:conditionwatcher:0.2'

  testImplementation 'junit:junit:4.12'
  testImplementation 'org.mockito:mockito-core:1.10.19'
  testImplementation 'org.robolectric:robolectric:3.8'
  testImplementation 'com.android.support.test:runner:1.0.2-alpha1'
  testImplementation 'com.android.support.test:rules:1.0.2-alpha1'

  
  implementation('host.exp.exponent:expoview:33.0.0@aar') {
    transitive = true
    exclude group: 'com.squareup.okhttp3', module: 'okhttp'
    exclude group: 'com.squareup.okhttp3', module: 'okhttp-urlconnection'
  }
  
}

addUnimodulesDependencies([
        modulesPaths : [
                '../../node_modules'
        ],
        configuration: 'api',
        target       : 'react-native',
        exclude      : [
                // You can exclude unneeded modules here, e.g.,
                // 'unimodules-face-detector-interface',
                // 'expo-face-detector'

                // Adding a name here will also remove the package
                // from auto-generated BasePackageList.java
        ]
])

// This has to be down here for some reason
apply plugin: 'com.google.gms.google-services'

MainApplication.java

package host.exp.exponent;

// import org.unimodules.core.interfaces.Package;

import com.facebook.react.ReactPackage;

import java.util.Arrays;
import java.util.List;

import com.facebook.FacebookSdk;
import com.facebook.CallbackManager;
import com.facebook.appevents.AppEventsLogger;

import okhttp3.OkHttpClient;

import host.exp.exponent.generated.BasePackageList;

// Needed for `react-native link`
// import com.facebook.react.ReactApplication;
import com.dooboolab.RNIap.RNIapPackage;
import com.facebook.reactnative.androidsdk.FBSDKPackage;
import com.geektime.rnonesignalandroid.ReactNativeOneSignalPackage;

public class MainApplication extends ExpoApplication {

  private static CallbackManager mCallbackManager = CallbackManager.Factory.create();

  @Override
  public boolean isDebug() {
    return BuildConfig.DEBUG;
  }

  // Needed for `react-native link`
  public List<ReactPackage> getPackages() {
    return Arrays.<ReactPackage>asList(
        // Add your own packages here!
        // TODO: add native modules!

        // Needed for `react-native link`
        // new MainReactPackage(),
            new RNIapPackage(),
            new FBSDKPackage(mCallbackManager),
            new ReactNativeOneSignalPackage()
    );
  }

  @Override
  public String gcmSenderId() {
    return getString(R.string.gcm_defaultSenderId);
  }

  public static OkHttpClient.Builder okHttpClientBuilder(OkHttpClient.Builder builder) {
    // Customize/override OkHttp client here
    return builder;
  }

  protected static CallbackManager getCallbackManager() {
    return mCallbackManager;
  }

  public List getExpoPackages() {
    return new BasePackageList().getPackageList();
  }
}

MainActivity.java

package host.exp.exponent;

import android.os.Bundle;
import android.content.Intent;

import com.facebook.react.ReactPackage;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.unimodules.core.interfaces.Package;
import host.exp.exponent.generated.DetachBuildConstants;
import host.exp.exponent.experience.DetachActivity;

public class MainActivity extends DetachActivity {

  @Override
  public String publishedUrl() {
    return "exp://exp.host/@kraegpoeth/plantjammer";
  }

  @Override
  public String developmentUrl() {
    return DetachBuildConstants.DEVELOPMENT_URL;
  }

  @Override
  public List<ReactPackage> reactPackages() {
    return ((MainApplication) getApplication()).getPackages();
  }

  @Override
  public List<Package> expoPackages() {
    // Here you can add your own packages.
    return super.expoPackages();
  }

  @Override
  public boolean isDebug() {
    return BuildConfig.DEBUG;
  }

  @Override
  public Bundle initialProps(Bundle expBundle) {
    // Add extra initialProps here
    return expBundle;
  }

  @Override
  public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    MainApplication.getCallbackManager().onActivityResult(requestCode, resultCode, data);
  }
}

settings.gradle

include ':app'
include ':react-native-iap'
project(':react-native-iap').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-iap/android')
include ':react-native-fbsdk'
project(':react-native-fbsdk').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fbsdk/android')
include ':react-native-onesignal'
project(':react-native-onesignal').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-onesignal/android')
apply from: '../node_modules/react-native-unimodules/gradle.groovy'

// Include unimodules.
includeUnimodulesProjects()

So true. Upgrade manual is really confusing. I’m just trying to upgrade from 31 to 33 and still no success. Some errors on every step :unamused:

What errors are you currently facing? I decided to do it one upgrade at a time instead. I’ve managed to upgrade from 30 to 31 and 31 to 32. Currently struggling with 32 to 33. :slight_smile:

I am in the process of doing 32 → 33 and it’s really a nightmare. iOS is just as bad as Android.

@kraegpoeth one note on your app/build.gradle - pretty sure addUnimodulesDependencies() code should be under dependencies {…}

Here’s a few build things that helped me:

  • gradle sync issue, remove modules.xml from android/.idea directory and re-sync
  • clean build and / or re-start Android Studio
  • make sure yarn and expo-cli are updated to latest
  • if you have force 'org.webkit:android-jsc:r224109' in resolutionStrategy add it to package.json w yarn add jsc-android@224109
  • clear out expo with expo start -c
  • make sure all of your ejected packages are up to date in package.json (I had a few that needed version bumps in order to compile with expo 33 / RN 59)
  • get Android Studio stable build 3.4.2

I got the Android build working and managed to build and generate a signed APK. However, when I download to my Nexus 6P and run, it is constantly relaunching the app when I start navigating between screens and / or tabs.

1 Like

Thanks a lot for the reply @helium. I just managed to build the APK to an emulator, also relying a lot of the first three steps you mention, multiple times, in random order. I didn’t get anything realted to jsc-android@224109, which just speaks to how crazy this is - I got some other issues that felt unique to our project, as it was difficult to Google the solution, and the anwsers were not related to Expo.

You were right about addUnimodulesDependencies() having to be inside dependencies {…}. That was a combination of me being too copy-paste and the docs being too brief.

In a way it’s nice to know that it’s not just me struggling. It’s a shame that the Expo team seems to be so disinterested in these upgrade issues. Maybe they just have other priorities right now, or are on vacation.

In terms of the last thing you mention, I’m also not too optimistic yet. Going to get iOS to build now, and then fix the JS errors. I still expect more issues down the line.

I think the Expo team is probably overwhelmed with issues due to the nature and complexity of the entire platform. Plus they probably prioritize the non-ejected forum thread first :slight_smile:

@kraegpoeth let me know how iOS goes for you, still haven’t cracked it yet…

Hi there, @kraegpoeth, @helium ! Sorry for my late answer.
My story:
I decided to upgrade from 31 to 32, then from 32 to 33. I followed the official guide from 31 to 32, but finally got an error connected with some missing modules (sorry, but I don’t remember exactly what module). Then I decided to continue to SDK 33. I think that it is the right way , because when upgraiding to 33, some modules from 32, like

api 'host.exp.exponent:expo-app-loader-provider:+'
api 'org.unimodules:core:+'
api 'org.unimodules:unimodules-constants-interface:+'
api 'host.exp.exponent:expo-constants:+'

are removed by unimodules.

Also, I think that the point is to put fresh values for androidExpoViewUrl & iosExpoViewUrl in your app.json.

Now I got my android dev build working well, but release build is not working at all :smile: I suppose it is again something wrong with expo publish url :thinking:
If you want, I can share with my MainActivity.java and so on. I didnt remove any old / unused lines, but commented them. So you can see some upgrade history from 31 SDK.

My status is that I got SDK 33 working on Android, and currently struggling with iOS because we used to used to have

pod 'react-native-fbsdk', :path => '../node_modules/react-native-fbsdk'

pod 'FBSDKCoreKit', :git => 'https://github.com/facebook/facebook-objc-sdk.git', :branch => 'master'

in our Podfile, from when we first ejected, and I was struggling to get Facebook login to work. These are giving some errors now. I might just have to remove them, and try to follow the Expo docs again to get it to work.

@kraegpoeth we aren’t using FB login but we have a different pod setup than the expo docs - try something like this above where you have your ejected path defs and below Target...do:

rn_path = ‘…/node_modules/react-native’

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.11.0”,
:subspecs => [
“Core”,
],
:inhibit_warnings => true

Install unimodules

require_relative ‘…/node_modules/react-native-unimodules/cocoapods.rb’
use_unimodules!

pod ‘React’,
:path => rn_path,
:subspecs => [
‘Core’,
‘CxxBridge’,
‘DevSupport’,
‘RCTActionSheet’,
‘RCTAnimation’,
‘RCTGeolocation’,
‘RCTImage’,
‘RCTLinkingIOS’,
‘RCTNetwork’,
‘RCTSettings’,
‘RCTText’,
‘RCTVibration’,
‘RCTWebSocket’,
‘ART’
]

So I think what fixed the “expo-gl-cpp is an Android project without build variants” problem was installing what is called “NDK” in Android studio.

  1. From an open project, select Tools > SDK Manager from the main menu.
  2. Click the SDK Tools tab.
  3. Check the boxes next to LLDB , CMake , and NDK.

https://developer.android.com/ndk/guides

Now Android Studio is no longer complaining about that dependency, and it looks the same as the others in the Project panel (before the little folder icon was different from the others).

I’m currently trying to update expoKit from SDK 32 to SDK 33 in Android, and I’m getting such errors: Errors after updating ExpoKit SDK from 32 to 33 . Any ideas how is possible to resolve them? or what can be wrong?

IOS works fine though.

What are the new values for androidExpoViewUrl & iosExpoViewUrl looks like ?

“iosExpoViewUrl”:“https://s3.amazonaws.com/exp-exponent-view-code/ios-v2.11.2-sdk33.0.0-76da9dd8-735b-43b3-9682-b386811f4e5f.tar.gz

“androidExpoViewUrl”:“https://s3.amazonaws.com/exp-exponent-view-code/android-v2.11.4-sdk33.0.0-6a4f0f3e-1f1b-4c33-9155-d0237f6d7c34.tar.gz

1 Like

I gave 30 → 33 a shot on iOS for about 6 hours today and ended up giving up. Kept running into issues with FBShareKit Semantic Issue after hitting the play button. Not sure if there’s anything special I need to do with react-native-fb-sdk. Wondering if I even need it and the extra setup (for Facebook Analytics and Audience Network) or if the newer Expo versions provide support out-of-box (https://docs.expo.io/versions/v33.0.0/sdk/facebook/, https://docs.expo.io/versions/v33.0.0/sdk/facebook-ads/)? I’ll try again when I feel motivated because I need to upgrade eventually. For now, I really feel everyone’s pain.

Does iosExpoViewUrl have to be changed too? They aren’t mentioned in the upgrade guide e.g. https://docs.expo.io/versions/latest/workflow/upgrading-expo-sdk-walkthrough/#sdk-33.

For iOS (and Android) I have removed the react-native-fbsdk for now.

I ended up having the biggest issues with the Android project. What I did was to init a new Expo project, eject to ExpoKit and the copy + paste (and replace) the android folder in our project. Then I searched the project for the new projects name, to replace it with our app’s name. I also had to re-add the few external dependencies we have, namely OneSignal and in-app purchases. It took some time but ended up working out. Now I also feel more up-to-date with how the Expo team organizes their project. Seems like a lot has changed since SDK 30… I recommend choosing a very distinct name for the new project, so that it’s easy to search and replace.

Can you tell me
What does it require to run
OneSignal
On sdk 34
For me 6 days I try to run it
Thank you

Are you having issues on both iOS and Android? I followed the OneSignal docs a long time ago. And what ended up helping was replacing the whole android folder with one from a newly ejected project, like stated above. Then I just moved the OneSignal lines back in.

Or are you setting up OneSignal for the first time?

1 Like

Thank you , you have moved the files from annotated been taken out on a very old version
Now he works

Solution that worked for me:

After ejecting, expo changes the applicationId and generates a new folder under android/src/com/java. Remove the old folder and then gradlew clean.