Saying that I've spent around 32 hours would be an understatement. I've been trying to enable Kotlin in a React Native project powered by Expo SDK 44.
I've been trying everything that I could find over the Internet, but it always ends up with an error in the Gradle Phase in EAS (Running it with eas build --profile development --platform android
) .
Here are my configurations:
I'm omitting code for brevity. If you need more context, let me know
app\android\build.gradle:
buildscript {
ext {
buildToolsVersion = "30.0.2"
minSdkVersion = 21
compileSdkVersion = 31
targetSdkVersion = 31
kotlinVersion = "1.4.11"
}
repositories {
google()
mavenCentral()
jcenter()
}
dependencies {
classpath("com.android.tools.build:gradle:4.1.0")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
apply plugin: "kotlin-android"
apply plugin: "kotlin-android-extensions"
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
implementation project(':react-native-plaid-link-sdk')
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3'
implementation 'androidx.core:core-ktx:1.1.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
// Other comed omitted
}
Here's my package.json
{
"name": "@pana/app",
"version": "22.0220",
"private": true,
"scripts": {
"start": "expo start --dev-client",
"android": "expo run:android",
"ios": "expo run:ios",
"eject": "expo eject",
"extract": "lingui extract",
"compile": "lingui compile",
"lint": "eslint src/** --ext .ts,.tsx",
"lint:fix": "yarn lint --fix",
"test": "jest",
"graphql:generate": "graphql-codegen --config codegen.yml",
"build": ""
},
"dependencies": {
"@apollo/client": "^3.5.10",
"@apollo/link-context": "^2.0.0-beta.3",
"@expo/react-native-action-sheet": "^3.13.0",
"@intercom/intercom-react-native": "^3.0.0",
"@lingui/react": "^3.13.2",
"@onfido/react-native-sdk": "^5.1.0",
"@react-native-async-storage/async-storage": "~1.15.0",
"@react-native-community/datetimepicker": "4.0.0",
"@react-navigation/bottom-tabs": "^6.3.1",
"@react-navigation/native": "^6.0.8",
"@react-navigation/stack": "^6.1.1",
"@reduxjs/toolkit": "^1.8.0",
"@segment/analytics-react-native": "^2.1.12",
"@segment/sovran-react-native": "^0.2.6",
"@sentry/react-native": "^3.2.13",
"axios": "^0.25.0",
"dayjs": "^1.10.8",
"expo": "~44.0.0",
"expo-application": "~4.0.1",
"expo-auth-session": "~3.5.0",
"expo-cellular": "~4.1.0",
"expo-clipboard": "~2.1.0",
"expo-constants": "~13.0.1",
"expo-crypto": "~10.1.1",
"expo-dev-client": "~0.8.5",
"expo-device": "~4.1.0",
"expo-document-picker": "~10.1.3",
"expo-image-loader": "~3.1.0",
"expo-image-picker": "~12.0.2",
"expo-linear-gradient": "~11.0.3",
"expo-local-authentication": "~12.1.0",
"expo-random": "~12.1.1",
"expo-secure-store": "~11.1.0",
"expo-splash-screen": "~0.14.1",
"expo-status-bar": "~1.2.0",
"expo-updates": "~0.11.7",
"make-plural": "^7.1.0",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-native": "0.64.3",
"react-native-animated-progress": "^1.0.2",
"react-native-country-picker-modal": "^2.0.0",
"react-native-dotenv": "^3.3.1",
"react-native-gesture-handler": "~2.1.0",
"react-native-keyboard-aware-scroll-view": "^0.9.5",
"react-native-phone-number-input": "^2.1.0",
"react-native-plaid-link-sdk": "^7.4.0",
"react-native-safe-area-context": "3.3.2",
"react-native-screens": "~3.10.1",
"react-native-shimmer-placeholder": "^2.0.8",
"react-native-svg": "12.1.1",
"react-native-uuid": "^2.0.1",
"react-native-web": "0.17.1",
"react-native-webview": "11.15.0",
"react-redux": "^7.2.6",
"semver-compare": "^1.0.0",
"sentry-expo": "^4.0.0",
"styled-components": "5.2.0",
"styled-system": "^5.1.5",
"validate.js": "^0.13.1"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@graphql-codegen/cli": "2.6.2",
"@graphql-codegen/typescript": "2.4.8",
"@graphql-codegen/typescript-operations": "2.3.5",
"@graphql-codegen/typescript-react-apollo": "3.2.11",
"@lingui/cli": "^3.13.2",
"@lingui/macro": "^3.13.2",
"@react-native-community/eslint-config": "^3.0.1",
"@types/jest": "^27.4.0",
"@types/react": "~17.0.21",
"@types/react-native": "~0.64.12",
"@types/react-native-animated-progress": "^1.0.0",
"@types/react-native-dotenv": "^0.2.0",
"@types/react-redux": "^7.1.23",
"@types/semver-compare": "^1.0.1",
"@types/styled-components": "^5.1.24",
"@types/styled-components-react-native": "5.1.0",
"@types/styled-system": "^5.1.15",
"@typescript-eslint/eslint-plugin": "^5.10.2",
"@typescript-eslint/parser": "^5.10.2",
"eslint": "^8.8.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^8.3.0",
"eslint-import-resolver-typescript": "^2.5.0",
"eslint-plugin-flowtype": "^8.0.3",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jest": "^26.1.0",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0",
"graphql": "^16.3.0",
"install-peers": "^1.0.3",
"jest": "^27.5.0",
"prettier": "^2.5.1",
"react-native-config": "^1.4.5",
"react-native-svg-transformer": "^1.0.0",
"remote-redux-devtools": "^0.5.16",
"ts-jest": "^27.1.3",
"typescript": "~4.3.5"
},
"jest": {
"preset": "react-native",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
]
},
"resolutions": {
"react-devtools-core": "4.14.0",
"@types/react": "17.0.21",
"@types/react-dom": "17.0.01"
}
}
Here's my folder structure:
Here's MyAppPackage.kt
(android\app\src\main\java\com\pana\MyAppPackage.kt)
package com.pana // replace your-app-name with your app’s name
import android.view.View
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ReactShadowNode
import com.facebook.react.uimanager.ViewManager
class MyAppPackage : ReactPackage {
override fun createViewManagers(
reactContext: ReactApplicationContext
): MutableList<ViewManager<View, ReactShadowNode<*>>> = mutableListOf()
override fun createNativeModules(
reactContext: ReactApplicationContext
): MutableList<NativeModule> = listOf(CalendarModule(reactContext)).toMutableList()
}
Here are some of the SO resources that I've resarched:
- ERROR ----> Task :expo-permissions:compileDebugKotlin FAILED
- React native android build is failing after configured kotlin-gradle-plugin, kotlin-android and kotlin-android-extensions
- Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.5.1, expected version is 1.1.15
- warning: Kotlin runtime JAR files in the classpath should have the same version
- Android Studio shows Kotlin Dependency Warning after Second Build
- Why do I have different versions of Kotlin JARs in the classpath?
- flutter build Runtime JAR files in the classpath should have the same version. These files were found in the classpath
- warning: Kotlin runtime JAR files in the classpath should have the same version
- Installing Kotlin-Jupyter: e: java.lang.NoClassDefFoundError: Could not initialize class org.jetbrains.kotlin.com.intellij.pom.java.LanguageLevel
Here are some othe resources that I've looked into:
- https://www.youtube.com/watch?v=wk_cR66AVXQ&t=114s
- https://www.youtube.com/watch?v=GWcEVk7SgOg&t=44s
- https://github.com/circleci/circleci-docs/issues/2945#issuecomment-471637158
- https://developer.android.com/kotlin/add-kotlin
Here are some of the errors and fixes that I've tried:
1 - Minimal Incrementing the project to barebones Kotlin
I've tried minimally incrementing my current project (Note that I had to set the compileSdkVersion
and targetSdkVersion
to 31 for an Intercom package, and that is building successfully). I've followed this video,the official React Native Docs, and the Add Kotlin to an existing app with Android Studio (Manual Approach).
a. (android/build.gradle) Added (Inside buildscript.ext) kotlin_version = '1.4.10'
b. (android/build.gradle) Added (Inside dependencies) classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
c. (android/app/build.gradle) Added (at the top of the file) apply plugin: "kotlin-android"
Tried to compile:
[stderr] Note: Recompile with -Xlint:deprecation for details.
> Task :app:compileDebugKotlin FAILED w: Runtime JAR files in the classpath should have the same version. These files were found in the classpath:
/home/expo/.gradle/caches/transforms-3/f47aaec93b5ce8275ab670559bc858c7/transformed/jetified-kotlin-stdlib-jdk8-1.5.31.jar (version 1.5)
/home/expo/.gradle/caches/transforms-3/e30ac7ea6364b484c3bc3c923afeabd2/transformed/jetified-kotlin-stdlib-jdk7-1.5.31.jar (version 1.5)
/home/expo/.gradle/caches/transforms-3/d9723caca13068e43e601371da49b5b2/transformed/jetified-kotlin-stdlib-1.6.10.jar (version 1.6)
/home/expo/.gradle/caches/transforms-3/c5966235c8aa66a583bf2afcd9edd1b7/transformed/jetified-kotlin-stdlib-common-1.6.10.jar (version 1.6) w: Some runtime JAR files in the classpath have an incompatible version. Consider removing them from the classpath [stderr] e: /home/expo/.gradle/caches/transforms-3/c5966235c8aa66a583bf2afcd9edd1b7/transformed/jetified-kotlin-stdlib-common-1.6.10.jar!/META-INF/kotlin-stdlib-common.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.6.0, expected version is 1.4.0.
2 - Pushing Kotlin to Version 1.6.10
Seeing this, led me to some research and suggested to push the Kotlin version to 1.6.10:
Task :expo-dev-launcher:compileDebugKotlin
[stderr] Compilation with Kotlin compile daemon was not successful
[stderr] java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
[stderr] java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
[stderr] java.io.InvalidClassException: org.jetbrains.kotlin.incremental.IncrementalModuleInfo; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 0
[stderr] at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:391)
[stderr] at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
[stderr] at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
[stderr] at java.base/java.security.AccessController.doPrivileged(Native Method)
[stderr] at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
[stderr] at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562)
[stderr] at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796)
[stderr] at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677)
[stderr] at java.base/java.security.AccessController.doPrivileged(Native Method)
[stderr] at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676)
[stderr] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
[stderr] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
[stderr] at java.base/java.lang.Thread.run(Thread.java:829)
[stderr] at java.rmi/sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:303)
[stderr] at java.rmi/sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:279)
[stderr] at java.rmi/sun.rmi.server.UnicastRef.invoke(UnicastRef.java:164)
This lead me to update to run expo upgrade
and expo doctor
to see if any of the updates would work. This opened Pandora's box. Upgrading to expo SDK 45 came with its own issues (apparently I have some conflicting packages that throw the following errors):
[stderr] Note: /home/expo/workingdir/build/app/node_modules/@sentry/react-native/android/src/main/java/io/sentry/react/RNSentryModule.java uses or overrides a deprecated API.
[stderr] Note: Recompile with -Xlint:deprecation for details.
> Task :app:compileDebugJavaWithJavac FAILED
[stderr] /home/expo/workingdir/build/app/android/app/src/main/java/app/pana/MainApplication.java:6: error: package android.app does not exist
[stderr] import android.app.Application;
[stderr] ^
[stderr] /home/expo/workingdir/build/app/android/app/src/main/java/app/pana/MainApplication.java:7: error: package android.content does not exist
[stderr] import android.content.Context;
[stderr] ^
[stderr] /home/expo/workingdir/build/app/android/app/src/main/java/app/pana/MainApplication.java:8: error: package android.content.res does not exist
[stderr] import android.content.res.Configuration;
[stderr] ^
[stderr] /home/expo/workingdir/build/app/android/app/src/main/java/app/pana/MainApplication.java:10: error: package android.webkit does not exist
[stderr] import android.webkit.WebView;
There were other builds that failed with the expo-dev-client
. I'm also aware of a bug in the SDK 45 that you will have problems with Hermes enabled. We're using JSC.
3 - A bunch of other things
Just to prevent this question from becoming longer, here are other things that I've tried:
a. Changing the distributionUrl
in the gradle-wrapper.properties
to a more recent gradle version.
b. Updating, and mathcing the org.jetbrains.kotlin:kotlin-gradle-plugin
(in android/build.gradle), org.jetbrains.kotlin:kotlin-stdlib-jdk7
(changed it to jdk8 and nothing), org.jetbrains.kotlinx:kotlinx-coroutines-core
, org.jetbrains.kotlinx:kotlinx-coroutines-android
, androidx.core:core-ktx
with the corresponding kotlin versions.
c. Added these implementations inside a debugImplementation
statement.
d. Researched React Native versions corresponding with Kotlin (Don't know if Version 0.64 which is Expo's SDK 44 supports Kotlin 1.6.10).
e. Checked for syntax errors using Android Studio.
f. Ran gradlew clean.
g. And other things...
Does anyone know anything? There doesn't seem to be anything reported in the Expo GitHub.