Skip to content

fix(app_check,apple): use the provider passed to activate() on Flutter 3.50 - #18968

Open
SelaseKay wants to merge 1 commit into
mainfrom
fix/18966-app-check-provider-factory
Open

SelaseKay wants to merge 1 commit into
mainfrom
fix/18966-app-check-provider-factory

Conversation

@SelaseKay

Copy link
Copy Markdown
Contributor

Description

On iOS and macOS with Flutter 3.50, FirebaseAppCheck.instance.activate() no longer changes the provider the native SDK uses. On a simulator the SDK keeps a debug provider with a random token and ignores AppleDebugProvider(debugToken:). On a device it keeps DeviceCheck when App Attest was requested.

Cause. Flutter 3.50 registers plugins dependencies first, so firebase_core now registers before firebase_app_check. Flutter 3.47 and earlier sorted by name, which put firebase_app_check first. firebase_core calls FirebaseApp.configure() during registration when a GoogleService-Info.plist is present. The Apple SDK creates App Check during configure and keeps the provider from whichever factory is installed at that moment. The plugin installed its factory only when it registered, which is now too late, so activate() reconfigured a provider the SDK never asks for a token.

Fix.

  • firebase_app_check: the plugin class has a fixed Objective-C name, one shared provider factory, and a static installProviderFactory().
  • firebase_core: immediately before FirebaseApp.configure(), look the App Check plugin up by name and call installProviderFactory(). There is no compile-time dependency on firebase_app_check, and nothing happens when that plugin is not in the app.

The macOS sources are symlinks to the iOS files, so both platforms get the change. There is no Dart API change and no generated code change.

Limits.

Related Issues

Fixes #18966

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]).
This will ensure a smooth and quick review process. Updating the pubspec.yaml and changelogs is not required.

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • My PR includes unit or integration tests for all changed/updated/fixed behaviors (See Contributor Guide).
  • All existing and new tests are passing.
  • I updated/added relevant documentation (doc comments with ///).
  • The analyzer (melos run analyze) does not report any problems on my PR.
  • I read and followed the Flutter Style Guide.
  • I signed the CLA.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Does your PR require plugin users to manually update their apps to accommodate your change?

  • Yes, this is a breaking change.
  • No, this is not a breaking change.

Test plan

New e2e test in the App Check example, getToken uses the provider passed to activate. It runs on the iOS simulator only. It activates App Attest and expects getToken(true) to fail with an App Attest error. No simulator supports App Attest, so that error appears only when the provider passed to activate() is the one the SDK uses.

Run locally on Flutter 3.50.0:

Check Result
App Check example e2e, iOS simulator, Swift Package Manager Passes. The new test fails with the two Swift files reverted to main.
App Check example e2e, macOS Passes. The new test is skipped.
macOS native log after activate(AppleDebugProvider(debugToken:)) The debug provider is the one asked for a token. It is not asked without the fix.
CocoaPods app, iOS simulator The SDK uses the token passed to activate(). Without the fix it creates a random token first.
flutter build ios --release --no-codesign Builds. The binary keeps the class name and the selector firebase_core looks up.
flutter_plugin_tools format, validate-formatting.sh Pass
melos run check-license-header Pass
flutter_plugin_tools analyze Pass

Not run: a physical device, a successful token exchange against a registered debug token, and the Android, web, and Windows e2e. The new test is skipped on those platforms.

…r 3.50

Flutter 3.50 registers firebase_core before firebase_app_check. firebase_core
configures Firebase during registration, and the Apple SDK creates the App
Check provider at that point from whichever factory is installed. The plugin
installed its factory later, so activate() reconfigured a provider the SDK
never used.

firebase_core now lets firebase_app_check install its factory immediately
before FirebaseApp.configure().

Fixes #18966

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request ensures that the Firebase App Check provider factory is installed on iOS before FirebaseApp.configure() is called. Since firebase_core is registered before firebase_app_check, a dynamic lookup helper installAppCheckProviderFactoryIfLinked was added to FLTFirebaseCorePlugin to invoke installProviderFactory on FirebaseAppCheckPlugin via Objective-C selectors if the plugin is linked. Additionally, an integration test was added to verify that getToken correctly uses the provider passed to activate on iOS simulators. There are no review comments, so I have no feedback to provide.

/// `FirebaseApp.configure()` and keeps that provider. `activate()`
/// reconfigures the provider this factory handed out, so there must only
/// ever be one factory.
static let sharedProviderFactory = FlutterAppCheckProviderFactory()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Optional, could be a follow-up. AppCheck is created eagerly for every app, so when providers[app.name] is nil in FlutterAppCheckProviderFactory.configure (line 354), this factory never handed a provider to that app's AppCheck. The wrapper made there is never asked for a token, yet activate() still completes. That is what happens in the two cases listed under Limits (FirebaseApp.configure() in the AppDelegate, #18613, and a new firebase_app_check with an older firebase_core). Could that branch log something like "App Check for was configured before firebase_app_check installed its provider factory, so the Apple provider passed to activate() is not used (see #18613)"? Apps following the native workaround from #18614 would see it on every launch, which is accurate for them, and everyone else would get a console line instead of only a 403 later.

@fatihdurmaz

Copy link
Copy Markdown

thank you for this pr.

This branch has not been deployed

No deployments
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.

[firebase_app_check]: On iOS with Flutter 3.50, activate() has no effect because firebase_core now registers before firebase_app_check

3 participants