In firebase_auth, how does signInWithProvider with Google or Apple behave across Android, iOS and web, and what platform traps should you expect?
answer
- native method versus popup and redirect
- kIsWeb branch
- Apple is native only on Apple platforms
- Custom Tab on Android
- taskAffinity and web-context-already-presented
basics
~10 ssignInWithProvider runs Google or Apple sign-in on Android and iOS; web uses signInWithPopup or signInWithRedirect, which throw UnimplementedError elsewhere. Apple is native on iOS, while Android runs every provider in a Chrome Custom Tab.
solid answer
~40 sYou build an `AuthProvider` — `GoogleAuthProvider()` or `AppleAuthProvider()` with `addScope('email')` and `addScope('name')` — and on Android and iOS call `signInWithProvider`; on web you call `signInWithPopup` or `signInWithRedirect`, which throw `UnimplementedError` on native platforms, so apps branch on `kIsWeb`. Underneath, iOS runs Apple through the native Sign in with Apple request and other providers through a browser OAuth flow; Android runs every provider, Apple included, in a Chrome Custom Tab; macOS supports only Apple. For Google on mobile, the FlutterFire guide also offers `google_sign_in` plus `signInWithCredential` for the native account picker. The classic Android trap: Flutter's template sets `android:taskAffinity=""`, so switching apps mid-login closes the tab and returns `web-context-already-presented` — remove that attribute.
code
dart · 9 linesimport 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
Future<UserCredential> signInWithGoogle() {
final GoogleAuthProvider provider = GoogleAuthProvider();
return kIsWeb
? FirebaseAuth.instance.signInWithPopup(provider)
: FirebaseAuth.instance.signInWithProvider(provider);
}go deeper
Know that mobile uses signInWithProvider and web uses signInWithPopup or signInWithRedirect, with a kIsWeb branch between them.
Describe what runs per platform: native Apple on iOS, browser OAuth for other providers, a Custom Tab on Android, Apple only on macOS.
Diagnose the taskAffinity Custom Tab failure, handle account-exists-with-different-credential by linking, and weigh google_sign_in against the generic flow.
Choose which providers to offer per platform, balancing store requirements, native user experience and the extra dependencies each flow brings.
## Three entry points for federated sign-in `firebase_auth` offers three ways to run a provider sign-in with an `AuthProvider` object such as `GoogleAuthProvider()` or `AppleAuthProvider()`: | Method | Platforms | What it does | |---|---|---| | `signInWithProvider(provider)` | Android, iOS (and macOS for Apple only) | Runs the provider's flow through the native Firebase SDK | | `signInWithPopup(provider)` | Web | Opens a popup window for the provider | | `signInWithRedirect(provider)` | Web | Navigates away and back, completed with `getRedirectResult()` | On Android and iOS, `signInWithPopup` and `signInWithRedirect` are not implemented: the pinned method-channel code throws `UnimplementedError` with "signInWithPopup() is only supported on web based platforms". A cross-platform app therefore branches on `kIsWeb`, exactly as the FlutterFire Apple example does. Scopes and custom parameters travel with the provider: `AppleAuthProvider()..addScope('email')..addScope('name')`, or `GoogleAuthProvider()..addScope(...)`. The FlutterFire guide notes that Apple shows its full first-time UI — including the share or hide email choice — only when `email` and `name` are requested. ## What actually runs on each platform The native implementations in the pinned plugin differ in a way interviewers like to probe: - **iOS, Apple provider** — `signInWithProvider(AppleAuthProvider())` launches the **native Sign in with Apple** request; the app needs the "Sign in with Apple" capability on its `Runner` target. - **iOS, any other provider (Google included)** — the plugin builds a generic `OAuthProvider` with the provider ID, scopes and parameters and runs a **browser-based OAuth flow**. - **Android, every provider (Apple included)** — the plugin builds an `OAuthProvider` and starts the flow through the Firebase SDK, which opens a **Chrome Custom Tab**. Apple on Android is a web flow too. - **macOS** — only `AppleAuthProvider` is supported; other providers fail with `unsupported-platform`. ## The Google-specific alternative For Google on Android and iOS, the FlutterFire guide recommends a different route: use the `google_sign_in` plugin to run Google's native account flow, then turn the result into a Firebase credential with `GoogleAuthProvider.credential(idToken: ...)` and pass it to `signInWithCredential`. The trade-off: - **`signInWithProvider(GoogleAuthProvider())`** needs no extra package but shows a browser tab rather than the device's account picker. - **`google_sign_in` plus `signInWithCredential`** gives the native account chooser at the cost of another dependency and its own setup, such as the Android SHA-1 fingerprint the guide mentions. Either way, the Google or Apple provider must be enabled in the Firebase console first. ## Android's Custom Tab trap The FlutterFire guide carries a warning that catches many Flutter apps: Flutter's default Android template sets `android:taskAffinity=""` on the main activity. With that attribute, the Custom Tab opened by `signInWithProvider` closes when the user switches apps mid-login — to open a password manager or read a one-time code — and coming back produces a `web-context-already-presented` error. The documented fix is to **remove `android:taskAffinity=""` from `AndroidManifest.xml`**. ## Setup checklist before the first call 1. Enable the Google or Apple provider for the project in the Firebase console. 2. For Apple on iOS, add the "Sign in with Apple" capability to the `Runner` target. 3. For Google through `google_sign_in`, complete that plugin's own setup, including the Android SHA-1 fingerprint. 4. On Android, remove `android:taskAffinity=""` from the main activity. 5. On web, pick popup or redirect and handle `getRedirectResult()` if you choose redirect. ## Errors and account conflicts Provider sign-ins throw `FirebaseAuthException` like every other method. The code worth handling specifically is `account-exists-with-different-credential`: when the project allows one account per email and the address already belongs to another provider, the exception carries the `email` and a pending `credential`. The app signs the user in with the existing provider, then links the pending credential with `linkWithCredential`. ## A cross-platform sketch ```dart import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/foundation.dart'; Future<UserCredential> signInWithApple() { final AppleAuthProvider provider = AppleAuthProvider() ..addScope('email') ..addScope('name'); return kIsWeb ? FirebaseAuth.instance.signInWithPopup(provider) : FirebaseAuth.instance.signInWithProvider(provider); } ``` The same shape works for Google; on success, the auth streams deliver the new `User` and the app's sign-in gate moves the cook to the recipe feed.
- What does account-exists-with-different-credential mean after a Google sign-in, and how do you resolve it?The project allows one account per email, and that address already belongs to another provider. The `FirebaseAuthException` carries the `email` and a pending `credential`. Sign the user in with the provider they used before, then call `linkWithCredential` with the pending credential so both providers reach the same account.
- Why might a team pick google_sign_in plus signInWithCredential over signInWithProvider for Google on mobile?`google_sign_in` shows Google's native account picker instead of a browser tab, which is the flow users expect on a phone. It costs an extra dependency and its own configuration, such as the Android SHA-1 fingerprint. `signInWithProvider` needs neither but runs as a web flow.
saying these in an interview costs you the question
- signInWithPopup works on Android and iOS as a native popup dialog.
- Apple sign-in on Android uses the native Sign in with Apple sheet.
- signInWithProvider supports every provider on macOS.
- web-context-already-presented is fixed by adding the SHA-1 fingerprint.
- Requesting no scopes still shows Apple's full share-or-hide-email screen.