2017-06-11 17 views
0

Firbaseを使用してIonic 3アプリでGoogle Sign-inを実装しています。私は正常にnative Google Plus Cordova pluginを使用して、Angular Fire 2を使用してFirebaseに資格情報でログインできました。ここに私のコードは次のとおりです。Ionicの約束が決して解決しない

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); 
     }); 
    }); 
} 

そして、私のログインページで、それへの呼び出し:

this.auth.loginWithGoogle() 
    .then(res => { 
    console.log('success login !!!!!'); 
    }) 
    .catch(err => { 
    console.log('error login !!!!!'); 
    }); 

しかし、私はXcodeのでのiOSにデプロイするとき、私はコンソール出力を見ることができます:

2017-06-11 11:32:01.384130 MyApp[2634:842028] login promise done: {"uid":"...","displayName":"...","photoURL":"..."...} 

約束は決して解決しません!私はZoneJSを手動で使用しようとしましたが失敗しました:

private zone; 

public loginWithGoogle(): Promise<any> { 

    this.zone = new NgZone({}); 

    ... 

     this.zone.run(() => { 
      resolve(user); 
     }); 
    }); 
    }); 
} 

結果は同じです。詳細については、ブラウザでログインが正常に動作します。

+0

私の悪いです!十分な注意を払わなかった。私は自分の答えを取り除いた。私の提案は、 'loginWithGoogle()'を2つの関数に分割することです。一方はモバイルでのログインを処理し、もう1つはブラウザのログイン(apartneの分離)を処理します。次に、2つのうちのどちらかを呼び出す前にプラットフォームチェックを行います。これによりコードのデバッグが容易になり、コードを読んでいる人にとっても読みやすいようになります。 – robbannn

+1

ご協力ありがとうございます!私はオブザーバブルでコードを書き直しました。そして私も問題を見つけました!認証情報を持つFirebaseの署名は、ポップアップでサインインするのと同じオブジェクトインターフェイスを返しません...問題は、ポップアップでサインインするときに存在するres.userにアクセスしていたのですが、クレデンシャルでサインインするときに存在しませんでした。後者の場合、プロパティ 'uid'、' email'、 'displayName'はオブジェクトのルートに直接あります:' res.uid'、 'res.email' ...これは開発者の視点からはかなり誤解を招く。 – user5365075

答えて

1

res.userにアクセスすると問題が発生します。この問題は、ポップアップでサインインする場合にのみ発生します。資格情報でサインインするときに返されるオブジェクトには、uid,emailなどのユーザープロパティがルートに含まれます。あなたは、モバイル環境かベア環境かにかかわらず、ユーザーを別々に作成する必要があります。モバイルの場合は、res.user.uidにアクセスし、ブラウザアクセスの場合はres.uidにアクセスしてください。

IMHOこれは、Angle Fire側の誤ったインターフェイス仕様です。

また、コードは読みにくいです。約束チェーンは良い習慣ではありません。可能な場合はObservablesを直接使用し、可能でない場合はRxJS fromPromiseオペレータを使用してObservablesへの約束を変換してください。結果をflatMapして、非同期呼び出しを連鎖させ、きれいなコードを得ることができます。 Observablesのメリットの1つは、subscribe関数のエラーコールバックがチェーン中に発生したエラーをキャッチし、手動でキャッチして拒否する必要があるという約束があることです。リファクタリングのビットで

、あなたは(働く)以下の取得:

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; 
    }); 
} 
関連する問題