CapacitorGoogleAuth
CapacitorGoogleAuth copied to clipboard
iOS M1 Mac/Tablets Fails to Initialize
I am getting this error when trigger GoogleAuth.signOut()
CodetrixStudioCapacitorGoogleAuth/Plugin.swift:121: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
@objc
func signOut(_ call: CAPPluginCall) {
DispatchQueue.main.async {
self.googleSignIn.signOut();
}
call.resolve();
}
- capacitor version
6.0.0
- plugin version
3.4.0 rc.4
Has there been any update regarding this issue? @fullstackduck
I believe this error prevents M1 and M2 processors to run this plugin.
I also get this error running Angular 18, Ionic 8 and Capacitor 6. The Google Auth worked great until I upgraded Angular and Ionic. Now I get the error:
CodetrixStudioCapacitorGoogleAuth/Plugin.swift:74: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
Any updates on this?
Some tablets have this issue, too because run on M1 processors.
Hey, is this issue resolved? Or any idea for that? My app is crashing randomly during signOut process. Looks like is crashing if user was login by e-mail. IF user login by plugin it works fine.
Or maybe have you another ways to allow login on multiple account?
For now i use this.authClient.signOut()
form authClient: AngularFireAuth = inject(AngularFireAuth)
and logout works fine but user can't login on another account. Looks like sth was cached.
Angular 17 Capacitor 6 Codetrilx 3.4.0-rc.4
Got the same error on line 74, CodetrixStudioCapacitorGoogleAuth/Plugin.swift:74: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
Solved calling GoogleAuth.initialize();
Previous versions, it was called only when in web. Now, I call when in iOS too.
Yes, thats true, in new version you have to call initialize() on mobile as well. But about signOut(). it works for you?
I finally found the issue to the "found nil" error.. I had to update the Cocoa Pod on iOS. In the Podfile make sure you're at AppAuth 1.7.5 and GoogleSignIn 6.2.4 and Firebase 10.28.1 Once I did that it seemed to start working.
I had a similar issue with the sign out. I found that the GoogleAuth.signOut() wasn't enough, it still seemed to cache the user and kept automatically signing back it. My fix was to do both: GoogleAuth.signOut() and singOut(auth) from firebase then also set my local user Subjects all to null (using rxjs).
Hope that helps
I used both but GoogleAuth.signOut()
crashing and close app on mobile device. maybe race condition (???). could you share snippet of your code?
Hey, here is what I used for my authentication service: The service allows for Email, Apple or Google authentication, then creates or loads a profile for the user.
import {
Auth,
GoogleAuthProvider,
signInWithPopup,
createUserWithEmailAndPassword,
sendPasswordResetEmail,
signInWithEmailAndPassword,
signOut,
OAuthProvider,
UserCredential,import { Injectable } from '@angular/core';
import {
Auth,
GoogleAuthProvider,
signInWithPopup,
createUserWithEmailAndPassword,
sendPasswordResetEmail,
signInWithEmailAndPassword,
signOut,
OAuthProvider,
UserCredential,
User,
signInWithCredential
} from '@angular/fire/auth';
import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth';
import { PhpFoxService } from './phpFox.service';
import { SignInWithApple, SignInWithAppleOptions, SignInWithAppleResponse } from '@capacitor-community/apple-sign-in'
import { ProfileService } from './profile.service';
import { SongBookService } from './songbook.service';
import { Preferences } from '@capacitor/preferences';
import { Capacitor } from '@capacitor/core';
import { isPlatform } from '@ionic/angular';
import { Subject, Subscription } from 'rxjs';
import { Profile } from '../../app/models/profile.model';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private email: string = '';
private password: string = '';
private fullname: string = '';
private stagename: string = '';
private user: User | null = null;
public signedInUser = new Subject<User>();
public userProfile = new Subject<Profile>();
private phpAccessToken: string = '';
private subProfile: Subscription | null = null;
constructor(
private auth: Auth,
private profileService: ProfileService,
private songBookService: SongBookService,
private phpFoxService: PhpFoxService
) {
this.auth.onAuthStateChanged(user => {
if (user === null) {
this.user = null;
this.email = '';
this.password = '';
this.fullname = '';
this.stagename = '';
} else if (user != null) {
this.user = user;
this.email = user.email;
this.fullname = user.displayName;
this.signedInUser.next(user);
if (user.providerData[0].providerId === 'google.com') {
this.password = 'Google101!';
this.setLoginLocal(user.email, this.password);
} else if (user.providerData[0].providerId === 'apple.com') {
this.password = 'Apple101!';
this.setLoginLocal(user.email, this.password);
}
}
});
GoogleAuth.initialize({});
}
public getUser() {
return this.user;
}
public async getEmail() {
if (!this.email) {
await this.getLoginLocal().catch(err => {
console.log('No email & password found');
});
}
return this.email;
}
public getPassword() {
return this.password;
}
public getFullname() {
return this.fullname;
}
public getStagename() {
return this.stagename;
}
async register(email, password, fullname, stagename, avatarURL, foxId, provider) {
this.email = email;
this.password = password;
this.fullname = fullname;
this.stagename = stagename;
if(provider === 'email') {
const user = await createUserWithEmailAndPassword(
this.auth,
email,
password
).catch(error => {
console.log('Register User Error = ' + error);
console.log('Register User Error USER = ' + user);
return null;
});
}
this.checkForProfile(email, fullname, stagename, avatarURL, foxId);
this.setLoginLocal(email, password);
}
async login ({ email, password }) {
this.email = email;
this.password = password;
const user = await signInWithEmailAndPassword(
this.auth,
email,
password
);
this.setLoginLocal(email, password);
return user;
}
loginWithGoogle() {
if (!isPlatform('capacitor')) {
this.signInWithGoogleWeb();
} else {
this.signInWithGoogleCapacitor();
}
}
async signInWithGoogleCapacitor() {
let googleUser = await GoogleAuth.signIn();
const credential = GoogleAuthProvider.credential(googleUser.authentication.idToken);
await signInWithCredential(this.auth, credential).then(result => {
this.user = result.user;
}).catch(error => {
console.log('Google Error = ', error);
});
}
async signInWithGoogleWeb() {
const provider = new GoogleAuthProvider();
await signInWithPopup(this.auth, provider).then(result => {
// The signed-in user info.
this.user = result.user;
// This gives you a Google Access Token.
}).catch(error => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
// The email of the user's account used.
const email = error.customData.email;
// The AuthCredential type that was used.
const credential = GoogleAuthProvider.credentialFromError(error);
});
}
async signOutWithGoogle() {
GoogleAuth.signOut();
}
loginWithApple() {
if (Capacitor.getPlatform() === 'web') {
this.signInWithAppleWeb();
} else {
this.signInWithAppleNative();
}
}
signInWithAppleWeb() {
const provider = new OAuthProvider('apple.com');
signInWithPopup(this.auth, provider).then((result: UserCredential) => {
});
}
signInWithAppleNative() {
let options: SignInWithAppleOptions = {
clientId: 'com.reackageinteractive.tagg',
redirectURI: 'https://tagg-9ee2b.firebaseapp.com/__/auth/handler',
scopes: 'email',
state: '12345'
};
SignInWithApple.authorize(options).then(async (result: SignInWithAppleResponse) => {
const provider = new OAuthProvider('apple.com');
const credential = provider.credential({
idToken: result.response.identityToken,
});
const UserCredential = await signInWithCredential(
this.auth,
credential
);
});
}
async logout(): Promise<void> {
await this.signOutWithGoogle();
return signOut(this.auth).then(async () => {
await this.clearLocalData();
}).catch(error => {
console.log('Auth Service: Logout Error = ', error);
});
}
async clearLocalData()
{
await Preferences.clear();
await this.songBookService.deleteSongBookFile();
this.signedInUser.next(null);
this.userProfile.next(null);
this.user = null;
this.email = '';
this.password = '';
this.fullname = '';
this.stagename = '';
this.profileService.clearProfile();
if(this.subProfile != null) {
this.subProfile.unsubscribe();
}
}
async setLoginLocal(email, password) {
await Preferences.set({
key: 'login',
value: JSON.stringify({
email: email,
password: password
})
});
}
async getLoginLocal() {
const ret = await Preferences.get({ key: 'login' });
const localData = JSON.parse(ret.value);
this.email = localData.email;
this.password = localData.password;
}
async forgotPassword(email: string) {
const res = await sendPasswordResetEmail(this.auth, email);
}
public checkForProfile(email: string, fullname: string, stagename: string, avatarURL: string, foxId: string) {
let username = email.replace(/[&\/\\#,+()!@^$~%.'":*?<>{}]/g,'_');
this.profileService.getUserProfile().subscribe(data => {
if (data === undefined) {
this.profileService.createProfile(email, fullname, foxId, '', stagename, username, avatarURL, '', '', '');
} else {
this.profileService.userProfile = data;
}
});
}
doesProfileExist() {
if (this.auth.currentUser != null) {
this.subProfile = this.profileService.getUserProfile().subscribe(data => {
this.userProfile.next(data);
});
}
}
async loginToFeed() {
let username: string = await this.getEmail();
let password: string = this.getPassword();
if(this.phpAccessToken !== undefined && this.phpAccessToken !== null && this.phpAccessToken !== '') {
return;
}
this.phpFoxService.login(username, password).then(response => {
this.phpAccessToken = response.data.access_token;
if (response.data.error) {
if(response.data.error == 'invalid_grant') {
console.log('User not found in Social Platform');
console.log('Check user list to see if this person exists.. if not, then create them');
this.registerUserToPhpFox();
} else {
console.log('User not found in Social Platform');
console.log('ERROR = ' + response.data.error_description);
}
} else {
console.log('User is logged into Social Platform');
}
}).catch(error => {
console.log('Login to Feed returned error: ', error);
});
}
async registerUserToPhpFox() {
let fullname: string = this.user.displayName;
let username: string = fullname.trim().replace(' ', '');
let email: string = await this.getEmail();
let password: string = this.getPassword();
this.phpFoxService.registerUser(fullname, username, email, password);
}
}
Unfortunately, none of the solutions above worked for me. I am using vue? How can we clear the cache for this plugin via vue?
I have just found the following solution:
await GoogleAuth.initialize({}); await GoogleAuth.signIn();
await GoogleAuth.initialize({}); await GoogleAuth.signOut();
I need to call these two always together.
Spent hours dealing with "CodetrixStudioCapacitorGoogleAuth/Plugin.swift:74: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value". Nothing worked from this topic tips.
The solution was to add iosClientId to GoogleAuth block in capacitor.config.ts file with value from Google OAuth iOS client id.
Great catch @ivarsmednis ! I forgot that I had done that as well..