diff --git a/MeAgent/ios/app/app.entitlements b/MeAgent/ios/app/app.entitlements
index 018a6e20..0675789a 100644
--- a/MeAgent/ios/app/app.entitlements
+++ b/MeAgent/ios/app/app.entitlements
@@ -4,5 +4,9 @@
aps-environment
development
+ com.apple.developer.in-app-payments
+
+ merchant.com.valuefrontier.meagent
+
\ No newline at end of file
diff --git a/MeAgent/navigation/Screens.js b/MeAgent/navigation/Screens.js
index bd7185a5..d3d7897c 100644
--- a/MeAgent/navigation/Screens.js
+++ b/MeAgent/navigation/Screens.js
@@ -62,6 +62,9 @@ import MemberList from "../src/screens/Community/MemberList";
// 新个人中心页面
import { ProfileScreen as NewProfileScreen } from "../src/screens/Profile";
+// 订阅管理页面
+import { SubscriptionScreen } from "../src/screens/Subscription";
+
// 认证页面
import { LoginScreen } from "../src/screens/Auth";
@@ -510,6 +513,13 @@ function NewProfileStack(props) {
cardStyle: { backgroundColor: "#0A0A0F" },
}}
/>
+
);
}
diff --git a/MeAgent/src/screens/Profile/ProfileScreen.js b/MeAgent/src/screens/Profile/ProfileScreen.js
index b89e6f83..68d8d306 100644
--- a/MeAgent/src/screens/Profile/ProfileScreen.js
+++ b/MeAgent/src/screens/Profile/ProfileScreen.js
@@ -354,6 +354,8 @@ const ProfileScreen = () => {
const handleMenuItemPress = useCallback((item) => {
if (item.route === 'WatchlistDrawer') {
navigation.navigate('WatchlistDrawer');
+ } else if (item.route === 'Subscription') {
+ navigation.navigate('Subscription');
} else if (item.route === 'Settings') {
navigation.navigate('SettingsDrawer');
} else if (item.route === 'About') {
diff --git a/MeAgent/src/screens/Subscription/SubscriptionScreen.js b/MeAgent/src/screens/Subscription/SubscriptionScreen.js
new file mode 100644
index 00000000..21d6c2fe
--- /dev/null
+++ b/MeAgent/src/screens/Subscription/SubscriptionScreen.js
@@ -0,0 +1,611 @@
+/**
+ * 订阅管理页面
+ * iOS 苹果内购订阅功能
+ */
+
+import React, { useState, useEffect, useCallback } from 'react';
+import {
+ StyleSheet,
+ ScrollView,
+ Alert,
+ Platform,
+ Linking,
+} from 'react-native';
+import {
+ Box,
+ VStack,
+ HStack,
+ Text,
+ Icon,
+ Pressable,
+ Spinner,
+ Button,
+ Badge,
+ Divider,
+} from 'native-base';
+import { Ionicons, MaterialCommunityIcons } from '@expo/vector-icons';
+import { LinearGradient } from 'expo-linear-gradient';
+import { useNavigation } from '@react-navigation/native';
+import { SafeAreaView } from 'react-native-safe-area-context';
+
+import { useAuth } from '../../contexts/AuthContext';
+import { IAP_PRODUCTS, getProductByPlanAndCycle, iapService } from '../../services/iapService';
+
+// 订阅计划配置
+const SUBSCRIPTION_PLANS = [
+ {
+ name: 'pro',
+ displayName: 'Pro 专业版',
+ icon: 'diamond-outline',
+ color: '#7C3AED',
+ gradientColors: ['#7C3AED', '#A855F7'],
+ description: '专业投资者的首选',
+ features: [
+ '事件关联股票深度分析',
+ '历史事件智能对比复盘',
+ '事件概念关联与挖掘',
+ '概念板块个股追踪',
+ '概念深度研报与解读',
+ '个股异动实时预警',
+ ],
+ pricingOptions: [
+ { cycleKey: 'monthly', label: '月付', months: 1, price: 299, discount: 0 },
+ { cycleKey: 'quarterly', label: '季付', months: 3, price: 799, originalPrice: 897, discount: 11 },
+ { cycleKey: 'semiannual', label: '半年付', months: 6, price: 1499, originalPrice: 1794, discount: 16 },
+ { cycleKey: 'yearly', label: '年付', months: 12, price: 2699, originalPrice: 3588, discount: 25 },
+ ],
+ },
+ {
+ name: 'max',
+ displayName: 'Max 旗舰版',
+ icon: 'crown-outline',
+ color: '#D4AF37',
+ gradientColors: ['#D4AF37', '#F5D85A'],
+ description: '重度用户的极致体验',
+ popular: true,
+ features: [
+ '包含Pro版全部功能',
+ '事件传导链路智能分析',
+ '概念演变时间轴追溯',
+ '个股全方位深度研究',
+ '价小前投研助手无限使用',
+ '新功能优先体验权',
+ '专属客服一对一服务',
+ ],
+ pricingOptions: [
+ { cycleKey: 'monthly', label: '月付', months: 1, price: 599, discount: 0 },
+ { cycleKey: 'quarterly', label: '季付', months: 3, price: 1599, originalPrice: 1797, discount: 11 },
+ { cycleKey: 'semiannual', label: '半年付', months: 6, price: 2999, originalPrice: 3594, discount: 17 },
+ { cycleKey: 'yearly', label: '年付', months: 12, price: 5399, originalPrice: 7188, discount: 25 },
+ ],
+ },
+];
+
+// 周期选择按钮组件
+const CycleSelector = ({ cycles, selectedCycle, onSelect }) => {
+ return (
+
+ {cycles.map((cycle) => (
+ onSelect(cycle.cycleKey)}
+ mb={2}
+ >
+
+
+ {cycle.label}
+
+ {cycle.discount > 0 && (
+
+
+ 省{cycle.discount}%
+
+
+ )}
+
+
+ ))}
+
+ );
+};
+
+// 价格显示组件
+const PriceDisplay = ({ plan, selectedCycle }) => {
+ const option = plan.pricingOptions.find(o => o.cycleKey === selectedCycle);
+ if (!option) return null;
+
+ return (
+
+
+ ¥
+ {option.price}
+ /{option.label}
+
+ {option.originalPrice && (
+
+
+ 原价 ¥{option.originalPrice}
+
+
+ 立省 ¥{option.originalPrice - option.price}
+
+
+ )}
+
+ 相当于 ¥{(option.price / option.months).toFixed(0)}/月
+
+
+ );
+};
+
+// 功能列表组件
+const FeatureList = ({ features, color }) => {
+ return (
+
+ {features.map((feature, index) => (
+
+
+
+ {feature}
+
+
+ ))}
+
+ );
+};
+
+// 订阅卡片组件
+const PlanCard = ({ plan, selectedCycle, onSelectCycle, onSubscribe, isCurrentPlan, loading }) => {
+ const currentOption = plan.pricingOptions.find(o => o.cycleKey === selectedCycle);
+
+ return (
+
+ {/* 热门标签 */}
+ {plan.popular && (
+
+
+
+ 最受欢迎
+
+
+
+ )}
+
+ {/* 卡片标题区域 */}
+
+
+
+
+
+ {plan.displayName}
+
+
+ {plan.description}
+
+
+
+
+
+ {/* 卡片内容 */}
+
+ {/* 周期选择 */}
+
+
+ {/* 价格显示 */}
+
+
+ {/* 功能列表 */}
+
+
+ {/* 订阅按钮 */}
+ onSubscribe(plan, selectedCycle)}
+ disabled={loading}
+ >
+
+ {loading ? (
+
+ ) : (
+
+ {isCurrentPlan ? '续费' : `订阅${plan.displayName}`}
+
+ )}
+
+
+
+ {/* 自动续费说明 */}
+
+ 自动续费,可随时取消
+
+
+
+ );
+};
+
+// 当前订阅状态卡片
+const CurrentSubscriptionCard = ({ subscription, onManage }) => {
+ if (!subscription || !subscription.is_active) {
+ return null;
+ }
+
+ const getPlanInfo = () => {
+ if (subscription.type === 'max') {
+ return { name: 'Max 旗舰版', color: '#D4AF37', icon: 'crown-outline' };
+ }
+ if (subscription.type === 'pro') {
+ return { name: 'Pro 专业版', color: '#7C3AED', icon: 'diamond-outline' };
+ }
+ return { name: '会员', color: '#3B82F6', icon: 'star-outline' };
+ };
+
+ const planInfo = getPlanInfo();
+
+ return (
+
+
+
+
+
+
+
+
+
+ {planInfo.name}
+
+
+ 使用中
+
+
+ {subscription.end_date && (
+
+ 到期时间: {new Date(subscription.end_date).toLocaleDateString('zh-CN')}
+
+ )}
+
+
+
+ 管理
+
+
+
+ );
+};
+
+// 主页面组件
+const SubscriptionScreen = () => {
+ const navigation = useNavigation();
+ const { user, subscription, refreshUser } = useAuth();
+
+ const [selectedCycles, setSelectedCycles] = useState({
+ pro: 'yearly',
+ max: 'yearly',
+ });
+ const [loading, setLoading] = useState(false);
+ const [loadingPlan, setLoadingPlan] = useState(null);
+
+ // 初始化 IAP 服务
+ useEffect(() => {
+ if (Platform.OS === 'ios') {
+ iapService.initialize();
+ }
+
+ return () => {
+ iapService.cleanup();
+ };
+ }, []);
+
+ // 处理周期选择
+ const handleCycleSelect = useCallback((planName, cycle) => {
+ setSelectedCycles(prev => ({
+ ...prev,
+ [planName]: cycle,
+ }));
+ }, []);
+
+ // 处理订阅
+ const handleSubscribe = useCallback(async (plan, cycle) => {
+ if (!user) {
+ Alert.alert(
+ '请先登录',
+ '登录后即可订阅会员服务',
+ [
+ { text: '取消', style: 'cancel' },
+ {
+ text: '去登录',
+ onPress: () => navigation.getParent()?.navigate('Login'),
+ },
+ ]
+ );
+ return;
+ }
+
+ if (Platform.OS !== 'ios') {
+ Alert.alert('提示', '苹果支付仅支持 iOS 设备');
+ return;
+ }
+
+ const productInfo = getProductByPlanAndCycle(plan.name, cycle);
+ if (!productInfo) {
+ Alert.alert('错误', '无效的订阅选项');
+ return;
+ }
+
+ setLoadingPlan(plan.name);
+ setLoading(true);
+
+ try {
+ // 发起购买
+ const purchase = await iapService.purchaseProduct(productInfo.productId);
+
+ // 验证收据并激活订阅
+ if (purchase && purchase.transactionReceipt) {
+ const result = await iapService.verifyAndActivateSubscription(
+ purchase.transactionReceipt,
+ productInfo.productId
+ );
+
+ if (result.success) {
+ // 完成交易(传入完整的 purchase 对象)
+ await iapService.finishPurchase(purchase);
+
+ // 刷新用户信息
+ await refreshUser();
+
+ Alert.alert(
+ '订阅成功',
+ `您已成功订阅${plan.displayName}!`,
+ [{ text: '好的', onPress: () => navigation.goBack() }]
+ );
+ }
+ }
+ } catch (error) {
+ console.error('[SubscriptionScreen] 订阅失败:', error);
+ Alert.alert(
+ '订阅失败',
+ error.message || '请稍后重试',
+ [{ text: '确定' }]
+ );
+ } finally {
+ setLoading(false);
+ setLoadingPlan(null);
+ }
+ }, [user, navigation, refreshUser]);
+
+ // 管理订阅(打开苹果订阅管理页面)
+ const handleManageSubscription = useCallback(() => {
+ // iOS 订阅管理页面 URL
+ Linking.openURL('https://apps.apple.com/account/subscriptions');
+ }, []);
+
+ // 恢复购买
+ const handleRestorePurchases = useCallback(async () => {
+ if (Platform.OS !== 'ios') {
+ Alert.alert('提示', '恢复购买仅支持 iOS 设备');
+ return;
+ }
+
+ setLoading(true);
+ try {
+ const purchases = await iapService.restorePurchases();
+
+ if (purchases && purchases.length > 0) {
+ // 验证最新的购买记录
+ const latestPurchase = purchases[0];
+ if (latestPurchase.transactionReceipt) {
+ const productInfo = Object.values(IAP_PRODUCTS).find(
+ p => p.productId === latestPurchase.productId
+ );
+
+ if (productInfo) {
+ await iapService.verifyAndActivateSubscription(
+ latestPurchase.transactionReceipt,
+ latestPurchase.productId
+ );
+
+ await refreshUser();
+ Alert.alert('恢复成功', '您的订阅已恢复');
+ }
+ }
+ } else {
+ Alert.alert('提示', '没有找到可恢复的购买记录');
+ }
+ } catch (error) {
+ console.error('[SubscriptionScreen] 恢复购买失败:', error);
+ Alert.alert('恢复失败', error.message || '请稍后重试');
+ } finally {
+ setLoading(false);
+ }
+ }, [refreshUser]);
+
+ return (
+
+
+ {/* 背景装饰 */}
+
+
+
+ {/* 标题栏 */}
+
+ navigation.goBack()} hitSlop={10}>
+
+
+
+ 订阅管理
+
+ {/* 占位,保持标题居中 */}
+
+
+ {/* 当前订阅状态 */}
+
+
+ {/* 标题 */}
+
+
+ 订阅方案
+
+
+ 开启智能投资之旅
+
+
+ 选择适合您的会员计划,解锁全部高级功能
+
+
+
+ {/* 订阅卡片 */}
+ {SUBSCRIPTION_PLANS.map((plan) => (
+ handleCycleSelect(plan.name, cycle)}
+ onSubscribe={handleSubscribe}
+ isCurrentPlan={subscription?.type === plan.name && subscription?.is_active}
+ loading={loading && loadingPlan === plan.name}
+ />
+ ))}
+
+ {/* 恢复购买按钮 */}
+
+
+
+
+ 恢复购买
+
+
+
+
+ {/* 说明文字 */}
+
+
+ 订阅将通过您的 Apple ID 账户付款
+
+
+ 除非在当前订阅期结束前至少 24 小时关闭自动续订,否则将自动续订
+
+
+ 您可以在 App Store 账户设置中管理和取消订阅
+
+
+
+ Linking.openURL('https://valuefrontier.cn/htmls/pro-member-agreement.html')}>
+
+ 服务协议
+
+
+ Linking.openURL('https://valuefrontier.cn/privacy')}>
+
+ 隐私政策
+
+
+
+
+
+ {/* 底部间距 */}
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ cardHeader: {
+ paddingVertical: 16,
+ paddingHorizontal: 20,
+ },
+ popularBadge: {
+ paddingHorizontal: 12,
+ paddingVertical: 4,
+ borderBottomLeftRadius: 10,
+ },
+ subscribeButton: {
+ paddingVertical: 14,
+ borderRadius: 12,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+});
+
+export default SubscriptionScreen;
diff --git a/MeAgent/src/screens/Subscription/index.js b/MeAgent/src/screens/Subscription/index.js
new file mode 100644
index 00000000..f60859b6
--- /dev/null
+++ b/MeAgent/src/screens/Subscription/index.js
@@ -0,0 +1,2 @@
+export { default as SubscriptionScreen } from './SubscriptionScreen';
+export { default } from './SubscriptionScreen';
diff --git a/MeAgent/src/services/api.js b/MeAgent/src/services/api.js
index a5f280c9..866d1653 100644
--- a/MeAgent/src/services/api.js
+++ b/MeAgent/src/services/api.js
@@ -13,6 +13,49 @@ export const API_BASE = 'https://valuefrontier-1308417363.cos-website.ap-shangha
// Token 存储键名(与 authService 保持一致)
const ACCESS_TOKEN_KEY = '@auth_access_token';
+// 🍪 Cookie 存储键名(用于手动管理 Cookie)
+const SESSION_COOKIE_KEY = '@session_cookie';
+
+/**
+ * 从响应头中提取 Set-Cookie
+ */
+const extractSetCookie = (response) => {
+ // React Native 的 fetch 可能无法直接获取 Set-Cookie
+ // 但我们尝试获取
+ const setCookie = response.headers.get('set-cookie');
+ if (setCookie) {
+ console.log('[API] 收到 Set-Cookie:', setCookie.substring(0, 50) + '...');
+ return setCookie;
+ }
+ return null;
+};
+
+/**
+ * 保存 Cookie 到 AsyncStorage
+ */
+const saveCookie = async (cookie) => {
+ if (cookie) {
+ try {
+ await AsyncStorage.setItem(SESSION_COOKIE_KEY, cookie);
+ console.log('[API] Cookie 已保存');
+ } catch (error) {
+ console.error('[API] 保存 Cookie 失败:', error);
+ }
+ }
+};
+
+/**
+ * 从 AsyncStorage 获取 Cookie
+ */
+const getCookie = async () => {
+ try {
+ return await AsyncStorage.getItem(SESSION_COOKIE_KEY);
+ } catch (error) {
+ console.error('[API] 读取 Cookie 失败:', error);
+ return null;
+ }
+};
+
/**
* 通用 API 请求函数
* @param {string} url - API 路径
@@ -29,6 +72,9 @@ export const apiRequest = async (url, options = {}) => {
// 获取存储的 access_token
const accessToken = await AsyncStorage.getItem(ACCESS_TOKEN_KEY);
+ // 🍪 获取存储的 Cookie
+ const storedCookie = await getCookie();
+
// 构建请求头
const headers = {
'Content-Type': 'application/json',
@@ -40,6 +86,12 @@ export const apiRequest = async (url, options = {}) => {
headers['Authorization'] = `Bearer ${accessToken}`;
}
+ // 🍪 手动添加 Cookie header(React Native 真机可能需要)
+ if (storedCookie) {
+ headers['Cookie'] = storedCookie;
+ console.log('[API] 添加 Cookie header');
+ }
+
const response = await fetch(fullUrl, {
...options,
headers,
@@ -47,6 +99,12 @@ export const apiRequest = async (url, options = {}) => {
credentials: 'include',
});
+ // 🍪 尝试从响应中提取并保存 Cookie
+ const setCookie = extractSetCookie(response);
+ if (setCookie) {
+ await saveCookie(setCookie);
+ }
+
// 处理 403 权限不足的情况
if (response.status === 403) {
const errorData = await response.json().catch(() => ({}));
@@ -75,4 +133,16 @@ export const apiRequest = async (url, options = {}) => {
}
};
+/**
+ * 清除存储的 Cookie(退出登录时调用)
+ */
+export const clearSessionCookie = async () => {
+ try {
+ await AsyncStorage.removeItem(SESSION_COOKIE_KEY);
+ console.log('[API] Cookie 已清除');
+ } catch (error) {
+ console.error('[API] 清除 Cookie 失败:', error);
+ }
+};
+
export default apiRequest;
diff --git a/MeAgent/src/services/authService.js b/MeAgent/src/services/authService.js
index 08054e10..0d601c78 100644
--- a/MeAgent/src/services/authService.js
+++ b/MeAgent/src/services/authService.js
@@ -4,7 +4,7 @@
*/
import AsyncStorage from '@react-native-async-storage/async-storage';
-import { apiRequest } from './api';
+import { apiRequest, clearSessionCookie } from './api';
// 存储键名
const STORAGE_KEYS = {
@@ -89,18 +89,27 @@ export const authService = {
*/
getCurrentUser: async (clearOnFail = false) => {
try {
- const response = await apiRequest('/api/account/user-info');
+ // ✅ 修复:使用正确的 API 端点 /api/auth/session
+ const response = await apiRequest('/api/auth/session');
- if (response.success && response.user) {
+ // 🔍 调试日志:打印完整响应
+ console.log('[AuthService] /api/auth/session 响应:', JSON.stringify(response, null, 2));
+
+ if (response.success && response.isAuthenticated && response.user) {
// 更新本地存储
await AsyncStorage.setItem(STORAGE_KEYS.USER_INFO, JSON.stringify(response.user));
await AsyncStorage.setItem(STORAGE_KEYS.IS_LOGGED_IN, 'true');
+
+ // 🔍 调试日志:打印用户订阅信息
+ console.log('[AuthService] 用户订阅类型:', response.user.subscription_type);
+ console.log('[AuthService] 用户订阅状态:', response.user.subscription_status);
+
return response.user;
}
- // 如果返回 401/403,说明 token 无效
- if (response.status === 401 || response.status === 403) {
- console.warn('[AuthService] Token 无效,需要重新登录');
+ // 未认证或返回 401/403
+ if (!response.isAuthenticated || response.status === 401 || response.status === 403) {
+ console.warn('[AuthService] 未认证或 Token 无效,需要重新登录');
if (clearOnFail) {
await authService.clearLocalAuth();
}
@@ -142,6 +151,8 @@ export const authService = {
await AsyncStorage.removeItem(STORAGE_KEYS.USER_INFO);
await AsyncStorage.removeItem(STORAGE_KEYS.IS_LOGGED_IN);
await AsyncStorage.removeItem(STORAGE_KEYS.ACCESS_TOKEN);
+ // 🍪 同时清除 Cookie
+ await clearSessionCookie();
} catch (error) {
console.error('[AuthService] 清除本地状态失败:', error);
}
diff --git a/MeAgent/src/services/iapService.js b/MeAgent/src/services/iapService.js
new file mode 100644
index 00000000..52a2913c
--- /dev/null
+++ b/MeAgent/src/services/iapService.js
@@ -0,0 +1,441 @@
+/**
+ * 苹果内购服务 (In-App Purchase Service)
+ * 处理 iOS 订阅购买逻辑
+ *
+ * 使用 react-native-iap 库实现苹果支付
+ */
+
+import { Platform } from 'react-native';
+import {
+ initConnection,
+ endConnection,
+ getProducts,
+ getSubscriptions,
+ requestSubscription,
+ getAvailablePurchases,
+ finishTransaction,
+ purchaseUpdatedListener,
+ purchaseErrorListener,
+ flushFailedPurchasesCachedAsPendingAndroid,
+} from 'react-native-iap';
+import { API_BASE_URL } from './api';
+
+// 苹果内购产品 ID 配置
+// 格式: com.valuefrontier.meagent.{plan}_{cycle}
+export const IAP_PRODUCTS = {
+ // Pro 专业版
+ pro_monthly: {
+ productId: 'com.valuefrontier.meagent.pro_monthly',
+ plan: 'pro',
+ cycle: 'monthly',
+ months: 1,
+ price: 299, // 人民币价格(供显示,实际以苹果返回为准)
+ },
+ pro_quarterly: {
+ productId: 'com.valuefrontier.meagent.pro_quarterly',
+ plan: 'pro',
+ cycle: 'quarterly',
+ months: 3,
+ price: 799,
+ },
+ pro_semiannual: {
+ productId: 'com.valuefrontier.meagent.pro_semiannual',
+ plan: 'pro',
+ cycle: 'semiannual',
+ months: 6,
+ price: 1499,
+ },
+ pro_yearly: {
+ productId: 'com.valuefrontier.meagent.pro_yearly',
+ plan: 'pro',
+ cycle: 'yearly',
+ months: 12,
+ price: 2699,
+ },
+ // Max 旗舰版
+ max_monthly: {
+ productId: 'com.valuefrontier.meagent.max_monthly',
+ plan: 'max',
+ cycle: 'monthly',
+ months: 1,
+ price: 599,
+ },
+ max_quarterly: {
+ productId: 'com.valuefrontier.meagent.max_quarterly',
+ plan: 'max',
+ cycle: 'quarterly',
+ months: 3,
+ price: 1599,
+ },
+ max_semiannual: {
+ productId: 'com.valuefrontier.meagent.max_semiannual',
+ plan: 'max',
+ cycle: 'semiannual',
+ months: 6,
+ price: 2999,
+ },
+ max_yearly: {
+ productId: 'com.valuefrontier.meagent.max_yearly',
+ plan: 'max',
+ cycle: 'yearly',
+ months: 12,
+ price: 5399,
+ },
+};
+
+// 获取所有产品 ID 列表
+export const getAllProductIds = () => {
+ return Object.values(IAP_PRODUCTS).map(p => p.productId);
+};
+
+// 根据计划和周期获取产品信息
+export const getProductByPlanAndCycle = (plan, cycle) => {
+ const key = `${plan}_${cycle}`;
+ return IAP_PRODUCTS[key] || null;
+};
+
+// 根据产品 ID 获取产品信息
+export const getProductById = (productId) => {
+ return Object.values(IAP_PRODUCTS).find(p => p.productId === productId) || null;
+};
+
+/**
+ * IAP 服务类
+ * 使用 react-native-iap 实现苹果内购功能
+ */
+class IAPService {
+ constructor() {
+ this.isInitialized = false;
+ this.products = [];
+ this.subscriptions = [];
+ this.purchaseUpdateSubscription = null;
+ this.purchaseErrorSubscription = null;
+ }
+
+ /**
+ * 初始化 IAP 服务
+ * @returns {Promise}
+ */
+ async initialize() {
+ if (Platform.OS !== 'ios') {
+ console.log('[IAPService] 非 iOS 平台,跳过初始化');
+ return false;
+ }
+
+ if (this.isInitialized) {
+ console.log('[IAPService] 已经初始化,跳过');
+ return true;
+ }
+
+ try {
+ // 初始化连接
+ const result = await initConnection();
+ console.log('[IAPService] IAP 连接初始化成功:', result);
+
+ // 获取订阅产品信息
+ const productIds = getAllProductIds();
+ console.log('[IAPService] 获取产品列表:', productIds);
+
+ try {
+ // 对于订阅类产品,使用 getSubscriptions
+ this.subscriptions = await getSubscriptions({ skus: productIds });
+ console.log('[IAPService] 获取到订阅产品:', this.subscriptions.length);
+ } catch (productError) {
+ console.warn('[IAPService] 获取产品信息失败(可能产品未在 App Store Connect 配置):', productError);
+ // 继续初始化,不阻止流程
+ }
+
+ // 设置购买监听器
+ this.setupPurchaseListeners();
+
+ this.isInitialized = true;
+ console.log('[IAPService] IAP 服务初始化完成');
+ return true;
+ } catch (error) {
+ console.error('[IAPService] 初始化失败:', error);
+ return false;
+ }
+ }
+
+ /**
+ * 设置购买事件监听器
+ */
+ setupPurchaseListeners() {
+ // 移除旧的监听器
+ if (this.purchaseUpdateSubscription) {
+ this.purchaseUpdateSubscription.remove();
+ }
+ if (this.purchaseErrorSubscription) {
+ this.purchaseErrorSubscription.remove();
+ }
+
+ // 购买成功/更新监听器
+ this.purchaseUpdateSubscription = purchaseUpdatedListener(async (purchase) => {
+ console.log('[IAPService] 购买更新:', purchase);
+
+ if (purchase.transactionReceipt) {
+ try {
+ // 验证收据
+ const verifyResult = await this.verifyAndActivateSubscription(
+ purchase.transactionReceipt,
+ purchase.productId
+ );
+
+ if (verifyResult.success) {
+ // 完成交易
+ await finishTransaction({ purchase, isConsumable: false });
+ console.log('[IAPService] 交易完成');
+ }
+ } catch (error) {
+ console.error('[IAPService] 处理购买失败:', error);
+ }
+ }
+ });
+
+ // 购买错误监听器
+ this.purchaseErrorSubscription = purchaseErrorListener((error) => {
+ console.error('[IAPService] 购买错误:', error);
+ });
+
+ console.log('[IAPService] 购买监听器已设置');
+ }
+
+ /**
+ * 获取可用产品列表(从苹果服务器获取最新价格)
+ * @returns {Promise}
+ */
+ async getAvailableProducts() {
+ if (!this.isInitialized) {
+ await this.initialize();
+ }
+
+ // 如果成功获取了苹果的产品信息,返回真实数据
+ if (this.subscriptions && this.subscriptions.length > 0) {
+ return this.subscriptions.map(subscription => {
+ const localProduct = getProductById(subscription.productId);
+ return {
+ ...localProduct,
+ productId: subscription.productId,
+ localizedPrice: subscription.localizedPrice,
+ price: subscription.price,
+ currency: subscription.currency,
+ title: subscription.title,
+ description: subscription.description,
+ };
+ });
+ }
+
+ // 否则返回本地配置的产品信息(用于测试或产品未配置时)
+ console.log('[IAPService] 使用本地产品配置');
+ return Object.values(IAP_PRODUCTS).map(product => ({
+ ...product,
+ localizedPrice: `¥${product.price}`,
+ currency: 'CNY',
+ }));
+ }
+
+ /**
+ * 发起订阅购买请求
+ * @param {string} productId - 产品 ID
+ * @returns {Promise