WhatsNewKit
一个用于轻松展示应用新功能的Swift包。
它从头开始设计,可以完全根据您的需求进行自定义。
import SwiftUI
import WhatsNewKit
struct ContentView: View {
var body: some View {
NavigationView {
// ...
}
.whatsNewSheet()
}
}
特性
- 轻松展示您的新应用功能 🤩
- 自动和手动展示模式 ✅
- 支持SwiftUI、UIKit和AppKit 🧑🎨
- 可在iOS、macOS和visionOS上运行 📱 🖥 👓
- 可调整的布局 🔧
安装
Swift包管理器
要使用Apple的Swift包管理器进行集成,请将以下内容作为依赖项添加到您的Package.swift
中:
dependencies: [
.package(url: "https://github.com/SvenTiigi/WhatsNewKit.git", from: "2.0.0")
]
或者导航到您的Xcode项目,然后选择Swift Packages
,点击"+"图标并搜索WhatsNewKit
。
示例
查看示例应用程序以了解WhatsNewKit的实际效果。只需打开Example/Example.xcodeproj
并运行"Example"方案即可。
使用
目录
手动展示
如果您希望手动展示WhatsNewView
,可以使用sheet(whatsNew:)
修饰符。
struct ContentView: View {
@State
var whatsNew: WhatsNew? = WhatsNew(
title: "WhatsNewKit",
features: [
.init(
image: .init(
systemName: "star.fill",
foregroundColor: .orange
),
title: "展示您的新应用功能",
subtitle: "展示您的新应用功能..."
),
// ...
]
)
var body: some View {
NavigationView {
// ...
}
.sheet(
whatsNew: self.$whatsNew
)
}
}
自动展示
自动展示模式允许您通过SwiftUI环境声明新功能,WhatsNewKit将负责展示相应的WhatsNewView
。
首先,在需要展示WhatsNewView
的视图上添加.whatsNewSheet()
修饰符。
struct ContentView: View {
var body: some View {
NavigationView {
// ...
}
// 如果需要,自动展示WhatsNewView。
// 需要展示给用户的WhatsNew内容
// 会自动从`WhatsNewEnvironment`中获取
.whatsNewSheet()
}
}
.whatsNewSheet()
修饰符使用WhatsNewEnvironment
来获取当前版本应该展示给用户的可选WhatsNew对象。因此,您可以通过environment
修饰符轻松配置WhatsNewEnvironment
。
extension App: SwiftUI.App {
var body: some Scene {
WindowGroup {
ContentView()
.environment(
\.whatsNew,
WhatsNewEnvironment(
// 指定以何种方式存储已展示的WhatsNew版本。
// 默认使用 `UserDefaultsWhatsNewVersionStore`。
versionStore: UserDefaultsWhatsNewVersionStore(),
// 传入 `WhatsNewCollectionProvider` 或 WhatsNew 实例数组
whatsNewCollection: self
)
)
}
}
}
// MARK: - App+WhatsNewCollectionProvider
extension App: WhatsNewCollectionProvider {
/// 为每个版本声明 WhatsNew 实例
var whatsNewCollection: WhatsNewCollection {
WhatsNew(
version: "1.0.0",
// ...
)
WhatsNew(
version: "1.1.0",
// ...
)
WhatsNew(
version: "1.2.0",
// ...
)
}
}
WhatsNewEnvironment
WhatsNewEnvironment
负责确定应该向用户展示的当前版本的匹配 WhatsNew 对象。
如前面的例子所示,你可以通过指定 WhatsNewVersionStore
并提供 WhatsNewCollection
来初始化 WhatsNewEnvironment
。
// 通过传入 WhatsNew 实例数组来初始化 WhatsNewEnvironment。
// UserDefaultsWhatsNewVersionStore 作为默认的 WhatsNewVersionStore 使用
let whatsNewEnvironment = WhatsNewEnvironment(
whatsNewCollection: [
WhatsNew(
version: "1.0.0",
// ...
)
]
)
// 使用 NSUbiquitousKeyValueWhatsNewVersionStore 初始化 WhatsNewEnvironment
// 该存储将已展示的版本保存在 iCloud 中。
// WhatsNewCollection 由 `WhatsNewBuilder` 闭包提供
let whatsNewEnvironment = WhatsNewEnvironment(
versionStore: NSUbiquitousKeyValueWhatsNewVersionStore(),
whatsNewCollection: {
WhatsNew(
version: "1.0.0",
// ...
)
}
)
此外,WhatsNewEnvironment
包含了补丁版本的回退机制。例如,当用户安装版本 1.0.1
,而你只声明了版本 1.0.0
的 WhatsNew
,环境将自动回退到版本 1.0.0
,并在需要时向用户展示 WhatsNewView
。
如果你希望进一步自定义 WhatsNewEnvironment
的行为,你可以轻松地对其进行子类化并重写 whatsNew()
函数。
class MyCustomWhatsNewEnvironment: WhatsNewEnvironment {
/// 获取应该向用户展示的 WhatsNew(如果有)。
override func whatsNew() -> WhatsNew? {
// 当前版本
let currentVersion = self.currentVersion
// 你声明的 WhatsNew 对象
let whatsNewCollection = self.whatsNewCollection
// 用于确定已展示版本的 WhatsNewVersionStore
let versionStore = self.whatsNewVersionStore
// TODO: 确定应该向用户展示的 WhatsNew...
}
}
WhatsNewVersionStore
WhatsNewVersionStore
是一个协议类型,负责保存和检索已向用户展示的版本。
let whatsNewVersionStore: WhatsNewVersionStore
// 保存已展示的版本
whatsNewVersionStore.save(presentedVersion: "1.0.0")
// 检索已展示的版本
let presentedVersions = whatsNewVersionStore.presentedVersions
// 检索给定版本是否已经展示的布尔值
let hasPresented = whatsNewVersionStore.hasPresented("1.0.0")
WhatsNewKit 提供了三种预定义的实现:
// 将已展示的版本持久化到 UserDefaults
let userDefaultsWhatsNewVersionStore = UserDefaultsWhatsNewVersionStore()
// 使用 NSUbiquitousKeyValueStore 将已展示的版本持久化到 iCloud
let ubiquitousKeyValueWhatsNewVersionStore = NSUbiquitousKeyValueWhatsNewVersionStore()
// 将已展示的版本存储在内存中。适合测试用途
let inMemoryWhatsNewVersionStore = InMemoryWhatsNewVersionStore()
如果你已经有特定的实现来存储用户相关设置,比如 Realm 或 Core Data,你可以轻松地让你的现有实现采用 WhatsNewVersionStore
协议。
NSUbiquitousKeyValueWhatsNewVersionStore
如果你使用 NSUbiquitousKeyValueWhatsNewVersionStore
,请确保在 Xcode 项目的"Signing & Capabilities"部分启用 iCloud Key-value storage 功能。
WhatsNew
以下部分解释了如何初始化 WhatsNew
结构体,以描述应用程序给定版本的新功能。
let whatsnew = WhatsNew(
// 与你要展示的功能相关的版本
version: "1.0.0",
// 显示在顶部的标题
title: "新功能",
// 你想要展示的功能
features: [
WhatsNew.Feature(
image: .init(systemName: "star.fill"),
title: "标题",
subtitle: "副标题"
)
],
// 用于关闭 WhatsNewView 的主要操作
primaryAction: WhatsNew.PrimaryAction(
title: "继续",
backgroundColor: .accentColor,
foregroundColor: .white,
hapticFeedback: .notification(.success),
onDismiss: {
print("WhatsNewView 已被关闭")
}
),
// 显示在主要操作上方的可选次要操作
secondaryAction: WhatsNew.SecondaryAction(
title: "了解更多",
foregroundColor: .accentColor,
hapticFeedback: .selection,
action: .openURL(
.init(string: "https://github.com/SvenTiigi/WhatsNewKit")
)
)
)
WhatsNew.Version
WhatsNew.Version
指定引入应用程序某些功能的版本。
// 使用主版本、次版本和补丁版本初始化
let version = WhatsNew.Version(
major: 1,
minor: 0,
patch: 0
)
// 使用字符串字面量初始化
let version: WhatsNew.Version = "1.0.0"
// 使用包的当前版本初始化 WhatsNew Version
let version: WhatsNew.Version = .current()
WhatsNew.Title
WhatsNew.Title
表示在功能上方渲染的标题文本。
// 使用字符串字面量初始化
let title: WhatsNew.Title = "继续"
// 使用文本和前景色初始化
let title = WhatsNew.Title(
text: "继续",
foregroundColor: .primary
)
// 在 iOS 15 及以上版本,使用 Markdown 初始化 AttributedString
let title = WhatsNew.Title(
text: try AttributedString(
markdown: "What's **New**"
)
)
WhatsNew.Feature
WhatsNew.Feature
描述了应用程序的特定功能,通常包含一个图像、标题和副标题。
let feature = WhatsNew.Feature(
image: .init(
systemName: "wand.and.stars"
),
title: "新设计",
subtitle: .init(
try AttributedString(
markdown: "一个很棒的新_设计_"
)
)
)
WhatsNew.PrimaryAction
WhatsNew.PrimaryAction
允许你配置主要按钮的行为,该按钮用于关闭呈现的 WhatsNewView
let primaryAction = WhatsNew.PrimaryAction(
title: "继续",
backgroundColor: .blue,
foregroundColor: .white,
hapticFeedback: .notification(.success),
onDismiss: {
print("WhatsNewView 已被关闭")
}
)
注意:触觉反馈仅在 iOS 上执行
WhatsNew.SecondaryAction
在初始化 WhatsNew
实例时,可以选择性地提供一个 WhatsNew.SecondaryAction
,它显示在 WhatsNew.PrimaryAction
上方,允许你呈现额外的视图、执行自定义操作或打开 URL。
// 呈现视图的 SecondaryAction
let secondaryActionPresentAboutView = WhatsNew.SecondaryAction(
title: "了解更多",
foregroundColor: .blue,
hapticFeedback: .selection,
action: .present {
AboutView()
}
)
// 打开 URL 的 SecondaryAction
let secondaryActionOpenURL = WhatsNew.SecondaryAction(
title: "阅读更多",
foregroundColor: .blue,
hapticFeedback: .selection,
action: .open(
url: .init(string: "https://github.com/SvenTiigi/WhatsNewKit")
)
)
// 自定义执行的 SecondaryAction
let secondaryActionCustom = WhatsNew.SecondaryAction(
title: "自定义",
action: .custom { presentationMode in
// ...
}
)
注意:触觉反馈仅在 iOS 上执行
布局
WhatsNewKit 允许你以多种方式调整呈现的 WhatsNewView
的布局。
最简单的方法是修改 WhatsNew.Layout.default
实例。
WhatsNew.Layout.default.featureListSpacing = 35
使用自动呈现样式时,你可以在初始化 WhatsNewEnvironment 时提供默认布局。
.environment(
\.whatsNew,
.init(
defaultLayout: WhatsNew.Layout(
showsScrollViewIndicators: true,
featureListSpacing: 35
),
whatsNew: self
)
)
或者,你可以在自动或手动呈现 WhatsNewView 时传递一个 WhatsNew.Layout
.whatsNewSheet(
layout: WhatsNew.Layout(
contentPadding: .init(
top: 80,
leading: 0,
bottom: 0,
trailing: 0
)
)
)
.sheet(
whatsNew: self.$whatsNew,
layout: WhatsNew.Layout(
footerActionSpacing: 20
)
)
WhatsNewViewController
在使用 UIKit
或 AppKit
时,你可以使用 WhatsNewViewController
。
let whatsNewViewController = WhatsNewViewController(
whatsNew: WhatsNew(
version: "1.0.0",
// ...
),
layout: WhatsNew.Layout(
contentSpacing: 80
)
)
如果你希望仅在 WhatsNew 实例的版本尚未呈现时才呈现 WhatsNewViewController
,你可以使用便利的可失败初始化器。
// 验证 WhatsNewViewController 是否可用于呈现
guard let whatsNewViewController = WhatsNewViewController(
whatsNew: WhatsNew(
version: "1.0.0",
// ...
),
versionStore: UserDefaultsWhatsNewVersionStore()
) else {
// WhatsNew 的版本已经呈现过
return
}
// 呈现 WhatsNewViewController
// 当 WhatsNewViewController 被关闭时,版本将自动保存在提供的
// WhatsNewVersionStore 中
self.present(whatsNewViewController, animated: true)