0

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,
                        ),
                      );
                    }),
//...
2

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

will this work on background??.... is it a good practice to leave event channel to stay on background...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.