Fix "APNS token has not been set yet" in Flutter on iOS
---
title: Fix "APNS token has not been set yet" in Flutter on iOS
published: true
date: 2026-11-05 00:00:00 UTC
tags: flutter,ios,firebase,dart
canonical_url: saymyframe.com
---
On iOS, Firebase delivers push notifications through Apple's push service (APNs), so FirebaseMessaging.instance.getToken() refuses to run until Apple has given the device its APNs token. Called earlier, it throws apns-token-not-set, which older versions of firebase_messaging describe as "APNS token has not been set yet". Usually the app just asked too early. How it should wait depends on the version: firebase_messaging 17 tells the app when Firebase is ready, and 16.7 doesn't. In a few setups, though, Apple never answers, however long the app waits.
I checked everything below on an iPhone 17 simulator with iOS 26.5, Xcode 27.2 and Flutter 3.44.2, with firebase_messaging 16.7.1 (Firebase iOS SDK 12.19.3) and 17.0.1 (Firebase iOS SDK 13.1.1).
APNS token has not been set yet, or has not been received on the device yet
The error comes in two wordings. Older versions say:
[firebase_messaging/apns-token-not-set] APNS token has not been set yet. Please ensure the APNS token is available by calling `getAPNSToken()`.
Since October 2025 (firebase_messaging 16.0.3, with firebase_messaging_platform_interface 4.7.3), the same error says:
[firebase_messaging/apns-token-not-set] APNS token has not been received on the device yet. Please ensure the APNS token is available before calling `getAPNSToken()`.
Both are a FirebaseException with the code apns-token-not-set, so check the code rather than the text. The hint to call getAPNSToken() is misleading, because that call never throws. It returns null until Apple has answered, which makes it the thing to wait on.
The check runs in Dart, before anything reaches iOS. getToken(), deleteToken(), subscribeToTopic() and unsubscribeFromTopic() all start with it. So a topic subscription at startup fails with the same error, while requestPermission() and onMessage work. If you use Firebase from Swift, the native SDK reports the same situation as No APNS token specified before fetching FCM Token.
Why getToken() fails right after the app starts
At launch, the plugin asks iOS to register the app for remote notifications, and iOS answers later, in application:didRegisterForRemoteNotificationsWithDeviceToken:. The Firebase iOS SDK keeps that answer in memory only. So an early getToken() fails on every launch, not just the first one, even when Firebase gave the app its FCM token on the previous launch.
How long the answer takes varies: about half a second on a simulator that had been running for a while, and about 30 seconds right after the simulator booted. On a phone, it depends on the network.
I checked this with a small app that calls getToken() right after Firebase.initializeApp(), after a fresh install and after a restart, with both versions. The call failed every time, although Apple answered within a second. What differs between the versions is whether the app learns that Firebase is ready.
firebase_messaging 16: wait for getAPNSToken()
With 16.7.1, the Firebase iOS SDK requests the FCM token by itself as soon as Apple answers (the log shows the app connecting to fcmtoken.googleapis.com), but the plugin doesn't pass it on to Dart: onTokenRefresh stayed silent for the 20 seconds I waited, after a fresh install and after a restart. So the app has to wait for getAPNSToken() itself, then call getToken():
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
/// The FCM token of this device once Apple has answered, or `null` when
/// Apple hasn't within [limit].
Future<String?> pushTokenWhenReady({
Duration limit = const Duration(minutes: 2),
}) async {
final messaging = FirebaseMessaging.instance;
if (!kIsWeb && defaultTargetPlatform == TargetPlatform.iOS) {
var wait = const Duration(milliseconds: 500);
var waited = Duration.zero;
while (await messaging.getAPNSToken() == null) {
if (waited >= limit) return null;
await Future<void>.delayed(wait);
waited += wait;
if (wait < const Duration(seconds: 8)) wait *= 2;
}
}
return messaging.getToken();
}
Don't await it before runApp(). I found apps on GitHub that opened to a white screen on iOS for exactly this reason: main() waited, getToken() threw, and runApp() never ran. Start the app first and send the result to your server when it arrives:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
runApp(const MyApp());
final token = await pushTokenWhenReady();
if (token != null) await sendTokenToServer(token);
}
If the wait runs out, try again when the user comes back to the app, for example from an AppLifecycleListener with onResume.
firebase_messaging 17: listen to onTokenRefresh
Since 17.0.0, released in October 2026, the plugin becomes the delegate of the Firebase iOS SDK during Firebase.initializeApp(), so onTokenRefresh gets two events that 16 lost. After a fresh install, it fires as soon as the SDK has the FCM token, in my runs 1.4 seconds after Apple answered. On every later launch, it fires right at startup with the value that the SDK saved last time: 0.2 seconds after main() started, before Apple had answered and while getToken() still threw.
So on 17, subscribe to onTokenRefresh right after initializeApp(), and keep the getToken() call for Android, where it doesn't depend on Apple:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
final messaging = FirebaseMessaging.instance;
messaging.onTokenRefresh.listen(sendTokenToServer);
runApp(const MyApp());
try {
final token = await messaging.getToken();
if (token != null) await sendTokenToServer(token);
} on FirebaseException catch (e) {
// On iOS before Apple has answered: onTokenRefresh delivers it.
if (e.code != 'apns-token-not-set') rethrow;
}
}
Your server may get the same value twice this way, so it should accept one that it already has. Subscribe early, because onTokenRefresh is a broadcast stream and a listener that comes after the startup event never sees it. If your code subscribes later, after a sign-in for example, wait for getAPNSToken() as with 16.
Firebase is also moving Cloud Messaging from registration tokens to the Firebase Installation ID (FID). Version 17 deprecates getToken(), onTokenRefresh and deleteToken() in favor of register(), onRegistered and unregister(), and flutter analyze exits with code 1 on the code above because of the deprecation infos. I haven't tried the FID path yet, so this article stays with getToken().
When the APNs token never comes
If getAPNSToken() still returns null after a minute, waiting longer won't help. These are the cases I know of.
No aps-environment entitlement
iOS registers an app for remote notifications only when the build is signed with the aps-environment entitlement, which Xcode adds with the Push Notifications capability in Signing & Capabilities. Without it, the Xcode console shows:
[FirebaseMessaging][I-FCM012002] Error in application:didFailToRegisterForRemoteNotificationsWithError: no valid "aps-environment" entitlement string found
The simulator follows the same rule. A build made with flutter build ios --simulator --no-codesign doesn't get the entitlement, and mine waited two minutes for Apple in vain.
A free Apple team
A personal team can't sign aps-environment. To run the app on an iPhone, you have to remove the capability, and then Apple never answers there. The simulator doesn't need a team, since Xcode signs simulator builds ad hoc.
The iOS simulator on GitHub Actions
The iOS simulator on a Mac gets a real APNs token. On a macOS virtual machine it never does, and the macOS runners of GitHub Actions are virtual machines. I tried a macos-26 runner: the app was built with the entitlement, nothing came in four minutes, and the push daemon logged no token info found in keychain before it disconnected. actions/runner-images#12747 reports the same for macos-15. A CI job on a hosted runner can check that the app starts without push notifications, but not that it gets them.
firebase_messaging 16.5.0 and 16.6.0
These two versions skipped the registration for remote notifications at launch in two common setups: when Firebase is initialized from Dart, as with Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform) (flutterfire#18643), and in apps with scenes (flutterfire#18555), which the iOS template of current Flutter creates with SceneDelegate.swift. getAPNSToken() then stayed null on every launch. Version 16.7.0 fixed both. Check which version your app has:
flutter pub deps | grep firebase_messaging
Auto-init is off
With FirebaseMessagingAutoInitEnabled set to NO in Info.plist, or after setAutoInitEnabled(false), the plugin doesn't register for remote notifications. Call setAutoInitEnabled(true) before you start waiting.
Not the APNs key
The APNs key in the Firebase console doesn't belong on this list. Firebase needs it to send messages through Apple, so without it nothing arrives, but getAPNSToken() and getToken() work all the same.
How SMF handles push notifications on iOS
The firebase_messaging module of SMF, a free, open-source Flutter project generator, gives the app the address of the device as appPush.address, which stays null until Firebase has one. The first frame never waits for it. On iOS, the module polls getAPNSToken() as above, waiting from half a second up to eight seconds between tries, for at most two minutes, and asks again whenever the user comes back to the app. It adds aps-environment and the background mode remote-notification, and the README of the app explains what to do with a free team. Uploading the APNs key stays a step you do by hand. SMF's CI starts the apps on the iOS simulator of a hosted runner, where they have to start and work without an address.
Build Responsive, AI-powered Apps with Cloud Functions for Firebase: Web Architecture & Implementation Guide
Original: codingcat.dev
Calling frontier multimodal models directly from a web or mobile client is a security minefield if you expose raw API keys or hardcode brittle system prompts in your frontend bundle. Following the announcement of Build Responsive, AI-powered Apps with Cloud Functions for Firebase by Daniel Lee, Jeff Huleatt on the Official Firebase Blog (2025-03-06), here is our hands-on CodingCat.dev breakdown of what actually shipped, how it works under the hood, and how we wire it into production TypeScript, Next.js, Astro, SvelteKit, React, and Angular applications. App users demand instant, dynamic app experiences, whether they’re chatting with an AI assistant, generating content in real time, or waiting for live data.
The Mental Model: Why Build Responsive, AI-powered Apps with Cloud Functions for Firebase Matters for Web Devs
As a Google Developer Expert (GDE) for Firebase and Senior Solutions Architect at CodingCat.dev, I evaluate every Firebase update through one lens: does it reduce boilerplate while keeping our runtime security and cloud bills predictable? Firebase AI Logic lets you invoke Gemini and Imagen models from client and edge apps using the Firebase Web SDK while keeping your API credentials off the wire, enforcing Firebase App Check, and managing server-side prompt templates centrally.
> AJ Pro-Tip from Alex: Combine Firebase AI Logic with server prompt templates, Firebase Remote Config feature flags, and project spend caps so you can iterate on prompts or swap Gemini models instantly without redeploying your Next.js or Astro frontend.
How It Works: Technical Breakdown & Implementation
Since their introduction in 2017, Cloud Functions for Firebase’s callable functions have focused on providing you with a streamlined server(less) development experience that simplifies server-to-client interactions. Now, The Firebase team announced two new features that make it easier than ever to build responsive, AI-powered apps:
Streaming responses for callable functions, Deliver data incrementally to clients.
A new onCallGenkit trigger, Seamlessly integrate Firebase Genkit to productionize generative AI workflows.
**Note: **In this post, we show how to stream data from a Node.js callable function to a client web app that’s using the Firebase JS SDK. We’re also working on bringing this to the Python functions SDK, as well as our Swift, Kotlin, and Dart client SDKs.
Send data to your app as it is generated
Traditionally, when a client application calls a server function, it has to wait for the entire response to be generated before it can do anything. This “all-or-nothing” approach works well for many scenarios, but it falls short when dealing with:
Why do generative AI APIs return their responses token-by-token?
With the new streaming capability for Callable Functions, your server can send data to the client in chunks, as it becomes available. The client can then process and display this data incrementally, creating a much more responsive and engaging user experience.
Imagine Firebase is building a web app for weather enthusiasts or frequent travelers that want to see the forecast for lots of locations at once, and that it calls a callable function to get these forecasts. Without streaming, they’d have to sit and wait while the forecast for each location is fetched, and can only start browsing the results once every location’s forecast is fetched and returned from the server.
With streaming, our weather enthusiasts can start viewing each location’s data as soon as it’s ready:
To stream results, check the acceptsStreaming field of the request object, and call response.sendChunk every time you have a chunk of data that’s ready to send back to the client. Return the full dataset at the end for clients that don’t accept streaming.
exports
const
const
const
// Stream each forecast as it resolves!
if
response.
}
return
});
// Fallback for non-streaming clients
return
});
Use the Firebase client SDKs to consume the streaming response from a web app:
const
const
for
updateUI
}
const
If you’re already using callable functions in your app, adding streaming behavior may just be a small change to your server and client code that results in big user-experience benefits!
For generative AI applications, The Firebase team built a new onCallGenkit trigger on top of this new streaming functionality.
Productionize Your AI-Powered Apps Faster
Firebase Genkit is an all-in-one toolkit to prototype, test, build, and monitor production-ready generative AI applications. The new onCallGenkit trigger now lets you deploy Genkit flows as secure, scalable APIs with one line:
// An example Genkit flow.
const
{
name:
// ...
},
async
const
`
);
for
sendChunk
}
return
},
);
// Deploy the flow with Cloud Functions for Firebase
exports
As above, use the functions SDK to consume the results from a client app:
const
const
for
updateUI
}
const
With onCallGenkit, you leverage all features we offer in Cloud Functions for Firebase, like:
**Simplified Deployment: **Deploy your Genkit flows with just the firebase deploy command you are familiar with.
**Automatic Streaming: **onCallGenkit automatically handles the streaming setup for you. Just use sendChunk() within your Genkit flow, and call the stream method from the client SDK.
**Built-in Abuse Prevention: **Protect your AI-powered function with Firebase App Check.
**Secret Management: **Securely store and access API keys and other sensitive information with enterprise-grade Cloud Secret Manager.
**Concurrency: **Benefit from Cloud Function for Firebase 2nd gen features like concurrency to scale your service efficiently. With concurrency, one function instance can handle multiple concurrent requests, a great fit for AI applications that depend heavily on API calls.
Here’s a more robust sample based on the code above:
const
{
name:
inputSchema: z.
outputSchema: z.
streamSchema: z.
},
async
const
`
);
for
sendChunk
}
return
},
);
// Deploy to Firebase with secrets and App Check
const
exports
{
secrets: [geminiApiKey],
enforceAppCheck:
},
jokeTeller,
);
Roadmap
These new features are ready to use now with the 2nd gen Node.js runtime, but we’re still working on Python support. You can follow along as we implement it!
We’re still working on updating our Swift, Kotlin, and Dart client SDKs so that native mobile apps can also use this streaming functionality, alongside web apps. Until then, your functions can fall back to non-streaming behavior for these clients.
Production Web Architecture & Security Checklist
Whether we are deploying on Firebase App Hosting, Cloudflare Workers, or Vercel, shipping AI features to production requires defense-in-depth across three layers:
- Enforce Firebase App Check & Attestation: **Protect your web endpoints, Cloud Functions, Data Connect GraphQL resolvers, and Firebase AI Logic calls against unauthorized replay or billing abuse using Firebase App Check with reCAPTCHA Enterprise**.
- **Validate Locally with the Firebase Emulator Suite: **Run deterministic integration tests against local Firestore, Auth, Functions, and Data Connect PostgreSQL emulators before promoting schema or rule changes to production.
- **Keep Server & Client Boundaries Type-Safe: **Use the modular Firebase Web SDK and generated TypeScript bindings so SSR frameworks like Next.js, Astro, SvelteKit, and Angular serialize state cleanly without hydration flickers.
Conclusion
Accelerate your full-stack web and AI development by pairing Build Responsive, AI-powered Apps with Cloud Functions for Firebase with strict Security Rules, Firebase App Check, and local emulator testing. Come tell us on X (@CodingCatDev) and LinkedIn (CodingCat.dev) how you are using Firebase in your stack, and subscribe to the CodingCat.dev YouTube Channel so you don't miss what we build next!
Watch Our Related Firebase Video Tutorial on YouTube
Want to see how we architect and debug Firebase web applications live? Watch our related CodingCat.dev session Firebase Security Rules: Effortless control over your app's data. below, and make sure to Subscribe to CodingCat.dev on YouTube for weekly full-stack web and AI deep dives:
{% youtube wGbEM0CXMuI %}
Resources, Official Docs & Related CodingCat.dev Guides
- Primary Release Source: **Build Responsive, AI-powered Apps with Cloud Functions for Firebase on the Official Firebase Blog (published 2025-03-06 by Daniel Lee, Jeff Huleatt)
- **Official Firebase Documentation: **Firebase Developer Docs & Web SDK Reference
- **Related on CodingCat.dev: Add image generation to your apps with Imagen 3
- Related on CodingCat.dev: App Hosting updates: rollbacks, SDK auto-configuration, and more
- Related on CodingCat.dev: Firebase SQL with Data Connect
- Related on CodingCat.dev: Build a Custom No-Code App in 90 Minutes
Frequently Asked Questions (FAQ)
What are the key capabilities introduced in Build Responsive, AI-powered Apps with Cloud Functions for Firebase?
Build Responsive, AI-powered Apps with Cloud Functions for Firebase (announced 2025-03-06 by the Firebase team) enhances the platform for Firebase, Google Cloud, Web Dev, AI, TypeScript, Security, Serverless workloads. App users demand instant, dynamic app experiences, whether they’re chatting with an AI assistant, generating content in real time, or waiting for live data. Developers can review the primary announcement on the Firebase Blog alongside our implementation patterns and production checklist above.
How do web developers use Build Responsive, AI-powered Apps with Cloud Functions for Firebase with Next.js, SvelteKit, React, or Angular?
Web developers can integrate these features using the modular Firebase JavaScript/TypeScript SDK, Firebase Data Connect web bindings, and Firebase App Hosting. Always pair client-side SDK initialization with Firebase App Check and strict Security Rules, and test locally with the Firebase Local Emulator Suite before deploying.
Where can I watch video tutorials on Firebase Web and AI development?
You can watch our hands-on Firebase video walkthroughs on the CodingCat.dev YouTube Channel, including Firebase Security Rules: Effortless control over your app's data., and follow us on X (@CodingCatDev) for weekly full-stack tutorials.
flutterfire#18872
割と困っているというか、ワークアラウンドするしかない状況が続いててうーんとなるやつ。
1 like · 189 views
Firebase iOS Push Notifications: APNs Key and SDK Setup
Firebase Cloud Messaging (FCM) can deliver push notifications to iPhones, but it doesn't talk to iOS devices directly — it goes through Apple Push Notification service (APNs). Most “Firebase iOS push isn't working” problems come from the Apple side of that handshake. This guide sets up both sides in order.
How Firebase push works on iOS
Your app registers with APNs and receives an APNs device token. The Firebase iOS SDK maps that token to an FCM registration token, which is the one your server uses. When you send a message, FCM authenticates with APNs using the key you uploaded, and APNs delivers it to the device. If Firebase can't authenticate with APNs, nothing arrives — even though everything looks fine in your app.
Prerequisites
- A paid Apple Developer Program membership — push needs one.
- A Firebase project with your iOS app added, and its GoogleService-Info.plist.
- Xcode and a physical iPhone or iPad. The Simulator isn't a reliable test for remote push.
1. Create an APNs authentication key
1. In the Apple Developer portal, open Certificates, Identifiers & Profiles → Keys and create a new key.
2. Enable Apple Push Notifications service (APNs) for the key, then register it.
3. Download the .p8 file and note its Key ID. Apple lets you download it only once, so store it somewhere safe.
4. Note your Team ID, shown in your developer account's membership details.
An authentication key doesn't expire like a push certificate, and one key works for all your apps — which is why it's the recommended option over the older .p12 certificates.
2. Upload the key to Firebase
In the Firebase console, open Project settings → Cloud Messaging. Under your Apple app, upload the .p8 key and enter the Key ID and Team ID. Firebase uses this key to authenticate with APNs on your behalf.
3. Add the Firebase iOS SDK
In Xcode, choose File → Add Package Dependencies and add https://github.com/firebase/firebase-ios-sdk. Select the FirebaseMessaging product. Then drag GoogleService-Info.plist into your app target.
4. Enable capabilities
Select your app target, open Signing & Capabilities, and add Push Notifications. Add Background Modes and check Remote notifications if you send silent or data-only pushes.
5. Request permission and get the FCM token
Configure Firebase at launch, ask the user for permission, register for remote notifications, and listen for the FCM token:
import UIKit
import FirebaseCore
import FirebaseMessaging
import UserNotifications
@main
class AppDelegate: UIResponder, UIApplicationDelegate,
UNUserNotificationCenterDelegate, MessagingDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
Messaging.messaging().delegate = self
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(
options: [.alert, .badge, .sound]
) { granted, error in
// Respect the user's choice; you can ask again later from settings
}
application.registerForRemoteNotifications()
return true
}
// Called with a new or refreshed FCM registration token
func messaging(_ messaging: Messaging,
didReceiveRegistrationToken fcmToken: String?) {
guard let fcmToken else { return }
// Send this token to your push server
print("FCM token: \(fcmToken)")
}
// Show notifications while the app is in the foreground
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification) async
-> UNNotificationPresentationOptions {
[.banner, .sound, .badge]
}
}
By default the Firebase SDK uses method swizzling to pass the APNs token to FCM automatically. If you set FirebaseAppDelegateProxyEnabled to NO in your Info.plist, you must pass the APNs token yourself by setting Messaging.messaging().apnsToken in didRegisterForRemoteNotificationsWithDeviceToken.
6. Send a test notification
Run the app on a physical device, accept the permission prompt, and copy the FCM token from the console. In the Firebase console, open Messaging, create a notification, and use Send test message with that token. Test with the app in the foreground, in the background, and fully closed.
Why Firebase iOS push isn't working
- No APNs key in Firebase: the token is generated, but nothing is delivered. Check Project settings → Cloud Messaging.
- Wrong Team ID or Key ID: APNs rejects Firebase's requests. Re-enter both from your Apple developer account.
- Bundle ID mismatch: the iOS app in Firebase must use exactly the same bundle ID as your Xcode target.
- Push Notifications capability missing: the app never receives an APNs token, so no FCM token works.
- Swizzling disabled without passing the APNs token: FCM has no APNs token to map.
- Permission denied: the user declined the prompt; notifications are delivered silently or not shown.
Using React Native or Flutter?
The Apple-side steps — APNs key, Firebase upload, and capabilities — are the same. The notifySphere SDKs handle the token and permission code for you: see the React Native guide and the Flutter guide. notifySphere runs on Firebase Cloud Messaging, so once your Firebase project can reach APNs, uploading its service account lets you send segmented iOS, Android, and web campaigns from one dashboard.
---
Originally published on the notifySphere blog. notifySphere is push notifications, WhatsApp Business API, deep linking, and in-app support in one SDK — free up to 1,000 users.
Swift Package ManagerをTuist経由で導入し、CocoaPodsと併用しながら移行する
株式会社DIGITALIOで開発しているiOS版 ECナビアンケートアプリ は、依存関係の管理にCocoaPodsを使っていました。本記事では、依存関係の管理をCocoaPodsからSPM(Swift Package Manager)に移行した経緯と手法について書きます。
TL;DR
想定読者: Tuistでプロジェクトを生成していて、CocoaPodsからSPMへの移行を検討している方
依存関係の宣言をTuistの定義ファイルに集約でき、移行は「定義ファイルへの追加と Podfile からの削除」の繰り返しで済んだ
広告メディエーションのSDK本体とアダプターだけCocoaPodsに残し、SPMと併用で運用できている
前提
本記事は、TuistでXcodeプロジェクトを生成している環境を前提にしています。前回の記事では、 project.pbxproj のコンフリクトをなくすためにTuistを導入し、ビルドターゲットを Project.swift に定義して tuist generate で生成する運用に切り替えました。
zenn.dev
生成物はGit管理から除外しているため、ブランチの切り替えやファイルの追加のたびに make sync-develop でプロジェクトを再生成しています。
SPM移行のきっかけ
きっかけはFirebaseから届いたメールでした。Firebase SDKは2026年10月にCocoaPodsへの新バージョン公開を停止し、以降はpodspecからのインストールが公式サポートの対象外となり、SPMまたは手動インストールへの移行が案内される、という内容です。手順は公式の移行ガイドにまとまっています。
firebase.google.com
これはFirebase固有の話ではありません。CocoaPods Trunk自体も、2026年12月2日にread-onlyモードへ移行することが以前から告知されており、同じ流れにあります1。
blog.cocoapods.org
CocoaPods経由でFirebaseを使い続けても公開済みのバージョンは動きますが、新機能やバグ修正は受け取れなくなります2。この告知を機に、依存関係管理をCocoaPodsからSPMへ移行することにしました。
依存関係を種類ごとに分けて移行
まず、Tuist経由でSPMを利用するために、依存関係を記述する Tuist/Package.swift を作成しました。
// swift-tools-version: 5.9
import PackageDescription
#if TUIST
import ProjectDescription
let packageSettings = PackageSettings(
productTypes: [:]
)
#endif
let package = Package(
name: "ECNaviEnqueteApp",
dependencies: [
// ここに追記していく
]
)
次に、 Podfile に書かれていた依存関係を、ネットワーク、認証、UI、その他の依存関係といった種類ごとに分類して順番に移行しました。種類ごとに分けたのは、1つのPRで動作確認すべき範囲を絞り、問題が起きたときに原因を特定しやすくするためです。
どのタスクも手順自体は共通で、次の3ステップです。実際にFirebaseを移行した例で見てみます。
Tuist/Package.swift に対象の依存関係を追加する
// ...
- .package(
- url: "firebase/firebase-ios-sdk",
- exact: "12.14.0"
- ),
.package(
url: "kaishin/Gifu",
exact: "3.4.0"
),
Project.swift で .external(name:) として依存関係を宣言する
// ...
- .external(name: "FirebaseAnalytics"),
- .external(name: "FirebaseMessaging"),
- .external(name: "FirebaseRemoteConfig"),
- .external(name: "FirebaseInAppMessaging-Beta"),
- .external(name: "FirebaseCrashlytics"),
.external(name: "Gifu"),
CocoaPodsではsubspec( Firebase/InAppMessaging など)で選んでいた機能が、SPMでは1つのパッケージが公開する複数のプロダクトになります。
.external(name:) にはSPM側のプロダクト名を指定するため、Pod側の名前と異なるものもあります。
Podfile から該当のPodを削除する
- # Firebase
- pod 'Firebase/Core', '>10.22.0'
- pod 'Firebase/Analytics'
- pod 'Firebase/Messaging'
- pod 'Firebase/RemoteConfig'
- pod 'Firebase/InAppMessaging'
- pod 'Firebase/Crashlytics'
-
...
依存関係の解決はTuistが担うようになるため、 Makefile に tuist install を追加しました。依存関係の解決はプロジェクト生成時に済んでいる必要があるため、 tuist generate の前に置いています。
sync-develop:
cp ECNaviEnqueteApp/Resource/GoogleService-Info-Develop.plist ECNaviEnqueteApp/Resource/GoogleService-Info.plist
- tuist install
tuist generate --no-open
bundle exec pod install
変更を反映するには make sync-develop を実行します。次の順にコマンドが動き、SPMとCocoaPodsのロックファイルも更新されます。
移行でつまずいた点と残った課題
SPMへの移行では、単に依存関係の宣言先を変えるだけでなく、依存関係の利用方法によって個別対応が必要になったものもありました。
スクリプトのパスが変わった
移行した依存関係の1つであるFirebase Crashlyticsは、ビルド後にdSYMをアップロードするビルドスクリプト(Run Script)を実行します。
このスクリプトは、CocoaPodsでは Pods/ 配下にありましたが、SPMでは取得したパッケージのディレクトリ内に移ります。Tuistはこれを Tuist/.build/checkouts/ 配下に置くため、移行のタイミングで定義ファイルのスクリプトが参照するパスも変更しました。
- "${PODS_ROOT}/FirebaseCrashlytics/run"
- "${SRCROOT}/Tuist/.build/checkouts/firebase-ios-sdk/Crashlytics/run"
コードの追加対応を伴ったもの
依存関係によっては、コードの追加が必要になった箇所もありました。例えば、ネットワークレイヤーを抽象化するMoyaをCocoaPodsからSPMに移行してビルドし直すと、次のようなエラーが出ました。
FooBarClass.swift:xx:yy Cannot find 'UIDevice' in scope
原因は、CocoaPodsが各Podに生成するumbrella header( Moya-umbrella.h )とmodulemapでした。新規のプロジェクトで Podfile に use_frameworks! を指定してMoyaを導入すると、次のようなファイルが生成されます(抜粋)。
// Moya-umbrella.h
#ifdef OBJC
#import <UIKit/UIKit.h>
#else
// ...
// Moya.modulemap
framework module Moya {
umbrella header "Moya-umbrella.h"
export *
module * { export * }
}
umbrella headerがUIKitを、UIKitがFoundationを読み込み、modulemapの export * がそれらを再エクスポートします。そのため、 import Moya と書くだけでFoundationとUIKit双方のシンボルが使えていました。
import Moya
│
├─ CocoaPods時代: FoundationもUIKitもついてきた ٩(ˊᗜˋ*)و
│
└─ SPM: Moyaしか来ない
(;゚Д゚) 「UIDeviceって誰…?」
SPM経由ではこの経路が失われます。その結果、実際にはFoundationやUIKitのAPIを直接使っているのに、Moyaのimportだけに依存していた数ファイルがコンパイルエラーになりました。
対象ファイルに import Foundation / import UIKit を追加して解決しました。暗黙の再エクスポートは他のPodでも起きうるため、移行対象を分けておくと、コンパイルエラーの原因を直前に移したPodに絞り込めます。
一部の依存関係はSPM対応待ち
すべての依存関係をSPMへ移行できたわけではありません。広告配信のために利用している広告メディエーションでは、SDK本体こそSPM対応が完了していました。しかし、私たちが利用している複数の広告ネットワークに対応するアダプターは、CocoaPods版のSDK本体に依存する構成でした。
アダプターのPodはSDK本体のPodを依存関係として引き込むため、SDK本体だけSPMへ移すと、同じSDKがCocoaPods版とSPM版の2系統で宣言された状態になります。検証したところ、ビルドは通りました。
ただし版が異なる場合、どちらが採用されるかを示す警告は出ず、手元の検証ではSPM版が採用されました3。意図しない版が混ざる状態を避けるため、アダプターのSPM対応が済むまでは、SDK本体もCocoaPodsに残すこととしました。
開発ツールはmiseで管理
本アプリでは、Swiftの静的解析ツールであるSwiftLintと、アプリで使用しているオープンソースライブラリのライセンス一覧を自動生成するLicensePlistを使用しています。
これらは、アプリ本体にリンクされるわけではない開発ツールです。CocoaPods管理から切り出すにあたって、前回Tuistのバージョン固定用に導入したmiseへ寄せ、ツールのバージョン管理を一元化しました。
[tools]
- license-plist = "3.27.9"
- swiftlint = "0.63.3"
tuist = "4.195.9"
これらを呼ぶスクリプトは、 Pods/ 配下のパスからmiseのshimを指すように変更しました。
- "${PODS_ROOT}/SwiftLint/swiftlint"
- "${MISE_DATA_DIR:-${HOME}/.local/share/mise}/shims/swiftlint"
なお、LicensePlistは、SPM管理のパッケージを検出するための設定が必要でした。LicensePlistは、SPMのパッケージを Package.resolved から探します。しかし本アプリでは、Tuistが Tuist/Package.resolved を管理しており、LicensePlistの既定の探索先には存在せず、アプリ内のライセンス一覧に含まれませんでした4。
そこで、 license_plist.yml の packagePaths に Tuist/Package.swift を指定すると、同じディレクトリの Package.resolved が参照されるようになりました。
- options:
- packagePaths:
- - Tuist/Package.swift
移行後の状況
一連の移行の結果、依存関係の状態は次のようになりました。
状態
対象
SPMへ移行済み
ネットワーク、認証、UI、その他の依存関係
miseへ移行済み
SwiftLint、LicensePlist
CocoaPodsのまま維持
広告メディエーションSDK本体とアダプター
Podfile に書かれていたSDK本体とアダプター以外の21件のPod宣言は、すべてなくなりました。残りの依存関係は、提供元のリリースノートでSPM対応の有無を確認しながら追従していきます。
まとめ
Tuistの .external(name:) で依存関係を宣言できるため、移行作業の多くは定義ファイルへの追加と Podfile からの削除という小さな差分の繰り返しになりました。種類ごとに分けて、独立してレビュー・マージできる単位で進めたことで、各PRも小さく保てました。同様の移行を控えている場合は、以下の手順で実施するとスムーズに移行が進められると思います。
前回の記事 を参考にXcodeプロジェクトの管理方式を決める。
依存関係ごとに、SPMへの対応状況を調べる。
種類ごとに分け、動作確認しやすい粒度で順番に移行する。
CocoaPodsに残る依存関係は、12月2日以降は新バージョンがTrunkに公開されなくなります。提供元のSPM対応状況を確認し、未対応のものはアダプターごと移行できる時期を見極める必要があります。
脚注
read-only化後も既存のPodは取得できるが、Trunkに新しいPodやバージョンは公開できなくなる。独自のspecリポジトリで配布されているPodは影響を受けない。 ↩︎
Firebase公式の移行ガイドによれば、CocoaPodsで最後に公開されるメジャーバージョンは12とされている。 ↩︎
CocoaPodsとSPMのバージョンを入れ替えて2通りで検証した。いずれも、ビルドしたバイナリに含まれていたのはSPM版で、新旧は関係なかった。どのパターンでも同じかまでは検証できていない。 ↩︎
既定の探索先は、プロジェクトルートの Package.swift と、 *.xcodeproj および *.xcworkspace 配下の xcshareddata/swiftpm/Package.resolved である。詳細は LicensePlistのREADME を参照。 ↩︎
Extracting structured data from PDFs using Gemini 2.0 and Genkit in Firebase: Web Architecture & Implementation Guide
Original: codingcat.dev
Building AI features in TypeScript or Go quickly turns into spaghetti when you try to bolt structured output validation, tool calling, and OpenTelemetry tracing onto raw model API calls. Following the announcement of Extracting structured data from PDFs using Gemini 2.0 and Genkit by Peter Friese on the Official Firebase Blog (2025-02-20), here is our hands-on CodingCat.dev breakdown of what actually shipped, how it works under the hood, and how we wire it into production TypeScript, Next.js, Astro, SvelteKit, React, and Angular applications. Last week, Google released Gemini 2.0, and after reading this blog post about parsing PDFs using Gemini 2.0, I decided to rebuild the sample using Genkit.
The Mental Model: Why Extracting structured data from PDFs using Gemini 2.0 and Genkit Matters for Web Devs
As a Google Developer Expert (GDE) for Firebase and Senior Solutions Engineer at CodingCat.dev, I evaluate every Firebase update through one lens: does it reduce boilerplate while keeping our runtime security and cloud bills predictable? Firebase Genkit gives full-stack engineers strongly typed flows, dotprompt templates, local developer UI trace inspection, and production observability wired directly into Google Cloud and Firebase.
> AJ Pro-Tip from Alex: Always wrap your Genkit flows with explicit Zod input/output schemas and enforce Firebase App Check attestation on callable endpoints so bots cannot rack up unauthenticated token spend.
How It Works: Technical Breakdown & Implementation
For those who are unfamiliar, Genkit is an AI integration framework that makes implementing AI features for your apps easier.
In this blog post, I am going to focus on Genkit for Node.js, but the team is also working on building support for Go (available in alpha) and Python (under development). This means you can use Genkit on any runtime that supports one of those three languages. The sample app I’m discussing in this blog post is a simple command-line utility that you can run on macOS or any other platform that supports Node.js, but you can also use Genkit on the backend, for example in Cloud Functions for Firebase, Cloud Run, or any other environment that supports Node.js.
Setup
Before you can use Gemini 2.0 Flash in Genkit, you need to install and add Genkit and the Google AI SDK plugin for Genkit.
You can then instantiate Genkit and define a default model. This model will then be used in all subsequent calls you make via the ai instance.
import
import
// instantiate Genkit
const
plugins: [
model: gemini20Flash,
});
For a detailed walkthrough of the setup process, check out this video:
Extracting structured data
In this first example, let’s look at how you can use Gemini 2.0 Flash and Genkit to extract structured data from PDFs. Let’s imagine you’ve received a PDF with an invoice. To further process the invoice, you need to extract the invoice number, date, all the line items (including description, amount, and their individual price), as well as the gross price of the invoice.
Thanks to Gemini’s vision capabilities, we can let it handle the OCR for us. The following code snippet shows how to call any LLM via Genkit’s unified generation API, and pass a multimodal prompt (including a URL to the PDF file we want to analyse as well as an instruction).
export
const
prompt: [
{ media: { url } },
{ text:
]
});
return
}
If you’d call this method now for example by passing this URL (which points to an invoice), you’d get the following result:
[
{
'Invoice no': '
'Date of issue': '
Seller: {
Name: 'Williams LLC',
Address: '
Tax Id': '
IBAN: 'GB
},
Client: {
Name: 'Hernandez-Anderson',
Address: '
'Tax Id': '
},
Items: [
[Object], [Object],
[Object], [Object],
[Object], [Object],
[Object]
],
Summary: {
'VAT [%]': '
'Net worth': '
VAT: '
'Gross worth': '
Total: '$
'Total VAT': '$
'Total Gross worth': '$
}
}
]
Which is pretty impressive - after all, the model was able to correctly extract all information. However, this might not be in the format you need this in.
This is where Genkit’s support for structured output comes in handy. You can define a schema for your data using Zod, like this:
export
const
prompt: [
{ media: { url } },
{ text:
]
});
return
}
Then, pass the schema to Genkit’s generate call to enforce this schema.
export
const
prompt: [
{ media: { url } },
{ text:
],
});
return
}
And now, calling the function with the same PDF file will yield the following result:
{
date: '
invoiceNumber: '
items: [
{
description: 'Lilly Pulitzer dress Size
grossWorth:
quantity:
},
{
description: 'New ERIN Erin Fertherston Straight Dress White Sequence Lining Sleeveless SZ
grossWorth:
quantity:
},
{
description: 'Sequence dress Size Small',
grossWorth:
quantity:
},
{
description: 'fire los angeles dress Medium',
grossWorth:
quantity:
},
{
description:
grossWorth:
quantity:
},
{
description: 'Lularoe Nicole Dress Size Small Light Solid Grey/ White Ringer Tee Trim',
grossWorth:
quantity:
},
{
description: 'J.Crew Collection Black & White sweater Dress sz S',
grossWorth:
quantity:
}
],
totalGrossWorth:
}
Since this adheres to the schema we provided, it will be much easier to process.
Gemini 2.0 Flash supports structured output, but even if you’re using an LLM that doesn’t support natively structured output, Genkit can help by augmenting the prompt and coercing the returned data for you. What’s really amazing about this: you won’t have to change your code, thanks to Genkit’s unified generation API (check out this thread on Bluesky in which I demonstrate this).
Parsing hand-written form input
I mentioned Gemini’s OCR capabilities, so let’s try extracting the hand-written entries in the following PDF:
One way to achieve this would be to define a new schema and then call Genkit’s generate method using this new schema. But there is a more flexible way to do this. It turns out that the actual code for calling Gemini to extract data from a PDF is always the same - only the output format (and potentially the instructions) change for each type of PDF we want to analyse.
So why not make this a bit more generic?
Genkit provides a way to extract prompts into external files, using the Dotprompt library. This allows you to keep your code free from any prompt, making it easier to change the prompt independently of the code.
---
model
input
schema
pdfUrl
default
pdfUrl
output
schema
formNumber
startDate
beginningOfYear
endOfYear
name
address
phoneNumber
ein
---
Extract the hand-written form data.
{{media url
This prompt file defines the model Genkit should use (Gemini 2.0 Flash), as well as the prompt itself. But it also specifies the input and output schemas for the prompt. For example, under input/schema, we define an input parameter named pdfUrl of type string, which can then be used in the prompt to pass the URL. Likewise, under output/schema, we define all the keys we want to extract from the PDF file, including their types.
Note that the descriptions of the keys do not just serve the purpose of documentation - Genkit will use them in the prompt to specifically tell the model how to find the data for the respective keys.
To load a prompt from a file, use ai.prompt(filename). This has a beneficial side effect: we can now create.prompt files for all the different types of data we want to extract from PDF files, and just pass the filename to the extract function:
export
const
const
return
}
Instead of using ai.generate() to call the LLM, you can execute a prompt by caling the prompt itself, and passing the required parameters.
Calling this method using extract("form", "https://storage.googleapis.com/generativeai-downloads/data/pdf_structured_outputs/handwriting_form.pdf") will yield the following result:
{
address: '
beginningOfYear:
ein: '
endOfYear:
formNumber: 'CA
name: 'Annual Return Plan',
phoneNumber: '
startDate: '
}
Which - if you ask me - is mind-boggling.
Where to go from here
To learn more about Genkit, check out the documentation. Also, feel free to drop by my weekly livestreams - I’m currently working on implementing a Second Brain app, and I’m using Genkit for some of the AI-powered features.
If you’d like to try out the sample app, the source code is available on GitHub.
Production Web Architecture & Security Checklist
Whether we are deploying on Firebase App Hosting, Cloudflare Workers, or Vercel, shipping AI features to production requires defense-in-depth across three layers:
- Enforce Firebase App Check & Attestation: **Protect your web endpoints, Cloud Functions, Data Connect GraphQL resolvers, and Firebase AI Logic calls against unauthorized replay or billing abuse using Firebase App Check with reCAPTCHA Enterprise**.
- **Validate Locally with the Firebase Emulator Suite: **Run deterministic integration tests against local Firestore, Auth, Functions, and Data Connect PostgreSQL emulators before promoting schema or rule changes to production.
- **Keep Server & Client Boundaries Type-Safe: **Use the modular Firebase Web SDK and generated TypeScript bindings so SSR frameworks like Next.js, Astro, SvelteKit, and Angular serialize state cleanly without hydration flickers.
Conclusion
Accelerate your full-stack web and AI development by pairing Extracting structured data from PDFs using Gemini 2.0 and Genkit with strict Security Rules, Firebase App Check, and local emulator testing. Come tell us on X (@CodingCatDev) and LinkedIn (CodingCat.dev) how you are using Firebase in your stack, and subscribe to the CodingCat.dev YouTube Channel so you don't miss what we build next!
Watch Our Related Firebase Video Tutorial on YouTube
Want to see how we architect and debug Firebase web applications live? Watch our related CodingCat.dev session Firebase SQL with Data Connect below, and make sure to Subscribe to CodingCat.dev on YouTube for weekly full-stack web and AI deep dives:
{% youtube N25khadfUag %}
Resources, Official Docs & Related CodingCat.dev Guides
- Primary Release Source: **Extracting structured data from PDFs using Gemini 2.0 and Genkit on the Official Firebase Blog (published 2025-02-20 by Peter Friese)
- **Official Firebase Documentation: **Firebase Developer Docs & Web SDK Reference
- **Related on CodingCat.dev: Announcing Firebase Genkit 1.0 for Node.js
- Related on CodingCat.dev: Firebase + Gemini Code Assist
- Related on CodingCat.dev: Firebase SQL with Data Connect
- Related on CodingCat.dev: Build a Custom No-Code App in 90 Minutes
Frequently Asked Questions (FAQ)
What are the key capabilities introduced in Extracting structured data from PDFs using Gemini 2.0 and Genkit?
Extracting structured data from PDFs using Gemini 2.0 and Genkit (announced 2025-02-20 by the Firebase team) enhances the platform for Firebase, Google Cloud, Web Dev, AI, TypeScript, Serverless workloads. Last week, Google released Gemini 2.0, and after reading this blog post about parsing PDFs using Gemini 2.0, I decided to rebuild the sample using Genkit. Developers can review the primary announcement on the Firebase Blog alongside our implementation patterns and production checklist above.
How do web developers use Extracting structured data from PDFs using Gemini 2.0 and Genkit with Next.js, SvelteKit, React, or Angular?
Web developers can integrate these features using the modular Firebase JavaScript/TypeScript SDK, Firebase Data Connect web bindings, and Firebase App Hosting. Always pair client-side SDK initialization with Firebase App Check and strict Security Rules, and test locally with the Firebase Local Emulator Suite before deploying.
Where can I watch video tutorials on Firebase Web and AI development?
You can watch our hands-on Firebase video walkthroughs on the CodingCat.dev YouTube Channel, including Firebase SQL with Data Connect, and follow us on X (@CodingCatDev) for weekly full-stack tutorials.
February Update: What's New in Data Connect in Firebase: Web Architecture & Implementation Guide
Original: codingcat.dev
For years, choosing Firebase meant trading away relational SQL joins, strict foreign keys, and pgvector similarity search in favor of NoSQL document denormalization. Following the announcement of February Update: What's New in Data Connect by Cynthia Wang on the Official Firebase Blog (2025-02-26), here is our hands-on CodingCat.dev breakdown of what actually shipped, how it works under the hood, and how we wire it into production TypeScript, Next.js, Astro, SvelteKit, React, and Angular applications. Note: Firebase Data Connect has been renamed to SQL Connect. Learn more in the SQL Connect announcement.
The Mental Model: Why February Update: What's New in Data Connect Matters for Web Devs
As a Google Developer Expert (GDE) for Firebase and Senior Solutions Engineer at CodingCat.dev, I evaluate every Firebase update through one lens: does it reduce boilerplate while keeping our runtime security and cloud bills predictable? Firebase Data Connect bridges that gap by pairing a managed Google Cloud SQL for PostgreSQL instance with a declarative GraphQL schema compiler that automatically generates type-safe TypeScript, React, and Angular SDKs alongside server-enforced @auth directives.
> AJ Pro-Tip from Alex: Keep your authorization logic inside your Data Connect GraphQL operations using @auth(level: USER) and server-evaluated expressions like auth.uid and request.time rather than trusting client-supplied user IDs in query variables.
How It Works: Technical Breakdown & Implementation
New year, new features! Built on CloudSQL, Firebase Data Connect is our backend-as-a-service for Postgres. It’s a high-performance, scalable, and secure way to work with relational data using GraphQL. Since our previous update in ‘24, we’ve been hot at work to make Firebase Data Connect better to use, here’s a peek at what’s new.
What’s New?
Using React? Now you can generate React SDKs for your projects, with bindings powered by TanStack Query, to integrate your GraphQL operations into your React based apps. More frameworks are also in the works, so keep an eye out!
Enable generating React Hooks in connector.yaml:
generate:
javascriptSdk:
react: true
outputDir: "../movies-generated"
package: "@movie-app/movies"
packageJsonDir: "../../"
import
function
const
if
return
}
if
return
}
return
<
{data.
<
))}
</
);
}
Learn more about React support in the documentation.
Moving data just got easier. With PGLite, you can quickly import and export your database, whether you’re migrating, backing up, or setting up a fresh project.
The Firebase team heard your feedback! You can now see the distance from the query vector in your similarity search results by selecting the _metadata.distance field:
query
movies_descriptionEmbedding_similarity(
compare_embed: {
within:
where: {
{
id
title
description
_metadata {
distance
}
}
}
This makes it easy to choose a good value for within and tune your search performance.
@check can now be used for queries as well as mutations! Define authorization rules with CEL expressions, allowing you to reference data from other tables and apply conditional logic for more precise access control.
query
user(id: $userId) {
privacySetting
@check
expr:
message:
)
@redact
favoriteMovies
movie {
id
title
genre
}
}
}
}
Android developers, we’ve got something for you! The new quickstart sample app shows you how to use Firebase Data Connect in an Android app, so you can start building right away.
Watch the Latest Livestream
Want a closer look? We hung out with Firebase After Hours for a live demo and some great Q&A. Check out the replay here: Firebase After Hours #9: Firebase Data Connect: SQL or NoSQL, that is no longer the question
Don’t forget to share your thoughts
Production Web Architecture & Security Checklist
Whether we are deploying on Firebase App Hosting, Cloudflare Workers, or Vercel, shipping SQL features to production requires defense-in-depth across three layers:
- Enforce Firebase App Check & Attestation: **Protect your web endpoints, Cloud Functions, Data Connect GraphQL resolvers, and Firebase AI Logic calls against unauthorized replay or billing abuse using Firebase App Check with reCAPTCHA Enterprise**.
- **Validate Locally with the Firebase Emulator Suite: **Run deterministic integration tests against local Firestore, Auth, Functions, and Data Connect PostgreSQL emulators before promoting schema or rule changes to production.
- **Keep Server & Client Boundaries Type-Safe: **Use the modular Firebase Web SDK and generated TypeScript bindings so SSR frameworks like Next.js, Astro, SvelteKit, and Angular serialize state cleanly without hydration flickers.
Conclusion
Accelerate your full-stack web and AI development by pairing February Update: What's New in Data Connect with strict Security Rules, Firebase App Check, and local emulator testing. Come tell us on X (@CodingCatDev) and LinkedIn (CodingCat.dev) how you are using Firebase in your stack, and subscribe to the CodingCat.dev YouTube Channel so you don't miss what we build next!
Watch Our Related Firebase Video Tutorial on YouTube
Want to see how we architect and debug Firebase web applications live? Watch our related CodingCat.dev session Firebase SQL with Data Connect below, and make sure to Subscribe to CodingCat.dev on YouTube for weekly full-stack web and AI deep dives:
{% youtube N25khadfUag %}
Resources, Official Docs & Related CodingCat.dev Guides
- Primary Release Source: **February Update: What's New in Data Connect on the Official Firebase Blog (published 2025-02-26 by Cynthia Wang)
- **Official Firebase Documentation: **Firebase Developer Docs & Web SDK Reference
- **Related on CodingCat.dev: Firebase + Gemini Code Assist
- Related on CodingCat.dev: Add image generation to your apps with Imagen 3
- Related on CodingCat.dev: Firebase SQL with Data Connect
- Related on CodingCat.dev: Build a Custom No-Code App in 90 Minutes
Frequently Asked Questions (FAQ)
What are the key capabilities introduced in February Update: What's New in Data Connect?
February Update: What's New in Data Connect (announced 2025-02-26 by the Firebase team) enhances the platform for Firebase, Google Cloud, Web Dev, SQL, React, Security workloads. Note: Firebase Data Connect has been renamed to SQL Connect. Learn more in the SQL Connect announcement. Developers can review the primary announcement on the Firebase Blog alongside our implementation patterns and production checklist above.
How do web developers use February Update: What's New in Data Connect with Next.js, SvelteKit, React, or Angular?
Web developers can integrate these features using the modular Firebase JavaScript/TypeScript SDK, Firebase Data Connect web bindings, and Firebase App Hosting. Always pair client-side SDK initialization with Firebase App Check and strict Security Rules, and test locally with the Firebase Local Emulator Suite before deploying.
Where can I watch video tutorials on Firebase Web and AI development?
You can watch our hands-on Firebase video walkthroughs on the CodingCat.dev YouTube Channel, including Firebase SQL with Data Connect, and follow us on X (@CodingCatDev) for weekly full-stack tutorials.
Hey, @twerske
I'm not sure if you can help out, but maybe 😅🍀
Just as a general thought. This is the most upvoted issue on flutterfire:
flutterfire#17338
IMO this is one of the greatest misses on Flutter Linux desktop. We can't use Firebase there (full Google end-to-end)
1 like · 84 views
firebase-ios-sdk#16972 Firebase v13からSceneDelegateを考慮するようになってFIAMのactionURLがhttpsだとどんなURLもUniversalLinkとして流れてくるのが困るよーというIssue
2 likes · 94 views
Can Firebase provide native per-user Firestore rate limits without replacing realtime listeners?
I am building an app around Firestore's direct client SDK, realtime listeners and offline cache. I want to keep that architecture, but I cannot find a supported native way to cap an otherwise authorised user's billable reads/writes across devices and concurrent connections.
The existing feature request dates from April 2023 and currently has 73 votes:
firebase.uservoice.com
There are concrete adoption concerns in its comments: Al3life reports moving to Supabase for this feature, capTarget archery says it may rule Firebase out for future projects, and Anatole Couasnon describes adding an API despite choosing Firebase for direct access. These are individual reports, not a survey, but they match the concern blocking my confidence in launching.
I am not asking for authentication or permissions to be replaced. Rules limit what a user can access, but a query-size limit does not limit how often an allowed query runs. App Check attests clients; it is not a configurable allowance for each UID. Budget alerts do not stop usage. Cloud Armor in front of my own API does not control the Google-managed Firestore endpoint the SDK calls.
A custom API/SSE/WebSocket gateway could control traffic routed through it, but rebuilding native listener synchronisation, reconnect handling, cache behaviour and authorisation adds infrastructure, cost and complexity. That is not a viable equivalent for this application. An after-read trigger alone would also be too late to stop the triggering charge or a concurrent burst.
What I would like Firebase to provide is a simple console or rules-level policy, enforced by the service: per-UID rolling/burst allowances shared across devices, plus a database/project backstop. It needs to address document/query volume, writes, initial listener snapshots, subsequent billable updates and reconnects, with clear charging and quota-exceeded semantics. I appreciate that the implementation may be more complex than the setting exposed to developers.
I submitted a detailed feature request yesterday and have asked our Google Cloud contacts to escalate it. Is there a Firestore product owner who can give this an explicit status or link it to the right backend tracker? If a supported solution now preserves direct SDK listeners and actually enforces the allowance, I would welcome a documentation link. Otherwise, please treat this as an adoption and cost-abuse concern that needs an owned response.
Related history: firebase-js-sdk#647
Official App Check limitations: firebase.google.com
Budget guidance: firebase.google.com
4 points · 4 comments
Mentions
Fix "APNS token has not been set yet" in Flutter on iOS --- title: Fix "APNS token has not been set yet" in Flutter on iOS published: true date: 2026-11-05 00:00:00 UTC tags: flutter,ios,firebase,dart canonical_url: saymyframe.com --- On iOS, Firebase delivers push notifications through Apple's push service (APNs), so FirebaseMessaging.instance.getToken() refuses to run until Apple has given the device its APNs token. Called earlier, it throws apns-token-not-set, which older versions of firebase_messaging describe as "APNS token has not been set yet". Usually the app just asked too early. How it should wait depends on the version: firebase_messaging 17 tells the app when Firebase is ready, and 16.7 doesn't. In a few setups, though, Apple never answers, however long the app waits. I checked everything below on an iPhone 17 simulator with iOS 26.5, Xcode 27.2 and Flutter 3.44.2, with firebase_messaging 16.7.1 (Firebase iOS SDK 12.19.3) and 17.0.1 (Firebase iOS SDK 13.1.1). APNS token has not been set yet, or has not been received on the device yet The error comes in two wordings. Older versions say: [firebase_messaging/apns-token-not-set] APNS token has not been set yet. Please ensure the APNS token is available by calling `getAPNSToken()`. Since October 2025 (firebase_messaging 16.0.3, with firebase_messaging_platform_interface 4.7.3), the same error says: [firebase_messaging/apns-token-not-set] APNS token has not been received on the device yet. Please ensure the APNS token is available before calling `getAPNSToken()`. Both are a FirebaseException with the code apns-token-not-set, so check the code rather than the text. The hint to call getAPNSToken() is misleading, because that call never throws. It returns null until Apple has answered, which makes it the thing to wait on. The check runs in Dart, before anything reaches iOS. getToken(), deleteToken(), subscribeToTopic() and unsubscribeFromTopic() all start with it. So a topic subscription at startup fails with the same error, while requestPermission() and onMessage work. If you use Firebase from Swift, the native SDK reports the same situation as No APNS token specified before fetching FCM Token. Why getToken() fails right after the app starts At launch, the plugin asks iOS to register the app for remote notifications, and iOS answers later, in application:didRegisterForRemoteNotificationsWithDeviceToken:. The Firebase iOS SDK keeps that answer in memory only. So an early getToken() fails on every launch, not just the first one, even when Firebase gave the app its FCM token on the previous launch. How long the answer takes varies: about half a second on a simulator that had been running for a while, and about 30 seconds right after the simulator booted. On a phone, it depends on the network. I checked this with a small app that calls getToken() right after Firebase.initializeApp(), after a fresh install and after a restart, with both versions. The call failed every time, although Apple answered within a second. What differs between the versions is whether the app learns that Firebase is ready. firebase_messaging 16: wait for getAPNSToken() With 16.7.1, the Firebase iOS SDK requests the FCM token by itself as soon as Apple answers (the log shows the app connecting to fcmtoken.googleapis.com), but the plugin doesn't pass it on to Dart: onTokenRefresh stayed silent for the 20 seconds I waited, after a fresh install and after a restart. So the app has to wait for getAPNSToken() itself, then call getToken(): import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; /// The FCM token of this device once Apple has answered, or `null` when /// Apple hasn't within [limit]. Future<String?> pushTokenWhenReady({ Duration limit = const Duration(minutes: 2), }) async { final messaging = FirebaseMessaging.instance; if (!kIsWeb && defaultTargetPlatform == TargetPlatform.iOS) { var wait = const Duration(milliseconds: 500); var waited = Duration.zero; while (await messaging.getAPNSToken() == null) { if (waited >= limit) return null; await Future<void>.delayed(wait); waited += wait; if (wait < const Duration(seconds: 8)) wait *= 2; } } return messaging.getToken(); } Don't await it before runApp(). I found apps on GitHub that opened to a white screen on iOS for exactly this reason: main() waited, getToken() threw, and runApp() never ran. Start the app first and send the result to your server when it arrives: Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); runApp(const MyApp()); final token = await pushTokenWhenReady(); if (token != null) await sendTokenToServer(token); } If the wait runs out, try again when the user comes back to the app, for example from an AppLifecycleListener with onResume. firebase_messaging 17: listen to onTokenRefresh Since 17.0.0, released in October 2026, the plugin becomes the delegate of the Firebase iOS SDK during Firebase.initializeApp(), so onTokenRefresh gets two events that 16 lost. After a fresh install, it fires as soon as the SDK has the FCM token, in my runs 1.4 seconds after Apple answered. On every later launch, it fires right at startup with the value that the SDK saved last time: 0.2 seconds after main() started, before Apple had answered and while getToken() still threw. So on 17, subscribe to onTokenRefresh right after initializeApp(), and keep the getToken() call for Android, where it doesn't depend on Apple: Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); final messaging = FirebaseMessaging.instance; messaging.onTokenRefresh.listen(sendTokenToServer); runApp(const MyApp()); try { final token = await messaging.getToken(); if (token != null) await sendTokenToServer(token); } on FirebaseException catch (e) { // On iOS before Apple has answered: onTokenRefresh delivers it. if (e.code != 'apns-token-not-set') rethrow; } } Your server may get the same value twice this way, so it should accept one that it already has. Subscribe early, because onTokenRefresh is a broadcast stream and a listener that comes after the startup event never sees it. If your code subscribes later, after a sign-in for example, wait for getAPNSToken() as with 16. Firebase is also moving Cloud Messaging from registration tokens to the Firebase Installation ID (FID). Version 17 deprecates getToken(), onTokenRefresh and deleteToken() in favor of register(), onRegistered and unregister(), and flutter analyze exits with code 1 on the code above because of the deprecation infos. I haven't tried the FID path yet, so this article stays with getToken(). When the APNs token never comes If getAPNSToken() still returns null after a minute, waiting longer won't help. These are the cases I know of. No aps-environment entitlement iOS registers an app for remote notifications only when the build is signed with the aps-environment entitlement, which Xcode adds with the Push Notifications capability in Signing & Capabilities. Without it, the Xcode console shows: [FirebaseMessaging][I-FCM012002] Error in application:didFailToRegisterForRemoteNotificationsWithError: no valid "aps-environment" entitlement string found The simulator follows the same rule. A build made with flutter build ios --simulator --no-codesign doesn't get the entitlement, and mine waited two minutes for Apple in vain. A free Apple team A personal team can't sign aps-environment. To run the app on an iPhone, you have to remove the capability, and then Apple never answers there. The simulator doesn't need a team, since Xcode signs simulator builds ad hoc. The iOS simulator on GitHub Actions The iOS simulator on a Mac gets a real APNs token. On a macOS virtual machine it never does, and the macOS runners of GitHub Actions are virtual machines. I tried a macos-26 runner: the app was built with the entitlement, nothing came in four minutes, and the push daemon logged no token info found in keychain before it disconnected. actions/runner-images#12747 reports the same for macos-15. A CI job on a hosted runner can check that the app starts without push notifications, but not that it gets them. firebase_messaging 16.5.0 and 16.6.0 These two versions skipped the registration for remote notifications at launch in two common setups: when Firebase is initialized from Dart, as with Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform) (flutterfire#18643), and in apps with scenes (flutterfire#18555), which the iOS template of current Flutter creates with SceneDelegate.swift. getAPNSToken() then stayed null on every launch. Version 16.7.0 fixed both. Check which version your app has: flutter pub deps | grep firebase_messaging Auto-init is off With FirebaseMessagingAutoInitEnabled set to NO in Info.plist, or after setAutoInitEnabled(false), the plugin doesn't register for remote notifications. Call setAutoInitEnabled(true) before you start waiting. Not the APNs key The APNs key in the Firebase console doesn't belong on this list. Firebase needs it to send messages through Apple, so without it nothing arrives, but getAPNSToken() and getToken() work all the same. How SMF handles push notifications on iOS The firebase_messaging module of SMF, a free, open-source Flutter project generator, gives the app the address of the device as appPush.address, which stays null until Firebase has one. The first frame never waits for it. On iOS, the module polls getAPNSToken() as above, waiting from half a second up to eight seconds between tries, for at most two minutes, and asks again whenever the user comes back to the app. It adds aps-environment and the background mode remote-notification, and the README of the app explains what to do with a free team. Uploading the APNs key stays a step you do by hand. SMF's CI starts the apps on the iOS simulator of a hosted runner, where they have to start and work without an address.
Build Responsive, AI-powered Apps with Cloud Functions for Firebase: Web Architecture & Implementation Guide Original: codingcat.dev Calling frontier multimodal models directly from a web or mobile client is a security minefield if you expose raw API keys or hardcode brittle system prompts in your frontend bundle. Following the announcement of Build Responsive, AI-powered Apps with Cloud Functions for Firebase by Daniel Lee, Jeff Huleatt on the Official Firebase Blog (2025-03-06), here is our hands-on CodingCat.dev breakdown of what actually shipped, how it works under the hood, and how we wire it into production TypeScript, Next.js, Astro, SvelteKit, React, and Angular applications. App users demand instant, dynamic app experiences, whether they’re chatting with an AI assistant, generating content in real time, or waiting for live data. The Mental Model: Why Build Responsive, AI-powered Apps with Cloud Functions for Firebase Matters for Web Devs As a Google Developer Expert (GDE) for Firebase and Senior Solutions Architect at CodingCat.dev, I evaluate every Firebase update through one lens: does it reduce boilerplate while keeping our runtime security and cloud bills predictable? Firebase AI Logic lets you invoke Gemini and Imagen models from client and edge apps using the Firebase Web SDK while keeping your API credentials off the wire, enforcing Firebase App Check, and managing server-side prompt templates centrally. > AJ Pro-Tip from Alex: Combine Firebase AI Logic with server prompt templates, Firebase Remote Config feature flags, and project spend caps so you can iterate on prompts or swap Gemini models instantly without redeploying your Next.js or Astro frontend. How It Works: Technical Breakdown & Implementation Since their introduction in 2017, Cloud Functions for Firebase’s callable functions have focused on providing you with a streamlined server(less) development experience that simplifies server-to-client interactions. Now, The Firebase team announced two new features that make it easier than ever to build responsive, AI-powered apps: Streaming responses for callable functions, Deliver data incrementally to clients. A new onCallGenkit trigger, Seamlessly integrate Firebase Genkit to productionize generative AI workflows. **Note: **In this post, we show how to stream data from a Node.js callable function to a client web app that’s using the Firebase JS SDK. We’re also working on bringing this to the Python functions SDK, as well as our Swift, Kotlin, and Dart client SDKs. Send data to your app as it is generated Traditionally, when a client application calls a server function, it has to wait for the entire response to be generated before it can do anything. This “all-or-nothing” approach works well for many scenarios, but it falls short when dealing with: Why do generative AI APIs return their responses token-by-token? With the new streaming capability for Callable Functions, your server can send data to the client in chunks, as it becomes available. The client can then process and display this data incrementally, creating a much more responsive and engaging user experience. Imagine Firebase is building a web app for weather enthusiasts or frequent travelers that want to see the forecast for lots of locations at once, and that it calls a callable function to get these forecasts. Without streaming, they’d have to sit and wait while the forecast for each location is fetched, and can only start browsing the results once every location’s forecast is fetched and returned from the server. With streaming, our weather enthusiasts can start viewing each location’s data as soon as it’s ready: To stream results, check the acceptsStreaming field of the request object, and call response.sendChunk every time you have a chunk of data that’s ready to send back to the client. Return the full dataset at the end for clients that don’t accept streaming. exports const const const // Stream each forecast as it resolves! if response. } return }); // Fallback for non-streaming clients return }); Use the Firebase client SDKs to consume the streaming response from a web app: const const for updateUI } const If you’re already using callable functions in your app, adding streaming behavior may just be a small change to your server and client code that results in big user-experience benefits! For generative AI applications, The Firebase team built a new onCallGenkit trigger on top of this new streaming functionality. Productionize Your AI-Powered Apps Faster Firebase Genkit is an all-in-one toolkit to prototype, test, build, and monitor production-ready generative AI applications. The new onCallGenkit trigger now lets you deploy Genkit flows as secure, scalable APIs with one line: // An example Genkit flow. const { name: // ... }, async const ` ); for sendChunk } return }, ); // Deploy the flow with Cloud Functions for Firebase exports As above, use the functions SDK to consume the results from a client app: const const for updateUI } const With onCallGenkit, you leverage all features we offer in Cloud Functions for Firebase, like: **Simplified Deployment: **Deploy your Genkit flows with just the firebase deploy command you are familiar with. **Automatic Streaming: **onCallGenkit automatically handles the streaming setup for you. Just use sendChunk() within your Genkit flow, and call the stream method from the client SDK. **Built-in Abuse Prevention: **Protect your AI-powered function with Firebase App Check. **Secret Management: **Securely store and access API keys and other sensitive information with enterprise-grade Cloud Secret Manager. **Concurrency: **Benefit from Cloud Function for Firebase 2nd gen features like concurrency to scale your service efficiently. With concurrency, one function instance can handle multiple concurrent requests, a great fit for AI applications that depend heavily on API calls. Here’s a more robust sample based on the code above: const { name: inputSchema: z. outputSchema: z. streamSchema: z. }, async const ` ); for sendChunk } return }, ); // Deploy to Firebase with secrets and App Check const exports { secrets: [geminiApiKey], enforceAppCheck: }, jokeTeller, ); Roadmap These new features are ready to use now with the 2nd gen Node.js runtime, but we’re still working on Python support. You can follow along as we implement it! We’re still working on updating our Swift, Kotlin, and Dart client SDKs so that native mobile apps can also use this streaming functionality, alongside web apps. Until then, your functions can fall back to non-streaming behavior for these clients. Production Web Architecture & Security Checklist Whether we are deploying on Firebase App Hosting, Cloudflare Workers, or Vercel, shipping AI features to production requires defense-in-depth across three layers: - Enforce Firebase App Check & Attestation: **Protect your web endpoints, Cloud Functions, Data Connect GraphQL resolvers, and Firebase AI Logic calls against unauthorized replay or billing abuse using Firebase App Check with reCAPTCHA Enterprise**. - **Validate Locally with the Firebase Emulator Suite: **Run deterministic integration tests against local Firestore, Auth, Functions, and Data Connect PostgreSQL emulators before promoting schema or rule changes to production. - **Keep Server & Client Boundaries Type-Safe: **Use the modular Firebase Web SDK and generated TypeScript bindings so SSR frameworks like Next.js, Astro, SvelteKit, and Angular serialize state cleanly without hydration flickers. Conclusion Accelerate your full-stack web and AI development by pairing Build Responsive, AI-powered Apps with Cloud Functions for Firebase with strict Security Rules, Firebase App Check, and local emulator testing. Come tell us on X (@CodingCatDev) and LinkedIn (CodingCat.dev) how you are using Firebase in your stack, and subscribe to the CodingCat.dev YouTube Channel so you don't miss what we build next! Watch Our Related Firebase Video Tutorial on YouTube Want to see how we architect and debug Firebase web applications live? Watch our related CodingCat.dev session Firebase Security Rules: Effortless control over your app's data. below, and make sure to Subscribe to CodingCat.dev on YouTube for weekly full-stack web and AI deep dives: {% youtube wGbEM0CXMuI %} Resources, Official Docs & Related CodingCat.dev Guides - Primary Release Source: **Build Responsive, AI-powered Apps with Cloud Functions for Firebase on the Official Firebase Blog (published 2025-03-06 by Daniel Lee, Jeff Huleatt) - **Official Firebase Documentation: **Firebase Developer Docs & Web SDK Reference - **Related on CodingCat.dev: Add image generation to your apps with Imagen 3 - Related on CodingCat.dev: App Hosting updates: rollbacks, SDK auto-configuration, and more - Related on CodingCat.dev: Firebase SQL with Data Connect - Related on CodingCat.dev: Build a Custom No-Code App in 90 Minutes Frequently Asked Questions (FAQ) What are the key capabilities introduced in Build Responsive, AI-powered Apps with Cloud Functions for Firebase? Build Responsive, AI-powered Apps with Cloud Functions for Firebase (announced 2025-03-06 by the Firebase team) enhances the platform for Firebase, Google Cloud, Web Dev, AI, TypeScript, Security, Serverless workloads. App users demand instant, dynamic app experiences, whether they’re chatting with an AI assistant, generating content in real time, or waiting for live data. Developers can review the primary announcement on the Firebase Blog alongside our implementation patterns and production checklist above. How do web developers use Build Responsive, AI-powered Apps with Cloud Functions for Firebase with Next.js, SvelteKit, React, or Angular? Web developers can integrate these features using the modular Firebase JavaScript/TypeScript SDK, Firebase Data Connect web bindings, and Firebase App Hosting. Always pair client-side SDK initialization with Firebase App Check and strict Security Rules, and test locally with the Firebase Local Emulator Suite before deploying. Where can I watch video tutorials on Firebase Web and AI development? You can watch our hands-on Firebase video walkthroughs on the CodingCat.dev YouTube Channel, including Firebase Security Rules: Effortless control over your app's data., and follow us on X (@CodingCatDev) for weekly full-stack tutorials.
flutterfire#18872 割と困っているというか、ワークアラウンドするしかない状況が続いててうーんとなるやつ。
Firebase iOS Push Notifications: APNs Key and SDK Setup Firebase Cloud Messaging (FCM) can deliver push notifications to iPhones, but it doesn't talk to iOS devices directly — it goes through Apple Push Notification service (APNs). Most “Firebase iOS push isn't working” problems come from the Apple side of that handshake. This guide sets up both sides in order. How Firebase push works on iOS Your app registers with APNs and receives an APNs device token. The Firebase iOS SDK maps that token to an FCM registration token, which is the one your server uses. When you send a message, FCM authenticates with APNs using the key you uploaded, and APNs delivers it to the device. If Firebase can't authenticate with APNs, nothing arrives — even though everything looks fine in your app. Prerequisites - A paid Apple Developer Program membership — push needs one. - A Firebase project with your iOS app added, and its GoogleService-Info.plist. - Xcode and a physical iPhone or iPad. The Simulator isn't a reliable test for remote push. 1. Create an APNs authentication key 1. In the Apple Developer portal, open Certificates, Identifiers & Profiles → Keys and create a new key. 2. Enable Apple Push Notifications service (APNs) for the key, then register it. 3. Download the .p8 file and note its Key ID. Apple lets you download it only once, so store it somewhere safe. 4. Note your Team ID, shown in your developer account's membership details. An authentication key doesn't expire like a push certificate, and one key works for all your apps — which is why it's the recommended option over the older .p12 certificates. 2. Upload the key to Firebase In the Firebase console, open Project settings → Cloud Messaging. Under your Apple app, upload the .p8 key and enter the Key ID and Team ID. Firebase uses this key to authenticate with APNs on your behalf. 3. Add the Firebase iOS SDK In Xcode, choose File → Add Package Dependencies and add https://github.com/firebase/firebase-ios-sdk. Select the FirebaseMessaging product. Then drag GoogleService-Info.plist into your app target. 4. Enable capabilities Select your app target, open Signing & Capabilities, and add Push Notifications. Add Background Modes and check Remote notifications if you send silent or data-only pushes. 5. Request permission and get the FCM token Configure Firebase at launch, ask the user for permission, register for remote notifications, and listen for the FCM token: import UIKit import FirebaseCore import FirebaseMessaging import UserNotifications @main class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { FirebaseApp.configure() Messaging.messaging().delegate = self UNUserNotificationCenter.current().delegate = self UNUserNotificationCenter.current().requestAuthorization( options: [.alert, .badge, .sound] ) { granted, error in // Respect the user's choice; you can ask again later from settings } application.registerForRemoteNotifications() return true } // Called with a new or refreshed FCM registration token func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { guard let fcmToken else { return } // Send this token to your push server print("FCM token: \(fcmToken)") } // Show notifications while the app is in the foreground func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions { [.banner, .sound, .badge] } } By default the Firebase SDK uses method swizzling to pass the APNs token to FCM automatically. If you set FirebaseAppDelegateProxyEnabled to NO in your Info.plist, you must pass the APNs token yourself by setting Messaging.messaging().apnsToken in didRegisterForRemoteNotificationsWithDeviceToken. 6. Send a test notification Run the app on a physical device, accept the permission prompt, and copy the FCM token from the console. In the Firebase console, open Messaging, create a notification, and use Send test message with that token. Test with the app in the foreground, in the background, and fully closed. Why Firebase iOS push isn't working - No APNs key in Firebase: the token is generated, but nothing is delivered. Check Project settings → Cloud Messaging. - Wrong Team ID or Key ID: APNs rejects Firebase's requests. Re-enter both from your Apple developer account. - Bundle ID mismatch: the iOS app in Firebase must use exactly the same bundle ID as your Xcode target. - Push Notifications capability missing: the app never receives an APNs token, so no FCM token works. - Swizzling disabled without passing the APNs token: FCM has no APNs token to map. - Permission denied: the user declined the prompt; notifications are delivered silently or not shown. Using React Native or Flutter? The Apple-side steps — APNs key, Firebase upload, and capabilities — are the same. The notifySphere SDKs handle the token and permission code for you: see the React Native guide and the Flutter guide. notifySphere runs on Firebase Cloud Messaging, so once your Firebase project can reach APNs, uploading its service account lets you send segmented iOS, Android, and web campaigns from one dashboard. --- Originally published on the notifySphere blog. notifySphere is push notifications, WhatsApp Business API, deep linking, and in-app support in one SDK — free up to 1,000 users.
Swift Package ManagerをTuist経由で導入し、CocoaPodsと併用しながら移行する 株式会社DIGITALIOで開発しているiOS版 ECナビアンケートアプリ は、依存関係の管理にCocoaPodsを使っていました。本記事では、依存関係の管理をCocoaPodsからSPM(Swift Package Manager)に移行した経緯と手法について書きます。 TL;DR 想定読者: Tuistでプロジェクトを生成していて、CocoaPodsからSPMへの移行を検討している方 依存関係の宣言をTuistの定義ファイルに集約でき、移行は「定義ファイルへの追加と Podfile からの削除」の繰り返しで済んだ 広告メディエーションのSDK本体とアダプターだけCocoaPodsに残し、SPMと併用で運用できている 前提 本記事は、TuistでXcodeプロジェクトを生成している環境を前提にしています。前回の記事では、 project.pbxproj のコンフリクトをなくすためにTuistを導入し、ビルドターゲットを Project.swift に定義して tuist generate で生成する運用に切り替えました。 zenn.dev 生成物はGit管理から除外しているため、ブランチの切り替えやファイルの追加のたびに make sync-develop でプロジェクトを再生成しています。 SPM移行のきっかけ きっかけはFirebaseから届いたメールでした。Firebase SDKは2026年10月にCocoaPodsへの新バージョン公開を停止し、以降はpodspecからのインストールが公式サポートの対象外となり、SPMまたは手動インストールへの移行が案内される、という内容です。手順は公式の移行ガイドにまとまっています。 firebase.google.com これはFirebase固有の話ではありません。CocoaPods Trunk自体も、2026年12月2日にread-onlyモードへ移行することが以前から告知されており、同じ流れにあります1。 blog.cocoapods.org CocoaPods経由でFirebaseを使い続けても公開済みのバージョンは動きますが、新機能やバグ修正は受け取れなくなります2。この告知を機に、依存関係管理をCocoaPodsからSPMへ移行することにしました。 依存関係を種類ごとに分けて移行 まず、Tuist経由でSPMを利用するために、依存関係を記述する Tuist/Package.swift を作成しました。 // swift-tools-version: 5.9 import PackageDescription #if TUIST import ProjectDescription let packageSettings = PackageSettings( productTypes: [:] ) #endif let package = Package( name: "ECNaviEnqueteApp", dependencies: [ // ここに追記していく ] ) 次に、 Podfile に書かれていた依存関係を、ネットワーク、認証、UI、その他の依存関係といった種類ごとに分類して順番に移行しました。種類ごとに分けたのは、1つのPRで動作確認すべき範囲を絞り、問題が起きたときに原因を特定しやすくするためです。 どのタスクも手順自体は共通で、次の3ステップです。実際にFirebaseを移行した例で見てみます。 Tuist/Package.swift に対象の依存関係を追加する // ... - .package( - url: "firebase/firebase-ios-sdk", - exact: "12.14.0" - ), .package( url: "kaishin/Gifu", exact: "3.4.0" ), Project.swift で .external(name:) として依存関係を宣言する // ... - .external(name: "FirebaseAnalytics"), - .external(name: "FirebaseMessaging"), - .external(name: "FirebaseRemoteConfig"), - .external(name: "FirebaseInAppMessaging-Beta"), - .external(name: "FirebaseCrashlytics"), .external(name: "Gifu"), CocoaPodsではsubspec( Firebase/InAppMessaging など)で選んでいた機能が、SPMでは1つのパッケージが公開する複数のプロダクトになります。 .external(name:) にはSPM側のプロダクト名を指定するため、Pod側の名前と異なるものもあります。 Podfile から該当のPodを削除する - # Firebase - pod 'Firebase/Core', '>10.22.0' - pod 'Firebase/Analytics' - pod 'Firebase/Messaging' - pod 'Firebase/RemoteConfig' - pod 'Firebase/InAppMessaging' - pod 'Firebase/Crashlytics' - ... 依存関係の解決はTuistが担うようになるため、 Makefile に tuist install を追加しました。依存関係の解決はプロジェクト生成時に済んでいる必要があるため、 tuist generate の前に置いています。 sync-develop: cp ECNaviEnqueteApp/Resource/GoogleService-Info-Develop.plist ECNaviEnqueteApp/Resource/GoogleService-Info.plist - tuist install tuist generate --no-open bundle exec pod install 変更を反映するには make sync-develop を実行します。次の順にコマンドが動き、SPMとCocoaPodsのロックファイルも更新されます。 移行でつまずいた点と残った課題 SPMへの移行では、単に依存関係の宣言先を変えるだけでなく、依存関係の利用方法によって個別対応が必要になったものもありました。 スクリプトのパスが変わった 移行した依存関係の1つであるFirebase Crashlyticsは、ビルド後にdSYMをアップロードするビルドスクリプト(Run Script)を実行します。 このスクリプトは、CocoaPodsでは Pods/ 配下にありましたが、SPMでは取得したパッケージのディレクトリ内に移ります。Tuistはこれを Tuist/.build/checkouts/ 配下に置くため、移行のタイミングで定義ファイルのスクリプトが参照するパスも変更しました。 - "${PODS_ROOT}/FirebaseCrashlytics/run" - "${SRCROOT}/Tuist/.build/checkouts/firebase-ios-sdk/Crashlytics/run" コードの追加対応を伴ったもの 依存関係によっては、コードの追加が必要になった箇所もありました。例えば、ネットワークレイヤーを抽象化するMoyaをCocoaPodsからSPMに移行してビルドし直すと、次のようなエラーが出ました。 FooBarClass.swift:xx:yy Cannot find 'UIDevice' in scope 原因は、CocoaPodsが各Podに生成するumbrella header( Moya-umbrella.h )とmodulemapでした。新規のプロジェクトで Podfile に use_frameworks! を指定してMoyaを導入すると、次のようなファイルが生成されます(抜粋)。 // Moya-umbrella.h #ifdef OBJC #import <UIKit/UIKit.h> #else // ... // Moya.modulemap framework module Moya { umbrella header "Moya-umbrella.h" export * module * { export * } } umbrella headerがUIKitを、UIKitがFoundationを読み込み、modulemapの export * がそれらを再エクスポートします。そのため、 import Moya と書くだけでFoundationとUIKit双方のシンボルが使えていました。 import Moya │ ├─ CocoaPods時代: FoundationもUIKitもついてきた ٩(ˊᗜˋ*)و │ └─ SPM: Moyaしか来ない (;゚Д゚) 「UIDeviceって誰…?」 SPM経由ではこの経路が失われます。その結果、実際にはFoundationやUIKitのAPIを直接使っているのに、Moyaのimportだけに依存していた数ファイルがコンパイルエラーになりました。 対象ファイルに import Foundation / import UIKit を追加して解決しました。暗黙の再エクスポートは他のPodでも起きうるため、移行対象を分けておくと、コンパイルエラーの原因を直前に移したPodに絞り込めます。 一部の依存関係はSPM対応待ち すべての依存関係をSPMへ移行できたわけではありません。広告配信のために利用している広告メディエーションでは、SDK本体こそSPM対応が完了していました。しかし、私たちが利用している複数の広告ネットワークに対応するアダプターは、CocoaPods版のSDK本体に依存する構成でした。 アダプターのPodはSDK本体のPodを依存関係として引き込むため、SDK本体だけSPMへ移すと、同じSDKがCocoaPods版とSPM版の2系統で宣言された状態になります。検証したところ、ビルドは通りました。 ただし版が異なる場合、どちらが採用されるかを示す警告は出ず、手元の検証ではSPM版が採用されました3。意図しない版が混ざる状態を避けるため、アダプターのSPM対応が済むまでは、SDK本体もCocoaPodsに残すこととしました。 開発ツールはmiseで管理 本アプリでは、Swiftの静的解析ツールであるSwiftLintと、アプリで使用しているオープンソースライブラリのライセンス一覧を自動生成するLicensePlistを使用しています。 これらは、アプリ本体にリンクされるわけではない開発ツールです。CocoaPods管理から切り出すにあたって、前回Tuistのバージョン固定用に導入したmiseへ寄せ、ツールのバージョン管理を一元化しました。 [tools] - license-plist = "3.27.9" - swiftlint = "0.63.3" tuist = "4.195.9" これらを呼ぶスクリプトは、 Pods/ 配下のパスからmiseのshimを指すように変更しました。 - "${PODS_ROOT}/SwiftLint/swiftlint" - "${MISE_DATA_DIR:-${HOME}/.local/share/mise}/shims/swiftlint" なお、LicensePlistは、SPM管理のパッケージを検出するための設定が必要でした。LicensePlistは、SPMのパッケージを Package.resolved から探します。しかし本アプリでは、Tuistが Tuist/Package.resolved を管理しており、LicensePlistの既定の探索先には存在せず、アプリ内のライセンス一覧に含まれませんでした4。 そこで、 license_plist.yml の packagePaths に Tuist/Package.swift を指定すると、同じディレクトリの Package.resolved が参照されるようになりました。 - options: - packagePaths: - - Tuist/Package.swift 移行後の状況 一連の移行の結果、依存関係の状態は次のようになりました。 状態 対象 SPMへ移行済み ネットワーク、認証、UI、その他の依存関係 miseへ移行済み SwiftLint、LicensePlist CocoaPodsのまま維持 広告メディエーションSDK本体とアダプター Podfile に書かれていたSDK本体とアダプター以外の21件のPod宣言は、すべてなくなりました。残りの依存関係は、提供元のリリースノートでSPM対応の有無を確認しながら追従していきます。 まとめ Tuistの .external(name:) で依存関係を宣言できるため、移行作業の多くは定義ファイルへの追加と Podfile からの削除という小さな差分の繰り返しになりました。種類ごとに分けて、独立してレビュー・マージできる単位で進めたことで、各PRも小さく保てました。同様の移行を控えている場合は、以下の手順で実施するとスムーズに移行が進められると思います。 前回の記事 を参考にXcodeプロジェクトの管理方式を決める。 依存関係ごとに、SPMへの対応状況を調べる。 種類ごとに分け、動作確認しやすい粒度で順番に移行する。 CocoaPodsに残る依存関係は、12月2日以降は新バージョンがTrunkに公開されなくなります。提供元のSPM対応状況を確認し、未対応のものはアダプターごと移行できる時期を見極める必要があります。 脚注 read-only化後も既存のPodは取得できるが、Trunkに新しいPodやバージョンは公開できなくなる。独自のspecリポジトリで配布されているPodは影響を受けない。 ↩︎ Firebase公式の移行ガイドによれば、CocoaPodsで最後に公開されるメジャーバージョンは12とされている。 ↩︎ CocoaPodsとSPMのバージョンを入れ替えて2通りで検証した。いずれも、ビルドしたバイナリに含まれていたのはSPM版で、新旧は関係なかった。どのパターンでも同じかまでは検証できていない。 ↩︎ 既定の探索先は、プロジェクトルートの Package.swift と、 *.xcodeproj および *.xcworkspace 配下の xcshareddata/swiftpm/Package.resolved である。詳細は LicensePlistのREADME を参照。 ↩︎
Extracting structured data from PDFs using Gemini 2.0 and Genkit in Firebase: Web Architecture & Implementation Guide Original: codingcat.dev Building AI features in TypeScript or Go quickly turns into spaghetti when you try to bolt structured output validation, tool calling, and OpenTelemetry tracing onto raw model API calls. Following the announcement of Extracting structured data from PDFs using Gemini 2.0 and Genkit by Peter Friese on the Official Firebase Blog (2025-02-20), here is our hands-on CodingCat.dev breakdown of what actually shipped, how it works under the hood, and how we wire it into production TypeScript, Next.js, Astro, SvelteKit, React, and Angular applications. Last week, Google released Gemini 2.0, and after reading this blog post about parsing PDFs using Gemini 2.0, I decided to rebuild the sample using Genkit. The Mental Model: Why Extracting structured data from PDFs using Gemini 2.0 and Genkit Matters for Web Devs As a Google Developer Expert (GDE) for Firebase and Senior Solutions Engineer at CodingCat.dev, I evaluate every Firebase update through one lens: does it reduce boilerplate while keeping our runtime security and cloud bills predictable? Firebase Genkit gives full-stack engineers strongly typed flows, dotprompt templates, local developer UI trace inspection, and production observability wired directly into Google Cloud and Firebase. > AJ Pro-Tip from Alex: Always wrap your Genkit flows with explicit Zod input/output schemas and enforce Firebase App Check attestation on callable endpoints so bots cannot rack up unauthenticated token spend. How It Works: Technical Breakdown & Implementation For those who are unfamiliar, Genkit is an AI integration framework that makes implementing AI features for your apps easier. In this blog post, I am going to focus on Genkit for Node.js, but the team is also working on building support for Go (available in alpha) and Python (under development). This means you can use Genkit on any runtime that supports one of those three languages. The sample app I’m discussing in this blog post is a simple command-line utility that you can run on macOS or any other platform that supports Node.js, but you can also use Genkit on the backend, for example in Cloud Functions for Firebase, Cloud Run, or any other environment that supports Node.js. Setup Before you can use Gemini 2.0 Flash in Genkit, you need to install and add Genkit and the Google AI SDK plugin for Genkit. You can then instantiate Genkit and define a default model. This model will then be used in all subsequent calls you make via the ai instance. import import // instantiate Genkit const plugins: [ model: gemini20Flash, }); For a detailed walkthrough of the setup process, check out this video: Extracting structured data In this first example, let’s look at how you can use Gemini 2.0 Flash and Genkit to extract structured data from PDFs. Let’s imagine you’ve received a PDF with an invoice. To further process the invoice, you need to extract the invoice number, date, all the line items (including description, amount, and their individual price), as well as the gross price of the invoice. Thanks to Gemini’s vision capabilities, we can let it handle the OCR for us. The following code snippet shows how to call any LLM via Genkit’s unified generation API, and pass a multimodal prompt (including a URL to the PDF file we want to analyse as well as an instruction). export const prompt: [ { media: { url } }, { text: ] }); return } If you’d call this method now for example by passing this URL (which points to an invoice), you’d get the following result: [ { 'Invoice no': ' 'Date of issue': ' Seller: { Name: 'Williams LLC', Address: ' Tax Id': ' IBAN: 'GB }, Client: { Name: 'Hernandez-Anderson', Address: ' 'Tax Id': ' }, Items: [ [Object], [Object], [Object], [Object], [Object], [Object], [Object] ], Summary: { 'VAT [%]': ' 'Net worth': ' VAT: ' 'Gross worth': ' Total: '$ 'Total VAT': '$ 'Total Gross worth': '$ } } ] Which is pretty impressive - after all, the model was able to correctly extract all information. However, this might not be in the format you need this in. This is where Genkit’s support for structured output comes in handy. You can define a schema for your data using Zod, like this: export const prompt: [ { media: { url } }, { text: ] }); return } Then, pass the schema to Genkit’s generate call to enforce this schema. export const prompt: [ { media: { url } }, { text: ], }); return } And now, calling the function with the same PDF file will yield the following result: { date: ' invoiceNumber: ' items: [ { description: 'Lilly Pulitzer dress Size grossWorth: quantity: }, { description: 'New ERIN Erin Fertherston Straight Dress White Sequence Lining Sleeveless SZ grossWorth: quantity: }, { description: 'Sequence dress Size Small', grossWorth: quantity: }, { description: 'fire los angeles dress Medium', grossWorth: quantity: }, { description: grossWorth: quantity: }, { description: 'Lularoe Nicole Dress Size Small Light Solid Grey/ White Ringer Tee Trim', grossWorth: quantity: }, { description: 'J.Crew Collection Black & White sweater Dress sz S', grossWorth: quantity: } ], totalGrossWorth: } Since this adheres to the schema we provided, it will be much easier to process. Gemini 2.0 Flash supports structured output, but even if you’re using an LLM that doesn’t support natively structured output, Genkit can help by augmenting the prompt and coercing the returned data for you. What’s really amazing about this: you won’t have to change your code, thanks to Genkit’s unified generation API (check out this thread on Bluesky in which I demonstrate this). Parsing hand-written form input I mentioned Gemini’s OCR capabilities, so let’s try extracting the hand-written entries in the following PDF: One way to achieve this would be to define a new schema and then call Genkit’s generate method using this new schema. But there is a more flexible way to do this. It turns out that the actual code for calling Gemini to extract data from a PDF is always the same - only the output format (and potentially the instructions) change for each type of PDF we want to analyse. So why not make this a bit more generic? Genkit provides a way to extract prompts into external files, using the Dotprompt library. This allows you to keep your code free from any prompt, making it easier to change the prompt independently of the code. --- model input schema pdfUrl default pdfUrl output schema formNumber startDate beginningOfYear endOfYear name address phoneNumber ein --- Extract the hand-written form data. {{media url This prompt file defines the model Genkit should use (Gemini 2.0 Flash), as well as the prompt itself. But it also specifies the input and output schemas for the prompt. For example, under input/schema, we define an input parameter named pdfUrl of type string, which can then be used in the prompt to pass the URL. Likewise, under output/schema, we define all the keys we want to extract from the PDF file, including their types. Note that the descriptions of the keys do not just serve the purpose of documentation - Genkit will use them in the prompt to specifically tell the model how to find the data for the respective keys. To load a prompt from a file, use ai.prompt(filename). This has a beneficial side effect: we can now create.prompt files for all the different types of data we want to extract from PDF files, and just pass the filename to the extract function: export const const return } Instead of using ai.generate() to call the LLM, you can execute a prompt by caling the prompt itself, and passing the required parameters. Calling this method using extract("form", "https://storage.googleapis.com/generativeai-downloads/data/pdf_structured_outputs/handwriting_form.pdf") will yield the following result: { address: ' beginningOfYear: ein: ' endOfYear: formNumber: 'CA name: 'Annual Return Plan', phoneNumber: ' startDate: ' } Which - if you ask me - is mind-boggling. Where to go from here To learn more about Genkit, check out the documentation. Also, feel free to drop by my weekly livestreams - I’m currently working on implementing a Second Brain app, and I’m using Genkit for some of the AI-powered features. If you’d like to try out the sample app, the source code is available on GitHub. Production Web Architecture & Security Checklist Whether we are deploying on Firebase App Hosting, Cloudflare Workers, or Vercel, shipping AI features to production requires defense-in-depth across three layers: - Enforce Firebase App Check & Attestation: **Protect your web endpoints, Cloud Functions, Data Connect GraphQL resolvers, and Firebase AI Logic calls against unauthorized replay or billing abuse using Firebase App Check with reCAPTCHA Enterprise**. - **Validate Locally with the Firebase Emulator Suite: **Run deterministic integration tests against local Firestore, Auth, Functions, and Data Connect PostgreSQL emulators before promoting schema or rule changes to production. - **Keep Server & Client Boundaries Type-Safe: **Use the modular Firebase Web SDK and generated TypeScript bindings so SSR frameworks like Next.js, Astro, SvelteKit, and Angular serialize state cleanly without hydration flickers. Conclusion Accelerate your full-stack web and AI development by pairing Extracting structured data from PDFs using Gemini 2.0 and Genkit with strict Security Rules, Firebase App Check, and local emulator testing. Come tell us on X (@CodingCatDev) and LinkedIn (CodingCat.dev) how you are using Firebase in your stack, and subscribe to the CodingCat.dev YouTube Channel so you don't miss what we build next! Watch Our Related Firebase Video Tutorial on YouTube Want to see how we architect and debug Firebase web applications live? Watch our related CodingCat.dev session Firebase SQL with Data Connect below, and make sure to Subscribe to CodingCat.dev on YouTube for weekly full-stack web and AI deep dives: {% youtube N25khadfUag %} Resources, Official Docs & Related CodingCat.dev Guides - Primary Release Source: **Extracting structured data from PDFs using Gemini 2.0 and Genkit on the Official Firebase Blog (published 2025-02-20 by Peter Friese) - **Official Firebase Documentation: **Firebase Developer Docs & Web SDK Reference - **Related on CodingCat.dev: Announcing Firebase Genkit 1.0 for Node.js - Related on CodingCat.dev: Firebase + Gemini Code Assist - Related on CodingCat.dev: Firebase SQL with Data Connect - Related on CodingCat.dev: Build a Custom No-Code App in 90 Minutes Frequently Asked Questions (FAQ) What are the key capabilities introduced in Extracting structured data from PDFs using Gemini 2.0 and Genkit? Extracting structured data from PDFs using Gemini 2.0 and Genkit (announced 2025-02-20 by the Firebase team) enhances the platform for Firebase, Google Cloud, Web Dev, AI, TypeScript, Serverless workloads. Last week, Google released Gemini 2.0, and after reading this blog post about parsing PDFs using Gemini 2.0, I decided to rebuild the sample using Genkit. Developers can review the primary announcement on the Firebase Blog alongside our implementation patterns and production checklist above. How do web developers use Extracting structured data from PDFs using Gemini 2.0 and Genkit with Next.js, SvelteKit, React, or Angular? Web developers can integrate these features using the modular Firebase JavaScript/TypeScript SDK, Firebase Data Connect web bindings, and Firebase App Hosting. Always pair client-side SDK initialization with Firebase App Check and strict Security Rules, and test locally with the Firebase Local Emulator Suite before deploying. Where can I watch video tutorials on Firebase Web and AI development? You can watch our hands-on Firebase video walkthroughs on the CodingCat.dev YouTube Channel, including Firebase SQL with Data Connect, and follow us on X (@CodingCatDev) for weekly full-stack tutorials.
February Update: What's New in Data Connect in Firebase: Web Architecture & Implementation Guide Original: codingcat.dev For years, choosing Firebase meant trading away relational SQL joins, strict foreign keys, and pgvector similarity search in favor of NoSQL document denormalization. Following the announcement of February Update: What's New in Data Connect by Cynthia Wang on the Official Firebase Blog (2025-02-26), here is our hands-on CodingCat.dev breakdown of what actually shipped, how it works under the hood, and how we wire it into production TypeScript, Next.js, Astro, SvelteKit, React, and Angular applications. Note: Firebase Data Connect has been renamed to SQL Connect. Learn more in the SQL Connect announcement. The Mental Model: Why February Update: What's New in Data Connect Matters for Web Devs As a Google Developer Expert (GDE) for Firebase and Senior Solutions Engineer at CodingCat.dev, I evaluate every Firebase update through one lens: does it reduce boilerplate while keeping our runtime security and cloud bills predictable? Firebase Data Connect bridges that gap by pairing a managed Google Cloud SQL for PostgreSQL instance with a declarative GraphQL schema compiler that automatically generates type-safe TypeScript, React, and Angular SDKs alongside server-enforced @auth directives. > AJ Pro-Tip from Alex: Keep your authorization logic inside your Data Connect GraphQL operations using @auth(level: USER) and server-evaluated expressions like auth.uid and request.time rather than trusting client-supplied user IDs in query variables. How It Works: Technical Breakdown & Implementation New year, new features! Built on CloudSQL, Firebase Data Connect is our backend-as-a-service for Postgres. It’s a high-performance, scalable, and secure way to work with relational data using GraphQL. Since our previous update in ‘24, we’ve been hot at work to make Firebase Data Connect better to use, here’s a peek at what’s new. What’s New? Using React? Now you can generate React SDKs for your projects, with bindings powered by TanStack Query, to integrate your GraphQL operations into your React based apps. More frameworks are also in the works, so keep an eye out! Enable generating React Hooks in connector.yaml: generate: javascriptSdk: react: true outputDir: "../movies-generated" package: "@movie-app/movies" packageJsonDir: "../../" import function const if return } if return } return < {data. < ))} </ ); } Learn more about React support in the documentation. Moving data just got easier. With PGLite, you can quickly import and export your database, whether you’re migrating, backing up, or setting up a fresh project. The Firebase team heard your feedback! You can now see the distance from the query vector in your similarity search results by selecting the _metadata.distance field: query movies_descriptionEmbedding_similarity( compare_embed: { within: where: { { id title description _metadata { distance } } } This makes it easy to choose a good value for within and tune your search performance. @check can now be used for queries as well as mutations! Define authorization rules with CEL expressions, allowing you to reference data from other tables and apply conditional logic for more precise access control. query user(id: $userId) { privacySetting @check expr: message: ) @redact favoriteMovies movie { id title genre } } } } Android developers, we’ve got something for you! The new quickstart sample app shows you how to use Firebase Data Connect in an Android app, so you can start building right away. Watch the Latest Livestream Want a closer look? We hung out with Firebase After Hours for a live demo and some great Q&A. Check out the replay here: Firebase After Hours #9: Firebase Data Connect: SQL or NoSQL, that is no longer the question Don’t forget to share your thoughts Production Web Architecture & Security Checklist Whether we are deploying on Firebase App Hosting, Cloudflare Workers, or Vercel, shipping SQL features to production requires defense-in-depth across three layers: - Enforce Firebase App Check & Attestation: **Protect your web endpoints, Cloud Functions, Data Connect GraphQL resolvers, and Firebase AI Logic calls against unauthorized replay or billing abuse using Firebase App Check with reCAPTCHA Enterprise**. - **Validate Locally with the Firebase Emulator Suite: **Run deterministic integration tests against local Firestore, Auth, Functions, and Data Connect PostgreSQL emulators before promoting schema or rule changes to production. - **Keep Server & Client Boundaries Type-Safe: **Use the modular Firebase Web SDK and generated TypeScript bindings so SSR frameworks like Next.js, Astro, SvelteKit, and Angular serialize state cleanly without hydration flickers. Conclusion Accelerate your full-stack web and AI development by pairing February Update: What's New in Data Connect with strict Security Rules, Firebase App Check, and local emulator testing. Come tell us on X (@CodingCatDev) and LinkedIn (CodingCat.dev) how you are using Firebase in your stack, and subscribe to the CodingCat.dev YouTube Channel so you don't miss what we build next! Watch Our Related Firebase Video Tutorial on YouTube Want to see how we architect and debug Firebase web applications live? Watch our related CodingCat.dev session Firebase SQL with Data Connect below, and make sure to Subscribe to CodingCat.dev on YouTube for weekly full-stack web and AI deep dives: {% youtube N25khadfUag %} Resources, Official Docs & Related CodingCat.dev Guides - Primary Release Source: **February Update: What's New in Data Connect on the Official Firebase Blog (published 2025-02-26 by Cynthia Wang) - **Official Firebase Documentation: **Firebase Developer Docs & Web SDK Reference - **Related on CodingCat.dev: Firebase + Gemini Code Assist - Related on CodingCat.dev: Add image generation to your apps with Imagen 3 - Related on CodingCat.dev: Firebase SQL with Data Connect - Related on CodingCat.dev: Build a Custom No-Code App in 90 Minutes Frequently Asked Questions (FAQ) What are the key capabilities introduced in February Update: What's New in Data Connect? February Update: What's New in Data Connect (announced 2025-02-26 by the Firebase team) enhances the platform for Firebase, Google Cloud, Web Dev, SQL, React, Security workloads. Note: Firebase Data Connect has been renamed to SQL Connect. Learn more in the SQL Connect announcement. Developers can review the primary announcement on the Firebase Blog alongside our implementation patterns and production checklist above. How do web developers use February Update: What's New in Data Connect with Next.js, SvelteKit, React, or Angular? Web developers can integrate these features using the modular Firebase JavaScript/TypeScript SDK, Firebase Data Connect web bindings, and Firebase App Hosting. Always pair client-side SDK initialization with Firebase App Check and strict Security Rules, and test locally with the Firebase Local Emulator Suite before deploying. Where can I watch video tutorials on Firebase Web and AI development? You can watch our hands-on Firebase video walkthroughs on the CodingCat.dev YouTube Channel, including Firebase SQL with Data Connect, and follow us on X (@CodingCatDev) for weekly full-stack tutorials.
Hey, @twerske I'm not sure if you can help out, but maybe 😅🍀 Just as a general thought. This is the most upvoted issue on flutterfire: flutterfire#17338 IMO this is one of the greatest misses on Flutter Linux desktop. We can't use Firebase there (full Google end-to-end)
firebase-ios-sdk#16972 Firebase v13からSceneDelegateを考慮するようになってFIAMのactionURLがhttpsだとどんなURLもUniversalLinkとして流れてくるのが困るよーというIssue
Can Firebase provide native per-user Firestore rate limits without replacing realtime listeners? I am building an app around Firestore's direct client SDK, realtime listeners and offline cache. I want to keep that architecture, but I cannot find a supported native way to cap an otherwise authorised user's billable reads/writes across devices and concurrent connections. The existing feature request dates from April 2023 and currently has 73 votes: firebase.uservoice.com There are concrete adoption concerns in its comments: Al3life reports moving to Supabase for this feature, capTarget archery says it may rule Firebase out for future projects, and Anatole Couasnon describes adding an API despite choosing Firebase for direct access. These are individual reports, not a survey, but they match the concern blocking my confidence in launching. I am not asking for authentication or permissions to be replaced. Rules limit what a user can access, but a query-size limit does not limit how often an allowed query runs. App Check attests clients; it is not a configurable allowance for each UID. Budget alerts do not stop usage. Cloud Armor in front of my own API does not control the Google-managed Firestore endpoint the SDK calls. A custom API/SSE/WebSocket gateway could control traffic routed through it, but rebuilding native listener synchronisation, reconnect handling, cache behaviour and authorisation adds infrastructure, cost and complexity. That is not a viable equivalent for this application. An after-read trigger alone would also be too late to stop the triggering charge or a concurrent burst. What I would like Firebase to provide is a simple console or rules-level policy, enforced by the service: per-UID rolling/burst allowances shared across devices, plus a database/project backstop. It needs to address document/query volume, writes, initial listener snapshots, subsequent billable updates and reconnects, with clear charging and quota-exceeded semantics. I appreciate that the implementation may be more complex than the setting exposed to developers. I submitted a detailed feature request yesterday and have asked our Google Cloud contacts to escalate it. Is there a Firestore product owner who can give this an explicit status or link it to the right backend tracker? If a supported solution now preserves direct SDK listeners and actually enforces the allowance, I would welcome a documentation link. Otherwise, please treat this as an adoption and cost-abuse concern that needs an owned response. Related history: firebase-js-sdk#647 Official App Check limitations: firebase.google.com Budget guidance: firebase.google.com