Warning
This project is archived and no longer maintained.
Please use pyios-firebase instead.
It uses Rubicon-ObjC, so you write
pure Python and no Objective-C (.m) code.
pyobjus-firebase was built on top of pyobjus. With it, many Firebase features
needed Objective-C (.m) code next to your Python code. That made the project
harder to set up, harder to read, and harder to maintain.
pyios-firebase uses Rubicon-ObjC instead. Everything is written in pure Python.
You do not need to write or compile any .m files. Keeping two projects for the
same job would only split the effort, so this one is now read-only.
- Install
pyios-firebaseand follow its README. - Replace the
pyobjus-firebaseimports in your code with the new ones. - Delete any
.mor.hfiles you added only forpyobjus-firebase. - If something does not work, open an issue on the new repo, not this one.
- No new features, fixes, or releases will come to this repo.
- The code stays here so old links and old builds keep working.
- Issues and pull requests are closed.
Native Objective-C bridges that make Firebase's block-based iOS SDKs usable from pyobjus — built for Kivy apps running on iOS via kivy-ios.
Part of the SimpleObjus organisation — bridges and tooling for using native Objective-C/iOS APIs from Python.
Firebase's iOS SDKs lean heavily on Objective-C blocks for callbacks — auth state listeners, completion handlers, snapshot listeners, and so on. pyobjus has no way to hand a Python callable to a method expecting a block argument, so calls like these can't be made directly from Python:
[[FIRAuth auth] addAuthStateDidChangeListener:^(FIRAuth *auth, FIRUser *user) {
// never reachable from pyobjus
}];pyobjus-firebase solves this with a small, native "bridge" layer: tiny Objective-C classes that call the block-based Firebase APIs internally and re-expose the results through plain delegate protocols — which pyobjus can call into via objc_delegate/@protocol. Your Python code never touches a block; it just implements a normal delegate method.
| Bridge | Wraps | Status |
|---|---|---|
FirebaseAuthBridge |
FIRAuth — auth state listener, email/password sign-up, Google Sign-In, sign-out |
✅ Stable |
FirestoreBridge |
Firestore — document/collection listeners, reads, writes |
🚧 Planned |
RealtimeDBBridge |
FIRDatabase — value/child event observers, transactions |
🚧 Planned |
StorageBridge |
FIRStorage — upload/download progress and completion |
🚧 Planned |
MessagingBridge |
FIRMessaging — push token and message callbacks |
🚧 Planned |
FunctionsBridge |
FIRFunctions (Cloud Functions client SDK) — callable function invocation |
🚧 Planned |
AppCheckBridge |
FIRAppCheck — token provider callbacks and token refresh listeners |
🚧 Planned |
AILogicBridge |
Firebase AI Logic (Vertex AI in Firebase / Gemini API) — streaming and completion callbacks for generative model calls | 🚧 Planned |
Contributions adding new bridges (Analytics, Remote Config, Crashlytics, Dynamic Links successor / App Links handling, In-App Messaging, Performance Monitoring, etc.) are very welcome — see Contributing.
Every bridge follows the same shape:
- A native Objective-C class (e.g.
FirebaseAuthBridge) wraps one Firebase feature area and internally holds the real block-based calls. - A companion
@protocol(e.g.FirebaseAuthBridgeDelegate) declares the callback methods, with every method marked@optionalso a Python delegate only needs to implement the ones it actually uses. - Each protocol is force-registered into the Objective-C runtime via an
__attribute__((constructor))function, so pyobjus'sobjc_getProtocol()can always find it — regardless of dead-code stripping or link order. - From Python, you
autoclass()the bridge, assign a plain Python object as itsdelegate, and implement whichever callback methods you need using pyobjus's@protocol(...)decorator.
Firebase SDK (blocks)
│
▼
FirebaseXyzBridge.m ── native shim, calls the block API internally
│
▼
FirebaseXyzBridgeDelegate ── plain Objective-C protocol
│
▼
pyobjus @protocol(...) ── your Python delegate methods
This is source you drop into your kivy-ios Xcode project — it is not a CocoaPod, framework, or pip package, since it has to be compiled directly into your app target alongside your existing Firebase setup.
- Copy
FirebaseAuthBridge.handFirebaseAuthBridge.m(and any other*Bridge.h/.mpairs you need) into your Xcode project. - Make sure they're checked under your app target's Compile Sources build phase.
- If your project compiles under manual reference counting (MRC) by default, either:
- leave the bridge files as-is (they're written to be MRC-compatible, using
unsafe_unretainedinstead ofweak), or - enable ARC for just these files via
-fobjc-arcin Compiler Flags, if you'd rather useweak.
- leave the bridge files as-is (they're written to be MRC-compatible, using
- Make sure Firebase (and Google Sign-In, if you're using that bridge) are already linked in your project — via CocoaPods, SPM, or manually — since these bridge files assume the relevant headers are already resolvable.
- pyobjus, installed and working in your kivy-ios build
- Firebase iOS SDK (
FirebaseAuth, plus whichever product a given bridge wraps) - Xcode project targeting iOS 13+
from pyobjus import autoclass, protocol
autoclass("FIRApp").configure()
FirebaseAuthBridge = autoclass("FirebaseAuthBridge")
class AuthDelegate:
@protocol("FirebaseAuthBridgeDelegate")
def authStateChanged_user_(self, auth, user):
if user:
print("Signed in as:", user.email().UTF8String())
else:
print("Signed out")
bridge = FirebaseAuthBridge.alloc().init()
delegate = AuthDelegate()
bridge.delegate = delegate
bridge.addAuthStateDidChangeListener()
# keep `bridge` and `delegate` alive for as long as you want the listener activeclass AuthDelegate:
@protocol("FirebaseAuthBridgeDelegate")
def userCreated_error_(self, auth_result, error):
if error:
print("Sign-up failed:", error.localizedDescription().UTF8String())
else:
print("User created:", auth_result.user().uid().UTF8String())
bridge.createUserWithEmail_password_("[email protected]", "hunter22")GIDConfiguration = autoclass("GIDConfiguration")
GIDSignIn = autoclass("GIDSignIn")
FIRApp = autoclass("FIRApp")
FIRGoogleAuthProvider = autoclass("FIRGoogleAuthProvider")
client_id = FIRApp.defaultApp().options().clientID()
config = GIDConfiguration.alloc().initWithClientID_(client_id)
GIDSignIn.sharedInstance().setConfiguration_(config)
class AuthDelegate:
@protocol("FirebaseAuthBridgeDelegate")
def signInWithGoogleCompletion_error_(self, result, error):
if error:
print("Google sign-in failed:", error.localizedDescription().UTF8String())
return
user = result.user()
credential = FIRGoogleAuthProvider.credentialWithIDToken_accessToken_(
user.idToken().tokenString(), user.accessToken().tokenString()
)
# pass `credential` on to FIRAuth signInWithCredential:completion:
# call this from a real user action (a button press), never during app startup —
# the presenting view controller isn't ready that early
bridge.signInWithGoogle()Important: trigger signInWithGoogle() from an actual user interaction (e.g. a button's on_press), not from __init__ or any other app-startup code path. Calling it before the app's window is fully up and key can silently fail and surface as a misleading "user canceled the sign-in flow" error.
success = bridge.signOut()
if not success:
print("Sign-out failed:", bridge.lastError().localizedDescription().UTF8String())- URL scheme (Google Sign-In only): add your
GoogleService-Info.plist'sREVERSED_CLIENT_IDas aCFBundleURLTypesentry inInfo.plist— this is required even though the sign-in flow is otherwise self-contained. application:openURL:options:: if your app doesn't already have an editableAppDelegate.m(true for kivy-ios/SDL2 apps, where the delegate class isSDLUIKitDelegate), add it via an Objective-C category rather than editing SDL2's own source. Seedocs/url-handling.md(coming soon) for the full pattern.
New bridges should follow the existing pattern in FirebaseAuthBridge.h/.m:
- Add a
@protocol FooBridgeDelegatewith@optionalmethods for each callback. - Add one line to the shared
_RegisterFirebaseBridgeProtocols()constructor for the new protocol. - Add a
FooBridgeclass wrapping the relevant Firebase calls. - Include a usage example in this README.
Issues and PRs welcome — including bug reports on existing bridges, new Firebase product coverage, and documentation improvements.
MIT — see LICENSE.
This project is not affiliated with or endorsed by Google or Firebase. "Firebase" and "Google Sign-In" are trademarks of Google LLC.