본문 바로가기

IAP 관련 iOS App Store 심사 가이드라인

GitHub

App Store에서 앱 승인을 받으려면 Apple의 가이드라인을 세심하게 준수해야 하며, 특히 인앱 결제와 구독을 구현할 때 더욱 주의해야 합니다. 이 가이드는 첫 제출에서 리뷰를 통과하는 데 필요한 모든 내용을 다룹니다.

iOS App Store 리뷰 프로세스

App Store Connect 설정 완료

“App Store Connect 설정 완료” 섹션

Apple이 구매 흐름을 리뷰하기 전에 앱 레코드 자체가 완성되었는지 확인하세요:

  • 다음 개인정보 처리방침 URL App Store Connect에서
  • 다음 지원 URL 사용자가 실제 연락처 정보를 찾을 수 있는
  • 다음을 완료하세요: 연령 등급 앱 출시가 가능하도록 설문 완료
  • 추가 App Review 연락처 정보 및 명확한 리뷰어 노트
  • 로그인이 필요하면 다음을 제공하세요: 심사 기간 중 만료되지 않는 데모 계정
정책 및 지원 링크가 포함된 App Store 등록 메타데이터
  • 심사 중인 실제 빌드의 최신 스크린샷을 사용하세요
  • iPhone의 경우, 1290 x 2796 (6.7인치)가 가장 기본적이고 편리한 사이즈입니다
  • iPad에서 앱이 실행된다면 iPad 스크린샷도 upload 하세요
  • 현재 승인되는 대형 iPad 사이즈는 다음과 같습니다 2064 x 2752 (13인치) 및 2048 x 2732 (12.9인치)
  • iPad 지원을 위해 iPhone 스크린샷을 늘리지 마세요

Apple 리뷰어가 실제 기기에서 수행할 경로를 그대로 실행해 보세요:

  • TestFlight에서 최신 빌드 설치
  • 제공할 리뷰용 계정으로 로그인
  • 숨겨진 제스처나 디버그 메뉴 없이 결제창(Paywall)까지 도달
  • 구매, 복원 및 구독 관리 흐름 완료
  • 권한을 거부했을 때도 앱이 정상 동작하는지 확인

In-App Purchase 요구 사항

“인앱 결제 요구 사항” 섹션

Apple은 구매 전에 가격을 명확히 공개하도록 요구합니다:

필수 포함 요소:

  • 구매 버튼 전에 정확한 가격 표시
  • 결제 주기 표시 (예: “$9.99/월”)
  • 사용자가 결제로 얻는 혜택을 명확히 명시
  • 결제 발생 시점 안내

흔한 거절 사유:

“구독 가격이 명확하고 사전에 공개되어야 합니다.”

:::caution 가격 일관성 모든 가격은 다음 항목에서 일치해야 합니다:

  • App Store 메타데이터 리스팅
  • 인앱 구매 화면
  • 구독 관리 화면

스토어 등록 정보($4.99)와 앱 내 가격($5.99)이 단 $1이라도 다르면 자동으로 거절됩니다. :::

구독 플랜 표시 방식

“구독 플랜 안내” 섹션

필수 고지 사항:

  • 모든 구독 티어를 한눈에 표시
  • 티어별 기능 비교를 명확하게 제공
  • UI 트릭을 이용한 프리미엄 티어 자동 선택 금지
  • 해지 방법을 쉽게 찾을 수 있도록 구성

UI 디자인 권장 및 주의 사항

구매 복원 및 법적 링크가 포함된 페이월

준수 UI 예시:

import { NativePurchases } from '@capgo/native-purchases';
function SubscriptionScreen() {
return (
<div>
<h2>Choose Your Plan</h2>
{/* Show all tiers equally */}
<PlanCard
title="Basic"
price="$4.99/month"
features={['Feature A', 'Feature B']}
/>
<PlanCard
title="Premium"
price="$9.99/month"
features={['All Basic', 'Feature C', 'Feature D']}
highlighted={false} // Don't force premium
/>
{/* Clear cancellation info */}
<Text>
Cancel anytime in Settings > Subscriptions.
No refunds for partial periods.
</Text>
</div>
);
}

필수 구현 사항:

IAP를 사용하는 모든 앱은 고객 지원팀에 문의하지 않고도 사용자가 이전 구매 내역을 복원할 수 있는 방법을 제공해야 합니다.

import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';
async function restorePurchases() {
try {
await NativePurchases.restorePurchases();
const { purchases } = await NativePurchases.getPurchases({
productType: PURCHASE_TYPE.SUBS,
});
const activeSub = purchases.find(
(purchase) => purchase.isActive && purchase.expirationDate,
);
if (activeSub) {
unlockPremiumFeatures();
showMessage('Purchases restored successfully!');
return;
}
const { purchases: iaps } = await NativePurchases.getPurchases({
productType: PURCHASE_TYPE.INAPP,
});
const hasIap = iaps.some((purchase) => purchase.productIdentifier === 'premium_unlock');
showMessage(
hasIap ? 'Premium purchase restored!' : 'No previous purchases found.',
);
} catch (error) {
showError('Failed to restore purchases. Please try again.');
}
}
// Add a visible "Restore Purchases" button
<Button onClick={restorePurchases}>
Restore Purchases
</Button>

1. 앱 크래시 또는 기능 오류

“1. 앱 충돌 또는 기능 오류” 섹션

거절 원인:

  • 앱 실행 시 충돌 발생
  • 결제 프로세스 완료 실패
  • 스크린샷의 기능이 작동하지 않음

방지 방법:

  • 실제 기기에서 테스트 (시뮬레이터 제외)
  • 모든 구독 플로우를 엔드 투 엔드로 테스트
  • 영수증 검증(receipt validation) 작동 확인
  • 네트워크 에러 핸들링 확인

2. 메타데이터 불일치

“2. 메타데이터 불일치” 섹션

거절 원인:

  • 현재 빌드에 없는 기능이 스크린샷에 포함됨
  • 설명에 존재하지 않는 기능이 언급됨
  • 메타데이터와 인앱 결제 가격 불일치

메타데이터 체크리스트

방지 방법:

// Document exactly what's in each tier
const SUBSCRIPTION_FEATURES = {
basic: ['Ad-free', 'Cloud sync', 'Basic themes'],
premium: ['Ad-free', 'Cloud sync', 'All themes', 'Priority support']
};
// Use these in both your app AND App Store description

3. 권한 요청 설명 누락

“3. 권한 설명 누락” 섹션

거절 원인:

  • 설명 없이 카메라/위치/건강 데이터 권한 요청
  • 여러 단계를 거쳐야 나타나는 권한 요청 화면
  • 모호하거나 일반적인 권한 설명

방지 방법:

다음 파일을 Info.plist 명확한 설명과 함께:

심사 통과가 어려울 정도로 모호한 권한 안내 문구 설명이 명확하게 포함된 권한 안내 문구
<key>NSCameraUsageDescription</key>
<string>Camera access is needed to scan product barcodes for quick subscription upgrades.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Location helps us show relevant local content in your Premium subscription.</string>

4. 오해의 소지가 있는 마케팅

“4. 오해의 소지가 있는 마케팅” 섹션

거절 원인:

  • 근거 없는 “세계 1위 앱” 등의 주장
  • 숨겨진 제한이 있는 “무제한” 기능
  • 허위 긴박감 조성 전략 (“남은 자리 단 2개!”)

설명 가이드라인 예시

추가 설명 가이드라인

예방 방법:

  • 설명은 구체적이고 사실에 기반해야 합니다
  • 근거 없는 최상급 표현은 피하세요
  • 가짜 품절 임박 등으로 사용자를 압박하지 마세요

5. 숨겨진 구독 해지 프로세스

“5. 숨겨진 해지 프로세스” 섹션

거절 원인:

  • 해지 방법에 대한 언급이 없음
  • 해지 버튼이 숨겨져 있거나 잘 보이지 않음
  • Apple의 네이티브 흐름을 따르지 않는 복잡한 해지 단계

예방 방법:

// Always inform users about cancellation
function SubscriptionInfo() {
return (
<div>
<h3>How to Cancel</h3>
<ol>
<li>Open iPhone Settings</li>
<li>Tap your name at the top</li>
<li>Tap Subscriptions</li>
<li>Select this app and tap Cancel</li>
</ol>
<p>Or manage directly in the App Store app.</p>
<Button onClick={openSubscriptionManagement}>
Manage Subscription in Settings
</Button>
</div>
);
}
async function openSubscriptionManagement() {
// Direct link to iOS subscription management
await NativePurchases.showManageSubscriptions();
}

개인정보 보호 및 데이터 사용 (섹션 5.1.1)

“개인정보 보호 및 데이터 사용 (섹션 5.1.1)” 섹션

Apple은 2025년에 개인정보 보호 요건을 대폭 강화했습니다.

모든 권한에 대해:

  1. 사용 이유 (구체적인 사용 사례)
  2. 사용 시점
  3. 데이터 저장 및 공유 방식
  4. 선택 사항 또는 필수 사항 여부

예시: 올바른 권한 요청 흐름

“예시: 올바른 권한 요청 흐름” 섹션
async function requestCameraPermission() {
// Show explanation BEFORE requesting
await showDialog({
title: 'Camera Access',
message: 'We need camera access to let you scan barcodes for quick product lookup. Your photos are never uploaded or stored.',
buttons: ['Not Now', 'Allow']
});
// Then request permission
const result = await Camera.requestPermissions();
return result.camera === 'granted';
}

개인정보 보호 영양 성분표

“개인정보 보호 영양 성분표” 섹션

App Store 개인정보 보호 라벨이 다음 사항을 정확히 반영하는지 확인하세요:

  • 구매 내역 수집
  • 이메일 주소 (영수증 발송용)
  • 기기 ID (부정 사용 방지용)
  • 사용 데이터 (분석용)

부정확한 개인정보 보호 라벨은 2025년 앱 심사 거절의 흔한 원인입니다. 데이터 수집 내역을 면밀히 검토하세요.

제출 전 체크리스트

“제출 전 체크리스트” 섹션

제출 전 체크리스트

  1. 모든 결제 흐름 테스트

    • 각 구독 티어별 구매 테스트
    • 무료 체험 테스트
    • 인트로덕션 오퍼 적용 여부 확인
    • 구매 복원 테스트
    • 가족 공유 확인 (활성화 시)
    • 여러 기기에서 테스트
  2. 가격 일관성 확인

    • App Store 메타데이터와 인앱 가격 일치 확인
    • 모든 통화 단위 정확성 확인
    • 무료 체험 기간과 설명 일치 여부 확인
    • 인트로덕션 오퍼 조건의 정확성 확인
  3. 전체 문구 검토

    • 플레이스홀더 텍스트 제거
    • 주장 사항의 테스트 가능 여부 확인
    • 문법 및 맞춤법 검사
    • 설명이 현재 빌드와 일치하는지 확인
    • 경쟁사 언급 제거
  4. 권한 테스트

    • 필요한 권한만 요청
    • 권한 요청 전 명확한 설명 제공
    • “거부” 흐름 테스트 (앱 기능 유지 확인)
    • Info.plist 설명이 명확한지 확인
  5. 테스트 계정 준비

    • 심사 기간 내내 유효한 리뷰용 계정 생성
    • App Review 정보에 로그인 정보 기록
    • 심사위원이 페이월에 접근하여 결제 프로세스를 완료할 수 있는지 확인
    • 필요 시 Notes 필드에 추가 계정이나 앱 전용 스위치 포함
  6. 메타데이터 확인

    • 스크린샷이 현재 UI와 일치하는지 확인
    • Support URL에 실제 연락처 정보 포함 여부 확인
    • 개인정보 처리방침 URL 입력 여부 확인
    • 연령 등급이 빌드 내 콘텐츠와 일치하는지 확인
    • 앱 미리보기 영상(있는 경우)이 최신 버전을 보여주는지 확인
    • 설명이 기능을 정확하게 설명하는지 확인
    • 앱 내 및 스토어 등록 정보에서 개인정보 처리방침 접근 가능 여부 확인
  7. 상세 리뷰 노트 작성

    Contact:
    Name: Jane Developer
    Email: review@yourapp.com
    Phone: +1 555-0100
    Test Account:
    Email: reviewer@test.com
    Password: TestPass123!
    This account does not expire during review.
    Testing Instructions:
    1. Log in with test account above
    2. Tap "Upgrade to Premium" button
    3. Select "Monthly Premium" subscription
    4. Complete purchase (no charge in sandbox)
    5. Verify premium features unlock
    Note: Subscription pricing is clearly shown before purchase.
    Cancellation instructions are in Settings > Account.

App Store 리뷰 타임라인

일반 리뷰: 24~48시간 피크 기간: 3~5일 (App Store 휴가 시즌) 주말: 리뷰 처리 안 함 긴급 리뷰: 중요 버그 수정 시 이용 가능 (App Store Connect에서 요청)

App Store Connect에서 확인할 수 있는 주요 상태:

  • Waiting for Review
  • In Review
  • Pending Developer Release
  • Rejected

2026년 제출 중점 사항

“2026년 제출 중점 사항” 섹션

현재 중점 검토 영역

“현재 중점 검토 영역” 섹션

1. 구독 정보의 명확성

  • 요금제 나란히 비교 필수
  • 저렴한 옵션을 숨기는 “다크 패턴” 금지
  • 명확한 다운그레이드/업그레이드 경로 확보

2. 메타데이터 정확성

  • 스크린샷은 심사 중인 빌드와 일치해야 함
  • iPad 지원이 활성화된 경우 iPad 스크린샷 필수
  • 지원 URL 및 개인정보 처리방침은 제출 전 활성화되어 있어야 함

3. 개인정보 보호 및 심사 상세 정보 품질

  • 개인정보 공개 내용은 SDK가 실제로 수집하는 데이터와 일치해야 함
  • App Review 연락처 정보와 메모는 첫 제출 시점에 모두 작성되어야 함
  • 데모 계정은 전체 심사 기간 동안 유효해야 함

4. 제출 준비 상태

  • Apple은 SDK 최소 요구 사항을 정기적으로 업데이트하므로, 릴리스 빌드를 업로드하기 전에 최신 데드라인을 확인하세요
  • 제출 전 TestFlight를 통해 실제 심사 경로를 확인하는 것이 가장 안전합니다

Native Purchases 플러그인 권장 사항

“Native Purchases 플러그인 권장 사항” 섹션

적절한 에러 핸들링 구현

“적절한 에러 핸들링 구현” 섹션
import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';
async function handlePurchase(productId: string) {
try {
const transaction = await NativePurchases.purchaseProduct({
productIdentifier: productId,
productType: PURCHASE_TYPE.SUBS,
});
// Success
await validateReceiptOnServer(transaction.receipt);
showSuccess('Subscription activated!');
unlockFeatures();
} catch (error: any) {
// Handle specific error cases
if (error.code === 'USER_CANCELLED') {
// User cancelled - don't show error
console.log('Purchase cancelled by user');
} else if (error.code === 'PAYMENT_PENDING') {
showInfo('Payment is pending. Please check back later.');
} else if (error.code === 'PRODUCT_ALREADY_PURCHASED') {
// Restore instead
await NativePurchases.restorePurchases();
} else {
// Show user-friendly error
showError('Unable to complete purchase. Please try again.');
}
}
}
function PurchaseButton({ productId }: { productId: string }) {
const [loading, setLoading] = useState(false);
const handlePurchase = async () => {
setLoading(true);
try {
await NativePurchases.purchaseProduct({ productIdentifier: productId });
} finally {
setLoading(false);
}
};
return (
<button onClick={handlePurchase} disabled={loading}>
{loading ? 'Processing...' : 'Subscribe Now'}
</button>
);
}
function SubscriptionTerms() {
return (
<div className="terms">
<p>
Subscription automatically renews unless cancelled at least 24 hours
before the end of the current period.
</p>
<p>
Your account will be charged for renewal within 24 hours prior to
the end of the current period.
</p>
<p>
Subscriptions may be managed by the user and auto-renewal may be
turned off in Account Settings after purchase.
</p>
<p>
<a href="/terms">Terms of Service</a> |
<a href="/privacy/">Privacy Policy</a>
</p>
</div>
);
}

앱 심사 거절 시 대응 방법

“앱이 거절되면” 섹션
  1. 거절 사유를 꼼꼼히 읽으세요

    • 인용된 특정 가이드라인을 확인하세요 (예: 3.1.1, 5.1.1)
    • Apple이 정확히 무엇을 지적했는지 파악하세요
  2. 문제를 철저히 수정하세요

    • 임시방편이 아닌 근본 원인을 해결하세요
    • 수정 사항을 철저히 테스트하세요
    • 변경 사항을 문서화하세요
  3. Resolution Center에서 답변하세요

    Thank you for your feedback. I have addressed the issue:
    Issue: Subscription pricing not clear upfront
    Fix: Added explicit pricing display on subscription selection
    screen showing "$9.99/month" before purchase button. Also added
    cancellation instructions on the same screen.
    The changes are in this submission and can be tested using the
    provided test account.
  4. 즉시 재제출하세요

    • 재제출 시 보통 더 빠르게 검토됩니다
    • 대개 24시간 이내에 완료됩니다

이의 신청 프로세스

“이의 신청 프로세스” 섹션

거절 사유가 부당하다고 판단되면:

App Store 소명 프로세스

  1. App Store Connect에서 “Appeal” 클릭
  2. 명확한 증거를 제출하세요:
    • 준수 사항을 보여주는 스크린샷
    • 특정 가이드라인에 대한 참조
    • 요구 사항 충족 방식에 대한 설명
  3. 전문적이고 객관적인 태도를 유지하세요
  4. 기능을 찾기 어렵다면 테스트 계정을 포함하세요

문서 요청 예시

문제가 계속 해결되지 않는다면:

전문가 도움이 필요하신가요?

“전문가의 도움이 필요하신가요?” 섹션

앱 심사 문제로 어려움을 겪고 계시거나 맞춤형 지원이 필요하신가요? 팀과 상담 예약하기 다음 항목에 대한 전담 지원을 받으세요:

  • IAP 구현 검토 및 최적화
  • App Store 심사 준비 및 전략
  • 제출 체크리스트 검토
  • 거절 해결 및 이의 신청
  • 테스트 및 검증 완료

저희 전문가들은 수백 개의 앱이 심사를 통과하도록 성공적으로 도왔습니다!

IAP 관련 iOS App Store 심사 가이드라인에서 계속하기

“IAP 관련 iOS App Store 심사 가이드라인에서 계속하기” 섹션

사용 중이라면 IAP 관련 iOS App Store 심사 가이드라인 스토어 승인 및 배포를 계획하려면, 다음 항목과 연결하세요 @capgo/native-purchases 사용하기 @capgo/native-purchases 사용 시 네이티브 기능을 위해, @capgo/capacitor-in-app-review @capgo/capacitor-in-app-review의 구현 세부 사항에 대해서는, @capgo/capacitor-in-app-review 사용하기 @capgo/capacitor-in-app-review 사용하기에서 네이티브 기능은, @capgo/capacitor-native-market @capgo/capacitor-native-market의 구현 세부 사항에 대해서는, 그리고 @capgo/capacitor-native-market 사용하기 @capgo/capacitor-native-market. 사용하기에서 네이티브 기능은