You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:实现Flutter App监听耳机按键并打印消息(多包尝试未果)

解决Flutter监听耳机按键事件的方案

你试过的几个包要么仅检测耳机连接状态,要么需要依赖音频播放上下文才能触发按键监听,直接通过**原生通道(MethodChannel)**实现会更可靠,以下是分平台的具体实现:

Android 端实现

Android的耳机媒体按键(播放/暂停、上一曲/下一曲)属于系统广播事件,需要注册BroadcastReceiver监听Intent.ACTION_MEDIA_BUTTON:

  1. 在MainActivity.kt中添加广播接收器和MethodChannel:
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.media.AudioManager
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {
    private val CHANNEL = "com.example.headset_keys/channel"
    private lateinit var methodChannel: MethodChannel
    private lateinit var mediaButtonReceiver: BroadcastReceiver

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
        
        // 注册媒体按键广播接收器
        mediaButtonReceiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {
                if (Intent.ACTION_MEDIA_BUTTON == intent?.action) {
                    val keyEvent = intent.getParcelableExtra<android.view.KeyEvent>(Intent.EXTRA_KEY_EVENT)
                    keyEvent?.let {
                        val keyAction = when (it.keyCode) {
                            android.view.KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> "play_pause"
                            android.view.KeyEvent.KEYCODE_MEDIA_NEXT -> "next"
                            android.view.KeyEvent.KEYCODE_MEDIA_PREVIOUS -> "previous"
                            else -> "unknown"
                        }
                        // 发送按键事件到Flutter端
                        methodChannel.invokeMethod("onHeadsetKeyPressed", keyAction)
                    }
                }
            }
        }
        val filter = IntentFilter(Intent.ACTION_MEDIA_BUTTON)
        filter.priority = IntentFilter.SYSTEM_HIGH_PRIORITY
        registerReceiver(mediaButtonReceiver, filter)
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(mediaButtonReceiver)
    }
}

iOS 端实现

iOS需要监听UIApplicationRemoteControlEvent,在AppDelegate.swift中配置:

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    private let CHANNEL = "com.example.headset_keys/channel"
    
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
        let methodChannel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger)
        
        // 启用远程控制事件
        application.beginReceivingRemoteControlEvents()
        
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
    
    override func remoteControlReceived(with event: UIEvent?) {
        guard let event = event, event.type == .remoteControl else { return }
        var keyAction = "unknown"
        switch event.subtype {
        case .remoteControlPlay:
            keyAction = "play"
        case .remoteControlPause:
            keyAction = "pause"
        case .remoteControlPlayPause:
            keyAction = "play_pause"
        case .remoteControlNextTrack:
            keyAction = "next"
        case .remoteControlPreviousTrack:
            keyAction = "previous"
        default:
            break
        }
        let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
        let methodChannel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger)
        methodChannel.invokeMethod("onHeadsetKeyPressed", arguments: keyAction)
    }
    
    override func applicationWillTerminate(_ application: UIApplication) {
        application.endReceivingRemoteControlEvents()
    }
}

Flutter 端代码

在Flutter页面中监听MethodChannel的回调,打印按键事件:

import 'package:flutter/services.dart';
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  static const platform = MethodChannel('com.example.headset_keys/channel');
  String _keyEvent = '等待耳机按键...';

  @override
  void initState() {
    super.initState();
    // 监听原生发送的按键事件
    platform.setMethodCallHandler((call) async {
      if (call.method == 'onHeadsetKeyPressed') {
        setState(() {
          _keyEvent = '按下了耳机按键:${call.arguments}';
        });
        print(_keyEvent);
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('耳机按键监听')),
        body: Center(child: Text(_keyEvent)),
      ),
    );
  }
}

注意事项

  • Android 13及以上需要在AndroidManifest.xml中添加权限:<uses-permission android:name="android.permission.MEDIA_CONTROL" />
  • iOS中,应用需处于前台状态(或后台播放音频时)才能接收远程控制事件,若需后台监听,需配置音频后台模式。
  • 此前使用audio_service时,需确保应用处于音频播放状态,该包的按键监听依赖媒体会话的激活状态。

内容的提问来源于stack exchange,提问作者RAM KUMAR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 13:45:18