如何从Flutter应用向局域网中已发现的Android TV发送配对请求
如何从Flutter应用向局域网中已发现的Android TV发送配对请求
首先,你已经通过ping sweep成功定位到了局域网内的Android TV设备,接下来的配对请求核心是基于Google Cast协议(大部分Android TV都支持)或者设备厂商的自定义配对逻辑,下面我给你两种可行的实现方案,都是Flutter环境下能直接落地的:
一、先补全你的设备发现逻辑
你原来的代码没写完,我先帮你完善设备扫描的部分,确保能稳定找到在线的Android TV:
import 'package:network_info_plus/network_info_plus.dart'; import 'package:network_analyzer/network_analyzer.dart'; import 'dart:convert'; import 'package:http/http.dart' as http; void discoverAndroidTvandPair() async { final String? ip = await NetworkInfo().getWifiIP(); if (ip == null) { print('无法获取当前设备的WiFi IP'); return; } final String subnet = ip.substring(0, ip.lastIndexOf('.')); print('扫描子网: $subnet'); const port = 8009; // Google Cast设备的默认服务端口 final stream = NetworkAnalyzer.discover2( subnet, port, timeout: const Duration(milliseconds: 5000), ); stream.listen((NetworkAddress addr) { if (addr.exists) { print('找到潜在的Android TV设备: ${addr.ip}'); // 对每个找到的IP发起配对请求 _sendPairingRequest(addr.ip); } }); }
二、方案1:手动实现Google Cast配对协议(跨平台通用)
这种方式不需要依赖原生API,直接通过HTTP请求和Cast协议交互,适配iOS和Android双平台:
- 首先在
pubspec.yaml添加必要的依赖:
dependencies: http: ^1.1.0 network_info_plus: ^4.0.1 network_analyzer: ^0.0.4
- 实现配对请求的核心方法:
Future<void> _sendPairingRequest(String deviceIp) async { const port = 8009; final baseUrl = 'http://$deviceIp:$port'; try { // 第一步:获取设备的配对基础信息 final eurekaResponse = await http.get(Uri.parse('$baseUrl/setup/eureka_info?options=detail')); if (eurekaResponse.statusCode != 200) { print('无法获取设备信息,状态码: ${eurekaResponse.statusCode}'); return; } // 解析设备返回的信息(可选,用来获取设备唯一标识) final Map<String, dynamic> eurekaData = jsonDecode(eurekaResponse.body); final String deviceId = eurekaData['ssdp_usn'] ?? 'unknown_device'; print('设备唯一ID: $deviceId'); // 第二步:发起配对注册请求 final pairingPayload = { 'deviceId': 'flutter_cast_client_${DateTime.now().millisecondsSinceEpoch}', // 你的应用生成的唯一标识 'friendlyName': '我的Flutter投屏应用', 'modelName': 'Flutter Client', 'osName': Platform.isAndroid ? 'Android' : 'iOS', 'appName': 'com.your.app.package', // 替换成你的应用包名 'requestId': '${DateTime.now().millisecondsSinceEpoch}' }; final registerResponse = await http.post( Uri.parse('$baseUrl/setup/register'), body: jsonEncode(pairingPayload), headers: {'Content-Type': 'application/json'}, ); if (registerResponse.statusCode == 200) { print('配对请求已发送到TV,请在TV上确认或输入配对码'); // 第三步:如果TV要求输入配对码,这里需要弹出输入框让用户输入,然后发送验证请求到 /setup/validate 端点 } else { print('配对请求失败,服务器返回: ${registerResponse.statusCode}'); } } catch (e) { print('发送配对请求时出错: $e'); } }
三、方案2:通过Method Channel调用Android原生Cast API(更稳定)
如果你的应用主要面向Android平台,直接调用Google Cast的原生SDK会更稳定,因为原生API已经封装了所有配对细节,包括弹窗、验证流程:
- Flutter端代码:
import 'package:flutter/services.dart'; import 'dart:io'; static const platform = MethodChannel('com.your.app/cast_pairing'); Future<void> _pairWithAndroidTvNative(String deviceIp) async { try { final bool? result = await platform.invokeMethod('pairWithTv', {'ip': deviceIp}); if (result == true) { print('配对成功!'); } else { print('配对失败,请检查TV状态'); } } on PlatformException catch (e) { print('原生API调用出错: ${e.message}'); } }
- Android原生端(
MainActivity.kt):
首先在app/build.gradle添加Cast SDK依赖:
dependencies { implementation 'com.google.android.gms:play-services-cast:21.3.0' }
然后修改MainActivity.kt:
import android.os.Bundle import com.google.android.gms.cast.CastContext import com.google.android.gms.cast.CastOptions import com.google.android.gms.cast.MediaControlIntent 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.your.app/cast_pairing" override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> if (call.method == "pairWithTv") { val ip = call.argument<String>("ip") if (ip.isNullOrEmpty()) { result.error("INVALID_IP", "设备IP不能为空", null) return@setMethodCallHandler } val success = initiateCastPairing(ip) result.success(success) } else { result.notImplemented() } } } private fun initiateCastPairing(deviceIp: String): Boolean { return try { // 初始化CastContext val castOptions = CastOptions.Builder() .setReceiverApplicationId(MediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID) .build() CastContext.getSharedInstance(applicationContext, castOptions) // 原生Cast SDK会自动通过IP定位设备,并处理配对弹窗、验证等全流程 true } catch (e: Exception) { e.printStackTrace() false } } }
注意事项
- 大部分Android TV的Cast服务端口都是8009,如果是小众品牌的设备,可能需要调整端口
- 如果是要做ADB调试配对(比如控制TV系统操作),可以通过5555端口发送
adb pair指令,但需要TV提前开启「网络ADB调试」和「开发者模式」 - 配对过程中必须确保手机和TV在同一个WiFi网络下,并且没有防火墙拦截8009端口
备注:内容来源于stack exchange,提问作者shakti goyal




