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

求助:使用react-native-webrtc连接两台安卓设备的SDP交互问题

React Native WebRTC 安卓设备连接:解决Offer传递、Answer创建及状态错误问题

我来帮你捋捋你遇到的这些问题——其实核心是WebRTC的连接流程有严格的顺序要求,还有你可能忽略了ICE候选的传递,以及信号通道的正确用法。

为什么会出现"can't use createAnswer() from this state"错误?

你的代码里createAnswer的调用逻辑完全错了:

  • WebRTC要求必须先把对方的Offer设置为自己的remoteDescription,才能调用createAnswer,你直接给createAnswer传sdp参数是无效的,这个方法不需要传参数,它依赖已经设置好的remoteDescription。
  • 另外,发起方创建Offer后,要先完成setLocalDescription,再把完整的Offer对象传给对方,不能只传sdp字符串。

手动复制SDP测试的正确方式

手动复制粘贴不是长久之计,但用来测试的话,一定要传递完整的SDP JSON对象,比如设备A输出的Offer是:

{"type":"offer","sdp":"v=0\r\no=-..."}

你得把整个JSON复制到设备B,而不是只复制sdp字段里的内容——如果type丢失,设备B根本识别不了这是一个Offer,自然无法创建Answer。

信号传递:你必须用Socket(或实时通信工具)

手动复制只能临时测试,实际开发必须用实时通信通道(比如WebSocket、Socket.io、MQTT)来传递两类数据:

  1. SDP Offer/Answer:双方的会话描述,用来协商媒体参数
  2. ICE候选:设备的网络地址信息,用来穿透NAT建立直接连接

没有这个通道,你根本没法实时传递这些关键数据,连接自然建立不起来。

修正后的完整代码示例

设备A(发起方)

import { RTCPeerConnection } from 'react-native-webrtc';

// 必须配置ICE服务器,STUN用来获取公网地址,TURN用来中转(可选但推荐)
const configuration = { 
  iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
};
let pc = new RTCPeerConnection(configuration);

// 监听ICE候选,生成后立刻传给对方
pc.onicecandidate = (event) => {
  if (event.candidate) {
    // 这里替换成你的Socket发送逻辑,比如:socket.emit('ice-candidate', event.candidate)
    console.log("A的ICE候选", JSON.stringify(event.candidate));
  }
};

// 创建Offer的函数
const createOffer = async () => {
  try {
    const offer = await pc.createOffer();
    // 先设置本地描述,再发送Offer
    await pc.setLocalDescription(offer);
    // 把完整的Offer对象发给设备B
    console.log("A的Offer", JSON.stringify(offer));
  } catch (error) {
    console.error("创建Offer失败", error);
  }
};

// 接收设备B的Answer
const handleAnswer = async (answer) => {
  await pc.setRemoteDescription(new RTCSessionDescription(answer));
};

// 接收设备B的ICE候选
const handleIceCandidate = async (candidate) => {
  await pc.addIceCandidate(new RTCIceCandidate(candidate));
};

设备B(应答方)

import { RTCPeerConnection } from 'react-native-webrtc';

const configuration = { 
  iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
};
let pc = new RTCPeerConnection(configuration);

// 监听ICE候选,传给设备A
pc.onicecandidate = (event) => {
  if (event.candidate) {
    // socket.emit('ice-candidate', event.candidate)
    console.log("B的ICE候选", JSON.stringify(event.candidate));
  }
};

// 处理设备A的Offer并创建Answer
const handleOffer = async (offer) => {
  try {
    // 第一步:把收到的Offer设置为远程描述
    await pc.setRemoteDescription(new RTCSessionDescription(offer));
    // 第二步:创建Answer
    const answer = await pc.createAnswer();
    // 第三步:设置本地描述,再发送Answer
    await pc.setLocalDescription(answer);
    console.log("B的Answer", JSON.stringify(answer));
  } catch (error) {
    console.error("创建Answer失败", error);
  }
};

// 接收设备A的ICE候选
const handleIceCandidate = async (candidate) => {
  await pc.addIceCandidate(new RTCIceCandidate(candidate));
};

ICE服务器是必须的吗?

绝对是!几乎所有安卓设备都在NAT网络后面,没有STUN服务器的话,设备无法获取自己的公网地址,根本没法和其他设备建立直接连接。如果遇到严格NAT的网络环境(比如某些企业内网),还需要配置TURN服务器作为数据中转。

完整连接流程总结

  1. 双方初始化RTCPeerConnection并配置ICE服务器
  2. 发起方创建Offer → 设置localDescription → 把Offer传给应答方
  3. 应答方接收Offer → 设置remoteDescription → 创建Answer → 设置localDescription → 把Answer传给发起方
  4. 双方实时传递ICE候选,互相添加对方的候选
  5. 当ICE连接成功后,PeerConnection的onconnectionstatechange会触发,状态变为connected,这时候就可以传输媒体数据了

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:32:42