Tag: swift

没有Fastlane的iOS连续交付的五个选项

原始文章发表在XCBlog上 Fastlane工具可自动执行整个iOS CI / CD管道,并允许我们将iOS基础结构保留为代码。 Fastlane提供了一系列工具,可自动执行从分析,构建,测试,代码签名和存档iOS应用程序的几乎所有操作。 但是,如果您向里看,它不过是本机Apple开发人员工具之上的Ruby层。 在某些情况下,Fastlane可能节省了一些时间,但是值得一提的是,Fastlane因频繁的重大更改而浪费了多少开发人员时间。 不断学习Ruby和Fastlane的自动化方法浪费了很多开发人员的时间。 像CocoaPods一样,Fastlane可能是您的iOS项目中使用Ruby的另一个大笨蛋,它与iOS开发无关。 学习某些本地Apple开发人员工具并从iOS开发工具箱中完全删除Ruby和其他第三方工具(如Fastlane)并不难。 在这篇文章中,我们将介绍iOS开发人员在使用Fastlane时面临的问题,以及Fastlane的当前替代方案。 五个快速通道问题 Fastlane声称通过自动执行常见任务为开发人员节省了时间。 在Fastlane能够按预期工作的情况下可能确实如此,但考虑到Fastlane在设置,调试和管理方面浪费了多少开发人员时间,这一点也很重要。 在本节中,我们将看到iOS开发人员使用Fastlane可能面临的常见问题。 1.红宝石 在iOS项目中使用Fastlane的第一个主要问题是Ruby。 通常,iOS开发人员并不擅长Ruby,但是要使用Fastlane或CocoaPods之类的工具,他们必须学习与实际的iOS开发无关的Ruby。 设置Fastlane工具需要对Ruby以及RubyGems和Bundler的工作方式有很好的了解。 最近宣布有Swift版本的Fastlane摆脱了Ruby,但它只是Swift在后台执行Ruby命令。 我怀疑Swift版本的Fastlane的可用性。 我已经在这篇文章中写了我的初步印象。 Fastlane拥有良好的文档,但是iOS开发人员仍然必须使用Ruby编写脚本来自动化iOS发布管道的所有基础架构。 2.频繁更新 Apple不断更改本机工具,从而不断破坏Fastlane工具。 他们需要始终追赶苹果和谷歌(如果是Android的话),以适应Fastlane中的这些变化。 这要求Fastlane开发人员实现这些功能并发布新版本的Fastlane。 如果Fastlane版本不是由Bundler管理,则大多数时候更新Fastlane版本都需要更新现有的Fastlane脚本。 由于更新的缘故,可能会经常导致内部版本崩溃,iOS开发人员需要花费时间来分析Fastlane中已更改的内容并相应地修复内部版本。 这种突破性的更新打扰了iOS开发人员的主要开发流程,最终浪费了数小时来修复构建。 使用Fastlane的痛苦之一是,在早期版本的Fastlane中配置的选项并不总是与较新的版本一起使用,如果您搜索解决方案,则最终将获得针对不同版本Fastlane的相同问题的多个解决方案。 3.耗时的设置和维护 尽管Fastlane提供了很好的模板代码入门指南,但是编写脚本来自动化iOS发布管道所需的所有内容并不是一件容易的事。 我们可能需要根据需要自定义选项,这要求这些选项在Fastlanes中的编码方式。 然后,我们可以使用不同的通道来编写管道脚本。 要设置所有内容,需要大量时间来学习Fastlane和Ruby工具箱。 当您设置所需的所有内容时,该工作并未完成,如上所述,它需要对Fastlane更新进行持续的持续维护。 4.难以贡献 可能需要根据公司特定的规则配置iOS发布管道,或者需要Fastlane进行自定义操作。 唯一的选择就是为Fastlane编写插件。 当前,编写插件的唯一方法是编写可以作为Fastlane插件安装的Rubygem。 同样,它需要对Ruby生态系统的深入了解,而通常iOS开发人员都不熟练。 不幸的是,iOS开发人员无法为他们当前在工具箱中使用的工具做出贡献。 最重要的是,为Fastlane做出贡献的过程既耗时又充满自动化机器人。 首先创建一个Github问题作为提案,然后进行无休止的讨论。 您可以在此处阅读有关Fastlane贡献指南的更多信息。 5. Github上的未解决问题 GitHub上存在多个问题,其中一些问题是由自动bot封闭的,没有为用户提供正确的解决方案。 很好的例子是,我如何浪费几天来确定Fastlane匹配支持企业应用程序是否使用Xcode 9构建发行版。在寻找解决方案时,我发现还有其他人也在寻找解决方案。 这是Fastlane bot在未提供适当解决方案的情况下解决的未解决问题的示例。 我已经尝试过针对11090、10543、10325、10458等问题提供的多种解决方案。阅读所有这些内容之后,我无法弄清楚哪种方法适用于企业构建。 […]

在Unity中实现Swift

这是我以前的文章中关于与ARKit一起在Unity中实现CoreML的后续文章。 学习完本教程后,您可以做什么。 您可以在Unity项目中使用任何Swift代码。 您可以从Unity调用Swift void,但也可以调用实际的返回类型。 您可以将变量从Unity传递给Swift函数。 您可以从Swift字符串转换为C#字符串(听起来更复杂)。 首先,在Unity中使用Swift。 让我们从Unity的Swift开始,最简单最重要的事情开始。 我之前的许多人已经做到了这一点,尤其是对于Unity 5.6及更低版本。 最近人们很难使其在Unity 2017或更高版本中工作。 在许多教程的帮助下,我使它可以在Unity 2017及更高版本中使用,一直到Unity 2018.2 beta为止。 所以我们开始: 步骤1:建立可可触控框架 打开Xcode时,创建一个新项目,然后选择“ Cocoa Touch Framework”并命名为任意名称。 我将其命名为“ SwiftPlugin”。 当然,语言是“快速”,您可以保留“包括单元测试”。 为了使事情井井有条,请在“ SwiftPlugin”文件夹中创建一个新文件夹。 并将其称为“来源”。 步骤2:开始编写您的Swift代码。 首先,我们在“ Source”文件夹中创建一个Swift文件。 我称我为“ SwiftForUnity.swift”。 将以下代码粘贴到您的.swift文件中: 进口基金会 导入UIKit @objc公共类SwiftForUnity:UIViewController { @objc静态让共享= SwiftForUnity() @objc func SayHiToUnity()->字符串{ 返回“嗨,我是斯威夫特” } } @objc表示该类和函数可以在Objective-c中使用,我们稍后需要在C#中使用它。 同样,您希望对Objective-C可见的所有类都需要从NSObject继承,因为UIViewController已经从NSObject继承了,所以无需在这里再次添加它。 编写Swift代码后,您需要制作一个Objective-C ++文件并将其命名为“ SwiftForUnityBridge.mm”。 您需要将其从“ SwiftForUnityBridge.m”重命名为“ SwiftForUnityBridge.mm”。 […]

创建和上传自己的CocoaPods

在上一篇名为“构建自己的框架”的后续文章中,本文将重点介绍如何使用该框架创建自己的CocoaPod并将其上传到GitHub。 但是首先,CocoaPod到底是什么? 用他们自己的话说: “ CocoaPods是Swift和Objective-C Cocoa项目的依赖项管理器。 它拥有超过24,000个库,并在超过120万个应用程序中使用。 CocoaPods可以帮助您优雅地扩展项目。” 说得好! 👏🏼👏🏼 CocoaPods通过提供一种上载,共享和管理第三方库的方式,使开发人员彼此之间的协作更加容易。 这意味着您可以完全使用其他开发人员已经编写的代码,而不必完全从头开始构建应用程序。 此外,CocoaPods的开源性质不仅使创建应用程序的过程效率大大提高,而且还创建了一个环境,邀请世界各地的开发人员共享任何内容,从微妙的图形到整个旨在促进Web导航和API请求的框架。 有几个网站重点介绍了新的和流行的CocoaPods,但是对于今天的帖子,我们将重点放在将我们自己的代码上传到GitHub上,以供每个人检查和实现! 正如我所说,虽然某些CocoaPods具有革命性并改变了我们与项目交互的方式,但其中许多都是简单的功能,它们以最小的努力增加了一些才能。 鉴于我精通的编码专业知识和充裕的时间,我将创建一个接近疏忽的代码的CocoaPod,以期说明流程并激发更多才华横溢的编码人员为CocoaPods网络做出贡献! 创建CocoaPod: 首先使用您希望捆绑的所有相关文件创建一个Xcode框架。 (如果您忘记了这样做的方法,也许我建议这个有用的资源😉) 接下来,将其保存在可靠的位置(也许是装满未来CocoaPods的“图书馆”文件夹)。 之后,您可以关闭Xcode 在终端中,找到文件并输入以下代码行5o创建一个新的Podfile 4.仔细检查Podfile的内容。 在我们的示例中,默认情况下应考虑所有内容,但是,如果项目中还有任何其他Pod,则必须在此处列出。 例如,如果要实现Alamofire,则可以在“继承! “ search_paths”。 否则,您可以简单地保存并关闭Podfile。 5.接下来,在终端中输入代码“ pod install”。 这将创建一个XCworkspace并安装文件。 大! 我们已经在计算机上拥有自己的Pod。 还不错吧? 接下来,我们将其连接到GitHub并将其代码疯狂发布! 🐯 将您的CocoaPod上载到GitHub 首先登录GitHub.com上的帐户 通过单击屏幕右上方的➕图标来创建新存储库。 您可以为其指定名称,描述,并决定是否向公众开放。 您还应该选择一个许可证。 最常见的是开放源代码的MIT(可以在这个恰当命名的网站上找到有关选择许可证的更多信息)。 接下来,我们将创建一个.podspec文件。 在终端的CocoaPod文件夹中输入以下代码行: podSpec文件中要求提供很多信息,但至少您的文件应包含您Pod的名称,版本,首页(其Github地址),其来源(通常是带有.git附件的Github地址),许可证以及所有其他依赖项的摘要和列表(例如,如果您使用的是Alamofire)。 使用语义版本控制显示版本,其中每个数字代表发行版本。 从技术上讲,第一个应写为0.1.0(代表重大更改。较小更改。补丁编辑)。 最后,您需要以正确的格式‘name.h,m’列出您的源文件。 如果其中任何一项在远程造成混淆,那么CocoaPods就它们在podSpec文件中寻找的内容而言非常有用。 还在我这儿? 挂在那里,您几乎成功了! 是时候画龙点睛了-推动IT生存!!! 再一次在Terminal中找到项目的文件夹,然后输入以下几行代码: 瞧! […]

单元测试和使用旧版代码

关于编写好的软件以及当您想要添加或删除功能时如何重构代码库的文章很多,但是大多数现有文献在示例中都使用C或Java。 在这里,我将尝试展示iOS开发人员如何使用XCTest来帮助维护旧版Swift代码。 什么是旧代码? 旧版代码基本上是任何现有代码-不管它有多旧。 但是它越老,即使您写了它,也不太可能熟悉它。 并且您希望能够对其进行修改,并且不会破坏现有功能。 我们要达到什么目标? 有很多原因需要接触遗留代码,但是它们通常分为以下几类: 修正错误 由于业务规则的改变而改变行为 扩展功能以支持新功能 如果幸运的话,我们不需要进行任何重大更改即可执行上述任何操作,但是通常我们需要重构代码以实现我们的目标。 这可能很简单,例如花费几行代码并将其提取到一个单独的函数中,或者复杂到将一个对象分解为几个单独的对象,从而导致无论从何处调用旧代码,都需要对整个代码库进行更改。 问题是,我们不想引入任何错误,除非我们对应用程序非常熟悉,或者代码库非常简单,否则我们很可能会破坏某些东西。 单元测试是我们的朋友 在更改任何代码之前,重要的是要确保我们先了解应用程序的功能,并知道更改代码后是否已更改该功能。 为了让我演示单元测试如何提供帮助,让我们想象一下我们有一个应用程序可以在UILabel中显示人员的姓名和地址。 我们将有一个简单的Person对象和一个带有返回标签文本的单个函数的视图模型。 Itty Bitty Apps 总部位于澳大利亚墨尔本, 为大小客户提供了出色的移动和Mac软件。 这也使 揭示   -适用于iOS开发人员的功能强大的运行时视图调试。

如何在Xcode 10中制作Vapor 3 Swift Playground

当您想学习新东西时,更好的学习机会就是尝试它。 这来自我们的童年。 Vapor是Swift编程语言的框架,旨在简化服务器应用程序。 该框架使用现代的编程模式,并利用了Apple的低级非阻塞和事件驱动IO库,称为SwiftNIO。 SwiftNIO&Vapor使用并发编程技术以及诸如Future和Promise之类的抽象。 为了深入理解,我需要触摸它。 因为如此简单,我决定制作Swift游乐场! 让我们先安装Vapor。 您可以使用自己的文档进行此操作: macOS –蒸气安装 docs.vapor.codes SwiftNIO被安装为依赖项。 让我们创建沙盒项目: $ vapor new Sandbox $ cd Sandbox && vapor xcode vapor将创建初始项目结构,并将生成.xcodeproj文件。 最后,它将询问您是否打开Xcode。 点击“ y” 您必须看到类似以下内容: 看起来不太友善,是吗? 让我们打开Project Navigator: 现在,更清楚了什么是内幕。 让我们去游乐场玩吧。 首先从项目中创建Xcode工作区: 称之为沙箱。 现在,在Workspace内部但在Sandbox项目外部创建Playground。 最小化Sandbox项目文件夹,然后右键单击Project导航器中的任何空白点: 选择“新建文件”,然后在弹出的窗口中选择“空白操场”。 留下MyPlayground作为名称或选择自己的名称: 瞧! 现在我们必须导入我们的模块:Vapor和ORM,它们在此模板项目FluentSQLite中被调用。 在将模块导入操场之前,我们必须先构建它们。 我们开始做吧: Xcode将构建运行方案,该方案还将构建所有基础依赖项。 现在我们可以将所需的模块导入到我们的游乐场。 这样做并按Run(运行)—代码左侧的“播放箭头”: 底部有错误。 该怎么办? 导致此错误的原因是,依赖项中存在的C框架(例如CNIOAtomics)不在Xcode的Framework系统文件夹中。 Xcode保留有关头文件的信息,并根据此信息使其成为内部符号查找表。 该文件夹的位置是$(PLATFORM_DIR)/Developer/Library/Frameworks,在我的系统(Mojave 10.14.1)中,该文件夹代表/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks 我们必须为所有C模块依赖项创建伪造的框架文件夹。 让我们从CNIOAtomics开始: […]

iOS-在Swift中进行重构:标识符!

更新(2018年12月): 向Mark Moeykens大喊大叫,他制作了一段受本文启发的视频:https://www.youtube.com/watch?v=6Om91KRQCiM&feature=youtu.be。 他在自己的YouTube频道上有一些有关iOS开发的精彩内容,如果你们喜欢这个,那么您绝对应该检查一下该频道。 在制作iOS应用程序时,我们需要一些标识符,例如可重用的UITableViewCells或UICollectionViewCells ,segues, UIStoryboards , UIViewControllers等。我们如何管理所有这些在源代码中只是字符串的标识符? 作为一个初学者(一年前),我的方法是简单地跟踪UI组件并将标识符复制并粘贴到我需要的位置。 但是,我很快意识到,随着应用程序的扩展,这种方法会使我的生活变得更加艰难,而且我还有更多的选择, UIViewControllers , UIStoryboards等。如果您在团队中工作,那么我强烈建议重构标识符! 1. UITableViewCells和UICollectionViewCells标识符: 本部分介绍了可重用的单元格,该单元格需要一个标识符来重用并将其注册到相应的容器视图,即UITableView或UICollectionView 。 当您创建一个新的自定义类时(我以UICollectionViewCell为例,它应该对UITableViewCell应用相同的方式),它看起来像这样: 现在,我们更新自定义单元格类以包含静态常量。 该名称具有名称标识符并存储我们的标识符,在本例中为MyCell 。 该行看起来像这样…… static let identifier = “MyCell” 。 但是,如果它与类名相同,那么我认为我们可以做得更好。 我们可以使用描述性的String初始值设定项来获取类的名称…… static let identifier = String(describing: MyCell.self) 。 如果我们使每个自定义单元格的标识符与类名相同,那么我们可以通过扩展UICollectionViewCell和UITableViewCell类来进一步泛化它! 我知道命名单元标识符与类名称相同可能会有例外。 这是我针对该异常的解决方案,而不是使标识符成为static var而不是使其成为static var class var ,这为我们提供了在自定义单元格类中覆盖identifier变量并分配自定义String的优势。 这增加了一个额外的步骤,但是我们仍然享受自动完成的好处。 更新后的代码如下所示: 此方法使源代码中没有字符串,可以帮助开发人员利用自动完成功能,并且易于维护和更新。 下一步:Segue标识符。 2. Segue标识符 这种类型的标识符非常凌乱,并且随着项目的扩大而变得非常混乱。 将标识符从相同的UIViewController重复到不同的UIViewControllers是非常容易的,尤其是当您在更大的团队中工作时。 此外,四处查看您的源代码并检查我们是否已经使用了标识符很不方便。 […]

不起眼的TableView

我最近一直在考虑表视图。 表视图和集合视图已成为为许多类型的应用程序(尤其是内容驱动的应用程序)构建UI的默认方法。 但是,随着我们的表格视图变得越来越复杂,很难测试它们是否显示了正确的内容。 我认为创建可测试表的许多困难源于一种模式,在这种模式下,我们具有描述应用程序域的模型对象,然后尝试将其显示在表中。 尽管这些模型完美地描述了应用程序域的特定问题,但它们可能无法完全描述我们要在特定表单元格中显示的内容。 让我们看一个例子,然后看看如何改进。 我将使用表视图,因为它稍微简单一些,但是您也可以将这些技术应用于集合视图。 您的应用程序中可能有一些模型对象,它们描述了您的应用程序所关注的领域。 例如,如果您制作一个社交应用程序,则可能具有User , Friend和Message对象。 您可能是通过从api获得的Json表示形式创建对象来获得这些对象的,并在整个应用程序中使用它们来对应用程序的域进行建模。 在我们的示例中,我们可以想象一个音乐流应用程序,其中有一个特定艺术家的屏幕,其中显示了可以为该艺术家播放的所有曲目。 我们可能已经有一个域对象Track ,因此我们可以获取艺术家的所有Track ,并在表中显示它们: struct Track { let id:字符串 让标题:字符串 持续时间:双倍 让streamURL:URL } TrackCell类:UITableViewCell { func configure(track:Track){ //用轨道配置单元格 } } 好吧,还不错! 当用户打开艺术家页面时,我们将从MusicAPI获取Track ,并将其显示在表格中。 然后,该单元格可以显示曲目标题和持续时间,并且当用户按下播放时,我们可以开始流式传输。 通过此设置,我们直接从域模型( Track )转到UITableViewCell 。 但是,当我们必须在单元格中显示Track对象未描述的信息时,该策略就会Track 。 假设我们有一个新的要求–我们的应用程序现在可以下载轨道,并且需要在列表中显示每个轨道的下载状态。 我们的用户界面将如下所示。 在此示例中,已下载了第三首曲目,而其他未下载。 不幸的是,我们的Track模型现在无法完全描述TrackTableViewCell需要了解的所有内容。 我们是从MusicAPI获取Track的,但是我们需要参考DownloadsManager来确定是否在本地下载了轨道。 也许我们可以在创建单元格并将其分别传递给下载状态时调出给DownloadsManager ,甚至可以从单元格内部调用它,如下所示: TrackCell类:UITableViewCell { func configure(track:Track){ //用轨道配置单元格 downloadIcon.showDownloaded […]

练习“在Swift中面向协议编程”的简单代码

这篇文章是使用协议,协议继承,结构和委托针对POP“面向协议的编程”的快速入门。 该样本将为申请大学提供一个简单的过程。 步骤如下: 创建项目后,添加一个名为“ Person.swift”的新文件。 步骤1:创建一个名为Person的协议: 协议人{ var firstName:字符串{获取设置} var lastName:字符串{获取设置} init(fName:String,lName:String) func getFullname()->字符串 } 步骤2:创建从称为“申请人”的人员继承的协议: 协议申请人:{ var email:字符串{获取设置} var grade:浮动{get set} } 步骤3:创建从申请人继承的协议,该协议称为Student: 协议学生:申请人{ var studentId:字符串{获取设置} var dateOfStar:日期{get} } 步骤4:创建一个名为WelcomeMessageDelegate的协议。 此功能将处理视图上显示的结果。 协议WelcomeMessageDelegate { func displayNameDelegate(消息:字符串) } 步骤5:创建注册结构。 除了编写上述函数,我们还需要一个init函数。 Xcode将帮助您编写根据上述步骤定义的所有属性。 结构注册:学生{ init(fName:String,lName:String){ self.firstName = fName self.lastName = lName self.email =“” self.grade = 0.0 self.studentId =“” […]

自动关闭,作为参数的关闭,尾随关闭和Swift开罗

您可能要略过,这只是一个介绍。 我一直在与一个我要在开罗建立的新社区进行在线课程:Cairo-Swift,并且我们一直在进行在线活动,以阅读一个开源项目并了解其来龙去脉,所以每个人可以从该项目及其构建过程中学到一些东西。 该建议是由我们的一位成员提出的,因为她受到这次演讲的启发:https://www.youtube.com/watch?v = mW_xKGUKLpk 我自己没想到它会这么有用,我真的很感谢迄今为止的进展以及我们每周要经过的信息和搜索量,而这个博客确实是其中的一项特权! 我自己选择了要进行的第一个项目,因为我们是聚会,所以我选择了trySwift的聚会应用,这是一个很好的灵感,也许我们迟早可以为我们的社区构建类似的东西! 通过代码,我们发现了重复的代码,我建议我们可以通过使用泛型来将其修改为更好的版本,我最近一直在与他们一起玩,并且有点像锤子一样使用它,所以让我们看看它在哪里走! 基本代码是: func showAbout(){让aboutViewController = AboutTableViewController()performSegue(withIdentifier:moreDetailSegue,发件人:aboutViewController)} webViewController = WebDisplayViewController()webViewController.url = URL(字符串:conference.codeOfConductURL)! webViewController.displayTitle =“行为准则”。localized()performSegue(withIdentifier:moreDetailSegue,发送者:webViewController)} func showOrganizers(){让organizerViewController = OrganizersTableViewController()performSegue(withIdentifier:moreDetailSegue,发送者:organizerViewController)} func showLibraries() {let path = Bundle.main.path(forResource:“ Pods-trySwift-acknowledgements”,ofType:“ plist”)let ConfirmationesViewController = AcknowListViewController(acknowledgementsPlistPath:path)ConfirmationesViewController.edgesForExtendedLayout = [] confirmmentesViewController.headerText =“我们❤️打开源代码软件”。localized()performSegue(withIdentifier:moreDetailSegue,发送者:confirmationesViewController)} 你能发现吗? 这是使用特定控制器和String ID执行segue的重复代码,因此让我们将其转换为通用函数吗? func navigationTo (_ withType:T.Type,id:String =“ moreDetailSegue”){ performSegue(withIdentifier:id,发件人:T()) } //称呼它 navigationTo(UIViewController.self) 最初,我尝试使用T.initialize()碰壁,这是通过Xcode自动完成来完成的,而.init()甚至simple()根本不显示,花了大约15分钟的时间来尝试找出问题所在用我的代码,我去看了关于该功能的苹果文档,但我完全不了解。 只是一个奇怪的函数,不会像我想的那样初始化! 上面的函数将摆脱上面的几个函数,并保留最后两个,那么我们如何改进呢? […]

后台音频播放器同步控制中心

在本教程中,您将创建一个能够在后台模式下播放音频并与Control Center中的音乐控件同步的播放器。 特征: 播放声音文件。 使声音在后台模式下继续播放。 从控制中心控制音频。 处理完成。 处理中断。 处理路线更改。 如果您遇到任何问题,可以在这里下载完整的源代码项目,然后再使用每个功能。 1.播放声音文件 要播放声音文件,您需要初始化播放器。 阅读以下文章以了解有关AVAudioPlayer的信息: AVAudioPlayer 音频播放器,可播放文件或内存中的音频数据。 将以下块代码添加到视图控制器中以初始化播放器: 您还需要准备一个mp3文件进行测试。 要播放mp3文件,请按如下所示调用play()方法: player.play() 现在,您可以从导入的文件中听到声音。 但是,当您按“主页”按钮将应用程序移至背景模式时,声音已被静音。 因此,我们需要让它在下一指南中继续在后台模式下播放。 2.使声音在后台模式下继续播放 要使声音在后台模式下继续播放,您需要阅读以下文章: AVAudioSession 与系统通信的中介对象,您打算如何在应用程序中使用音频。 启用背景音频 配置您的应用,使其在进入后台时继续播放音频。 如下替换AppDelegate.swift文件的application(_:didFinishLaunchingWithOptions:)方法以配置音频会话: 现在运行该应用程序,播放声音,然后按“主页”按钮将应用程序移至背景模式,并检查声音是否仍继续播放。 3.从控制中心控制音频 阅读以下文章,了解如何从“控制中心”和“ iOS锁定”屏幕控制背景音频: 控制背景音频 支持从控制中心和iOS锁定屏幕控制背景音频。 将以下方法添加到视图控制器中,并从viewDidLoad()方法调用setupRemoteTransportControls() , setupNowPlaying() viewDidLoad()方法: 现在运行该应用程序,打开“控制中心”并进行检查。 4.处理完比赛 音频播放器播放完毕后,您需要更新nowPlayingInfo和UI。 要接收此事件,您需要实现AVAudioPlayerDelegate协议的audioPlayerDidFinishPlaying(_:successfully :)方法,并如下更新setUpPlayer()方法: 运行该应用程序并进行检查。 5.处理中断 在后台模式下播放时,如果打来电话,则声音会静音,但在挂断电话时,声音不会自动继续播放。 因此,我们需要阅读以下文章来处理这些中断事件: 响应音频会话中断 直接观察音频会话通知,以确保您的应用响应中断。 在中断结束时添加以下代码片段以自动播放: 现在运行该应用程序并进行测试。 6.处理路线变更 现在,当您将耳机插入手机时,声音将在耳机上发出。 但是当您拔下耳机插头时,声音会自动继续在内置扬声器上播放。 […]