首页
/ 深入解析hyochan/expo-iap项目中的完整应用内购买商店实现

深入解析hyochan/expo-iap项目中的完整应用内购买商店实现

2025-07-02 10:30:46作者:羿妍玫Ivan

前言

在移动应用开发中,应用内购买(IAP)是变现的重要方式之一。hyochan/expo-iap项目为React Native开发者提供了跨平台的IAP解决方案。本文将深入解析该项目中完整应用内购买商店的实现方式,帮助开发者理解核心概念和最佳实践。

核心概念

1. 产品类型

应用内购买主要分为两种类型:

  • 消耗型产品:如游戏中的金币、道具等,可多次购买
  • 订阅型产品:如会员服务,通常有周期性收费

2. 平台差异

iOS和Android平台的IAP实现存在显著差异:

  • 购买API调用方式不同
  • 收据验证机制不同
  • 产品信息结构不同

实现步骤详解

1. 初始化IAP连接

const {
  connected,
  products,
  subscriptions,
  currentPurchase,
  currentPurchaseError,
  getProducts,
  getSubscriptions,
  requestPurchase,
  finishTransaction,
  validateReceipt,
} = useIAP();

这段代码初始化了IAP连接,获取了所有必要的功能方法。

2. 获取产品列表

useEffect(() => {
  if (!connected) return;

  const initializeStore = async () => {
    try {
      await getProducts(productSkus);
      await getSubscriptions(subscriptionSkus);
    } catch (error) {
      console.error('Failed to initialize store:', error);
    }
  };

  initializeStore();
}, [connected]);

在连接建立后,立即获取产品列表和订阅列表。

3. 处理购买请求

const handlePurchase = async (productId) => {
  try {
    if (Platform.OS === 'ios') {
      await requestPurchase({
        request: {
          sku: productId,
          andDangerouslyFinishTransactionAutomaticallyIOS: false,
        },
      });
    } else {
      await requestPurchase({
        request: {skus: [productId]},
      });
    }
  } catch (error) {
    console.error('Purchase failed:', error);
  }
};

注意iOS和Android平台API调用的差异。

4. 完成交易流程

useEffect(() => {
  if (currentPurchase) {
    const completePurchase = async () => {
      try {
        const isValid = await validateReceipt(currentPurchase.id);
        
        if (isValid) {
          await finishTransaction({
            purchase: currentPurchase,
            isConsumable: true,
          });
          
          console.log('Purchase completed successfully!');
        }
      } catch (error) {
        console.error('Failed to complete purchase:', error);
      }
    };

    completePurchase();
  }
}, [currentPurchase]);

收据验证是确保交易安全的关键步骤。

高级实现细节

1. 收据验证

const validatePurchaseReceipt = useCallback(
  async (productId, purchase, validateReceiptFn) => {
    try {
      if (Platform.OS === 'ios') {
        const validationResult = await validateReceiptFn(productId);
        return validationResult.isValid;
      } else if (Platform.OS === 'android') {
        const purchaseToken = purchase.purchaseTokenAndroid;
        const packageName = purchase.packageNameAndroid || 'your.package.name';
        const isSub = subscriptionSkus.includes(productId);

        if (!purchaseToken) {
          console.error('Purchase token is missing for Android purchase');
          return false;
        }

        const validationResult = await validateReceiptFn(productId, {
          packageName,
          productToken: purchaseToken,
          isSub,
        });

        return validationResult.isValid;
      }
      return true;
    } catch (validationError) {
      console.error('Error during receipt validation:', validationError);
      return true;
    }
  },
  [],
);

2. 数据库记录

const recordPurchaseInDatabase = useCallback(
  async (purchase, productId, productsList, subscriptionsList) => {
    try {
      const transactionId = Platform.OS === 'ios'
        ? purchase.transactionId || ''
        : purchase.purchaseTokenAndroid || '';

      // 提取价格和货币信息
      let price = 0;
      let currency = 'USD';
      const product = productsList.find(p => p.id === productId) ||
                    subscriptionsList.find(s => s.id === productId);

      if (product) {
        // 处理iOS和Android不同的价格结构
        // ...
      }

      // 保存到数据库
      await savePurchaseToDatabase({
        productId,
        amount: price,
        currency,
        paymentMethod: Platform.OS,
        transactionId,
        metadata: purchase,
      });
    } catch (dbError) {
      console.error('Error recording purchase in database:', dbError);
    }
  },
  [],
);

3. 订阅状态管理

const updatePremiumStatus = useCallback(async () => {
  try {
    await checkPremiumStatus();

    if (!subscriptionAlertShown.current) {
      subscriptionAlertShown.current = true;
      InteractionManager.runAfterInteractions(() => {
        Alert.alert(
          'Thank You!',
          'Your premium subscription has been activated.',
        );
      });
    }
  } catch (error) {
    console.error('Error updating premium status:', error);
  }
}, []);

最佳实践

  1. 始终验证收据:防止欺诈交易
  2. 正确处理平台差异:iOS和Android需要不同的处理方式
  3. 完善的错误处理:特别是用户取消购买的情况
  4. 清晰的用户反馈:购买成功或失败时提供明确提示
  5. 数据库记录:保存交易记录用于对账和分析

常见问题解决方案

  1. 连接失败:检查网络连接和IAP配置
  2. 产品加载失败:确认产品ID是否正确配置
  3. 收据验证失败:检查服务器端验证逻辑
  4. 交易未完成:确保调用了finishTransaction

总结

hyochan/expo-iap项目提供了完整的应用内购买解决方案,通过本文的解析,开发者可以理解其核心实现逻辑和最佳实践。关键点包括正确处理平台差异、完善的收据验证机制、清晰的用户反馈流程等。这些知识将帮助开发者在自己的应用中实现安全可靠的应用内购买功能。

登录后查看全文
热门项目推荐

热门内容推荐

最新内容推荐

项目优选

收起
ohos_react_nativeohos_react_native
React Native鸿蒙化仓库
C++
176
260
RuoYi-Vue3RuoYi-Vue3
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
858
507
openGauss-serveropenGauss-server
openGauss kernel ~ openGauss is an open source relational database management system
C++
129
182
openHiTLSopenHiTLS
旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件,通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求,让密码技术应用更简单,同时探索后量子等先进算法创新实践,构建密码前沿技术底座!
C
255
299
ShopXO开源商城ShopXO开源商城
🔥🔥🔥ShopXO企业级免费开源商城系统,可视化DIY拖拽装修、包含PC、H5、多端小程序(微信+支付宝+百度+头条&抖音+QQ+快手)、APP、多仓库、多商户、多门店、IM客服、进销存,遵循MIT开源协议发布、基于ThinkPHP8框架研发
JavaScript
93
15
Cangjie-ExamplesCangjie-Examples
本仓将收集和展示高质量的仓颉示例代码,欢迎大家投稿,让全世界看到您的妙趣设计,也让更多人通过您的编码理解和喜爱仓颉语言。
Cangjie
331
1.08 K
HarmonyOS-ExamplesHarmonyOS-Examples
本仓将收集和展示仓颉鸿蒙应用示例代码,欢迎大家投稿,在仓颉鸿蒙社区展现你的妙趣设计!
Cangjie
397
370
note-gennote-gen
一款跨平台的 Markdown AI 笔记软件,致力于使用 AI 建立记录和写作的桥梁。
TSX
83
4
CangjieCommunityCangjieCommunity
为仓颉编程语言开发者打造活跃、开放、高质量的社区环境
Markdown
1.07 K
0
kernelkernel
deepin linux kernel
C
21
5