离子iOS承诺永远不会解决

时间:2017-06-11 09:50:34

标签: angular ionic-framework promise ionic3 zonejs

我正在使用Firbase在我的Ionic 3应用中实施Google登录。我已成功使用native Google Plus Cordova plugin,然后使用Angular Fire 2使用凭据登录Firebase。这是我的代码:

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

但结果是一样的。有关信息,登录在浏览器中正常工作。

1 个答案:

答案 0 :(得分:1)

问题来自访问res.user,仅在使用弹出窗口登录时才存在。使用凭据登录时返回的对象在其根目录中包含uidemail和其他用户属性。无论您是在移动环境还是降压环境中,都需要以不同方式创建用户。在移动设备上,访问res.user.uid和浏览器访问res.uid

恕我直言,这是Angular Fire方面的误导性接口规范。

此外,代码很难阅读。承诺链不是一个好习惯。如果可能,直接使用Observables,如果不可能,使用RxJS fromPromise运算符将promises转换为Observables。然后,您可以将flatMap结果链接到异步调用并获得干净的代码。 Observables的一个优点是subscribe函数的错误回调将捕获链中发生的任何错误,而使用promises则需要手动捕获和拒绝。

通过一些重构,您可以获得以下(有效):

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