当前位置: 首页 > news >正文

Android监听第三方播放获取音乐信息及包名

文章目录

  • NotificationListenerService
  • 代码获取播放音乐
    • 步骤 1:声明权限和服务
    • 步骤 2:实现NotificationListenerService
    • 步骤 3:请求用户启用通知监听权限
    • 启动服务
    • 注意事项
    • 获取播放信息如下图:

NotificationListenerService

NotificationListenerService 是 Android 系统提供的一个特殊服务,允许应用监听和获取其他应用发出的通知。通过这个服务,开发者可以读取通知的内容、发送时间、来源应用等信息,还可以对通知进行操作(如删除通知)。
核心功能。

  • 监听通知:获取系统中所有应用发出的通知。
  • 读取通知内容:包括标题、文本、图标等。
  • 通知操作:删除通知或执行通知中的操作。

在 Android 中使用 NotificationListenerService 监听媒体播放器状态是可行的,因为大多数媒体应用(如音乐播放器、视频播放器)会在发出的通知中包含当前播放状态(播放 / 暂停)、曲目信息(标题、艺术家、专辑)等内容。下面介绍如何实现这一功能。

注意:有一些应用NotificationListenerService是监听不到播放状态的,比如其不发通知,或者是在后台播放情况下没有通知,这种可以考虑不使用NotificationListenerService实现,而是用一个定时器去轮询MediaSessionManager的getActiveSessions()函数获取音乐信息,这里不贴代码了。

代码获取播放音乐

步骤 1:声明权限和服务

在AndroidManifest.xml中添加以下权限和服务:

<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" /><serviceandroid:name=".MediaSessionListenerService"android:label="Notification Listener"android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"><intent-filter><action android:name="android.service.notification.NotificationListenerService" /></intent-filter>
</service>

步骤 2:实现NotificationListenerService

创建MediaSessionListenerService类继承NotificationListenerService:

import android.app.Notification;
import android.media.session.MediaController;
import android.media.MediaMetadata;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;public class MediaSessionListenerService extends NotificationListenerService {private static final String TAG = "MusicProgressListener";private MediaController mMediaController;private String currentPlayingPackage;public void onMusicStateChanged(PlaybackState state) {if (state != null) {long currentPosition = state.getPosition();Log.d(TAG, "[" + currentPlayingPackage + "] 当前进度: " + currentPosition + " ms");}}public void onMusicMetadataChanged(MediaMetadata metadata) {if (metadata != null) {long duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);String title = metadata.getString(MediaMetadata.METADATA_KEY_TITLE);String artist = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST);Log.d(TAG, "[" + currentPlayingPackage + "] 歌曲: " + title + " - " + artist);Log.d(TAG, "[" + currentPlayingPackage + "] 总时长: " + duration + " ms");}}private final MediaController.Callback mControllerCallback = new MediaController.Callback() {@Overridepublic void onPlaybackStateChanged(PlaybackState state) {onMusicStateChanged(state);}@Overridepublic void onMetadataChanged(MediaMetadata metadata) {onMusicMetadataChanged(metadata);}};@Overridepublic void onListenerConnected() {super.onListenerConnected();Log.d(TAG, "通知监听服务已连接");// 服务连接后,立即检查当前是否有活跃的媒体会话checkActiveMediaSessions();}@Overridepublic void onNotificationPosted(StatusBarNotification sbn) {super.onNotificationPosted(sbn);// 当有新通知发出时,检查是否是媒体通知handleMediaNotification(sbn);}@Overridepublic void onNotificationRemoved(StatusBarNotification sbn) {super.onNotificationRemoved(sbn);// 当媒体通知被移除时(如音乐停止),清理资源if (isMediaNotification(sbn)) {// 确保只清理当前正在播放的会话if (mMediaController != null && sbn.getPackageName().equals(currentPlayingPackage)) {mMediaController.unregisterCallback(mControllerCallback);mMediaController = null;currentPlayingPackage = null; // 重置包名Log.d(TAG, "媒体会话已断开: " + sbn.getPackageName());}}}private void checkActiveMediaSessions() {StatusBarNotification[] activeMediaSessions = getActiveNotifications();if (activeMediaSessions != null && activeMediaSessions.length > 0) {// 通常我们只关心第一个活跃的媒体会话handleMediaNotification(activeMediaSessions[0]);}}private void handleMediaNotification(StatusBarNotification sbn) {if (!isMediaNotification(sbn)) {return;}// 如果已经是当前正在处理的包,无需重复操作if (sbn.getPackageName().equals(currentPlayingPackage)) {return;}try {Bundle extras = sbn.getNotification().extras;MediaSession.Token token = extras.getParcelable(Notification.EXTRA_MEDIA_SESSION);if (token != null) {// 如果已经有一个控制器,先注销它if (mMediaController != null) {mMediaController.unregisterCallback(mControllerCallback);}// 创建新的 MediaControllermMediaController = new MediaController(this, token);mMediaController.registerCallback(mControllerCallback);// 从 StatusBarNotification 获取包名并存储currentPlayingPackage = sbn.getPackageName();Log.d(TAG, "已连接到媒体会话: " + currentPlayingPackage);// 立即获取一次当前状态,防止错过回调PlaybackState state = mMediaController.getPlaybackState();MediaMetadata metadata = mMediaController.getMetadata();if (state != null) {onMusicStateChanged(state);}if (metadata != null) {onMusicMetadataChanged(metadata);}}} catch (Exception e) {Log.e(TAG, "处理媒体通知时出错", e);}}private boolean isMediaNotification(StatusBarNotification sbn) {// 判断一个通知是否为媒体通知Notification notification = sbn.getNotification();return notification != null && notification.extras != null&& notification.extras.containsKey(Notification.EXTRA_MEDIA_SESSION);}
}

步骤 3:请求用户启用通知监听权限

在Activity中检查并请求权限,系统不会自动授予此权限。你需要引导用户去设置页面手动开启:
MainActivity.java

private void checkNotificationListenerPermission() {if (!isNotificationServiceEnabled()) {startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));}
}private boolean isNotificationServiceEnabled() {String packageName = getPackageName();String flat = Settings.Secure.getString(getContentResolver(), "enabled_notification_listeners");if (flat != null) {String[] names = flat.split(":");for (String name : names) {ComponentName cn = ComponentName.unflattenFromString(name);if (cn != null && cn.getPackageName().equals(packageName)) {return true;}}}return false;
}

然后MainActivity.java中调用

checkNotificationListenerPermission();

用户必须点击进入设置,并手动开启你的 App 的“通知监听”开关。
在这里插入图片描述

启动服务

通常不需要显式启动 NotificationListenerService,只要用户开启了权限,系统就会自动绑定并运行服务。
但你可以调用以下代码来“尝试”触发绑定(实际是否运行仍由系统控制),

// 可以尝试启动服务(非必需)
Intent intent = new Intent(this, MediaSessionListenerService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {startForegroundService(intent);
} else {startService(intent);
}

运行正常的话onListenerConnected()会被自动调用

@Override
public void onListenerConnected() {super.onListenerConnected();Log.d(TAG, "通知监听服务已连接"); // 这行会被执行checkActiveMediaSessions();
}

你可以在 Logcat 中搜索 “通知监听服务已连接” 来确认是否成功触发。

注意事项

  1. 用户授权:必须引导用户到设置中启用应用的通知监听权限。
  2. 媒体会话限制:并非所有应用都使用MediaSession,因此可能无法检测到所有播放情况。
  3. 多应用播放:可能存在多个应用同时播放的情况,需根据业务逻辑处理。

如果报以下错误,
java.lang.SecurityException: Missing permission to control media.
需要加上这个权限

获取播放信息如下图:

在这里插入图片描述
注意上面有总时长为-1的,这个是不对的需要特殊处理。
作者:帅得不敢出门

http://www.dtcms.com/a/479053.html

相关文章:

  • wordpress仿站教程网wordpress 房屋租赁
  • 在线视频网站开发成本手机版网页开发者工具
  • [GO]一文理清Go语言依赖管理:从go get到Go Modules,避坑指南
  • 嵌入式软件架构--按键消息队列2(组合键,按键转义与三种消息模式)
  • 电商平台有哪些网站名山东省城乡建设厅网站
  • Vue 3 + Vite:现代前端开发新范式-前端开发的”涡轮增压引擎”-优雅草卓伊凡
  • 前端-Vuex
  • 微信小说网站开发商丘网络科技有限公司
  • 避免时区问题的最佳实践, 数据库, mybatis
  • 望江县建设局网站发布网页
  • Codeforces1058(Div.2) A至F题解
  • MCP原理与实践1-原理部分(详细)
  • 云栖实录|人工智能+大数据平台加速企业模型后训练
  • WordPress整站下载器长春火车站建在哪里
  • 做电影平台网站怎么赚钱吗营销型网站建设多少钱
  • CF1057 BCD
  • 网站开发外文翻译中国纪检监察报网站
  • 医疗级能效革命:医院 “AI + 中央空调” 节能改造全解析
  • [Linux系统编程——Lesson11.进程控制:等待]
  • 甘南网站建设vi设计网站有哪些
  • 网站开发的一般流程是什么建个网站有收
  • 网站开发完成如何上线vs能建设网站吗
  • 婚车租赁网站怎样做wordpress 去掉主题版权
  • yolo的各模块扫盲
  • 宁波营销网站建设外包软件项目管理流程
  • 部门网站的开发 意义二次元wordpress博客
  • Spring 中解决 “Could not autowire. There is more than one bean of type“ 错误
  • 网站开发 前景wordpress魔方
  • 湖南平台网站建设找哪家凤城市网站建设
  • 常规的长焦镜头有哪些类型?能做什么?