移动端WebRTC:Android与iOS的集成实战
说实话,移动端做WebRTC开发,跟PC端完全是两码事。我在2018年第一次把WebRTC塞进Android项目时,光是编译库就折腾了两天。那时候官方文档还不像现在这么完善,踩了不少坑。今天我把这些经验整理出来,希望能帮你少走弯路。
Android端集成:从零开始
Android集成WebRTC,核心就三步:引入库、初始化PeerConnectionFactory、建立连接。但每一步都有讲究。
1. 引入WebRTC库
现在官方推荐用Maven依赖,简单直接:
// build.gradle (app级别)
dependencies {
implementation 'org.webrtc:google-webrtc:1.0.32006'
}
嗯,这里要注意版本号。我习惯用稳定版,比如1.0.32006。太新的版本可能有兼容问题,太旧的又缺功能。
如果你需要定制化编译,比如裁剪不需要的编解码器,那就得走源码编译了。我个人建议:初期先用预编译库,等业务稳定了再考虑定制。
2. 初始化PeerConnectionFactory
这是WebRTC的核心工厂类。初始化代码大概长这样:
// 初始化
PeerConnectionFactory.InitializationOptions initOptions =
PeerConnectionFactory.InitializationOptions.builder(context)
.setFieldTrials("")
.createInitializationOptions();
PeerConnectionFactory.initialize(initOptions);
// 创建工厂
PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
PeerConnectionFactory factory = PeerConnectionFactory.builder()
.setOptions(options)
.createPeerConnectionFactory();
我在项目中遇到过一个问题:初始化必须在主线程调用,否则会崩溃。你想想看,如果放在子线程里,那调试起来得多头疼。
3. 创建PeerConnection
有了工厂,接下来就是创建连接:
// ICE服务器配置
List<PeerConnection.IceServer> iceServers = new ArrayList<>();
iceServers.add(PeerConnection.IceServer.builder("stun:stun.l.google.com:19302").createIceServer());
PeerConnection.RTCConfiguration config = new PeerConnection.RTCConfiguration(iceServers);
config.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;
PeerConnection connection = factory.createPeerConnection(config, observer);
这里有个坑:sdpSemantics一定要设成UNIFIED_PLAN。为什么?因为PLAN_B已经被废弃了,不设的话,跟新版浏览器互通时会出问题。我曾经因为这个排查了一整天。
iOS端集成:Swift与Objective-C的抉择
iOS端我推荐用CocoaPods集成,省心:
# Podfile
pod 'GoogleWebRTC'
然后pod install就完事了。但要注意,GoogleWebRTC这个pod体积不小,大概80MB左右。如果你的App对包大小敏感,可以考虑用源码编译裁剪。
初始化流程
iOS的初始化跟Android类似,但API风格不同:
// 初始化SSL
RTCDefaultSSLAdapter.initializeSSL()
// 创建工厂
let factory = RTCPeerConnectionFactory()
// 创建连接
let config = RTCConfiguration()
config.iceServers = [RTCIceServer(urlStrings: ["stun:stun.l.google.com:19302"])]
config.sdpSemantics = .unifiedPlan
let connection = factory.peerConnection(with: config, constraints: constraints, delegate: self)
我个人习惯用Swift写iOS端,但如果你维护的是老项目,Objective-C也完全没问题。WebRTC的Objective-C接口设计得挺清晰的。
NSCameraUsageDescription和NSMicrophoneUsageDescription。否则一启动就闪退,用户体验极差。
移动端适配与性能优化
移动端跟PC最大的区别是什么?资源有限。CPU、内存、电池,样样都得省着用。
1. 硬件编码器与解码器
Android和iOS都支持硬件编解码。但Android碎片化严重,不同厂商的硬件编码器质量参差不齐。我建议:
- 优先使用硬件编码,省电且发热低
- 如果硬件编码质量不行,回退到软件编码
- iOS端硬件编码质量普遍较好,可以放心用
代码里怎么控制?很简单:
// Android端启用硬件编码
PeerConnectionFactory.builder()
.setVideoEncoderFactory(new DefaultVideoEncoderFactory(
rootEglBase.getEglBaseContext(),
true, // 启用硬件编码
true // 启用硬件解码
))
.createPeerConnectionFactory();
2. 分辨率与码率自适应
移动端网络环境变化大。WiFi切4G、地铁隧道、电梯里...信号说断就断。我建议开启WebRTC的带宽估计和码率自适应:
// 设置码率范围
MediaConstraints constraints = new MediaConstraints();
constraints.mandatory.add(
new MediaConstraints.KeyValuePair("minBitrate", "100000") // 100kbps
);
constraints.mandatory.add(
new MediaConstraints.KeyValuePair("maxBitrate", "2000000") // 2Mbps
);
说白了,就是让WebRTC自己根据网络状况调整码率。你只需要设个范围,剩下的交给它。
3. 屏幕适配
Android屏幕千奇百怪,刘海屏、挖孔屏、瀑布屏...渲染视频时要注意:
- 使用
SurfaceViewRenderer而不是TextureViewRenderer,性能更好 - 设置
setScalingType为SCALE_ASPECT_FILL或SCALE_ASPECT_FIT - 注意安全区域,别让视频被刘海挡住
RTCMTLVideoView,它基于Metal,性能比OpenGL好不少。Android端也有对应的SurfaceViewRenderer,记得开启硬件加速。
Native与Web互通
这是整个课程的核心。Native端和Web端能不能打通?能。但有几个关键点必须一致。
1. SDP格式统一
Web端默认用UNIFIED_PLAN,Native端也必须用这个。否则SDP解析会失败。
// Android端
config.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;
// Web端(JavaScript)
const config = { sdpSemantics: 'unified-plan' };
2. 编解码器协商
Web端通常支持H.264和VP8/VP9。Native端建议也支持这些。我遇到过一个问题:Android端默认只开了VP8,Web端只支持H.264,结果两边协商失败,画面出不来。
解决办法:手动指定编解码器优先级。
// Android端设置H.264优先
List<PeerConnection.IceServer> codecs = new ArrayList<>();
// 把H.264放在前面
codecs.add(PeerConnection.IceServer.builder("H264").createIceServer());
3. 信令协议一致
Web端和Native端必须用同一套信令协议。我习惯用JSON格式,简单明了:
// 信令消息格式
{
"type": "offer", // offer | answer | candidate
"sdp": "v=0\r\n...", // SDP内容
"candidate": "" // ICE候选
}
Web端用WebSocket,Native端也用WebSocket。两边解析逻辑保持一致就行。
知识体系总览
下面这张图总结了移动端WebRTC的核心流程:
性能优化实战清单
| 优化项 | Android | iOS | 说明 |
|---|---|---|---|
| 硬件编码 | DefaultVideoEncoderFactory | RTCVideoEncoderFactoryH264 | 优先使用,省电省CPU |
| 渲染器 | SurfaceViewRenderer | RTCMTLVideoView | 性能优于TextureView/OpenGL |
| 码率自适应 | minBitrate/maxBitrate | RTCMediaConstraints | 根据网络动态调整 |
| 分辨率 | 640x480(默认) | 640x480(默认) | 根据场景调整,视频通话建议720p |
| ICE服务器 | STUN+TURN | STUN+TURN | 生产环境必须配TURN |
最后说一句:移动端调试比PC端麻烦得多。我习惯用adb logcat抓Android日志,用Xcode控制台看iOS日志。遇到问题别慌,先看日志,八成能找到线索。