<lambda>null1 // Copyright 2015-present 650 Industries. All rights reserved.
2 package host.exp.exponent.exceptions
3 
4 import host.exp.exponent.Constants
5 import host.exp.expoview.ExpoViewBuildConfig
6 import org.json.JSONArray
7 import org.json.JSONException
8 import org.json.JSONObject
9 import java.lang.Exception
10 import java.lang.NumberFormatException
11 
12 class ManifestException : ExponentException {
13   private val manifestUrl: String
14   private var errorJSON: JSONObject? = null
15   val errorHeader: String?
16     get() = errorJSON?.let {
17       try {
18         when (it.getString("errorCode")) {
19           "EXPERIENCE_SDK_VERSION_OUTDATED" -> "Project is incompatible with this version of Expo Go"
20           "EXPERIENCE_SDK_VERSION_TOO_NEW" -> "Project is incompatible with this version of Expo Go"
21           "SNACK_NOT_FOUND_FOR_SDK_VERSION" -> "This Snack is incompatible with this version of Expo Go"
22           else -> null
23         }
24       } catch (e: JSONException) {
25         null
26       }
27     }
28 
29   constructor(originalException: Exception?, manifestUrl: String) : super(originalException) {
30     this.manifestUrl = manifestUrl
31     this.errorJSON = null
32   }
33 
34   constructor(originalException: Exception?, manifestUrl: String, errorJSON: JSONObject?) : super(
35     originalException
36   ) {
37     this.errorJSON = errorJSON
38     this.manifestUrl = manifestUrl
39   }
40 
41   override fun toString(): String {
42     val extraMessage = if (ExpoViewBuildConfig.DEBUG) {
43       // This will get hit in a detached app.
44       " Are you sure expo-cli is running?"
45     } else {
46       ""
47     }
48 
49     return when (manifestUrl) {
50       Constants.INITIAL_URL -> "Could not load app.$extraMessage"
51       else -> {
52         var formattedMessage = "Could not load $manifestUrl.$extraMessage"
53         val supportedSdks = Constants.SDK_VERSIONS_LIST.map {
54           it.substring(0, it.indexOf('.')).toInt()
55         }.sorted()
56         val supportedSdksString = { conjunction: String ->
57           supportedSdks.subList(0, supportedSdks.size - 1)
58             .joinToString(", ") + " $conjunction ${supportedSdks.last()}"
59         }
60 
61         if (errorJSON != null) {
62           try {
63             val errorCode = errorJSON!!.getString("errorCode")
64             val rawMessage = errorJSON!!.getString("message")
65             when (errorCode) {
66               "EXPERIENCE_NOT_FOUND", // Really doesn't exist
67               "EXPERIENCE_NOT_PUBLISHED_ERROR", // Not published
68               "EXPERIENCE_RELEASE_NOT_FOUND_ERROR" -> // Can't find a release for the requested release channel
69                 formattedMessage =
70                   "No project found at $manifestUrl."
71               "EXPERIENCE_SDK_VERSION_OUTDATED" -> {
72                 val metadata = errorJSON!!.getJSONObject("metadata")
73                 val availableSDKVersions = metadata.getJSONArray("availableSDKVersions")
74                 val sdkVersionRequired = availableSDKVersions.getString(0).let {
75                   it.substring(0, it.indexOf('.'))
76                 }
77 
78                 formattedMessage =
79                   "This project uses SDK $sdkVersionRequired, but this version of Expo Go supports only SDKs ${supportedSdksString("and")}.<br><br>" +
80                   "To open this project:<br>" +
81                   "• Update it to SDK ${supportedSdksString("or")}.<br>" +
82                   "• Install an older version of Expo Go that supports the project's SDK version.<br><br>" +
83                   "If you are unsure how to update the project or install a suitable version of Expo Go, refer to the <a href='https://docs.expo.dev/get-started/expo-go/#sdk-versions'>SDK Versions Guide</a>."
84               }
85               "SNACK_NOT_FOUND_FOR_SDK_VERSION" -> {
86                 formattedMessage =
87                   "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.<br><a href='https://docs.expo.dev/develop/development-builds/introduction/'>Learn more about development builds</a>."
88               }
89               "EXPERIENCE_SDK_VERSION_TOO_NEW" ->
90                 formattedMessage =
91                   "This project requires a newer version of Expo Go - please download the latest version from the Play Store."
92               "EXPERIENCE_NOT_VIEWABLE" ->
93                 formattedMessage =
94                   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.
95               "USER_SNACK_NOT_FOUND", "SNACK_NOT_FOUND" ->
96                 formattedMessage =
97                   "No snack found at $manifestUrl."
98               "SNACK_RUNTIME_NOT_RELEASED" ->
99                 formattedMessage =
100                   rawMessage // From server: `The Snack runtime for corresponding sdk version of this Snack ("${sdkVersions[0]}") is not released.`,
101               "SNACK_NOT_FOUND_FOR_SDK_VERSION" -> run closure@{
102                 val metadata = errorJSON!!.getJSONObject("metadata")
103                 val fullName = metadata["fullName"] ?: ""
104                 val snackSdkVersion =
105                   (metadata["sdkVersions"] as? JSONArray)?.get(0) as? String ?: "unknown"
106 
107                 if (snackSdkVersion == "unknown" || snackSdkVersion.indexOf(".") == -1) {
108                   formattedMessage = rawMessage
109                   return@closure
110                 }
111 
112                 val snackSdkVersionValue = try {
113                   Integer.parseInt(snackSdkVersion.substring(0, snackSdkVersion.indexOf(".")))
114                 } catch (e: NumberFormatException) {
115                   formattedMessage = rawMessage
116                   return@closure
117                 }
118                 formattedMessage =
119                   "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")}."
120                 formattedMessage += if (supportedSdks.last() < snackSdkVersionValue) {
121                   "<br><br>You need to update your Expo Go app in order to run this Snack."
122                 } else {
123                   "<br><br>Snack needs to be upgraded to a current SDK version. To do it, open the project at <a href='https://snack.expo.dev'>Expo Snack website</a>. It will be automatically upgraded to a supported SDK version."
124                 }
125                 formattedMessage += "<br><br><a href='https://docs.expo.dev/get-started/expo-go/#sdk-versions'>Learn more about SDK versions and Expo Go</a>."
126               }
127             }
128           } catch (e: JSONException) {
129             return formattedMessage
130           }
131         }
132         formattedMessage
133       }
134     }
135   }
136 }
137