You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何从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双平台:

  1. 首先在pubspec.yaml添加必要的依赖:
dependencies:
  http: ^1.1.0
  network_info_plus: ^4.0.1
  network_analyzer: ^0.0.4
  1. 实现配对请求的核心方法:
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已经封装了所有配对细节,包括弹窗、验证流程:

  1. 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}');
  }
}
  1. 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

火山引擎 最新活动