在锁屏界面上像Android中的Google Play音乐一样控制媒体吗?

10
我已经阅读了锁屏小部件文档,我实现了它,但是这不是自动放置在主锁定窗口上的东西。 我正在寻找解决方案,可以在Jelly Bean及以上版本的主锁屏窗口上提供媒体控件,就像Google Play音乐应用程序一样。
看看Google Play音乐锁屏,显然不是锁屏小部件。
3个回答

15

你是否已经查看了RemoteControlClient?它用于Android音乐遥控,即使应用程序处于锁定模式。(与您附加的图像相同)

请查看RemoteControlClient

只需在接收到播放、暂停、下一曲和上一曲命令时调用以下方法即可。

  private void lockScreenControls() {

    // Use the media button APIs (if available) to register ourselves for media button
    // events

    MediaButtonHelper.registerMediaButtonEventReceiverCompat(mAudioManager, mMediaButtonReceiverComponent);
    // Use the remote control APIs (if available) to set the playback state
    if (mRemoteControlClientCompat == null) {
        Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
        intent.setComponent(mMediaButtonReceiverComponent);
        mRemoteControlClientCompat = new RemoteControlClientCompat(PendingIntent.getBroadcast(this /*context*/,0 /*requestCode, ignored*/, intent /*intent*/, 0 /*flags*/));
        RemoteControlHelper.registerRemoteControlClient(mAudioManager,mRemoteControlClientCompat);
    }
    mRemoteControlClientCompat.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
    mRemoteControlClientCompat.setTransportControlFlags(
            RemoteControlClient.FLAG_KEY_MEDIA_PAUSE |
            RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS |
            RemoteControlClient.FLAG_KEY_MEDIA_NEXT |
            RemoteControlClient.FLAG_KEY_MEDIA_STOP);

  //update remote controls
    mRemoteControlClientCompat.editMetadata(true)
            .putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, "NombreArtista")
            .putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, "Titulo Album")
            .putString(MediaMetadataRetriever.METADATA_KEY_TITLE, nombreCancion)
            //.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION,playingItem.getDuration())
                    // TODO: fetch real item artwork
            .putBitmap(RemoteControlClientCompat.MetadataEditorCompat.METADATA_KEY_ARTWORK, getAlbumArt())
            .apply();
    }
}

MediaButtonHelper类

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.content.ComponentName;
import android.media.AudioManager;
import android.util.Log;

/**
 * Class that assists with handling new media button APIs available in API level 8.
 */
public class MediaButtonHelper {
    // Backwards compatibility code (methods available as of API Level 8)
    private static final String TAG = "MediaButtonHelper";

    static {
        initializeStaticCompatMethods();
    }

    static Method sMethodRegisterMediaButtonEventReceiver;
    static Method sMethodUnregisterMediaButtonEventReceiver;

    static void initializeStaticCompatMethods() {
        try {
            sMethodRegisterMediaButtonEventReceiver = AudioManager.class.getMethod(
                    "registerMediaButtonEventReceiver",
                    new Class[] { ComponentName.class });
            sMethodUnregisterMediaButtonEventReceiver = AudioManager.class.getMethod(
                    "unregisterMediaButtonEventReceiver",
                    new Class[] { ComponentName.class });
        } catch (NoSuchMethodException e) {
            // Silently fail when running on an OS before API level 8.
        }
    }

    public static void registerMediaButtonEventReceiverCompat(AudioManager audioManager,
            ComponentName receiver) {
        if (sMethodRegisterMediaButtonEventReceiver == null)
            return;

        try {
            sMethodRegisterMediaButtonEventReceiver.invoke(audioManager, receiver);
        } catch (InvocationTargetException e) {
            // Unpack original exception when possible
            Throwable cause = e.getCause();
            if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            } else if (cause instanceof Error) {
                throw (Error) cause;
            } else {
                // Unexpected checked exception; wrap and re-throw
                throw new RuntimeException(e);
            }
        } catch (IllegalAccessException e) {
            Log.e(TAG, "IllegalAccessException invoking registerMediaButtonEventReceiver.");
            e.printStackTrace();
        }
    }

    @SuppressWarnings("unused")
    public static void unregisterMediaButtonEventReceiverCompat(AudioManager audioManager,
            ComponentName receiver) {
        if (sMethodUnregisterMediaButtonEventReceiver == null)
            return;

        try {
            sMethodUnregisterMediaButtonEventReceiver.invoke(audioManager, receiver);
        } catch (InvocationTargetException e) {
            // Unpack original exception when possible
            Throwable cause = e.getCause();
            if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            } else if (cause instanceof Error) {
                throw (Error) cause;
            } else {
                // Unexpected checked exception; wrap and re-throw
                throw new RuntimeException(e);
            }
        } catch (IllegalAccessException e) {
            Log.e(TAG, "IllegalAccessException invoking unregisterMediaButtonEventReceiver.");
            e.printStackTrace();
        }
    }
}

请参考给出的开发者应用程序了解如何集成RemoteControlClient:随机音乐播放器。然而,RemoteControlClient的UI会根据设备而异,您不能更新其UI为自己的,但可以控制显示和显示音乐应用程序的组件和控件。

更新

上述提到的类现在已过时。因此,请使用Media Session进行检查并进行相应的更新。


1
谢谢你提供这段代码!但是你能否给我们一个完整的教程,来说明如何做到这一点! - satyres
RemoteController已经过时,有更新的教程链接吗? - WideFide
1
@AnandSavjani 在回答中添加了 MediaButtonHelper 类。请根据您的需要进行更新。 :) - Shreyash Mahajan
一些方法现在已经过时,请查看链接并提供答案:https://stackoverflow.com/questions/54633202/how-to-set-mediaplayer-notification-with-mediasession-and-notificationcompat-med?noredirect=1#comment96070177_54633202 - Vipul Chauhan
嗨@iDroidExplorer。我在这里给出了一个解释,那有用吗?链接 - halfer
显示剩余3条评论

2

1
MediaSession看起来不错,但它需要API 21,而我仍然必须支持API 16+。 - Tauri
然后使用 MediaSessionCompat 代替 @dkzm - user3793589
它在4.4上运行良好,但6.0显示通知而不是按钮,有什么诀窍吗? - Singagirl
为什么要使用mediaBrowserServiceCompat,如果我们可以通过mediaSessionCompat在锁屏/通知栏上提供播放控制? - V1 Kr
@eremzeit:你知道RemoteViews是否可以更改锁屏壁纸吗? - JoshuaTree

0

如果您的通知媒体控制工作良好,且已在锁屏界面上显示,但却无法使用,则可以按照以下代码使锁屏界面上的媒体控制(播放、暂停、下一首、上一首)正常工作:

private MediaSessionCompat mMediaSessionCompat;  
private AudioManager audioManager;

在您的服务类的onCreate方法中调用以下方法:
private void RegisterRemoteClient() {
    audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    assert audioManager != null;
    audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
            AudioManager.AUDIOFOCUS_GAIN);

    ComponentName mRemoteControlResponder = new ComponentName(getPackageName(),
            NotificationBroadcast.class.getName());


    Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
    mediaButtonIntent.setComponent(mRemoteControlResponder);

    mMediaSessionCompat = new MediaSessionCompat(getApplication(), "JairSession", mRemoteControlResponder, null);
    mMediaSessionCompat.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
    PlaybackStateCompat playbackStateCompat = new PlaybackStateCompat.Builder()
            .setActions(
                    PlaybackStateCompat.ACTION_SEEK_TO |
                            PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS |
                            PlaybackStateCompat.ACTION_SKIP_TO_NEXT |
                            PlaybackStateCompat.ACTION_PLAY |
                            PlaybackStateCompat.ACTION_PAUSE |
                            PlaybackStateCompat.ACTION_STOP
            )
            .build();
    mMediaSessionCompat.setPlaybackState(playbackStateCompat);
    mMediaSessionCompat.setCallback(mMediaSessionCallback);
    mMediaSessionCompat.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
}

现在在服务类中创建这个回调函数:

private MediaSessionCompat.Callback mMediaSessionCallback = new MediaSessionCompat.Callback() {

    @Override
    public void onPlay() {
        super.onPlay();
        mMediaSessionCompat.setActive(true);
        Log.d("dvmMediaSessionCompat ","onPlay");
        if (PlayerConstants.SONG_PAUSED){
            Controls.playControl(getApplicationContext());
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.d("dvmMediaSessionCompat ","onPause");
        if (!PlayerConstants.SONG_PAUSED){
            Controls.pauseControl(getApplicationContext());
        }
        else
            Controls.playControl(getApplicationContext());


    }
    @Override
    public void onSkipToQueueItem(long queueId) {

    }

    @Override
    public void onSeekTo(long position) {

    }

    @Override
    public void onStop() {
        Log.d("dvmMediaSessionCompat ","onStop");
    }

    @Override
    public void onSkipToNext() {
        Log.d("dvmMediaSessionCompat ","onSkipToNext");
        Controls.nextControl(getApplicationContext());
    }

    @Override
    public void onSkipToPrevious() {
        Log.d("dvmMediaSessionCompat ","onSkipToPrevious");
        Controls.previousControl(getApplicationContext());
    }

};

这就是我所做的,控件开始工作了,我只是忘记在我的 MediaSessionCompat 实例上添加 setCallback,这就是为什么我的控件没有工作的原因。但现在它完美地工作了。

注意:Controls.nextControl(context) 这是我添加自己功能以切换歌曲的方法,您可以用您的逻辑来替换它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接