跳转至正文
教程

Capacitor 中的 Stripe 支付:Apple 新指南

学习如何在您的 Capacitor 应用中实现 Stripe Payment Links,以便根据 2025 年 5 月 1 日生效的 Apple 新指南处理数字商品支付。

Capacitor 中的 Stripe 支付:遵循 Apple 新指南的 Capgo 博客插图

遵循 Apple 新指南在 Capacitor 应用中实现 Stripe Payment Links

自 2025 年 5 月 1 日起,随着法院对以下案件的裁决,Apple 已对其 App Store Review Guidelines 进行了重大调整: Epic v. Apple 案。这些变化明确允许美国的 App 开发者为数字商品和服务提供外部支付方式的链接,为 Apple 的应用内购买系统提供了替代方案。

改变移动支付格局的史诗级之战

通往这一刻的道路漫长且充满争议。一切始于 2020 年 8 月,热门游戏 Fortnite 的开发商 Epic Games 通过推出绕过 Apple 30% 佣金的直接支付选项,蓄意违反了 Apple App Store 的指南。Apple 随即将 Fortnite 从 App Store 下架,Epic 则提起诉讼,挑战 Apple 对 iOS 应用分发和应用内支付的控制权。

经过多年的法律斗争、上诉和反诉,法院最终裁定 Apple 必须允许开发者引导用户使用应用外的其他支付方式。这一决定从根本上改变了 App Store 生态的经济模式,而该模式自 2008 年诞生以来一直沿用至今。

最终裁决:不再有上诉

此次裁决之所以意义重大,是因为它是最终裁决,无法再上诉。最高法院在 2025 年初拒绝受理 Apple 的上诉,使下级法院的判决成为最终定论。这意味着开发者可以放心地接入外部支付方式,因为 Apple 无法再通过法律挑战推翻这一决定。

法律保障平等待遇

最重要的是,裁决明确指出 Apple 不得歧视使用外部支付方式的应用。法院特别禁止 Apple 进行以下行为:

  1. 对使用外部支付方式的应用收取额外费用或施加额外限制
  2. 在搜索结果中给予仅使用 Apple IAP 系统的应用优先待遇或推荐位
  3. 通过技术手段降低外部支付体验,使其劣于 Apple 自有系统
  4. 施加超出基本消费者信息之外的繁重披露要求

这些明确的保护措施意味着开发者可以放心集成 Stripe 或其他外部支付提供商,而无需担心受到 Apple 的隐性报复或歧视。竞争环境已在法律层面实现公平,无论应用选择何种支付方式,Apple 都必须一视同仁。

该裁决代表了对 Apple “围墙花园”模式最重大的挑战之一,标志着移动应用变现方式的重大转变。对于长期诟病 Apple 30% 佣金(小微企业为 15%)的开发者来说,这一裁决为提高利润率和增强客户体验控制权提供了路径。

相比 Apple In-App Purchases,使用 Stripe 的财务优势

这一变化对开发者而言具有重大的财务影响:

  • 降低支付处理费用Apple 通常对应用内购买收取 30% 的佣金(小微企业为 15%),而 Stripe 的费用仅为每笔交易约 2.9% + $0.30。这一差异可以显著提升您的利润率。

  • 更快的结算速度:使用 Apple 时,通常需要等待 45-90 天才能收到资金。相比之下,Stripe 会在 2-3 个工作日内将款项存入您的银行账户。

  • 更简化的退款流程:直接通过 Stripe dashboard 处理退款,无需经过 Apple 复杂的退款系统。

这些成本节约和现金流的改善可能会带来颠覆性的变化,尤其是对于小型开发者和企业而言。

在本文中,我们将探讨如何在您的 Capacitor 应用中实现 Stripe Payment Links,以利用这些新规则,同时确保符合 Apple 的 最新指南.

此实现方案基于 Stripe 关于 Payment Links 的官方文档,并专门针对 Capacitor 应用进行了适配。

解读新指南

更新后的 App Store Review Guidelines 现在允许开发者将用户引导至外部网站进行支付处理,特别是针对数字产品和订阅服务。此变更目前仅适用于在美国 App Store 分发的应用。

需要了解的核心要点:

  1. 现在,您可以在应用内为数字商品链接到外部支付选项
  2. 这仅适用于美国 App Store 中的应用
  3. 您仍需遵守 Apple 的披露要求
  4. 您仍需负责所有客户支持和退款处理

让我们深入了解技术实现:

首先,在您的 Stripe Dashboard 中创建一个 Payment Link:

  1. 前往 Stripe Dashboard 中的 Payment Links 部分
  2. 点击“+ New”创建新的 Payment Link
  3. 定义您的产品或订阅详情
  4. 在“After payment”设置中,选择“Don’t show confirmation page”
  5. 将通用链接 (Universal Link) 设置为成功回调 URL(稍后我们会进行配置)
  6. 点击 “Create Link” 生成您的支付链接

若要在支付完成后将用户重定向回您的 App,请配置 Universal Links:

  1. 创建一个 apple-app-site-association 您域名下的文件:
{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appIDs": ["YOURTEAMID.com.yourdomain.yourapp"],
        "components": [
          {
            "/": "/checkout_redirect*",
            "comment": "Matches any URL whose path starts with /checkout_redirect"
          }
        ]
      }
    ]
  }
}
  1. 将此文件托管在 https://yourdomain.com/.well-known/apple-app-site-association

  2. 确保其以正确的 MIME 类型进行传输 application/json

  3. 通过添加相应的 entitlement 来配置您的 Capacitor App 以处理 Universal Links。首先,在您的 capacitor.config.ts:

import { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  // Your existing app configuration (appId, appName, etc.)
  plugins: {
    Geolocation: {
      // Request precise location access on iOS
      iosLocationAccuracy: 'reduced'
    }
  }
};

export default config;
  1. 在 Xcode 项目中添加 Associated Domains entitlement:
    • 打开您的 Xcode 项目
    • 选择您的 App Target
    • 前往“Signing & Capabilities”
    • 点击“+ Capability”并选择“Associated Domains”
    • 添加 applinks:yourdomain.com

步骤 3:创建备用页面

在重定向 URL 上创建一个备用页面,用于处理应用未安装的情况:

<!DOCTYPE html>
<html>
<head>
  <title>Redirecting...</title>
  <meta http-equiv="refresh" content="0;url=https://yourdomain.com/app-download">
</head>
<body>
  <p>Redirecting to download page...</p>
</body>
</html>

步骤 4:在您的 Capacitor 应用中实现支付按钮

现在,将支付按钮添加到您的应用中:

import { Capacitor } from '@capacitor/core';

export async function openPaymentLink(userEmail, userId) {
  // Use your actual Stripe payment link
  const baseUrl = 'https://buy.stripe.com/your_payment_link';
  
  // Add URL parameters to customize the experience
  const params = new URLSearchParams({
    prefilled_email: encodeURIComponent(userEmail),
    client_reference_id: userId
  });

  const fullUrl = `${baseUrl}?${params.toString()}`;
  
  // Simple window.open works in both web and Capacitor
  // Using _blank opens in Safari on iOS which is important for users with saved Stripe Link credentials
  window.open(fullUrl, '_blank');
}

为什么 Safari 至关重要:在 Safari 中打开支付链接(通过 window.open)而不是在应用内浏览器中打开,会更有优势,因为之前用 Stripe Link 保存过支付信息的用户,会自动带出已保存的凭据。这样结账体验更顺畅,用户无需重新输入信用卡信息,从而显著减少摩擦和弃单率。

配置您的应用,以便在用户被重定向回来时处理 Universal Links:

  1. 首先,安装 App 插件:
npm install @capacitor/app
  1. 在你的应用中注册 App 插件:
import { App } from '@capacitor/app';

// In your initialization code
App.addListener('appUrlOpen', (event) => {
  // Example URL: https://yourdomain.com/checkout_redirect?session_id=cs_test_...
  const url = new URL(event.url);
  
  if (url.pathname.startsWith('/checkout_redirect')) {
    // Extract any parameters you need
    const params = new URLSearchParams(url.search);
    const sessionId = params.get('session_id');
    
    // Handle successful payment
    if (sessionId) {
      // Verify the payment on your server if needed
      verifyPayment(sessionId);
      
      // Update UI to reflect successful purchase
      updatePurchaseStatus(true);
    }
  }
});

async function verifyPayment(sessionId) {
  // Call your backend to verify the payment
  // This is optional if you're relying on webhooks
}

function updatePurchaseStatus(success) {
  // Update your app UI to reflect purchase status
}

第 6 步:设置订单履约 Webhook

最后,在你的服务器上配置一个 webhook 来处理支付成功回调:

// Using Express.js as an example
const express = require('express');
const stripe = require('stripe')('sk_test_your_stripe_secret_key');
const app = express();

// Use raw body parser for webhook signature verification
app.post('/webhook', express.raw({type: 'application/json'}), async (req, res) => {
  const sig = req.headers['stripe-signature'];
  const webhookSecret = 'whsec_your_webhook_secret';
  
  let event;
  
  try {
    event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);
  } catch (err) {
    console.log(`Webhook Error: ${err.message}`);
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }
  
  // Handle the checkout.session.completed event
  if (event.type === 'checkout.session.completed') {
    const session = event.data.object;
    
    // Retrieve client_reference_id (your user ID)
    const userId = session.client_reference_id;
    
    // Grant access to the purchased content
    await grantAccess(userId, session.id);
  }
  
  res.status(200).send();
});

async function grantAccess(userId, sessionId) {
  // Your logic to grant access to the purchased content
  // This could be updating a database, sending a notification, etc.
}

app.listen(3000, () => console.log('Webhook server running on port 3000'));

Android 兼容性

我们需要明确一点:Epic 对阵 Apple 的裁决从根本上改变了移动支付格局。这不仅直接影响 iOS 应用,也为一直使用外部支付方式的 Android 开发者提供了更有力的支持。

现在,Android 开发者可以完全放心地实现外部支付方案。 Apple 裁决所创下的先例,实际上保护了跨平台的开发者免受未来潜在限制的影响。这一法院判决验证了许多 Android 开发者多年来一直在做的事情——提供手续费更低的替代支付选项。

Google Play Store 在外部支付方式方面的限制一直比 Apple 少,而随着法律先例的确立,在 Android 应用中集成 Stripe 或其他外部支付提供商几乎没有任何风险。你可以放心地进行这些开发,因为你拥有坚实的法律依据。

我们为 iOS 实现的方案在 Android 设备上几乎完全相同。由于 Google Play Store 对外部支付方式没有同样的限制,你可以直接使用相同的 Stripe Payment Links 方案,而无需特殊的披露对话框。

为了处理 Deep Linking(相当于 iOS 上的 Universal Links),你需要:

  1. 在您的 AndroidManifest.xml 以处理重定向 URL
  2. 创建一个 .well-known/assetlinks.json 域名下的文件,其中包含您应用详情
  3. 使用与分页列表相同的 appUrlOpen 监听逻辑,用于处理支付成功

Capacitor 的妙处在于,一旦您完成了平台特定的配置,实际的支付流程 code 在两个平台上都是一致的。

创建支付 UI

这是一个可以在您的 Capacitor 应用中使用的 Vue 支付按钮组件示例:

<template>
  <div class="payment-container">
    <div class="pricing-card">
      <h2 class="mb-4 text-xl font-bold">{{ product.name }}</h2>
      <p class="mb-6 text-gray-600">{{ product.description }}</p>
      <div class="mb-6 price-tag">
        <span class="text-2xl font-bold">${{ product.price }}</span>
        <span v-if="product.isSubscription" class="text-sm text-gray-500">/month</span>
      </div>
      <button 
        @click="handlePayment" 
        class="py-3 w-full font-medium text-white bg-indigo-600 rounded-lg transition-colors hover:bg-indigo-700"
      >
        Purchase Now
      </button>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { Dialog } from '@capacitor/dialog';

const props = defineProps({
  product: {
    type: Object,
    required: true
  },
  userEmail: {
    type: String,
    default: ''
  },
  userId: {
    type: String,
    required: true
  }
});

const isLoading = ref(false);

async function showExternalPaymentDisclosure() {
  const { value } = await Dialog.confirm({
    title: 'Leaving App for Payment',
    message: 'You are about to leave this app to make a payment. Apple is not responsible for the privacy or security of payments that are not made through the App Store. All payment-related issues, including refunds, must be handled by our support team.',
    okButtonTitle: 'Continue',
    cancelButtonTitle: 'Cancel'
  });
  
  return value;
}

async function openPaymentLink() {
  // Use your actual Stripe payment link
  const baseUrl = 'https://buy.stripe.com/your_payment_link';
  
  // Add URL parameters to customize the experience
  const params = new URLSearchParams({
    prefilled_email: encodeURIComponent(props.userEmail),
    client_reference_id: props.userId
  });

  const fullUrl = `${baseUrl}?${params.toString()}`;
  
  // Simple window.open works in both web and Capacitor
  // Using _blank opens in Safari on iOS which is important for users with saved Stripe Link credentials
  window.open(fullUrl, '_blank');
}

async function handlePayment() {
  isLoading.value = true;
  try {
    // Only show the disclosure on iOS
    if (window.Capacitor?.getPlatform() === 'ios') {
      const userConfirmed = await showExternalPaymentDisclosure();
      if (!userConfirmed) return;
    }
    
    await openPaymentLink();
  } catch (error) {
    console.error('Payment error:', error);
    await Dialog.alert({
      title: 'Payment Error',
      message: 'There was an error initiating the payment. Please try again.'
    });
  } finally {
    isLoading.value = false;
  }
}
</script>

处理不同地区

由于新的 Apple 指南仅适用于美国 App Store 的应用,您需要制定一套策略来检测用户所在地区并应用相应的支付方式。以下是使用 IP 地理位置检测的一种更可靠的方法:

import { Capacitor } from '@capacitor/core';

async function determinePaymentMethod() {
  // Always use Stripe for Android
  if (Capacitor.getPlatform() !== 'ios') {
    return 'external';
  }
  
  try {
    // Use a geolocation service to determine user's country
    const response = await fetch('https://ipapi.co/json/');
    const locationData = await response.json();
    
    // Check if the user is in the United States
    if (locationData.country_code === 'US') {
      return 'external'; // Can use Stripe Payment Links
    } else {
      return 'iap'; // Must use In-App Purchases
    }
  } catch (error) {
    console.error('Error detecting region:', error);
    return 'iap'; // Default to IAP to be safe
  }
}

export async function processPayment(product, userEmail, userId) {
  const paymentMethod = await determinePaymentMethod();
  
  if (paymentMethod === 'external') {
    // Use Stripe Payment Links
    await initiateExternalPayment(userEmail, userId);
  } else {
    // Use Apple's In-App Purchase
    await initiateInAppPurchase(product.appleProductId);
  }
}

此方法使用了免费的 ipapi.co 根据用户的 IP 地址确定其所在国家/地区的服务。你也可以使用 MaxMind 等其他地理位置服务,或在服务端执行此检查以增强安全性。

注意: 虽然这种方法可行,但需要记住 IP 地理位置定位并不总是 100% 准确。对于关键业务应用,请考虑使用多种检测方法,或允许用户手动选择其所在区域。

使用 Capacitor 插件实现更精准的定位检测

为了获得更准确的定位检测,你可以结合使用 Capacitor Geolocation 插件和 @capgo/capacitor-nativegeocoder,从而更精确地确定用户所在的国家/地区:

  1. 首先,安装所需的插件:
npm install @capacitor/geolocation @capgo/capacitor-nativegeocoder
  1. 在你的 Capacitor 项目中配置插件。将以下内容添加到你的 capacitor.config.ts:
import { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  // Your existing app configuration (appId, appName, etc.)
  plugins: {
    Geolocation: {
      // Request precise location access on iOS
      iosLocationAccuracy: 'reduced'
    }
  }
};

export default config;
  1. 实现基于位置的区域检测:
import { Capacitor } from '@capacitor/core';
import { Geolocation } from '@capacitor/geolocation';
import { NativeGeocoder } from '@capgo/capacitor-nativegeocoder';

async function isUserInUSA() {
  try {
    // Request permission first
    const permissionStatus = await Geolocation.requestPermissions();
    
    if (permissionStatus.location === 'granted') {
      // Get current position
      const position = await Geolocation.getCurrentPosition({
        timeout: 10000,
        enableHighAccuracy: false
      });
      
      // Use NativeGeocoder to reverse geocode the coordinates
      const results = await NativeGeocoder.reverseGeocode({
        latitude: position.coords.latitude,
        longitude: position.coords.longitude,
        useLocale: true,
        maxResults: 1
      });
      
      if (results.addresses.length > 0) {
        // Check if the user is in the USA
        return results.addresses[0].countryCode === 'US';
      }
    }
    
    // If we couldn't determine location or permission denied, fall back to IP detection
    return await isUserInUSAByIP();
  } catch (error) {
    console.error('Error detecting location:', error);
    // Fall back to IP detection on error
    return await isUserInUSAByIP();
  }
}

async function isUserInUSAByIP() {
  try {
    const response = await fetch('https://ipapi.co/json/');
    const data = await response.json();
    return data.country_code === 'US';
  } catch (error) {
    console.error('Error detecting IP location:', error);
    return false; // Default to false to be safe
  }
}

export async function determinePaymentMethod() {
  // Always use Stripe for Android
  if (Capacitor.getPlatform() !== 'ios') {
    return 'external';
  }
  
  // Check if user is in the USA
  const isUSA = await isUserInUSA();
  return isUSA ? 'external' : 'iap';
}

export async function processPayment(product, userEmail, userId) {
  const paymentMethod = await determinePaymentMethod();
  
  if (paymentMethod === 'external') {
    // Use Stripe Payment Links
    await initiateExternalPayment(userEmail, userId);
  } else {
    // Use Apple's In-App Purchase
    await initiateInAppPurchase(product.appleProductId);
  }
}

这种实现方式能更准确地判断用户是否实际位于美国。它会首先尝试使用设备的 GPS 和原生 geocoder 来确定国家。如果失败(由于权限问题或其他错误),则回退到基于 IP 的检测。

记得将必要的权限添加到你的 info.plist (iOS) 和 AndroidManifest.xml (Android) 文件:

iOS(ios/App/App/Info.plist):

<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location to determine which payment method to use based on regional availability.</string>

针对 Android (android/app/src/main/AndroidManifest.xml):

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

采用此方法可以让你最准确地判断用户是否符合 Apple 新指南中关于外部支付选项的资格。

管理订阅

使用 Stripe 进行支付的一个核心优势是能够提供并管理订阅服务。以下是在你的 Capacitor 应用中处理订阅管理的方法:

1. 创建订阅管理页面

在应用中添加一个订阅管理页面,用于展示用户当前生效的订阅:

<template>
  <div class="subscription-manager">
    <div v-if="isLoading" class="loading-indicator">
      Loading subscription data...
    </div>
    
    <div v-else-if="subscription" class="subscription-info">
      <h2 class="mb-4 text-xl font-bold">Your Subscription</h2>
      
      <div class="mb-6 plan-details">
        <p><span class="font-medium">Plan:</span> {{ subscription.planName }}</p>
        <p><span class="font-medium">Status:</span> {{ subscription.status }}</p>
        <p><span class="font-medium">Renews:</span> {{ formatDate(subscription.currentPeriodEnd) }}</p>
      </div>
      
      <button 
        @click="manageSubscription" 
        class="py-3 w-full font-medium text-white bg-indigo-600 rounded-lg transition-colors hover:bg-indigo-700"
      >
        Manage Subscription
      </button>
    </div>
    
    <div v-else class="no-subscription">
      <p class="mb-4">You don't have an active subscription.</p>
      <button 
        @click="goToPricingPage" 
        class="py-3 w-full font-medium text-white bg-indigo-600 rounded-lg transition-colors hover:bg-indigo-700"
      >
        View Plans
      </button>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { getUserSubscription } from '../services/subscription';

const subscription = ref(null);
const isLoading = ref(true);

onMounted(async () => {
  try {
    const userData = await getUserSubscription();
    subscription.value = userData.subscription;
  } catch (error) {
    console.error('Failed to load subscription:', error);
  } finally {
    isLoading.value = false;
  }
});

function formatDate(timestamp) {
  return new Date(timestamp * 1000).toLocaleDateString();
}

function manageSubscription() {
  // Open Stripe Customer Portal
  window.open(subscription.value.portalUrl, '_blank');
}

function goToPricingPage() {
  // Navigate to pricing page
  // router.push('/pricing');
}
</script>

2. 用于订阅管理的 Customer Portal

Stripe 提供了 Customer Portal,允许用户自行管理订阅。你可以从服务器端生成指向该 Portal 的链接:

// Server-side code (Node.js)
const stripe = require('stripe')('sk_your_stripe_secret_key');

async function createPortalSession(customerId) {
  const session = await stripe.billingPortal.sessions.create({
    customer: customerId,
    return_url: 'https://yourdomain.com/account',
  });
  
  return session.url;
}

确保符合 App Store 合规要求

为确保你的实现符合 Apple 的指南:

  1. 包含有关外部购买的适当披露说明
  2. 实现一个模态弹窗,告知用户即将离开应用(这是 Apple 的强制要求)
  3. 切勿尝试规避 Apple 对应用内购买收取的佣金
  4. 向用户明确说明 Apple 不对该交易负责

以下是实现该强制性披露弹窗的示例:

import { Dialog } from '@capacitor/dialog';

async function showExternalPaymentDisclosure() {
  const { value } = await Dialog.confirm({
    title: 'Leaving App for Payment',
    message: 'You are about to leave this app to make a payment. Apple is not responsible for the privacy or security of payments that are not made through the App Store. All payment-related issues, including refunds, must be handled by our support team.',
    okButtonTitle: 'Continue',
    cancelButtonTitle: 'Cancel'
  });
  
  return value;
}

export async function initiateExternalPayment(userEmail, userId) {
  const userConfirmed = await showExternalPaymentDisclosure();
  
  if (userConfirmed) {
    await openPaymentLink(userEmail, userId);
  }
}

测试你的实现

要测试你的实现:

  1. 点击应用中的支付按钮,应当先显示披露弹窗,随后打开 Stripe 支付页面
  2. 使用 Stripe 测试卡完成一笔测试支付 4242 4242 4242 4242
  3. 支付完成后,你应该通过 Universal Link 被重定向回你的应用
  4. 检查你的 webhook 是否收到了 checkout.session.completed event

总结

在 iOS 应用中使用外部支付方式销售数字产品是一项重大变革,为开发者提供了更高的灵活性。虽然这一变化目前仅适用于美国 App Store 的应用,但它为 Apple 的应用内购买系统提供了一个重要的替代方案。

通过结合 Capacitor 使用 Stripe Payment Links,您可以快速实现精简的结账体验,同时确保符合 Apple 的指南。对于 Apple 应用内购买系统仍然适用的美国以外的用户, @capgo/native-purchases 直接实现 StoreKit 和 Google Play Billing。与 Apple 的应用内购买系统相比,这种方式还让您受益于 Stripe 强大的支付基础设施、更低的交易手续费(3% 对比 30%)以及更快的结算速度(以天计而非月计)。

请记住,由于这些交易发生在 Apple 生态系统之外,您需要直接处理所有的客户支持和退款问题。

您是否在 Capacitor 应用中实现了 Stripe Payment Links?欢迎在下方评论区分享您的经验!

常见问题

问:这种方式符合 Apple 的指南吗?
答:是的。自 2025 年 5 月 1 日起,只要包含必要的披露信息,Apple 允许在通过美国 App Store 分发的应用中,为数字商品和服务提供外部支付方式的链接。

问:使用外部支付方式时,我还需要向 Apple 支付佣金吗?
答:不是的,新规的一大好处就是,在 Apple 系统之外处理的付款无需缴纳其佣金。

问:我的公司必须设在美国才能享受这些新规带来的好处吗?
答:不需要。只要您的 App 在美国 App Store 上架,且购买用户位于美国境内,全球任何地方的公司都可以接入外部支付方式。该裁决针对的是市场(美国 App Store)和用户所在地,而非您的公司所在地。这意味着来自欧洲、亚洲、南美洲或世界任何其他地区的开发者,都可以为美国客户接入 Stripe Payment Links。

问:如果美国境外的用户尝试使用外部支付选项会怎样?
答:您应该实现地区检测(如本文所示),仅向美国用户提供外部支付选项。对于其他地区,您应继续使用 Apple 的应用内购买系统。

问:我可以用这种方式销售在 App 之外消费的实物商品或服务吗?
答:可以。Apple 一直允许针对在 App 之外消费的实物商品和服务(例如网约车或外卖)使用外部支付方式。

继续阅读 Capacitor 中的 Stripe Payments:Apple 新指南

如果你正在使用 Capacitor 中的 Stripe 支付:Apple 新指南 来规划安全与合规,请结合 加密 了解 Encryption 的实现细节, 合规性 了解合规部分的实现细节, Capgo 安全扫描器 了解 Capgo Security Scanner 的产品工作流, Capgo 安全 用于 Capgo 安全的产品工作流,以及 Capgo 信任中心 用于 Capgo 信任中心的产品工作流。

为 Capacitor 应用提供 Live Updates

当 Web 层出现线上 Bug 时,通过 Capgo 发布修复,而不用等 App Store 审核好几天。用户会在后台收到更新,原生变更则仍走正常审核流程。

博客最新动态

Capgo 为你提供打造真正专业的移动应用所需的最有价值的洞察。