Tag: 测试

Swift快照测试简介

因此,我正在制作一个新的应用程序,我很乐意在进行过程中分享自己的所有经验,以便保持自己的积极性并分享一些知识,希望您可以自己使用应用。 为什么要测试UI? 很简单,您要确保每次触摸任何UI元素时,一切都保持原样,这种集成测试还可以帮助您实现像素完美的视图并通过设计使设计师满意他们甚至在您的拉取请求中也可以看到的参考图像 。 怎么样 我将尝试描述如何使用坚如磐石的facebook lib`FBSnapshotTestCase`测试所有UI组件和视图。 正如lib参考资料所述: “快照测试用例”采用已配置的UIView或CALayer并使用renderInContext:方法获取其内容的图像快照。 它将快照与存储在源代码存储库中的“参考图像”进行比较,如果两个图像不匹配,则测试失败。 为了安装库,我们将使用Cocoapods安装依赖项 将以下行添加到您的Podfile中 之后,使用终端在项目根文件夹上进行Pod安装 ,然后打开生成的工作区以配置应用程序架构,如下所示 之后,您可以进入运行方案并将此环境变量添加到项目中 FB_REFERENCE_IMAGE_DIR = $(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages IMAGE_DIFF_DIR = $(SOURCE_ROOT)/$(PROJECT_NAME)Tests/FailureDiffs 看起来像这样 完成所有这些设置之后,我们将实际构成测试部分,您需要记住,我们可以测试任何UIView或CALayer因此,要检查的任何视图在添加新的测试用例 (包括UIViewController)时都比较容易 要测试什么? 就像我说过的,您可以测试要从UIView或CALayer继承的任何内容之前, 所以在这种情况下,我将测试设计师设计的新按钮组件 在这种情况下,我们要测试每个按钮的状态,以便当我们意外更新或更改任何GenericButton代码时,如果出现错误,则测试将失败 因此,让我们开始添加一个新的单元测试用例 然后更新代码,以便我们可以开始使用FBSnapshotTestCase。 为了使用该库,我们需要导入FBSnapshotTestCase ,然后将XCTestCase更改为FBSnapshotTestCase ,更改后将如下所示: 首先,让我尝试向您解释这个概念,以便您了解其工作原理。 为了进行快照测试,我们应该首先拍摄当前视图组件,此后,库将存储参考图像,以便以后每次运行此测试套件时,可以将其与新更改进行比较。 为了拍摄第一个快照,我们应该添加一些测试用例,然后在设置方法中将recordMode变量激活为true 按下测试操作后,您将看到所有UI测试失败的原因,请不要担心这是该过程的一部分,因为您会看到一条消息,告诉您现在所有参考图像都已保存,您可以打开recordMode为false并再次运行测试 如果要验证是否创建了参考图像,则可以检查测试文件夹,如果一切正常,则应看到一些具有实际组件状态的图像,在这种情况下,所有按钮状态均作为设计标记 但是我们还没有完成,我们想检查一下它是否有效,因此每当发生任何变化时,测试目标上都会出现红灯,因此我们应该从设置中删除recordMode行,然后再次击中测试目标 从现在开始,每次更改GenericButton组件中的某些会影响设计状态的警告时,都会警告您并且测试将失败,此技术可用于视图控制器,因此根据视图的状态,您可以查看元素是否到位一切正常,您还可以与设计人员共享参考图像,以便他们检查像素是否完美。 尾注 还有其他方法可以通过使用诸如KIF或Google的EarlGrey之类的库来测试UI元素,但我认为这种快照测试更易于维护,其中一个FBSnapshotTestCase可能与许多其他框架相同。 如果您有任何疑问或疑问,可以通过Twitter与我联系,我会尽力帮助您。 这是我的第一篇英文书面文章,请原谅我的错字🤓

在Swift中隔离任务,或如何创建可测试的网络层。

在过去的几年中,有许多闪亮的iOS体系结构越来越受到人们的炒作。 因为它们都是有效的,并且有好有坏,所以它们都解决了同一件事: 将业务逻辑与表示分离。 今天,我将写一个简单的概念,该概念适用于您下一个项目的架构,无论您打算使用哪种架构。 相当普通的网络层 为了解释我的观点,我将首先谈谈通常如何实现网络层。 我见过很多不同的网络层。 在大多数情况下,都有NetworkManager,ConnectionManager或类似的东西。 有一个类包含应用程序中的每个API调用。 尽管这是有效的并且可以正常工作,但它并没有遵循软件设计的核心概念: 单一职责。 ConnectionManager包含太多职责,因此不被认为是好的做法。 而且,它通常实现为单例。 我并不是说单例不一定很坏,但是不能将它们作为依赖项注入,并且在测试时不能轻易模拟。 这是非常常见的做法。 我也在MVVM或MVP架构中看到了这一点。 不同的方法 数据访问层可以以不同的方式实现。 让我们描述网络获取的过程: 这样,网络调用至少包含三个步骤: 创建一个请求 :这意味着设置URL,方法,参数(在URL路径或http正文中)和HTTP标头。 发货请求 :这是非常非常重要的一步。 必须使用URLSession或其上的一层(例如Alamofire)调度在上一步中创建和配置的请求。 获取和解析响应 :重要的是,此步骤应与前两个步骤分开实施。 在这里,您应该验证JSON或XML响应,然后将其解析为有效的Entity(如果愿意,也可以解析为Model)。 如果您确实希望您的体系结构干净且可测试,则应在不同的对象中实现这三个步骤。 这些对象如下: Request : Request对象具有配置网络请求所需的一切。 它是负责配置单个网络请求的结构或类。 这非常重要: 一个网络请求,一个 Request 对象。 NetworkDispatcher : NetworkDispatcher是一个对象,负责获取Request并返回Response 。 它应该作为协议来实现。 您应该针对该协议而不是针对具体的类(或结构)进行编码,并且永远不应将其实现为单例。 如果执行此操作,则可以将该NetworkDispatcher替换为实际上不发出任何网络请求的MockNetworkDispatcher ,而是从JSON文件获取响应,从而形成自然可测试的体系结构。 NetworkTask : NetworkTask是通用类Task的子类。 正如我将在稍后更好地解释的,任务是一个通用类,它负责以同步或异步方式获取Input类型并返回Output类型。 您可以使用RxSwift,ReactiveCocoa,Hydra,Microfutures,FOTask或仅使用闭包来实现Task 。 由你决定。 这里的重要部分是概念,而不是实现细节。 实施请求 […]

Swift —在Bitbucket上的持续集成

本文是同时介绍TDD和多个CI概念的指南的一部分。 您可以在 此处 查看介绍性文章 。 当使用位桶时,我们将使用CircleCI来满足CI的需求,因为它与TravisCI非常相似且易于配置。 不幸的是,它仅适用于对我们不起作用的Linux机器(因为我们需要一台macOS机器来构建我们的xcode项目)。 但是CircleCI确实提供了为期两周的免费试用,因此您可以签出它,看看它是否值得。 让我们开始工作: 首先在CircleCI网站上创建一个帐户,然后对您的Bitbucket帐户进行配对(您也可以使用您的BitBucket凭据直接登录Travis,从而无需进行配对过程)。 从项目列表中选择所需的项目,以便CircleCI可以为其生成Webhook。 现在,CircleCI已挂接到您的项目上,并且当您的代码更改时,它会收到通知(默认情况下,它被设置为在每次推送以及合并时都运行)。 现在是时候告诉CircleCI每次对代码进行推送更改时要做什么。 为此,我们必须将一个文件添加到项目的根目录,并将其circle.yml 。 CircleCI的配置方案需要更多的指令(​​与Travis相比),如果被多个文件分割,则更容易做到,这就是我们要做的。 首先在项目的根目录下创建一个Scripts文件夹。 现在创建以下文件(每个要点底部的文件名): 7.现在配置CircleCI并准备就绪! 提交并推送您的更改(确保包括.yml文件和所有脚本),应该通知CircleCI,它将开始构建您的项目并运行测试! 如果一切顺利,您应该得到一个类似于以下的屏幕: 有些不对劲? 请在下面发表评论,我将尽力帮助! 9.随着CircleCI的启动和运行,我们现在应该利用它的功能并使我们的CI工作流更加强大。 SwiftLint Swiftlint是一种工具,可以帮助您识别和标记代码的某些部分,这些部分可能不遵循社区或您的团队所遵循的样式规则。 因此,它将帮助您坚持简洁的代码惯例,并在整个团队之间保持共同的风格。 Swiftlint可以在本地或CI服务器上运行。 让我们先在本地运行它: 首先在控制台上运行brew update和brew install swiftlint ,然后在转到项目的根文件夹后,运行swiftlint 。 而已! 短毛猫会检查您的代码并提出可能发现的任何问题! 2. SwiftLint的另一个优点是,您可以配置XCode来运行它,以便在每次构建后进行编码时都能得到实时警告! 为此,我们必须在Xcode的构建过程中添加一个新的“运行脚本阶段”,并包含以下脚本: 尽管非常有用,但SwifLint有时还是会有些干扰。 在某些情况下,您可能会收到您确实不想更改的代码的警告(例如上面的AppDelegate甚至是测试类,它们本来就很长)。 为避免这种情况,您可以配置.yml文件以指定文件排除项。 我希望您更明确一些,并像 // swiftline:disable:next line_length 有了SwiftLint的本地部分,现在该让CircleCI处理它了。 首先,将新文件添加到Scripts文件夹中: 现在是时候创建一个CodeCov帐户了。 使用您的Bitbucket帐户注册,然后从列表中添加您的存储库。 您应该看到类似于此屏幕。 记下令牌ID,因为稍后我们将需要它。 最后,我们现在可以配置CircleCI,以便每次构建项目时也可以检查覆盖范围。 我们必须在yml文件中添加两件事: […]

如何在iOS应用程序中为多个模拟器运行UITest?

本文假定您已经知道如何在Xcode中编写UITest。 现在,如何运行与彼此交互的UITest,在这种情况下,您可以为一种消息传递功能编写测试用例,该功能可以在多个模拟器中运行多个用户,并等待他们彼此聊天。 这是消息传递应用程序的理想自动UITest,对吗? 我知道,关于此的StackOverFlow问题不多。 我知道,RayWenderlich网站上也没有教程。 我知道,您可能尝试过不同的解决方案,但是其中任何一个都有一些局限性。 但是,在这里您可以找到适合我的解决方案! 为什么呢 好吧,如果您的应用程序中具有消息传递功能,则应用程序最重要的测试范围是消息传递的整个功能,不仅要确保已发送消息,还要确保将收到消息,或者如果您有群组消息,请确保群组中的所有成员都会收到消息。 您可能会想到可能的解决方案,以下是每种解决方案的缺点: 手动测试 您知道这不是一个好选择! 因为这很耗时,所以即使您的测试场景文档齐全,您也可能会有人为错误,但是测试人员可能会错过对所有案例进行测试的机会! 在一个模拟器/设备中运行两个应用程序: 首先 ,如果您要测试多个用户,则必须为要运行的每个主应用程序定义多个捆绑标识符,并且有一个测试应用程序将与其他应用程序交互。 但可以肯定的是,这不是一个漂亮的测试环境! 其次 ,在应用程序之间进行切换将非常耗时! 第三,但最重要的是,如果您不仅仅想要像行为测试这样的UITest,或者您正在使用像KIF这样的库,它们仅与UnitTest Target兼容,那么在任何这些情况下,您都必须在UnitTest Target中使用测试用例可以访问您的应用程序模块,并获得诸如KIF之类的库的支持! 但是,您将失去运行可与主应用程序交互的单独测试应用程序的功能! 甚至,您将无法在setup()函数中运行以下命令,您将获得运行时错误! XCUIApplication()。launch() 同时运行两个模拟器: 是的,这也是我认为的最佳解决方案。 但请记住,我们不仅需要UITest,而且还使用KIF编写UITest案例!

Swift —在Github上的持续集成

本文是同时介绍TDD和多个CI概念的指南的一部分。 您可以在 此处 查看介绍性文章 。 如介绍性文章所述,对于本指南,我们将使用TravisCI作为CI平台。 它对开源项目是免费的,并且易于使用。 让我们开始工作: 首先在TravisCI网站上创建一个帐户,然后对GitHub帐户进行配对(您也可以使用GitHub凭据直接登录到Travis,从而无需进行配对过程)。 从项目列表中选择所需的项目,以便Travis可以为其生成一个Webhook。 TravisCI现在已挂接到您的项目上,并且在您的代码更改时将得到通知(默认情况下,它设置为在每次推送以及合并时都运行。您可以在github的项目配置页面上对其进行编辑。 现在是时候告诉TravisCI每次对代码进行推送更改时要做什么。 为此,我们必须将一个文件添加到项目的根目录,并将其命名为“ .travis.yml”。 它看起来应该像这样: 7. TravisCI现在已经配置好,可以开始使用了! 提交并推送您的更改(确保包括.yml文件),应通知TravisCI,它将开始构建您的项目并运行测试! 如果一切顺利,您应该得到一个类似于以下的屏幕: 有些不对劲? 请在下面发表评论,我将尽力帮助! 8.您可能还需要检查日志,以了解实际情况。 但是, xcodebuild日志可能有些冗长和混乱。 为了解决这个问题,我们将使用另一个名为xcpretty小工具,它将获取构建日志并使其更加用户友好。 这很容易。 我们只需要向.yml配置文件添加几行: 2. SwiftLint的另一个优点是,您可以配置XCode来运行它,以便在每次构建后进行编码时都能得到实时警告! 为此,我们必须在Xcode的构建过程中添加一个新的“运行脚本阶段”,并包含以下脚本: 尽管非常有用,但SwifLint有时还是会有些干扰。 在某些情况下,您可能会收到您确实不想更改的代码的警告(例如上面的AppDelegate甚至是测试类,它们本来就很长)。 为避免这种情况,您可以配置.yml文件以指定文件排除项。 我希望您更明确一些,并像 // swiftline:disable:next line_length 随着SwiftLint的本地部分得到照顾,现在是时候让TravisCI处理它了。 同样,这是通过travis.yml:完成的travis.yml: 现在该创建一个CodeCov帐户了。 使用您的GitHub帐户注册并从列表中添加您的存储库。 您应该看到类似于此屏幕。 记下令牌ID,因为稍后我们将需要它。 最后,我们现在可以配置TravisCI,以便每次构建项目时也可以检查覆盖范围。 我们必须在yml文件中添加两件事: 通过添加标志-enableCodeCoverage YES ,将xcodebuild配置为也启用coverage数据 使用after_script选项将覆盖率数据上传到codecov 。 您的Yaml应该如下所示: 已知的错误 xcodebuild目前发生一个已知的错误,其中没有考虑UI测试,这会影响您的覆盖率。 例如,当我想以正确的百分比(在FizzBu​​zz示例中为100%)更新CodeCov时,例如在合并合并请求之前,我直接在XCode中运行整个测试套件,然后手动上载coverage使用相同的命令向codecov报告: bash […]

如何正确编写扫描QR码的ViewController

让我们编写一个解耦的代码,通过使用组合甚至可以测试我们的ViewController! 😱 当我不得不编写QR码扫描仪应用程序时,我以前从未使用过AVFoundation。 因此,我遵循了通常的脚本:我阅读了一些文档,阅读了一些教程并将学习的内容应用于我的需求。 通用方法的问题在于,它使ViewController符合另一种协议。 因此,它增加了另一个责任! 我将以一个简单的应用程序为例,向您展示一种更好的方法。 第一个ViewController需要一种使用摄像机捕获视频并显示在此辣味混合框中捕获的内容的方法。 另外,当用户将相机指向QR码时,它需要解释并解码其值。 之后,它可以停止捕获视频。 AVFoundation助我们一臂之力! AVFoundation 尽管QR代码已经很老了,但是直到iOS 7才有了AV Nativeation的巨大改进,我们没有在iOS上读取它们的原生方法。 现在,这是在iOS上实现代码读取器的最简单方法! 它具有我们完成此任务所需的所有功能。 AVCaptureDevice Input负责捕获视频。 AVCaptureVideo 预览层,用于显示实时视频。 AVCaptureMetadata 输出是将解释和解码QR码的输出。 AVCapture Session可以管理输入和输出之间的数据流。 我将所有这些逻辑包装在名为AVCodeReader的类中。 它的界面由两个函数和一个属性组成。 该函数开始读取QR码并使用转义闭包来通知何时解码值。 另一个停止使用相机资源。 还有CALayer属性,其中包含正在捕获的视频。 定义AVCodeReader接口的协议 AVCodeReader 我使用init来设置前面提到的所有AVFoundation类。 https://github.com/danielCarlosCE/aguente/blob/master/Aguente/Model/Implementation/AVCodeReader.swift 首先要记住的是,该设备(如模拟器)可能没有摄像头。 您必须决定接下来会发生什么。 我选择不破坏应用程序,而是选择一个空的videoPreview和一个nil captureSession 。 现在,它可以在不为captureSession时使用captureSession启动和停止读取QR码。 https://github.com/danielCarlosCE/aguente/blob/master/Aguente/Model/Implementation/AVCodeReader.swift 请注意,我将completion闭包分配给didRead属性,因此可以从另一个函数调用它。 要用作输出的委托,它必须符合AVCaptureMetadataOutputObjectsDelegate 。 该协议需要NSObjectProtocol ,因此我将类NSObject的子类。 https://github.com/danielCarlosCE/aguente/blob/master/Aguente/Model/Implementation/AVCodeReader.swift ReaderViewController 承诺是写一个解耦的代码! 让我们看看ViewController的样子。 https://github.com/danielCarlosCE/aguente/blob/master/Aguente/Controller/ReaderViewController.swift 尽管ViewController不知道如何扫描QR码,但它具有依赖关系。 由于在使用情节提要时不能使用构造函数注入,因此我在此处使用了强制展开属性。 因此,如果有人在调用此视图之前忘记设置依赖项,则应用程序将崩溃! 请注意,我不仅要添加videoPreview图层,而且还要在视图布局其子视图时对其进行更新,因为在viewDidLoad尚未设置自动布局的约束。 […]

A / B测试移动应用

什么是A / B测试? 是一项实验,您将两个版本的服务提供给不同的人群,并评估每个变体的性能。 这很简单,例如更改网站上按钮的颜色并衡量哪个按钮获得了更多点击。 A / B测试的其他名称是存储桶测试和拆分运行测试。 我为什么要在乎? A / B测试提供了一种科学的,没有偏见的方法来改善您提供的服务。 您可以制定假设,与真实用户进行检验,并根据真实数据制定业务决策,而不受HiPPO(最高薪人士的意见)的驱动。 该技术的强大之处在于,当您发现违反直觉的结果时,如果不使用科学方法很难找到该结果。 谁在使用它? 几乎每个科技公司都以某种方式使用它。 一些著名的例子是Google,Facebook和Spotify。 您很可能已经在不知不觉中参加了实验,例如,在Facebook中,您看到的UI不同于朋友。 如何实施? 以最简单的方式,A / B只需要两件事,一种是创建统一的变体,另一种是测量结果。 例如,我们可以有一个标志,当用户首次启动应用程序时,它会随机决定用户是在A组还是B组上,然后根据此标志更改行为。 当用户与应用程序进行交互时,我们会评估其行为,并使用分析将结果与用户所在的组一起发送。 但是,如果您使用商业平台从小处着手,则可能会有一些优势并简化您的工作。 在这篇博客文章中,我们将探讨如何使用Taplytics完成A / B测试。 集成SDK是一个非常标准的过程,一旦您在Taplytics中注册,便可以遵循。 之后,您可以使用“实验”标签开始创建A / B测试。 我们设计的实验称为“表情符号或图片”,以了解我们的用户是否更喜欢使用表情符号或图片的界面。 我们最初的用户界面是: 我们想测试通过用表情符号替换图像是否可以增加应用程序的整体使用率。 我们可以衡量的一项测试和一项指标。 该服务的可视化编辑器可让您点击应用中的任何内容,并为实验进行编辑,而无需编写代码。 这个功能虽然很有希望,但并未按预期工作,将UI中的错误图片关联了起来。 即使给视图提供不同的标签和IBOutlets也不会改变情况。 我们联系了Taplytics团队以更好地了解问题。 因此,我们使用布尔变量来控制UI并将其更改为用表情符号替换图像。 然后,我们可以创建实验目标: 然后,您可以创建暴露测试的用户细分,并按特定参数进行过滤: 您甚至可以选择要公开实验的用户百分比和要进行首次展示的用户百分比: 开始实验后,您可以获取摘要和结果以衡量假设。 一段时间后,您可以声明Winning变体并将该版本部署到所有用户。 样例项目 我们的示例项目可在我们的GitHub上找到。 注意:不要忘记更改帐户的API密钥和URL方案。 更多工具和服务 其他工具和服务的列表在此处提供。 例如Optimizely,Apptimize,Lifecycle,Leanplum和Localytics。

Swift-持续集成(CI)

本文是同时介绍TDD和多个CI概念的指南的一部分。 您可以在 此处 查看介绍性文章 。 在一个简单的项目(例如,有一个开发人员)下处理和管理代码通常是一件容易的事。 但是,当更多的人开始加入时,项目将增长,代码将获得更多功能,管理任务将逐步升级,并且很快就无法实现。 CI的基本原理是,通过不断审核更改,可以防止(或至少减少)此类集成问题。 每次提交后(如果您使用的是git),CI都会构建您的代码并运行测试套件,以确保最新的更改不会破坏任何内容! CI还可以在单​​独的计算机上(无论是否在本地)运行,以确保代码在与用户的计算机不同的计算机上运行,​​并且该代码也可以在“干净”的计算机上构建,而无需事先安装任何吊舱等。 在为我的Swift项目寻找合适的CI时,我遍历了其中三个: Travis CI:基于云,它提供了一个VM,供您在其中运行代码。适用于XCode项目,您可以运行xcodebuild xctool甚至fastlane命令。 简单的界面,但至少到目前为止,它仅与GitHub项目配对。 它是免费的开源项目,并且为私有存储库提供了不同的层次。 Circle CI:非常类似于TravisCI,也是基于云的。 它的配置有些不同,但没什么特别的。 它的免费套餐仅适用于Linux机器,并已付费MacOS平台(提供免费的两周计划) Jenkins CI:与前两个相反,Jenkins是免费的,但您必须将其托管在自己的服务器中。 它具有更多的可定制性,但这是以不那么友好的配置为代价的。 它的学习曲线更陡峭,但是如果您想对事情进行更多的控制,这可能是我的选择。 此外,我还想包括其他工具,这些工具将有助于检查测试覆盖率,代码质量和棉绒: CodeCov:有关测试覆盖率的报告 SwiftLint:分析代码中可能的错误,样式错误和/或可疑的内容; 猎犬:类似于SwiftLint,但基于云 Codebeat:通才代码审查,检查代码重复,长函数或语句等 让我们从这里开始看看该工具如何与GitHub存储库一起使用。

在Swift 4中关于JSON解析的简短思考

首先,将Codable定义为typealias Codable = Decodable&Encodable,我们采用两种必需的协议: 可解码 :解析JSON(获取响应) –通过解码JSONData,我们将接收/读取数据 2. Encodable :生成JSON(响应后) –要将可编码 类型转换为Data 。 它适用于基本类型(Int,String和Float等),某些基础类型(数据,URL,日期等)以及数组,字典和可选参数(枚举)。 – NSData – NSString – NSNumber – UInt – Int – Float – Double – Bool – NSDate – NSArray – NSDictionary 为什么? 在我们的数据管理器中简化依赖关系 将数据结构转换为JSON数据从未如此简单(hmmmm ..),允许开发人员将JSON数据存储到磁盘或将其编码为URLRequest的httpBody :)。 您可以编写一个使用外部来源的JSON或通过存根进行测试的应用。 这里的开始问题是您在应用程序中建模的概念的结构与JSON生产者建模的概念之间的不一致。 在您的应用中更改和使用JSON结构的一些示例: 使用CodingKey更改名称属性 2.通过手动编码和解码简化复杂的结构 3.使用嵌套数据(数组JSON内的数组) 对于1.,即使我们不必解析JSON表示形式的每个元素,我们也需要创建与JSONData中名称相同的属性,或者使用CodingKey重命名它们以直接存储基本示例。 到目前为止很简单!🤠🤠 struct SurfBoard:可编码{ var品牌:字符串 var size:大小 枚举CodingKeys:字符串,CodingKey […]

打开iPhone的本机屏幕记录

对于那些还没有听说过的人,Apple在iOS 11中包含了一个很棒的小功能,让您可以原生录制屏幕。 此功能非常适合展示您最新的iPhone应用程序功能或记录难以截图的可怕错误。 默认情况下它是关闭的,但是只需单击几下您就可以从控制中心访问它。 如何打开屏幕记录 →转到设置 →控制中心 →自定义控件 →单击绿色加号,从更多控件列表中添加“屏幕录像” →打开控制面板,将出现屏幕录制按钮。 对于我们当中的专业人士 →打开本机搜索 →输入“自定义控件” →单击绿色加号,从更多控件列表中添加“屏幕录像” →打开控制面板,将出现屏幕录制按钮。 Apple Insider提供了一个很棒的视频,解释了如何将屏幕嵌入视频https://youtu.be/tBA_HyL18JA