版本记录
| 版本号 | 时间 |
|---|---|
| V1.0 | 2021.03.22 星期一 |
前言
QuickLook框架提供了文档的预览功能。接下来几篇我们就一起看一下这个框架。感兴趣的可以看下面几篇。
1. QuickLook框架详细解析(一) —— 基本概览(一)
2. QuickLook框架详细解析(二) —— QuickLook 预览简单示例(一)
3. QuickLook框架详细解析(三) —— QuickLook 预览简单示例(二)
开始
首先看下写作内容:
了解如何构建自己的
Quick Look预览和缩略图扩展名以在iOS中显示自定义文件类型。内容来自翻译。
下面就是写作环境:
Swift 5, iOS 14, Xcode 12
接着就是正文啦。
您可能会发现自己想要在应用程序中显示文件的缩略图,或者甚至想要显示文件本身的更丰富的预览。 幸运的是,QuickLook框架使您可以轻松生成缩略图并显示许多标准文件类型的预览。

虽然这对标准文件类型非常有用,但是如果您的应用程序专注于QuickLook不能涵盖的特定文件类型,该怎么办?好吧,不要害怕。借助iOS 13中引入的Quick Look previews和thumbnail extension点,您可以在自己的应用程序以及也使用QuickLook的同一设备上的任何其他应用程序中为自定义文件类型提供自定义预览和缩略图。
注意:您会看到两种形式的间距形式,都用于后端QuickLook framework(不带空格)和面向用户的Quick Look(带空格)。名称中的空格规则似乎很复杂,因此我们努力做到平衡。
在本教程中,您将学习如何:
- 使用
QLThumbnailGenerator生成缩略图 - 为您的自定义文件格式定义并导出您自己的
document type - 构建自己的
Quick Look preview extension - 构建自己的
Thumbnail extension - 调试您在扩展
extension程序中运行的代码
为此,您将使用RazeThumb,该应用程序显示文件列表并在点按时显示每个文件的Quick Look预览。您将增强该应用程序,以使用QuickLook显示代表列表中每个文件的缩略图。最后,您将为您的自定义.thumb文件类型添加Quick Look preview extension 和 Thumbnail extension,并在app和Files应用程序中看到它。
打开下载项目材料。然后在启动程序文件夹中打开RazeThumb.xcodeproj。
RazeThumb是一个简单的文档浏览应用程序。它预装了各种包含缩略图的文件类型。六种格式中的五种是标准文件类型。第六种是自定义文件类型,称为.thumb文件。
构建并运行:

该应用程序显示六种不同文件类型的列表,每种文件类型均带有一个占位符文档图标。 轻按每个文件将显示QLPreviewController,它显示文件的预览。 这就是目前所做的全部,但是您将在不断改进该应用程序。
Adding Quick Look Thumbnails
您要做的第一件事就是增强RazeThumb,以使用每种文件类型的缩略图。 当前,RazeThumb为每个文件显示一个通用文档图标。 QuickLook框架为各种文件类型提供缩略图,包括图像,PDF,音频和视频。 请查看Apple的文档Apple’s documentation,以获取有关Apple支持的其他文件类型的更多详细信息。 如果QuickLook无法识别文件类型,它仍会创建某种占位符缩略图。 将缩略图添加到应用后,您将学到更多有关此的知识。
现在,是时候开始修饰RazeThumb了。

打开Document.swift并将import Foundation更改为:
import QuickLook
在文件底部,粘贴以下扩展名:
// MARK: - QLThumbnailGenerator
extension Document {
func generateThumbnail(
size: CGSize,
scale: CGFloat,
completion: @escaping (UIImage) -> Void
) {
if let thumbnail = UIImage(systemName: "doc") {
completion(thumbnail)
}
}
}
上面的代码是异步缩略图生成方法的占位符。 现在,它返回文档系统图标的UIImage。 稍后,您将替换为对QuickLook框架的请求以生成缩略图。
接下来,打开DocumentThumbnailView.swift并将以下代码直接粘贴到.groupBoxStyle(PlainGroupBoxStyle())下面:
.onAppear {
document.generateThumbnail(
size: thumbnailSize,
scale: displayScale
) { uiImage in
DispatchQueue.main.async {
self.thumbnail = Image(uiImage: uiImage)
}
}
}
上面的代码等待视图出现。 然后,它要求为每个文件提供缩略图UIImage。 UIImage到达后,视图将使用主线程更新SwiftUI图像Image。 这是所有用户界面更新所必需的。
构建并运行:

您会看到每个文件的文档图标现在要小得多。 这是因为您没有调整图像的大小。 但是很快,QuickLook框架将为您处理大小调整。
1. Generating a Quick Look thumbnail
要从QuickLook框架中获取缩略图,您需要使用QLThumbnailGenerator创建一个QLThumbnailGenerator.Request并执行请求。 再次打开Document.swift,并用以下代码替换generateThumbnail(size:scale:completion :)的内容:
// 1
let request = QLThumbnailGenerator.Request(
fileAt: url,
size: size,
scale: scale,
representationTypes: .all)
// 2
let generator = QLThumbnailGenerator.shared
generator.generateRepresentations(for: request) { thumbnail, _, error in
// 3
if let thumbnail = thumbnail {
print("\(name) thumbnail generated")
completion(thumbnail.uiImage)
} else if let error = error {
print("\(name) - \(error)")
}
}
在上面的代码中,您将执行以下操作:
- 1) 使用视图提供的大小和比例以及定义的表示形式类型,创建一个新的
QLThumbnailGenerator.Request。 可用的表示形式为.icon,.lowQualityThumbnail和.thumbnail。 在这种情况下,您需要全部请求并使用最佳选择。 如果使用所有格式的速度太慢,则可以指定一种格式。 - 2) 使用
.shared生成器,您可以启动请求并等待提供缩略图。 - 3) 如果
generator在完成闭包中传递了图像,则将其传递回视图。 如果收到错误,请打印错误消息。 请记住,generator最多可以返回三个不同的图像,因为该请求适用于所有表示形式。
构建并运行:

现在,您将看到每种文件类型的缩略图。 不幸的是,QuickLook对.thumb文件一无所知,因此其缩略图为空白。
2. Searching messages printed in the Console
现在,查看“调试”区域中的消息。 每个缩略图有三种可能的表示形式,因此控制台中针对每个显示的文档有三则消息。
在“调试”区域右下角的Filter字段中,键入.html。 您会看到三则消息 —— 一则消息显示缩略图已生成,两则消息显示失败。 这是正常现象,在要求所有表示时您可以忽略这一点。 要求所有表示的好处是您将获得至少一个可以使用的代表。

现在删除.html并输入.pdf。 对于PDF文件,QuickLook生成了两个缩略图。 DocumentThumbnailView显示占位符文档图标,然后使用生成的缩略图对其进行两次更新。 使用所有表示形式的权衡是多次更新视图的额外工作。
替换.pdf并键入.thumb。 尽管QuickLook对缩略文件一无所知,但它至少为您提供了一个缩略图,尽管它是空白的。
现在,花点时间检查框架生成的不同缩略图。 文件zombiethumb.jpg,humanthumb.pdf和thumbsup.txt生成了文件内容的精美缩略图。 Markdown文件thumbsdown.md的缩略图以文本形式呈现,因为该框架不支持Markdown展示。

thumbsdown.html文件将一个通用的HTML图标作为其缩略图,因为框架设计者认为渲染HTML以生成实际的缩略图效果不佳。
最后,您已经发现,greenthumb.thumb缩略图是空白图像。但是不用担心;您将很快解决该问题。
生成缩略图,给自己一个很大的“竖起大拇指”。接下来做下一个事情。
Defining and Exporting a Document Type
那么,为什么.thumb文件没有缩略图?好吧,第一个问题是系统不知道如何将此文件扩展名映射到文档类型。系统使用Uniform Type Identifiers定义已知的数据格式,同时还允许您定义自己的专有格式,例如.thumb。您可以按照相同的步骤在将来的项目中实现新的文件类型。
1. Defining a Document Type
请按照以下步骤定义新的文档类型:
- 在项目导航器中,选择顶部的
RazeThumb项目图标。 - 在
Targets下选择RazeThumb target。 - 选择
target上方的Info标签。 - 单击
Document Types旁边的显示三角形以展开该部分。 - 显示时单击
+。

使用以下详细信息填写新的文档类型:
- 将
Name设置为Thumb File。 - 将
Types设置为com.raywenderlich.rwthumbfile。 - 将
Handler Rank设置为Owner,因为此应用是该文件类型的所有者。 - 单击显示
Click here to add additional document type properties。 - 将
Key设置为CFBundleTypeRole。 - 将
Type保留为String。 - 输入编辑器的值
Value。
查看您的设置。 它们应符合以下显示的内容:

2. Exporting a Document Type
既然您已经告诉系统您的应用拥有.thumb文档类型,则需要将其导出,以便其他应用可以识别.thumb文件。 这是执行此操作的步骤:
- 单击
Exported Type Identifiers旁边的显示三角形。 - 点击显示的
+。 - 对于
Description,键入Thumb File。 - 对于
Identifier,键入com.raywenderlich.rwthumbfile - 对于
Conforms To,键入public.data,public.content。 - 对于
Extensions,键入thumb,这是此新文件类型的文件扩展名。
仔细检查您的设置是否符合以下显示的内容:

构建并运行

在缩略图上查看greenthumb.thumb。 通过添加和导出文档类型信息,您使iOS知道了.thumb文件类型。 默认情况下,QuickLook框架会将应用程序图标(如您在主屏幕上看到的那样)用作缩略图,因为此应用程序拥有该文件类型。 因此,RazeThumb应用程序图标现在显示为系统上所有.thumb文件的缩略图。 再给自己竖起大拇指!
Quick Look Extensions
因此,现在RazeThumb使用QuickLook框架为每个文件提供缩略图,如果您一个一个地点击每个文件,您还将看到每个文件的丰富预览,直到进入greenthumb.thumb为止:

现在该看看如何利用iOS 13中引入的新扩展点来改善.thumb文件的使用体验。
1. Adding a Quick Look preview extension
Quick Look预览扩展程序使您的应用程序可以使用完全自定义的视图控制器替换上述无聊的预览。 RazeThumb不仅可以利用您的扩展名,而且使用已安装的扩展名预览.thumb文件,所有安装的其他应用程序都将受益。
要将扩展添加到项目中,请按照下列步骤操作:
- 在项目导航器中选择
RazeThumb项目。 - 在列出
Targets的窗口底部,单击+图标。 - 在
Preview中键入Filter。 - 双击
Quick Look Preview Extension,并将其命名为ThumbFilePreview。 - 单击
Finish。 - 如果出现提示,请不要立即激活新的
ThumbFilePreview scheme。

RazeThumb应用程序的Sources文件夹中有两个文件,您的新扩展程序将在生成预览时使用这些文件。 您将使用ThumbFile.swift来加载Thumb文件,并使用ThumbFileViewController.swift将ThumbFile的实例作为预览呈现。
为确保这些文件也包含在新创建的ThumbFilePreview target中,请按照下列步骤操作:
- 在
Project navigator中选择ThumbFile.swift。 - 打开
Xcode右侧的Inspectors,然后单击文档图标以显示File inspector。 - 在
Target Membership部分下,选中该框以将文件包括在ThumbFilePreview和RazeThumb目标中。 - 在项目导航器中选择
ThumbFileViewController.swift,然后重复上述步骤以再次更Target Membership资格。

在项目导航器中,展开新的ThumbFilePreview组。 Xcode添加了名为PreviewViewController.swift,MainInterface.storyboard和Info.plist的文件。 这些是构成扩展名的文件。
2. Invoking a Quick Look Preview Extension
现在,要正确调用扩展程序,您需要将其与.thumb文件类型相关联。 为此,请按照以下步骤操作:
- 打开
ThumbFilePreview / Info.plist。 - 通过按住
Option键单击旁边的显示三角形,展开NSExtension条目及其所有子条目。 - 将鼠标悬停在
QLSupportedContentTypes上,然后单击出现的+,在其下方添加一个项。 - 将
Item 0设置为String,并为其赋予com.raywenderlich.rwthumbfile值,该值与您之前添加的文档类型标识符匹配。

现在,系统知道何时调用您的扩展程序,您需要自定义扩展程序提供的预览。 打开PreviewViewController.swift并将其内容替换为以下内容:
import UIKit
import QuickLook
// 1
class PreviewViewController: ThumbFileViewController, QLPreviewingController {
// 2
enum ThumbFilePreviewError: Error {
case unableToOpenFile(atURL: URL)
}
func preparePreviewOfFile(
at url: URL,
completionHandler handler: @escaping (Error?) -> Void
) {
// 3
guard let thumbFile = ThumbFile(from: url) else {
handler(ThumbFilePreviewError.unableToOpenFile(atURL: url))
return
}
// 4
self.thumbFile = thumbFile
// 5
handler(nil)
}
}
这是您在上面的代码中所做的事情:
- 1) 不是从
UIViewController继承,而是从ThumbFileViewController继承,ThumbFileViewController是已经知道如何通过分配thumbFile属性来显示ThumbFile的视图控制器。 - 2) 声明一个简单的错误类型,该错误类型可以通知
QuickLook加载失败。 - 3) 在
preparePreviewOfFile(at:completionHandler :)内部,尝试从指定位置加载ThumbFile,并在失败时返回错误。 - 4) 更新视图控制器以显示刚刚加载的缩略图。
- 5) 通过传递
nil错误,通知提供的处理程序预览已成功完成加载。
最后,在再次运行该应用程序之前,打开ThumbFilePreview / MainInterface.storyboard并删除默认情况下添加的“Hello World”标签。
构建并运行,然后单击greenthumb.thumb以调用您的扩展程序:

恭喜你!由于上述工作,QuickLook框架可以加载您的扩展名并生成.thumb文件的更好预览。再给自己竖起大拇指!
3. Adding a Thumbnail Extension
现在RazeThumb可以渲染一个thumb文件了,是时候从该渲染中生成缩略图了。为此,您可以通过将缩略图扩展名添加到项目中的方式,类似于添加最后一个扩展名的方式。
QuickLook框架使用缩略图扩展名来创建自定义文件类型的缩略图,然后通过QLThumbnailGenerator将其返回到RazeThumb以及设备上的任何其他应用程序。首先,请按照以下步骤添加下一个扩展名:
- 在
Project navigator中选择RazeThumb项目。 - 在列出
Targets的窗口底部,单击+图标,然后在Filter中键入Thumbnail。 - 双击
Thumbnail Extension,并将其命名为ThumbFileThumbnail。 - 单击
Finish。 - 如果出现提示,请不要立即激活新的
ThumbFileThumbnail scheme。

在Project navigator中,展开新的ThumbFileThumbnail组。Xcode已添加ThumbnailProvider.swift和Info.plist。这些是构成扩展名的文件。
4. Invoking a Thumbnail extension
为了调用Thumbnail扩展名,您需要将此缩略图扩展名与.thumb文件类型相关联,就像使用预览扩展名一样。
- 打开
ThumbFileThumbnail扩展文件夹中的Info.plist文件。 - 通过按住
Option键单击旁边的显示三角形,展开NSExtension条目及其所有子条目。 - 将鼠标悬停在
QLSupportedContentTypes上,然后单击出现的+,在其下方添加一个item。 - 将
Item 0设置为String,并为其赋予com.raywenderlich.rwthumbfile值,该值与您之前添加的文档类型标识符(document type identifier)匹配。 - 可选,您还可以使用
QLThumbnailMinimumDimension为缩略图指定最小尺寸(以点为单位)。如果缩略图在Internet浏览器选项卡中显示为像收藏夹中的小图标,则您可能想使用缓存的缩略图(例如默认的应用程序图标),而不是生成的缩略图(例如markdown文字),因为缩略图可能太复杂而无法识别小尺寸。在此应用中,您将不会使用最小尺寸功能。

与ThumbFilePreview target目标一样,ThumbFileThumbnail target也将使用ThumbFile.swift和ThumbFileViewController.swift。 按照之前的相同步骤,在Project navigator中选择两个快速文件,并通过在File inspector中选中相应的复选框,将其target memberships更新为包括ThumbFileThumbnail。
接下来,打开ThumbnailProvider.swift并将文件内容替换为以下内容:
import UIKit
import QuickLookThumbnailing
class ThumbnailProvider: QLThumbnailProvider {
// 1
enum ThumbFileThumbnailError: Error {
case unableToOpenFile(atURL: URL)
}
// 2
override func provideThumbnail(
for request: QLFileThumbnailRequest,
_ handler: @escaping (QLThumbnailReply?, Error?) -> Void
) {
// 3
guard let thumbFile = ThumbFile(from: request.fileURL) else {
handler(
nil,
ThumbFileThumbnailError.unableToOpenFile(atURL: request.fileURL))
return
}
// 4
DispatchQueue.main.async {
// 5
let image = ThumbFileViewController.generateThumbnail(
for: thumbFile,
size: request.maximumSize)
// 6
let reply = QLThumbnailReply(contextSize: request.maximumSize) {
image.draw(in: CGRect(origin: .zero, size: request.maximumSize))
return true
}
// 7
handler(reply, nil)
}
}
}
这里涉及一些步骤:
- 1) 定义一个简单的错误类型,如果需要,可以将任何失败描述回
QLThumbnailProvider。 - 2) 覆盖
ProvideThumbnail(for:_),以便您可以加载ThumbFile并为QuickLookThumbnailing框架呈现其缩略图。 - 3) 尝试失败时尝试加载
ThumbFile并使用错误调用处理程序。 - 4)
QuickLookThumbnailing框架在后台线程上调用此方法。但是为了在屏幕上绘制用户界面,您必须位于主线程中。 - 5) 使用
ThumbFileViewController中的一些现有代码,使用正确的尺寸构造预览的UIImage表示形式。 - 6) 使用生成的缩略图,创建一个
QLThumbnailReply对象,该对象将图像缩略图绘制到提供的上下文中。 - 7) 使用回复对象和
nil错误来调用处理程序,以指示成功。
注意:在此示例中,您调度到主队列,因为
ThumbFileViewController.generateThumbnail(for:size :)在内部使用UIGraphicsImageRenderer(需要使用主线程)。在其他情况下,您可能直接使用其他绘图API(例如CoreGraphics),则可能不需要这样做。
构建并运行。现在,您应该会看到greenthumb.thumb的缩略图,看起来像是预览的微型版本。

祝贺您两个伟大的大拇指! RazeThumb应用程序已完成。
Trying Out Your Extensions Using the Files App
现在,您已经为.thumb文件创建了预览扩展名和缩略图扩展名,其他应用程序将可以使用该文件类型。在本部分中,您可以通过向模拟器添加.thumb文件并使用Files应用程序浏览到该文件来表明扩展程序支持其他应用程序。
以下是将缩略图文件添加到模拟器的步骤:
- 1) 从模拟器中删除
RazeThumb。这是因为模拟器会在收到拇指文件后启动RazeThumb,但RazeThumb不会保存文件。将文件复制到模拟器后,您将重新安装该应用程序。 - 2) 将
greenthumb.thumb从Xcode或Finder拖到模拟器应用程序中。这将打开Files应用程序以导入文件。选择将文件保存在On My iPhone上。 - 3) 点击
Save返回浏览。 - 4) 如果选择了
Recents选项卡,请依次单击Browse和On My iPhone以查看刚添加的文件。
由于您删除了RazeThumb,因此您将不会看到缩略图,并且如果打开文件,则不会看到预览。
在Xcode中,构建并运行RazeThumb以将其重新安装到模拟器上。安装RazeThumb将重新建立缩略图文件和RazeThumb之间的关联。这是因为RazeThumb包括缩略图文件的预览和缩略图扩展名。
在模拟器中打开Files应用程序:

点按On My iPhone,您将看到缩略图文件的渲染缩略图。点击greenthumb.thumb,文件将呈现其预览,就像在RazeThumb应用程序中一样。多么酷啊?
Attaching the Debugger to Your Extension
Quick Look预览扩展和缩略图扩展过程与主应用程序分开运行。它们一起安装时,它们是完全隔离的,这使系统可以在Quick Look框架中有效地使用它们,以在设备上安装的其他应用程序中生成预览和缩略图。
在开发扩展程序时,您可能需要设置一个断点并查看其执行过程,但是由于Xcode调试器只能附加到一个进程一次,因此必须决定是否将调试器附加到您的应用程序或者扩展中。
注意:在撰写本文时,在扩展中设置断点时,
Xcode调试器似乎无法正常工作。一些断点似乎会导致运行循环run loop崩溃。其他时候,调试器似乎失去了与扩展的连接。您可能必须尝试几次此练习。
首先在ThumbnailProvider.swift文件中,在ProvideThumbnail(for:_ :)的开头guard let thumbFile = ThumbFile(from: request.fileURL)语句处设置一个断点。

如果您构建并运行RazeThumb并滚动直到greenthumb.thumb可见,您会注意到调试器不会在断点处停止。 不要惊慌。 您可以解决该问题。
单击scheme selector中的RazeThumb以查看带有可用schemes列表的下拉列表。 选择ThumbFileThumbnail作为scheme,然后单击Run。 当提示您选择要启动的应用程序时,选择RazeThumb并滚动直到greenthumb.thumb可见。 这次,调试器应在断点处停止。

为了获得更多乐趣,请重新运行ThumbFileThumbnail scheme,而不是选择Files应用程序以查看您的代码在其他应用程序中运行!
您现在已经了解了如何为受支持的文件类型和自定义文件类型创建Quick Look缩略图和预览。
以下是您在此过程中涉及的一些关键点:
- 缩略图是文件内容的缩影。
-
QuickLook框架可以为各种标准文件类型(例如图像,音频,视频,文本,PDF等)创建缩略图和预览。 - 使用扩展名,您可以扩展
QuickLook框架以支持您自己的自定义文件类型。 - 扩展程序允许设备上的所有应用程序访问其功能。
- 扩展程序与应用程序分开运行。
- 您可以在开发过程中将
Xcode调试器附加到扩展程序。
如果您想了解更多信息,可以探索许多相关主题:
- 您可以在QuickLook Thumbnailing和WWDC 2019 Quick Look Previews from the Ground Up深入研究苹果文档。两者都提供了对可能性的更多见解。
- 在 QuickLook Previews for iOS: Getting Started中了解有关文档预览的更多信息,其中涵盖了编辑工具和缩放过渡以及预览的其他功能。
- 基于文档的应用程序使用自定义文件类型,您可以在 Document Based Apps Tutorial: Getting Started中探索有关如何定义自定义文件类型并使用它们的更多信息。
- 在Apple Developer网站上查看
Apple提供了哪些其他扩展。
后记
本篇主要讲述了
QuickLook预览和缩略图扩展的实现,感兴趣的给个赞或者关注~~~
