firebase-ios-sdk

Framework

firebase/firebase-ios-sdk

Official Firebase SDK for Apple platforms: auth, database, messaging, AI and more.

Overview

The official open-source Firebase SDK for iOS, macOS, tvOS, watchOS and visionOS. It bundles client libraries for Authentication, Cloud Firestore, Realtime Database, Cloud Messaging, Crashlytics, Remote Config, Storage, AI Logic and more. Distributed via Swift Package Manager and CocoaPods to help developers build, grow and monetize Apple apps.

README Preview

\n  \n    \n  \n  \n    \n  \n  \n    \n  \n  \n    \n  \n  \n    \n  \n\n\n> [!WARNING]\n> **CocoaPods:** New versions of the Firebase Apple SDK will no longer be\n> published to CocoaPods after **October 2026**. Existing CocoaPods versions\n> will remain available and installations will remain functional. See the\n> [migration guide](https://firebase.google.com/docs/ios/cocoapods-deprecation)\n> for more information.\n\n> [!TIP]\n> **Preview Release:** Firebase AI Logic's Gemini Foundation Models framework\n> adapter is now available in preview. Get started by visiting the\n> [documentation](https://firebase.google.com/docs/ai-logic/apple-foundation-models-framework/get-started).\n\n# Firebase Apple Open Source Development\n\nThis repository contains the source code for all Apple platform Firebase\nlibraries except `FirebaseAnalytics`.\n\nFirebase is an app development platform with libraries, services, and tools to\nhelp you build, grow, and monetize your app. Learn more about Firebase at the\n[official Firebase website](https://firebase.google.com).\n\n### Supported Firebase Products\n\nThe following products are open-source and included in this repository:\n\n*   [Firebase AI Logic](https://firebase.google.com/docs/ai-logic) (`FirebaseAI`)\n*   [App Check](https://firebase.google.com/docs/app-check) (`FirebaseAppCheck`)\n*   [App Distribution](https://firebase.google.com/docs/app-distribution) (`FirebaseAppDistribution`)\n*   [Authentication](https://firebase.google.com/docs/auth) (`FirebaseAuth`)\n*   [Cloud Firestore](https://firebase.google.com/docs/firestore) (`FirebaseFirestore`)\n*   [Cloud Functions](https://firebase.google.com/docs/functions) (`FirebaseFunctions`)\n*   [Cloud Messaging](https://firebase.google.com/docs/cloud-messaging) (`FirebaseMessaging`)\n*   [Crashlytics](https://firebase.google.com/docs/crashlytics) (`FirebaseCrashlytics`)\n*   [In-App Messaging](https://firebase.google.com/docs/in-app-messaging) (`FirebaseInAppMessaging`)\n*   [Pe

FAQ (5)

Troubleshooting
How to fix Firebase iOS crash EXC_BAD_ACCESS in GULNetworkURLSession setSessionInFetcherMap:forSessionID:?

This crash (EXC_BAD_ACCESS / KERN_INVALID_ADDRESS in -[NSConcreteMapTable setObject:forKey:] called from +[GULNetworkURLSession setSessionInFetcherMap:forSessionID:]) is a known bug in GoogleUtilities 8.1.0 and earlier (tracked as GoogleUtilities#228). It was fixed in GoogleUtilities 8.1.1, with further hardening up to 8.1.5. Since Firebase 12.14.0 only requires GoogleUtilities ~> 8.1, CocoaPods may keep 8.1.0 pinned in your Podfile.lock. Check your Podfile.lock for the GoogleUtilities version, then run: pod update GoogleUtilities to pull 8.1.1 or later (8.1.5 recommended), and rebuild.

GitHub Issue #16905
Troubleshooting
How to fix "Unexpected format for streamed response" (dataLoss) error in Firebase Functions HTTPSCallable.stream() on iOS?

This error occurs when a streaming callable function stays idle for more than 30 seconds. firebase-functions (v7.x) sends an SSE comment line (: ping) as a heartbeat after 30s of inactivity (default heartbeatSeconds: 30), but the Firebase iOS SDK's parser in Functions.swift only accepts lines starting with data: and throws FunctionsError(.dataLoss) on anything else.

Workaround: disable or raise the heartbeat in your Cloud Function's CallableOptions:

import { onCall } from 'firebase-functions/v2/https';

export const slow = onCall({ heartbeatSeconds: null }, async (req, res) => {
  await new Promise((r) => setTimeout(r, 40_000));
  res.sendChunk('hello');
  return 'done';
});

Alternatively, set heartbeatSeconds to a value larger than your function's longest expected idle time (e.g., heartbeatSeconds: 60). Note: disabling the heartbeat may allow intermediate proxies or load balancers to close long-idle connections. The Node client and web SDK handle : ping comments correctly; a permanent fix requires the iOS SDK to skip SSE comment lines per the SSE spec.

GitHub Issue #16605
Troubleshooting
Why does Firebase Data Connect for iOS crash with a 'malformedTimestamp' fatal error when decoding a date-like string?

In FirebaseDataConnect (11.12.6 and earlier, including main @ be6a46f), Timestamp.init(from:) validates strings with a regex that only checks the format (^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}...), not value ranges, then force-tries try! Google_Protobuf_Timestamp(jsonString:). Strings that match the format but are out of range — e.g. "2026-13-01T00:00:00Z" (month 13), "2026-01-01T24:00:00Z" (hour 24), "0000-01-01T00:00:00Z" (year 0) — pass the regex but throw SwiftProtobuf.JSONDecodingError.malformedTimestamp, and the try! crashes the process. Because AnyCodableValue.init(from:) attempts Timestamp first for every JSON string, any GraphQL String or Any/JSON field holding such a value triggers the crash — including during client-cache dehydration on the first fetch, so it recurs on every run of that query. Fix: in CodableTimestamp.swift (line ~61-62), replace try! with try in init(from:) — the initializer already throws, and AnyCodableValue then falls back to .string through its existing try?, while decoding as an actual Timestamp throws DataConnectCodecError. A PR with tests is open at firebase/data-connect-ios-sdk#123; update the SDK once it is merged and released. Until then, sanitize data so out-of-range date-like values never match the timestamp regex (e.g. change the stored format), and note that disabling the client cache does not fully avoid the crash for Any/JSON fields.

GitHub Issue #16888
Troubleshooting
Why does removeStateDidChangeListener not release the listener in Firebase Auth for iOS (memory leak)?

This is a known bug in Firebase iOS SDK versions 11.0.0 through 13.1.0 (a regression from the Swift rewrite of Auth). addIDTokenDidChangeListener(_:) stores the listener closure in listenerHandles, but removeStateDidChangeListener(_:), removeIDTokenDidChangeListener(_:) and deinit try to remove the observer *handle* from that array. Since the handle never matches the stored closure, removal is a no-op: every listener you add (and everything it captures) stays alive for the lifetime of the Auth instance — which for Auth.auth() is the entire app session. Repeatedly adding/removing listeners (e.g., per screen or per reactive subscription) leaks memory without bound.

**Fix:** Upgrade to Firebase iOS SDK 13.2.0 or later, where the fix (storing the observer handle instead of the closure) has merged.

**Workaround for older versions:** Capture state weakly inside the listener closure so the retained closure doesn't keep other objects alive:

let handle = Auth.auth().addStateDidChangeListener { [weak self] _, user in
    guard let self = self else { return }
    // handle auth state change
}

Note that addStateDidChangeListener is built on addIDTokenDidChangeListener, so both APIs are affected.

GitHub Issue #16938
Troubleshooting
How to fix Firestore iOS crash 'FIRInvalidArgumentException: Invalid path... Paths must not contain //' when passing a URL as document ID?

Firestore validates document paths in Objective-C and throws an NSException (FIRInvalidArgumentException), which Swift's do-catch cannot intercept — so the app always crashes on invalid input. The only reliable fix is to validate/sanitize the ID yourself before calling document(id). Document IDs must not contain /, must not be . or .., must be non-empty, and must be ≤1500 bytes.

Validate first:

func isValidDocumentID(_ id: String) -> Bool {
    return !id.isEmpty
        && !id.contains("/")
        && id != "." && id != ".."
        && id.utf8.count <= 1500
}

guard isValidDocumentID(id) else { return /* reject or transform */ }
let docRef = db.collection(recipeShareCollection).document(id)

Better approach for URLs: never use a raw URL as a document ID. Hash it instead:

import CryptoKit
let docID = SHA256.hash(data: Data(urlString.utf8))
    .map { String(format: "%02x", $0) }.joined()
let docRef = db.collection(recipeShareCollection).document(docID)

Base64-url encoding or UUID v5 also work. This guarantees a safe, deterministic ID regardless of input.

GitHub Issue #15775