这是官方的 MagicBell iOS SDK。
此 SDK 提供:
它需要:
首先,从您的 MagicBell 仪表盘 获取您的 API 密钥。然后,初始化客户端并设置当前用户
import MagicBell
// Create the MagicBell client with your project's API key
let client = MagicBellClient(apiKey: "[MAGICBELL_API_KEY]")
// Set the MagicBell user
let user = client.connectUser(email: "richard@example.com")
// Create a store of notifications
let store = user.store.build()
// Fetch the first page of notifications
store.fetch { result in
if let notifications = try? result.get() {
// Print the unread count
print("Count: \(store.unreadCount)")
// Print the fetched notifications
print("notifications: \(notifications)")
}
}
此代码仓库还包含一个完整的示例。要运行该项目:
Example
目录运行 pod install
要使用 CocoaPods 安装 MagicBell,请将以下条目添加到您的 Podfile
中:
pod 'MagicBell', '>=3.0.0'
重要提示:请确保在您的 Podfile
中指定 use_frameworks!
。
然后,运行 pod install
。
要使用 Swift Package Manager 安装 MagicBell,只需将依赖项添加到您的项目,如下所示:
dependencies: [
.package(url: "https://github.com/magicbell/magicbell-swift", .upToNextMajor(from: "3.0.0"))
]
要使用 Carthage 安装 MagicBell,请将以下依赖项添加到 Carfile:
github "magicbell/magicbell-swift" "3.0.0"
然后,运行 carthage update --use-xcframeworks --platform [iOS|macOS] --no-use-binaries
(选择所需的平台) 以解析依赖项。
将 MagicBell.xcframework
与 Carthage 解析的其他依赖项一起添加到您的项目链接的框架中。
第一步是创建一个 MagicBellClient
实例。它将为您管理用户和其他功能。初始化它需要您的 MagicBell 项目的 API 密钥。
let magicbell = MagicBellClient(apiKey: "[MAGICBELL_API_KEY]")
您可以在初始化客户端时提供其他选项:
let magicbell = MagicBellClient(
apiKey: "[MAGICBELL_API_KEY]"
logLevel: .debug
)
参数 | 默认值 | 描述 |
---|---|---|
apiKey |
- | 您的 MagicBell 的 API 密钥 |
apiSecret |
nil |
您的 MagicBell 的 API 密钥 |
logLevel |
.none |
将其设置为 .debug 以启用日志 |
虽然 API 密钥旨在发布,但您不应分发 API 密钥。而是为您的项目启用 HMAC,并在分发您的应用程序之前在您的后端生成用户密钥。
您应该在应用程序中尽早创建客户端实例,并确保您的应用程序中只使用一个实例。
import MagicBell
// Store the instance at a place of your convenience
let magicbell = MagicBellClient(apiKey: "[MAGICBELL_API_KEY]")
或者,您可以将唯一实例作为静态共享实例分配到 MagicBellClient
中。
import MagicBell
extension MagicBellClient {
static var shared = MagicBellClient(apiKey: "[MAGICBELL_API_KEY]")
}
对 MagicBell API 的请求需要您识别 MagicBell 用户。 这可以通过使用用户的电子邮件或外部 ID 在 MagicBellClient
实例上调用 connectUser(...)
方法来完成
// Identify the user by its email
let user = magicbell.connectUser(email: "richard@example.com")
// Identify the user by its external id
let user = magicbell.connectUser(externalId: "001")
// Identify the user by both, email and external id
let user = magicbell.connectUser(email: "richard@example.com", externalId: "001")
connectUser
的每个变体都支持一个可选的 hmac
参数,该参数应在为项目启用 HMAC 安全性时发送。
您可以连接 您需要的许多用户。
重要提示: User
实例是单例。因此,使用相同参数调用 connectUser
方法将产生相同的用户
let userOne = magicbell.connectUser(email: "mary@example.com")
let userTwo = magicbell.connectUser(email: "mary@example.com")
assert(userOne === userTwo, "Both users reference to the same instance")
如果您的应用支持多个登录,您可能希望同时显示所有已登录用户的通知状态。MagicBell SDK 允许您这样做。
您可以根据需要多次使用已登录用户的电子邮件或外部 ID 调用 connectUser(:)
方法。
let userOne = magicbell.connectUser(email: "richard@example.com")
let userTwo = magicbell.connectUser(email: "mary@example.com")
let userThree = magicbell.connectUser(externalId: "001")
当用户从您的应用程序注销时,您希望:
这可以使用 MagicBell
客户端实例的 disconnectUser
方法来实现
// Remove by email
magicbell.disconnectUser(email: "richard@example.com")
// Remove by external id
magicbell.disconnectUser(externalId: "001")
// Remove by email and external id
magicbell.disconnectUser(email: "richard@example.com", externalId: "001")
MagicBell User
实例需要可以在您的应用程序中使用。这里有一些选择:
如果您在您的应用程序中有一个用户对象,此方法会很有帮助。MagicBell 将保证给定电子邮件/externalId 的 User
实例是唯一的,您只需要提供对该实例的访问权限。例如:
import MagicBell
// Your own user
struct User {
let name: String
let email: String
}
extension User {
/// Returns the logged in MagicBell user
func magicBell() -> MagicBell.User {
return magicbell.connectUser(email: email)
}
}
这是如何定义一个可空的全局变量,它将代表您的 MagicBell 用户:
import MagicBell
let magicbell = MagicBellClient(apiKey: "[MAGICBELL_API_KEY]")
var magicbellUser: MagicBell.User? = nil
一旦您执行登录,就为此变量分配一个值。请记住,您必须检查 magicbellUser
变量是否已实际设置,然后才能在您的代码中访问它。
您还可以将 MagicBell User
实例注入到您自己的图中,并使用您喜欢的模式跟踪它。
NotificationStore
类表示 MagicBell 通知的集合。您可以通过用户存储对象上的 .build(...)
方法创建此类的实例。
例如:
let allNotifications = user.store.build()
let readNotifications = user.store.build(read: true)
let unreadNotifications = user.store.build(read: false)
let archviedNotifications = user.store.build(archived: true)
let billingNotifications = user.store.build(category: "billing")
let firstOrderNotifications = user.store.build(topic: "order:001")
以下是通知存储的属性:
属性 | 类型 | 描述 |
---|---|---|
totalCount |
Int |
通知的总数 |
unreadCount |
Int |
未读通知的数量 |
unseenCount |
Int |
未查看通知的数量 |
hasNextPage |
Bool |
向前分页时是否有更多项目 |
count |
Int |
商店中当前通知的数量 |
predicate |
StorePredicate |
用于过滤通知的谓词 |
以下是可用的方法:
方法 | 描述 |
---|---|
refresh |
重置商店并获取第一页通知 |
fetch |
获取下一页通知 |
subscript(index:) |
用于访问通知的下标:store[index] |
delete |
删除通知 |
delete |
删除通知 |
markAsRead |
将通知标记为已读 |
markAsUnread |
将通知标记为未读 |
archive |
存档通知 |
unarchive |
取消存档通知 |
markAllRead |
将所有通知标记为已读 |
markAllUnseen |
将所有通知标记为已查看 |
大多数方法都有两种实现:
Result
对象)Future
(iOS 13+ 上可用)// Delete notification
store.delete(notification) { result in
switch result {
case .success:
print("Notification deleted")
case .failure(error):
print("Failed: \(error)")
}
}
// Read a notification
store.markAsRead(notification)
.sink { error in
print("Failed: \(error)")
} receiveValue: { notification in
print("Notification marked as read")
}
这些方法确保当通知更改时,商店的状态是一致的。例如,当读取通知时,谓词为 read: .unread
的商店将从自身中删除该通知,并通知通知商店的所有观察者。
您还可以使用更高级的过滤器创建商店。为此,使用带有 StorePredicate
的 .build(...)
方法获取商店。
let predicate = StorePredicate()
let notifications = user.store.build(predicate: predicate)
以下是可用的选项:
参数 | 选项 | 默认 | 描述 |
---|---|---|---|
read |
true 、false 、nil |
nil |
按 read 状态过滤(nil 表示未指定) |
seen |
true 、false 、nil |
nil |
按 seen 状态过滤(nil 表示未指定) |
archived |
true 、false |
false |
按 archived 状态过滤 |
category |
String |
nil |
按类别过滤 |
topic |
String |
nil |
按主题过滤 |
例如,使用此谓词获取类别为 "important"
的未读通知
let predicate = StorePredicate(read: .unread, category: "important")
let store = user.store.build(predicate: predicate)
通知商店是单例。两次使用相同的谓词创建商店将产生相同的实例。
注意:一旦获取了商店,它将被保存在内存中,以便可以实时更新。您可以使用 .dispose
方法强制删除商店。
let predicate = StorePredicate()
user.store.dispose(with: predicate)
当您 删除用户实例 时,会自动为您完成此操作。
当调用 fetch
或 refresh
时,商店将通知内容观察者新添加的通知(请在 此处 阅读有关观察者的信息)。
// Obtaining a new notification store (first time)
let store = user.store.build()
// First loading
store.fetch { result in
if let notifications = try? result.get() {
print("Notifications: \(notifications))")
// If store has next page available
if store.hasNextPage {
// Load next page
store.fetch { result in
if let notifications = try? result.get() {
print("Notifications: \(notifications))")
}
}
}
}
}
要重置和获取商店:
store.refresh { result in
if let notifications = try? result.get() {
print("Notifications: \(notifications))")
}
}
NotificationStore
是一个可迭代的集合。因此,可以按预期方式访问通知
for i in 0..<store.count {
let notification = store[i]
print("notification: \(notification)")
}
// forEach
store.forEach { notification in
print("notification: \(notification)")
}
// for in
for notification in store {
print("notification: \(notification)")
}
// As an array
let notifications = store.notifications
枚举也可用
// forEach
store.enumerated().forEach { idx, notification in
print("notification[\(idx)] = \(notification)")
}
// for in
for (idx, notification) in store.enumerated() {
print("notification[\(idx)] = \(notification)")
}
当新通知到达或通知状态更改(标记为已读、已存档等)时,NotificationStore
的实例会自动更新。
要观察通知商店的更改,您的观察者必须实现以下协议
// Get notified when the list of notifications of a notification store changes
protocol NotificationStoreContentObserver: AnyObject {
func didReloadStore(_ store: NotificationStore)
func store(_ store: NotificationStore, didInsertNotificationsAt indexes: [Int])
func store(_ store: NotificationStore, didChangeNotificationAt indexes: [Int])
func store(_ store: NotificationStore, didDeleteNotificationAt indexes: [Int])
func store(_ store: NotificationStore, didChangeHasNextPage hasNextPage: Bool)
}
// Get notified when the counters of a notification store change
protocol NotificationStoreCountObserver: AnyObject {
func store(_ store: NotificationStore, didChangeTotalCount count: Int)
func store(_ store: NotificationStore, didChangeUnreadCount count: Int)
func store(_ store: NotificationStore, didChangeUnseenCount count: Int)
}
要观察更改,请实现这些协议(或其中之一),并将自己注册为通知商店的观察者。
let store = user.store.build()
let observer = myObserverClassInstance
store.addContentObserver(observer)
store.addCountObserver(observer)
使用类 NotificationStorePublisher
创建一个能够发布 NotificaitonStore
的主要属性更改的 ObservableObject
。
每当需要时,都必须由用户创建并保留此对象。
属性 | 类型 | 描述 |
---|---|---|
totalCount |
@Published Int |
总数 |
unreadCount |
@Published Int |
未读数 |
unseenCount |
@Published Int |
未查看数 |
hasNextPage |
@Published Bool |
指示是否还有更多内容要获取的 Bool 值。 |
notifications |
@Published [Notification] |
通知数组。 |
一个典型的用法是在 SwiftUI 的 View
中,充当可以直接从视图引用的视图模型
import SwiftUI
import MagicBell
class Notifications: View {
let store: NotificationStore
@ObservedObject var bell: NotificationStorePublisher
init(store: NotificationStore) {
self.store = store
self.bell = NotificationStorePublisher(store)
}
var body: some View {
List(bell.notifications, id: \.id) { notification in
VStack(alignment: .leading) {
Text(notification.title)
Text(notification.content ?? "-")
}
}
.navigationBarTitle("Notifications - \(bell.totalCount)")
}
}
您可以获取和设置 MagicBell 频道和类别的通知首选项。
public struct Channel {
public let label: String
public let slug: String
public let enabled: Bool
}
public struct Category {
public let channels: [Channel]
public let label: String
public let slug: String
}
public struct NotificationPreferences {
public let categories: [Category]
}
要获取通知首选项,请按如下方式使用 fetch
方法:
user.preferences.fetch { result in
if let preferences = try? result.get() {
print("Notification Preferences: \(preferences)")
}
}
要更新首选项,请使用 update
。
// Updating notification preferences.
// The update can be partial and only will affect the categories included in the object being sent
user.preferences.update(preferences) { result in }
要更新单个频道,您可以使用提供的便捷函数 updateChannel
。
user.preferences.update(categorySlug: "new_comment", channelSlug: "in_app", enabled: true) { result in }
您可以向 MagicBell 注册设备令牌,以便接收移动推送通知。 要做到这一点,请在 iOS 提供设备令牌后立即设置它。
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Storing device token when refreshed
magicbell.setDeviceToken(deviceToken: deviceToken)
}
MagicBell 会将设备令牌临时存储在内存中,并在通过 MagicBellClient.connectUser
声明新用户时立即发送该令牌。
当用户断开连接(MagicBellClient.disconnectUser
)时,设备令牌将自动取消注册该用户。
我们欢迎各种形式的贡献。 为此,请克隆存储库,通过在根文件夹中运行命令 carthage bootstrap --use-xcframeworks --no-use-binaries
使用 Carthage 解决依赖关系,然后打开 MagicBell.xcodeproj
。