Android 通知栏,锁屏播放音乐,类似音乐播放器

项目中需要用到播放音频的功能,想做一个类似酷狗、酷我这样的音频播放功能,在通知栏和锁屏时都可以操控音乐,开发中发现oppo reno手机在锁屏时不显示通知栏,研究了整整一天终于解决,特作记录,给遇到同样问题的童鞋做个参考。

整体功能实现思路如下:

1.播放音乐时启动前台服务,在服务中创建播放器和通知并且创建广播,音频的播控通过广播来操控,实现跨模块;

2.在切换音频源、播放、暂停的时候通过重新创建通知来实现通知的界面更新;

3.在关闭音频功能时关掉通知,释放播放器。

 

细节,以下只做简单说明,具体实现方式请百度,本文只是为了解决锁屏不显示通知的问题,已测试正常使用的机型有华为、荣耀、oppo:

1.通知的自定义view为remoteView;

2.通知创建时需要判断8.0渠道配置:

    private fun createChannel(context: Context, channel_id: String, channel_name: CharSequence, description: String) {
        //8.0以上版本通知适配
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val notificationChannel = NotificationChannel(channel_id, channel_name, NotificationManager.IMPORTANCE_HIGH)

            notificationChannel.setSound(null, null)
            notificationChannel.enableLights(false) //通知灯
            notificationChannel.lightColor = Color.RED // 通知灯颜色
            notificationChannel.setShowBadge(false) //角标
            notificationChannel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC // 所有情况下显示,包括锁屏
            notificationChannel.description = description

            val notificationManager = context.getSystemService(NotificationManager::class.java)
            notificationManager.createNotificationChannel(notificationChannel)
        }
    }


    /**
     * 返回一个前台通知
     *
     * @param channel_id  通知渠道id,注意8.0创建通知的时候渠道id与此要匹配
     * @param remoteViews 自定义通知view
     * @return
     */
    fun createForeNotification(context: Context, channel_id: String, channel_name: CharSequence, description: String, remoteViews: RemoteViews): Notification {
        CreateChannel(context, channel_id, channel_name, description)

        val builder = NotificationCompat.Builder(context, channel_id)
                .setSmallIcon(R.mipmap.ic_launcher) //最顶部的小图标
                .setContent(remoteViews)
                .setAutoCancel(true) // 允许自动清除
                .setPriority(NotificationCompat.PRIORITY_MAX)
                .setSound(Uri.EMPTY) //声音
                .setDefaults(NotificationCompat.DEFAULT_ALL) //统一消除声音和震动
                .setVisibility(Notification.VISIBILITY_PUBLIC) // 所有情况下显示,包括锁屏


        return builder.build()
    }

3.对通知设置点击事件,切换、暂停、播放的原理一样,如果别的模块需要调用播控的话直接发送广播即可:

        // 暂停
        val pauseIntent = Intent(AudioBroadCastReceiver.PAUSE)
        val pausePendingIntent = PendingIntent.getBroadcast(this, 0, pauseIntent, 0)
        notifyLayout.setOnClickPendingIntent(R.id.iv_music_pause, pausePendingIntent)

        // 播放
        val playIntent = Intent(AudioBroadCastReceiver.PLAY)
        val playPendingIntent = PendingIntent.getBroadcast(this, 0, playIntent, 0)
        notifyLayout.setOnClickPendingIntent(R.id.iv_music_play, playPendingIntent)
object AudioBroadCastReceiver : BroadcastReceiver() {
    private val TAG = javaClass.simpleName

    const val PLAY_PRE = "com.audio.PLAY_PRE"
    const val PLAY_NEXT = "com.audio.PLAY_NEXT"
    const val PLAY = "com.audio..PLAY"
    const val PAUSE = "com.audio.PAUSE"

    // 停止播放器、关闭通知、关闭服务、关掉播放界面
    const val CLOSE = "com.audio.CLOSE"

    var receiveListener: ((Context, Intent?) -> Unit)? = null

    override fun onReceive(context: Context, intent: Intent?) {
        Logger.d(TAG, "onReceive: ${intent?.action}")

        val audioPlayerHelper = App.get().audioPlayerHelper

        intent?.let {
            when (it.action) {
                PLAY_PRE -> {
                    Logger.d(TAG, "onReceive: 上一节")
                    audioPlayerHelper.playPre()
                }
                PLAY_NEXT -> {
                    Logger.d(TAG, "onReceive: 下一节")
                    audioPlayerHelper.playNext()
                }
                PLAY -> {
                    Logger.d(TAG, "onReceive: 播放")
                    audioPlayerHelper.play()
                }
                PAUSE -> {
                    Logger.d(TAG, "onReceive: 暂停")
                    audioPlayerHelper.pause()
                }
                CLOSE -> {
                    Logger.d(TAG, "onReceive: 停止")
                    audioPlayerHelper.stop()
                }
                else -> {
                }
            }

            receiveListener?.invoke(context,intent)
        }
    }


}

4.服务中启动通知:

  startForeground(AudioNotifyHelper.NOTIFY_ID, notification)

5.监听锁屏,我遇到的问题就是在oppo手机上锁屏不显示通知,其实解决办法就是监听锁屏,在锁屏后再次发送一次通知即可:

public class HomeWatcherReceiver extends BroadcastReceiver {
    private final String TAG = getClass().getSimpleName();

    private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
    private static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
    private static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
    private static final String SYSTEM_DIALOG_REASON_LOCK = "lock";
    private static final String SYSTEM_DIALOG_REASON_ASSIST = "assist";

    private PhysicalKeyListener listener;

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Logger.i(TAG, "onReceive: action: " + action);

        if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
            // android.intent.action.CLOSE_SYSTEM_DIALOGS
            String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
            Logger.i(TAG, "reason: " + reason);

            if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)) {
                // 短按Home键
                Logger.i(TAG, "homekey");

                if(listener != null){
                    listener.onHome();
                }

            } else if (SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) {
                // 长按Home键 或者 activity切换键
                Logger.i(TAG, "long press home key or activity switch");

                if(listener != null){
                    listener.onRecentApp();
                }

            } else if (SYSTEM_DIALOG_REASON_LOCK.equals(reason)) {
                // 锁屏
                Logger.i(TAG, "lock");

                if(listener != null){
                    listener.onLock();
                }
            } else if (SYSTEM_DIALOG_REASON_ASSIST.equals(reason)) {
                // samsung 长按Home键
                Logger.i(TAG, "assist");

                if(listener != null){
                    listener.onAssist();
                }
            }
        } else if (Intent.ACTION_SCREEN_ON.equals(action)) { // 开屏
            Logger.i(TAG, "onReceive: 开屏");

            if(listener != null){
                listener.onScreenOn();
            }

        } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { // 锁屏
            Logger.i(TAG, "onReceive: 锁屏");
            if(listener != null){
                listener.onScreenOff();
            }

        } else if (Intent.ACTION_USER_PRESENT.equals(action)) { // 解锁
            Logger.i(TAG, "onReceive: 解锁");

            if(listener != null){
                listener.onUserPresent();
            }
        }
    }

    public void setListener(PhysicalKeyListener listener) {
        this.listener = listener;
    }
}

6.在服务中注册锁屏广播监听,监听到锁屏再发一次通知即可。

至此,仿音乐播放器的通知栏和锁屏操控音乐就OK了,如果有特殊机型或者其他情况不管用的,评论区咱们互相讨论、学习。

共勉!

效果如下:

 

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值