damer-0210 #21

Merged
damer merged 3 commits from damer-0210 into main 2026-02-10 09:24:01 +00:00
4 changed files with 52 additions and 8 deletions
Showing only changes of commit 076bd5636f - Show all commits

View File

@@ -7,10 +7,10 @@ import { httpJson } from '../utils/http';
import { APP_ENV } from '../constants/env'; import { APP_ENV } from '../constants/env';
import { import {
getDailyReminderSettings, getDailyReminderSettings,
getLastRegisteredPushToken, getLastRegisteredPushPayload,
getOrCreateClientUserId, getOrCreateClientUserId,
getUserProfileScoring, getUserProfileScoring,
setLastRegisteredPushToken, setLastRegisteredPushPayload,
} from '../storage/appStorage'; } from '../storage/appStorage';
import type { UserProfileScoring } from '../storage/appStorage'; import type { UserProfileScoring } from '../storage/appStorage';
import { toBackendLocaleFromLanguageTag } from '../i18n/locale'; import { toBackendLocaleFromLanguageTag } from '../i18n/locale';
@@ -170,14 +170,27 @@ export async function ensurePushTokenRegisteredIfPermitted(): Promise<{ ok: bool
const settings = await Notifications.getPermissionsAsync(); const settings = await Notifications.getPermissionsAsync();
if (!isSystemNotificationPermissionGranted(settings.status)) return { ok: false, reason: 'permission_not_granted' }; if (!isSystemNotificationPermissionGranted(settings.status)) return { ok: false, reason: 'permission_not_granted' };
const clientUserId = await getOrCreateClientUserId();
const token = await getExpoPushTokenOrThrow(); const token = await getExpoPushTokenOrThrow();
const env = toPushEnv(APP_ENV);
const appId = pickAppId();
// 简单去重token 未变化则不重复上报(减少网络与日志噪音) // 去重规则(更严格):
const last = await getLastRegisteredPushToken().catch(() => null); // - 只有当 token + client_user_id + env + app_id 全都一致时才跳过
if (last && String(last) === String(token)) return { ok: true, reason: 'already_registered' }; // - 避免出现“client_user_id 变化但 token 没变,导致后端绑定不更新”的问题
const last = await getLastRegisteredPushPayload().catch(() => null);
if (
last &&
last.pushToken === token &&
last.clientUserId === clientUserId &&
last.env === env &&
last.appId === appId
) {
return { ok: true, reason: 'already_registered' };
}
await registerPushToken({ pushToken: token }); await registerPushToken({ pushToken: token });
await setLastRegisteredPushToken(token); await setLastRegisteredPushPayload({ pushToken: token, clientUserId, env, appId });
return { ok: true, reason: 'registered' }; return { ok: true, reason: 'registered' };
} }

View File

@@ -18,8 +18,9 @@ const KEY_RECO_FEED_HISTORY = 'reco.feedHistory';
const KEY_UI_THEME_MODE = 'ui.theme.mode'; const KEY_UI_THEME_MODE = 'ui.theme.mode';
const KEY_UI_THEME_SUIXIN_STATE = 'ui.theme.suixin.state'; const KEY_UI_THEME_SUIXIN_STATE = 'ui.theme.suixin.state';
const KEY_DAILY_REMINDER_SETTINGS = 'dailyReminder.settings'; const KEY_DAILY_REMINDER_SETTINGS = 'dailyReminder.settings';
const KEY_PUSH_LAST_REGISTERED_TOKEN = 'push.lastRegisteredToken'; const KEY_PUSH_LAST_REGISTERED_TOKEN = 'push.lastRegisteredToken'; // 旧:仅 token保留兼容读取
const KEY_PUSH_LAST_REGISTERED_AT = 'push.lastRegisteredAt'; const KEY_PUSH_LAST_REGISTERED_AT = 'push.lastRegisteredAt'; // 旧:时间(保留兼容)
const KEY_PUSH_LAST_REGISTERED_PAYLOAD = 'push.lastRegisteredPayload'; // 新token+client_user_id+env+app_id
export type PushPromptState = 'enabled' | 'skipped' | 'unknown'; export type PushPromptState = 'enabled' | 'skipped' | 'unknown';
export type Reaction = 'like' | 'dislike'; export type Reaction = 'like' | 'dislike';
@@ -81,6 +82,36 @@ export async function setLastRegisteredPushToken(token: string): Promise<void> {
await AsyncStorage.setItem(KEY_PUSH_LAST_REGISTERED_AT, new Date().toISOString()); await AsyncStorage.setItem(KEY_PUSH_LAST_REGISTERED_AT, new Date().toISOString());
} }
export type LastRegisteredPushPayload = {
pushToken: string;
clientUserId: string;
env: 'dev' | 'prod';
appId: string;
savedAt: string; // ISO8601
};
export async function getLastRegisteredPushPayload(): Promise<LastRegisteredPushPayload | null> {
const raw = await AsyncStorage.getItem(KEY_PUSH_LAST_REGISTERED_PAYLOAD);
if (!raw) return null;
try {
const obj = JSON.parse(raw) as Partial<LastRegisteredPushPayload>;
if (!obj || typeof obj !== 'object') return null;
if (!obj.pushToken || !obj.clientUserId || !obj.env || !obj.appId || !obj.savedAt) return null;
if (obj.env !== 'dev' && obj.env !== 'prod') return null;
return obj as LastRegisteredPushPayload;
} catch {
return null;
}
}
export async function setLastRegisteredPushPayload(payload: Omit<LastRegisteredPushPayload, 'savedAt'>): Promise<void> {
const savedAt = new Date().toISOString();
const full: LastRegisteredPushPayload = { ...payload, savedAt };
await AsyncStorage.setItem(KEY_PUSH_LAST_REGISTERED_PAYLOAD, JSON.stringify(full));
// 同时写入旧 key便于兼容老逻辑/快速排查
await setLastRegisteredPushToken(payload.pushToken);
}
export type RecoFeedCacheItem = { export type RecoFeedCacheItem = {
content_id: number; content_id: number;
text: string; text: string;

Binary file not shown.

Binary file not shown.