feat: 添加原生通知桥接功能及相关配置
This commit is contained in:
@@ -9,12 +9,16 @@ import {
|
||||
loadNotificationRules,
|
||||
transformNotificationToTransaction,
|
||||
} from '../services/notificationRuleService'
|
||||
import NotificationBridge, { isNativeNotificationBridgeAvailable } from '../lib/notificationBridge'
|
||||
|
||||
const notifications = ref([])
|
||||
const processingId = ref('')
|
||||
const syncing = ref(false)
|
||||
const rulesLoading = ref(false)
|
||||
const ruleSet = ref([])
|
||||
|
||||
const nativeBridgeReady = isNativeNotificationBridgeAvailable()
|
||||
let permissionChecked = false
|
||||
let bootstrapped = false
|
||||
|
||||
const ensureRulesReady = async () => {
|
||||
@@ -31,6 +35,21 @@ const ensureRulesReady = async () => {
|
||||
export const useTransactionEntry = () => {
|
||||
const transactionStore = useTransactionStore()
|
||||
|
||||
// 原生端:在首次同步前做一次权限校验与请求
|
||||
const ensureNativePermission = async () => {
|
||||
if (!nativeBridgeReady || permissionChecked) return
|
||||
try {
|
||||
const result = await NotificationBridge.hasPermission()
|
||||
if (!result?.granted) {
|
||||
await NotificationBridge.requestPermission()
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('[notifications] 原生权限检查失败', error)
|
||||
} finally {
|
||||
permissionChecked = true
|
||||
}
|
||||
}
|
||||
|
||||
const removeNotification = (id) => {
|
||||
notifications.value = notifications.value.filter((item) => item.id !== id)
|
||||
}
|
||||
@@ -63,6 +82,9 @@ export const useTransactionEntry = () => {
|
||||
if (syncing.value) return
|
||||
syncing.value = true
|
||||
try {
|
||||
if (nativeBridgeReady) {
|
||||
await ensureNativePermission()
|
||||
}
|
||||
await ensureRulesReady()
|
||||
await transactionStore.ensureInitialized()
|
||||
const queue = await fetchNotificationQueue()
|
||||
|
||||
32
src/lib/notificationBridge.js
Normal file
32
src/lib/notificationBridge.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Capacitor, registerPlugin } from '@capacitor/core'
|
||||
|
||||
// Web 端的兜底实现:保证浏览器环境下不会报错
|
||||
const webFallback = {
|
||||
async hasPermission() {
|
||||
return { granted: true }
|
||||
},
|
||||
async requestPermission() {
|
||||
return { granted: true }
|
||||
},
|
||||
async getPendingNotifications() {
|
||||
return { notifications: [] }
|
||||
},
|
||||
async acknowledgeNotification() {
|
||||
return { acknowledged: true }
|
||||
},
|
||||
async clearNotifications() {
|
||||
return { cleared: true }
|
||||
},
|
||||
}
|
||||
|
||||
const NotificationBridge = registerPlugin('NotificationBridge', {
|
||||
web: () => webFallback,
|
||||
})
|
||||
|
||||
export const isNativeNotificationBridgeAvailable = () =>
|
||||
typeof Capacitor.isNativePlatform === 'function'
|
||||
? Capacitor.isNativePlatform()
|
||||
: Capacitor.getPlatform() !== 'web'
|
||||
|
||||
export default NotificationBridge
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import NotificationBridge, {
|
||||
isNativeNotificationBridgeAvailable,
|
||||
} from '../lib/notificationBridge'
|
||||
|
||||
// 原生插件回调,可按需在应用启动时注入,例如用于上报到服务端
|
||||
let remoteNotificationFetcher = async () => []
|
||||
let remoteNotificationAcknowledger = async () => {}
|
||||
|
||||
// 判断当前是否为原生环境(Android 容器内)
|
||||
const nativeBridgeReady = isNativeNotificationBridgeAvailable()
|
||||
|
||||
/**
|
||||
* 本地模拟通知缓存,真实环境可以由原生插件 push
|
||||
* 本地模拟通知缓存:
|
||||
* - 浏览器环境:用于 Demo & Mock
|
||||
* - 原生环境:作为 NotificationBridge 数据的补充/兜底
|
||||
*/
|
||||
let localNotificationQueue = [
|
||||
{
|
||||
@@ -38,12 +47,20 @@ export const setRemoteNotificationAcknowledger = (fn) => {
|
||||
const sortByCreatedAtDesc = (a, b) =>
|
||||
new Date(b.createdAt || b.id) - new Date(a.createdAt || a.id)
|
||||
|
||||
/**
|
||||
* 统一获取待处理通知队列:
|
||||
* - 原生环境:优先从 NotificationBridge 中拿未处理通知
|
||||
* - 浏览器:仅使用本地模拟通知
|
||||
*/
|
||||
export const fetchNotificationQueue = async () => {
|
||||
const remote = await remoteNotificationFetcher()
|
||||
const composed = [...localNotificationQueue, ...(Array.isArray(remote) ? remote : [])]
|
||||
return composed.sort(sortByCreatedAtDesc)
|
||||
}
|
||||
|
||||
/**
|
||||
* 浏览器环境下模拟「新通知」进入队列
|
||||
*/
|
||||
export const pushLocalNotification = (payload) => {
|
||||
const entry = {
|
||||
id: payload?.id || uuidv4(),
|
||||
@@ -54,11 +71,42 @@ export const pushLocalNotification = (payload) => {
|
||||
localNotificationQueue = [entry, ...localNotificationQueue]
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认/忽略某条通知后,从本地队列中移除,并尝试同步到远端
|
||||
*/
|
||||
export const acknowledgeNotification = async (id) => {
|
||||
localNotificationQueue = localNotificationQueue.filter((item) => item.id !== id)
|
||||
if (id) {
|
||||
localNotificationQueue = localNotificationQueue.filter((item) => item.id !== id)
|
||||
}
|
||||
try {
|
||||
await remoteNotificationAcknowledger(id)
|
||||
} catch (error) {
|
||||
console.warn('[notifications] 远程确认失败,将在下次同步重试', error)
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 原生桥接(Android NotificationListenerService)集成 =====
|
||||
|
||||
if (nativeBridgeReady) {
|
||||
// 从原生层拉取待处理通知
|
||||
setRemoteNotificationFetcher(async () => {
|
||||
try {
|
||||
const { notifications = [] } = await NotificationBridge.getPendingNotifications()
|
||||
return notifications
|
||||
} catch (error) {
|
||||
console.warn('[notifications] 获取原生通知失败,退回本地模拟数据', error)
|
||||
return []
|
||||
}
|
||||
})
|
||||
|
||||
// 通知已确认/忽略后,告知原生层清除对应记录
|
||||
setRemoteNotificationAcknowledger(async (id) => {
|
||||
if (!id) return
|
||||
try {
|
||||
await NotificationBridge.acknowledgeNotification({ id })
|
||||
} catch (error) {
|
||||
console.warn('[notifications] 通知确认同步失败', error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user