Reputation: 382
I want to use an Event Channel to get a data stream from the Spotify SDK. On the native side, I can automatically display the status of a current song by subscribing to my PlayerState. My goal is to be able to access this data stream with my Flutter app. However, I don't get any real data, just a MapStream:
Instance of '_MapStream<dynamic, double>'
According to my StreamBuilder, this MapStream has no data. Where is the mistake? How do I push the data from the Native to Flutter side?
Native Code:
package test.test.spotifysdk04
import com.spotify.android.appremote.api.ConnectionParams
import com.spotify.android.appremote.api.Connector
import com.spotify.android.appremote.api.SpotifyAppRemote
import com.spotify.protocol.types.PlayerState
import com.spotify.sdk.android.authentication.AuthenticationClient
import com.spotify.sdk.android.authentication.AuthenticationRequest
import com.spotify.sdk.android.authentication.AuthenticationResponse
import io.flutter.Log
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar
import com.spotify.protocol.types.Track
class Spotifysdk04Plugin(private var registrar: Registrar): MethodCallHandler, EventChannel.StreamHandler {
private val clientId = "65fd9b2b0ee74575a6d26223a1675917"
private val redirectUri = "spotify-flutter://callback"
private var spotifyAppRemote: SpotifyAppRemote? = null
private val REQUEST_CODE = 1337
private var mEventSink: EventChannel.EventSink? = null
companion object {
@JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "spotifysdk")
channel.setMethodCallHandler(Spotifysdk04Plugin(registrar))
val eventChannel = EventChannel(registrar.messenger(), "timerStream")
eventChannel.setStreamHandler(Spotifysdk04Plugin(registrar))
}
}
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "loginAppRemote") {
val connectionParams = ConnectionParams.Builder(clientId)
.setRedirectUri(redirectUri)
.showAuthView(true)
.build()
SpotifyAppRemote.connect(registrar.context(), connectionParams, object : Connector.ConnectionListener {
override fun onConnected(appRemote: SpotifyAppRemote) {
spotifyAppRemote = appRemote
Log.d("Spotify App Remote Login", "Connected!")
result.success(true)
}
override fun onFailure(throwable: Throwable) {
Log.e("Spotify App Remote Login", "Error!", throwable)
result.success(false)
}
})
} else if(call.method == "loginSpotifyAuthentication") {
try {
AuthenticationClient.openLoginActivity(
registrar.activity(), REQUEST_CODE,
AuthenticationRequest.Builder(clientId,AuthenticationResponse.Type.TOKEN,redirectUri)
.setScopes(arrayOf("user-modify-playback-state")).build())
}catch (err:Throwable){
Log.v("getAuthTokenError",err.message.toString())
}
registrar.addActivityResultListener { requestCode, resultCode, intent ->
if (requestCode == REQUEST_CODE){
val response = AuthenticationClient.getResponse(resultCode, intent).accessToken
result.success(response)
}
true
}
} else {
result.notImplemented()
}
}
override fun onCancel(arguments: Any?) {
mEventSink = null
}
override fun onListen(arguments: Any?, eventSink: EventChannel.EventSink?) {
createListener(eventSink)
}
fun createListener(event: EventChannel.EventSink?) {
if (spotifyAppRemote != null) {
spotifyAppRemote!!.playerApi.subscribeToPlayerState()
.setEventCallback { playerState: PlayerState? ->
var position = playerState!!.playbackPosition.toDouble()
Log.d("playbackPosition", position.toString())
event?.success(position)
}
}
}
}
Dart Plugin Code:
import 'dart:async';
import 'package:flutter/services.dart';
class Spotifysdk04 {
static const MethodChannel _channel = const MethodChannel('spotifysdk');
static const EventChannel _timerEventChannel = const EventChannel('timerStream');
static Stream<double> _timerStream;
static Future<bool> get loginAppRemote async {
final bool connected = await _channel.invokeMethod('loginAppRemote');
return connected;
}
static Future<String> get loginSpotifyAuthentication async {
final String accessToken =
await _channel.invokeMethod('loginSpotifyAuthentication');
return accessToken;
}
static Stream<double> get timerStream {
_timerStream =
_timerEventChannel.receiveBroadcastStream().map<double>((value) => value);
print(_timerStream);
return _timerStream;
}
}
Flutter Code:
//...
StreamBuilder(
stream: Spotifysdk04.timerStream,
builder: (BuildContext context, AsyncSnapshot snapshot) {
print(snapshot);
if (snapshot.hasData) {
return Text(
'Pressure Stream ${snapshot.data}',
style: TextStyle(
color: Colors.white,
),
);
}
return Text(
'No data',
style: TextStyle(
color: Colors.white,
),
);
}),
//...
Upvotes: 0
Views: 11010
Reputation: 828
You're almost there.
_timerStream = _timerEventChannel.receiveBroadcastStream();
That's already enough. Usually you would listen to a stream using its StreamSubscription<T> listen(void onData(T))
method:
_timerStream = _timerEventChannel.receiveBroadcastStream();
var subscription = _timerStream.listen(onData);
void onData(dynamic d) {
print("Data: $d");
}
A StreamBuilder however already takes care of all the listening logic for you.
Upvotes: 1