Flutter:如何将原生 SDK(Spotify Android SDK)添加到应用程序中?

Posted

技术标签:

【中文标题】Flutter:如何将原生 SDK(Spotify Android SDK)添加到应用程序中?【英文标题】:Flutter: How to add a native SDK (Spotify Android SDK) to an app? 【发布时间】:2020-02-23 03:38:19 【问题描述】:

我想编写一个访问 Spotify android SDK 的包。我正在尝试添加身份验证。那是行不通的。我没有设法打开登录屏幕。我是否需要在 dart 代码中添加一个视图(如此处所述:https://60devs.com/how-to-add-native-code-to-flutter-app-using-platform-views-android.html)?

飞镖:

...
void initPlatformState() async 
    try 
      String test = await Nativecode05.spotifyTest;
      print(test);
     on PlatformException 
      platformVersion = 'Failed';
    
  
...

包装:

import 'dart:async';

import 'package:flutter/services.dart';

class Nativecode05 
  static const MethodChannel _channel = const MethodChannel('nativecode05');

  static Future<String> get spotifyTest async 
    final String version = await _channel.invokeMethod('spotifyTest');
    return version;
  

包中的Java代码:

package example.com.nativecode05;

import io.flutter.Log;
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.android.appremote.api.ConnectionParams;
import com.spotify.android.appremote.api.Connector;
import com.spotify.android.appremote.api.SpotifyAppRemote;

import static android.content.ContentValues.TAG;

/** Nativecode05Plugin */
public class Nativecode05Plugin implements MethodCallHandler 
  private static final String CLIENT_ID = "7b23dface41e4a9595276a7c12262143";
  private static final String REDIRECT_URI = "http://cape/callback";
  private SpotifyAppRemote mSpotifyAppRemote;
  private Registrar mRegistrar;

  /** Plugin registration. */
  public static void registerWith(Registrar registrar) 
    final MethodChannel channel = new MethodChannel(registrar.messenger(), "nativecode05");
    channel.setMethodCallHandler(new Nativecode05Plugin(registrar));
  

  Nativecode05Plugin(Registrar registrar) 
        mRegistrar = registrar;
    

  @Override
  public void onMethodCall(MethodCall call, Result result) 
    if (call.method.equals("spotifyTest")) 
      result.success("test");
      performAuthorization();
      return;
    

    result.notImplemented();
  

  private void performAuthorization() 
    Log.d(TAG, "Performing authorization...");

    // Set the connection parameters
    ConnectionParams connectionParams =
            new ConnectionParams.Builder(CLIENT_ID)
                    .setRedirectUri(REDIRECT_URI)
                    .showAuthView(true)
                    .build();

    SpotifyAppRemote.connect(mRegistrar.activeContext(), connectionParams,
            new Connector.ConnectionListener() 

              @Override
              public void onConnected(SpotifyAppRemote spotifyAppRemote) 
                mSpotifyAppRemote = spotifyAppRemote;
                Log.d(TAG, "Connected! Yay!");

                // Now you can start interacting with App Remote
                //connected();
              

              @Override
              public void onFailure(Throwable throwable) 
                Log.e(TAG, throwable.getMessage(), throwable);

                // Something went wrong when attempting to connect! Handle errors here
              
            );
  


终端中的结果:

Launching lib\main.dart on SM G960F in debug mode...
Initializing gradle...
Resolving dependencies...
Running Gradle task 'assembleDebug'...
Built build\app\outputs\apk\debug\app-debug.apk.
Installing build\app\outputs\apk\app.apk...
D/EmergencyMode(17067): [EmergencyManager] android createPackageContext successful
D/InputTransport(17067): Input channel constructed: fd=87
D/ViewRootImpl@a7a19f9[MainActivity](17067): setView = DecorView@97d1d3e[MainActivity] TM=true MM=false
W/ecode05_exampl(17067): Accessing hidden method Landroid/view/accessibility/AccessibilityNodeInfo;->getSourceNodeId()J (light greylist, reflection)
W/ecode05_exampl(17067): Accessing hidden method Landroid/view/accessibility/AccessibilityRecord;->getSourceNodeId()J (light greylist, reflection)
W/ecode05_exampl(17067): Accessing hidden field Landroid/view/accessibility/AccessibilityNodeInfo;->mChildNodeIds:Landroid/util/LongArray; (light greylist, reflection)
W/ecode05_exampl(17067): Accessing hidden method Landroid/util/LongArray;->get(I)J (light greylist, reflection)
D/SurfaceView(17067): onWindowVisibilityChanged(0) true 5395cb5 of ViewRootImpl@a7a19f9[MainActivity]
D/ViewRootImpl@a7a19f9[MainActivity](17067): dispatchAttachedToWindow
D/ViewRootImpl@a7a19f9[MainActivity](17067): Relayout returned: old=[0,0][1440,2960] new=[0,0][1440,2960] result=0x7 surface=valid=true 508548042752 changed=true
I/OpenGLRenderer(17067): Initialized EGL, version 1.4
D/OpenGLRenderer(17067): Swap behavior 2
D/mali_winsys(17067): EGLint new_window_surface(egl_winsys_display *, void *, EGLSurface, EGLConfig, egl_winsys_surface **, EGLBoolean) returns 0x3000
D/OpenGLRenderer(17067): eglCreateWindowSurface = 0x765347ca00, 0x7667d35010
D/SurfaceView(17067): show() Surface(name=SurfaceView - example.com.nativecode05_example/example.com.nativecode05_example.MainActivity@5395cb5@0[17067])/@0xca9cf4a io.flutter.view.FlutterView5395cb5 VFED..... ......ID 0,0-1440,2900
Syncing files to device SM G960F...
D/SurfaceView(17067): surfaceCreated 1 #8 io.flutter.view.FlutterView5395cb5 VFED..... ......ID 0,0-1440,2900
D/mali_winsys(17067): EGLint new_window_surface(egl_winsys_display *, void *, EGLSurface, EGLConfig, egl_winsys_surface **, EGLBoolean) returns 0x3000
D/SurfaceView(17067): surfaceChanged (1440,2900) 1 #8 io.flutter.view.FlutterView5395cb5 VFED..... ......ID 0,0-1440,2900
I/Choreographer(17067): Skipped 39 frames!  The application may be doing too much work on its main thread.
D/ViewRootImpl@a7a19f9[MainActivity](17067): Relayout returned: old=[0,0][1440,2960] new=[0,0][1440,2960] result=0x3 surface=valid=true 508548042752 changed=false
I/OpenGLRenderer(17067): Davey! duration=814ms; Flags=1, IntendedVsync=626714985015335, Vsync=626715635015309, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=626715637655313, AnimationStart=626715637750275, PerformTraversalsStart=626715637758236, DrawStart=626715651163506, SyncQueued=626715655711967, SyncStart=626715655915390, IssueDrawCommandsStart=626715656392275, SwapBuffers=626715796396544, FrameCompleted=626715799700313, DequeueBufferDuration=11272000, QueueBufferDuration=584000, 
D/ViewRootImpl@a7a19f9[MainActivity](17067): MSG_WINDOW_FOCUS_CHANGED 1 1
D/InputMethodManager(17067): prepareNavigationBarInfo() DecorView@97d1d3e[MainActivity]
D/InputMethodManager(17067): getNavigationBarColor() -855310
D/InputMethodManager(17067): prepareNavigationBarInfo() DecorView@97d1d3e[MainActivity]
D/InputMethodManager(17067): getNavigationBarColor() -855310
V/InputMethodManager(17067): Starting input: tba=example.com.nativecode05_example ic=null mNaviBarColor -855310 mIsGetNaviBarColorSuccess true , NavVisible : true , NavTrans : false
D/InputMethodManager(17067): startInputInner - Id : 0
I/InputMethodManager(17067): startInputInner - mService.startInputOrWindowGainedFocus
D/ViewRootImpl@a7a19f9[MainActivity](17067): MSG_RESIZED_REPORT: frame=Rect(0, 0 - 1440, 2960) ci=Rect(0, 96 - 0, 60) vi=Rect(0, 96 - 0, 60) or=1
D/InputTransport(17067): Input channel constructed: fd=96
D/InputMethodManager(17067): prepareNavigationBarInfo() DecorView@97d1d3e[MainActivity]
D/InputMethodManager(17067): getNavigationBarColor() -855310
V/InputMethodManager(17067): Starting input: tba=example.com.nativecode05_example ic=null mNaviBarColor -855310 mIsGetNaviBarColorSuccess true , NavVisible : true , NavTrans : false
D/InputMethodManager(17067): startInputInner - Id : 0
D/ContentValues(17067): Performing authorization...
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/HelloDetails; annotation class 153
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/HelloDetails; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/HelloDetails; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/HelloDetails; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/HelloDetails; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/HelloDetails; annotation class 156
I/chatty  (17067): uid=10433(example.com.nativecode05_example) AsyncTask #2 identical 2 lines
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/HelloDetails; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Info; annotation class 153
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Info; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Info; annotation class 156
I/chatty  (17067): uid=10433(example.com.nativecode05_example) AsyncTask #2 identical 9 lines
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Info; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Info; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Info; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Info; annotation class 156
I/chatty  (17067): uid=10433(example.com.nativecode05_example) AsyncTask #2 identical 1 line
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Info; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Info; annotation class 156
I/chatty  (17067): uid=10433(example.com.nativecode05_example) AsyncTask #2 identical 5 lines
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Info; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/HelloDetails; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/HelloDetails; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Roles; annotation class 153
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Roles; annotation class 156
I/chatty  (17067): uid=10433(example.com.nativecode05_example) AsyncTask #2 identical 5 lines
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Roles; annotation class 156
W/ecode05_exampl(17067): Unable to resolve Lcom/spotify/protocol/types/Roles; annotation class 156
E/ContentValues(17067): "message":"Could not authenticate within 60 s."
E/ContentValues(17067): com.spotify.android.appremote.api.error.AuthenticationFailedException: "message":"Could not authenticate within 60 s."
E/ContentValues(17067):     at com.spotify.android.appremote.api.LocalConnector.asAppRemoteException(LocalConnector.java:131)
E/ContentValues(17067):     at com.spotify.android.appremote.api.LocalConnector.access$000(LocalConnector.java:35)
E/ContentValues(17067):     at com.spotify.android.appremote.api.LocalConnector$1.onConnectionFailed(LocalConnector.java:111)
E/ContentValues(17067):     at com.spotify.android.appremote.internal.SdkRemoteClientConnector$ConnectionTask.onPostExecute(SdkRemoteClientConnector.java:142)
E/ContentValues(17067):     at com.spotify.android.appremote.internal.SdkRemoteClientConnector$ConnectionTask.onPostExecute(SdkRemoteClientConnector.java:75)
E/ContentValues(17067):     at android.os.AsyncTask.finish(AsyncTask.java:695)
E/ContentValues(17067):     at android.os.AsyncTask.access$600(AsyncTask.java:180)
E/ContentValues(17067):     at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712)
E/ContentValues(17067):     at android.os.Handler.dispatchMessage(Handler.java:106)
E/ContentValues(17067):     at android.os.Looper.loop(Looper.java:214)
E/ContentValues(17067):     at android.app.ActivityThread.main(ActivityThread.java:6986)
E/ContentValues(17067):     at java.lang.reflect.Method.invoke(Native Method)
E/ContentValues(17067):     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
E/ContentValues(17067):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)
E/ContentValues(17067): Caused by: com.spotify.protocol.client.error.RemoteClientException: "message":"Could not authenticate within 60 s."
E/ContentValues(17067):     at com.spotify.protocol.client.RemoteWampClient.getRemoteClientException(RemoteWampClient.java:139)
E/ContentValues(17067):     at com.spotify.protocol.client.RemoteWampClient.access$200(RemoteWampClient.java:16)
E/ContentValues(17067):     at com.spotify.protocol.client.RemoteWampClient$1.onAbort(RemoteWampClient.java:44)
E/ContentValues(17067):     at com.spotify.protocol.client.WampRouterImpl.routeAbort(WampRouterImpl.java:100)
E/ContentValues(17067):     at com.spotify.protocol.client.WampRouterImpl.route(WampRouterImpl.java:26)
E/ContentValues(17067):     at com.spotify.protocol.client.AppProtocolCommunicator.onData(AppProtocolCommunicator.java:78)
E/ContentValues(17067):     at com.spotify.android.appremote.internal.RemoteServiceIo.handleMessage(RemoteServiceIo.java:113)
E/ContentValues(17067):     at com.spotify.android.appremote.internal.RemoteServiceIo.access$000(RemoteServiceIo.java:47)
E/ContentValues(17067):     at com.spotify.android.appremote.internal.RemoteServiceIo$IncomingHandler.handleMessage(RemoteServiceIo.java:91)
E/ContentValues(17067):     ... 6 more
I/flutter (17067): test
D/InputMethodManager(17067): prepareNavigationBarInfo() DecorView@97d1d3e[MainActivity]
D/InputMethodManager(17067): getNavigationBarColor() -855310
V/InputMethodManager(17067): Starting input: tba=example.com.nativecode05_example ic=null mNaviBarColor -855310 mIsGetNaviBarColorSuccess true , NavVisible : true , NavTrans : false
D/InputMethodManager(17067): startInputInner - Id : 0
I/InputMethodManager(17067): startInputInner - mService.startInputOrWindowGainedFocus
D/InputTransport(17067): Input channel constructed: fd=97
D/InputTransport(17067): Input channel destroyed: fd=96
D/SurfaceView(17067): windowStopped(true) false 5395cb5 of ViewRootImpl@a7a19f9[MainActivity]
D/SurfaceView(17067): show() Surface(name=SurfaceView - example.com.nativecode05_example/example.com.nativecode05_example.MainActivity@5395cb5@0[17067])/@0xca9cf4a io.flutter.view.FlutterView5395cb5 VFED..... ........ 0,0-1440,2900
D/SurfaceView(17067): surfaceDestroyed callback.size 1 #1 io.flutter.view.FlutterView5395cb5 VFED..... ........ 0,0-1440,2900
W/libEGL  (17067): EGLNativeWindowType 0x7667d36010 disconnect failed
D/SurfaceView(17067): destroy() Surface(name=SurfaceView - example.com.nativecode05_example/example.com.nativecode05_example.MainActivity@5395cb5@0[17067])/@0xca9cf4a io.flutter.view.FlutterView5395cb5 VFED..... ........ 0,0-1440,2900
D/ViewRootImpl@a7a19f9[MainActivity](17067): MSG_WINDOW_FOCUS_CHANGED 0 1
D/InputMethodManager(17067): prepareNavigationBarInfo() DecorView@97d1d3e[MainActivity]
D/InputMethodManager(17067): getNavigationBarColor() -855310
D/SurfaceView(17067): onWindowVisibilityChanged(8) false 5395cb5 of ViewRootImpl@a7a19f9[MainActivity]
W/libEGL  (17067): EGLNativeWindowType 0x7667d35010 disconnect failed
D/OpenGLRenderer(17067): eglDestroySurface = 0x765347ca00, 0x7667d35000
D/ViewRootImpl@a7a19f9[MainActivity](17067): Relayout returned: old=[0,0][1440,2960] new=[0,0][1440,2960] result=0x5 surface=valid=false 0 changed=true

【问题讨论】:

【参考方案1】:

您好,spotify_sdk 包完全符合您的要求。免责声明我是这个包的开发者:)

【讨论】:

【参考方案2】:

您可以将此代码用于 Spotify API。它也可以用于其他 API 调用。这里使用的是flutter_web_auth 0.1.2 包。比较容易。

void authenticate() async 
  // Present the dialog to the user
  final result = await FlutterWebAuth.authenticate(
    url:
        "https://accounts.spotify.com/authorize?client_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx&redirect_uri=yourname:/&scope=user-read-currently-playing&response_type=token&state=123",
    callbackUrlScheme: "yourname",
  );

// Extract token from resulting url
  final token = Uri.parse(result);
  String at = token.fragment;
  at = "http://website/index.html?$at"; // Just for easy persing
  var accesstoken = Uri.parse(at).queryParameters['access_token'];
  print('token');
  print(accesstoken);

添加到 AndroidManifest.xml android\app\src\main

                 ...
        </activity>
        <activity android:name="com.linusu.flutter_web_auth.CallbackActivity" >
            <intent-filter android:label="flutter_web_auth">
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="yourname" />
            </intent-filter>
            </activity>
    </application>
</manifest>

【讨论】:

以上是关于Flutter:如何将原生 SDK(Spotify Android SDK)添加到应用程序中?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Flutter web 调用原生 Android 代码。?

如何使用 Spotify API 和 Spotify SDK [关闭]

使用android sdk登录spotify时如何获取帐户类型

将 Spotify 的 Android SDK 导入 Android Studio

Flutter笔记-调用原生IOS高德地图sdk

将 Spotify SDK 与 Android 集成