Android 获取第三方音乐的播放信息

3,544 阅读2分钟

控制第三方播放的播放状态

控制第三方播放的播放暂停等等可以通过AudioManager API控制其他播放器的播放状态


//播放/暂停
import android.view.KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
//播放
import android.view.KeyEvent.KEYCODE_MEDIA_PLAY;
//暂停
import android.view.KeyEvent.KEYCODE_MEDIA_PAUSE;
//上一曲
import android.view.KeyEvent.KEYCODE_MEDIA_PREVIOUS;
//下一曲
import android.view.KeyEvent.KEYCODE_MEDIA_NEXT;


/**
 * 模拟按键事件
 */
private void sendKeyEvent(final int keyCode) {
    KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
    audioManager.dispatchMediaKeyEvent(keyEvent);
    keyEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
    audioManager.dispatchMediaKeyEvent(keyEvent);
}

获取第三方播放器的播放信息

第一步获取通知权限

获取第三方的播放信息需要android.permission.BIND_NOTIFICATION_LISTENER_SERVICE权限,并且要获得用户的许可

<!--通知的监听服务 继承android.service.notification.NotificationListenerService-->
<service android:name=".YourNotificationListenerService"
    android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
    <intent-filter>
        <action android:name="android.service.notification.NotificationListenerService" />
    </intent-filter>
</service>
//进入通知权限设置,找到自己的应用并打开
startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));

判断是否开启了通知权限

public static boolean isNotificationListenerEnabled(Context context) {
    Set<String> packageNames = NotificationManagerCompat.getEnabledListenerPackages(context);
    if (packageNames.contains(context.getPackageName())) {
        return true;
    }
    return false;
}

第二步获取播放信息

在运行设备Android >= 21 ,使用MediaSessionManager 获取活动的MediaController

Object service =getContext().getSystemService(Context.MEDIA_SESSION_SERVICE);
if (service instanceof MediaSessionManager) {
    MediaSessionManager manager = (MediaSessionManager) service;
    ComponentName componentName =
            new ComponentName(this, YourNotificationListenerService.class);
    mSessionsChangedListener
            = new MediaSessionManager.OnActiveSessionsChangedListener() {
        @Override
        public void onActiveSessionsChanged(List<MediaController> controllers) {
            synchronized (this) {
                mActiveSessions = controllers;
                registerSessionCallbacks();
            }
        }
    };
    manager.addOnActiveSessionsChangedListener(mSessionsChangedListener, componentName);
    synchronized (this) {
        mActiveSessions = manager.getActiveSessions(componentName);
        registerSessionCallbacks();
    }
}

在这里通过MediaMetadataPlaybackState就可以获取到第三方播放器的播放信息和播放状态

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void registerSessionCallbacks() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        for (MediaController controller : mActiveSessions) {
            if (mSessionCallback == null) {
                mSessionCallback = new MediaController.Callback() {
                    @Override
                    public void onMetadataChanged(MediaMetadata metadata) {
                        if (metadata != null) {
                            String trackName =
                                    metadata.getString(MediaMetadata.METADATA_KEY_TITLE);
                            String artistName =
                                    metadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
                            String albumArtistName =
                                    metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ARTIST);
                            String albumName =
                                    metadata.getString(MediaMetadata.METADATA_KEY_ALBUM);
                            
                        }
                    }
					
		    @Override
		    public void onPlaybackStateChanged(PlaybackState state) {
			if(state != null){
			   boolean isPlaying = state.getState() == PlaybackState.STATE_PLAYING
			}
						
		    }
					
                };
            }
            controller.registerCallback(mSessionCallback);
        }
    }
}

在运行设备Android < 21 ,使用RemoteController

 public void registerRemoteController() {
     //YourNotificationListenerService实现RemoteController.OnClientUpdateListener接口
     mRemoteController = new RemoteController(getContext(), this);
     boolean registered;
     try {
         registered = ((AudioManager) getSystemService(AUDIO_SERVICE)).registerRemoteController(mRemoteController);
     } catch (NullPointerException | SecurityException e) {
         registered = false;
     }
     if (registered) {
         try {
             mRemoteController.setArtworkConfiguration(100, 100);
             mRemoteController.setSynchronizationMode(RemoteController.POSITION_SYNCHRONIZATION_CHECK);
         } catch (IllegalArgumentException e) {
             e.printStackTrace();
         }
     }
 }

回调的播放信息和播放状态

 @Override
 public void onClientMetadataUpdate(RemoteController.MetadataEditor arg0) {
     String trackName = arg0.getString(MediaMetadataRetriever.METADATA_KEY_TITLE, null);
     String artistName = arg0.getString(MediaMetadataRetriever.METADATA_KEY_ARTIST, null);
     String albumArtistName = arg0
             .getString(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, null);
     String albumName = arg0.getString(MediaMetadataRetriever.METADATA_KEY_ALBUM, null);
 }
 
 @Override
 public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs, long currentPosMs, float speed) {
     boolean isPlaying = state == PlaybackState.STATE_PLAYING
 }

并不是所有的第三方音乐app都可以获取到它播放信息和播放状态,如果第三方播放器没有把 MediaMetadataPlaybackState给到 MediaSession,通过以上方法是无法获取到该app的播放信息和播放状态的。

具体媒体类app怎么把播放器和播放状态给到Android系统,可以参考android的官方音乐播放器demouamp,最新的代码是kotlin的,java的可以看1.2版本的MusicService

最后感谢:

stackoverflow.com/questions/5…

github.com/YoungBill/A…

github.com/tomahawk-pl…

最后最后就是还有个bug,因为现在很多音乐播放器支持同时播放,就可能会导致获取到的播放信息和播放状态不对。