You need to enable JavaScript to run this app.
导航

Android 集成常见问题

最近更新时间2024.04.22 17:52:24

首次发布时间2023.10.07 18:05:49

集成 RTC SDK 时因 Failed resolution of: Landroid/support/v4/content/ContextCompat; 崩溃

RTC SDK 对 support/v4 有依赖,是较早的版本,早于 Android X。如果你的工程通过 android.useAndroidX=true 配置,标记 APP 强制使用 AndroidX,那么,可能会导致编译不通过,并有以上报错。

解决方案:在项目根目录的 gradle.properties 文件中添加 android.enableJetifier=true

如何进行混淆配置?

自较早的版本开始,RTC SDK 中都在根目录下,包含名为 proguard-rules.pro 的混淆配置文件。你的 App 集成 RTC SDK 打包时,会自动将此混淆配置加入 App 的混淆配置中。你无需为 RTC SDK 的混淆配置专门添加规则。

对于更早的版本(3.30 及以前),RTC 强烈建议你升级到最新版本。如果您需要混淆配置方面的详细信息,请咨询技术支持。

前台服务权限适配方法

如果你的应用以 Android 11(API 级别 30)或更高版本为目标平台,且希望在应用退到后台时仍能进行音视频采集,则需启动一个前台服务。
以下说明以麦克风权限为例,摄像头权限同理,具体字段参看前台服务类型

  1. AndroidManifest.xml 文件中声明前台服务类型。

    <service
        android:name="<service dir>.<service file name>"
        android:foregroundServiceType="microphone"
        tools:node="merge" />
    
    • 如果你的应用以 Android 13(API 级别 33)或更高版本为目标平台,你需要为前台服务绑定一个 Notification,否则,通知栏将无法弹出,前台服务启动失败。需要额外申请 android.permission.POST_NOTIFICATION 权限。
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    
    • 如果你的应用以 Android 14(API 级别 34)或更高版本为目标平台,则必须针对前台服务将要执行的工作类型请求适当的权限类型。每种前台服务类型都有对应的权限类型,以麦克风为例,需要额外申请 FOREGROUND_SERVICE_MICROPHONE 权限。
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"/>
    
  2. 继承系统服务,并重载相关的函数,实现服务的启动和停止。

    package com.ss.demo.service;
    
    import android.app.Notification;
    import android.app.NotificationChannel;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.app.Service;
    import android.content.Intent;
    import android.content.pm.ServiceInfo;
    import android.os.Build;
    import android.os.IBinder;
    import android.support.annotation.Nullable;
    import android.support.v4.app.NotificationCompat;
    
    import com.ss.video.rtc.demo.ui.chat.ChatActivity;
    
    public class RoomKeepLifeService extends Service {
        public static final String CHANNEL_ID = "RoomKeepLifeServiceChannel";
        private static final String COMMAND = "command";
        private static final String COMMAND_START = "start";
        private static final String COMMAND_STOP = "stop";
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            startAsForeground(new Intent());
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            if(intent != null){
                switch (intent.getStringExtra(COMMAND)){
                    case COMMAND_START:
                        startAsForeground(intent);
                        break;
                    case COMMAND_STOP:
                        stopInternal();
                        break;
                    default:
                        break;
                }
            }
    
            return super.onStartCommand(intent, flags, startId);
        }
    
        public void stopInternal() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                stopForeground(true);
                stopSelf();
            }
        }
    
        private void startAsForeground(Intent intent) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                createNotificationChannel();
                Intent notificationIntent = new Intent(this, ChatActivity.class);
                PendingIntent pendingIntent = PendingIntent.getActivity(this,
                        0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
    
                Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                        .setContentTitle("房间正在进行中...")
                        .setSmallIcon(com.ss.video.rtc.common.R.drawable.icon_default_avatar)
                        .setContentIntent(pendingIntent)
                        .setShowWhen(false)
                        .build();
    
                startForeground(110, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
            }
        }
    
        private void createNotificationChannel() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                NotificationChannel serviceChannel = new NotificationChannel(
                        CHANNEL_ID,
                        "Foreground Service Channel",
                        NotificationManager.IMPORTANCE_DEFAULT
                );
    
                NotificationManager manager = getSystemService(NotificationManager.class);
                if (manager != null) {
                    manager.createNotificationChannel(serviceChannel);
                }
            }
        }
    }
    
  3. 在适当的位置调用服务启动和停止。以进房启动,退房停止为例:

    public void joinRoom() {
        // -- 启动服务 -- //
        startRoomKeepLifeService();
        
        // -- 进房相关操作 -- //
        // ...
    }
    
    public void leaveRoom() {
        // -- 退房相关操作 -- //
        // ...
        
        // -- 停止服务 -- //
        stopRoomKeepLifeService();
    }
    
    private void startRoomKeepLifeService() {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
            Intent serviceIntent = new Intent(EnvUtilities.getAppContext(), RoomKeepLifeService.class);
            serviceIntent.putExtra("command", "start");
            ContextCompat.startForegroundService(EnvUtilities.getAppContext(), serviceIntent);
        }
    }
    
    private void stopRoomKeepLifeService(){
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            Intent serviceIntent = new Intent(EnvUtilities.getAppContext(), RoomKeepLifeService.class);
            serviceIntent.putExtra("command", "stop");
            ContextCompat.startForegroundService(EnvUtilities.getAppContext(), serviceIntent);
        }
    }
    

应用的 targetSDKVersion >= 31 时如何配置蓝牙权限?

  1. AndroidManifest.xml 文件中配置应用所需的权限。

    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    
  2. 在 Activity 中动态申请 BLUETOOTH_CONNECT 权限。参考以下代码进行申请:

    private static final int PERMISSION_REQ_ID_RECORD_AUDIO = 22;// 可以任意值
    private static final int PERMISSION_REQ_ID_CAMERA = PERMISSION_REQ_ID_RECORD_AUDIO + 1;
    private static final int PERMISSION_REQ_ID_BLUETOOTH_CONNECT = PERMISSION_REQ_ID_CAMERA + 1;
    
    // Check necessary permissions granted and
    // if the permissions are not granted, use the built-in Android feature to request them.
    private boolean checkSelfPermissions() {
        return  checkSelfPermission(Manifest.permission.RECORD_AUDIO, PERMISSION_REQ_ID_RECORD_AUDIO) &&
                checkSelfPermission(Manifest.permission.CAMERA, PERMISSION_REQ_ID_CAMERA) &&
                // If targetSDKVersion >= 31 and want to use bluetooth headset, need request permission.
                checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT, PERMISSION_REQ_ID_BLUETOOTH_CONNECT);
    }
    
    public boolean checkSelfPermission(String permission, int requestCode) {
        if (PermissionChecker.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
            return false;
        }
        return true;
    }
    

如何在华为手机使用硬件耳返功能?

说明

  • 如果你需要使用华为硬件耳返功能,建议通过 Maven 集成 RTC SDK。通过 Maven 集成 RTC SDK 不需要手动添加耳返依赖。
  • 建议预先判断当前手机和耳机是否支持系统耳返功能。
  1. 在项目根目录的 settings.gradle 文件配置 Maven 仓库地址。

    dependencyResolutionManagement {
        repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            ...
            maven { url "https://developer.huawei.com/repo/" }
        }
    }
    

    说明

    如果你的 Android Gradle Plugin 版本低于 v7.1.0,则应在项目根目录的 build.gradle 文件配置 Maven 仓库地址。

    allprojects {
        repositories {
            ...
            maven { url "https://developer.huawei.com/repo/"}
            ...
        }
    }
    
  2. 在 App 的 build.gradle 文件中添加 audiokit 和 gson 依赖。

    dependencies {
        ...
        implementation "com.huawei.multimedia:audiokit:1.0.3"
        ...
        }
    

使用模拟器调试时出现花屏

推荐使用真机调试,模拟器出现花屏可能是摄像头设置有误或未开放当前设备的摄像头权限。

  • 使用 Mac 开发并设置模拟器摄像头为设备摄像头后,需要重启电脑以使设置生效。
  • 运行模拟器时,在弹窗中需允许模拟器使用摄像头。

OpenCL 库 Android 12 适配说明

安卓平台上,RTC 视频超分、视频降噪、暗光增强等视频处理特性在 GPU 上的正常运行依赖厂商提供的 OpenCL 库。根据 Android 开发者指南对 Android 12 的行为变更说明,当应用升级目标平台为 Android 12(targetSdkVersion>=31) 及以上版本后,app 访问设备厂商提供的本地库时,必须使用应用清单 (AndroidManifest.xml) 中的 <uses-native-library> 标记指明其依赖,以免出现帧率下降、视频暗光增强功能无法开启等异常。你可以参考此文档进行适配操作。

适用条件

  • 应用以 Android 12(targetSdkVersion>=31) 及以上版本为目标平台;
  • 使用到视频超分、视频降噪、视频暗光增强等依赖 OpenCL 库的特性,或者对视频渲染帧率有较高要求。

适配步骤

  1. 升级 Android app 的Android Gradle Plugin 版本到 4.2.0+,确保构建工具链支持 <uses-native-library> 标记。

  2. 在应用 AndroidManifest.xml 文件的 <application> 标签下加入 <uses-native-library> 标记,声明以下 OpenCL 相关本地库的白名单(详情参考 Android 开发者指南):

    <application>
    <uses-native-library
        android:name="libOpenCL.so"
        android:required="false"/>
    <uses-native-library
        android:name="libGLES_mali.so"
        android:required="false"/>
    <uses-native-library
        android:name="libmali.so"
        android:required="false"/>
    <uses-native-library
        android:name="libPVROCL.so"
        android:required="false"/>
    <uses-native-library
        android:name="libpocl.so"
        android:required="false"/>
    </application>