Skip to content

feat(functions): httpsCallable.stream support#8799

Merged
mikehardy merged 154 commits intomainfrom
cloud-functions-streaming
Feb 11, 2026
Merged

feat(functions): httpsCallable.stream support#8799
mikehardy merged 154 commits intomainfrom
cloud-functions-streaming

Conversation

@MichaelVerdon
Copy link
Copy Markdown
Contributor

@MichaelVerdon MichaelVerdon commented Dec 9, 2025

Description

@russellwheatley taken over:

  • I had to create a swift implementation for callables as the Swift firebase-ios-sdk is the only way to set limited app check token.
  • As mentioned internally, the HttpsCallableStreamOptions will only apply to web streaming. Use HttpsCallableOptions for iOS and android http rest calls/streaming.
  • I created an asynciterator for cancelling streams on web as AbortSignal isn't available on any version of RN lower than v.81.
  • refactored android and removed UniversalFirebaseFunctionsModule.java‎. This required making TaskExecutorService constructor public on Firebase App so we can still use it.
  • refactored android, ios and TS to remove code duplications.

Related issues

fixes #8210

Release Summary

Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
    • Yes
  • My change supports the following platforms;
    • Android
    • iOS
    • Other (macOS, web)
  • My change includes tests;
    • e2e tests added or updated in packages/\*\*/e2e
    • jest tests added or updated in packages/\*\*/__tests__
  • I have updated TypeScript types that are affected by my change.
  • This is a breaking change;
    • Yes
    • No

Test Plan


Think react-native-firebase is great? Please consider supporting the project with any of the below:

@vercel
Copy link
Copy Markdown

vercel Bot commented Dec 9, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
react-native-firebase Ready Ready Preview, Comment Feb 11, 2026 1:32pm

Request Review

@mikehardy mikehardy changed the title feat(cloud_functions): httpsCallable.stream support feat(functions): httpsCallable.stream support Dec 10, 2025
Copy link
Copy Markdown
Collaborator

@mikehardy mikehardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of my comments would result in any change in functionality - it all seems like it would work fine. Just trivial nitpicks or similar, along with notes on cross-checking performed (with positive outcomes)

So +1 and I'd squash merge - but leaving open in case you want to adopt any of the suggestions?

Comment thread .github/workflows/scripts/functions/src/testStreamingCallable.ts
Comment thread .github/workflows/scripts/functions/src/testStreamingCallable.ts
Comment thread packages/functions/RNFBFunctions.podspec Outdated
s.private_header_files = "ios/**/*.h"
s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*'
# Turbo modules require these compiler flags
s.compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_CFG_NO_COROUTINES=1'
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the compiler_flags is already handled by the install_module_dependencies() call (which is...frankly non-negotiable so should be taken out of the if(defined?(install_modules_dependencies()) conditional and be the only path)

suggest experiment with removing this line and removing the conditional so that install_modules_dependencies is always called, and I think TurboModules will be set up correctly for all supported react-native

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made install_module_dependencies () always run.

I've tried a number of different ways not setting all headers private (nuclear option) but no matter what, the Swift module build blows up when it encounters C++ stdlib header from codegen.

Comment thread jest.setup.ts Outdated
/// Swift wrapper for Firebase Functions streaming that's accessible from Objective-C
/// This is necessary because Firebase's streaming API uses Swift's AsyncStream which
/// doesn't have Objective-C bridging
@available(iOS 15.0, macOS 12.0, *)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this @available annotation shouldn't be necessary unless the pbxproj IPHONEOS_DEPLOYMENT_TARGET is wrong

In fact no, it is set to 10 ! That's not correct

4 places, here is an example

confirmed iOS 15 is already our minimum supported iOS version - we're issuing the merge result of this as a breaking change but it's related to functions going new architecture only, this iOS version doesn't have to be mentioned.

As a separate issue / peeled from this review (right-click on this comment and create issue - I formatted it well for that), we should raise the deploy target to 15 in the package pbxproj's to match current requirements

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, if I understood you correctly - raise min deployment target in Functions package (and possibly across the board) in a separate PR(s)?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep exactly that - just peel this to another issue directly via the comment tools and table it since it's good for hygiene but that's low priority and this PR needs to go in

Comment thread packages/functions/lib/namespaced.ts Outdated
streamOptions?: HttpsCallableStreamOptions,
) => {
const platformOptions =
isAndroid || isIOS
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could also be written maybe more concisely as !isOther but isOther is defined as !isAndroid && !isIOS so means literally the same thing. Philosophically I think isOther is technically more accurate as perhaps we add more native platforms that need the non-web type, but isOther is specifically how we say "firebase-js-sdk implementation" so is maybe best?

Suggested change
isAndroid || isIOS
!isOther

Comment thread packages/functions/lib/namespaced.ts Outdated
Comment thread packages/functions/lib/namespaced.ts Outdated
@"listenerId" : listenerIdNumber,
@"body" : event
};
[[RNFBRCTEventEmitter shared] sendEventWithName:@"functions_streaming_event"
Copy link
Copy Markdown
Collaborator

@mikehardy mikehardy Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have noticed event batching behavior on iOS only, and I trace it to this method call (so far).
Specifically if I add an NSLog call here before the RNFBRCTEventEmitter call, and I alter the Basic Stream local-test to wait 5 seconds, I get no events emitted for 20 seconds, then the first 4 come all at once. Then nothing, then the last event and the terminate event (you can see it in the timestamps):

Image

The function itself (running in the emulator) emits logs as expected, every 5 seconds when configured for a 5 second delay.

I haven't determined why yet but it's worth noting as I believe batching these is unwanted, and android doesn't exhibit this behavior.

It could be in the functions emulator batching the chunk sends to iOS for some reason (but...the native/emulator event emitting doesn't do that on android?) or it could be in firebase-ios-sdk, or it could be in our native code / firebase-ios-sdk setup / callbacks somehow.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't see anything on our iOS setup that would batch the responses to JS side. We can infer from android working fine, it isn't a problem with JS internal implementation. Sounds like a firebase-ios-sdk issue

for try await response in stream {
switch response {
case .message(let message):
eventCallback([
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

related to investigating why events are delayed/batched on iOS, they are also batched here - this isn't called every time the emulator function actually sends a chunk

@mikehardy
Copy link
Copy Markdown
Collaborator

CI being pesky.

  • Simulator boot issue on one of the iOS. Unrelated flake
  • compile error on debug attempt, while release still worked? That's new
image

@russellwheatley
Copy link
Copy Markdown
Member

@mikehardy - I think the build issue is related to changes made to podspec from PR review. I've reran debug build to confirm. Keeping my eye on it 👍

@russellwheatley
Copy link
Copy Markdown
Member

@mikehardy - failed. I think sendable protocol is related to Swift v6 that causes issue perhaps 🤔

@mikehardy
Copy link
Copy Markdown
Collaborator

swift to 5 did it, ios debug was a simulator pre-boot flake, re-running

@ftaibi
Copy link
Copy Markdown

ftaibi commented Feb 14, 2026

is stream() available now in main?

@mikehardy
Copy link
Copy Markdown
Collaborator

@ftaibi yes on main and I believe if you look at the PR where it went in, you should be able to grab patch-package packages that apply to the current release (and bring it up to main+that PR at that point in time) if you would like to use it pre-release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛 [@react-native-firebase/functions] Missing stream implementation for httpsCallable functions

4 participants