App does not work in Android - please help

I am using Ionic 2 building on Mac.

Your system information:

Cordova CLI: 6.4.0 
Ionic Framework Version: 2.0.0-rc.4
Ionic CLI Version: 2.1.18
Ionic App Lib Version: 2.1.9
Ionic App Scripts Version: 1.0.0
ios-deploy version: Not installed
ios-sim version: Not installed
OS: macOS Sierra
Node Version: v6.9.4
Xcode version: Xcode 8.2.1 Build version 8C1002

I have an app I have been developing. When I build the app via Xcode for iOS, everything works fine.

But when I try build it for Android, it generates the android-debug.apk file, but if I try run this on an emulator (Android Studio) or my Android phone, it seems to load but then freeze.

I have 3 pages. It loads the initial page, I can navigate to the second page, but as soon as I try navigate to the third page, the navigation freezes. This only occurs in Android.

As a result I think there may be a problem with my third page that is causing the navigation to break.

If anyone has any suggestions, or can suggest how I can debug this, I would appreciate your help.

This is the third page (the initial alert in the constructor doesnā€™t get invoked):

login.ts

import { Component, Inject, forwardRef } from '@angular/core';
import { NavController, AlertController, Platform, Loading, LoadingController } from 'ionic-angular';
import { FirebaseAuth, AuthProviders, FirebaseAuthState } from 'angularfire2';
import { JobModel } from '../model/jobModel';
import { PersonModel } from '../model/personModel';
import { UtilityService } from '../utils/utilityService';
import { PersonService } from '../service/personService';
import { LoginEmailPage } from '../loginemail/loginemail';
import { PersonPage } from '../person/person';
import { PersonUserService } from '../person/personUserService';

@Component({
  templateUrl: 'login.html'
})
export class LoginPage {
  public jobModel: JobModel;
  public personModel: PersonModel;
  public fireAuth: firebase.auth.Auth;
  public utilityService: UtilityService = null;
  public loading: Loading = null;
  public authState: FirebaseAuthState = null;

  constructor( @Inject(forwardRef(() => UtilityService)) utilityService, public nav: NavController, public auth: FirebaseAuth, public alertCtrl: AlertController, public personService: PersonService, public platform: Platform, public loadingCtrl: LoadingController, public personUserService: PersonUserService) {
    alert('login.ts constructor');
    this.fireAuth = firebase.auth();
    this.utilityService = utilityService;
    this.utilityService.logout(this.auth, this.fireAuth);
    this.auth.subscribe((authState: FirebaseAuthState) => {
      this.authState = authState;
    });
  }

  setUpUser(firebaseAuthState: FirebaseAuthState, provider_id: number): Promise<PersonModel> {
    return new Promise<PersonModel>((resolve) => {
      let provider: AuthProviders = firebaseAuthState.provider;
      if (!provider) {
        provider = provider_id;
      }
      this.personService.getPersonByUidAndProvider(window.localStorage.getItem('uid'), provider).then((personModel: PersonModel) => {
        if (personModel && personModel.id) {
          this.personModel = personModel;
          this.personModel.provider = provider;
          if (!this.personModel || !this.personModel.uid) {
            this.fireAuth.onAuthStateChanged((user: firebase.User) => {
              if (user) {
                this.newPerson(user, firebaseAuthState, provider_id).then((data: PersonModel) => {
                  this.personModel = data;
                  resolve(this.personModel);
                });
              }
            });
          } else {
            this.personModel.avatarFirebase = window.localStorage.getItem('photoURL');
            this.personModel.lastAccessDate = new Date().getTime();
            let user: firebase.User = this.fireAuth.currentUser;
            if (!user) {
              let loginPromise: Promise<PersonModel> = this.utilityService.login(this.personModel, this.authState.auth, this.nav, this.auth, this.fireAuth, false);
              if (loginPromise) {
                loginPromise.then((person: PersonModel) => {
                  resolve(person);
                });
              } else {
                resolve(null);
              }
            } else {
              let loginPromise: Promise<PersonModel> = this.utilityService.login(this.personModel, user, this.nav, this.auth, this.fireAuth, false);
              if (loginPromise) {
                loginPromise.then((person: PersonModel) => {
                  resolve(person);
                });
              } else {
                resolve(null);
              }
            }
          }
        } else {
          let user: firebase.User = this.fireAuth.currentUser;
          if (this.authState && this.authState.auth) {
            this.newPerson(this.authState.auth, firebaseAuthState, provider_id).then((personData: PersonModel) => {
              this.personModel = personData;
              resolve(this.personModel);
            });
          } else if (user) {
            this.newPerson(user, firebaseAuthState, provider_id).then((personData: PersonModel) => {
              this.personModel = personData;
              resolve(this.personModel);
            });
          } else {
            this.doAlert('Logging into Firebase unsuccessful');
            console.info('Logging into Firebase unsuccessful', this.authState, user);
          }
        }
      }, (error) => {
        console.error('Error getting personModel for uid: ' + window.localStorage.getItem('uid'), error);
      });
    });
  }

  newPerson(user: firebase.User, firebaseAuthState: FirebaseAuthState, provider_id: number): Promise<PersonModel> {
    return new Promise<PersonModel>(resolve => {
      this.personModel = new PersonModel();
      if (user && user.email) {
        this.personModel.emailAddress = user.email;
      } else if (firebaseAuthState && firebaseAuthState.auth && firebaseAuthState.auth.email) {
        this.personModel.emailAddress = firebaseAuthState.auth.email;
      } else if (this.fireAuth && this.fireAuth.currentUser && this.fireAuth.currentUser.email) {
        this.personModel.emailAddress = this.fireAuth.currentUser.email;
      } else {
        console.error('Firebase current user is null, so cannot get email address and cannot save user to RESTful Service.', this.fireAuth);
      }
      this.personModel.uid = window.localStorage.getItem('uid');
      this.personModel.displayName = window.localStorage.getItem('displayName');
      this.personModel.avatarFirebase = window.localStorage.getItem('photoURL');
      this.personModel.provider = firebaseAuthState.provider;
      this.personModel.lastAccessDate = new Date().getTime();
      if (!this.personModel.provider) {
        this.personModel.provider = provider_id;
      }
      if (this.personModel.emailAddress) {
        this.utilityService.getPersonLocations(this.personModel).then((person: PersonModel) => {
          return this.savePerson(person, user).then((person: PersonModel) => {
            resolve(person);
          });
        }).catch((error) => {
          console.info('Saving person, but location not found');
          return this.savePerson(this.personModel, user).then((person: PersonModel) => {
            resolve(person);
          });
        });
      }
    });
  }

  savePerson(personModel: PersonModel, user: firebase.User): Promise<PersonModel> {
    return new Promise<PersonModel>(resolve => {
      this.personModel = personModel;
      this.personService.savePerson(this.personModel).then((personModel: PersonModel) => {
        this.utilityService.login(personModel, user, this.nav, this.auth, this.fireAuth, true).then((person: PersonModel) => {
          resolve(person);
        });
      });
    });
  }

  signIn(firebaseAuthState: FirebaseAuthState, provider_id: number) {
    let emailVerified: boolean = false;
    let user: firebase.User = this.fireAuth.currentUser;
    if (user) {
      if (user.emailVerified) {
        emailVerified = true;
      }
    } else {
      if (firebaseAuthState.auth && firebaseAuthState.auth.emailVerified) {
        emailVerified = true;
      }
    }
    if (firebaseAuthState && firebaseAuthState.uid) {
      this.setUpUser(firebaseAuthState, provider_id).then((personModel: PersonModel) => {
        if (personModel && emailVerified) {
          this.nav.setRoot(PersonPage, {
            personModel: personModel,
            fromLogin: true
          }).then(() => {
            this.loading.dismiss();
          });
        }
      });
    }
    window.setTimeout(() => {
      this.loading.dismiss();
    }, 6000);
  }

  // sanityCheck(firebaseAuthState: FirebaseAuthState): void {
  //   if (firebaseAuthState && firebaseAuthState.auth && !firebaseAuthState.auth.emailVerified) {
  //     this.personService.getPersonByUid(firebaseAuthState.uid).then((personModel: any) => {
  //       if (!personModel) {
  //         console.error('RDS PersonModel does not exist for Firebase User ', personModel, firebaseAuthState);
  //         firebaseAuthState.auth.delete().then(() => {
  //           console.info('Firebase User deleted', firebaseAuthState);
  //         });
  //       } else if (personModel.ok === false) {
  //         console.error('RDS PersonModel does not exist for Firebase User ', personModel, firebaseAuthState);
  //         firebaseAuthState.auth.delete().then(() => {
  //           console.info('Firebase User deleted', firebaseAuthState);
  //         });
  //       }
  //     }).catch((error) => {
  //       console.error('RDS PersonModel does not exist for Firebase User ', firebaseAuthState);
  //       firebaseAuthState.auth.delete().then(() => {
  //         console.info('Firebase User deleted', firebaseAuthState);
  //       });
  //     });
  //   }
  // }

  loginGoogle(): void {
    this.loading = this.loadingCtrl.create({
      content: 'Please wait...'
    });
    this.loading.present();
    this.personUserService.init(this.nav, this.personModel, null, this.loading);
    if (this.platform.is('cordova')) {
      this.platform.ready().then(() => {
        this.personUserService.loginGoogleCordova().then((data: FirebaseAuthState) => {
          this.signIn(data, AuthProviders.Google);
        });
      });
    } else {
      this.personUserService.loginGoogleBrowser().then((data: FirebaseAuthState) => {
        this.signIn(data, AuthProviders.Google);
      });
    }
  }

  loginFacebook(): void {
    alert('login.ts loginFacebook');
    this.loading = this.loadingCtrl.create({
      content: 'Please wait...'
    });
//    this.loading.present();
    this.personUserService.init(this.nav, this.personModel, null, this.loading);
    alert('login.ts loginFacebook just initialised personUserService');
    if (this.platform.is('cordova')) {
    alert('login.ts loginFacebook cordova');
      this.platform.ready().then(() => {
    alert('login.ts loginFacebook ready');
        this.personUserService.loginFacebookCordova().then((data: FirebaseAuthState) => {
    alert('login.ts loginFacebook loginFacebookCordova done');
          this.signIn(data, AuthProviders.Facebook);
        });
      });
    } else {
    alert('login.ts loginFacebook not cordova');
      this.personUserService.loginFacebookBrowser().then((data: FirebaseAuthState) => {
    alert('login.ts loginFacebook loginFacebookBrowser done');
        this.signIn(data, AuthProviders.Facebook);
      });
    }
  }

  loginEmail() {
    this.nav.push(LoginEmailPage);
  }

  doAlert(msg: string) {
    let alert = this.alertCtrl.create({
      title: 'Login',
      subTitle: msg,
      buttons: ['Dismiss']
    });
    alert.present();
  }

}

Found what is causing it to crash, but I donā€™t know why.

In the constructor:

alert('personUserService.ts constructor');
alert('personUserService.ts constructor firebase = '+firebase);
    this.fireAuth = firebase.auth();
alert('personUserService.ts constructor this.fireAuth = '+this.fireAuth);
    this.auth.subscribe((authState: FirebaseAuthState) => {
        this.authState = authState;
    });

The first alert gets invoked, and then it freezes. This means that the firebase object is causing it to freeze.

This works in iOS, so not sure why it does not in Android.

firebase is a namespace referencing firebase.d.ts in the node_modules/firebase/server-auth-node/ folder.

Maybe itā€™s a ā€œspeedā€ problem. Like your iOS debugger is faster or slower and because of that another mandatory thread would have been done or not, you know what I mean?

Some ideas:

  • Add this piece of code inside a device.ready section
  • Move the code to ionViewWillEnter or ionViewDidEnter
  • Check the other actions before the call of the page to see if their are really finished
1 Like

Thanks for the suggestion. If a wrap the code in a platform.ready:

alert('login.ts constructor');
this.platform.ready().then(() => {
  alert('login.ts constructor in ready ');
  alert('login.ts constructor firebase = ' + firebase);
  this.fireAuth = firebase.auth();
  alert('login.ts constructor this.fireAuth = ' + this.fireAuth);
  this.utilityService = utilityService;
  this.utilityService.logout(this.auth, this.fireAuth);
  this.auth.subscribe((authState: FirebaseAuthState) => {
    this.authState = authState;
  });
});

The ā€˜login.ts constructor in readyā€™ alert gets fired, but not the next one with the firebase object.

This means the code does not freeze anymore, but it looks like the firebase object is still an issue.

Donā€™t know if nothing is better than no freeze, but at least something happened :wink:

What about moving this piece of code to ionViewWillEnterā€¦do that change something?

1 Like

Moved all the code to ionViewWillEnter, and get the same result. the code runs until there is a reverence to firebase.

Strange thing is also, I have a RESTful web-service that I call from the app. In iOS, it calls successfully, but in Android the call always returns a 404.

Also, I have the following function, that works in iOS, but in Android it only gets to the first alert with the error.message as undefined.

loginFacebookCordova(): Promise<FirebaseAuthState> {
    return new Promise<FirebaseAuthState>((resolve) => {
        alert('personUserService.ts loginFacebookCordova');
        Facebook.login(['public_profile', 'email']).then(facebookData => {
            alert('personUserService.ts loginFacebookCordova login done');
            let cred: firebase.auth.AuthCredential = firebase.auth.FacebookAuthProvider.credential(facebookData.authResponse.accessToken);
            alert('personUserService.ts loginFacebookCordova cred = ' + cred);
            firebase.auth().signInWithCredential(cred).then((data: FirebaseAuthState) => {
                alert('personUserService.ts signInWithCredential data = ' + data);
                resolve(data);
            });
        }, error => {
            this.loading.dismiss();
            console.error('loginFacebook: ' + error);
            this.doAlert('loginFacebook: ' + error.message);
        });
    });
}

Do you think thereā€™s something fundamentally wrong with my Android build?

Sure looking what you just says Iā€™m agree with you, if all request are blocked with android, something is wrong generally there!

Maybe try to remove and add the android platform again?
Or maybe something wrong with the emulator, try to install/run an apk on a real phone?
Also maybe is the cordova android up-to-date?

1 Like

Thank you, I did the following, and all my issues went away:

  1. ionic platform rm android
  2. ionic platform add android
1 Like

Congrats, cool to hear you manage to solve that!

1 Like