feat: 通知权限+推送
This commit is contained in:
parent
0307ed0a00
commit
5b23951643
@ -1,5 +1,6 @@
|
||||
import IP from '@/assets/icons/svg/ip.svg';
|
||||
import Lottie from '@/components/lottie/lottie';
|
||||
import MessagePush from '@/components/message-push';
|
||||
import { useRouter } from 'expo-router';
|
||||
import * as SecureStore from 'expo-secure-store';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -35,7 +36,7 @@ export default function HomeScreen() {
|
||||
{"\n"}
|
||||
{t('auth.welcomeAwaken.back', { ns: 'login' })}
|
||||
</Text>
|
||||
|
||||
<MessagePush />
|
||||
{/* 唤醒按钮 */}
|
||||
<TouchableOpacity
|
||||
className="bg-white rounded-full px-10 py-4 shadow-[0_2px_4px_rgba(0,0,0,0.1)] w-full items-center"
|
||||
|
||||
76
components/message-push.tsx
Normal file
76
components/message-push.tsx
Normal file
@ -0,0 +1,76 @@
|
||||
import * as Notifications from 'expo-notifications';
|
||||
import { useRouter } from 'expo-router';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { Button, Text, View } from 'react-native';
|
||||
|
||||
Notifications.setNotificationHandler({
|
||||
handleNotification: async () => ({
|
||||
shouldShowAlert: true,
|
||||
shouldPlaySound: true,
|
||||
shouldSetBadge: false,
|
||||
shouldShowBanner: true,
|
||||
shouldShowList: true,
|
||||
}),
|
||||
});
|
||||
|
||||
export default function MessagePush() {
|
||||
const router = useRouter();
|
||||
const notificationListener = useRef<Notifications.Subscription>(null);
|
||||
const responseListener = useRef<Notifications.Subscription>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// 监听通知点击事件
|
||||
responseListener.current = Notifications.addNotificationResponseReceivedListener(response => {
|
||||
const data = response.notification.request.content.data;
|
||||
console.log('通知被点击,数据:', data);
|
||||
|
||||
// 根据通知数据跳转到指定页面
|
||||
if (data.screen === 'ask') {
|
||||
router.push('/ask');
|
||||
} else if (data.screen === 'owner') {
|
||||
router.push('/owner');
|
||||
}
|
||||
});
|
||||
|
||||
// 清理监听器
|
||||
return () => {
|
||||
if (notificationListener.current) {
|
||||
Notifications.removeNotificationSubscription(notificationListener.current);
|
||||
}
|
||||
if (responseListener.current) {
|
||||
Notifications.removeNotificationSubscription(responseListener.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
const sendNotification = async () => {
|
||||
// 请求通知权限
|
||||
const { status } = await Notifications.requestPermissionsAsync();
|
||||
if (status !== 'granted') {
|
||||
alert('请先允许通知权限');
|
||||
return;
|
||||
}
|
||||
|
||||
// 调度本地通知
|
||||
await Notifications.scheduleNotificationAsync({
|
||||
content: {
|
||||
title: '你有一条新消息 🎉',
|
||||
body: '点击查看详情内容',
|
||||
data: { screen: 'ask' },
|
||||
priority: 'high', // 关键:设置 high 或 max
|
||||
},
|
||||
trigger: {
|
||||
seconds: 2, // 延迟2秒显示
|
||||
type: Notifications.SchedulableTriggerInputTypes.TIME_INTERVAL // 添加 type 字段
|
||||
}, // 延迟2秒显示
|
||||
});
|
||||
|
||||
alert('通知将在2秒后显示');
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 }}>
|
||||
<Text>点击按钮发送本地通知</Text>
|
||||
<Button title="发送通知" onPress={sendNotification} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@ -13,7 +13,7 @@ import LcensesModal from './qualification/lcenses';
|
||||
import PrivacyModal from './qualification/privacy';
|
||||
import CustomSwitch from './switch';
|
||||
import UserInfo from './userInfo';
|
||||
import { getLocationPermission, getPermissions, requestLocationPermission, requestMediaLibraryPermission, reverseGeocode } from './utils';
|
||||
import { checkNotificationPermission, getLocationPermission, getPermissions, requestLocationPermission, requestMediaLibraryPermission, requestNotificationPermission, reverseGeocode } from './utils';
|
||||
|
||||
const SettingModal = (props: { modalVisible: boolean, setModalVisible: (visible: boolean) => void, userInfo: User }) => {
|
||||
const { modalVisible, setModalVisible, userInfo } = props;
|
||||
@ -32,7 +32,17 @@ const SettingModal = (props: { modalVisible: boolean, setModalVisible: (visible:
|
||||
};
|
||||
// 通知消息权限开关
|
||||
const [notificationsEnabled, setNotificationsEnabled] = useState(false);
|
||||
const toggleNotifications = () => setNotificationsEnabled(previous => !previous);
|
||||
const toggleNotifications = () => {
|
||||
if (notificationsEnabled) {
|
||||
// 引导去设置关闭权限
|
||||
openAppSettings()
|
||||
} else {
|
||||
console.log('请求通知权限');
|
||||
requestNotificationPermission().then((res) => {
|
||||
setNotificationsEnabled(res as boolean);
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// 相册权限
|
||||
const [albumEnabled, setAlbumEnabled] = useState(false);
|
||||
@ -126,7 +136,6 @@ const SettingModal = (props: { modalVisible: boolean, setModalVisible: (visible:
|
||||
};
|
||||
|
||||
// 退出登录
|
||||
|
||||
const handleLogout = () => {
|
||||
fetchApi("/iam/logout", {
|
||||
method: "POST",
|
||||
@ -154,6 +163,11 @@ const SettingModal = (props: { modalVisible: boolean, setModalVisible: (visible:
|
||||
getPermissions().then((res) => {
|
||||
setAlbumEnabled(res);
|
||||
})
|
||||
// 通知权限
|
||||
checkNotificationPermission().then((res) => {
|
||||
console.log('通知权限:', res);
|
||||
setNotificationsEnabled(res);
|
||||
})
|
||||
}
|
||||
}, [modalVisible])
|
||||
|
||||
|
||||
@ -1,8 +1,21 @@
|
||||
// 地理位置逆编码
|
||||
import * as ImagePicker from 'expo-image-picker';
|
||||
import * as Location from 'expo-location';
|
||||
import * as Notifications from 'expo-notifications';
|
||||
import * as SecureStore from 'expo-secure-store';
|
||||
import { Alert, Linking, Platform } from 'react-native';
|
||||
|
||||
// 配置通知处理器
|
||||
Notifications.setNotificationHandler({
|
||||
handleNotification: async () => ({
|
||||
shouldShowAlert: true,
|
||||
shouldPlaySound: true,
|
||||
shouldSetBadge: false,
|
||||
shouldShowBanner: true,
|
||||
shouldShowList: true,
|
||||
}),
|
||||
});
|
||||
|
||||
export const reverseGeocode = async (latitude: number, longitude: number) => {
|
||||
try {
|
||||
const addressResults = await Location.reverseGeocodeAsync({ latitude, longitude });
|
||||
@ -193,3 +206,97 @@ export const requestMediaLibraryPermission = async (showAlert: boolean = true):
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 检查通知权限
|
||||
export const checkNotificationPermission = async () => {
|
||||
const { status } = await Notifications.getPermissionsAsync();
|
||||
console.log('当前通知权限状态:', status);
|
||||
|
||||
return status === 'granted';
|
||||
};
|
||||
|
||||
// 请求通知权限
|
||||
export const requestNotificationPermission = async () => {
|
||||
try {
|
||||
// 1. 先检查当前权限状态
|
||||
const { status, canAskAgain } = await Notifications.getPermissionsAsync();
|
||||
console.log('当前通知权限状态:', { status, canAskAgain });
|
||||
|
||||
// 2. 如果已经有权限,直接返回
|
||||
if (status === 'granted') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 3. 如果用户之前选择了"拒绝且不再询问"
|
||||
if (status === 'denied' && !canAskAgain) {
|
||||
// 显示提示,引导用户去设置
|
||||
const openSettings = await new Promise(resolve => {
|
||||
Alert.alert(
|
||||
'需要通知权限',
|
||||
'您之前拒绝了通知权限。要使用此功能,请在设置中启用通知权限。',
|
||||
[
|
||||
{
|
||||
text: '取消',
|
||||
style: 'cancel',
|
||||
onPress: () => resolve(false)
|
||||
},
|
||||
{
|
||||
text: '去设置',
|
||||
onPress: () => resolve(true)
|
||||
}
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
if (openSettings) {
|
||||
// 打开应用设置
|
||||
await Linking.openSettings();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 如果是第一次请求或可以再次询问,则请求权限
|
||||
console.log('请求通知权限...');
|
||||
const { status: newStatus } = await Notifications.requestPermissionsAsync();
|
||||
console.log('新通知权限状态:', newStatus);
|
||||
|
||||
if (newStatus !== 'granted') {
|
||||
Alert.alert('需要通知权限', '请允许通知以使用此功能');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('请求通知权限时出错:', error);
|
||||
Alert.alert('错误', '请求通知权限时出错');
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 发送本地通知的辅助函数
|
||||
export const sendLocalNotification = async (title: string, body: string, data: Record<string, any> = {}) => {
|
||||
try {
|
||||
const hasPermission = await checkNotificationPermission();
|
||||
if (!hasPermission) {
|
||||
const granted = await requestNotificationPermission();
|
||||
if (!granted) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
await Notifications.scheduleNotificationAsync({
|
||||
content: {
|
||||
title,
|
||||
body,
|
||||
data,
|
||||
priority: 'high',
|
||||
},
|
||||
trigger: null, // 立即触发
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('发送通知时出错:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user