版本记录
版本号 | 时间 |
---|---|
V1.0 | 2021.04.10 星期六 |
前言
Firebase是一家实时后端数据库创业公司,它能帮助开发者很快的写出Web端和移动端的应用。自2014年10月Google收购Firebase以来,用户可以在更方便地使用Firebase的同时,结合Google的云服务。Firebase能让你的App从零到一。也就是说它可以帮助手机以及网页应用的开发者轻松构建App。通过Firebase背后负载的框架就可以简单地开发一个App,无需服务器以及基础设施。接下来几篇我们就一起看一下基于Firebase平台的开发。感兴趣的看下面几篇文章。
1. 基于Firebase平台开发(一) —— 基于ML Kit的iOS图片中文字的识别(一)
2. 基于Firebase平台开发(二) —— 基于ML Kit的iOS图片中文字的识别(二)
3. 基于Firebase平台开发(三) —— Firebase基本使用简介(一)
4. 基于Firebase平台开发(四) —— Firebase基本使用简介(二)
5. 基于Firebase平台开发(五) —— Firebase基本使用简介(三)
6. 基于Firebase平台开发(六) —— 基于Firebase Analytics的App使用率的跟踪(一)
7. 基于Firebase平台开发(七) —— iOS的A/B Test(一)
8. 基于Firebase平台开发(八) —— 使用Firebase Cloud Messaging进行Push Notification的发送和接收(一)
源码
1. Swift
首先看下工程组织结构
下面就是源码了
1. AppMain.swift
import SwiftUI
@main
struct AppMain: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
AppTabView()
.accentColor(Color("rw-green"))
}
}
}
2. AppDelegate.swift
import UIKit
import Firebase
import FirebaseMessaging
import FirebaseAnalytics
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
FirebaseApp.configure()
FirebaseConfiguration.shared.setLoggerLevel(.min)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions) { _, _ in }
application.registerForRemoteNotifications()
Messaging.messaging().delegate = self
return true
}
}
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler:
@escaping (UNNotificationPresentationOptions) -> Void
) {
process(notification)
completionHandler([[.banner, .sound]])
}
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
process(response.notification)
completionHandler()
}
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
Messaging.messaging().apnsToken = deviceToken
}
private func process(_ notification: UNNotification) {
let userInfo = notification.request.content.userInfo
UIApplication.shared.applicationIconBadgeNumber = 0
if let newsTitle = userInfo["newsTitle"] as? String,
let newsBody = userInfo["newsBody"] as? String {
let newsItem = NewsItem(title: newsTitle, body: newsBody, date: Date())
NewsModel.shared.add([newsItem])
Analytics.logEvent("NEWS_ITEM_PROCESSED", parameters: nil)
}
Messaging.messaging().appDidReceiveMessage(userInfo)
Analytics.logEvent("NOTIFICATION_PROCESSED", parameters: nil)
}
}
extension AppDelegate: MessagingDelegate {
func messaging(
_ messaging: Messaging,
didReceiveRegistrationToken fcmToken: String?
) {
let tokenDict = ["token": fcmToken ?? ""]
NotificationCenter.default.post(
name: Notification.Name("FCMToken"),
object: nil,
userInfo: tokenDict)
}
}
3. NewsModel.swift
import Foundation
class NewsModel: ObservableObject {
@Published private(set) var newsItems: [NewsItem] = []
func add(_ items: [NewsItem]) {
var tempItems = newsItems
tempItems.append(contentsOf: items)
newsItems = tempItems.sorted {
$0.date > $1.date
}
}
}
extension NewsModel {
static let shared = mockModel()
private static func mockModel() -> NewsModel {
let newsModel = NewsModel()
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
guard
let url = Bundle.main.url(forResource: "MockNewsItems", withExtension: "json"),
let data = try? Data(contentsOf: url),
let newsItems = try? decoder.decode([NewsItem].self, from: data)
else {
return newsModel
}
newsModel.add(newsItems)
return newsModel
}
}
4. NewsItem.swift
import Foundation
struct NewsItem: Identifiable, Codable {
var id = UUID()
let title: String
let body: String
let date: Date
private enum CodingKeys: String, CodingKey {
case title
case body
case date
}
}
5. TopicsModel.swift
import SwiftUI
import FirebaseMessaging
class TopicsModel: ObservableObject {
static let familyKey = "family"
static let petsKey = "pets"
@AppStorage(TopicsModel.familyKey) var family = false {
didSet {
updateSubscription(for: TopicsModel.familyKey, subscribed: family)
}
}
@AppStorage(TopicsModel.petsKey) var pets = false {
didSet {
updateSubscription(for: TopicsModel.petsKey, subscribed: pets)
}
}
private func updateSubscription(for topic: String, subscribed: Bool) {
if subscribed {
subscribe(to: topic)
} else {
unsubscribe(from: topic)
}
}
private func subscribe(to topic: String) {
Messaging.messaging().subscribe(toTopic: topic)
}
private func unsubscribe(from topic: String) {
Messaging.messaging().unsubscribe(fromTopic: topic)
}
}
6. AppTabView.swift
import SwiftUI
struct AppTabView: View {
var body: some View {
TabView {
NavigationView {
NewsListView(newsModel: NewsModel.shared)
}
.tabItem {
Image(systemName: "newspaper")
Text("News")
}
NavigationView {
TopicsView()
}
.tabItem {
Image(systemName: "rectangle.3.offgrid.bubble.left")
Text("Topics")
}
}
}
}
struct AppTabView_Previews: PreviewProvider {
static var previews: some View {
AppTabView()
}
}
7. NewsListView.swift
import SwiftUI
struct NewsListView: View {
@ObservedObject var newsModel: NewsModel
var body: some View {
List(newsModel.newsItems) { newsItem in
NewsItemView(newsItem: newsItem)
}
.listStyle(InsetGroupedListStyle())
.navigationTitle("Good News")
}
}
struct NewsListView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
NewsListView(newsModel: NewsModel.shared)
}
}
}
8. NewsItemView.swift
import SwiftUI
struct NewsItemView: View {
let newsItem: NewsItem
var body: some View {
VStack(alignment: .leading) {
Text(newsItem.title)
.font(.title2)
.bold()
Text(newsItem.body)
.font(.body)
Text(newsItem.date, formatter: dateFormatter)
.font(.caption2)
.italic()
}
}
private var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .short
return formatter
}
}
struct NewsItemRowView_Previews: PreviewProvider {
static var previews: some View {
NewsItemView(newsItem: NewsItem(title: "News Title", body: "News body, with more information", date: Date()))
}
}
9. TopicsView.swift
import SwiftUI
struct TopicsView: View {
@ObservedObject var topicsModel = TopicsModel()
var body: some View {
Form {
Section(header: Text("Select the topics you would like to receive notifications for")) {
Toggle("Family", isOn: $topicsModel.family)
Toggle("Pets", isOn: $topicsModel.pets)
}
}
.navigationTitle("Topics")
}
}
struct SubscriptionsView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
TopicsView()
}
}
}
10. NotificationService.swift
import UserNotifications
import FirebaseMessaging
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContent
guard let bestAttemptContent = bestAttemptContent else { return }
FIRMessagingExtensionHelper().populateNotificationContent(
bestAttemptContent,
withContentHandler: contentHandler)
}
override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}
后记
本篇主要讲述了使用
Firebase Cloud Messaging
进行Push Notification
的发送和接收,感兴趣的给个赞或者关注~~~