Firebase iOS SDK终极指南:从零构建企业级应用

Firebase iOS SDK终极指南:从零构建企业级应用

【免费下载链接】firebase-ios-sdk 适用于苹果应用开发的Firebase SDK。 【免费下载链接】firebase-ios-sdk 项目地址: https://gitcode.com/GitHub_Trending/fi/firebase-ios-sdk

引言:为什么选择Firebase iOS SDK?

还在为iOS应用的后端开发、用户认证、数据分析而烦恼吗?Firebase iOS SDK提供了一套完整的解决方案,让你专注于应用逻辑而非基础设施。本文将带你从零开始,全面掌握Firebase iOS SDK在企业级应用开发中的实战应用。

读完本文,你将获得:

  • Firebase核心模块的深度理解
  • 企业级应用架构的最佳实践
  • 实时数据库与云存储的优化策略
  • 用户认证与安全防护的完整方案
  • 性能监控与错误追踪的专业技巧

环境准备与项目配置

系统要求

mermaid

安装方式对比

安装方式优点缺点适用场景
CocoaPods成熟稳定,社区支持好需要维护Podfile传统项目,需要精确版本控制
Swift Package Manager原生支持,无需额外工具部分功能可能受限新项目,追求现代化开发
Carthage编译速度快,依赖清晰配置相对复杂大型项目,需要自定义构建

基础配置步骤

  1. 创建Firebase项目
# 在Firebase控制台创建新项目
# 下载GoogleService-Info.plist配置文件
  1. 配置Podfile
platform :ios, '13.0'
use_frameworks!

target 'YourApp' do
  # Firebase核心服务
  pod 'FirebaseCore'
  pod 'FirebaseAnalytics'
  
  # 数据库服务
  pod 'FirebaseFirestore'
  pod 'FirebaseDatabase'
  
  # 用户认证
  pod 'FirebaseAuth'
  
  # 云存储
  pod 'FirebaseStorage'
  
  # 性能监控
  pod 'FirebasePerformance'
  
  # 崩溃报告
  pod 'FirebaseCrashlytics'
end
  1. 初始化配置
import FirebaseCore

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, 
                   didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // 配置Firebase
        FirebaseApp.configure()
        
        // 设置日志级别
        FirebaseConfiguration.shared.setLoggerLevel(.debug)
        
        return true
    }
}

核心模块深度解析

FirebaseApp:应用入口点

mermaid

多环境配置策略

enum Environment {
    case development
    case staging
    case production
    
    var options: FIROptions {
        switch self {
        case .development:
            return FIROptions(contentsOfFile: Bundle.main.path(forResource: "GoogleService-Info-Dev", ofType: "plist"))!
        case .staging:
            return FIROptions(contentsOfFile: Bundle.main.path(forResource: "GoogleService-Info-Staging", ofType: "plist"))!
        case .production:
            return FIROptions(contentsOfFile: Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist"))!
        }
    }
}

// 使用示例
func setupFirebase(for environment: Environment) {
    if FirebaseApp.app() == nil {
        FirebaseApp.configure(options: environment.options)
    }
}

实时数据库:Firestore实战

数据模型设计

import FirebaseFirestore
import FirebaseFirestoreSwift

struct User: Codable, Identifiable {
    @DocumentID var id: String?
    let name: String
    let email: String
    let createdAt: Date
    let updatedAt: Date
    var isActive: Bool = true
    
    enum CodingKeys: String, CodingKey {
        case id
        case name
        case email
        case createdAt = "created_at"
        case updatedAt = "updated_at"
        case isActive = "is_active"
    }
}

struct Post: Codable, Identifiable {
    @DocumentID var id: String?
    let title: String
    let content: String
    let authorID: String
    let createdAt: Date
    var likes: Int = 0
    var tags: [String] = []
    
    enum CodingKeys: String, CodingKey {
        case id
        case title
        case content
        case authorID = "author_id"
        case createdAt = "created_at"
        case likes
        case tags
    }
}

高级查询优化

class FirestoreManager {
    private let db = Firestore.firestore()
    
    // 分页查询
    func fetchPosts(limit: Int = 20, lastDocument: DocumentSnapshot? = nil) async throws -> ([Post], DocumentSnapshot?) {
        var query = db.collection("posts")
            .whereField("is_published", isEqualTo: true)
            .order(by: "created_at", descending: true)
            .limit(to: limit)
        
        if let lastDocument = lastDocument {
            query = query.start(afterDocument: lastDocument)
        }
        
        let snapshot = try await query.getDocuments()
        let posts = try snapshot.documents.compactMap { document in
            try document.data(as: Post.self)
        }
        
        return (posts, snapshot.documents.last)
    }
    
    // 实时监听
    func observeUserPosts(userID: String, completion: @escaping ([Post]) -> Void) -> ListenerRegistration {
        return db.collection("posts")
            .whereField("author_id", isEqualTo: userID)
            .whereField("is_published", isEqualTo: true)
            .order(by: "created_at", descending: true)
            .addSnapshotListener { snapshot, error in
                guard let documents = snapshot?.documents else {
                    print("Error fetching documents: \(error?.localizedDescription ?? "Unknown error")")
                    return
                }
                
                let posts = documents.compactMap { document in
                    try? document.data(as: Post.self)
                }
                completion(posts)
            }
    }
    
    // 事务操作
    func likePost(postID: String, userID: String) async throws {
        try await db.runTransaction { transaction, errorPointer in
            let postRef = self.db.collection("posts").document(postID)
            let userLikeRef = self.db.collection("user_likes").document("\(userID)_\(postID)")
            
            let postDocument: DocumentSnapshot
            do {
                postDocument = try transaction.getDocument(postRef)
            } catch let fetchError as NSError {
                errorPointer?.pointee = fetchError
                return nil
            }
            
            guard let post = try? postDocument.data(as: Post.self) else {
                let error = NSError(domain: "AppError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Post not found"])
                errorPointer?.pointee = error
                return nil
            }
            
            // 检查是否已经点赞
            let likeDocument: DocumentSnapshot
            do {
                likeDocument = try transaction.getDocument(userLikeRef)
            } catch {
                // 文档不存在,可以继续
            }
            
            if likeDocument.exists {
                throw NSError(domain: "AppError", code: -2, userInfo: [NSLocalizedDescriptionKey: "Already liked"])
            }
            
            // 更新点赞数
            transaction.updateData(["likes": post.likes + 1], forDocument: postRef)
            transaction.setData(["created_at": Date()], forDocument: userLikeRef)
            
            return post.likes + 1
        }
    }
}

安全规则配置

// firestore.rules
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // 用户文档:只能自己读写
    match /users/{userId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
    
    // 帖子文档:所有人可读,只能作者写
    match /posts/{postId} {
      allow read: if true;
      allow create: if request.auth != null;
      allow update, delete: if request.auth != null && request.auth.uid == resource.data.author_id;
    }
    
    // 点赞记录:只能创建,不能修改删除
    match /user_likes/{likeId} {
      allow create: if request.auth != null;
      allow read: if request.auth != null;
      allow delete: if false;
      allow update: if false;
    }
  }
}

用户认证:Firebase Auth深度应用

多提供商认证集成

import FirebaseAuth

class AuthManager {
    static let shared = AuthManager()
    private let auth = Auth.auth()
    
    // 邮箱密码认证
    func signUpWithEmail(email: String, password: String) async throws -> AuthDataResult {
        return try await auth.createUser(withEmail: email, password: password)
    }
    
    // 第三方认证(Apple Sign in)
    func signInWithApple(idToken: String, nonce: String) async throws -> AuthDataResult {
        let credential = OAuthProvider.credential(withProviderID: "apple.com",
                                                idToken: idToken,
                                                rawNonce: nonce)
        return try await auth.signIn(with: credential)
    }
    
    // 第三方认证(Google Sign in)
    func signInWithGoogle(idToken: String, accessToken: String) async throws -> AuthDataResult {
        let credential = GoogleAuthProvider.credential(withIDToken: idToken,
                                                     accessToken: accessToken)
        return try await auth.signIn(with: credential)
    }
    
    // 手机号认证
    func signInWithPhoneNumber(_ phoneNumber: String) async throws -> String {
        return try await PhoneAuthProvider.provider()
            .verifyPhoneNumber(phoneNumber, uiDelegate: nil)
    }
    
    // 验证短信验证码
    func verifySMSCode(verificationID: String, verificationCode: String) async throws -> AuthDataResult {
        let credential = PhoneAuthProvider.provider().credential(
            withVerificationID: verificationID,
            verificationCode: verificationCode
        )
        return try await auth.signIn(with: credential)
    }
    
    // 登出
    func signOut() throws {
        try auth.signOut()
    }
    
    // 获取当前用户
    var currentUser: User? {
        return auth.currentUser
    }
    
    // 监听认证状态变化
    func addAuthStateListener(handler: @escaping (User?) -> Void) -> AuthStateDidChangeListenerHandle {
        return auth.addStateDidChangeListener { _, user in
            handler(user)
        }
    }
}

用户信息管理

extension AuthManager {
    // 更新用户资料
    func updateUserProfile(displayName: String?, photoURL: URL?) async throws {
        let changeRequest = auth.currentUser?.createProfileChangeRequest()
        changeRequest?.displayName = displayName
        changeRequest?.photoURL = photoURL
        try await changeRequest?.commitChanges()
    }
    
    // 更新邮箱
    func updateEmail(_ email: String) async throws {
        try await auth.currentUser?.updateEmail(to: email)
    }
    
    // 发送邮箱验证
    func sendEmailVerification() async throws {
        try await auth.currentUser?.sendEmailVerification()
    }
    
    // 重置密码
    func resetPassword(email: String) async throws {
        try await auth.sendPasswordReset(withEmail: email)
    }
    
    // 删除账户
    func deleteAccount() async throws {
        try await auth.currentUser?.delete()
    }
}

云存储:Firebase Storage最佳实践

文件上传下载管理

import FirebaseStorage

class StorageManager {
    static let shared = StorageManager()
    private let storage = Storage.storage()
    
    // 上传图片
    func uploadImage(_ image: UIImage, path: String, compressionQuality: CGFloat = 0.8) async throws -> URL {
        guard let imageData = image.jpegData(compressionQuality: compressionQuality) else {
            throw NSError(domain: "StorageError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to convert image to data"])
        }
        
        let storageRef = storage.reference().child(path)
        let metadata = StorageMetadata()
        metadata.contentType = "image/jpeg"
        
        _ = try await storageRef.putDataAsync(imageData, metadata: metadata)
        return try await storageRef.downloadURL()
    }
    
    // 下载文件
    func downloadFile(at path: String) async throws -> Data {
        let storageRef = storage.reference().child(path)
        return try await storageRef.data(maxSize: 10 * 1024 * 1024) // 10MB限制
    }
    
    // 获取下载URL
    func getDownloadURL(for path: String) async throws -> URL {
        let storageRef = storage.reference().child(path)
        return try await storageRef.downloadURL()
    }
    
    // 删除文件
    func deleteFile(at path: String) async throws {
        let storageRef = storage.reference().child(path)
        try await storageRef.delete()
    }
    
    // 列出文件
    func listFiles(in directory: String) async throws -> [StorageReference] {
        let storageRef = storage.reference().child(directory)
        let result = try await storageRef.listAll()
        return result.items
    }
    
    // 获取文件元数据
    func getFileMetadata(at path: String) async throws -> StorageMetadata {
        let storageRef = storage.reference().child(path)
        return try await storageRef.getMetadata()
    }
    
    // 更新文件元数据
    func updateFileMetadata(at path: String, metadata: [String: Any]) async throws {
        let storageRef = storage.reference().child(path)
        try await storageRef.updateMetadata(StorageMetadata(dictionary: metadata))
    }
}

大文件分片上传

extension StorageManager {
    // 分片上传大文件
    func uploadLargeFile(_ data: Data, path: String, chunkSize: Int = 1 * 1024 * 1024) async throws -> URL {
        let storageRef = storage.reference().child(path)
        let metadata = StorageMetadata()
        metadata.contentType = "application/octet-stream"
        
        // 计算分片数量
        let totalChunks = Int(ceil(Double(data.count) / Double(chunkSize)))
        var uploadTask: StorageUploadTask?
        
        for chunkIndex in 0..<totalChunks {
            let start = chunkIndex * chunkSize
            let end = min(start + chunkSize, data.count)
            let chunkData = data.subdata(in: start..<end)
            
            if chunkIndex == 0 {
                // 第一片
                uploadTask = storageRef.putData(chunkData, metadata: metadata)
            } else {
                // 后续分片
                uploadTask = uploadTask?.continueWith { task, error in
                    if let error = error {
                        throw error
                    }
                    return storageRef.putData(chunkData)
                }
            }
        }
        
        guard let finalTask = uploadTask else {
            throw NSError(domain: "StorageError", code: -2, userInfo: [NSLocalizedDescriptionKey: "Upload task not created"])
        }
        
        _ = try await finalTask.value
        return try await storageRef.downloadURL()
    }
    
    // 带进度监控的上传
    func uploadWithProgress(_ data: Data, path: String, 
                          onProgress: @escaping (Double) -> Void) async throws -> URL {
        let storageRef = storage.reference().child(path)
        let metadata = StorageMetadata()
        metadata.contentType = "application/octet-stream"
        
        return try await withCheckedThrowingContinuation { continuation in
            let uploadTask = storageRef.putData(data, metadata: metadata)
            
            uploadTask.observe(.progress) { snapshot in
                guard let progress = snapshot.progress else { return }
                let percentComplete = Double(progress.completedUnitCount) / Double(progress.totalUnitCount)
                onProgress(percentComplete)
            }
            
            uploadTask.observe(.success) { _ in
                Task {
                    do {
                        let downloadURL = try await storageRef.downloadURL()
                        continuation.resume(returning: downloadURL)
                    } catch {
                        continuation.resume(throwing: error)
                    }
                }
            }
            
            uploadTask.observe(.failure) { snapshot in
                if let error = snapshot.error {
                    continuation.resume(throwing: error)
                }
            }
        }
    }
}

性能监控与错误追踪

Firebase Performance监控

import FirebasePerformance

class PerformanceMonitor {
    static let shared = PerformanceMonitor()
    private let perf = Performance.sharedInstance()
    
    // 自定义性能追踪
    func trackCustomTrace(name: String, operation: () async throws -> Void) async rethrows {
        let trace = perf.trace(name: name)
        trace.start()
        
        defer {
            trace.stop()
        }
        
        try await operation()
    }
    
    // 网络请求监控
    func monitorNetworkRequest(_ request: URLRequest, 
                             completion: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask {
        let httpMetric = HTTPMetric(url: request.url!, httpMethod: .get)
        httpMetric.start()
        
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            if let httpResponse = response as? HTTPResponse {
                httpMetric.responseCode = httpResponse.statusCode
            }
            httpMetric.stop()
            
            completion(data, response, error)
        }
        
        task.resume()
        return task
    }
    
    // 应用启动性能
    func trackAppStart() {
        let trace = perf.trace(name: "app_start_trace")
        trace.start()
        
        // 在应用启动完成后停止
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            trace.stop()
        }
    }
}

Crashlytics错误报告

import FirebaseCrashlytics

class ErrorReporter {
    static let shared = ErrorReporter()
    private let crashlytics = Crashlytics.crashlytics()
    
    // 记录自定义错误
    func recordError(_ error: Error, userInfo: [String: Any]? = nil) {
        var customUserInfo = userInfo ?? [:]
        customUserInfo["timestamp"] = Date().iso8601String()
        customUserInfo["app_version"] = Bundle.main.appVersion
        
        crashlytics.record(error: error, userInfo: customUserInfo)
    }
    
    // 设置用户标识
    func setUserID(_ userID: String) {
        crashlytics.setUserID(userID)
    }
    
    // 设置自定义键值
    func setCustomValue(_ value: Any, forKey key: String) {
        crashlytics.setCustomValue(value, forKey: key)
    }
    
    // 记录非致命异常
    func recordNonFatalError(domain: String, code: Int, description: String) {
        let error = NSError(domain: domain, code: code, userInfo: [NSLocalizedDescriptionKey: description])
        recordError(error)
    }
    
    // 启用/禁用崩溃报告
    func setCrashReportingEnabled(_ enabled: Bool) {
        crashlytics.setCrashReportingEnabled(enabled)
    }
}

// 扩展工具方法
extension Bundle {
    var appVersion: String {
        return infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
    }
    
    var buildNumber: String {
        return infoDictionary?["CFBundleVersion"] as? String ?? "Unknown"
    }
}

extension Date {
    var iso8601String: String {
        let formatter = ISO8601DateFormatter()
        return formatter.string(from: self)
    }
}

企业级架构设计

依赖注入架构

mermaid

服务层实现

protocol FirestoreService {
    func fetchPosts(limit: Int, lastDocument: DocumentSnapshot?) async throws -> ([Post], DocumentSnapshot?)
    func observeUserPosts(userID: String, completion: @escaping ([Post]) -> Void) -> ListenerRegistration
    func likePost(postID: String, userID: String) async throws
}

protocol AuthService {
    func signInWithEmail(email: String, password: String) async throws -> AuthDataResult
    func signOut() throws
    var currentUser: User? { get }
}

protocol StorageService {
    func uploadImage(_ image: UIImage, path: String) async throws -> URL
    func downloadFile(at path: String) async throws -> Data
}

// 具体实现
class FirebaseFirestoreService: FirestoreService {
    private let firestoreManager: FirestoreManager
    
    init(firestoreManager: FirestoreManager) {
        self.firestoreManager = firestoreManager
    }
    
    func fetchPosts(limit: Int, lastDocument: DocumentSnapshot?) async throws -> ([Post], DocumentSnapshot?) {
        return try await firestoreManager.fetchPosts(limit: limit, lastDocument: lastDocument)
    }
    
    // 其他方法实现...
}

// 依赖注入容器
class AppContainer {
    let firestoreService: FirestoreService
    let authService: AuthService
    let storageService: StorageService
    
    init(environment: Environment) {
        let firestoreManager = FirestoreManager()
        let authManager = AuthManager()
        let storageManager = StorageManager()
        
        self.firestoreService = FirebaseFirestoreService(firestoreManager: firestoreManager)
        self.authService = FirebaseAuthService(authManager: authManager)
        self.storageService = FirebaseStorageService(storageManager: storageManager)
        
        // 配置Firebase
        setupFirebase(for: environment)
    }
    
    private func setupFirebase(for environment: Environment) {
        if FirebaseApp.app() == nil {
            FirebaseApp.configure(options: environment.options)
        }
    }
}

测试策略与质量保证

单元测试示例

import XCTest
@testable import YourApp
import FirebaseAuth
import FirebaseFirestore

class FirestoreServiceTests: XCTestCase {
    var firestoreService: FirestoreService!
    var mockFirestore: MockFirestore!
    
    override func setUp() {
        super.setUp()
        mockFirestore = MockFirestore()
        let firestoreManager = FirestoreManager(firestore: mockFirestore)
        firestoreService = FirebaseFirestoreService(firestoreManager: firestoreManager)
    }
    
    func testFetchPosts() async throws {
        // 准备测试数据
        let mockPosts = [
            Post(id: "1", title: "Test Post", content: "Content", authorID: "user1", createdAt: Date()),
            Post(id: "2", title: "Test Post 2", content: "Content 2", authorID: "user1", createdAt: Date())
        ]
        mockFirestore.mockDocuments = mockPosts.map { post in
            let document = MockDocumentSnapshot()
            document.mockData = try! Firestore.Encoder().encode(post)
            return document
        }
        
        // 执行测试
        let (posts, _) = try await firestoreService.fetchPosts(limit: 20, lastDocument: nil)
        
        // 验证结果
        XCTAssertEqual(posts.count, 2)
        XCTAssertEqual(posts[0].title, "Test Post")
        XCTAssertEqual(posts[1].title, "Test Post 2")
    }
    
    func testLikePost() async throws {
        // 准备测试数据
        let postID = "test-post"
        let userID = "test-user"
        
        // 执行测试
        try await firestoreService.likePost(postID: postID, userID: userID)
        
        // 验证事务操作
        XCTAssertTrue(mockFirestore.didRunTransaction)
        XCTAssertEqual(mockFirestore.updatedDocuments.count, 2)
    }
}

// Mock类实现
class MockFirestore: Firestore {
    var mockDocuments: [DocumentSnapshot] = []
    var didRunTransaction = false
    var updatedDocuments: [String: [String: Any]] = [:]
    
    override func collection(_ collectionPath: String) -> CollectionReference {
        return MockCollectionReference(firestore: self, path: collectionPath)
    }
    
    override func runTransaction(_ updateBlock: @escaping (Transaction, NSErrorPointer) -> Any?) async throws -> Any? {
        didRunTransaction = true
        let transaction = MockTransaction(firestore: self)
        var error: NSError?
        return updateBlock(transaction, &error)
    }
}

集成测试策略

class IntegrationTests: XCTestCase {
    var app: XCUIApplication!
    
    override func setUp() {
        super.setUp()
        continueAfterFailure = false
        
        app = XCUIApplication()
        app.launchEnvironment = ["FIREBASE_EMULATORS": "true"]
        app.launch()
    }
    
    func testUserRegistrationFlow() {
        // 启动注册界面
        app.buttons["Sign Up"].tap()
        
        // 填写注册信息
        let emailTextField = app.textFields["Email"]
        emailTextField.tap()
        emailTextField.typeText("test@example.com")
        
        let passwordTextField = app.secureTextFields["Password"]
        passwordTextField.tap()
        passwordTextField.typeText("password123")
        
        // 提交注册
        app.buttons["Register"].tap()
        
        // 验证注册成功
        XCTAssertTrue(app.staticTexts["Welcome"].waitForExistence(timeout: 5))
    }
    
    func testPostCreation() {
        // 登录
        loginIfNeeded()
        
        // 创建新帖子
        app.buttons["New Post"].tap()
        
        let titleTextField = app.textFields["Title"]
        titleTextField.tap()
        titleTextField.typeText("Integration Test Post")
        
        let contentTextView = app.textViews["Content"]
        contentTextView.tap()
        contentTextView.typeText("This is a test post created during integration testing.")
        
        app.buttons["Publish"].tap()
        
        // 验证帖子创建成功
        XCTAssertTrue(app.staticTexts["Integration Test Post"].waitForExistence(timeout: 3))
    }
    
    private func loginIfNeeded() {
        if app.buttons["Login"].exists {
            app.textFields["Email"].tap()
            app.textFields["Email"].typeText("test@example.com")
            
            app.secureTextFields["Password"].tap()
            app.secureTextFields["Password"].typeText("password123")
            
            app.buttons["Login"].tap()
        }
    }
}

性能优化与最佳实践

数据库查询优化

struct QueryOptimizer {
    // 使用复合索引
    static func createOptimalIndexes() {
        // Firestore会自动建议创建复合索引
        // 对于常见查询模式,提前创建索引
    }
    
    // 查询限制优化
    static func optimizeQuery(_ query: Query, for context: QueryContext) -> Query {
        var optimizedQuery = query
        
        // 添加必要的where条件
        if context.requiresPublished {
            optimizedQuery = optimizedQuery.whereField("is_published", isEqualTo: true)
        }
        
        // 限制返回字段
        if let fields = context.fieldsToReturn {
            optimizedQuery = optimizedQuery.selecting(fields)
        }
        
        // 添加分页
        if let limit = context.limit {
            optimizedQuery = optimizedQuery.limit(to: limit)
        }
        
        return optimizedQuery
    }
    
    // 批量操作优化
    static func performBatchOperations(_ operations: [() async throws -> Void]) async throws {
        // 使用Firestore的批量写入
        let batch = Firestore.firestore().batch()
        
        for operation in operations {
            try await operation()
        }
        
        try await batch.commit()
    }
}

struct QueryContext {
    let requiresPublished: Bool
    let fieldsToReturn: [String]?
    let limit: Int?
    let orderBy: String?
    let descending: Bool?
}

网络请求优化

class NetworkOptimizer {
    // 请求去重
    private var ongoingRequests: [String: Task<Any, Error>] = [:]
    private let lock = NSLock()
    
    func deduplicatedRequest<T>(key: String, operation: @escaping () async throws -> T) async throws -> T {
        lock.lock()
        defer { lock.unlock() }
        
        if let existingTask = ongoingRequests[key] as? Task<T, Error> {
            return try await existingTask.value
        }
        
        let task = Task {
            defer {
                lock.lock()
                ongoingRequests.removeValue(forKey: key)
                lock.unlock()
            }
            return try await operation()
        }
        
        ongoingRequests[key] = task as? Task<Any, Error>
        return try await task.value
    }
    
    // 请求缓存
    private var cache: [String: (data: Any, timestamp: Date)] = [:]
    private let cacheTTL: TimeInterval = 300 // 5分钟
    
    func cachedRequest<T: Codable>(key: String, operation: @escaping () async throws -> T) async throws -> T {
        if let cached = cache[key], Date().timeIntervalSince(cached.timestamp) < cacheTTL {
            return cached.data as! T
        }
        
        let result = try await operation()
        cache[key] = (result, Date())
        return result
    }
    
    // 请求优先级管理
    func prioritizedRequest<T>(priority: TaskPriority = .medium, operation: @escaping () async throws -> T) async throws -> T {
        return try await Task(priority: priority) {
            try await operation()
        }.value
    }
}

安全防护与合规性

数据安全策略

class SecurityManager {
    // 数据加密
    static func encryptData(_ data: Data, key: String) throws -> Data {
        // 使用iOS内置的加密框架
        // 实际实现应使用Keychain和CryptoKit
        return data // 简化示例
    }
    
    static func decryptData(_ encryptedData: Data, key: String) throws -> Data {
        return encryptedData // 简化示例
    }
    
    // 输入验证
    static func validateInput(_ input: String, type: InputType) -> Bool {
        switch type {
        case .email:
            let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
            return NSPredicate(format: "SELF MATCHES %@", emailRegex).evaluate(with: input)
        case .password:
            return input.count >= 8 && input.count <= 128
        case .username:
            let usernameRegex = "^[a-zA-Z0-9_]{3,20}$"
            return NSPredicate(format: "SELF MATCHES %@", usernameRegex).evaluate(with: input)
        }
    }
    
    // XSS防护
    static func sanitizeHTML(_ html: String) -> String {
        // 使用专业的HTML清理库
        // 这里使用基础过滤作为示例
        return html.replacingOccurrences(of: "<script", with: "&lt;script")
                  .replacingOccurrences(of: "</script>", with: "&lt;/script&gt;")
    }
    
    // CSRF防护
    static func generateCSRFToken() -> String {
        return UUID().uuidString
    }
    
    static func validateCSRFToken(_ token: String) -> Bool {
        // 验证token的有效性
        return !token.isEmpty
    }
}

enum InputType {
    case email
    case password
    case username
}

合规性检查

class ComplianceChecker {
    // GDPR合规检查
    static func checkGDPRCompliance() -> [ComplianceIssue] {
        var issues: [ComplianceIssue] = []
        
        // 检查数据收集同意
        if !UserDefaults.standard.bool(forKey: "hasDataCollectionConsent") {
            issues.append(.missingDataCollectionConsent)
        }
        
        // 检查隐私政策版本
        let acceptedPrivacyPolicyVersion = UserDefaults.standard.string(forKey: "privacyPolicyVersion") ?? ""
        let currentPrivacyPolicyVersion = "2.0" // 从配置读取
        
        if acceptedPrivacyPolicyVersion != currentPrivacyPolicyVersion {
            issues.append(.privacyPolicyUpdateRequired)
        }
        
        return issues
    }
    
    // 数据本地化检查
    static func checkDataLocalization() -> Bool {
        // 检查用户数据存储位置是否符合当地法规
        // 这里简化实现
        return true
    }
    
    // 用户数据访问权限检查
    static func checkUserDataAccess() -> [DataAccessIssue] {
        var issues: [DataAccessIssue] = []
        
        // 检查是否需要提供数据导出功能
        // 检查数据删除功能
        
        return issues
    }
}

enum ComplianceIssue {
    case missingDataCollectionConsent
    case privacyPolicyUpdateRequired
    case dataLocalizationViolation
}

enum DataAccessIssue {
    case dataExportRequired
    case dataDeletionRequired
}

部署与监控

持续集成配置

# .github/workflows/ci.yml
name: Firebase iOS CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: macos-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Select Xcode
      run: sudo xcode-select -switch /Applications/Xcode_15.2.app
      
    - name: Install CocoaPods
      run: gem install cocoapods
      
    - name: Install Dependencies
      run: pod install
      
    - name: Run Unit Tests
      run: xcodebuild test -workspace YourApp.xcworkspace -scheme YourApp -destination 'platform=iOS Simulator,name=iPhone 15,OS=17.2'
      
    - name: Run Integration Tests
      run: xcodebuild test -workspace YourApp.xcworkspace -scheme YourAppIntegrationTests -destination 'platform=iOS Simulator,name=iPhone 15,OS=17.2'
      
    - name: Upload Test Results
      uses: actions/upload-artifact@v3
      if: always()
      with:
        name: test-results
        path: build/reports/tests/
        
  build:
    runs-on: macos-latest
    needs: test
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Select Xcode

【免费下载链接】firebase-ios-sdk 适用于苹果应用开发的Firebase SDK。 【免费下载链接】firebase-ios-sdk 项目地址: https://gitcode.com/GitHub_Trending/fi/firebase-ios-sdk

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值