@wwdrew/expo-spotify-sdk 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +37 -4
  2. package/android/build.gradle +49 -0
  3. package/android/src/main/AndroidManifest.xml +11 -0
  4. package/android/src/main/java/expo/modules/spotifysdk/ExpoSpotifySDKModule.kt +180 -0
  5. package/build/ExpoSpotifySDK.types.d.ts +0 -1
  6. package/build/ExpoSpotifySDK.types.d.ts.map +1 -1
  7. package/build/ExpoSpotifySDK.types.js.map +1 -1
  8. package/external/android/SpotifySDK/auth-lib/spotify-auth-release-2.1.0.aar +0 -0
  9. package/ios/ExpoSpotifySDKModule.swift +1 -3
  10. package/ios/ExpoSpotifySessionManager.swift +3 -3
  11. package/ios/SpotifySDK/SpotifyiOS.xcframework/Info.plist +9 -5
  12. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTAppRemote.h +14 -10
  13. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTAppRemoteContentItem.h +3 -0
  14. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SPTSessionManager.h +3 -13
  15. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Headers/SpotifyAppRemote.h +2 -0
  16. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Info.plist +0 -0
  17. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/Modules/module.modulemap +1 -1
  18. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/PrivacyInfo.xcprivacy +14 -0
  19. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64/SpotifyiOS.framework/SpotifyiOS +0 -0
  20. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemote.h +14 -10
  21. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteContentItem.h +3 -0
  22. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SPTSessionManager.h +3 -13
  23. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Headers/SpotifyAppRemote.h +2 -0
  24. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Info.plist +0 -0
  25. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/Modules/module.modulemap +1 -1
  26. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/PrivacyInfo.xcprivacy +14 -0
  27. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/SpotifyiOS +0 -0
  28. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_x86_64-simulator/SpotifyiOS.framework/_CodeSignature/CodeResources +20 -133
  29. package/package.json +3 -1
  30. package/plugin/build/android/withSpotifyAndroidAppBuildGradle.js +18 -2
  31. package/plugin/build/index.js +2 -2
  32. package/plugin/build/ios/{withSpotifyConfigIOS.d.ts → withSpotifyConfigValues.d.ts} +1 -1
  33. package/plugin/build/ios/{withSpotifyConfigIOS.js → withSpotifyConfigValues.js} +3 -3
  34. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemote.h +0 -240
  35. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemoteAlbum.h +0 -18
  36. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemoteArtist.h +0 -18
  37. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemoteCommon.h +0 -36
  38. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemoteConnectionParams.h +0 -65
  39. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemoteContentAPI.h +0 -75
  40. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemoteContentItem.h +0 -43
  41. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemoteCrossfadeState.h +0 -18
  42. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemoteImageAPI.h +0 -25
  43. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemoteImageRepresentable.h +0 -16
  44. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemoteLibraryState.h +0 -19
  45. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemotePlaybackOptions.h +0 -32
  46. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemotePlaybackRestrictions.h +0 -32
  47. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemotePlayerAPI.h +0 -262
  48. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemotePlayerState.h +0 -40
  49. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemotePodcastPlaybackSpeed.h +0 -15
  50. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemoteTrack.h +0 -47
  51. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemoteUserAPI.h +0 -103
  52. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTAppRemoteUserCapabilities.h +0 -15
  53. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTConfiguration.h +0 -63
  54. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTError.h +0 -33
  55. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTLogin.h +0 -10
  56. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTMacros.h +0 -89
  57. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTScope.h +0 -68
  58. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTSession.h +0 -32
  59. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SPTSessionManager.h +0 -140
  60. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SpotifyAppRemote.h +0 -30
  61. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Headers/SpotifyiOS.h +0 -7
  62. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Info.plist +0 -0
  63. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/Modules/module.modulemap +0 -6
  64. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_armv7/SpotifyiOS.framework/SpotifyiOS +0 -0
  65. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemote.h +0 -240
  66. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteAlbum.h +0 -18
  67. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteArtist.h +0 -18
  68. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteCommon.h +0 -36
  69. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteConnectionParams.h +0 -65
  70. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteContentAPI.h +0 -75
  71. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteContentItem.h +0 -43
  72. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteCrossfadeState.h +0 -18
  73. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteImageAPI.h +0 -25
  74. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteImageRepresentable.h +0 -16
  75. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteLibraryState.h +0 -19
  76. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemotePlaybackOptions.h +0 -32
  77. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemotePlaybackRestrictions.h +0 -32
  78. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemotePlayerAPI.h +0 -262
  79. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemotePlayerState.h +0 -40
  80. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemotePodcastPlaybackSpeed.h +0 -15
  81. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteTrack.h +0 -47
  82. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteUserAPI.h +0 -103
  83. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTAppRemoteUserCapabilities.h +0 -15
  84. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTConfiguration.h +0 -63
  85. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTError.h +0 -33
  86. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTLogin.h +0 -10
  87. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTMacros.h +0 -89
  88. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTScope.h +0 -68
  89. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTSession.h +0 -32
  90. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SPTSessionManager.h +0 -140
  91. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SpotifyAppRemote.h +0 -30
  92. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Headers/SpotifyiOS.h +0 -7
  93. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Info.plist +0 -0
  94. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/Modules/module.modulemap +0 -6
  95. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/SpotifyiOS +0 -0
  96. package/ios/SpotifySDK/SpotifyiOS.xcframework/ios-arm64_i386_x86_64-simulator/SpotifyiOS.framework/_CodeSignature/CodeResources +0 -537
  97. package/plugin/build/android/withSpotifyConfigAndroid.d.ts +0 -3
  98. package/plugin/build/android/withSpotifyConfigAndroid.js +0 -16
  99. package/plugin/build/withSpotifyConfig.d.ts +0 -3
  100. package/plugin/build/withSpotifyConfig.js +0 -11
package/README.md CHANGED
@@ -4,7 +4,7 @@ An Expo Module for the native [iOS](https://github.com/spotify/ios-sdk/) and [An
4
4
 
5
5
  ## Supported Features
6
6
 
7
- - Authentication (currently iOS only, Android coming soon)
7
+ - Authentication
8
8
 
9
9
  More to come...
10
10
 
@@ -52,13 +52,15 @@ authenticateAsync(config: SpotifyConfig): Promise<SpotifySession>
52
52
 
53
53
  Starts the authentication process. Requires an array of OAuth scopes. If the Spotify app is installed on the target device it will interact directly with it, otherwise it will open a web view to authenticate with the Spotify website.
54
54
 
55
+ **Note for Android:** If not providing a token swap or refresh URL, the Spotify session response access token will expire after 60 minutes and will not include a refresh token. This is due to a limitation in the Android Spotify SDK. It's recommended to [implement a token swap endpoint](#token-swap) for this reason.
56
+
55
57
  ### Parameters
56
58
 
57
59
  - `tokenSwapURL` (optional): &lt;string&gt; The URL to use for attempting to swap an authorization code for an access token
58
60
  - `tokenRefreshURL` (optional): &lt;string&gt; The URL to use for attempting to renew an access token with a refresh token
59
61
  - `scopes`: An array of OAuth scopes that declare how your app wants to access a user's account. See [Spotify Scopes](https://developer.spotify.com/web-api/using-scopes/) for more information.
60
62
 
61
- **Note**: The following scopes are not available to Expo Spotify SDK:
63
+ **Note:** The following scopes are not available to Expo Spotify SDK:
62
64
 
63
65
  - user-read-playback-position
64
66
  - user-soa-link
@@ -78,9 +80,8 @@ interface SpotifyConfig {
78
80
 
79
81
  interface SpotifySession {
80
82
  accessToken: string;
81
- refreshToken: string;
83
+ refreshToken: string | null;
82
84
  expirationDate: number;
83
- isExpired: boolean;
84
85
  scopes: SpotifyScopes[];
85
86
  }
86
87
 
@@ -105,6 +106,38 @@ type SpotifyScopes =
105
106
  | "user-read-private";
106
107
  ```
107
108
 
109
+ ## Token Swap Example
110
+
111
+ An example token swap endpoint has been provided in the `example` project. For it to work it needs your Spotify client details to be included.
112
+
113
+ 1. Open the `server.js` file and add your client details:
114
+
115
+ ```javascript
116
+ const CLIENT_ID = "<your-client-id>";
117
+ const CLIENT_SECRET = "<your-client-secret>";
118
+ ```
119
+
120
+ These values can be found in your [Spotify Developer Dashboard](https://developer.spotify.com/dashboard). You will need an existing Spotify app for this.
121
+
122
+ 2. Run the server
123
+
124
+ ```sh
125
+ node server.js
126
+ ```
127
+
128
+ 3. Set the `tokenSwapURL` value in your `authenticateAsync` call:
129
+
130
+ ```javascript
131
+ const session = await authenticateAsync({
132
+ tokenSwapURL: "http://192.168.1.120:3000/swap",
133
+ scopes: [
134
+ ...
135
+ ]
136
+ });
137
+ ```
138
+
139
+ All authentication requests will now be sent through the token swap server.
140
+
108
141
  ## Acknowledgments
109
142
 
110
143
  This project has been heavily inspired by the following projects:
@@ -0,0 +1,49 @@
1
+ apply plugin: 'com.android.library'
2
+
3
+ group = 'expo.modules.spotifysdk'
4
+ version = '0.1.0'
5
+
6
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
7
+ apply from: expoModulesCorePlugin
8
+ applyKotlinExpoModulesCorePlugin()
9
+ useCoreDependencies()
10
+ useExpoPublishing()
11
+
12
+ // If you want to use the managed Android SDK versions from expo-modules-core, set this to true.
13
+ // The Android SDK versions will be bumped from time to time in SDK releases and may introduce breaking changes in your module code.
14
+ // Most of the time, you may like to manage the Android SDK versions yourself.
15
+ def useManagedAndroidSdkVersions = false
16
+ if (useManagedAndroidSdkVersions) {
17
+ useDefaultAndroidSdkVersions()
18
+ } else {
19
+ buildscript {
20
+ // Simple helper that allows the root project to override versions declared by this library.
21
+ ext.safeExtGet = { prop, fallback ->
22
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
23
+ }
24
+ }
25
+ project.android {
26
+ compileSdkVersion safeExtGet("compileSdkVersion", 34)
27
+ defaultConfig {
28
+ minSdkVersion safeExtGet("minSdkVersion", 21)
29
+ targetSdkVersion safeExtGet("targetSdkVersion", 34)
30
+ }
31
+ }
32
+ }
33
+
34
+ android {
35
+ namespace "expo.modules.spotifysdk"
36
+ defaultConfig {
37
+ versionCode 1
38
+ versionName "0.1.0"
39
+ }
40
+ lintOptions {
41
+ abortOnError false
42
+ }
43
+ }
44
+
45
+ dependencies {
46
+ implementation 'androidx.browser:browser:1.8.0'
47
+ implementation 'com.squareup.okhttp3:okhttp:4.9.2'
48
+ implementation files("../external/android/SpotifySDK/auth-lib/spotify-auth-release-2.1.0.aar")
49
+ }
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
+ <application>
4
+ <meta-data
5
+ android:name="spotifyClientId"
6
+ android:value="${spotifyClientId}" />
7
+ <meta-data
8
+ android:name="spotifyRedirectUri"
9
+ android:value="${spotifyRedirectUri}" />
10
+ </application>
11
+ </manifest>
@@ -0,0 +1,180 @@
1
+ package expo.modules.spotifysdk
2
+
3
+ import android.content.pm.PackageManager
4
+ import expo.modules.kotlin.Promise
5
+ import expo.modules.kotlin.modules.Module
6
+ import expo.modules.kotlin.modules.ModuleDefinition
7
+ import com.spotify.sdk.android.auth.AuthorizationClient
8
+ import com.spotify.sdk.android.auth.AuthorizationRequest
9
+ import com.spotify.sdk.android.auth.AuthorizationResponse
10
+ import com.spotify.sdk.android.auth.app.SpotifyNativeAuthUtil
11
+ import expo.modules.kotlin.exception.Exceptions
12
+ import expo.modules.kotlin.records.Field
13
+ import expo.modules.kotlin.records.Record
14
+
15
+ import okhttp3.OkHttpClient
16
+ import okhttp3.FormBody
17
+ import okhttp3.Request
18
+ import okhttp3.Callback
19
+ import okhttp3.Call
20
+ import okhttp3.Response
21
+
22
+ import java.io.IOException
23
+ import org.json.JSONObject
24
+
25
+ class SpotifyConfigOptions : Record {
26
+ @Field
27
+ val scopes: List<String> = emptyList()
28
+
29
+ @Field
30
+ val tokenSwapURL: String? = null
31
+
32
+ @Field
33
+ val tokenRefreshURL: String? = null
34
+ }
35
+
36
+ class ExpoSpotifySDKModule : Module() {
37
+
38
+ private val requestCode = 2095
39
+ private var requestConfig: SpotifyConfigOptions? = null
40
+ private var authPromise: Promise? = null
41
+ private val context
42
+ get() = appContext.reactContext ?: throw Exceptions.ReactContextLost()
43
+ private val currentActivity
44
+ get() = appContext.currentActivity ?: throw Exceptions.MissingActivity()
45
+
46
+ override fun definition() = ModuleDefinition {
47
+
48
+ Name("ExpoSpotifySDK")
49
+
50
+ Function("isAvailable") {
51
+ return@Function SpotifyNativeAuthUtil.isSpotifyInstalled(context)
52
+ }
53
+
54
+ AsyncFunction("authenticateAsync") { config: SpotifyConfigOptions, promise: Promise ->
55
+ try {
56
+ val packageInfo =
57
+ context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_META_DATA)
58
+ val applicationInfo = packageInfo.applicationInfo
59
+ val metaData = applicationInfo.metaData
60
+ val clientId = metaData.getString("spotifyClientId")
61
+ val redirectUri = metaData.getString("spotifyRedirectUri")
62
+
63
+ requestConfig = config
64
+
65
+ if (clientId == null || redirectUri == null) {
66
+ promise.reject(
67
+ "ERR_EXPO_SPOTIFY_SDK",
68
+ "Missing Spotify configuration in AndroidManifest.xml. Ensure SPOTIFY_CLIENT_ID and SPOTIFY_REDIRECT_URI are set.",
69
+ null
70
+ )
71
+ return@AsyncFunction
72
+ }
73
+
74
+ val responseType = if (config.tokenSwapURL != null || config.tokenRefreshURL != null) {
75
+ AuthorizationResponse.Type.CODE
76
+ } else {
77
+ AuthorizationResponse.Type.TOKEN
78
+ }
79
+
80
+ val request = AuthorizationRequest.Builder(
81
+ clientId,
82
+ responseType,
83
+ redirectUri
84
+ )
85
+ .setScopes(config.scopes.toTypedArray())
86
+ .build()
87
+
88
+ authPromise = promise
89
+ AuthorizationClient.openLoginActivity(currentActivity, requestCode, request)
90
+
91
+ } catch (e: PackageManager.NameNotFoundException) {
92
+ promise.reject(
93
+ "ERR_EXPO_SPOTIFY_SDK",
94
+ "Missing Spotify configuration in AndroidManifest.xml",
95
+ e
96
+ )
97
+ }
98
+ }
99
+
100
+ OnActivityResult { _, payload ->
101
+ if (payload.requestCode == requestCode) {
102
+ val authResponse = AuthorizationClient.getResponse(payload.resultCode, payload.data)
103
+
104
+ when (authResponse.type) {
105
+ AuthorizationResponse.Type.TOKEN -> {
106
+ val expirationDate = System.currentTimeMillis() + authResponse.expiresIn * 1000
107
+
108
+ authPromise?.resolve(
109
+ mapOf(
110
+ "accessToken" to authResponse.accessToken,
111
+ "refreshToken" to null, // Spotify SDK does not return refresh token
112
+ "expirationDate" to expirationDate,
113
+ "scope" to requestConfig?.scopes
114
+ )
115
+ )
116
+ }
117
+
118
+ AuthorizationResponse.Type.CODE -> {
119
+ val client = OkHttpClient()
120
+ val requestBody = FormBody.Builder()
121
+ .add("code", authResponse.code)
122
+ .build()
123
+
124
+ val request = Request.Builder()
125
+ .url(requestConfig?.tokenSwapURL!!)
126
+ .post(requestBody)
127
+ .header("Content-Type", "application/x-www-form-urlencoded")
128
+ .build()
129
+
130
+ client.newCall(request).enqueue(object : Callback {
131
+ override fun onFailure(call: Call, e: IOException) {
132
+ authPromise?.reject("ERR_EXPO_SPOTIFY_SDK", e.message, e)
133
+ authPromise = null
134
+ }
135
+
136
+ override fun onResponse(call: Call, response: Response) {
137
+ if (!response.isSuccessful) {
138
+ authPromise?.reject("ERR_EXPO_SPOTIFY_SDK", "Failed to swap code for token", null)
139
+ authPromise = null
140
+ return
141
+ }
142
+
143
+ response.body?.string()?.let { body ->
144
+ val json = JSONObject(body)
145
+ val accessToken = json.getString("access_token")
146
+ val refreshToken = json.getString("refresh_token")
147
+ val expiresIn = json.getInt("expires_in")
148
+ val scope = json.getString("scope")
149
+ val expirationDate = System.currentTimeMillis() + expiresIn * 1000
150
+
151
+ authPromise?.resolve(
152
+ mapOf(
153
+ "accessToken" to accessToken,
154
+ "refreshToken" to refreshToken,
155
+ "expirationDate" to expirationDate,
156
+ "scope" to scope.split(' ')
157
+ )
158
+ )
159
+ } ?: run {
160
+ authPromise?.reject("ERR_EXPO_SPOTIFY_SDK", "Empty response body", null)
161
+ }
162
+ authPromise = null
163
+ }
164
+ })
165
+ }
166
+
167
+ AuthorizationResponse.Type.ERROR -> {
168
+ authPromise?.reject("ERR_EXPO_SPOTIFY_SDK", authResponse.error, null)
169
+ authPromise = null
170
+ }
171
+
172
+ else -> {
173
+ authPromise?.reject("ERR_EXPO_SPOTIFY_SDK", "Unknown response type", null)
174
+ authPromise = null
175
+ }
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
@@ -2,7 +2,6 @@ export interface SpotifySession {
2
2
  accessToken: string;
3
3
  refreshToken: string;
4
4
  expirationDate: number;
5
- isExpired: boolean;
6
5
  scopes: SpotifyScope[];
7
6
  }
8
7
  export interface SpotifyConfig {
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoSpotifySDK.types.d.ts","sourceRoot":"","sources":["../src/ExpoSpotifySDK.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,YAAY,GACpB,kBAAkB,GAClB,0BAA0B,GAC1B,4BAA4B,GAC5B,6BAA6B,GAC7B,oBAAoB,GACpB,WAAW,GACX,uBAAuB,GACvB,6BAA6B,GAC7B,yBAAyB,GACzB,wBAAwB,GACxB,oBAAoB,GACpB,kBAAkB,GAClB,eAAe,GACf,2BAA2B,GAC3B,qBAAqB,GACrB,mBAAmB,GACnB,iBAAiB,GACjB,mBAAmB,CAAC"}
1
+ {"version":3,"file":"ExpoSpotifySDK.types.d.ts","sourceRoot":"","sources":["../src/ExpoSpotifySDK.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAMD,MAAM,MAAM,YAAY,GACpB,kBAAkB,GAClB,0BAA0B,GAC1B,4BAA4B,GAC5B,6BAA6B,GAC7B,oBAAoB,GACpB,WAAW,GACX,uBAAuB,GACvB,6BAA6B,GAC7B,yBAAyB,GACzB,wBAAwB,GACxB,oBAAoB,GACpB,kBAAkB,GAClB,eAAe,GACf,2BAA2B,GAC3B,qBAAqB,GACrB,mBAAmB,GACnB,iBAAiB,GACjB,mBAAmB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoSpotifySDK.types.js","sourceRoot":"","sources":["../src/ExpoSpotifySDK.types.ts"],"names":[],"mappings":"","sourcesContent":["export interface SpotifySession {\n accessToken: string;\n refreshToken: string;\n expirationDate: number;\n isExpired: boolean;\n scopes: SpotifyScope[];\n}\n\nexport interface SpotifyConfig {\n scopes: SpotifyScope[];\n tokenSwapURL?: string;\n tokenRefreshURL?: string;\n}\n\nexport type SpotifyScope =\n | \"ugc-image-upload\"\n | \"user-read-playback-state\"\n | \"user-modify-playback-state\"\n | \"user-read-currently-playing\"\n | \"app-remote-control\"\n | \"streaming\"\n | \"playlist-read-private\"\n | \"playlist-read-collaborative\"\n | \"playlist-modify-private\"\n | \"playlist-modify-public\"\n | \"user-follow-modify\"\n | \"user-follow-read\"\n | \"user-top-read\"\n | \"user-read-recently-played\"\n | \"user-library-modify\"\n | \"user-library-read\"\n | \"user-read-email\"\n | \"user-read-private\";\n"]}
1
+ {"version":3,"file":"ExpoSpotifySDK.types.js","sourceRoot":"","sources":["../src/ExpoSpotifySDK.types.ts"],"names":[],"mappings":"","sourcesContent":["export interface SpotifySession {\n accessToken: string;\n refreshToken: string;\n expirationDate: number;\n scopes: SpotifyScope[];\n}\n\nexport interface SpotifyConfig {\n scopes: SpotifyScope[];\n tokenSwapURL?: string;\n tokenRefreshURL?: string;\n}\n\n// export interface AndroidSpotifyConfig extends SpotifyConfig {\n// responseType: \"token\" | \"code\";\n// }\n\nexport type SpotifyScope =\n | \"ugc-image-upload\"\n | \"user-read-playback-state\"\n | \"user-modify-playback-state\"\n | \"user-read-currently-playing\"\n | \"app-remote-control\"\n | \"streaming\"\n | \"playlist-read-private\"\n | \"playlist-read-collaborative\"\n | \"playlist-modify-private\"\n | \"playlist-modify-public\"\n | \"user-follow-modify\"\n | \"user-follow-read\"\n | \"user-top-read\"\n | \"user-read-recently-played\"\n | \"user-library-modify\"\n | \"user-library-read\"\n | \"user-read-email\"\n | \"user-read-private\";\n"]}
@@ -27,13 +27,11 @@ public class ExpoSpotifySDKModule: Module {
27
27
  "accessToken": session.accessToken,
28
28
  "refreshToken": session.refreshToken,
29
29
  "expirationDate": Int(session.expirationDate.timeIntervalSince1970 * 1000),
30
- "scopes": SPTScopeSerializer.serializeScopes(session.scope),
31
- "isExpired": session.isExpired
30
+ "scopes": SPTScopeSerializer.serializeScopes(session.scope)
32
31
  ])
33
32
  }.catch { error in
34
33
  promise.reject(error)
35
34
  }
36
35
  }
37
-
38
36
  }
39
37
  }
@@ -46,8 +46,8 @@ final class ExpoSpotifySessionManager: NSObject {
46
46
 
47
47
  func authenticate(scopes: [String], tokenSwapURL: String?, tokenRefreshURL: String?) -> PromiseKit.Promise<SPTSession> {
48
48
  return Promise { seal in
49
- guard let clientID = expoSpotifyConfiguration?.clientID,
50
- let redirectURL = expoSpotifyConfiguration?.redirectURL else {
49
+ guard let clientID = self.expoSpotifyConfiguration?.clientID,
50
+ let redirectURL = self.expoSpotifyConfiguration?.redirectURL else {
51
51
  NSLog("Invalid Spotify configuration")
52
52
  seal.reject(SessionManagerError.invalidConfiguration)
53
53
  return
@@ -68,7 +68,7 @@ final class ExpoSpotifySessionManager: NSObject {
68
68
  self.sessionManager = SPTSessionManager(configuration: configuration, delegate: self)
69
69
 
70
70
  DispatchQueue.main.sync {
71
- sessionManager?.initiateSession(with: SPTScopeSerializer.deserializeScopes(scopes), options: .default)
71
+ sessionManager?.initiateSession(with: SPTScopeSerializer.deserializeScopes(scopes), options: .default, campaign: nil)
72
72
  }
73
73
  }
74
74
  }
@@ -5,31 +5,35 @@
5
5
  <key>AvailableLibraries</key>
6
6
  <array>
7
7
  <dict>
8
+ <key>BinaryPath</key>
9
+ <string>SpotifyiOS.framework/SpotifyiOS</string>
8
10
  <key>LibraryIdentifier</key>
9
- <string>ios-arm64</string>
11
+ <string>ios-arm64_x86_64-simulator</string>
10
12
  <key>LibraryPath</key>
11
13
  <string>SpotifyiOS.framework</string>
12
14
  <key>SupportedArchitectures</key>
13
15
  <array>
14
16
  <string>arm64</string>
17
+ <string>x86_64</string>
15
18
  </array>
16
19
  <key>SupportedPlatform</key>
17
20
  <string>ios</string>
21
+ <key>SupportedPlatformVariant</key>
22
+ <string>simulator</string>
18
23
  </dict>
19
24
  <dict>
25
+ <key>BinaryPath</key>
26
+ <string>SpotifyiOS.framework/SpotifyiOS</string>
20
27
  <key>LibraryIdentifier</key>
21
- <string>ios-arm64_x86_64-simulator</string>
28
+ <string>ios-arm64</string>
22
29
  <key>LibraryPath</key>
23
30
  <string>SpotifyiOS.framework</string>
24
31
  <key>SupportedArchitectures</key>
25
32
  <array>
26
33
  <string>arm64</string>
27
- <string>x86_64</string>
28
34
  </array>
29
35
  <key>SupportedPlatform</key>
30
36
  <string>ios</string>
31
- <key>SupportedPlatformVariant</key>
32
- <string>simulator</string>
33
37
  </dict>
34
38
  </array>
35
39
  <key>CFBundlePackageType</key>
@@ -166,24 +166,26 @@ typedef NS_ENUM(NSUInteger, SPTAppRemoteLogLevel) {
166
166
  * The passed URI will start playing unless Spotify is already playing.
167
167
  *
168
168
  * @param URI The URI to play. Use a blank string to attempt to play the user's last song
169
+ * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
169
170
  *
170
- * @return `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
171
171
  * Note: The return `BOOL` here is not a measure of whether or not authentication succeeded, only a check if
172
172
  * the Spotify app is installed and can attempt to handle the authorization request.
173
173
  */
174
- - (BOOL)authorizeAndPlayURI:(NSString *)URI;
174
+ - (void)authorizeAndPlayURI:(NSString *)URI completionHandler:(void (^ __nullable)(BOOL success))completionHandler;
175
175
 
176
176
  /**
177
177
  * Open Spotify app to obtain access token and start playback.
178
178
  *
179
179
  * @param playURI The URI to play. Use a blank string to attempt to play the user's last song
180
180
  * @param asRadio `YES` to start radio for the given URI.
181
+ * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
181
182
  *
182
- * @return `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
183
183
  * Note: The return `BOOL` here is not a measure of whether or not authentication succeeded, only a check if
184
184
  * the Spotify app is installed and can attempt to handle the authorization request.
185
185
  */
186
- - (BOOL)authorizeAndPlayURI:(NSString *)playURI asRadio:(BOOL)asRadio;
186
+ - (void)authorizeAndPlayURI:(NSString *)playURI
187
+ asRadio:(BOOL)asRadio
188
+ completionHandler:(void (^ __nullable)(BOOL success))completionHandler;
187
189
 
188
190
  /**
189
191
  * Open Spotify app to obtain access token and start playback.
@@ -191,14 +193,15 @@ typedef NS_ENUM(NSUInteger, SPTAppRemoteLogLevel) {
191
193
  * @param playURI The URI to play. Use a blank string to attempt to play the user's last song
192
194
  * @param asRadio `YES` to start radio for the given URI.
193
195
  * @param additionalScopes An array of scopes in addition to `app-remote-control`. Can be nil if you only need `app-remote-control`
196
+ * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
194
197
  *
195
- * @return `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
196
198
  * Note: The return `BOOL` here is not a measure of whether or not authentication succeeded, only a check if
197
199
  * the Spotify app is installed and can attempt to handle the authorization request.
198
200
  */
199
- - (BOOL)authorizeAndPlayURI:(NSString *)playURI
201
+ - (void)authorizeAndPlayURI:(NSString *)playURI
200
202
  asRadio:(BOOL)asRadio
201
- additionalScopes:(nullable NSArray<NSString *> *)additionalScopes;
203
+ additionalScopes:(nullable NSArray<NSString *> *)additionalScopes
204
+ completionHandler:(void (^ __nullable)(BOOL success))completionHandler;
202
205
 
203
206
  /**
204
207
  * Open Spotify app to obtain access token and start playback.
@@ -209,15 +212,16 @@ typedef NS_ENUM(NSUInteger, SPTAppRemoteLogLevel) {
209
212
  * @param sessionIdentifier An optional unique identifier for this specific session, which is used for analytics purposes. Every new attempt to
210
213
  * connect to the Spotify app should have a new identifier, but the identifier used here should then be reused for the accompanied call to
211
214
  * `connectWithSessionIdentifier:`.
215
+ * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
212
216
  *
213
- * @return `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
214
217
  * Note: The return `BOOL` here is not a measure of whether or not authentication succeeded, only a check if
215
218
  * the Spotify app is installed and can attempt to handle the authorization request.
216
219
  */
217
- - (BOOL)authorizeAndPlayURI:(NSString *)playURI
220
+ - (void)authorizeAndPlayURI:(NSString *)playURI
218
221
  asRadio:(BOOL)asRadio
219
222
  additionalScopes:(nullable NSArray<NSString *> *)additionalScopes
220
- sessionIdentifier:(nullable NSUUID *)sessionIdentifier;
223
+ sessionIdentifier:(nullable NSUUID *)sessionIdentifier
224
+ completionHandler:(void (^ __nullable)(BOOL success))completionHandler;
221
225
  /**
222
226
  * Parse out an access token or error description from a url passed to application:openURL:options:
223
227
  *
@@ -33,6 +33,9 @@ NS_ASSUME_NONNULL_BEGIN
33
33
  /// Returns `YES` if the item is expected to contain children, otherwise `NO`.
34
34
  @property (nonatomic, assign, readonly, getter=isContainer) BOOL container;
35
35
 
36
+ /// Returns `YES` if the item is pinned in Your Library, otherwise `NO`.
37
+ @property (nonatomic, assign, readonly, getter=isPinned) BOOL pinnned;
38
+
36
39
  /**
37
40
  A list of the content item's children.
38
41
 
@@ -44,26 +44,16 @@ typedef NSString * const SPTAuthorizationCode;
44
44
  - (instancetype)init NS_UNAVAILABLE;
45
45
 
46
46
  /**
47
- Initiate the authorization process on iOS 11 and later.
47
+ Initiate the authorization process
48
48
 
49
49
  @param scope The scope to request, e.g. `SPTPlaylistReadPrivateScope`|`SPTUserReadEmailScope` if you wish to request read access to private playlists, and read access to the user's email address.
50
50
  @param options Options bitmask that informs authorization behavior.
51
- See `SPTSessionManagerDelegate` for messages regarding changes in session state.
52
- */
53
- - (void)initiateSessionWithScope:(SPTScope)scope
54
- options:(SPTAuthorizationOptions)options NS_AVAILABLE_IOS(11_0);
55
-
56
- /**
57
- Initiate the authorization process on iOS versions < 11.
58
-
59
- @param scope The scope to request, e.g. `SPTPlaylistReadPrivateScope`|`SPTUserReadEmailScope` if you wish to request read access to private playlists, and read access to the user's email address.
60
- @param options Options bitmask that informs authorization behavior.
61
- @param presentingViewController The `UIViewController` to present the login `SFSafariViewController` on
51
+ @param campaign The campaign identifier, to help attribute where the account linking was initiated from.
62
52
  See `SPTSessionManagerDelegate` for messages regarding changes in session state.
63
53
  */
64
54
  - (void)initiateSessionWithScope:(SPTScope)scope
65
55
  options:(SPTAuthorizationOptions)options
66
- presentingViewController: (UIViewController *)presentingViewController NS_DEPRECATED_IOS(9_0, 11_0);
56
+ campaign:(nullable NSString *)campaign;
67
57
 
68
58
  /// Attempt to renew the access token, using the refresh token in the current `SPTSession` which must be valid.
69
59
  - (void)renewSession;
@@ -24,6 +24,8 @@
24
24
  #import "SPTAppRemoteLibraryState.h"
25
25
  #import "SPTAppRemoteContentItem.h"
26
26
  #import "SPTAppRemotePodcastPlaybackSpeed.h"
27
+ #import "SPTAppRemoteConnectivityAPI.h"
28
+ #import "SPTAppRemoteConnectivityState.h"
27
29
 
28
30
  #import "SPTConfiguration.h"
29
31
 
@@ -1,6 +1,6 @@
1
1
  framework module SpotifyiOS {
2
2
  umbrella header "SpotifyiOS.h"
3
-
4
3
  export *
4
+
5
5
  module * { export * }
6
6
  }
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>NSPrivacyCollectedDataTypes</key>
6
+ <array/>
7
+ <key>NSPrivacyAccessedAPITypes</key>
8
+ <array/>
9
+ <key>NSPrivacyTrackingDomains</key>
10
+ <array/>
11
+ <key>NSPrivacyTracking</key>
12
+ <false/>
13
+ </dict>
14
+ </plist>
@@ -166,24 +166,26 @@ typedef NS_ENUM(NSUInteger, SPTAppRemoteLogLevel) {
166
166
  * The passed URI will start playing unless Spotify is already playing.
167
167
  *
168
168
  * @param URI The URI to play. Use a blank string to attempt to play the user's last song
169
+ * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
169
170
  *
170
- * @return `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
171
171
  * Note: The return `BOOL` here is not a measure of whether or not authentication succeeded, only a check if
172
172
  * the Spotify app is installed and can attempt to handle the authorization request.
173
173
  */
174
- - (BOOL)authorizeAndPlayURI:(NSString *)URI;
174
+ - (void)authorizeAndPlayURI:(NSString *)URI completionHandler:(void (^ __nullable)(BOOL success))completionHandler;
175
175
 
176
176
  /**
177
177
  * Open Spotify app to obtain access token and start playback.
178
178
  *
179
179
  * @param playURI The URI to play. Use a blank string to attempt to play the user's last song
180
180
  * @param asRadio `YES` to start radio for the given URI.
181
+ * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
181
182
  *
182
- * @return `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
183
183
  * Note: The return `BOOL` here is not a measure of whether or not authentication succeeded, only a check if
184
184
  * the Spotify app is installed and can attempt to handle the authorization request.
185
185
  */
186
- - (BOOL)authorizeAndPlayURI:(NSString *)playURI asRadio:(BOOL)asRadio;
186
+ - (void)authorizeAndPlayURI:(NSString *)playURI
187
+ asRadio:(BOOL)asRadio
188
+ completionHandler:(void (^ __nullable)(BOOL success))completionHandler;
187
189
 
188
190
  /**
189
191
  * Open Spotify app to obtain access token and start playback.
@@ -191,14 +193,15 @@ typedef NS_ENUM(NSUInteger, SPTAppRemoteLogLevel) {
191
193
  * @param playURI The URI to play. Use a blank string to attempt to play the user's last song
192
194
  * @param asRadio `YES` to start radio for the given URI.
193
195
  * @param additionalScopes An array of scopes in addition to `app-remote-control`. Can be nil if you only need `app-remote-control`
196
+ * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
194
197
  *
195
- * @return `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
196
198
  * Note: The return `BOOL` here is not a measure of whether or not authentication succeeded, only a check if
197
199
  * the Spotify app is installed and can attempt to handle the authorization request.
198
200
  */
199
- - (BOOL)authorizeAndPlayURI:(NSString *)playURI
201
+ - (void)authorizeAndPlayURI:(NSString *)playURI
200
202
  asRadio:(BOOL)asRadio
201
- additionalScopes:(nullable NSArray<NSString *> *)additionalScopes;
203
+ additionalScopes:(nullable NSArray<NSString *> *)additionalScopes
204
+ completionHandler:(void (^ __nullable)(BOOL success))completionHandler;
202
205
 
203
206
  /**
204
207
  * Open Spotify app to obtain access token and start playback.
@@ -209,15 +212,16 @@ typedef NS_ENUM(NSUInteger, SPTAppRemoteLogLevel) {
209
212
  * @param sessionIdentifier An optional unique identifier for this specific session, which is used for analytics purposes. Every new attempt to
210
213
  * connect to the Spotify app should have a new identifier, but the identifier used here should then be reused for the accompanied call to
211
214
  * `connectWithSessionIdentifier:`.
215
+ * @param completionHandler `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
212
216
  *
213
- * @return `YES` if the Spotify app is installed and an authorization attempt can be made, otherwise `NO`.
214
217
  * Note: The return `BOOL` here is not a measure of whether or not authentication succeeded, only a check if
215
218
  * the Spotify app is installed and can attempt to handle the authorization request.
216
219
  */
217
- - (BOOL)authorizeAndPlayURI:(NSString *)playURI
220
+ - (void)authorizeAndPlayURI:(NSString *)playURI
218
221
  asRadio:(BOOL)asRadio
219
222
  additionalScopes:(nullable NSArray<NSString *> *)additionalScopes
220
- sessionIdentifier:(nullable NSUUID *)sessionIdentifier;
223
+ sessionIdentifier:(nullable NSUUID *)sessionIdentifier
224
+ completionHandler:(void (^ __nullable)(BOOL success))completionHandler;
221
225
  /**
222
226
  * Parse out an access token or error description from a url passed to application:openURL:options:
223
227
  *
@@ -33,6 +33,9 @@ NS_ASSUME_NONNULL_BEGIN
33
33
  /// Returns `YES` if the item is expected to contain children, otherwise `NO`.
34
34
  @property (nonatomic, assign, readonly, getter=isContainer) BOOL container;
35
35
 
36
+ /// Returns `YES` if the item is pinned in Your Library, otherwise `NO`.
37
+ @property (nonatomic, assign, readonly, getter=isPinned) BOOL pinnned;
38
+
36
39
  /**
37
40
  A list of the content item's children.
38
41