在 Firebase 通知注册和设备令牌后触发 Angular 应用程序逻辑
Trigger Angular app logic after Firebase notifications registration and device token
我希望在我的 Angular 13 Ionic 6 应用程序中实现此逻辑:
应用启动时,获取设备令牌。
使用设备令牌,我执行一些逻辑(查询数据库以查看此设备是已知的还是新的)并根据结果 - 路由到页面:未知设备的注册页面和现有的一些主页。在出现这些页面中的任何一个之前,我可能会展示一个微调器或其他东西。
我无法达到使用有效令牌调用 appLauncher() 函数的情况。
我尝试将令牌存储在本地存储中 - 但我无法与正在填充的存储异步。
我尝试的最后一件事(此处显示)是使用 @Output 发射器 - 从未调用过 appLauncher。
这是我拥有的:
app.component.ts - 在这里我也尝试了嵌套的 Promises。如果令牌已经在本地存储中找到,并且只有这是第一个 运行 - 我会等一段时间,直到这个存储被填充,我才同意第一个承诺很快解决。但是这里调用 appLauncher 也失败了,我相信这不是一个优雅的实现方式。我更喜欢反应事件 运行在此处显示。
import { Component } from '@angular/core';
import { AlertController, Platform } from '@ionic/angular';
import { Router } from '@angular/router';
import { SplashScreen } from '@capacitor/splash-screen';
import { FbNotificationsService } from './services/fb-notifications.service';
import { TigergraphService } from "./services/tigergraph.service";
import { get, set, remove } from './services/storage.service';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss'],
})
export class AppComponent {
deviceId: string;
private _tgdb;
constructor(
private platform: Platform,
private fbNotifications: FbNotificationsService,
private route: Router,
public tgdb: TigergraphService,
public LoggerService: LoggerService,
private alertCtrl: AlertController
) {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(async (source) => {
console.log("platform source: " + source);
// Trigger the push setup
this.fbNotifications.initPush();
get('device-token').then(
(res) => {
if (res==null) {
console.log('No token returned - need to wait for the promise to complete');
return new Promise(function(resolve, reject) {
setTimeout(function() {
// Fetch token again after a delay
get('device-token').then(
(res) => {
resolve(res);
}
)
}, 15000);
});
} else {
console.log('app main just received a device token: ', res.value);
this.appLauncher(res.value);
}
},
(err) => {
console.error('Error in receiving device token in app main: ', err);
}).then(function(resToken2: any) {
console.log('Obtained the device token on second attempt: ', resToken2);
if (resToken2) {
this.appLauncher(resToken2);
}
});
try {
await SplashScreen.hide();
} catch (err) {
console.log('This is normal in a browser: ', err);
}
});
}
deviceTokenReceived(event) {
console.log('Device Token received from emitter: ', event);
if (event) {
this.appLauncher(event);
}
}
//Based on deviceId and if existing user or not - route
appLauncher(deviceId: string) {
console.log('Entered appLauncher: ', deviceId);
this._tgdb.runQuery("getPersonByDeviceId", {"DeviceId": deviceId}).subscribe(
res => {
if(res == null){
//No person found in DB - need registration routing
console.log('No person found with DeviceID. Routing to signup');
this.route.navigate(['/signup']);
} else {
//person exists in db
console.log('TG Query Result PErson by DeviceID: ' + JSON.stringify(res) + ' firstName: ' + res[0].vPerson[0].attributes.firstName);
set('curr-person', res[0].vPerson[0].attributes); //Store locally for use throughout the app
console.log('curr-person just saved');
//Rout based on user type
}
},
err => {
console.log('TG Query Error: ' + err.description);
//Route to some error page?
this.showAlert("Network Error", "Ooooops. I can't find any Internet at this time");
}
);
}
}
app.component.html - 仅用于捕获发出的 @Output 变量事件 - 但从未真正起作用:
<ion-app>
<ion-item (deviceId)="deviceTokenReceived($event)"></ion-item>
<ion-router-outlet></ion-router-outlet>
</ion-app>
Firebase 服务:
import { EventEmitter, Injectable, Output } from '@angular/core';
import {ActionPerformed, PushNotifications, PushNotificationSchema, Token} from '@capacitor/push-notifications';
import { Capacitor } from '@capacitor/core';
import { get, set, remove } from './storage.service';
@Injectable({
providedIn: 'root'
})
export class FbNotificationsService {
@Output('deviceId') deviceId = new EventEmitter<string>();
constructor() {}
initPush() {
if (Capacitor.getPlatform() !== 'web') {
this.registerPush()
} else {
}
}
private registerPush() {
PushNotifications.requestPermissions().then((permission) => {
if (permission.receive === 'granted') {
// Register with Apple / Google to receive push via APNS/FCM
console.log('FB Permission granted');
PushNotifications.register(); //Registers app to receive notifications
} else {
// No permission for push granted by user on iOS
console.log('FB NO permissions granted');
}
});
PushNotifications.addListener(
'registration',
(token: Token) => {
console.log('My token: ' + JSON.stringify(token));
//This is the device token.
this.deviceId.emit(token.value);
set('device-token', token.value).then( () => {
remove('curr-person'); //clear local store of current person in app init
}); //to be picked up in registration
});
PushNotifications.addListener('registrationError', (error: any) => {
console.log('Error: ' + JSON.stringify(error));
//Alert that the registration of this device for notifications failed
});
}
}
为简洁起见,此处跳过存储服务,它仅使用从@capacitor/storage 到get/set 令牌值的存储服务。
请问,正确的方法是什么?
谢谢!
感谢您的报告
我建议你使用 BehaviorSubject 来解决这个问题。
试试这个。
- 在 FBNotificationService.ts 文件中
onFCMTokenChanged: BehaviorSubject<string> = new BehaviorSubject("");
PushNotifications.addListener('registration', (token: Token) => {
console.log('My token: ' + JSON.stringify(token));
//This is the device token.
this.onFCMTokenChanged.next(token);
});
- 在 app.component.ts 文件中
内部构造函数()函数
this.fbNotifications.onFCMTokenChanged.pipe(takeUntil(this._unsubscribeAll)).subscribe(token => {
if ((token)&&(!this.appLaunched)) {
this.appLaunched = true;
this.appLauncher(token);
}
});
我希望在我的 Angular 13 Ionic 6 应用程序中实现此逻辑: 应用启动时,获取设备令牌。 使用设备令牌,我执行一些逻辑(查询数据库以查看此设备是已知的还是新的)并根据结果 - 路由到页面:未知设备的注册页面和现有的一些主页。在出现这些页面中的任何一个之前,我可能会展示一个微调器或其他东西。
我无法达到使用有效令牌调用 appLauncher() 函数的情况。 我尝试将令牌存储在本地存储中 - 但我无法与正在填充的存储异步。 我尝试的最后一件事(此处显示)是使用 @Output 发射器 - 从未调用过 appLauncher。 这是我拥有的:
app.component.ts - 在这里我也尝试了嵌套的 Promises。如果令牌已经在本地存储中找到,并且只有这是第一个 运行 - 我会等一段时间,直到这个存储被填充,我才同意第一个承诺很快解决。但是这里调用 appLauncher 也失败了,我相信这不是一个优雅的实现方式。我更喜欢反应事件 运行在此处显示。
import { Component } from '@angular/core';
import { AlertController, Platform } from '@ionic/angular';
import { Router } from '@angular/router';
import { SplashScreen } from '@capacitor/splash-screen';
import { FbNotificationsService } from './services/fb-notifications.service';
import { TigergraphService } from "./services/tigergraph.service";
import { get, set, remove } from './services/storage.service';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss'],
})
export class AppComponent {
deviceId: string;
private _tgdb;
constructor(
private platform: Platform,
private fbNotifications: FbNotificationsService,
private route: Router,
public tgdb: TigergraphService,
public LoggerService: LoggerService,
private alertCtrl: AlertController
) {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(async (source) => {
console.log("platform source: " + source);
// Trigger the push setup
this.fbNotifications.initPush();
get('device-token').then(
(res) => {
if (res==null) {
console.log('No token returned - need to wait for the promise to complete');
return new Promise(function(resolve, reject) {
setTimeout(function() {
// Fetch token again after a delay
get('device-token').then(
(res) => {
resolve(res);
}
)
}, 15000);
});
} else {
console.log('app main just received a device token: ', res.value);
this.appLauncher(res.value);
}
},
(err) => {
console.error('Error in receiving device token in app main: ', err);
}).then(function(resToken2: any) {
console.log('Obtained the device token on second attempt: ', resToken2);
if (resToken2) {
this.appLauncher(resToken2);
}
});
try {
await SplashScreen.hide();
} catch (err) {
console.log('This is normal in a browser: ', err);
}
});
}
deviceTokenReceived(event) {
console.log('Device Token received from emitter: ', event);
if (event) {
this.appLauncher(event);
}
}
//Based on deviceId and if existing user or not - route
appLauncher(deviceId: string) {
console.log('Entered appLauncher: ', deviceId);
this._tgdb.runQuery("getPersonByDeviceId", {"DeviceId": deviceId}).subscribe(
res => {
if(res == null){
//No person found in DB - need registration routing
console.log('No person found with DeviceID. Routing to signup');
this.route.navigate(['/signup']);
} else {
//person exists in db
console.log('TG Query Result PErson by DeviceID: ' + JSON.stringify(res) + ' firstName: ' + res[0].vPerson[0].attributes.firstName);
set('curr-person', res[0].vPerson[0].attributes); //Store locally for use throughout the app
console.log('curr-person just saved');
//Rout based on user type
}
},
err => {
console.log('TG Query Error: ' + err.description);
//Route to some error page?
this.showAlert("Network Error", "Ooooops. I can't find any Internet at this time");
}
);
}
}
app.component.html - 仅用于捕获发出的 @Output 变量事件 - 但从未真正起作用:
<ion-app>
<ion-item (deviceId)="deviceTokenReceived($event)"></ion-item>
<ion-router-outlet></ion-router-outlet>
</ion-app>
Firebase 服务:
import { EventEmitter, Injectable, Output } from '@angular/core';
import {ActionPerformed, PushNotifications, PushNotificationSchema, Token} from '@capacitor/push-notifications';
import { Capacitor } from '@capacitor/core';
import { get, set, remove } from './storage.service';
@Injectable({
providedIn: 'root'
})
export class FbNotificationsService {
@Output('deviceId') deviceId = new EventEmitter<string>();
constructor() {}
initPush() {
if (Capacitor.getPlatform() !== 'web') {
this.registerPush()
} else {
}
}
private registerPush() {
PushNotifications.requestPermissions().then((permission) => {
if (permission.receive === 'granted') {
// Register with Apple / Google to receive push via APNS/FCM
console.log('FB Permission granted');
PushNotifications.register(); //Registers app to receive notifications
} else {
// No permission for push granted by user on iOS
console.log('FB NO permissions granted');
}
});
PushNotifications.addListener(
'registration',
(token: Token) => {
console.log('My token: ' + JSON.stringify(token));
//This is the device token.
this.deviceId.emit(token.value);
set('device-token', token.value).then( () => {
remove('curr-person'); //clear local store of current person in app init
}); //to be picked up in registration
});
PushNotifications.addListener('registrationError', (error: any) => {
console.log('Error: ' + JSON.stringify(error));
//Alert that the registration of this device for notifications failed
});
}
}
为简洁起见,此处跳过存储服务,它仅使用从@capacitor/storage 到get/set 令牌值的存储服务。
请问,正确的方法是什么? 谢谢!
感谢您的报告 我建议你使用 BehaviorSubject 来解决这个问题。 试试这个。
- 在 FBNotificationService.ts 文件中
onFCMTokenChanged: BehaviorSubject<string> = new BehaviorSubject("");
PushNotifications.addListener('registration', (token: Token) => {
console.log('My token: ' + JSON.stringify(token));
//This is the device token.
this.onFCMTokenChanged.next(token);
});
- 在 app.component.ts 文件中 内部构造函数()函数
this.fbNotifications.onFCMTokenChanged.pipe(takeUntil(this._unsubscribeAll)).subscribe(token => {
if ((token)&&(!this.appLaunched)) {
this.appLaunched = true;
this.appLauncher(token);
}
});