push.js与Angular集成:服务封装与依赖注入
你还在为Angular应用中的桌面通知管理感到困扰吗?本文将详细介绍如何将push.js(GitHub 加速计划 / pu / push.js)与Angular框架无缝集成,通过服务封装和依赖注入实现优雅的通知管理方案。读完本文,你将掌握:push.js核心API封装、Angular服务设计模式、依赖注入最佳实践以及跨浏览器通知适配方案。
push.js核心能力解析
push.js作为一款跨平台通知框架,其核心类Push.js提供了创建、管理和关闭桌面通知的完整生命周期支持。该类通过Permission.js处理浏览器通知权限请求,同时集成了多种通知代理(Agent)以支持不同浏览器环境:
// 多浏览器代理支持 [src/push/Push.js#L50-L56]
this._agents = {
desktop: new DesktopAgent(win),
chrome: new MobileChromeAgent(win),
firefox: new MobileFirefoxAgent(win),
ms: new MSAgent(win),
webkit: new WebKitAgent(win)
};
框架的核心能力包括:
- 自动检测浏览器环境并选择最佳通知实现
- 统一的通知生命周期管理(创建/关闭/自动过期)
- 服务 worker 集成支持后台通知
- 权限请求与状态管理
Angular服务封装方案
基础服务封装
创建PushNotificationService封装push.js核心功能,通过Angular依赖注入系统提供全局访问点:
// src/app/services/push-notification.service.ts
import { Injectable } from '@angular/core';
import Push from 'push.js/src/push/Push';
import Permission from 'push.js/src/push/Permission';
@Injectable({ providedIn: 'root' })
export class PushNotificationService {
private pushInstance: Push;
constructor() {
this.pushInstance = new Push(window);
// 配置服务工作器路径 [src/push/Push.js#L58-L61]
this.pushInstance.config({
serviceWorker: '/assets/serviceWorker.min.js'
});
}
// 检查浏览器支持状态 [src/push/Push.js#L370-L378]
isSupported(): boolean {
return this.pushInstance.supported();
}
// 请求通知权限 [src/push/Permission.js#L89-L132]
async requestPermission(): Promise<boolean> {
if (!this.pushInstance.Permission.has()) {
try {
await this.pushInstance.Permission.request();
return true;
} catch {
return false;
}
}
return true;
}
// 创建通知 [src/push/Push.js#L283-L314]
async showNotification(title: string, options: any): Promise<void> {
if (!await this.requestPermission()) {
throw new Error('通知权限被拒绝');
}
return this.pushInstance.create(title, {
body: options.body,
icon: options.icon || '/assets/icons/notification.png',
timeout: options.timeout || 5000,
onClick: options.onClick
});
}
// 清除所有通知 [src/push/Push.js#L355-L364]
clearAll(): boolean {
return this.pushInstance.clear();
}
}
高级功能封装
扩展服务以支持通知分组、历史记录和自定义事件:
// 通知分组管理
private notificationGroups: Map<string, Array<{id: string, title: string}>> = new Map();
async showGroupedNotification(groupKey: string, title: string, options: any) {
const notification = await this.showNotification(title, options);
const group = this.notificationGroups.get(groupKey) || [];
group.push({
id: Date.now().toString(),
title
});
this.notificationGroups.set(groupKey, group);
return notification;
}
// 获取分组通知历史
getGroupHistory(groupKey: string): Array<{id: string, title: string}> {
return this.notificationGroups.get(groupKey) || [];
}
依赖注入与模块配置
根模块集成
在AppModule中配置通知服务,并注册全局错误处理:
// src/app/app.module.ts
import { NgModule, ErrorHandler } from '@angular/core';
import { PushNotificationService } from './services/push-notification.service';
class NotificationErrorHandler implements ErrorHandler {
constructor(private pushService: PushNotificationService) {}
handleError(error: any): void {
this.pushService.showNotification('应用错误', {
body: error.message || '发生未知错误',
icon: '/assets/icons/error.png'
});
console.error(error);
}
}
@NgModule({
providers: [
PushNotificationService,
{ provide: ErrorHandler, useClass: NotificationErrorHandler }
]
})
export class AppModule { }
组件中使用
在组件中注入并使用通知服务:
// src/app/components/dashboard/dashboard.component.ts
import { Component, OnInit } from '@angular/core';
import { PushNotificationService } from '../../services/push-notification.service';
@Component({
selector: 'app-dashboard',
template: `
<button (click)="sendNotification()">发送通知</button>
<div *ngIf="!isSupported">您的浏览器不支持桌面通知</div>
`
})
export class DashboardComponent implements OnInit {
isSupported = false;
constructor(private notificationService: PushNotificationService) {}
ngOnInit() {
this.isSupported = this.notificationService.isSupported();
}
async sendNotification() {
try {
await this.notificationService.showNotification('新消息', {
body: '您有3条未读消息',
icon: '/assets/icons/message.png',
timeout: 10000,
onClick: () => window.focus()
});
} catch (e) {
console.error('通知发送失败', e);
}
}
}
高级集成策略
服务工作器配置
为支持后台通知,需配置service worker并在Angular应用中注册:
// src/app/services/push-notification.service.ts
async registerServiceWorker() {
if ('serviceWorker' in navigator) {
try {
await navigator.serviceWorker.register(
this.pushInstance.config().serviceWorker,
{ scope: '/' }
);
console.log('服务工作器注册成功');
} catch (error) {
console.error('服务工作器注册失败:', error);
}
}
}
通知权限状态管理
结合Angular Router实现基于路由的权限控制:
// 路由守卫中检查权限
@Injectable()
export class NotificationGuard implements CanActivate {
constructor(
private notificationService: PushNotificationService,
private router: Router
) {}
async canActivate(): Promise<boolean> {
const hasPermission = await this.notificationService.requestPermission();
if (!hasPermission) {
this.router.navigate(['/notification-permission-guide']);
return false;
}
return true;
}
}
常见问题解决方案
跨浏览器兼容性处理
push.js已内置多浏览器适配,但在Angular应用中仍需注意:
-
Safari兼容性:确保在
index.html中添加权限提示:<meta name="apple-mobile-web-app-capable" content="yes"> -
服务工作器作用域:Angular CLI默认输出路径可能需要调整service worker位置:
// angular.json "assets": [ "src/assets", { "glob": "serviceWorker.min.js", "input": "node_modules/push.js/dist/", "output": "/" } ]
构建优化
使用Angular的tree-shaking优化push.js引入大小:
// 仅导入所需模块
import Push from 'push.js/src/push/Push';
import { DesktopAgent } from 'push.js/src/agents/DesktopAgent';
总结与最佳实践
通过服务封装与依赖注入,我们实现了push.js与Angular的优雅集成。关键最佳实践包括:
- 单一职责:通知服务专注于通知管理,避免业务逻辑混入
- 错误边界:通过全局错误处理器捕获并通知异常
- 权限管理:在用户交互后请求权限,提升用户体验
- 浏览器检测:提前检查支持状态并提供降级方案
- 服务工作器:配置后台通知支持以提升应用离线能力
这种集成方案不仅保持了Angular应用的架构清晰,还充分利用了push.js的跨平台优势,为用户提供一致的通知体验。完整实现可参考项目测试用例中的使用示例。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



