ionic 4 + firebaseX stopped receiving push (android and ios) - firebase

My app has stopped from receiving push notifications.
I don't know what else I can do to check it.
It was working a few months ago
Stopped working for both iOS and Android
Installed and checked app permissions many times
Firebase is initializing, getting token and registering in my database fine
Tried test messages on Firebase console with generated token and it didn't work as well
Here is my notification.service.ts code:
import { Injectable } from '#angular/core';
import { Platform, Events } from '#ionic/angular';
import { HttpClient } from '#angular/common/http';
import { Storage } from '#ionic/storage';
import { BehaviorSubject } from 'rxjs';
import { tap } from 'rxjs/operators';
import { FirebaseX } from "#ionic-native/firebase-x/ngx";
import { environment } from '../../environments/environment';
import { AppService } from './app.service';
import { AuthService } from './auth.service';
#Injectable({
providedIn: 'root'
})
export class NotificationService {
fcm_token:any = null;
constructor(
private platform: Platform,
private http:HttpClient,
private appService:AppService,
private firebase: FirebaseX,
public events: Events,
public authService:AuthService,
) { }
async initialize(){
console.log('notificationService.initialize()');
let self = this;
let platforms = this.platform.platforms();
if(platforms.includes('ios') || platforms.includes('android')){
this.firebase.getToken().then(token => {
if(platforms.includes('ios')){ this.firebase.grantPermission(); }
if(platforms.includes('android')){ }
self.saveToken(token);
}).catch(error => console.error('FIREBASE Error getting token', error));
this.firebase.onTokenRefresh().subscribe((token: string) => { self.saveToken(token); });
this.firebase.onMessageReceived().subscribe(data => { });
}else{
// using browser, do nothing
}
}
async saveToken(token){
console.log('notificationService.saveToken()', token);
if(this.authService.is_logged == true){
this.fcm_token = token;
return this.http.post(environment.api_url+'/user/save-fcm-token', {fcm_token:this.fcm_token}, {headers:{'Authorization':'Bearer '+this.authService.auth_token}}).toPromise();
}
}
}
What else can I try?
Is there some place when I can see sending/receiving push errors?

Related

SignInWithApple is not defined in IONIC Project

Scenario:
I am trying to add identification via Apple and Firebase for my IONIC 4 application.
So I made my installation:
npm i cordova-plugin-apple-login
ionic cordova plugin add cordova-plugin-apple-login
Then I added in my service :
import {AngularFireAuth} from '#angular/fire/auth';
import {Facebook} from '#ionic-native/facebook/ngx';
import * as firebase from 'firebase';
import {GooglePlus} from '#ionic-native/google-plus/ngx';
declare var SignInWithApple: any;
export class AuthService {
constructor(public fAuth: AngularFireAuth,
public fb: Facebook,
public google: GooglePlus) {}
async loginApple() {
SignInWithApple.request({requestedScopes: [ SignInWithApple.Scope.Email, SignInWithApple.Scope.FullName ]})
.then((appleCredential) => {
const credential = new firebase.auth.OAuthProvider('apple.com').credential(appleCredential.identityToken);
this.fAuth.auth.signInWithCredential(credential)
.then((response) => {
console.log('Login successful');
})
.catch((error) => {
console.log(error);
alert('error:' + JSON.stringify(error));
});
});
}
}
Problem:
This is the method I find everywhere on the internet, but it gives me the error:
SignInWithApple is not defined
I also tried this :
Scenario:
ionic cordova plugin add cordova-plugin-sign-in-with-apple
npm i --save #ionic-native/sign-in-with-apple
import {AngularFireAuth} from '#angular/fire/auth';
import {Facebook} from '#ionic-native/facebook/ngx';
import * as firebase from 'firebase';
import {GooglePlus} from '#ionic-native/google-plus/ngx';
import { SignInWithApple,
AppleSignInResponse,
AppleSignInErrorResponse,
ASAuthorizationAppleIDRequest } from '#ionic-native/sign-in-with-apple';
export class AuthService {
constructor(public fAuth: AngularFireAuth,
public fb: Facebook,
public google: GooglePlus) {}
async loginApple() {
try {
const appleCredential: AppleSignInResponse = await SignInWithApple.signin({
requestedScopes: [
ASAuthorizationAppleIDRequest.ASAuthorizationScopeFullName,
ASAuthorizationAppleIDRequest.ASAuthorizationScopeEmail
]
});
const credential = new firebase.auth.OAuthProvider('apple.com').credential(
appleCredential.identityToken
);
this.fAuth.auth.signInWithCredential(credential)
.then((res) => {
console.log('Login successful', res);
})
.catch((error) => {
console.log(error);
});
} catch (error) {
console.log(error);
}
}
}
Problem:
Class not found
I don't find much explanation on the documentation ...
In both I have an error that I do not understand, what is the method to keep and how to correct it ?
An idea ?
Thank you

from http to Http Client, cant get my object to become a string array [duplicate]

Following Google's official Angular 4.3.2 doc here, I was able to do a simple get request from a local json file. I wanted to practice hitting a real endpoint from JSON placeholder site, but I'm having trouble figuring out what to put in the .subscribe() operator. I made an IUser interface to capture the fields of the payload, but the line with .subscribe(data => {this.users = data}) throws the error Type 'Object' is not assignable to type 'IUser[]'. What's the proper way to handle this? Seems pretty basic but I'm a noob.
My code is below:
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { IUsers } from './users';
#Component({
selector: 'pm-http',
templateUrl: './http.component.html',
styleUrls: ['./http.component.css']
})
export class HttpComponent implements OnInit {
productUrl = 'https://jsonplaceholder.typicode.com/users';
users: IUsers[];
constructor(private _http: HttpClient) { }
ngOnInit(): void {
this._http.get(this.productUrl).subscribe(data => {this.users = data});
}
}
You actually have a few options here, but use generics to cast it to the type you're expecting.
// Notice the Generic of IUsers[] casting the Type for resulting "data"
this.http.get<IUsers[]>(this.productUrl).subscribe(data => ...
// or in the subscribe
.subscribe((data: IUsers[]) => ...
Also I'd recommend using async pipes in your template that auto subscribe / unsubscribe, especially if you don't need any fancy logic, and you're just mapping the value.
users: Observable<IUsers[]>; // different type now
this.users = this.http.get<IUsers[]>(this.productUrl);
// template:
*ngFor="let user of users | async"
I'm on the Angular doc team and one open todo item is to change these docs to show the "best practice" way to access Http ... which is through a service.
Here is an example:
import { Injectable } from '#angular/core';
import { HttpClient, HttpErrorResponse } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import { IProduct } from './product';
#Injectable()
export class ProductService {
private _productUrl = './api/products/products.json';
constructor(private _http: HttpClient) { }
getProducts(): Observable<IProduct[]> {
return this._http.get<IProduct[]>(this._productUrl)
.do(data => console.log('All: ' + JSON.stringify(data)))
.catch(this.handleError);
}
private handleError(err: HttpErrorResponse) {
// in a real world app, we may send the server to some remote logging infrastructure
// instead of just logging it to the console
let errorMessage = '';
if (err.error instanceof Error) {
// A client-side or network error occurred. Handle it accordingly.
errorMessage = `An error occurred: ${err.error.message}`;
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
errorMessage = `Server returned code: ${err.status}, error message is: ${err.message}`;
}
console.error(errorMessage);
return Observable.throw(errorMessage);
}
}
The component would then look like this:
ngOnInit(): void {
this._productService.getProducts()
.subscribe(products => this.products = products,
error => this.errorMessage = <any>error);
}

How to fix push not found in Navcontroller ionic

I am getting the following error while using this code. I have also tried to change the push function to setRoot and the same error still persists.
I want to navigate to the home page which is the login page in case the user is not signed in but unable to do so.
The console shows that it entered the if statement but the navctrl command is not getting executed.
MyApp_Host.ngfactory.js? [sm]:1 ERROR TypeError: Cannot read property 'push' of undefined
This my code:
import { Component, ViewChild } from '#angular/core';
import { IonicPage, NavController, NavParams, AlertController} from 'ionic-angular';
import * as firebase from 'firebase/app';
import { HomePage } from '../home/home';
/**
* Generated class for the MainPage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-main',
templateUrl: 'main.html',
})
export class MainPage {
constructor(public navParams: NavParams, public alertCtrl: AlertController, public navController:NavController) {
}
ionViewDidLoad() {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
console.log(user);
console.log('entered in if');
// User is signed in.
} else {
console.log(user);
console.log('entered in else');
this.navController.push(HomePage);
// No user is signed in.
}
});
console.log('ionViewDidLoad MainPage')
}
}

Angularfire2: Nested observables on auth change and permission denied

My users can like a list of heroes, so I have this structure in my firebase rules/datas:
"user_flags": {
"$uid": {
".write": "auth.uid == $uid",
".read": "auth.uid == $uid",
"liked": {
"$heroIdx": {
".validate": "newData.isString()"
}
}
}
}
In my code I want to subscribe to the "liked heroes" ref, so that's what I do:
import { Injectable } from '#angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { Observable } from 'rxjs/Observable';
import { AngularFireAuth } from 'angularfire2/auth';
#Injectable()
export class UserFlagsService {
likedHeroes$: Observable<string[]>;
constructor(
private afAuth: AngularFireAuth,
private db: AngularFireDatabase
) {
this.likedHeroes$ = afAuth.authState.flatMap(user => {
return user && user.uid
? this.db.list(`user_flags/${user.uid}/liked`)
.map(heroes => heroes.map(hero => <string>hero.$value))
: Observable.of([])
});
}
}
Everything works fine until the user signs out... Even with the check on user and user.uid the query user_flags/MY_ID_HERE/liked seems to be triggered and I get a "permission denied".
I tried to use subscribe and watch for signout to unsubscribe but it didn't work either... The query was still triggered and failed with "permission denied"
How should I handle this ? I want my service to return a reliable observable so I can subscribe to it in my components.
Thanks a lot for your help
I am assuming that you want to ensure that the data you are rendering in the view disappears on sign out?
If this is the case, I would suggest using the switchMap operator from RXJS and the following pattern:
this.userProvider = this.afAuth.authState;
this.likedHeroes$ = this.userProvider.switchMap((auth) => {
if(auth){
return this.af.list('user_flags/' + auth.uid + '/liked');
}
});
You need to add the following to import the switchMap operator:
import 'rxjs/add/operator/switchMap';
Hit me with some comments if you want me to fill this out some more or if my assumption about what you're trying to achieve is incorrect. I've been trying to figure out the best way to do this stuff as well.
You should also check out this video from the Angular Firebase YouTube, it might help you with some of the issues in your question.
I managed to make it work by creating a BehaviorSubject and unsubscribing the event before the "signout" is triggered.
Here is my provider:
import { Injectable } from '#angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Subscription } from 'rxjs/Subscription';
import { UserProvider } from '../../providers/user/user';
#Injectable()
export class UserFlagsProvider {
likedHeroes$: Observable<string[]>;
subHeroesLiked: Subscription;
constructor(
protected userProvider: UserProvider,
protected db: AngularFireDatabase
) {
const heroesLikedSubject: BehaviorSubject<string[]> = new BehaviorSubject([]);
this.likedHeroes$ = heroesLikedSubject.asObservable();
this.userProvider.user$.subscribe(user => {
if (user) {
this.subHeroesLiked = this.db.list(`user_flags/${user.uid}/liked`).subscribe(heroesSlugs => {
heroesLikedSubject.next(heroesSlugs.map(hero => <string>hero.$key));
});
}
});
this.userProvider.signingOut$.subscribe(() => {
this.subHeroesLiked.unsubscribe();
});
}
}
And my userProvider
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { AngularFireAuth } from 'angularfire2/auth';
#Injectable()
export class UserProvider {
user$: Observable<firebase.User>;
user: firebase.User;
signingOut$: Subject<any> = new Subject();
constructor(private afAuth: AngularFireAuth) {
this.user$ = afAuth.authState;
this.user$.subscribe(user => this.user = user);
}
// [...]
signout() {
this.signingOut$.next();
return this.afAuth.auth.signOut();
}
}
Hope it helps someone.
FYI, this doesn't work (for now) with angularfire2-offline for an unknown reason.
If someone sees a better way to do it I'm interested

Firebase Authentication on Ionic 2

I am trying to implement login with firebase on Ionic 2 with the following code.
export class MyApp {
rootPage:any = Login;
isAuthenticated = false;
constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {
firebase.initializeApp({
apiKey: "AIzaSyC94rD8wXG0aRLTcG29qVGw8CFfvCK7XVQ",
authDomain: "myfirstfirebaseproject-6da6c.firebaseapp.com",
});
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
this.rootPage = Home;
} else {
this.rootPage = Login;
}
});
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
statusBar.styleDefault();
splashScreen.hide();
});
}
}
I realize that even when I am authenticated, I am always brought to the Login screen because it does not wait for onAuthStateChanged promise to be fulfilled and carries on with initializing the app, therefore, the Login screen instead of the Home screen is always shown.
But how should I change my code so that I can show Home when authenticated?
Remove the login from the rootPage declaration
export class MyApp {
rootPage:any;
...
}
You're setting the page to your LoginPage as the app initializes and before he can check if the user is loged.
For it to run the onAuthStateChange, when the app initializes you need to use Zone to create an observable and the run it.
import { NgZone } from '#angular/core';
zone: NgZone; // declare the zone
this.zone = new NgZone({});
const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
this.zone.run(() => {
if (user) {
this.rootPage = Home;
unsubscribe();
} else {
this.rootPage = Login;
unsubscribe();
}
});
});
Hope it helps

Resources