视频互动直播是当前比较热门的玩法,我们经常见到有PK 连麦、直播答题、一起 KTV、电商直播、互动大班课、视频相亲等。本文将演示如何通过声网视频 SDK 在 iOS 端实现一个视频直播应用。话不多说,我们开始动手实操。

前提准备

在声网开发者控制台 Console https://console.agora.io 注册声网开发者账号后,需要获取项目 AppID。另外,开发者每个月可获得 10000 分钟的免费使用额度,可实现各类实时音视频场景。

一、 通过开源Demo,体验视频直播

可能有些人,还不了解我们要实现的功能最后是怎样的。所以声网在 GitHub上提供一个开源的基础视频直播 Demo 项目,在开始开发之前你可以通过该示例项目体验视频直播的体验效果。

Demo 源码地址

  • Github Swift 版本:https://github.com/AgoraIO/Basic-Video-Broadcasting/tree/master/OpenLive-iOS
  • Github Objective-C 版本:https://github.com/AgoraIO/Basic-Video-Broadcasting/tree/master/OpenLive-iOS-Objective-C

效果截图

二、 视频直播的技术原理

我们在这里要实现的是视频直播,声网的视频直播可以实现互动效果,所以也经常叫互动直播。你可以理解为是多个用户通过加入同一个频道,实现的音视频的互通,而这个频道的数据,会通过声网的 SD-RTN 实时网络来进行低延时传输的。

需要特别说明的是,声网互动直播不同于视频直播。视频通话不区分主播和观众,所有用户都可以发言并看见彼此;而互动直播的用户分为主播和观众,只有主播可以自由发言,且被其他用户看见。

下图展示在 App 中集成声网互动直播的基本工作流程

如上图所示,实现视频直播的步骤如下:

  1. 获取 Token:当 app 客户端加入频道时,你需要使用 Token 验证用户身份。在测试或生产环境中,从 app 服务器中获取 Token。
  2. 加入频道:调用 joinChannel 创建并加入频道。使用同一频道名称的 app 客户端默认加入同一频道。频道可理解为专用于传输实时音视频数据的通道。
  3. 在频道内发布和订阅音视频流:加入频道后,app 客户端均可以在频道内发布和订阅音视频。

App 客户端加入频道需要以下信息:

  1. App ID:声网后台随机生成的字符串,用于识别你的 App,可从声网控制台获取.
  2. 用户 ID:用户的唯一标识。你需要自行设置用户 ID,并确保它在频道内是唯一的。
  3. Token:在测试或生产环境中,app 客户端从你的服务器中获取 Token。在本文介绍的流程中,你可以从可从声网控制台获取获取临时 Token。临时 Token 的有效期为 24 小时。
  4. 频道名称:用于标识视频直播频道的字符串。

三、 开发环境

声网 SDK 的兼容性良好,对硬件设备和软件系统的要求不高,开发环境和测试环境满足以下条件即可:
• Xcode 9.0或以上版本
• 支持语音和视频功能的真机
• App 要求支持iOS 8.0或以上版本的iOS设备

以下是本文的开发环境和测试环境:

开发环境

• macOS 11.6版本
• Xcode Version 13.1

测试环境

• iPhone7 (iOS 15.3)

如果你此前还未接触过声网 SDK,那么你还需要做以下准备工作
• 注册一个声网账号,进入后台创建 AppID、获取 Token,
• 下载声网官方最新的视频直播 SDK;

四、 项目设置

1. 实现视频直播之前,参考如下步骤设置你的项目

a) 如需创建新项目, Xcode里,打开 Xcode 并点击 Create a new Xcode project。(创建 iOS项目链接:https://developer.apple.com/documentation/xcode/creating-an-xcode-project-for-an-app)

b) 选择平台类型为 iOS、项目类型为 Single View App,并点击 Next。

c) 输入项目名称(Product Name)、开发团队信息(Team)、组织名称(Organization Name)和语言(Language)等项目信息,并点击 Next。

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

d) 选择项目存储路径,并点击 Create。

2. 集成SDK

两种方法集成声网 SDK,选择如下任意一种方式获取声网 iOS SDK。

方法一:使用 CocoaPods 获取 SDK

a) 开始前确保你已安装 Cocoapods。参考 Getting Started with CocoaPods 安装说明。(Getting Started with CocoaPods 安装说明链接:CocoaPods Guides - Getting Started

b) 在终端里进入项目根目录,并运行 pod init 命令。项目文件夹下会生成一个 Podfile 文本文件。

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

platform :ios, '9.0'
target 'Your App' dopod 'AgoraRtcEngine_iOS'
end
方法二:从官网获取 SDK

a) 前往 SDK 下载页面,获取最新版的声网 iOS SDK,然后解压。

b) 根据你的需求,将 libs 文件夹中的动态库复制到项目的 ./project_name 文件夹下(project_name 为你的项目名称)。

c) 打开 Xcode,进入 TARGETS > Project Name > Build Phases > Link Binary with Libraries 菜单,点击 + 添加如下库(如:)。在添加 AgoraRtcEngineKit.framework 文件时,还需在点击 + 后点击 Add Other…,找到本地文件并打开。

共需要添加11个库文件:

i. AgoraRtcEngineKit.framework
ii. Accelerate.framework
iii. AudioToolbox.framework
iv. AVFoundation.framework
v. CoreMedia.framework
vi. CoreML.framework
vii. CoreTelephony.framework
viii. libc++.tbd
ix. libresolv.tbd
x. SystemConfiguration.framework
xi. VideoToolbox.framework

**注意1:**如需支持 iOS 9.0 或更低版本的设备,请在 Xcode 中将对 CoreML.framework 的依赖设为 Optional。

d) 打开 Xcode,进入 TARGETS > Project Name > General > Frameworks, Libraries, and Embedded Content 菜单。

e) 点击 + > Add Other… > Add Files 添加对应动态库,并确保添加的动态库 Embed 属性设置为 Embed & Sign。添加完成后,项目会自动链接所需系统库。

注意2: 根据 Apple 官方要求,app 的 Extension 中不允许包含动态库。如果项目中的 Extension 需要集成 SDK,则添加动态库时需将文件状态改为 Do Not Embed。
· 声网 SDK 默认使用 libc++ (LLVM),如需使用 libstdc++ (GNU),请联系 sales@agora.io。SDK 提供的库是 FAT Image,包含 32/64 位模拟器、32/64 位真机版本。

3. 权限设置

1) Xcode进入 TARGETS > Project Name > General > Signing 菜单,选择 Automatically manage signing,并在弹出菜单中点击 Enable Automatic。

2)添加媒体设备权限
根据场景需要,在 info.plist 文件中,点击 + 图标开始添加如下内容,获取相应的设备权限:

4. 导入声网相关的类

在项目中导入 AgoraRtcEngineKit 类:

Objective-C 版本

// Objective-C
// 导入 AgoraRtcKit 类
// 自 3.0.0 版本起,AgoraRtcEngineKit 类名更换为 AgoraRtcKit
// 如果获取的是 3.0.0 以下版本的 SDK,请改用 #import <AgoraRtcEngineKit/AgoraRtcEngineKit.h>
#import <AgoraRtcKit/AgoraRtcEngineKit.h>
// 声明 AgoraRtcEngineDelegate,用于监听回调
@interface ViewController : UIViewController <AgoraRtcEngineDelegate>
// 定义 agoraKit 变量
@property (strong, nonatomic) AgoraRtcEngineKit *agoraKit;

Swift 版本

// Swift
// 导入 AgoraRtcKit 类
// 自 3.0.0 版本起,AgoraRtcEngineKit 类名更换为 AgoraRtcKit
// 如果获取的是 3.0.0 以下版本的 SDK,请改用 import AgoraRtcEngineKit
import AgoraRtcKit
class ViewController: UIViewController {...// 定义 agoraKit 变量var agoraKit: AgoraRtcEngineKit?
}

5. 设置声网账号信息

在 KeyCenter.swift 文件中,将你的AppID填写到对应位置,可替换“Your App ID”;
Objective-C 版本

//  Objective-C
//  AppID.m
//  声网 iOS Tutorial
NSString *const appID = <#Your App ID#>;

Swift 版本

//  Swift
// AppID.swift
//  声网 iOS Tutorial
Static let AppID: String = Your App ID

五、 客户端实现

本节介绍如何使用声网视频 SDK 在你的 App 里实现视频直播的几个小贴士。

1. 创建用户界面

根据场景需要,为你的项目创建视频直播的用户界面。我们推荐你在项目中添加元素:本地视频窗口、远端视频窗口。

你可以参考以下代码创建一个基础的用户界面。

Objective-C 版本

// Objective-C
// 导入 UIKit
#import <UIKit/UIKit.h>
@interface ViewController ()
// 定义 localView 变量
@property (nonatomic, strong) UIView *localView;
// 定义 remoteView 变量
@property (nonatomic, strong) UIView *remoteView;
@end
@implementation ViewController
...
- (void)viewDidLoad {[super viewDidLoad];// 调用初始化视频窗口函数[self initViews];// 后续步骤调用声网 API 使用的函数[self initializeAgoraEngine];[self setChannelProfile];[self setClientRole];[self setupLocalVideo];[self joinChannel];
}
// 设置视频窗口布局
- (void)viewDidLayoutSubviews {[super viewDidLayoutSubviews];self.remoteView.frame = self.view.bounds;self.localView.frame = CGRectMake(self.view.bounds.size.width - 90, 0, 90, 160);
}
- (void)initViews {// 初始化远端视频窗口。只有当远端用户为主播时,才会显示视频画面self.remoteView = [[UIView alloc] init];[self.view addSubview:self.remoteView];// 初始化本地视频窗口。只有当本地用户为主播时,才会显示视频画面self.localView = [[UIView alloc] init];[self.view addSubview:self.localView];
}

Swift 版本

// Swift
// 导入 UIKit
import UIKit
class ViewController: UIViewController {...// 定义 localView 变量var localView: UIView!// 定义 remoteView 变量var remoteView: UIView!override func viewDidLoad() {super.viewDidLoad()// 调用初始化视频窗口函数initView()// 后续步骤调用声网 API 使用的函数initializeAgoraEngine()setChannelProfile()setClientRole()setupLocalVideo()joinChannel()  }// 设置视频窗口布局override func viewDidLayoutSubviews() {super.viewDidLayoutSubviews()remoteView.frame = self.view.boundslocalView.frame = CGRect(x: self.view.bounds.width - 90, y: 0, width: 90, height: 160)}func initView() {// 初始化远端视频窗口。只有当远端用户为主播时,才会显示视频画面remoteView = UIView()self.view.addSubview(remoteView)// 初始化本地视频窗口。只有当本地用户为主播时,才会显示视频画面localView = UIView()self.view.addSubview(localView)}
}

2. 实现视频直播逻辑

现在,我们已经将声网 iOS SDK 集成到项目中了。接下来我们要在 ViewController 中调用声网 iOS SDK 提供的核心 API 实现基础的视频直播功能。

API 调用时序见下图


参考上图,按照以下步骤实现该逻辑

a) 初始化AgoraRtcEngineKit对象

在调用其他声网 API 前,需要创建并初始化 AgoraRtcEngineKit 对象。调用 sharedEngineWithAppId 方法,传入获取到的 App ID,即可初始化 AgoraRtcEngineKit 。

Objective-C 版本

// Objective-C
// 输入 App ID 并初始化 AgoraRtcEngineKit 类。
- (void) viewDidLoad{
self.rtcEngine = [AgoraRtcEngineKit sharedEngineWithAppId:[KeyCenter AppId] delegate:self];
}

Swift 版本

// Swift
// 输入 App ID 并初始化 AgoraRtcEngineKit 类。
private lazy var agoraKit: AgoraRtcEngineKit = {let engine = AgoraRtcEngineKit.sharedEngine(withAppId: KeyCenter.AppId, delegate: nil)return engine}()

你还可以根据场景需要,在初始化时注册想要监听的回调事件,如本地用户加入频道,及解码远端用户视频首帧等。

b) 设置频道场景

调用 setChannelProfile 方法,将频道场景设为直播。一个 AgoraRtcEngineKit 只能使用一种频道场景。如果想切换为其他频道场景,需要先调用 destroy 方法销毁当前的 AgoraRtcEngineKit 对象,然后使用 sharedEngineWithAppId 方法创建一个新的对象,再调用setChannelProfile 设置新的频道场景。

Objective-C 版本

// Objective-C
// 设置频道场景为直播模式
[self.rtcEngine setChannelProfile:AgoraChannelProfileLiveBroadcasting];

Swift 版本

// Swift
// 设置频道场景为直播模式
agoraKit.setChannelProfile(.liveBroadcasting)
c) 设置用户角色

直播频道有两种用户角色:主播和观众,其中默认的角色为观众。设置频道场景为直播后,你可以在 app 中参考如下步骤设置用户角色:

让用户选择自己的角色是主播还是观众;
调用 setClientRole 方法,然后使用用户选择的角色进行传参。
注意,直播频道内的用户,只能看到主播的画面、听到主播的声音。加入频道后,如果你想切换用户角色,也可以调用 setClientRole 方法。

Objective-C 版本

// Objective-C
// 设置用户角色
- (IBAction)doBroadcastPressed:(UIButton *)sender {
if (self.isBroadcaster) {// 设置用户角色为主播self.clientRole = AgoraClientRoleAudience;if (self.fullSession.uid == 0) {self.fullSession = nil;}
} else {// 设置用户角色为观众self.clientRole = AgoraClientRoleBroadcaster;}[self.rtcEngine setClientRole:self.clientRole];[self updateInterfaceWithAnimation:YES];
}

Swift 版本

// Swift
// 选择用户角色
@IBAction func doBroadcasterTap(_ sender: UITapGestureRecognizer) {
// 选择用户角色为主播selectedRoleToLive(role: .broadcaster)}@IBAction func doAudienceTap(_ sender: UITapGestureRecognizer)
// 选择用户角色为观众
selectedRoleToLive(role: .audience)// 设置用户角色
agoraKit.setClientRole(settings.role)
// 设置为主播角色时
if settings.role == .broadcaster {addLocalSession()agoraKit.startPreview()}//设置为观众角色时
let isHidden = settings.role == .audience
d) 设置本地视图

成功初始化 AgoraRtcEngineKit 对象后,需要在加入频道前设置本地视图,以便在通话中看到本地图像。参考以下步骤设置本地视图:
· 调用 enableVideo 方法启用视频模块。
· 调用 setupLocalVideo 方法设置本地视图。

Objective-C 版本

// Objective-C
// 启用视频模块。
[self.rtcEngine enableVideo];
// 设置本地视图。
- (void)addLocalSession {VideoSession *localSession = [VideoSession localSession];
[self.videoSessions addObject:localSession];
// 设置本地视图。[self.rtcEngine setupLocalVideo:localSession.canvas];[self updateInterfaceWithAnimation:YES];
}// VideoSession部分
//  VideoSession.m
#import "VideoSession.h"
@implementation VideoSession
- (instancetype)initWithUid:(NSUInteger)uid {if (self = [super init]) {self.uid = uid;self.hostingView = [[UIView alloc] init];self.hostingView.translatesAutoresizingMaskIntoConstraints = NO;self.canvas = [[AgoraRtcVideoCanvas alloc] init];self.canvas.uid = uid;self.canvas.view = self.hostingView;self.canvas.renderMode = AgoraVideoRenderModeHidden;}return self;
}+ (instancetype)localSession {return [[VideoSession alloc] initWithUid:0];
}
@end

Swift 版本

// Swift
// 启用视频模块。
agoraKit.enableVideo()
// 设置本地视图。
agoraKit.setupLocalVideo(videoCanvas)// VideoSession部分
// VideoSession.swift
hostingView = VideoView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
hostingView.translatesAutoresizingMaskIntoConstraints = false
canvas = AgoraRtcVideoCanvas()
canvas.uid = uid
canvas.view = hostingView.videoView
canvas.renderMode = .hidden
e) 加入频道

频道是人们在同一个视频直播中的公共空间。完成初始化和设置本地视图后(视频直播场景),你就可以调用 joinChannelByToken 方法加入频道。你需要在该方法中传入如下参数:

  1. channelId: 传入能标识频道的频道 ID。输入频道 ID 相同的用户会进入同一个频道。
  2. token: 传入能标识用户角色和权限的 Token。你可以设置如下值:
  • nil 。
  • 控制台中生成的临时 Token。一个临时 Token 的有效期为 24 小时,详情见获取临时 Token。
  • 你的服务器端生成的正式 Token。适用于对安全要求较高的生产环境,详情见生成 Token。若项目已启用 App 证书,请使用 Token。
  • uid: 本地用户的 ID。数据类型为整型,且频道内每个用户的 uid 必须是唯一的。若将 uid 设为 0,则 SDK 会自动分配一个 uid ,并在 joinSuccessBlock 回调中报告。
  • joinSuccessBlock:成功加入频道回调。 joinSuccessBlock 优先级高于 didJoinChannel ,2 个同时存在时, didJoinChannel 会被忽略。需要有 didJoinChannel 回调时,请将 joinSuccessBlock 设置为 nil 。

更多的参数设置注意事项请参考 joinChannelByToken 接口中的参数描述。
Objective-C 版本

// Objective-C
// 加入频道。
self.rtcEngine joinChannelByToken:[KeyCenter Token] channelId:self.roomName info:nil uid:0 joinSuccess:nil

Swift 版本

// Swift
// 加入频道。
agoraKit.joinChannel(byToken: KeyCenter.Token, channelId: channelId, info: nil, uid: 0, joinSuccess: nil)
f) 设置远端视图

视频互动直播中,通常你也需要看到其他主播。远端主播成功加入频道后,SDK 会触发 didJoinedOfUid 回调,该回调中会包含这个远端主播的 uid 信息。在该回调中调用 setupRemoteVideo 方法,传入获取到的 uid,设置远端主播的视图。

Objective-C 版本

// Objective-C
// 监听 didJoinedOfUid 回调
// 远端主播加入频道时,会触发该回调
- (void)rtcEngine:(AgoraRtcEngineKit *)engine didJoinedOfUid:(NSUInteger)uid elapsed:(NSInteger)elapsed {AgoraRtcVideoCanvas *videoCanvas = [[AgoraRtcVideoCanvas alloc] init];videoCanvas.uid = uid;videoCanvas.renderMode = AgoraVideoRenderModeHidden;videoCanvas.view = self.remoteView;// 设置远端视图[self.agoraKit setupRemoteVideo:videoCanvas];
}

Swift 版本

// Swift
//需要在额外添加以下代码
extension LiveRoomViewController: AgoraRtcEngineDelegate {// 监听 didJoinedOfUid 回调// 远端主播加入频道时,会触发该回调func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {guard videoSessions.count <= maxVideoSession else {return}let userSession = videoSession(of: uid)// 设置远端视图agoraKit.setupRemoteVideo(userSession.canvas)}}
g) 离开频道

根据场景需要,如结束通话、关闭 App 或 App 切换至后台时,调用 leaveChannel 离开当前通话频道。

Objective-C 版本

// Objective-C
// 离开频道的步骤
- (void)leaveChannel {[self setIdleTimerActive:YES];
[self.rtcEngine setupLocalVideo:nil]; // nil means unbind
// 离开频道。[self.rtcEngine leaveChannel:nil];    // leave the channel, callback = nilif (self.isBroadcaster) {[self.rtcEngine stopPreview];}for (VideoSession *session in self.videoSessions) {[session.hostingView removeFromSuperview];}[self.videoSessions removeAllObjects];if ([self.delegate respondsToSelector:@selector(liveVCNeedClose:)]) {[self.delegate liveVCNeedClose:self];}
}

Swift 版本

// Swift
// 离开频道的步骤
func leaveChannel() {// Step 1, release local AgoraRtcVideoCanvas instanceagoraKit.setupLocalVideo(nil)// Step 2, leave channel and end group chatagoraKit.leaveChannel(nil)// Step 3, if current role is broadcaster,  stop preview after leave channelif settings.role == .broadcaster {agoraKit.stopPreview()}setIdleTimerActive(true)navigationController?.popViewController(animated: true)}
h) 销毁AgoraRtcEngineKit对象

最后,离开频道,我们需要调用 destroy 销毁 AgoraRtcEngineKit 对象,释放声网 SDK 使用的所有资源。
Objective-C 版本

// Objective-C
// 将以下代码填入你定义的函数中
[AgoraRtcEngineKit destroy];

Swift 版本

// Swift
// 将以下代码填入你定义的函数中
AgoraRtcEngineKit.destroy()


至此,完成声网视频 SDK 的集成,运行看看效果。拿两部手机安装编译好的App,加入同一个频道名,分别选择主播角色和观众角色,如果2个手机都能看见同一个自己,说明你成功了。

如果你在集成开发过程中遇到问题,可以访问 RTE 开发者社区 吐槽与声网工程师交流。

基于声网 iOS SDK 实现视频直播应用相关推荐

  1. 基于声网 Flutter SDK 实现互动直播

    前言 互动直播是实现很多热门场景的基础,例如直播带货.秀场直播,还有类似抖音的直播 PK等.本文是由声网社区的开发者"小猿"撰写的Flutter基础教程系列中的第二篇,他将带着大家 ...

  2. 基于声网 Flutter SDK 实现多人视频通话

    前言 本文是由声网社区的开发者"小猿"撰写的Flutter基础教程系列中的第一篇.本文除了讲述实现多人视频通话的过程,还有一些 Flutter 开发方面的知识点.该系列将基于声网 ...

  3. 开发最佳实践|集成声网 iOS SDK,实现语音聊天室

    大家好,我是声网 RTE 开发者社区作者 @小曾同学.本次主要分享集成声网SDK实现语音聊天室. 01 前言 在日常生活中经常会看到一些聊天场景,比如在线KTV.连麦开黑.多人相亲.娱乐聊天室等应用场 ...

  4. 基于声网 视频通话SDK 的opencv 人脸检测

    目前在用声网的 视频通话SDK 制作一款会议系统软件,将来可能要加入人脸的一些操作,因此就想到了opencv,并且声网SDK 也提供了原始的视频帧 回调函数,所以在此基础上集成opencv 是可以的. ...

  5. 保姆级教程!基于声网 Web SDK实现音视频通话及屏幕共享

    前言 大家好,我是 @小曾同学,小伙伴们也可以叫我小曾- 如果你想实现一对一音视频通话和屏幕共享功能,不妨来看看这篇文章,保姆级教程,不需要从零实现,直接集成声网 SDK 即可轻松上手. 本文也分享了 ...

  6. 基于声网 SDK 实现 iOS 端的一对一视频通话

    在很多产品,加入实时视频通话已经不是新鲜事情了,尤其是近几年的疫情影响,个人公司国家对于实时音视频的需求一直在快速的增长.例如视频会议.社交应用.实时游戏,甚至也可能出现在一些元宇宙的场景中. 本文将 ...

  7. 神奇,声网Web SDK还能这么实现直播中美颜功能

    前言 本篇文章是通过使用声网Web SDK来实现直播中美颜效果的深度体验文章,其中发现了屏幕共享并本地合图多个视频.图片,声网美颜插件等功能特性十分强大和专业,特为此做一个技术+体验的分享,毕竟好技术 ...

  8. 基于声网的音视频SDK和FreeSWITCH开发WebRTC2SIP Gateway 方案和思路

    为什么做这个? 今年初接到一个项目任务,客户要求在自己的音视频平台系统中集成webrtc功能(原系统是基于SIP协议开发的,已经稳定运行多年,有很多客户).在比对了多家RTC产品的效果后,.他们对声网 ...

  9. 声网Agora SDK支持50ms超低延时耳返 适配主流手机机型

    近年来,随着网络直播的火爆,直播唱歌成为了很多主播在直播间的必备技巧,同时全民K歌.唱吧等在线K歌软件的兴起,也让很多人足不出户也能享受K歌的乐趣,并成为越来越多人偏爱的在线娱乐方式.而不管是直播唱歌 ...

最新文章

  1. 计算机道德 英语作文,公共道德英语作文
  2. 512M内存编译php出错
  3. 软硬兼备 学做CIO
  4. js 判断时区, 时区过滤
  5. oracle服务开机启动,Linux下建立Oracle服务及其开机自启动
  6. JAXB处理java对象与xml格式之间的转换
  7. php 打印系统变量值,php – Twig:打印变量名为String的变量的值
  8. CSDN下载频道【2月热门资源TOP100】汇总
  9. 三菱驱动器参数表_三菱伺服驱动器参数设置CM100TJ-24F
  10. 华为云服务器手机密码找回,忘记华为账号密码怎么办?两招就能帮你解决
  11. Python移植MATLAB的巴特沃斯滤波器,椭圆滤波器
  12. .NET Framework 4.6.1包和语言包下载
  13. 计算机管理软件禁止玩游戏,如何禁止电脑指定程序不能运行 怎么屏蔽QQ或游戏运行提高办公效率...
  14. Krytox VPF1525 VPF1514 VPF1506 XP Chemours DuPont
  15. console接口是干嘛的(console接口是干嘛的电信室外光猫)
  16. 机器学习06|两万字:决策树 【jupyter代码详解篇】
  17. daterangepicker 清空_Date Range Picker 中文网
  18. 电脑怎么录制屏幕视频,3种方法,轻松弄懂
  19. 分享:用Python语言轻松实现二代身份证阅读器(读卡器)自动读卡,支持定制开发
  20. Render函数的使用方法

热门文章

  1. 医院在线预约挂号系统 jsp+mysql+maven
  2. [教程]配置青鸟云Web服务器
  3. 台式计算机加固态硬盘,台式机添加固态硬盘教程_台式主机固态硬盘怎么安装-win7之家...
  4. Oracle中根据日期范围进行查询,查询大于某一天的数据,查询小于某一天的数据
  5. cse7761电能计量芯片驱动程序
  6. 查看linux镜像版本的命令,Linux镜像列表中 怎样决定自己下载哪个版本
  7. php网页设计导航栏代码,CSS导航栏及弹窗示例代码
  8. 手机摄像头+Matlab完成图像的自动识别
  9. P2178 [NOI2015] 品酒大会(并查集+后缀数组)
  10. 风陵渡口初相遇,一见杨过误终身