tencent cloud

云顾问-Tencent RTC 云助手

产品动态
产品简介
产品概述
产品优势
应用场景
购买指南
新手指引
场景化方案
场景化方案概述
社交娱乐
电商直播
音视频通话
远程实时操控
智能客服
AI 面试
模块化方案
模块化方案概述
网络质量监控
移动端应用保活方案
视频画中画方案
直播上下滑
跨房 PK 连麦方案
AI 对话 Chat 信令方案
常见问题
联系我们

移动端应用保活方案

PDF
聚焦模式
字号
最后更新时间: 2025-11-18 15:15:33
对于涉及音视频采集和播放的移动端应用,通常需要进行额外的保活处理,否则应用在后台运行时会受到一定的功能性限制,甚至在后台运行一段时间后被系统强制终止运行。下面我们分别介绍 Android 应用保活方案,以及 iOS 应用保活方案

Android 应用保活方案

目前 Android 端常用的保活方式是启动前台服务。前台服务是一种特殊的服务,它在运行时会显示一个持续的通知,以告知用户该服务正在运行。由于前台服务的通知是持续可见的,系统会认为这是一个高优先级的任务,应用可以在后台持续运行,而不容易被系统终止。下面介绍前台服务的实现方式及步骤。

步骤1:声明权限

在 AndroidManifest.xml 文件中添加以下权限声明。
<!-- 允许应用使用前台服务 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<!-- 如果应用需要在前台服务中使用摄像头 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />

<!-- 如果应用需要在前台服务中使用麦克风 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />

<!-- 允许前台服务发送通知 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
注意:
若您的项目设置 targetSdkVersion 34及以上,且需要在前台服务中使用摄像头和麦克风,则 FOREGROUND_SERVICE_CAMERAFOREGROUND_SERVICE_MICROPHONE 权限声明是必须的。
在 Android 13及以上,如果想让前台服务显示在通知栏上,则需要声明 POST_NOTIFICATIONS 权限。

步骤2:创建服务类

创建一个继承自 Service 的类,并在其中实现前台服务的逻辑。
public class MyForegroundService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public void onCreate() {
super.onCreate();
// 创建通知渠道
Notification notification = createNotification();
// 处理服务启动逻辑
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(1024, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
} else {
startForeground(1024, notification);
}
}

private Notification createNotification() {
String CHANNEL_ONE_ID = "CHANNEL_ONE_ID";
String CHANNEL_ONE_NAME = "CHANNEL_ONE_ID";
NotificationChannel notificationChannel;
//进行8.0的判断
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,
CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_HIGH);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setShowBadge(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (manager != null) {
manager.createNotificationChannel(notificationChannel);
}
}
// 设置点击通知栏回到应用,可选
Intent intent = new Intent(this, MainActivity.class);
ActivityOptions options = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
options = ActivityOptions.makeBasic();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
options.setPendingIntentBackgroundActivityStartMode(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
}
PendingIntent pendingIntent;
if (options != null) {
pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE, options.toBundle());
} else {
pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Notification notification = new Notification.Builder(this, CHANNEL_ONE_ID).setChannelId(CHANNEL_ONE_ID)
.setSmallIcon(R.mipmap.videocall_float_logo)
.setContentTitle("这是一个测试标题")
.setContentIntent(pendingIntent)
.setContentText("这是一个测试内容")
.build();
notification.flags |= Notification.FLAG_NO_CLEAR;
return notification;
}else {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ONE_ID)
.setSmallIcon(R.mipmap.videocall_float_logo)
.setContentTitle("这是一个测试标题")
.setContentText("这是一个测试内容")
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
return builder.build();
}
}

@Override
public void onDestroy() {
super.onDestroy();
// 停止前台服务
stopForeground(true);
}
}

步骤3:声明服务

在 AndroidManifest.xml 文件中声明服务。
<service
android:name=".MyForegroundService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="mediaPlayback|mediaProjection|microphone|camera" />
注意:
您可以通过 android:foregroundServiceType 属性指定前台服务需要使用的服务类型,以确保后台可以保持正常的服务功能。
mediaPlayback 服务用于媒体播放。
mediaProjection 服务用于媒体投影。
microphone 服务用于使用麦克风。
camera 服务用于使用摄像头。

步骤4:启动前台服务

在需要启动前台服务的地方,按需启动前台服务。
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
boolean areNotificationsEnabled = notificationManager.areNotificationsEnabled();
if (!areNotificationsEnabled) {
// 提示用户启用通知权限
Toast.makeText(this, "请启用通知权限以确保服务正常运行", Toast.LENGTH_LONG).show();
// 引导用户到设置页面
Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
startActivity(intent);
} else {
// 启动前台服务
Intent serviceIntent = new Intent(this, MyForegroundService.class);
ContextCompat.startForegroundService(this, serviceIntent);
}
注意:
为了确保前台服务能够正常运行,建议在启动前台服务之前,检查通知权限是否被禁用。如果被禁用,可以提示用户启用通知权限。

步骤5:停止前台服务

可从外部组件(例如 Activity 或 BroadcastReceiver)中停止前台服务。
// 创建服务的Intent
Intent serviceIntent = new Intent(this, MyForegroundService.class);

// 停止服务
stopService(serviceIntent);
在大部分移动设备上,针对启动前台服务的应用,用户在最近应用列表里划卡强杀,前台服务会同时终止,应用会完全停止运行。但在部分境外品牌移动设备上(例如 Google Pixel 系列和 SAMSUNG A 系列),划卡强杀后应用并不会完全停止运行,前台服务仍然处于活跃状态,这会导致用户还能够听到媒体播放
针对此类设备,可以通过实现以下两种方案,从而避免应用被强杀后仍然播放媒体声音的现象。

方案一:在服务声明中定义 stopWithTask 属性

添加 android:stopWithTask="true" 属性值,服务会在任务被移除时立即停止。
<service
android:name=".MyForegroundService"
android:enabled="true"
android:exported="false"
android:stopWithTask="true"
android:foregroundServiceType="mediaPlayback|microphone" />

方案二:在 Service 层监听 onTaskRemoved 回调

监听 onTaskRemoved,当任务被移除时,该方法会被回调,您可以在这里执行清理操作或保存数据的逻辑。
@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
// 例如在这里执行 RTC Engine 退房,避免继续进行音频采集和播放
TRTCCloud mTRTCCloud = TRTCCloud.sharedInstance(this);
mTRTCCloud.exitRoom();
}
注意:
以上两种方案任选其一即可,当设置 android:stopWithTask="true" 之后,onTaskRemoved 方法将不会被回调。

iOS 应用保活方案

苹果对应用在后台的行为有严格的限制,以保护用户的隐私和设备的电池寿命。通常可以通过启用特定的后台模式(Background Modes),从而在一定程度上实现应用保活,允许应用在后台播放音频或视频。

启用后台模式

Xcode 启用后台模式(Background Modes)的步骤如下:
1. 打开您的 Xcode 项目。
2. 选择您的项目文件(通常在项目导航器的顶部)。
3. 在项目文件中,选择您的目标(Targets)。
4. 在目标设置中,选择 Signing & Capabilities 选项卡。
5. 找到 Background Modes 选项,勾选 Audio, AirPlay, and Picture in Picture 模式。




常见问题

1. 在语音通话或直播场景中,主播将应用退至后台或锁屏,插拔耳机导致音频采集和播放无声
在 SDK 默认的音频策略下,系统音量类型处于自动切换模式,即“麦上通话,麦下媒体”。同时音量类型也会随音频路由的变化而变化,例如插入耳机音量类型会由通话音量切换至媒体音量。因此,在自动切换模式下,主播插拔耳机会导致系统音量类型的切换,此时系统需要重启音频驱动。而 iOS 系统在后台或锁屏状态下重启音频驱动有概率会失败,所以会导致音频采集和播放无声。
针对这类问题,可以通过固定系统音量类型来规避,例如指定全程通话音量或全程媒体音量。
// 指定全程通话音量
[self.trtcCloud setSystemVolumeType:TRTCSystemVolumeTypeVOIP];

// 指定全程媒体音量
[self.trtcCloud setSystemVolumeType:TRTCSystemVolumeTypeMedia];
2. 在视频通话或直播场景中,主播将应用退至后台或锁屏,远端观众拉流画面黑屏但声音正常
苹果系统严格禁止应用在后台采集视频。即使您启用了后台模式,应用在进入后台后,摄像头仍然会自动停止工作。这是为了保护用户的隐私,防止应用在未经用户同意的情况下录制视频。因此,这类场景下的视频采集问题暂时无法避免,只能实现音频的正常采集和播放。
3. 观众进房时房间内无人推流,将应用退至后台或锁屏,后续房间内有人推流也无法正常接收
iOS 应用在切换至后台之前,如果没有启动 AudioUnit 采集或播放,则很快会被挂起,且无法人为唤醒,直到切换至前台。要解决此类问题,只需要在应用切换至后台之前,保持 AudioUnit 一直运行即可(播放静音数据)。具体实现方法可参考下方示例代码。
// 进房之后启用自定义音轨
[self.trtcCloud enableMixExternalAudioFrame:NO playout:YES];

// 退房之前关闭自定义音轨
[self.trtcCloud enableMixExternalAudioFrame:NO playout:NO];

视频画中画 应用保活方案

通过视频画中画功能,可以确保应用视频始终在前台播放,同时实现应用保活。具体实现方法请参考 视频画中画方案


帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈