React Native直播新纪元:Pili Streaming Cloud SDK全功能探索
# React Native 直播新纪元:Pili Streaming Cloud SDK 全功能探索
随着移动直播需求的爆炸式增长,选择一款可靠、高性能的直播 SDK 至关重要。本文围绕 **Pili Streaming Cloud SDK** 在 React Native 中的完整集成与使用展开,内容包含环境配置、原生模块封装、示例代码、ASCII 图解与详细说明,帮助你更快上手并掌握直播推流与拉流的全流程。
---
## 一、前言与概览
Pili(七牛云)直播云服务提供强大的云端推流、CDN 分发与点播回看功能,官方发布了 Android、iOS 原生 SDK,并对 React Native 也提供了社区维护的封装包。本文示例基于:
- **React Native ≥ 0.65**
- **Pili Streaming Cloud SDK v2**(2025 年最新版)
- **社区封装库**:`react-native-pili`(适配 Pili SDK v2.x)
我们将分步讲解:
1. **环境准备与依赖安装**
2. **Android / iOS 原生配置**
3. **React Native 模块封装与引入**
4. **推流(Publisher)示例**
5. **拉流(Player)示例**
6. **进阶功能:连麦、切换摄像头、水印、音视频参数**
7. **ASCII 图解:直播数据流动示意**
8. **常见问题与最佳实践**
---
## 二、环境准备与依赖安装
### 2.1 创建基础 React Native 项目
```bash
# 全局安装 React Native CLI(若未安装)
npm install -g react-native-cli
# 创建项目
react-native init PiliLiveDemo
cd PiliLiveDemo
确保本地环境已经满足 React Native 官方文档的要求(Android Studio、Xcode、Node.js 等)。
2.2 安装 Pili React Native 封装包
社区封装的库名为 react-native-pili
,同时需要安装对应的原生 SDK:
# 安装 React-Native Pili 封装
yarn add react-native-pili
# 或者
# npm install react-native-pili --save
该包会自动在 podspec
中拉取 iOS 原生依赖,并在 Android build.gradle
中引入 Pili SDK。如果遇到版本冲突,请参考文档手动对齐。
三、Android / iOS 原生配置
不同平台需做少量原生配置,保证 SDK 能正常工作。
3.1 iOS 配置
Podfile 添加引入
react-native-pili
会在PiliReactNative.podspec
中声明依赖,但我们要确保最低 iOS 版本匹配:platform :ios, '11.0' target 'PiliLiveDemo' do use_frameworks! pod 'PiliReactNative', :path => '../node_modules/react-native-pili' # ... 其他 pods end
Info.plist 权限
为了使用摄像头与麦克风,需在Info.plist
中添加:<key>NSCameraUsageDescription</key> <string>App 需要访问相机用于直播推流</string> <key>NSMicrophoneUsageDescription</key> <string>App 需要访问麦克风用于直播收音</string> <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key><true/> </dict>
Pod 安装与编译
cd ios pod install cd .. react-native run-ios
注意:如果启动时遇到
Undefined symbols for architecture arm64
,请检查PiliReactNative
与 Xcode Build Settings 中的Excluded Architectures
配置。
3.2 Android 配置
在
android/app/build.gradle
中添加依赖react-native-pili
已加入自动链接,但如需手动,则:dependencies { implementation project(':react-native-pili') // 或者直接引入 Pili SDK implementation 'cn.pili:pili-rtmp-sdk:2.5.0' implementation 'cn.pili:pili-rtc-sdk:2.0.1' }
添加摄像头/录音权限
在android/app/src/main/AndroidManifest.xml
中:<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
导入 React-Pili 包
在settings.gradle
中:include ':react-native-pili' project(':react-native-pili').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-pili/android')
在
MainApplication.java
中:import com.pili.rn.PiliReactPackage; // 根据封装包实际命名 @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new PiliReactPackage() // ...其他包 ); }
Gradle 同步与编译
cd android ./gradlew clean ./gradlew assembleDebug cd .. react-native run-android
至此,基础环境与原生配置已完成,下面开始在 JS 侧进行直播推流与拉流示例。
四、推流(Publisher)示例
本文推流示例分为以下几步:
- 界面布局与权限申请
- 创建推流链接与 Stream Key
- 初始化推流组件并开启预览
- 开始/停止推流
- 切换摄像头、麦克风静音等功能
4.1 界面布局与权限申请
在 React Native 中,为了调用摄像头与麦克风,需要先动态申请权限(Android 与 iOS 差异不大,示例以 Android 为主)。
// src/PublisherScreen.js
import React, { useEffect, useRef, useState } from 'react';
import {
View,
Text,
Button,
StyleSheet,
PermissionsAndroid,
Platform,
Alert,
} from 'react-native';
import { PiliPlayerView, PiliPublisher } from 'react-native-pili'; // 示例命名
export default function PublisherScreen() {
const publisherRef = useRef(null);
const [hasPermission, setHasPermission] = useState(false);
const [isStreaming, setIsStreaming] = useState(false);
// 申请权限
const requestPermissions = async () => {
if (Platform.OS === 'android') {
try {
const granted = await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.CAMERA,
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
]);
const cameraOK = granted[PermissionsAndroid.PERMISSIONS.CAMERA] === PermissionsAndroid.RESULTS.GRANTED;
const audioOK = granted[PermissionsAndroid.PERMISSIONS.RECORD_AUDIO] === PermissionsAndroid.RESULTS.GRANTED;
if (cameraOK && audioOK) {
setHasPermission(true);
} else {
Alert.alert('权限不足', '请在设置中开启相机和麦克风权限');
}
} catch (err) {
console.warn(err);
}
} else {
setHasPermission(true);
}
};
useEffect(() => {
requestPermissions();
}, []);
// 流地址与推流 key
const publishUrl = 'rtmp://pili-publish.qiniuapi.com/myapp/';
const streamKey = 'user_stream_key_123456';
// 开始推流
const startStreaming = () => {
if (!publisherRef.current) return;
publisherRef.current.start((error) => {
if (error) {
console.error('推流失败:', error);
Alert.alert('推流失败', error.message);
} else {
setIsStreaming(true);
}
});
};
// 停止推流
const stopStreaming = () => {
if (!publisherRef.current) return;
publisherRef.current.stop();
setIsStreaming(false);
};
if (!hasPermission) {
return (
<View style={styles.center}>
<Text>正在申请摄像头与麦克风权限...</Text>
</View>
);
}
return (
<View style={styles.container}>
{/* 1. 推流预览视图 */}
<PiliPlayerView
style={styles.preview}
ref={publisherRef}
publishUrl={publishUrl + streamKey}
cameraId="front" // 默认前置
audioEnable={true}
videoEnable={true}
bitrate={800 * 1024} // 800kbps
resolution={{ width: 720, height: 1280 }}
fps={15}
/>
{/* 2. 控制按钮 */}
<View style={styles.controls}>
{!isStreaming ? (
<Button title="开始推流" onPress={startStreaming} />
) : (
<Button title="停止推流" onPress={stopStreaming} />
)}
<View style={styles.spacer} />
<Button
title="切换摄像头"
onPress={() => {
if (publisherRef.current) {
publisherRef.current.switchCamera();
}
}}
/>
<View style={styles.spacer} />
<Button
title={isStreaming ? '关闭麦克风' : '开启麦克风'}
onPress={() => {
if (publisherRef.current) {
publisherRef.current.toggleMic(!isStreaming);
}
}}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#000' },
center: { flex: 1, justifyContent: 'center', alignItems: 'center' },
preview: { flex: 1 },
controls: {
flexDirection: 'row',
justifyContent: 'space-around',
paddingVertical: 12,
backgroundColor: '#111',
},
spacer: { width: 16 },
});
4.1.1 关键说明
组件
PiliPlayerView
publishUrl
:RTMP 推流地址,形式如rtmp://{domain}/{app}/{streamKey}
,需先在 Pili 控制台创建 App 并生成 Stream Key。cameraId
:可选front
或back
,默认使用前置摄像头。bitrate
、resolution
、fps
:设置视频编码参数。
Ref 操作
- 通过
ref
拿到原生模块实例,调用start()
/stop()
/switchCamera()
等方法。 start(callback)
:启动推流,若失败通过回调返回错误信息。
- 通过
权限申请
- Android 端需动态请求
CAMERA
与RECORD_AUDIO
,否则推流会报错。 - iOS 在
Info.plist
中已声明,执行时系统会弹窗请求。
- Android 端需动态请求
4.2 推流流程图解
┌───────────────────────────────────────────────────────────────┐
│ React Native JS │
│ ┌────────────────────────┐ ┌──────────────────────────┐ │
│ │ PiliPlayerView (RN) │ │ publisherRef.start() │ │
│ │ - publishUrl: rtmp://… │────▶ 调用 Native Module │ │
│ │ - cameraId, bitrate… │ │ (PiliPublisher.start) │ │
│ └────────────────────────┘ └──────────────────────────┘ │
│ │ │ │
│ ▼ │ │
│ ┌───────────────────────────────────────────────────────┐ │ │
│ │ Android / iOS 原生层 (Pili SDK) │ │ │
│ │ ┌───────────────────────────────────────────────────┐ │ │ │
│ │ │ 摄像头采集 (Camera) / 麦克风采样 (AudioRecord) │ │ │ │
│ │ └───────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌───────────────────────────────────────────────────┐ │ │
│ │ │ 视频编码 (H.264) / 音频编码 (AAC) │ │ │
│ │ └───────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌───────────────────────────────────────────────────┐ │ │
│ │ │ RTMP 推流:Pili Cloud (CDN) │ │ │
│ │ └───────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌───────────────────────────────────────────────────┐ │ │
│ │ │ 观众端可通过拉流 URL (http://…/playlist.m3u8) 拉流 │ │ │
│ │ └───────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │ │
└───────────────────────────────────────────────────────────────┘
五、拉流(Player)示例
Pili 也提供了高效的播放组件,可直接播放 RTMP、HLS 或 FLV 格式的直播流。下面示例演示在 React Native 中使用 PiliPlayer
进行直播拉流。
// src/PlayerScreen.js
import React, { useRef, useState } from 'react';
import { View, Text, Button, StyleSheet, ActivityIndicator } from 'react-native';
import { PiliPlayer } from 'react-native-pili';
export default function PlayerScreen() {
const playerRef = useRef(null);
const [status, setStatus] = useState('IDLE');
// 播放地址,可为 RTMP / HLS / FLV
const playUrl = 'http://pili-live-example.qiniuapi.com/live/streamkey/playlist.m3u8';
// 开始拉流
const startPlay = () => {
if (!playerRef.current) return;
setStatus('LOADING');
playerRef.current.start((err) => {
if (err) {
console.error('拉流失败:', err);
setStatus('ERROR');
} else {
setStatus('PLAYING');
}
});
};
// 停止拉流
const stopPlay = () => {
if (!playerRef.current) return;
playerRef.current.stop();
setStatus('STOPPED');
};
return (
<View style={styles.container}>
{/* 1. 拉流预览视图 */}
<PiliPlayer
style={styles.player}
ref={playerRef}
url={playUrl}
autoPlay={false}
muted={false}
/>
{/* 2. 状态指示与加载指示 */}
<View style={styles.statusContainer}>
{status === 'LOADING' && <ActivityIndicator size="large" color="#fff" />}
<Text style={styles.statusText}>状态:{status}</Text>
</View>
{/* 3. 控制按钮 */}
<View style={styles.controls}>
<Button title="开始播放" onPress={startPlay} />
<View style={styles.spacer} />
<Button title="停止播放" onPress={stopPlay} />
</View>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#000' },
player: { flex: 1 },
statusContainer: {
position: 'absolute',
top: 20,
left: 20,
flexDirection: 'row',
alignItems: 'center',
},
statusText: { color: '#fff', marginLeft: 8 },
controls: {
flexDirection: 'row',
justifyContent: 'space-around',
paddingVertical: 12,
backgroundColor: '#111',
},
spacer: { width: 16 },
});
5.1 关键说明
组件
PiliPlayer
url
:拉流地址,可为 HLS(.m3u8
)、RTMP(需要硬解码)或 FLV。autoPlay
:是否自动开始拉流,设为false
提供手动控制。muted
:静音开关,适用于声音调试。
Ref 操作
playerRef.current.start(callback)
:开始拉流并回调状态。playerRef.current.stop()
:停止拉流并释放资源。
状态管理
status
用于在界面上显示当前播放器状态:IDLE
、LOADING
、PLAYING
、ERROR
、STOPPED
。
六、进阶功能:连麦、切换摄像头、水印、音视频参数
Pili SDK 支持更丰富的功能,下面简要介绍常见进阶用法。
6.1 连麦 (Mix Stream)
连麦场景需要将多个推流合并到同一路流,通常分两步:
- 后台配置:在 Pili 控制台或通过 API 创建 “合流模版” (
mix-template
),指定连麦布局(画面分区)。 - 前端推流:推流端在初始化时带上
mixStreamID
,Pili C++ SDK 会自动将推流信号与合流模板匹配。
// 连麦示例:连麦推流时带上 mixStreamID
<PiliPlayerView
ref={publisherRef}
publishUrl={publishUrl + streamKey}
mixStreamID="mix_123" // Pili 后台配置的合流 ID
// ... 其他参数不变
/>
后台合流模板可设置画中画、九宫格、拼接等多种布局。推流端只需保证 mixStreamID
与后台一致,Pili 服务会自动合并。
6.2 水印
推流端可以在画面中添加图片或文字水印,示例:
<PiliPlayerView
ref={publisherRef}
publishUrl={publishUrl + streamKey}
waterMark={{
image: 'https://your.cdn.com/watermark.png',
pos: 'top-left', // top-left / top-right / bottom-left / bottom-right
x: 20,
y: 20,
width: 80,
height: 80,
alpha: 0.8,
}}
// ... 其他推流参数
/>
参数说明:
image
:水印图片 URL 或本地资源引用(require('./wm.png')
)。pos
:四角位置,可微调x
,y
。width
/height
:水印尺寸。alpha
:透明度(0.0\~1.0)。
6.3 切换摄像头与闪光灯
推流过程中可以随时切换前后摄像头或打开闪光灯:
// 切换摄像头
publisherRef.current.switchCamera();
// 切换闪光灯
publisherRef.current.toggleTorch(true); // 打开
publisherRef.current.toggleTorch(false); // 关闭
6.4 视频参数动态调节
在推流过程中可动态修改编码参数(分辨率、比特率、帧率、GOP):
// 修改分辨率
publisherRef.current.updateVideoResolution({ width: 480, height: 640 });
// 修改比特率
publisherRef.current.updateVideoBitrate(500 * 1024); // 500kbps
// 修改帧率
publisherRef.current.updateVideoFPS(20);
// 修改关键帧间隔(GOP)
publisherRef.current.updateVideoGOP(2); // 2 秒一个关键帧
注意:动态修改参数时,需确保推流网络能稳定支撑,否则可能出现推流抖动或断流。
七、ASCII 图解:直播数据流动示意
┌─────────────────────────────────────────────────────────┐
│ React Native App │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ PublisherScreen.js (推流) │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ PiliPlayerView (RN Component) │ │ │
│ │ │ - publishUrl: rtmp://…/app/streamKey │ │ │
│ │ │ - switchCamera / toggleTorch / updateVideoXXX │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ start() 调用 ▼ │ │
│ │ (JS → Native) ┌─────────────────────────────────────┐ │ │
│ │ │ PiliPublisher (原生封装) │ │ │
│ │ │ - 摄像头采集(Camera2 / AVCapture) │ │ │
│ │ │ - 麦克风采样(AVAudioSession / AudioRec) │ │ │
│ │ │ - 视频编码(H.264) / 音频编码(AAC) │ │ │
│ │ │ - RTMP 推流(Pili RTMP 推流库) │ │ │
│ │ └─────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────────────────────────────────────┐ │ │
│ │ │ Pili 云端 CDN & 流媒体服务器 │ │ │
│ │ │ - 接收 RTMP 流,触发 Service 拉取 & 分发 │ │ │
│ │ │ - HLS 录制与 CDN 分发 │ │ │
│ │ └──────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────────────────────────────────────┐ │ │
│ │ │ 观众端拉流 (PlayerScreen.js) │ │ │
│ │ │ ┌────────────────────────────────────┐ │ │ │
│ │ │ │ PiliPlayer (RN Component) │ │ │ │
│ │ │ │ - url: http://…/streamKey/playlist.m3u8 │ │ │ │
│ │ │ │ - start() / stop() / mute() │ │ │ │
│ │ │ └────────────────────────────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ ▼ │ │
│ │ │ ┌────────────────────────────────┐ │ │
│ │ │ │ PiliPlayer (原生封装 iOS / Android) │ │ │
│ │ │ │ - HLS 解码(AVPlayer / ExoPlayer) │ │ │
│ │ │ │ - 视频渲染 (SurfaceView / UIView) │ │ │
│ │ │ └────────────────────────────────┘ │ │
│ │ └──────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
- 推流链路:RN JS 层调用
PiliPublisher
→ 原生 SDK 采集/编码 → RTMP 推送到 Pili 云。 - 拉流链路:RN JS 层调用
PiliPlayer
→ 原生播放器组件使用 HLS/RTMP 播放库解码渲染 → 画面呈现到界面。
八、常见问题与最佳实践
8.1 推流前常见调试要点
检查 RTMP 推流地址与 Stream Key
- 在 Pili 控制台创建 App、创建流并记住
Stream Key
。示例如:rtmp://pili-publish.qiniuapi.com/live/user123
。
- 在 Pili 控制台创建 App、创建流并记住
网络、时延与带宽
- 在 Wi-Fi 环境下测试时,注意带宽是否充足;在移动网络下,建议将码率控制在 500–800kbps 左右。
权限与系统兼容性
- Android 6.0+ 需动态申请摄像头与麦克风权限;iOS 端需在
Info.plist
中正确声明。
- Android 6.0+ 需动态申请摄像头与麦克风权限;iOS 端需在
测试日志输出
- Pili SDK 原生层会打印推流/拉流状态日志,需在 Android Studio 或 Xcode Console 中查看,确认是否连上服务器。
8.2 拉流时延与自动重连
拉流时可能会因为网络不稳产生卡顿或断流,建议:
- 监听网络状态:使用
NetInfo
监听网络变化,当网络恢复时自动重连。 - 播放器重连策略:在
onError
回调中尝试调用playerRef.current.start()
重连,或在短时间(如 3 秒)后重新调用。
- 监听网络状态:使用
8.3 后台推流与前台服务
在 Android 后台推流时,一旦应用进入后台,进程可能被系统杀死。若要保证后台长时间稳定推流,需要:
- 使用前台服务:配合
react-native-background-actions
启动 Foreground Service,并在通知栏显示 “正在直播中” 提示。 - 优化推流参数:背景中可适当降低分辨率与帧率,减少网络与 CPU 占用。
- 监测系统杀死事件:在
AppState
监听到background
状态时,提前将推流参数切换为“静态图像或纯音频”,避免因为长时间无画面被系统回收。
- 使用前台服务:配合
8.4 iOS 多任务(Multitasking)与后台模式
iOS 进入后台后,非音频/VoIP/导航等模式的推流会被挂起。若希望在后台也能保持某些功能,可考虑:
- 开启 Audio Background Mode:Fake 播放一个无声音轨,让系统认为正在播放音频。
- 开启 Location Background Mode:Fake 启动持续定位服务,保持应用在后台存活。
- 静默推送:当需要从后台唤醒执行推流/断流逻辑时,可发送静默推送触发。
但这些方案并不完全符合 Apple 审核要求,请谨慎评估使用场景。
九、总结
本文从 React Native 视角出发,全面讲解了如何在Pili Streaming Cloud SDK的加持下,实现高质量的直播推流与拉流功能。主要涵盖了:
- 环境与原生配置:包括 Android / iOS 原生依赖、动态权限申请。
- 推流模块(Publisher):示例代码展示推流预览、开始/停止推流、切换摄像头、水印、参数动态调整等功能点。
- 拉流模块(Player):示例代码展示播放 HLS/RTMP 流、显示加载状态、停止播放等。
- 进阶功能:连麦、合流、水印、动态视频参数、前台服务。
- ASCII 图解:直播数据流动全流程示意,从 RN JS → 原生采集编码 → Pili 云端 → 观众端解码渲染。
- 常见问题与最佳实践:推流前调试要点、后台运行限制、网络抖动优化、iOS 后台模式注意事项。
通过以上示例与说明,你已经具备了在 React Native 中集成 Pili SDK、快速搭建直播功能的能力。接下来可根据业务场景继续拓展:
- 多路拉流与画中画:在同一个页面展示多个直播流或观众互动画面。
- 连麦与 PK:使用 Pili 提供的混流功能,实现主播与主播、主播与观众连麦。
- 自定义美颜与滤镜:引入 OpenGL / Metal 自定义渲染管线,叠加美颜滤镜。
- 与 RTC 合作:结合 Pili RTC SDK,实现更低时延互动直播。
- 运营策略:封装流量监控、统计 SDK 埋点、弹幕与聊天功能。
评论已关闭