22、移动端适配:React Native集成、原生WebRTC、移动端性能优化、触控交互

说实话,做WebRTC这么久,我踩过最大的坑就是移动端适配。

PC上跑得飞起的视频会议,一到手机上就卡成PPT。屏幕小、网络差、CPU弱,这三个问题就像三座大山。今天我就把这几年的实战经验掰开揉碎,跟你聊聊怎么在移动端把WebRTC玩明白。

22.1 React Native集成:从Web到App的跨越

很多团队选React Native,说白了就是为了复用代码。但WebRTC这块,RN并没有原生支持。你需要一个桥接层。

核心思路:用react-native-webrtc这个库,把原生WebRTC能力暴露给JS层。

安装很简单:

npm install react-native-webrtc
cd ios && pod install

然后你就可以在RN里写这样的代码:

import {
  mediaDevices,
  RTCPeerConnection,
  RTCSessionDescription,
  RTCIceCandidate
} from 'react-native-webrtc';

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

// 获取本地流
const stream = await mediaDevices.getUserMedia({
  audio: true,
  video: { facingMode: 'user' }
});

stream.getTracks().forEach(track => {
  pc.addTrack(track, stream);
});

嗯,这里要注意一点。RN的getUserMedia和浏览器版不太一样。它返回的不是MediaStream,而是MediaStream的RN封装。我刚开始没注意,直接当浏览器API用,结果调试了一整天。

我的习惯:在RN项目里,我会单独封装一个webrtcService.js,把所有原生API调用都集中管理。这样万一要切到Flutter或者纯原生,改动范围最小。

22.2 原生WebRTC:Android和iOS的差异

如果你追求极致性能,或者RN满足不了你的需求,那就得上原生WebRTC了。

Android用Google的官方库,iOS用Google的Pod库。接口基本一致,但细节差异很大。

平台 库名 关键类 注意事项
Android org.webrtc:google-webrtc PeerConnectionFactory 需手动初始化EglBase
iOS GoogleWebRTC RTCPeerConnectionFactory 需在主线程操作UI

Android初始化示例:

PeerConnectionFactory.InitializationOptions initOptions =
    PeerConnectionFactory.InitializationOptions.builder(context)
        .setFieldTrials("WebRTC-H264HighProfile/Enabled/")
        .createInitializationOptions();
PeerConnectionFactory.initialize(initOptions);

EglBase eglBase = EglBase.create();
PeerConnectionFactory factory = PeerConnectionFactory.builder()
    .setVideoDecoderFactory(new DefaultVideoDecoderFactory(eglBase.getEglBaseContext()))
    .setVideoEncoderFactory(new DefaultVideoEncoderFactory(eglBase.getEglBaseContext(), true, true))
    .createPeerConnectionFactory();

iOS初始化示例:

RTCPeerConnectionFactory *factory = [[RTCPeerConnectionFactory alloc] init];

RTCVideoSource *videoSource = [factory videoSource];
RTCVideoCapturer *capturer = [[RTCCameraVideoCapturer alloc] initWithDelegate:videoSource];

我曾经踩过的坑:Android上如果忘记初始化EglBase,渲染视频时直接黑屏。iOS上如果在后台线程操作UI,会触发断言崩溃。这两个问题我各花了两天才定位到。

22.3 移动端性能优化:帧率、分辨率、码率

移动端性能优化,说白了就是做减法。你不能像PC那样开1080p 30fps,手机扛不住。

我一般建议这样配置:

  • 分辨率:默认640x480,网络好时升到1280x720
  • 帧率:15fps起步,最高24fps
  • 码率:500kbps-1.5Mbps,动态调整

代码实现:

const constraints = {
  audio: true,
  video: {
    width: { ideal: 640 },
    height: { ideal: 480 },
    frameRate: { ideal: 15, max: 24 },
    bitrate: { ideal: 800000 }
  }
};

// 动态调整
function adjustBitrate(pc, newBitrate) {
  const sender = pc.getSenders().find(s => s.track?.kind === 'video');
  if (sender) {
    const params = sender.getParameters();
    params.encodings[0].maxBitrate = newBitrate;
    sender.setParameters(params);
  }
}

你想想看,为什么帧率要设15fps?因为人眼对视频流畅度的感知,15fps已经够用了。再高的话,CPU和电池都受不了。

核心原则:移动端优化不是追求最高质量,而是在可接受的质量下,保证稳定性和低功耗。

22.4 触控交互:手势、缩放、布局

移动端没有鼠标,所有交互都靠手指。这就带来了一些特殊问题。

手势缩放:视频画面支持双指缩放

// React Native手势处理
import { PinchGestureHandler, State } from 'react-native-gesture-handler';

function onPinchEvent(event) {
  if (event.nativeEvent.state === State.ACTIVE) {
    const scale = event.nativeEvent.scale;
    // 调整视频渲染尺寸
    videoRef.current.setNativeProps({
      style: { transform: [{ scale: scale }] }
    });
  }
}

布局适配:不同屏幕尺寸下,视频网格要自适应

  • 竖屏模式:主视频占上半屏,小窗列表在底部
  • 横屏模式:视频网格铺满全屏
  • 画中画:支持悬浮小窗

触控反馈:按钮点击要有视觉反馈,不然用户不知道点没点上

我个人的经验:移动端视频会议里,最常用的操作是静音和切换摄像头。这两个按钮一定要放在拇指容易够到的位置。别学某些App把静音按钮放在左上角,单手根本点不到。

22.5 知识体系总览

下面这张图,是我整理的本章节核心逻辑。你看一眼就能明白移动端适配的全貌。

移动端WebRTC适配 React Native集成 原生WebRTC (Android/iOS) 性能优化 触控交互 react-native-webrtc桥接 getUserMedia封装 PeerConnectionFactory初始化 EglBase / 主线程UI操作 分辨率/帧率/码率动态调整 低功耗编码器选择 手势缩放 / 布局自适应 画中画 / 触控反馈 图:移动端WebRTC适配知识体系

这张图把四个核心模块串起来了。你从RN集成入手,搞不定就下沉到原生层,然后做性能优化,最后用触控交互收尾。每一步都有坑,但每一步也都有解法。

总结一句话:移动端WebRTC适配,本质是在有限资源下做平衡。平衡质量与功耗,平衡流畅与清晰,平衡功能与易用。


公众号:蓝海资料掘金营,微信deep3321