angular / angularfire

Angular + Firebase = ❤️
https://firebaseopensource.com/projects/angular/angularfire2
MIT License
7.68k stars 2.19k forks source link

AngularFire does not work on ios with ionic capacitor 3 #3087

Open moblizeitllc opened 2 years ago

moblizeitllc commented 2 years ago

Version info

Angular: "@angular/common": "~12.1.1", "@angular/core": "~12.1.1",

"@angular/forms": "~12.1.1",
"@angular/platform-browser": "~12.1.1",
"@angular/platform-browser-dynamic": "~12.1.1",
"@angular/router": "~12.1.1",
"@capacitor/android": "^3.3.2",
"@capacitor/app": "^1.0.6",
"@capacitor/core": "3.3.2",
"@capacitor/ios": "^3.3.2",
"@ionic/angular": "^5.5.2",

"rxjs": "~6.6.0",
"tslib": "^2.2.0",
"xcode": "^3.0.1",
"xml-js": "^1.6.11",
"zone.js": "~0.11.4"

Firebase: "firebase": "^9.5.0", AngularFire: "@angular/fire": "^7.2.0",

Other (e.g. Ionic/Cordova, Node, browser, operating system): ionic info

Ionic:

Ionic CLI : 6.18.1 (/usr/local/lib/node_modules/@ionic/cli) Ionic Framework : @ionic/angular 5.9.1 @angular-devkit/build-angular : 12.1.4 @angular-devkit/schematics : 12.1.4 @angular/cli : 12.1.4 @ionic/angular-toolkit : 4.0.0

Capacitor:

Capacitor CLI : 3.3.2 @capacitor/android : 3.3.2 @capacitor/core : 3.3.2 @capacitor/ios : 3.3.2

Cordova:

Cordova CLI : 10.0.0 (cordova-lib@10.1.0) Cordova Platforms : android broken, ios 5.1.1 Cordova Plugins : no whitelisted plugins (0 plugins total)

Utility:

cordova-res (update available: 0.15.4) : 0.15.3 native-run : 1.5.0

System:

ios-deploy : 1.9.4 ios-sim : ios-sim/9.0.0 darwin-x64 node-v14.17.0 NodeJS : v14.17.0 (/usr/local/bin/node) npm : 7.24.0 OS : macOS Monterey Xcode : Xcode 13.1 Build version 13A1030d

How to reproduce these conditions

Failing test unit, Stackblitz demonstrating the problem

Steps to set up and reproduce ionic build ionic cap copy ionic cap sync open xcode and either run on device or simulator

Sample data and security rules

Debug output

2021-12-08 13:25:36.266937-0600 App[2469:682932] KeyboardPlugin: resize mode - native 2021-12-08 13:25:36.280309-0600 App[2469:682932] InAppPurchase[objc] Initialized. ⚡️ Loading app at capacitor://localhost... ⚡️ [log] - onscript loading complete ⚡️ To Native -> Device getId 109505367 ⚡️ [log] - Ionic Native: deviceready event fired after 48 ms ⚡️ TO JS {"uuid":"14A77728-365E-4EDC-8F78-7CD1F6CC8CA0"} To Native Cordova -> AppVersion getVersionNumber AppVersion678940142 ["options": []] ⚡️ WebView loaded SplashScreen.hideSplash: SplashScreen was automatically hidden after default timeout. You should call SplashScreen.hide() as soon as your web app is loaded (or increase the timeout). Read more at https://capacitorjs.com/docs/apis/splash-screen#hiding-the-splash-screen ⚡️ To Native -> App addListener 109505368

Errors in the JavaScript console above pasted nothing else

Output from firebase.database().enableLogging(true);

Screenshots

Expected behavior

should run fine as it runs on android

Actual behavior

does not run on ios but run on android

moblizeitllc commented 2 years ago

some new observations. i can actually run on ios using

ionic capacitor run ios -l --external

but not directly from xcode. so there is something that xcode is doing while running it

tcns commented 2 years ago

Same here. I also tried with modular. But issue still happens

tcns commented 2 years ago

I got rid of angular/fire. And on vanilla firebase and rxfire works perfectly

"rxfire": "^6.0.3", "firebase": "^9.6.0"

moblizeitllc commented 2 years ago

do u have code sample/example on how ur appmodule.ts and a sample call to firebase looks like?

ChristianGerardHizon commented 2 years ago

I was also having this issue when building for an iOS emulator and actual iOS device, but adding this to the app.component.ts worked for me.

import { Component } from '@angular/core';
import { Capacitor } from '@capacitor/core';
import { initializeApp } from 'firebase/app';
import { indexedDBLocalPersistence, initializeAuth } from 'firebase/auth';
import { environment } from 'src/environments/environment';

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent {
  constructor() {
    const app = initializeApp(environment.firebase);
    if (Capacitor.isNativePlatform) {
      initializeAuth(app, {
        persistence: indexedDBLocalPersistence
      });
    }
  }
}

This is where I found the fix and a sample code https://github.com/firebase/firebase-js-sdk/issues/5552#issuecomment-929580662

Original Issue https://forum.ionicframework.com/t/firebase-auth-in-sdk-9-does-not-work-on-ios-sim-or-devices/215362/9

moblizeitllc commented 2 years ago

but i am not using auth module. does this still apply?

gianmd commented 2 years ago

I was also having this issue when building for an iOS emulator and actual iOS device, but adding this to the app.component.ts worked for me.

import { Component } from '@angular/core';
import { Capacitor } from '@capacitor/core';
import { initializeApp } from 'firebase/app';
import { indexedDBLocalPersistence, initializeAuth } from 'firebase/auth';
import { environment } from 'src/environments/environment';

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent {
  constructor() {
    const app = initializeApp(environment.firebase);
    if (Capacitor.isNativePlatform) {
      initializeAuth(app, {
        persistence: indexedDBLocalPersistence
      });
    }
  }
}

This is where I found the fix and a sample code firebase/firebase-js-sdk#5552 (comment)

Original Issue https://forum.ionicframework.com/t/firebase-auth-in-sdk-9-does-not-work-on-ios-sim-or-devices/215362/9

This did the trick for me, thanks

moblizeit commented 2 years ago

as i am initilaizing the firebase in app.module.ts so curious how does your app.module.ts looks like?

tcns commented 2 years ago

@moblizeit Sorry for late answer. Here app.module.ts. I just deleted all firebase initializers and providers.

@NgModule({
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    FormsModule,
    SwiperModule,
    IonicModule.forRoot(),
    IonicStorageModule.forRoot(),
    ServiceWorkerModule.register('ngsw-worker.js', {
      enabled: environment.production
    })
  ],
  declarations: [AppComponent],
  providers: [InAppBrowser, StatusBar, Broadcaster],
  exports: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

Instead of this I created small service

import {Injectable, OnInit} from '@angular/core';
import {environment} from '../../environments/environment';
import 'firebase/firestore';
import 'firebase/database';
import { initializeApp } from 'firebase/app';
import { initializeAuth, indexedDBLocalPersistence, Auth, browserLocalPersistence } from 'firebase/auth';
import { getDatabase, Database } from '@firebase/database';
import { FirebaseApp } from '@firebase/app';

@Injectable({
  providedIn: 'root'
})
export class FirebasecustomService implements OnInit {
  app: FirebaseApp;
  database: Database;
  auth: Auth;
  constructor() {
    this.app = initializeApp(environment.firebaseConfig);
    this.auth = initializeAuth(this.app, {
      persistence: indexedDBLocalPersistence
    });
    this.database = getDatabase(this.app);
  }

  ngOnInit(): void {

  }
}

And just use vanilla rxfire. Like this.

import {BehaviorSubject, forkJoin, from, Observable, of, pipe, Subject} from 'rxjs';
import {catchError, first, map, mergeMap, switchMap, tap} from 'rxjs/operators';
import {User} from '@firebase/auth';
import {Database, ref, set, remove} from 'firebase/database';
import {objectVal} from 'rxfire/database';

...

  constructor(
    public storage: Storage,
    public firebaseCustom: FirebasecustomService
  ) {
    this.db = firebaseCustom.database;
  }

...

  loadStories(): Observable<Story[]> {
    return objectVal<Story[]>(ref(this.db, '/stories'))
        .pipe(
            mergeMap(val => of(Object.values(val)))
        );
  }

I dont know if its normal code. Because I'm not js dev. Just my pet project. But its working both on sim and real device

eeschiavo commented 2 years ago

I have the same error. Launching angular fire app on real iOS device I get this error:

TypeError: undefined is not an object (evaluating 'gapi.iframes.getContext')

is it possible to solve this and continue using angular fire?

eeschiavo commented 2 years ago

@tcns solution is working. You must use AngularFire v7 (not with compatibility mode) to solve this issue.

mifo111 commented 2 years ago

Yes, but the problem with AngularFire v7 in compatibility mode still exists!

mifo111 commented 2 years ago

some new observations. i can actually run on ios using

ionic capacitor run ios -l --external

but not directly from xcode. so there is something that xcode is doing while running it

ionic capacitor run ios --external (without livereload) also does not work.

SeppeD commented 2 years ago

Been struggling a lot with this issue the last days but I managed to fix it. For those who need help here's my code. Thanks to @tcns for the first solution which I added upon.

You can delete all Firebase related imports from app.module.ts since my solution only uses Firebase. The packages rxfire and @angular/fire can be removed from your package.json. The only dependency I have is "firebase": "^9.6.1". I used observables for the getObject and list functions since that's what I'm used to use and I didn't want to rewrite my original code.

Hope this can help somebody.

import { Injectable } from '@angular/core';
import { Capacitor } from '@capacitor/core';
import { environment } from '@environment';
import { initializeApp } from 'firebase/app';
import { Auth, getAuth, indexedDBLocalPersistence, initializeAuth, signInWithCustomToken } from 'firebase/auth';
import { Database, getDatabase, onValue, orderByChild, query, ref } from 'firebase/database';
import { Observable, Observer, from } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class FirebaseService {
  private readonly database: Database;
  private readonly auth: Auth;

  constructor() {
    const firebaseApp = initializeApp(environment.firebase);

    if (Capacitor.isNativePlatform()) {
      initializeAuth(firebaseApp, {
        persistence: indexedDBLocalPersistence
      });
    }

    this.database = getDatabase(firebaseApp);
    this.auth = getAuth(firebaseApp);
  }

  connectFirebase(firebaseToken) {
    return from(signInWithCustomToken(this.auth, firebaseToken));
  }

  disconnectFirebase() {
    return from(this.auth.signOut());
  }

  getObject<T>(path: string): Observable<T> {
    return new Observable((observer: Observer<T>) => {
      const dbRef = ref(this.database, path);
      const listener = onValue(dbRef, snapshot => {
        const data = snapshot.val();
        observer.next(data);
      });

      return {
        unsubscribe() {
          listener();
        }
      };
    });
  }

  public list<T>(path: string, orderChildBy?: string): Observable<Array<T>> {
    return new Observable<Array<T>>((observer: Observer<Array<T>>) => {
      const dbRef = ref(this.database, path);
      const dbReference = !orderChildBy ? dbRef : query(dbRef, orderByChild(orderChildBy));

      const listener = onValue(dbReference, snapshot => {
        const data = Object.values<T>(snapshot.val() || {});
        console.log(path, data);
        observer.next(data);
      });

      return {
        unsubscribe() {
          listener();
        }
      };
    });
  }
}
tommy-neeld-rft commented 2 years ago

Came across the same issue and found a temporary solution. I was using "@angular/fire": "^7.2.0" and was getting the TypeError: undefined is not an object (evaluating 'gapi.iframes.getContext') when building for IOS using capacitor. By downgrading to "@angular/fire": "^6.1.5" I can get it working by just removing the /compat from the imports. In the end my app.module.ts looks like this:

import { AngularFireModule } from '@angular/fire';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFireDatabaseModule } from '@angular/fire/database';
import { AngularFirestoreModule } from '@angular/fire/firestore';

@NgModule({
  entryComponents: [],
  imports: [
    BrowserModule,
    HammerModule,
    IonicModule.forRoot({ mode: "ios" }),
    AppRoutingModule,
    HttpClientModule,
    ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
    IonicSelectableModule,
    AngularFireModule.initializeApp(environment.firebaseConfig),
    AngularFireAuthModule,
    AngularFireDatabaseModule,
    AngularFirestoreModule
  ],
  declarations: [AppComponent],
  providers: [InAppBrowser, StatusBar, Broadcaster],
  exports: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

This required minimal code changes but not ideal I am using an old version of AngularFire.

davidecampello commented 2 years ago

I'm having the same issue. Any solution instead of using the old version?

DeezCashews commented 2 years ago

Ok, so I got this working finally with the following dependencies:

    "@angular/fire": "^7.2.0",
    "firebase": "^9.6.4",
    "rxfire": "^6.0.3"

After reading this ticket and many others I decided to remove all references to compat but no luck, it still wouldn't connect on iOS. I was going to try vanilla like others described and create a service but didn't like that I'd lose DI.

Instead I did this:

import { provideFirebaseApp, getApp, initializeApp, FirebaseApp } from '@angular/fire/app';
import { provideAuth, initializeAuth } from '@angular/fire/auth';
import { provideFirestore, getFirestore } from '@angular/fire/firestore';

import { indexedDBLocalPersistence } from 'firebase/auth';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideFirestore(() => getFirestore()),
    provideAuth(() => initializeAuth(getApp(), { persistence: indexedDBLocalPersistence })),
    BrowserModule,
    IonicModule.forRoot(),
    AppRoutingModule
  ],
  providers: [
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
    AuthService
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

Notice I imported indexedDBLocalPersistence from 'firebase/auth' instead of @angular/fire/auth. I was getting compile time errors saying indexedDBLocalPersistence wasn't available. Something for the AngularFire team to look at.

Now I can use like so:

import { Component } from '@angular/core';
import { Auth, signInWithEmailAndPassword, UserCredential, User } from '@angular/fire/auth';

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent {
  constructor(private afAuth: Auth) {
    signInWithEmailAndPassword(this.afAuth, email, password);
  }
}

Hope this saves someone the hours I wasted.

ThierryLib commented 2 years ago

I'm experiencing the same problem since I've upgraded to Capacitor 3, Angular 12, Firebase 9, AngularFire 7.2.0 and Ionic 6. It's clear from my logs that it gets stuck while authentifying with Firebase or loading data. I tried to initialize firebase differently as suggested in the previous posts but without success.

However I noticed very different behaviors and it's quite confusing:

Anyone facing the same issue ?

limes commented 2 years ago

Ok, so I got this working finally with the following dependencies:

    "@angular/fire": "^7.2.0",
    "firebase": "^9.6.4",
    "rxfire": "^6.0.3"

After reading this ticket and many others I decided to remove all references to compat but no luck, it still wouldn't connect on iOS. I was going to try vanilla like others described and create a service but didn't like that I'd lose DI.

Instead I did this:

import { provideFirebaseApp, getApp, initializeApp, FirebaseApp } from '@angular/fire/app';
import { provideAuth, initializeAuth } from '@angular/fire/auth';
import { provideFirestore, getFirestore } from '@angular/fire/firestore';

import { indexedDBLocalPersistence } from 'firebase/auth';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideFirestore(() => getFirestore()),
    provideAuth(() => initializeAuth(getApp(), { persistence: indexedDBLocalPersistence })),
    BrowserModule,
    IonicModule.forRoot(),
    AppRoutingModule
  ],
  providers: [
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
    AuthService
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

Notice I imported indexedDBLocalPersistence from 'firebase/auth' instead of @angular/fire/auth. I was getting compile time errors saying indexedDBLocalPersistence wasn't available. Something for the AngularFire team to look at.

Now I can use like so:

import { Component } from '@angular/core';
import { Auth, signInWithEmailAndPassword, UserCredential, User } from '@angular/fire/auth';

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent {
  constructor(private afAuth: Auth) {
    signInWithEmailAndPassword(this.afAuth, email, password);
  }
}

Hope this saves someone the hours I wasted.

Work like a charm 👍 Thank you!

aogorek commented 2 years ago

I'm experiencing the same problem since I've upgraded to Capacitor 3, Angular 12, Firebase 9, AngularFire 7.2.0 and Ionic 6. It's clear from my logs that it gets stuck while authentifying with Firebase or loading data. I tried to initialize firebase differently as suggested in the previous posts but without success.

However I noticed very different behaviors and it's quite confusing:

  • android: OK on any device
  • ionic capacitor run ios -l --external: OK on any device (iPhone or iPad)
  • emulator via XCode on iPad: OK
  • emulator via XCode iPhone: KO
  • app from the store on iPad: OK
  • app from the store on iPhone: KO

Anyone facing the same issue ?

Yes, same issue in my project.

Mobiletainment commented 2 years ago

Oh my! I also ran into this problem on iOS for iPhone devices and simulators.

What made it really hard to identify the cause of the problem is that the error seems to get swallowed. 😱

You don't see the message undefined is not an object (evaluating 'gapi.iframes.getContext) anywhere in the logs. Instead, you have to use Safari's Web Inspector and enable a breakpoint for uncaught exceptions to reveal it: AngularFire undefined is not an object (evaluating 'gapi iframes getContext)

I am using Capacitor 3 and the app is using the compatibility mode in @angular/fire@7 and firebase@9 for the AngularFireDatabase. I observed that the valueChanges() didn't emit anything, leading me to think that it's a network/configuration-related problem rather than a problem in one of the libraries...

I tested the simple workaround of downgrading to @angular/fire@6 and firebase@8 and can confirm that it resolves the issue.

What makes me a bit sad though is that if I had known that there are such unexpected differences with the compat mode, then I would have migrated to the modular approach right away instead of going the lazy way, which in the end consumed more time for the error identification than if I migrated right away 😅

In any case, a thousand thanks for the hints that the problem originates from the compat mode. 🙌

davidecampello commented 2 years ago

unfortunatly using @angular/fire@6 is not always a solution because I'm using a library (@robingenz/capacitor-firebase-authentication) that require firebase 9 to work.

timstoute commented 2 years ago

Is there a solution to this problem that allows the use of AngularFire and doesn't involve downgrading? I've tried @DeezCashews approach but wasn't successful.

mattlin4567 commented 2 years ago

@timstoute I switch to modular way just like @DeezCashews, and it works. Maybe you miss some injection or import.

alistairheath commented 2 years ago

This issue is causing a bit of headache for my app so I thought I'd do some research and post it here. I still don't have a solution but maybe an underlying cause.

As @Mobiletainment points out, there is an error which shows that "gapi.iframes.getContext" is missing from the window object. Following this research I found a StackOverflow answer suggesting that you mock this object and inject it into the window yourself (1). I could not get this to work, but this perhaps could be a viable solution.

I then questioned why I couldn't see the gapi object on iOS, but I could see it when I ran the same app in the browser or on Android. I believe this could come down to CORS. On Android and the browser, the Ionic app is run from http://localhost but when deployed to iOS it is run from capacitor://localhost (2). I had a look at the domains allowed on my firebase project and sure enough I can enable http:// domain but domains on other protocols. It is possible that the compat mode does not mitigate for this (as previous versions did) and therefore Firebase does not enable the creation of the gapi object.

Just an idea, sources below!

1: https://stackoverflow.com/questions/69778975/angular-ionic-mobile-app-ios-does-not-fetch-from-firebase-using-angularfire 2:https://ionicframework.com/docs/troubleshooting/cors

alistairheath commented 2 years ago

Based on my comment above, I believe I have found a workaround. If calls from capacitor://localhost are being rejected by firebase which then prevents the creation of the "gapi" object on the browser window, what if we could use a different protocol instead of "capacitor://".

Fortunately capacitor.config.ts has a feature do exactly this, just set server .iosScheme to "ionic" like so: const config: CapacitorConfig = { ... server: { iosScheme: 'ionic' } };

I tried this and compat worked immediately on iOS! I'm still nervous to push this into production as I unsure what unintended consequences may arise from using the "ionic" protocol, which was used with Cordova, instead of the "capacitor" protocol.

timstoute commented 2 years ago

@alistairheath - amazing, great sleuthing! I confirm this worked in Xcode / Simulator and on local iOS device. Very much appreciated.

markdgold commented 2 years ago

Thank you @alistairheath!! That one line solved my days of debugging

dodomui commented 2 years ago

@alistairheath this is works but after changing iosScheme, analytics will stop function from what I had found out now.

farisfaisalthena commented 2 years ago

Hi. Just wanted to know, is there any fix for this instead of workaround?

tobiaskkd commented 2 years ago

@alistairheath thanks! Keep in mind though that this might affect storage on iOS devices.

alistairheath commented 2 years ago

As far as I know, at the moment there doesn't seem to be a longer term solution @farisfaisalthena. The creation of the GAPI object on the window happens because Firebase doesn't like the API calls coming from the compat functions - I'm guessing that the same isn't true true for the standard functions. I'm fairly new to using GitHub so don't know how to raise this issue to anyone who could develop a fix.

Would you be able to elaborate how this would impact storage @tobiaskkd?

djabif commented 2 years ago

@alistairheath what did you do to solve this? I added const config: CapacitorConfig = { ... server: { iosScheme: 'ionic' } }; but I'm still having the same error TypeError: undefined is not an object (evaluating 'gapi.iframes.getContext'). Is there anything else I have to change? Thanks in advance. 🙏

wmadden commented 2 years ago

Very likely it's related to this: https://github.com/firebase/firebase-js-sdk/blob/4983f4d5a0dc385c5b3e042ace44c8204d3cce81/packages/auth-compat/src/platform.ts#L54

riderx commented 2 years ago

Hey, i made the PR for this : https://github.com/firebase/firebase-js-sdk/pull/6236

REPTILEHAUS commented 2 years ago

Issue is nearly 6 months old! hitting the same brick wall as everyone else albeit im not using firebase for auth, just realtime db.

The PR provided by @riderx might be a fix for most but for me I am using a custom iosScheme and I'm sure others are also so some kind of whitelisting either that or allow it to be configured in app.module.ts as part of the rest of the configuration. Ill downgrade for now

can confirm this works:

npm un @angular/fire firebase npm i @angular/fire@6.1.5 firebase@8.9.0 --save

riderx commented 2 years ago

@REPTILEHAUS i wandering what was the need for custom iodScheme ?

REPTILEHAUS commented 2 years ago

@riderx its for redirection between apps on the same device. Let’s say you have an app that authenticates from one to the other, then you call your app with the scheme. So the scheme should be passable from capacitor/ionic config through to fire base but this scheme check is easier to be removed from firebase maybe

riderx commented 2 years ago

@REPTILEHAUS iosScheme is internal scheme it's here for retro compat for me. In my app I use custom scheme at native level to call app from email, you don't need to alter that. See the doc here : https://capacitorjs.com/docs/guides/deep-links#add-associated-domain

By the way my PR was merge in master today, so the fix will come in production soon !

evallgar commented 2 years ago

I was also having this issue when building for an iOS emulator and actual iOS device, but adding this to the app.component.ts worked for me.

import { Component } from '@angular/core';
import { Capacitor } from '@capacitor/core';
import { initializeApp } from 'firebase/app';
import { indexedDBLocalPersistence, initializeAuth } from 'firebase/auth';
import { environment } from 'src/environments/environment';

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent {
  constructor() {
    const app = initializeApp(environment.firebase);
    if (Capacitor.isNativePlatform) {
      initializeAuth(app, {
        persistence: indexedDBLocalPersistence
      });
    }
  }
}

This is where I found the fix and a sample code firebase/firebase-js-sdk#5552 (comment)

Original Issue https://forum.ionicframework.com/t/firebase-auth-in-sdk-9-does-not-work-on-ios-sim-or-devices/215362/9

This worked for me. Didn't have to change a bit out of my existing code but to add this to the app.component.ts file. I'm using modular version (not the compat one). Using Mac OS with Apple Silicon M1

My dependencies:

"dependencies": {
    "@angular/common": "~13.2.2",
    "@angular/core": "~13.2.2",
    "@angular/fire": "^7.3.0",
    "@angular/forms": "~13.2.2",
    "@angular/platform-browser": "~13.2.2",
    "@angular/platform-browser-dynamic": "~13.2.2",
    "@angular/router": "~13.2.2",
    "@capacitor-community/background-geolocation": "^1.2.1",
    "@capacitor-community/barcode-scanner": "^2.1.1",
    "@capacitor/android": "3.5.1",
    "@capacitor/app": "1.1.1",
    "@capacitor/core": "3.5.1",
    "@capacitor/device": "^1.1.2",
    "@capacitor/geolocation": "^1.3.1",
    "@capacitor/haptics": "1.1.4",
    "@capacitor/ios": "3.5.1",
    "@capacitor/keyboard": "1.2.2",
    "@capacitor/status-bar": "1.0.8",
    "@ionic/angular": "^6.0.0",
    "@ionic/storage-angular": "^3.0.6",
    "date-fns": "^2.28.0",
    "firebase": "^9.8.1",
    "firebase-tools": "^10.9.2",
    "rxjs": "~6.6.0",
    "tslib": "^2.2.0",
    "zone.js": "~0.11.4"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~13.2.3",
    "@angular-eslint/builder": "~13.0.1",
    "@angular-eslint/eslint-plugin": "~13.0.1",
    "@angular-eslint/eslint-plugin-template": "~13.0.1",
    "@angular-eslint/template-parser": "~13.0.1",
    "@angular/cli": "~13.2.3",
    "@angular/compiler": "~13.2.2",
    "@angular/compiler-cli": "~13.2.2",
    "@angular/language-service": "~13.2.2",
    "@capacitor/cli": "3.5.1",
    "@ionic/angular-toolkit": "^6.0.0",
    "@types/jasmine": "~3.6.0",
    "@types/jasminewd2": "~2.0.3",
    "@types/node": "^12.11.1",
    "@typescript-eslint/eslint-plugin": "5.3.0",
    "@typescript-eslint/parser": "5.3.0",
    "eslint": "^7.6.0",
    "eslint-plugin-import": "2.22.1",
    "eslint-plugin-jsdoc": "30.7.6",
    "eslint-plugin-prefer-arrow": "1.2.2",
    "jasmine-core": "~3.8.0",
    "jasmine-spec-reporter": "~5.0.0",
    "karma": "~6.3.2",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.0.3",
    "karma-coverage-istanbul-reporter": "~3.0.2",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "^1.5.0",
    "protractor": "~7.0.0",
    "ts-node": "~8.3.0",
    "typescript": "~4.4.4"
  },

Ionic info:

Ionic CLI                     : 6.19.1 
   Ionic Framework               : @ionic/angular 6.1.6
   @angular-devkit/build-angular : 13.2.6
   @angular-devkit/schematics    : 13.2.6
   @angular/cli                  : 13.2.6
   @ionic/angular-toolkit        : 6.1.0

Capacitor:

   Capacitor CLI      : 3.5.1
   @capacitor/android : 3.5.1
   @capacitor/core    : 3.5.1
   @capacitor/ios     : 3.5.1

Utility:

   cordova-res : 0.15.4
   native-run  : 1.6.0

System:

   NodeJS : v16.14.0
   npm    : 8.3.1
   OS     : macOS Monterey
dodomui commented 2 years ago

firebase/firebase-js-sdk#5552 (comment)

Firebase 9.8.2 had fixed the issue. But AngularFire/Analytics still not working for iOS. Does anyone having solution?

Currently I'm using native plugin (Capacitor-community/firebase-analytics) for the Firebase Analytics

riderx commented 2 years ago

@dodomui did you are sure to have update your firebase version, check in your lockfile :) otherwise did you check this : https://forum.ionicframework.com/t/firebase-auth-in-sdk-9-does-not-work-on-ios-sim-or-devices/215362/9 You have to configure the auth module specificly for Capacitor, i'm not sure how to translate it in angularfire, but you could find something here : https://github.com/angular/angularfire/blob/master/docs/auth/getting-started.md

drkhannah commented 1 year ago

i still get this, none of the above has worked for me

vishal-revdiwala commented 1 year ago

I'm facing exactly same issue in my ionic cordova Angular based project. And workaround for Cordova? As I see workaround is there for capacitor.

dodomui commented 1 year ago

@riderx sorry just saw your message. I'm using compat SDK and everything is working fine since my last post May 29 2022. After a year plus, I'd changed to modular implementation and boom, angularfire not working on iOS devices anymore.

YaroslavG commented 1 year ago

I'm facing exactly same issue in my ionic cordova Angular based project. And workaround for Cordova? As I see workaround is there for capacitor.

I have the same problem, did you find a solution ?

rcpilotp51 commented 10 months ago

is there a solution for this?

TypeError: undefined is not an object (evaluating 'gapi.iframes.getContext')

Error Screenshot

rcpilotp51 commented 10 months ago

@wmadden any insight or fixes

greg-md commented 9 months ago

Seems like old answers related to local data are still working. So in the v9 I could make it work by changing persistance to Auth and localCache to Firestore to LOCAL:

provideFirebaseApp(() => {
  const app = initializeApp(environment.firebase);
  if (Capacitor.isNativePlatform()) {
    initializeFirestore(app, {
      localCache: persistentLocalCache(),
    });
    initializeAuth(app, {
      persistence: indexedDBLocalPersistence
    });
  }
  return app;
}),