【保姆级教程】Android - iOS 视频互通 | 掘金技术征文

3,172 阅读14分钟

不需要任何技术背景,跟着本教程绝对不会失手,让你轻松体验做程序员的快乐。

本文选用 Agora 视频通话 SDK,在 Android 和 iOS 手机上实现一个基础的一对一视频通话。适用于零基础开发者。主要包含如下内容:

  • Android 端集成
  • iOS 端集成
  • 运行 Demo

Android App 集成

前提条件

  • Android Studio 3.0 及以上版本
  • Android SDK API Level Level ≥ 16
  • Android 4.1 及以上版本的移动设备
  • 一个 Agora 的项目 App ID

请使用真机运行项目。模拟机可能会因为功能缺失而无法运行。

创建项目

如果你已经有一个 Android 项目,可以跳过该章节,直接阅读下文的集成 SDK。

  1. 打开 Android Studio,点击 Start a new Android Studio project
  2. Choose your project 页面,选择 Phone and Tablet > Empty Activity,然后点击 Next
  3. Configure your project 页面,依次填入:
    • Name:所创建项目的名称,如 HelloAgora
    • Package name:项目包的名称,如 io.agora.helloagora
    • Project location:项目在本地的保存路径
    • Language:项目使用的语言,如 Java
    • Minimum API level:项目使用的 Android API 等级

然后点击 Finish

Android Studio 会花一段时间进行配置,如果有提示需要安装插件,根据屏幕提示下载即可。

在工作的电脑上,连接 Android 手机或平板。点击右上方的 Sync 按钮,提示 Build: completed successdully 表示编译成功后,点击右上方的 Run app 图标。

等待一段时间后,Android 手机或平板上会弹出一个是否安装应用程序的弹框。同意后,手机上就会安装上一个名为 HelloAgora 的应用。恭喜你,成功创建了第一个 App!

集成 Agora SDK 到项目中

  1. 下载并解压 SDK。从声网开发者中心下载最新版的 Android 视频通话/视频直播 SDK

    其中,libs 文件夹中包含 jar 文件和 so 文件夹。samples 文件夹中包含一对一视频通话和互动直播的代码示例程序。

  2. 拷贝 SDK 文件到项目目录。在项目文件夹的 app/src/main 路径下,创建一个 jniLibs 文件夹。然后将 SDK 包中的 arm64-v8aarmeabi-v7ax86 文件拷贝到 jniLibs 文件夹下。

  3. 导入 jar 包。将 SDK 包中的 agora-rtc-sdk.jar 文件拷贝到你项目文件夹的 app/libs 路径下。

  4. 同步 SDK。在 Android Studio 中,将项目的页面视图切换为 Project 模式。点击右上角的 Sync Project with Gradle Files 按钮。确认 app/build.gradle 文件中有如下行,完成集成。

    implementation fileTree(dir: 'libs', include: ['*.jar'])
    

添加项目权限

/app/src/main/AndroidManifest.xml 文件中,将 package 的名字改为你自己项目包的名字,然后添加如下 <uses-permission... /> 行,增加设备权限:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- If the app uses Bluetooth, please add Bluetooth permissions.-->
<uses-permission android:name="android.permission.BLUETOOTH" />

防止代码混淆

app 模块下的 proguard-rules.pro 文件中,添加如下行,防止代码混淆:

-keep class io.agora.**{*;}

到这里,你就将 Agora 视频通话/视频直播 SDK 集成到你的项目中,并完成了开发环境准备。

创建 UI

想象你和朋友正在一对一视频通话。这个视频通话的界面上会有以下元素:本地视频画面(你)、远端视频画面(你朋友)、能退出频道的按钮。下面我们就使用 Android Studio 在新建的项目中创建这些 UI 元素吧。

  1. 设置通话界面布局

    在项目的 /app/src/main/res/layout/activity_main.xml 文件里,参考如下代码,依次设置本地及远端视窗的位置、尺寸;通话界面提示文字;通话界面上结束按钮的位置等。

    <?xml version="1.0" encoding="UTF-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activity_video_chat_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
     
        <FrameLayout
            android:id="@+id/remote_video_view_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/white" />
     
        <FrameLayout
            android:id="@+id/local_video_view_container"
            android:layout_width="160dp"
            android:layout_height="284dp"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:layout_marginEnd="16dp"
            android:layout_marginRight="16dp"
            android:layout_marginTop="16dp"
            android:background="@android:color/darker_gray" />
     
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="16dp"
            android:orientation="vertical">
     
            <TextView
                android:id="@+id/quick_tips_when_use_agora_sdk"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="40dp"
                android:layout_marginLeft="16dp"
                android:layout_marginStart="16dp"
                android:gravity="center_vertical|start"
                android:text="1. Default channel name is demoChannel1\n2. Waiting for remote users\n3. This demo only supports 1v1 video calling" />
     
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:orientation="horizontal">
     
     
                <ImageView
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="20"
                    android:onClick="onEndCallClicked"
                    android:scaleType="centerInside"
                    android:src="@drawable/btn_end_call" />
     
            </LinearLayout>
     
        </LinearLayout>
     
    </RelativeLayout>
    
  2. 获取通话结束按钮

    为方便起见,我们直接使用代码示例程序的 UI 元素和设计。将 Demo 中的 /app/src/main/res/drawable-xxxdpi/ 路径下的 btn_end_call.png 复制黏贴至项目的 /app/src/main/res/drawable/ 路径下。

  3. 查看并更新通话界面

    activity_main.xml 页面,点击切换到 Design 页签,实时查看或更新设置的通话视窗布局。

    到这里,一个简单的通话界面就创建好了。

调用核心 API 实现视频通话

视频通话场景的 API 调用流程如下图所示。在实际开发中,你还需要配合 Android 的原生 API 来实现视频通话。如果你对 Android 原生 API 不熟悉,也可以直接参考下文中的完整代码进行调用。

  1. 导入头文件

    在项目的 app/src/main/java/MainActivity 文件中,package io.agora.helloagora 行的下方,黏贴如下行,导入相应的 SDK 头文件:

    import io.agora.rtc.IRtcEngineEventHandler;
    import io.agora.rtc.RtcEngine;
    import io.agora.rtc.video.VideoCanvas;
     
    import io.agora.rtc.video.VideoEncoderConfiguration;
    
  2. 初始化 SDK

    在初始化过程中调用 create 方法获取一个 RtcEngine 实例。

    • 在 /app/src/main/res/values/string.xml 文件中,添加 <string name="agora_app_id">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</string> 行,并填入你所获取到的 App ID。
    • 指定 RtcEngine 的事件回调,用以通知 SDK 在运行过程中发生的事件。
    private RtcEngine mRtcEngine;
     
     
    private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
        @Override
        public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    setupRemoteVideo(uid);
                }
            });
        }
    };
     
    ...
     
     
    private void initializeAgoraEngine() {
        try {
            mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler);
        } catch (Exception e) {
            throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e));
        }
    }
    
  3. 设置视频属性

    由于 Agora Video SDK 中默认不开始视频模块,因此设置视频属性包含 2 个步骤:

    • 调用 enableVideo 开启视频模式
    • 通过 setVideoEncoderConfiguration 方法设置本地视频的编码属性
    
    private void setupVideoProfile() {
        mRtcEngine.enableVideo();
     
        mRtcEngine.setVideoEncoderConfiguration(new VideoEncoderConfiguration(VideoEncoderConfiguration.VD_640x360, VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_15,
                VideoEncoderConfiguration.STANDARD_BITRATE,
                VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT));
    }
    
  4. 设置本地视图

    本地视图,指本地用户在通话界面上看到的本地的视频画面。调用 setupLocalVideo 方法设置本地看到的视频。该方法为本地视频流创建一个 View 对象,并:

    • setZOrderMediaOverlay 设为 true,表示新增一个图层
    • 将该视频图层与通话界面布局 /app/src/main/res/layout/activity_main.xml 文件中的 local_video_view_container 进行绑定
    
    private void setupLocalVideo() {
        FrameLayout container = (FrameLayout) findViewById(R.id.local_video_view_container);
        SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());
        surfaceView.setZOrderMediaOverlay(true);
        container.addView(surfaceView);
        mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, 0));
    }
    
  5. 加入频道

    调用 joinChannel 方法加入视频通话频道。你需要在该方法中传入想要加入的频道名称。App ID 和 Channel Name 均相同的用户可以加入同一个频道进行通话。

    private void joinChannel() {
        mRtcEngine.joinChannel(null, "demoChannel1", "Extra Optional Data", 0); 
    }
    
  6. 设置远端视图

    远端视频,只本地用户在通话界面上看到的远端用户的视频画面。该方法创建一个新的图层,同时将该视频图层与通话界面布局 /app/src/main/res/layout/activity_main.xml 文件中的 remote_video_view_container 进行绑定。

    private void setupRemoteVideo(int uid) {
        FrameLayout container = (FrameLayout) findViewById(R.id.remote_video_view_container);
     
        if (container.getChildCount() >= 1) {
            return;
        }
     
        SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());
        container.addView(surfaceView);
        mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, uid));
     
        surfaceView.setTag(uid); // for mark purpose
        View tipMsg = findViewById(R.id.quick_tips_when_use_agora_sdk); // optional UI
        tipMsg.setVisibility(View.GONE);
    }
    
  7. 离开频道

    调用 leaveChannel 方法离开当前频道。

    private void leaveChannel() {
        mRtcEngine.leaveChannel();
    }
    

完整代码

以上为 Agora 核心 API 的代码示例。你还需要为退出频道的按钮设置一个离开该页面的方法,并在 onCreate 和 onDestroy 中调用上述 API。如下展示的是完整的代码示例:

package io.agora.helloagora;
 
import android.support.v4.view.PagerTitleStrip;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
 
import io.agora.rtc.IRtcEngineEventHandler;
import io.agora.rtc.RtcEngine;
import io.agora.rtc.video.VideoCanvas;
 
import io.agora.rtc.video.VideoEncoderConfiguration;
 
public class MainActivity extends AppCompatActivity {
 
    private RtcEngine mRtcEngine;
 
    private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
        @Override
        public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    setupRemoteVideo(uid);
                }
            });
        }
    };
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initializeAgoraEngine();
        setupVideoProfile();
        setupLocalVideo();
        joinChannel();
    }
 
    protected void onDestroy() {
        super.onDestroy();
 
        leaveChannel();
        RtcEngine.destroy();
        mRtcEngine = null;
 
    }
 
    public void onEndCallClicked(View view) {
        finish();
    }
 
    private void initializeAgoraEngine() {
        try {
            mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler);
        } catch (Exception e) {
            throw new RuntimeException("NEED to check rtc sdk init fatal error\n" + Log.getStackTraceString(e));
        }
    }
 
 
    private void setupVideoProfile() {
        mRtcEngine.enableVideo();
 
        mRtcEngine.setVideoEncoderConfiguration(new VideoEncoderConfiguration(
                VideoEncoderConfiguration.VD_640x360,
                VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_15,
                VideoEncoderConfiguration.STANDARD_BITRATE,
                VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_ADAPTIVE));
    }
 
    private void setupLocalVideo() {
        FrameLayout container = (FrameLayout) findViewById(R.id.local_video_view_container);
        SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());
        surfaceView.setZOrderMediaOverlay(true);
        container.addView(surfaceView);
        mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, 0));
    }
 
    private void joinChannel() {
        mRtcEngine.joinChannel(null, "demoChannel1", "Extra Optional Data", 0);
    }
 
    private void setupRemoteVideo(int uid) {
        FrameLayout container = (FrameLayout) findViewById(R.id.remote_video_view_container);
 
        if (container.getChildCount() >= 1) {
            return;
        }
 
        SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());
        container.addView(surfaceView);
        mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView,  VideoCanvas.RENDER_MODE_FIT, uid));
 
        surfaceView.setTag(uid);
        View tipMsg = findViewById(R.id.quick_tips_when_use_agora_sdk);
        tipMsg.setVisibility(View.GONE);
 
    }
 
    private void leaveChannel() {
        mRtcEngine.leaveChannel();
    }
 
 
}

至此,Android App 就配置好了。点击右上角的 Sync Project with Gradle Files 按钮重新进行同步。

iOS App 集成

前提条件

  • Xcode 9.0+。
  • iOS 8.0+ 真机(iPhone 或 iPad)。
  • 一个有效的 Agora 开发者账号(免费注册)。
  • 请确保你的项目已设置有效的开发者签名。

请使用真机运行项目。模拟机可能会因为功能缺失而无法运行。

创建项目

  1. 打开 Xcode,新建一个项目。

  2. 选择 Single View App 模板,点击 Next

  3. 填入你的项目名称,公司名称等信息,选择开发团队与开发语言,点击 Next

    如果你没有添加过开发团队信息,会看到 Add account… 按钮。点击该按钮并按照屏幕提示登入 Apple ID,完成后即可选择你的账户作为开发团队。

  4. 选择你的项目所要存放的位置,点击 Create

设置开发者签名

如果你已经设置过开发者签名,可跳过该节。

将你的 iOS 设备连接至电脑。选中当前项目 Target ,在 General 标签页上找到 Signing,勾选 Automatically manage signing,在弹窗中点击 Enable Automatic

等待片刻,你会看到如下状态,说明你已经设置好了开发者签名。

至此,你已经完成了项目的创建。接下来,让我们把 Agora SDK 包添加到这个项目中。

集成 Agora SDK 到项目中

有两种方式将 Agora SDK 添加到你的项目中:

  • 自动添加库:该方法无需下载 Agora SDK,直接使用 CocoaPods 将 SDK 库添加到项目中。
  • 手动添加库:该方法需要下载 Agora SDK,并手动将 SDK 的库添加到项目中。

自动添加库

开始前请确保你已安装 Cocoapods。参考 Cocoapods Getting Started 了解安装方法。

  1. 在 Terminal 里进入项目根目录,然后输入以下命令。项目路径下会生成一个 Podfile 文本文件。

    pod init
    
  2. 打开 Podfile 文件,修改文件为如下内容。注意将 Your App 替换为你的 Target 名称。

    platform :ios, '9.0'
    use_frameworks!
    
    target 'Your App' do
    	pod 'AgoraRtcEngine_iOS'
    end
    
  3. 在 Terminal 内输入以下命令更新本地库版本:

    pod update
    
  4. 在 Terminal 内输入以下命令安装 Agora SDK:

    pod install
    

    如果 Terminal 显示 Pod installation complete!,则表示自动添加库已完成。此时项目文件夹中会生成一一个 xcworkspace 文件。关闭当前打开的项目,双击打开新生成的 xcworkspace 文件。

手动添加库

  1. 下载 Agora Video SDK for iOS ,解压后将 libs 文件夹内的 AgoraRtcEngineKit.framework 文件复制到你的项目文件夹内。

  2. 使用 Xcode 打开你的项目,然后选中当前 Target。

  3. 打开 Build Phases 页面,展开 Link Binary with Libraries 项并添加如下库。点击 + 图标开始添加。

    ../_images/ios_video_3.jpg
    • AgoraRtcEngineKit.framework
    • Accelerate.framework
    • AudioToolbox.framework
    • AVFoundation.framework
    • CoreMedia.framework
    • CoreML.framework
    • CoreTelephony.framework
    • libc++.tbd
    • libresolv.tbd
    • SystemConfiguration.framework
    • VideoToolbox.framework

    其中,AgoraRtcEngineKit.framework 位于你的项目文件夹下。因此点击 + 后,还需要点击 Add Other… ,然后进入你的项目所在目录,选中这个文件并点击 Open

添加媒体设备权限

使用 Agora SDK 前,需要对设备的麦克风和摄像头进行授权。打开 info.plist ,点击 + 图标开始添加:

  • Privacy - Microphone Usage Description,并填入使用麦克风的目的,例如:Video Call
  • Privacy - Camera Usage Description,并填入使用摄像头的目的,例如:Video Call
../_images/ios_video_7.jpg

访问库

打开 ViewController.swift 文件,在 import UIKit 下一行填入下面的代码。

import AgoraRtcEngineKit

如果填入 import 代码后提示找不到文件,可以尝试在 Build Settings 页面 Framework search paths 设置中添加 $(SRCROOT)

现在,我们已经将 Agora SDK 集成到项目中了。

创建 UI

与安卓相似,视频通话需要创建一些基本的 UI 元素:本地视频画面(你)、远端视频画面(你朋友)、能退出频道的按钮。下面我们就在新建的项目中创建这些 UI 元素,顺便将需要用到的方法和变量写好。

ViewController.swift 文件中,用以下代码替代 import 行下面的内容:

class ViewController: UIViewController, AgoraRtcEngineDelegate {

    var agoraKit: AgoraRtcEngineKit!
    var localVideo: UIView!
    var remoteVideo: UIView!
    var leaveButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        initView()
        initAgora()
        setupVideo()
        setupLocalVideo()
        joinChannel()
    }
    
    func initView() {
        // 设置远端视频画面
        remoteVideo = UIView(frame: self.view.bounds)
        self.view.addSubview(remoteVideo)
        
        // 设置本地视频画面
        localVideo = UIView(frame: CGRect(x: self.view.bounds.width - 90, y: 0, width: 90, height: 160))
        self.view.addSubview(localVideo)
        
        // 设置离开按钮
        leaveButton = UIButton(type: .custom)
        leaveButton.setTitleColor(UIColor.red, for: .normal)
        leaveButton.frame = CGRect(x: self.view.bounds.width / 2 - 50, y: self.view.bounds.height - 50, width: 100, height: 20)
        leaveButton.setTitle("Leave", for: .normal)
        leaveButton.addTarget(self, action: Selector(("didClickLeave")), for: .touchUpInside)
        self.view.addSubview(leaveButton)
    }
    
}

到这里,一个简单的通话界面就创建好了。接下来我们需要通过调用 Agora SDK 提供的核心 API 来实现基础的视频通话功能。

调用核心 API 实现视频通话

视频通话场景的 API 调用流程如下图所示。你也可以直接参考下文的中完整代码进行调用。

  1. 初始化 AgoraRtcEngineKit

    进入通话频道之前,调用 sharedEngineWithAppId 方法创建一个 AgoraRtcEngine 实例。

    1)在 initView 方法定义后继续添加下面的代码:

    func initAgora() {
       agoraKit = AgoraRtcEngineKit.sharedEngine(withAppId: "YourAppId", delegate: self)
    }
    

    2)用你刚刚在 Android 项目中填写的 App ID 替换上面代码中的 YourAppId(注意保留双引号)。

  2. 设置视频属性

    由于 Agora SDK 中默认视频模块是关闭的,因此设置视频属性包含 2 个步骤:

    • 调用 enableVideo 开启视频模式
    • 通过 setVideoEncoderConfiguration 方法设置本地视频的编码属性
    func setupVideo() {
        // 打开视频模式
        agoraKit.enableVideo()
        // 设置视频编码配置
        agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: AgoraVideoDimension640x360,
                                                                                 frameRate: .fps15,
                                                                                 bitrate: AgoraVideoBitrateStandard,
                                                                                 orientationMode: .adaptative))
    }
    
  3. 设置本地视频视图

    本地视频视图,是指用户在本地设备上看到的本地视频流的视图。

    在进入频道前调用 setupLocalVideo 方法,使应用程序绑定本地视频流的显示视窗,并设置本地看到的本地视频视图。

    func setupLocalVideo() {
      let videoCanvas = AgoraRtcVideoCanvas()
      videoCanvas.uid = 0
      videoCanvas.view = localVideo
      videoCanvas.renderMode = .hidden
      agoraKit.setupLocalVideo(videoCanvas)
    }
    
  4. 加入频道

    现在你可以加入频道开始视频通话了。 调用 joinChannelByToken 方法加入频道。

    你需要在该方法中传入想要加入的频道名称。App ID 和频道名称均相同的用户可以加入同一个频道进行通话。

    func joinChannel() {
        agoraKit.joinChannel(byToken: nil, channelId: "demoChannel1", info:nil, uid:0) {(sid, uid, elapsed) -> Void in}
        UIApplication.shared.isIdleTimerDisabled = true
    }
    

    请确保你在该方法中传入的 channelId 的值与在 Android 项目该方法中传入的值是一致的。

  5. 设置远端视频视图

    远端视频视图,是指用户在本地设备上看到的远端用户的视频画面。

    在远端用户进入频道后,可以在远端视频首帧解码回调 firstRemoteVideoDecodedOfUid 中调用 setupRemoteVideo 方法设置本地看到的远端用户的视频视图。

    func rtcEngine(_ engine: AgoraRtcEngineKit, firstRemoteVideoDecodedOfUid uid:UInt, size:CGSize, elapsed:Int) {
        let videoCanvas = AgoraRtcVideoCanvas()
        videoCanvas.uid = uid
        videoCanvas.view = remoteVideo
        videoCanvas.renderMode = .hidden
        agoraKit.setupRemoteVideo(videoCanvas)
    }
    
  6. 离开频道

    视频通话结束时,调用 leaveChannel 方法离开频道。

    @IBAction func didClickLeaveButton() {
        agoraKit.leaveChannel(nil)
        UIApplication.shared.isIdleTimerDisabled = false
        remoteVideo.removeFromSuperview()
        localVideo.removeFromSuperview()
    }
    

完整代码

现在你的项目文件中代码应该类似下面这样:

import UIKit
import AgoraRtcEngineKit

class ViewController: UIViewController, AgoraRtcEngineDelegate {
​    var agoraKit: AgoraRtcEngineKit!
​    var localVideo: UIView!
​    var remoteVideo: UIView!
​    var leaveButton: UIButton!
​    
​    override func viewDidLoad() {
​        super.viewDidLoad()
​        initView()
​        initAgora()
​        setupVideo()
​        setupLocalVideo()
​        joinChannel()
​    }
​    
​    func initView() {
	    // 设置远端视频画面
​       remoteVideo = UIView(frame: self.view.bounds)
​       self.view.addSubview(remoteVideo)
	
	    // 设置本地视频画面
        localVideo = UIView(frame: CGRect(x: self.view.bounds.width - 90, y: 0, width: 90, height: 160))
        self.view.addSubview(localVideo)
	
	    // 设置离开按钮
        leaveButton = UIButton(type: .custom)
        leaveButton.setTitleColor(UIColor.red, for: .normal)
        leaveButton.frame = CGRect(x: self.view.bounds.width / 2 - 50, y: self.view.bounds.height - 50, width: 100, height: 20)
        leaveButton.autoresizingMask = [.flexibleTopMargin, .flexibleLeftMargin, .flexibleRightMargin]
        leaveButton.setTitle("Hang Up", for: .normal)
        leaveButton.addTarget(self, action: Selector(("didClickLeaveButton")), for: .touchUpInside)
        self.view.addSubview(leaveButton)
    }
    
    func initAgora() {
        agoraKit = AgoraRtcEngineKit.sharedEngine(withAppId: "YourAppId", delegate: self)
    }
    
    func setupVideo() {
        agoraKit.enableVideo()
        agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: AgoraVideoDimension640x360, frameRate: .fps15, bitrate: AgoraVideoBitrateStandard, orientationMode: .adaptative))
    }
    
    func setupLocalVideo() {
        let videoCanvas = AgoraRtcVideoCanvas()
        videoCanvas.uid = 0
        videoCanvas.view = localVideo
        videoCanvas.renderMode = .hidden
        agoraKit.setupLocalVideo(videoCanvas)
    }
    
    func joinChannel() {
​        agoraKit.joinChannel(byToken: nil, channelId: "demoChannel1", info:nil, uid:0) {(sid, uid, elapsed) -> Void in}  
​        UIApplication.shared.isIdleTimerDisabled = true
​    }
​    
​    func rtcEngine(_ engine: AgoraRtcEngineKit, firstRemoteVideoDecodedOfUid uid:UInt, size:CGSize, elapsed:Int) {
​        let videoCanvas = AgoraRtcVideoCanvas()
​        videoCanvas.uid = uid
​        videoCanvas.view = remoteVideo
​        videoCanvas.renderMode = .hidden
​        agoraKit.setupRemoteVideo(videoCanvas)
​    }
​    
​    @IBAction func didClickLeaveButton() {
​        agoraKit.leaveChannel(nil)
​        UIApplication.shared.isIdleTimerDisabled = false
​        remoteVideo.removeFromSuperview()
​        localVideo.removeFromSuperview()
​    }
}

测试和运行 Demo

现在我们可以连接真机,开始 Android 和 iOS app 一对一视频通话了。

  1. 将电脑连接至一台 Android 设备,在 Android Studio 中点击右上角的 Run 按钮,Android 手机或平板上会弹出一个是否安装应用程序的弹框。同意后,手机上就会安装一个名为 HelloAgora 的应用并直接进入通话界面。
  2. 将电脑与你的 iOS 设备连接,在 Xcode 中选择你的设备并点击左上角的 Build 按钮,Xcode 会在你的设备上安装并运行 app。

如果一切顺利的话,此时 Android 和 iOS 应用加入了同一个频道并能互相看到对方,可以进行视频通话了。

Agora SDK 使用体验征文大赛 | 掘金技术征文,征文活动正在进行中