// Copyright 2015-present 650 Industries. All rights reserved.
package host.exp.exponent.exceptions
import host.exp.exponent.Constants
import host.exp.expoview.ExpoViewBuildConfig
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.lang.Exception
import java.lang.NumberFormatException
class ManifestException : ExponentException {
private val manifestUrl: String
private var errorJSON: JSONObject? = null
val errorHeader: String?
get() = errorJSON?.let {
try {
when (it.getString("errorCode")) {
"EXPERIENCE_SDK_VERSION_OUTDATED" -> "Project is incompatible with this version of Expo Go"
"EXPERIENCE_SDK_VERSION_TOO_NEW" -> "Project is incompatible with this version of Expo Go"
"SNACK_NOT_FOUND_FOR_SDK_VERSION" -> "This Snack is incompatible with this version of Expo Go"
else -> null
}
} catch (e: JSONException) {
null
}
}
constructor(originalException: Exception?, manifestUrl: String) : super(originalException) {
this.manifestUrl = manifestUrl
this.errorJSON = null
}
constructor(originalException: Exception?, manifestUrl: String, errorJSON: JSONObject?) : super(
originalException
) {
this.errorJSON = errorJSON
this.manifestUrl = manifestUrl
}
override fun toString(): String {
val extraMessage = if (ExpoViewBuildConfig.DEBUG) {
// This will get hit in a detached app.
" Are you sure expo-cli is running?"
} else {
""
}
return when (manifestUrl) {
Constants.INITIAL_URL -> "Could not load app.$extraMessage"
else -> {
var formattedMessage = "Could not load $manifestUrl.$extraMessage"
val supportedSdks = Constants.SDK_VERSIONS_LIST.map {
it.substring(0, it.indexOf('.')).toInt()
}.sorted()
val supportedSdksString = { conjunction: String ->
supportedSdks.subList(0, supportedSdks.size - 1)
.joinToString(", ") + " $conjunction ${supportedSdks.last()}"
}
if (errorJSON != null) {
try {
val errorCode = errorJSON!!.getString("errorCode")
val rawMessage = errorJSON!!.getString("message")
when (errorCode) {
"EXPERIENCE_NOT_FOUND", // Really doesn't exist
"EXPERIENCE_NOT_PUBLISHED_ERROR", // Not published
"EXPERIENCE_RELEASE_NOT_FOUND_ERROR" -> // Can't find a release for the requested release channel
formattedMessage =
"No project found at $manifestUrl."
"EXPERIENCE_SDK_VERSION_OUTDATED" -> {
val metadata = errorJSON!!.getJSONObject("metadata")
val availableSDKVersions = metadata.getJSONArray("availableSDKVersions")
val sdkVersionRequired = availableSDKVersions.getString(0).let {
it.substring(0, it.indexOf('.'))
}
formattedMessage =
"This project uses SDK $sdkVersionRequired, but this version of Expo Go supports only SDKs ${supportedSdksString("and")}.
" +
"To open this project:
" +
"• Update it to SDK ${supportedSdksString("or")}.
" +
"• Install an older version of Expo Go that supports the project's SDK version.
" +
"If you are unsure how to update the project or install a suitable version of Expo Go, refer to the SDK Versions Guide."
}
"SNACK_NOT_FOUND_FOR_SDK_VERSION" -> {
formattedMessage =
"Incompatible SDK version or no SDK version specified. This version of Expo Go only supports the following SDKs (runtimes): " + Constants.SDK_VERSIONS_LIST.joinToString() + ". A development build must be used to load other runtimes.
Learn more about development builds."
}
"EXPERIENCE_SDK_VERSION_TOO_NEW" ->
formattedMessage =
"This project requires a newer version of Expo Go - please download the latest version from the Play Store."
"EXPERIENCE_NOT_VIEWABLE" ->
formattedMessage =
rawMessage // From server: The experience you requested is not viewable by you. You will need to log in or ask the owner to grant you access.
"USER_SNACK_NOT_FOUND", "SNACK_NOT_FOUND" ->
formattedMessage =
"No snack found at $manifestUrl."
"SNACK_RUNTIME_NOT_RELEASED" ->
formattedMessage =
rawMessage // From server: `The Snack runtime for corresponding sdk version of this Snack ("${sdkVersions[0]}") is not released.`,
"SNACK_NOT_FOUND_FOR_SDK_VERSION" -> run closure@{
val metadata = errorJSON!!.getJSONObject("metadata")
val fullName = metadata["fullName"] ?: ""
val snackSdkVersion =
(metadata["sdkVersions"] as? JSONArray)?.get(0) as? String ?: "unknown"
if (snackSdkVersion == "unknown" || snackSdkVersion.indexOf(".") == -1) {
formattedMessage = rawMessage
return@closure
}
val snackSdkVersionValue = try {
Integer.parseInt(snackSdkVersion.substring(0, snackSdkVersion.indexOf(".")))
} catch (e: NumberFormatException) {
formattedMessage = rawMessage
return@closure
}
formattedMessage =
"The snack \"${fullName}\" was found, but it is not compatible with your version of Expo Go. It was released for SDK $snackSdkVersionValue, but your Expo Go supports only SDKs ${supportedSdksString("and")}."
formattedMessage += if (supportedSdks.last() < snackSdkVersionValue) {
"
You need to update your Expo Go app in order to run this Snack."
} else {
"
Snack needs to be upgraded to a current SDK version. To do it, open the project at Expo Snack website. It will be automatically upgraded to a supported SDK version."
}
formattedMessage += "
Learn more about SDK versions and Expo Go."
}
}
} catch (e: JSONException) {
return formattedMessage
}
}
formattedMessage
}
}
}
}