feat: 消息推送
This commit is contained in:
parent
153838aec0
commit
6c270302f5
@ -1,14 +1,163 @@
|
|||||||
import { Tabs } from 'expo-router';
|
|
||||||
import React from 'react';
|
|
||||||
import { Platform } from 'react-native';
|
|
||||||
|
|
||||||
import { HapticTab } from '@/components/HapticTab';
|
import { HapticTab } from '@/components/HapticTab';
|
||||||
import TabBarBackground from '@/components/ui/TabBarBackground';
|
import TabBarBackground from '@/components/ui/TabBarBackground';
|
||||||
import { Colors } from '@/constants/Colors';
|
import { Colors } from '@/constants/Colors';
|
||||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||||
|
import { fetchApi } from '@/lib/server-api-util';
|
||||||
|
import * as Notifications from 'expo-notifications';
|
||||||
|
import { Tabs } from 'expo-router';
|
||||||
|
import * as SecureStore from 'expo-secure-store';
|
||||||
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import { Platform } from 'react-native';
|
||||||
|
|
||||||
|
interface PollingData {
|
||||||
|
title: string;
|
||||||
|
id: string;
|
||||||
|
content: string;
|
||||||
|
extra: any;
|
||||||
|
}
|
||||||
export default function TabLayout() {
|
export default function TabLayout() {
|
||||||
const colorScheme = useColorScheme();
|
const colorScheme = useColorScheme();
|
||||||
|
const [pollingData, setPollingData] = useState<PollingData[]>([]);
|
||||||
|
const pollingInterval = useRef<NodeJS.Timeout | number>(null);
|
||||||
|
const tokenInterval = useRef<NodeJS.Timeout | number>(null);
|
||||||
|
const isMounted = useRef(true);
|
||||||
|
const [token, setToken] = useState('');
|
||||||
|
const sendNotification = async (item: PollingData) => {
|
||||||
|
// 请求通知权限
|
||||||
|
const { status } = await Notifications.requestPermissionsAsync();
|
||||||
|
if (status !== 'granted') {
|
||||||
|
alert('请先允许通知权限');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调度本地通知
|
||||||
|
await Notifications.scheduleNotificationAsync({
|
||||||
|
content: {
|
||||||
|
title: item.title,
|
||||||
|
body: item.content,
|
||||||
|
data: { screen: 'ask', extra: item.extra, id: item.id },
|
||||||
|
priority: 'high', // 关键:设置 high 或 max
|
||||||
|
},
|
||||||
|
trigger: {
|
||||||
|
seconds: 2, // 延迟2秒显示
|
||||||
|
type: Notifications.SchedulableTriggerInputTypes.TIME_INTERVAL // 添加 type 字段
|
||||||
|
}, // 延迟2秒显示
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听通知点击事件
|
||||||
|
useEffect(() => {
|
||||||
|
const notificationListener = Notifications.addNotificationResponseReceivedListener(response => {
|
||||||
|
const data = response.notification.request.content.data;
|
||||||
|
console.log('通知被点击,数据:', data);
|
||||||
|
pollingData?.filter((item) => item.id !== data.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 清理监听器
|
||||||
|
return () => {
|
||||||
|
Notifications.removeNotificationSubscription(notificationListener);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 轮询获取推送消息
|
||||||
|
const startPolling = useCallback(async (interval: number = 5000) => {
|
||||||
|
|
||||||
|
// 设置轮询
|
||||||
|
pollingInterval.current = setInterval(async () => {
|
||||||
|
if (isMounted.current) {
|
||||||
|
await getMessageData();
|
||||||
|
}
|
||||||
|
}, interval);
|
||||||
|
|
||||||
|
// 返回清理函数
|
||||||
|
return () => {
|
||||||
|
if (pollingInterval.current) {
|
||||||
|
clearInterval(pollingInterval.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 获取推送消息
|
||||||
|
const getMessageData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetchApi<PollingData[]>("/notice/push/message", {
|
||||||
|
method: "POST"
|
||||||
|
});
|
||||||
|
setPollingData((prev) => ([...prev, ...response]));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取轮询数据时出错:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取认证token
|
||||||
|
const getAuthToken = async (): Promise<string> => {
|
||||||
|
let tokenValue = '';
|
||||||
|
if (Platform.OS === 'web') {
|
||||||
|
tokenValue = localStorage.getItem('token') || '';
|
||||||
|
} else {
|
||||||
|
tokenValue = (await SecureStore.getItemAsync('token')) || '';
|
||||||
|
}
|
||||||
|
setToken(tokenValue); // 只在获取到新token时更新状态
|
||||||
|
return tokenValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const checkAuthStatus = async () => {
|
||||||
|
try {
|
||||||
|
if (token) {
|
||||||
|
// 启动轮询
|
||||||
|
startPolling(5000);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取推送消息出错:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkAuthStatus();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
// 清理函数
|
||||||
|
if (pollingInterval.current) {
|
||||||
|
clearInterval(pollingInterval.current);
|
||||||
|
}
|
||||||
|
isMounted.current = false;
|
||||||
|
};
|
||||||
|
}, [token]);
|
||||||
|
|
||||||
|
// 本地推送
|
||||||
|
useEffect(() => {
|
||||||
|
pollingData?.map((item) => {
|
||||||
|
sendNotification(item)
|
||||||
|
})
|
||||||
|
}, [pollingData])
|
||||||
|
|
||||||
|
// 轮询获取token
|
||||||
|
useEffect(() => {
|
||||||
|
// 如果已经有token,直接返回
|
||||||
|
if (token) {
|
||||||
|
if (tokenInterval.current) {
|
||||||
|
clearInterval(tokenInterval.current);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!tokenInterval.current) return;
|
||||||
|
// 设置轮询
|
||||||
|
tokenInterval.current = setInterval(async () => {
|
||||||
|
if (isMounted.current) {
|
||||||
|
const currentToken = await getAuthToken();
|
||||||
|
// 如果获取到token,清除定时器
|
||||||
|
if (currentToken && tokenInterval.current) {
|
||||||
|
clearInterval(tokenInterval.current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
// 返回清理函数
|
||||||
|
return () => {
|
||||||
|
if (tokenInterval.current) {
|
||||||
|
clearInterval(tokenInterval.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [token]); // 添加token作为依赖
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user