Wdrażam logowanie Google w mojej aplikacji Ionic 3 za pomocą Firbase. Z powodzeniem mogłem korzystać z natywna wtyczka Google Plus Cordova, a następnie zaloguj się przy użyciu poświadczeń do Firebase przy użyciu Angular Fire 2. Oto mój kod:
public loginWithGoogle(): Promise<any> {
return new Promise((resolve, reject) => {
let loginPromise: Promise<any>;
if (this.isMobile()) {
loginPromise = new Promise((resolve, reject) => {
this.googleplus.login({
"webClientId": "--------.apps.googleusercontent.com",
"offline": true
})
.then(res => {
this.afAUth.auth.signInWithCredential(firebase.auth.GoogleAuthProvider.credential(res.idToken))
.then(firebaseRes => {
resolve(firebaseRes);
})
.catch(err => {
reject(err);
});
})
.catch(err => {
reject(err);
});
});
} else {
loginPromise = this.afAUth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider()) as Promise<any>;
}
loginPromise
.then(res => {
console.log("login promise done: " + JSON.stringify(res));
const user: User = {
uid: res.user.uid,
email: res.user.email,
displayName: res.user.displayName
};
resolve(user);
});
});
}
I wezwanie do tego na mojej stronie logowania:
this.auth.loginWithGoogle()
.then(res => {
console.log("success login !!!!!");
})
.catch(err => {
console.log("error login !!!!!");
});
Jednak po wdrożeniu do systemu iOS za pomocą Xcode widzę dane wyjściowe konsoli:
2017-06-11 11:32:01.384130 MyApp[2634:842028] login promise done: {"uid":"...","displayName":"...","photoURL":"..."...}
Obietnica nigdy nie rozwiązuje się! Próbowałem używać ZoneJS ręcznie, ale bezskutecznie:
private zone;
public loginWithGoogle(): Promise<any> {
this.zone = new NgZone({});
...
this.zone.run(() => {
resolve(user);
});
});
});
}
Ale wynik jest taki sam. Aby uzyskać informacje, logowanie działa poprawnie w przeglądarce.
Odpowiedzi:
1 dla odpowiedzi № 1Problem pochodzi z dostępu res.user
, który istnieje tylko podczas logowania za pomocą wyskakującego okienka. Obiekt zwrócony podczas logowania przy użyciu poświadczeń zawiera uid
, email
i inne właściwości użytkownika w jego katalogu głównym. Musisz utworzyć użytkownika w różny sposób, niezależnie od tego, czy jesteś w środowisku mobilnym czy altanowym. Na telefonie komórkowym dostęp res.user.uid
i dostęp do przeglądarki res.uid
.
IMHO jest to wprowadzająca w błąd specyfikacja interfejsu po stronie Angular Fire.
Ponadto kod jest trudny do odczytania. Łańcuchy obietnic nie są dobrą praktyką. Jeśli to możliwe, używaj Observables bezpośrednio, a gdy nie jest to możliwe, zamień obietnice na Observables przy użyciu RxJS fromPromise operator. Następnie możesz płasko mapować wyniki, aby łączyć asynchroniczne wywołania i uzyskać czysty kod. Jedną z zalet Observables jest to, że wywołanie zwrotne błędu subscribe
funkcja wyłapie każdy błąd, który wystąpił podczas łańcucha, a przy obietnicach musisz złapać i odrzucić ręcznie.
Przy odrobinie refaktoryzacji otrzymasz następujące (które działa):
private signInWithGooglePlus(): Observable<any> {
return Observable.fromPromise(
...
);
}
private signInFirebaseWithCredentials(idToken: string): Observable<User> {
return Observable.fromPromise(
...
).map(credentials => ({
uid: credentials.uid,
...
}));
}
private signInWithGooglePopup(): Observable<User> {
return Observable.fromPromise(
...
).map(firebaseRes => ({
uid: firebaseRes.user.uid,
...
}));
}
public loginWithGoogle(): Observable<any> {
let loginPromise: Observable<User>;
if (this.isMobile()) {
loginPromise = this.signInWithGooglePlus().flatMap(res => this.signInFirebaseWithCredentials(res.idToken));
} else {
loginPromise = this.signInWithGooglePopup();
}
let user: User;
return loginPromise
.flatMap(userTmp => {
user = userTmp;
return this.getJWTToken(userTmp.uid);
})
.map(token => {
this.storeData(token, user);
return user;
});
}