메인 콘텐츠로 건너뛰기
__CAPGO_KEEP_0__

Capacitor에서 스트라이프 결제: 새로운 애플 지침

Capacitor 앱에서 스트라이프 결제 링크를 구현하는 방법을 배워 스트라이프 결제를 통해 디지털 상품 결제를 새로운 애플 지침에 따라 처리하세요. 2025년 5월 1일부터 적용됩니다.

마틴 도나디우

마틴 도나디우

콘텐츠 마케터

Capacitor에서 스트라이프 결제: 새로운 애플 지침

Capacitor 앱에서 새로운 애플 지침에 따라 스트라이프 결제 링크를 구현하는 방법

2025년 5월 1일부터, 애플은 에픽 v. 애플 사례 판결에 따라 앱 스토어 리뷰 지침을 크게 변경했습니다. 미국의 앱 개발자들은 디지털 상품과 서비스에 대한 외부 결제 방법에 대한 링크를 제공할 수 있게 되었습니다. 이는 애플의 내 앱 구매 시스템에 대한 대안을 열어주었습니다. __CAPGO_KEEP_0____CAPGO_KEEP_0__

이중 결제 시스템의 혁명

이 순간에 이르기까지의 길은 오랜 시간과 논쟁이 있었다. 2020년 8월 에픽 게임즈가 개발한 인기 게임 포트나이트의 제작사 에픽 게임즈가 애플의 앱 스토어 지침을 위반하기 위해 직접 결제 옵션을 구현했다. 애플은 포트나이트를 앱 스토어에서 제거했고, 에픽은 애플의 iOS 앱 배포 및 인앱 결제에 대한 통제를 주장하는 소송을 제기했다.

법적 분쟁이 수년 동안 계속되며, 항소와 반항소가 이어지다 보니, 최종적으로 법원은 애플이 개발자에게 앱 외부의 대안 결제 방법을 사용하도록 허용해야 한다고 판결했다. 이 결정은 2008년부터 앱 스토어 생태계가 운영해온 기본적인 금융 모델을 바꾸게 되었다.

최종 판결 - 더 이상 항소할 수 없다.

이 판결이 특히 중요한 이유는 그것이 최종적이고 더 이상 항소할 수 없다는 점이다. 2025년 초, 대법원은 애플의 항소를 기각했고, 이로써 하급 법원의 판결이 법률의 원칙이 되었다. 개발자는 애플이 이 결정에 대한 법적 도전을 통해 이 결정이 뒤집히지 않는다는 자신감으로 외부 결제 방법을 구현할 수 있다.

법률에 의해 보장되는 평등한 대우

중요한 것은 이 판결이 애플이 외부 결제 방법을 사용하는 앱에 대해 차별할 수 없다는 것을 명확히 밝히고 있다는 점이다. 법원은 애플이 다음과 같은 것을 금지했다.

  1. 외부 결제 방법을 사용하는 앱에 추가 요금을 부과하거나 추가 요구 사항을 부과하는 경우
  2. 애플의 IAP 시스템을 독점적으로 사용하는 앱에 선호하는 검색 결과 또는 특징을 제공하는 경우
  3. 외부 결제 경험을 애플의 시스템보다 불리하게 만드는 기술적 조치를 취하는 경우
  4. 기본적인 고객 정보 이외의 추가적인 공개 요건을 부과하는 경우

이러한 명확한 보호 조치로 개발자는 스트라이프 또는 다른 외부 결제 제공 업체를 implement할 수 있으며, 애플의 은밀한 복수 또는 차별로부터 자유로울 수 있습니다. 게임 필드가 법적으로 평준화되었으며, 애플은 앱의 결제 방법 선택에 관계없이 모든 앱을 동일하게 다루어야 합니다.

이 판결은 애플의 벽으로 둘러싸인 정원 접근 방식에 대한 가장重大한 도전 중 하나이며, 모바일 앱 수익화 방식의 전환점을 나타냅니다. 개발자들이 오랫동안 애플의 30% 수수료 (소규모 기업에 대한 15%로 감소)로 불만을 표명해 왔는데, 이 판결은 더 높은 수익 마진과 고객 경험에 대한 더 많은 통제를 제공하는 길을 열어줍니다.

스트라이프를 사용하는 것과 애플의 인앱 구매를 사용하는 것의 금융 이점

이 변화의 금융적 영향은 개발자에게 다음과 같은 결과를 낳습니다:

  • 낮은 결제 처리 수수료: 애플은 일반적으로 인앱 구매에 대해 30% 수수료 (소규모 기업에 대한 15%로 감소)를 부과하며, 스트라이프의 수수료는 거래당 약 2.9% + $0.30입니다. 이 차이는 수익 마진을 크게 증가시킬 수 있습니다.

  • 빠른 지불: Apple과 함께라면 45-90일 동안 자금을 받을 수 있습니다. 반면에 Stripe은 2-3일 이내에 업무일정을 기준으로 지불금을 은행 계좌에 입금합니다.

  • 간소화된 환불 처리: Apple의 복잡한 환불 시스템 대신 Stripe의 대시보드에서 환불을 직접 처리할 수 있습니다.

이러한 비용 절감 및 현금 흐름 개선은 특히 작은 개발자 및 기업에게 게임 체이저일 수 있습니다.

이 기사에서는 Capacitor 앱에서 Stripe Payment Links를 구현하는 방법을 살펴보겠습니다. 이 새로운 규칙을 활용하면서 Apple의 업데이트 된 지침을 준수할 수 있도록 하겠습니다. 업데이트 된 지침.

이 구현은 Stripe의 Payment Links 공식 문서에 기반을 두고 Capacitor 앱을 위해 특별히 적응되었습니다.

새로운 지침을 이해하는

업데이트 된 App Store 리뷰 지침에서는 개발자가 디지털 상품 및 구독과 관련된 지불 처리를 위해 사용자에게 외부 웹사이트로 안내할 수 있도록 허용합니다. 이 변경은 현재 미국 App Store에서만 적용됩니다.

중요한 이해 요약:

  1. 현재 앱 내에서 디지털 상품에 대한 외부 결제 옵션에 대한 링크를 연결할 수 있습니다.
  2. 이 규칙은 미국 앱 스토어에만 적용됩니다.
  3. 애플의 공개 요건에 따라야 합니다.
  4. 고객 지원 및 환불 처리에 대한 모든 책임은 여전히 당신에게 있습니다.

기술 구현에 대해 자세히 알아보겠습니다.

먼저 Stripe 대시보드에서 결제 링크를 생성하세요.

  1. Stripe 대시보드의 결제 링크 섹션으로 이동하세요.
  2. 새 결제 링크를 생성하려면 '+ New' 버튼을 클릭하세요.
  3. 제품 또는 구독 정보를 정의하세요.
  4. 결제 후 설정에서 '확인 페이지 표시하지 않기'를 선택하세요.
  5. 성공 URL로 universal 링크를 설정하세요 (이것은 나중에 설정할 것입니다)
  6. 결제 링크를 생성하기 위해 "Create Link"를 클릭하세요

결제 완료 후 사용자에게 앱으로 되돌아가도록 하려면 universal 링크를 구성하세요:

  1. Create an apple-app-site-association __CAPGO_KEEP_0__ 도메인에
{
  "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. Capacitor 앱을 universal 링크를 처리하도록 구성하려면 올바른 권한을 추가하세요. 먼저, 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 권한을 추가하세요:
    • Xcode 프로젝트를 열어보세요
    • 앱 대상 선택
    • ‘인증 및 기능’으로 이동하세요
    • ‘+ 기능’을 클릭하고 ‘연관된 도메인’을 선택하세요
    • 추가 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 앱에 결제 버튼을 Implement하세요

앱에 결제 버튼을 추가하세요:

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');
}

사파리 왜 중요합니까?: 사용자가 이전에 스티프 링크에서 결제 정보를 저장한 경우, 사파리(via )를 통해 결제 링크를 열 때 자동으로 자격 증명이 제공되므로, 사용자가 다시 신용 카드 정보를 입력하지 않아도 체크아웃 경험을 더 편리하게 할 수 있습니다. 이는 사용자가 신용 카드 정보를 다시 입력하지 않아도 체크아웃 경험을 더 편리하게 할 수 있으므로, 사용자가 다시 신용 카드 정보를 입력하지 않아도 체크아웃 경험을 더 편리하게 할 수 있습니다. window.open5단계: 앱에서 Universal 링크를 처리하세요

Configure your app to handle the universal links when users are redirected back:

  1. __CAPGO_KEEP_0__을 설치하세요:
npm install @capacitor/app
  1. __CAPGO_KEEP_0__을 앱에 등록하세요:
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단계: 주문 완료 웹훅 설정

마지막으로, 성공적인 결제를 처리하기 위해 서버에서 웹훅을 구성하세요:

// 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'));

안드로이드 호환성

iOS 앱에 대한 에픽 v. 애플 판결은 모바일 결제 환경을根本적으로 바꾸었습니다. iOS 앱만 직접적으로 영향을 받는 것은 물론, 안드로이드 개발자들이 외부 결제 방법을 사용해 왔던 것을 강화시킵니다.

안드로이드 개발자들은 이제 외부 결제 솔루션을 완벽한 자신감으로 implement할 수 있습니다. 애플 판결에 의해 설정된 전례는 플랫폼을 막론하고 개발자가 потен셜한 미래 제한으로부터 보호합니다. 이 법적 판결은 많은 안드로이드 개발자가 이미 몇 년 동안 수행해 왔던 것과 동일한 것을 확인했습니다 - 낮은 수수료의 대안 결제 옵션을 제공합니다.

구글 플레이 스토어는 항상 애플보다 외부 결제 방법에 대한 제한이 적었으며, 법적 전례가established되었으므로, 스트라이프 또는 다른 외부 결제 제공자를 안드로이드 앱에 implement할 때 virtually의 위험이 없습니다. 이들 implement에 대해 진행할 수 있습니다. knowing이 solid한 법적 기반을 갖고 있습니다.

iOS에 대해 설명한 implement는 거의 동일한 안드로이드 기기에 적용됩니다. 구글 플레이 스토어는 외부 결제 방법에 대한 제한이 없기 때문에, 스트라이프 결제 링크에 대한 동일한 접근 방식을 사용할 수 있습니다. disclosure dialog가 필요하지 않습니다.

deep linking을 처리하기 위해 (iOS의 universal links와 동일한), 다음을 수행해야 합니다:

  1. 앱 링크를 설정하세요. AndroidManifest.xml __CAPGO_KEEP_0__에서 리다이렉트 URL을 처리하는 방법을 알아보세요.
  2. Capgo를 사용하여 .well-known/assetlinks.json __CAPGO_KEEP_0__에 대한 정보를 포함하는 파일을 생성하세요.
  3. Capacitor와 __CAPGO_KEEP_0__에서 동일한 appUrlOpen __CAPGO_KEEP_0__에서 성공적인 결제를 처리하는 로직을 사용하세요.

Capacitor의 아름다움은 플랫폼별 설정을 구현한 후 실제 결제 흐름이 code 두 플랫폼 모두에서 동일하게 유지되는 것입니다.

결제 UI를 생성하세요.

Vue에서 다음 결제 버튼 컴포넌트를 Capacitor 앱에 추가하세요.

<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>

다양한 지역을 처리하세요.

새로운 애플 지침은 미국 앱 스토어에만 적용되므로 사용자 지역을 감지하고 적절한 결제 방법을 적용하는 전략이 필요합니다. 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% 정확하지 않다는 것을 기억하는 것이 중요합니다. mission-critical 애플리케이션에 대해, 여러 감지 방법을 사용하거나 사용자에게 지역을 수동으로 선택하도록 허용하는 것을 고려하십시오.

더 정확한 위치 감지에 대한 Capacitor 플러그인

더 정확한 위치 감지를 위해, Capacitor 지리 위치 플러그인과 @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와 네이티브 지오코더를 사용하여 국가를 결정하려고 시도합니다. 실패 (권한 문제 또는 기타 오류로 인해) 시, IP 기반 감지를 사용하십시오.

필요한 권한을 __CAPGO_KEEP_0__ 프로젝트의 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 지침에 따라 외부 결제 옵션에 적합한지 가장 정확하게 판단할 수 있는 방법입니다.

구독 관리

Capacitor 앱에서 구독 관리를 처리하는 방법은 다음과 같습니다.

1. 구독 관리 페이지 만들기

__CAPGO_KEEP_0__ 앱에 구독 관리 페이지를 추가하여 사용자의 활성 구독을 표시합니다.

<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. 구독 관리 고객 포털

Stripe은 고객 포털을 제공하여 사용자가 구독을 관리할 수 있습니다. 서버에서 이 포털에 대한 링크를 생성할 수 있습니다.

// 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;
}

애플 스토어 준수

Apple 지침을 준수하기 위해 구현을 확인하려면:

  1. 외부 구매에 대한 적절한 공개를 포함해야 합니다.
  2. 사용자가 앱을 떠나는 것을 알리는 모달 시트를 구현하세요 (애플의 요구 사항)
  3. 앱 내에서 구매한 애플의 수수료를 피하려 하지 마세요
  4. 사용자에게 거래에 대한 애플의 책임이 없다는 것을 rõ ràng하게 알려주세요

필요한 공개 지시 모달의 구현 예제입니다:

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. 앱 내의 결제 버튼을 클릭하여 공개 지시를 보여주고 스티프支付 페이지로 열립니다
  2. 스트리프 테스트 카드를 사용하여 테스트 결제를 완료하세요 4242 4242 4242 4242
  3. 결제 후 앱으로 다시 리다이렉트되어야 합니다
  4. 웹 훅이 이벤트를 받았는지 확인하세요 checkout.session.completed 결론

__CAPGO_KEEP_0__

iOS 앱에서 디지털 상품에 대한 외부 결제 옵션을 사용할 수 있는 능력은 개발자에게 더 많은 유연성을 제공하는 중요한 변화입니다. 이 변경은 현재 미국 앱 스토어에만 적용되지만 애플의 내 앱 구매 시스템에 대한 중요한 대안을 제공합니다.

Capacitor에서 Stripe Payment Links를 사용하여, Stripe의 강력한 결제 인프라, 낮은 처리 수수료(3% 대 30%), 빠른ayout(일 단위 대 월 단위)를 제공하는 스트리밍된 체크아웃 경험을 빠르게 구현할 수 있습니다. 또한 애플의 내 앱 구매 시스템에 비해 Apple의 지침을 준수하는 동시에.

이 거래는 애플의 생태계 외부에서 발생하므로 고객 지원 및 환불 문제를 직접 처리해야 합니다.

Capacitor 앱에서 Stripe Payment Links를 구현했습니까? 댓글 섹션에서 경험을 공유해 보세요!

FAQs

Q: 이 접근 방식은 애플의 지침을 준수합니까?
A: 2025년 5월 1일부터, 미국 앱 스토어에 배포된 앱에서 디지털 상품 및 서비스에 대한 외부 결제 방법에 대한 링크를 포함하는 경우, 애플은 이 접근 방식이 지침을 준수한다고 허용합니다.

Q: 외부 결제 방법을 사용할 때 애플의 수수료를 지불해야 합니까?
A: 새로운 규칙의 주요 이점 중 하나는 애플의 시스템 외부에서 처리되는 결제에 대한 애플의 수수료가 면제된다는 것입니다.

Q: 이 새로운 규칙을 활용하기 위해 회사에 미국에 기반을 두고 있어야 합니까?
A: 미국 앱 스토어와 구매를 하는 사용자가 미국에 거주하는 경우에만 외부 결제 방법을 구현할 수 있습니다. 미국 앱 스토어와 사용자의 위치가 아니라 회사 위치에 따라 적용되지 않습니다. 따라서 유럽, 아시아, 남미, 또는 어디서든 개발자는 미국 고객을 위해 Stripe Payment Links를 구현할 수 있습니다.

Q: 미국 밖의 사용자가 외부 결제 옵션을 사용하려고 할 때 어떻게 되나요?
A: 미국 사용자만 외부 결제 옵션을 제공하기 위해 지역 감지 기능을 구현해야 합니다. 다른 지역의 사용자는 Apple의 인앱 구매 시스템을 계속 사용해야 합니다.

Q: 앱 외부에서 물리적 상품이나 서비스를 사용할 수 있나요?
A: 물리적 상품이나 앱 외부에서 서비스를 사용하는 경우 Apple은 항상 외부 결제 방법을 허용했습니다. 예를 들어 택시나 음식 배달과 같은 경우입니다.

Capacitor 앱에 대한 실시간 업데이트

Capgo를 사용하여 웹-layer 버그가 생긴 경우, 앱 스토어 승인 대기 없이 바로修정할 수 있습니다. 사용자는 배경에서 업데이트 받을 수 있고, 네이티브 변경은 일반적인 검토 경로를 유지합니다.

시작하기

최신 블로그

Capgo은 전문적인 모바일 앱을 만들기 위해 필요한 최고의洞察력을 제공합니다.