React-native-iap: finishTransactionIOS / finishTransaction์€ iOS์—์„œ ์•„๋ฌด๊ฒƒ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2020๋…„ 02์›” 19์ผ  ยท  34์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: dooboolab/react-native-iap

react-native-iap ๋ฒ„์ „

4.4.1

๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฒ„์ „

0.60.4

์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ํ”Œ๋žซํผ (IOS ๋˜๋Š” Android ๋˜๋Š” ๋‘˜ ๋‹ค?)

iOS

์˜ˆ์ƒ๋˜๋Š” ํ–‰๋™

๊ตฌ๋…์„ ์œ„ํ•ด finishTransactionIOS (purchaseId) ๋˜๋Š” finishTransaction (purchase)๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํŠธ๋žœ์žญ์…˜์ด ์™„๋ฃŒ๋˜์–ด์•ผํ•˜๋ฉฐ ๋‹ค์Œ ์‹คํ–‰์‹œ ์•ฑ์œผ๋กœ ๋‹ค์‹œ ๋‚ด๋ณด๋‚ด์ง€์ง€ ์•Š์•„์•ผํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฉด ์˜ค๋ฅ˜ ๋ฆฌ์Šค๋„ˆ ๋˜๋Š” finishTransaction ํ•จ์ˆ˜ ์ค‘ ํ•˜๋‚˜์˜ ์•ฝ์†์—์„œ ๋ฌด์–ธ๊ฐ€๊ฐ€ ๋ฐ˜ํ™˜ ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์•„๋ฌด ์ผ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Android๊ฐ€ ์ž˜ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์‹ค์ œ ํ–‰๋™

ํŠธ๋žœ์žญ์…˜์€ clearTransactionIOS๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š” ํ•œ ๋ชจ๋“  ๋‹จ์ผ ์‹คํ–‰์—์„œ ๋ฐฉ์ถœ๋˜๋ฉฐ ๋‹ค๋ฅธ ๋ถ€์ž‘์šฉ์ด์žˆ๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ๋œ ํ™˜๊ฒฝ (์—๋ฎฌ๋ ˆ์ดํ„ฐ? ์‹ค์ œ ์žฅ์น˜?)

์‹ค์ œ ์žฅ์น˜

ํ–‰๋™์„ ์žฌํ˜„ํ•˜๋Š” ๋‹จ๊ณ„

  • ๊ตฌ๋… ์ œํ’ˆ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
  • ๊ตฌ๋… ๊ตฌ๋งค
  • ๋ฐฑ์—”๋“œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
  • ํ•ด๋‹น ๊ตฌ๋…์— ๋Œ€ํ•ด finishTransactionIOS ๋˜๋Š” finishTransaction์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ํšจ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š”์ด ๋”๋ฏธ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์‹œ๋„ํ•ด ๋ณด์•˜๊ณ  ๋‚ด๊ฐ€ ๋ฌด์—‡์„ํ•˜๋“  ๊ฑฐ๋ž˜๋ฅผ ์ง€์šฐ๋Š” ๊ฒƒ ์™ธ์—๋Š” ์•„๋ฌด๊ฒƒ๋„ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ตฌ๋งค๋Š” ๋งค ์ถœ์‹œ๋งˆ๋‹ค ๋‹ค์‹œ ์•ฑ์œผ๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค. ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€, ๋‚ด๊ฐ€ ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋˜๋Š” ์ž˜๋ชป ์ดํ•ดํ•˜๊ณ  ์žˆ๋Š”์ง€ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

โ„น needs more info ๐Ÿ“ฑ iOS ๐Ÿ™ help wanted ๐Ÿšถ๐Ÿป stale

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

@hyochan ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ์šฐ๋ฆฌ๋Š” ๊ฝค ์˜ค๋žซ๋™์•ˆ ๊ฐ‡ํ˜€ ์žˆ์—ˆ๊ณ  ์•ฑ์„ ๊ฒŒ์‹œ ํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  34 ๋Œ“๊ธ€

๋‚˜๋Š” ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

ackResult ๋ฅผ ๊ณต์œ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

          try {
            const ackResult = await finishTransaction(purchase);
            console.log('ackResult', ackResult);
          } catch (ackErr) {
            console.warn('ackErr', ackErr);
          }

ํšจ์ฐฌ
๋‚˜์˜ ๊ฒฝ์šฐ์—๋Š”:
ackResult undefined

ํšจ์ฐฌ
๋‚˜์˜ ๊ฒฝ์šฐ์—๋Š”:
ackResult undefined

์—ฌ๊ธฐ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€

๋˜ํ•œ ์ œ ๊ฒฝ์šฐ์—๋Š” ๋ฐ˜ํ™˜ ๋œ ๊ฐ’์ด ์ •์˜๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค (์ƒŒ๋“œ ๋ฐ•์Šค ์‚ฌ์šฉ์ž๊ฐ€์žˆ๋Š” ์‹ค์ œ ์žฅ์น˜).

# 366๊ณผ ๊ด€๋ จ์ด์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ios finishTransaction ๊ฒฝ์šฐ ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋ชจ๋‘ # 366์— ์ง‘์ค‘ํ•˜๊ณ  ์—…๋ฐ์ดํŠธ๋ฅผ ์œ„ํ•ด ๋Œ์•„์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

# 366๊ณผ ๊ด€๋ จ์ด์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ios finishTransaction ๊ฒฝ์šฐ ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋ชจ๋‘ # 366์— ์ง‘์ค‘ํ•˜๊ณ  ์—…๋ฐ์ดํŠธ๋ฅผ ์œ„ํ•ด ๋Œ์•„์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋ช…ํ™•ํžˆํ•˜๊ธฐ ์œ„ํ•ด-# 366์€ ํ…Œ์ŠคํŠธ์— ๊ด€ํ•œ ๊ฒƒ์ด๋ฏ€๋กœ clearTransactionIOS ์—†์ด๋„ ํ”„๋กœ๋•์…˜์—์„œ ์ž˜ ์ž‘๋™ํ•ด์•ผํ•œ๋‹ค๊ณ  ์ œ์•ˆํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

@hyochan ์ƒŒ๋“œ ๋ฐ•์Šค ๊ณ„์ •์œผ๋กœ ๋””๋ฒ„๊ทธ ๊ตฌ์„ฑ์„ ํ…Œ์ŠคํŠธ ํ•  ๋•Œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์„œ๋ฒ„์—์„œ ์„œ๋ฒ„ ์•Œ๋ฆผ (Apple)์œผ๋กœ ๊ตฌ๋งค์— ๋Œ€ํ•œ ์•Œ๋ฆผ์„๋ฐ›์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ์–ผ๋งˆ ํ›„ ๋‚ด ํด๋ผ์ด์–ธํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ๊ตฌ๋งค์— ๋Œ€ํ•œ ๋˜ ๋‹ค๋ฅธ ์•Œ๋ฆผ์„ ๋ฐ›์ง€๋งŒ ๊ตฌ๋งค ์กฐ์น˜๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ์—๋„ transactionId๊ฐ€ ๋‹ค๋ฅด๋ฏ€๋กœ ์ด์ „ ํŠธ๋žœ์žญ์…˜์„ ์ œ๋Œ€๋กœ ์™„๋ฃŒํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. Android์—์„œ๋Š” ๋ชจ๋“  ๊ฒƒ์ด ์ž˜ ์ž‘๋™ํ•˜๋ฉฐ ์ƒŒ๋“œ ๋ฐ•์Šค ๊ณ„์ •์œผ๋กœ ๊ตฌ๋งค ํ”„๋กœ์„ธ์Šค๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— # 366๊ณผ ๊ด€๋ จ์ด ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

```tsx
useEffect (() => {
purchaseUpdateSubscription.current = purchaseUpdatedListener (
๋น„๋™๊ธฐ (๊ตฌ๋งค : InAppPurchase | SubscriptionPurchase) => {
const ์˜์ˆ˜์ฆ = purchase.transactionReceipt;
if (์˜์ˆ˜์ฆ) {
{
await myBackendHandler ({
์‚ฌ์šฉ์ž,
๋งค์ˆ˜,
});
const result = await RNIap.finishTransaction (purchase, false);
console.log ( 'result', ๊ฒฐ๊ณผ);
} catch (e) {
// ํ•  ๊ฒƒ
}
}
}
);
๋ฐ˜ํ™˜ () => {
if (purchaseUpdateSubscription.current) {
purchaseUpdateSubscription.current.remove ();
purchaseUpdateSubscription.current = null;
}
};
}, []);
````

์•ˆ๋…•ํ•˜์„ธ์š” ํŒ€,์ด ๋„์„œ๊ด€์˜ ๋ชจ๋“  ๋…ธ๋ ฅ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์ •๋ง ์šฐ๋ฆฌ์˜ ์‚ถ์„ ๋” ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜๊ฒฌ์„ ๋งํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์ •๋ฆฌ๋˜์ง€ ์•Š์€ ์˜ค๋ž˜๋œ ๊ฑฐ๋ž˜๊ฐ€ # 366๊ณผ ๊ด€๋ จ์ด ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋‚ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š”

  1. ์‚ฌ์šฉ์ž 1์€ ๊ตฌ๋งค ๋ฐ ํ”„๋ฆฌ๋ฏธ์—„ ํ˜œํƒ์„ ์ž์‹ ์˜ ๊ณ„์ •์— ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  2. ์‚ฌ์šฉ์ž 1 ๋กœ๊ทธ ์•„์›ƒ
  3. ์‚ฌ์šฉ์ž 2๊ฐ€ ๋กœ๊ทธ์ธ

์˜ˆ์ƒ ๊ฒฐ๊ณผ:

  • ์‚ฌ์šฉ์ž 1์˜ ํŠธ๋žœ์žญ์…˜์€ ๊ตฌ๋งค ๋ฆฌ์Šค๋„ˆ๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‹ค์ œ ๊ฒฐ๊ณผ

  • ์‚ฌ์šฉ์ž 1์˜ ํŠธ๋žœ์žญ์…˜์€ ์ง€์›Œ์ง€์ง€ ์•Š๊ณ  ๋‹ค์‹œ ๋ฐœํ–‰๋ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜์—ฌ ์ž˜๋ชป๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐœ์ƒํ•˜๋”๋ผ๋„.

์ด๊ฒƒ์€์ด ๋ฌธ์ œ์— ์šฐ์„  ์ˆœ์œ„๋ฅผ ๋‘๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•œ ์ด์œ ์— ๋Œ€ํ•œ ์˜ˆ์ผ๋ฟ์ž…๋‹ˆ๋‹ค. ์ด ๊ธด ๋Œ“๊ธ€์„ ์ฝ์–ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ...

์—ฌ๊ธฐ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€

์œ„์™€ ๋˜‘๊ฐ™์€ ๋ฌธ์ œ์ธ๋ฐ, ์ƒŒ๋“œ ๋ฐ•์Šค / itunes ๊ณ„์ • ์—ฐ๊ฒฐ์„ ๋Š๊ณ  ๊ธฐ๊ธฐ๋ฅผ ์žฌ๋ถ€ํŒ…ํ•˜๊ณ  ์•ฑ์„ ๋‹ค์‹œ ์„ค์น˜ํ•ด๋„ ์Šคํƒ์ด ์ „ํ˜€ ์ง€์›Œ์ง€์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. : /

finishTransaction ์ด RNIapIos.m ํŒŒ์ผ์—์„œ ์‹ค์ œ๋กœ ์•„๋ฌด ์ž‘์—…๋„ํ•˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
๋ฐฉ๊ธˆ ํ™•์ธํ–ˆ๊ณ  ๊ฑฐ๋ž˜๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค.

clearTransaction ๋˜๋Š” finishTransactionWithIdentifier ๋ฉ”์†Œ๋“œ๋ฅผ ํ™•์ธํ•˜๊ณ  ๋‚ด๋ถ€์— ๋กœ๊ทธ๋ฅผ ๋„ฃ์œผ์‹ญ์‹œ์˜ค. ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐพ์œผ์‹ญ์‹œ์˜ค.

RCT_EXPORT_METHOD(clearTransaction) {
    NSArray *pendingTrans = [[SKPaymentQueue defaultQueue] transactions];
    NSLog(@"\n\n\n  ***  clear remaining Transactions. Call this before make a new transaction   \n\n.");
    for (int k = 0; k < pendingTrans.count; k++) {
        [[SKPaymentQueue defaultQueue] finishTransaction:pendingTrans[k]];
    }
-(void)finishTransactionWithIdentifier:(NSString *)transactionIdentifier {
    SKPaymentQueue *queue = [SKPaymentQueue defaultQueue];
    for(SKPaymentTransaction *transaction in queue.transactions) {
        if([transaction.transactionIdentifier isEqualToString:transactionIdentifier]) {
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        }
    }
}

๋‚˜๋Š” ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ์ „ํ˜€ ์•Œ์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์—์ด ๋ฌธ์ œ๋ฅผ ์ง„ํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ์ž์‹ ์˜ ํ™˜๊ฒฝ์—์„œ ๋””๋ฒ„๊น…ํ•˜๊ณ  ๊ณต์œ  ํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์œ„๋กœ, ๋‚˜๋„์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ๋™์ผ finishTransactionIOS / finishTransaction ์ด๊ฒƒ์€ IOS์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ €๋„ ๊ฐ™์€ ๊ฒฝํ—˜์„ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
IAP์˜ ๊ตฌ๋งค๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜์ง€๋งŒ๋กœ ์ตœ์ข… ํ˜ธ์ถœ finishTransaction ๋ฐ˜ํ™˜ undefined .

// Finish transaction
const ackResult = await finishTransaction(purchase);
console.log("Ack result: ", ackResult); // Ack result: undefined

_App Store Sandbox ํ™˜๊ฒฝ์„ ํ™œ์šฉ ํ•œ ์‹ค์ œ ๊ธฐ๊ธฐ "iPhone 6s"_

finishTransaction์˜ ์˜ˆ์ƒ ๊ฒฐ๊ณผ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? undefined ์ข‹์€ ๊ฒฐ๊ณผ์ž…๋‹ˆ๊นŒ ์•„๋‹ˆ๋ฉด ๋‹ค๋ฅธ ๊ฒƒ์„ ๊ธฐ๋Œ€ํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ?

๋˜ํ•œ finishTransactionIOS ๋„ finishTransaction ๋„ ์‹ค์ œ๋กœ ํ•ด๋‹น ํŠธ๋žœ์žญ์…˜์„ ์ œ๊ฑฐํ•˜์ง€ ์•Š์•„ ์•ฑ์„ ์ถœ์‹œ ํ•  ์ˆ˜์—†๋Š” iOS์—์„œ๋„์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์—…๋ฐ์ดํŠธ?

@hyochan ๋ถ„๋ช…ํžˆ Objective-C์— ๋Šฅํ†ตํ•˜์ง€๋Š” ์•Š์ง€๋งŒ finishTransaction ๋ฐ finishTransactionWithIdentifier ์— ์ผ๋ถ€ ๋กœ๊ทธ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋Š”๋ฐ ์ œ๋Œ€๋กœ ์‹คํ–‰๋˜๊ณ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค (ID๊ฐ€ ์ „๋‹ฌ๋˜๊ณ  ์ผ์น˜ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค). ๋‚ด๊ฐ€ ์ƒ๊ฐํ•  ์ˆ˜์žˆ๋Š” ์œ ์ผํ•œ ๊ฒƒ์€ [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; ์ด ์‹ค์ œ๋กœ StoreKit์— ์—ฐ๊ฒฐ๋˜์–ด ํŠธ๋žœ์žญ์…˜์„ ์™„๋ฃŒํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ ์–ด๋””๋กœ ๊ฐ€์•ผํ• ์ง€ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ๋””๋ฒ„๊น… ํ•  ๋•Œ ๋„์›€์ด๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

App Store์˜ ๊ตฌ๋… ์ƒํƒœ ์•Œ๋ฆผ๋„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ์ œ ๊ฒฝ์šฐ์—๋Š” ์„œ๋ฒ„๊ฐ€ ๋ชจ๋“  ์•Œ๋ฆผ ์ด๋ฒคํŠธ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ณ  200์œผ๋กœ ์‘๋‹ต ํ•  ๋•Œ๊นŒ์ง€์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

@espenjanson ํฅ๋ฏธ

@lachlanglen ์‹ ๊ฒฝ

๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์กฐ์‚ฌํ•˜๊ณ  ์žˆ์—ˆ๊ณ  finishTransactions ํ˜ธ์ถœ์ด obj-c์—์„œ ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— undefined๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ๋งž์Šต๋‹ˆ๋‹ค.
๋ช‡ ๊ฐ€์ง€ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ–ˆ์œผ๋ฉฐ ์ œ ๊ฒฝ์šฐ์—๋Š” ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์™„๋ฃŒ ํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค (๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ, ๋ณด๋ฅ˜์ค‘์ธ ํŠธ๋žœ์žญ์…˜ ๊ฐ€์ ธ ์˜ค๊ธฐ, ์•„๋ฌด๊ฒƒ๋„ ์—†์œผ๋ฉด ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค)

@espenjanson Expo ํŒจํ‚ค์ง€๊ฐ€ ์ž˜ ๊ด€๋ฆฌ๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ์ด์œ ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. Expo๊ฐ€ ์ตœ๊ทผ์— iap ๋ชจ๋“ˆ์„ ์ถœ์‹œํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. iap์„ ๊ตฌํ˜„ํ•  ๋•Œ expo์— iap ๋ชจ๋“ˆ์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜๋‹ค๋ฉด ๋‘ ๋ฒˆ ์ƒ๊ฐํ•˜์ง€ ์•Š๊ณ  expo๋ฅผ ์„ ํƒํ–ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?
๋‚˜๋Š” ์ƒˆ๋กœ์šด sandbox ์‚ฌ์šฉ์ž๋กœ๋„ TestFlight์—์„œ ์ด๊ฒƒ์„ ํ…Œ์ŠคํŠธํ–ˆ์œผ๋ฉฐ ์—ฌ์ „ํžˆ ๊ณ„์† ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋‚ด purchaseUpdateListener "์ด์ „"๊ฑฐ๋ž˜๊ฐ€ ๊ณ„์† ์ˆ˜์‹ ๋ฉ๋‹ˆ๋‹ค.
์ž๋™ ๊ฐฑ์‹  ๊ตฌ๋…์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ finishTransaction(purchase,false) ๋กœ ์ „ํ™”ํ•ฉ๋‹ˆ๋‹ค.
ํ˜ธ์ถœ ๊ฒฐ๊ณผ๋Š” undefined ์ž…๋‹ˆ๋‹ค.

์•„๋ฌด๋„ ์ด๊ฒƒ์ด ์™œ ๋ฐœ์ƒํ•˜๋Š”์ง€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด๋‚˜ ์„ค๋ช…์„ ์ œ๊ณต ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

@zatloeri ๋ถ„๋ช…ํžˆ ์›ํ•˜๋Š” ํ–‰๋™์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์„ ๊นจ๋‹ซ๋Š” ๋ฐ ์‹œ๊ฐ„์ด ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค. App Store๋Š” ๊ด€์ฐฐ์ž๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” StoreKit์— ๊ฐฑ์‹ ์„์œ„ํ•œ ์ƒˆ ์˜์ˆ˜์ฆ์„ ๋„ฃ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜์ˆ˜์ฆ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฑฐ๋ž˜๋ฅผ ์™„๋ฃŒํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

https://developer.apple.com/videos/play/wwdc2018/705/
https://developer.apple.com/videos/play/wwdc2020/10671

(HD ํ’ˆ์งˆ์„ ์œ„ํ•ด Safari์—์„œ ์‹œ์ฒญ)

@ziyoshams ๋น ๋ฅธ ๋‹ต๋ณ€๊ณผ

ํ•˜์ง€๋งŒ ๋จผ์ € ํ•œ ๊ฐ€์ง€๋งŒ ์ง€์ ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋‚ด๊ฐ€ ๊ทธ๊ฒƒ์„ ์ ์ ˆํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ๋‹ค ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
๋‹น์‹ ์ด ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์€ ๋‚˜์—๊ฒŒ ๋…ผ๋ฆฌ์ ์œผ๋กœ ๋ณด์ด๋ฉฐ ์ด๊ฒƒ์ด ์ผ์–ด๋‚  ๊ฒƒ์ด๋ผ๊ณ  ์˜ˆ์ƒํ–ˆ์ง€๋งŒ ๋‚˜๋ฅผ ๋‹นํ™ฉํ•˜๊ฒŒํ•˜๋Š” ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

receipt validation ์˜ํ•ด ํ™•์ธ ๋œ ์ œํ’ˆ A ๊ฐ€ ๋งŒ๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
์•ฑ์„ ์‹œ์ž‘ํ•˜๊ฑฐ๋‚˜ ํฌ ๊ทธ๋ผ์šด๋“œ ํ•  ๋•Œ ์ œํ’ˆ A์— ๋Œ€ํ•œ ์ด์ „ (์ „๋‚ ๋ถ€ํ„ฐ) ํŠธ๋žœ์žญ์…˜์„ ์ˆ˜์‹ ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฐ ๋‹ค์Œ ๋‹ค์Œ ๋ฒˆ์— ์•ฑ์„ ๋‹ค์‹œ ํฌ ๊ทธ๋ผ์šด๋“œ ํ•  ๋•Œ ์ œํ’ˆ A์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ์˜ค๋ž˜๋œ (์•„๋งˆ๋„ ์ด์ „๋ณด๋‹ค ์กฐ๊ธˆ ๋” ์ƒˆ๋กญ๊ณ  ํ™•์‹คํ•˜์ง€ ์•Š์€) ํŠธ๋žœ์žญ์…˜์„๋ฐ›์Šต๋‹ˆ๋‹ค.
๋‹ค๋ฅธ ์ „๊ฒฝ์—์„œ ์•„๋งˆ๋„ ๋‹ค๋ฅธ ๊ฒƒ ๋“ฑ๋“ฑ.

๊ตฌ๋…์ด ์ด๋ฏธ ๋งŒ๋ฃŒ ๋œ ๊ฒฝ์šฐ ํ•˜๋‚˜์˜ ์•ฑ ์‹œ์ž‘์—์„œ ๋ชจ๋“  ๊ฒƒ์„ ์–ป์„ ์ˆ˜์žˆ์„ ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ ๋˜ํ•œ ์˜ˆ์ƒ๋˜๋Š” ๋™์ž‘์ž…๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ๋ญ”๊ฐ€ ์ด์ƒํ•œ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

@zatloeri ์™„๋ฃŒ๋˜์ง€ ์•Š์€ ๋ชจ๋“  ํŠธ๋žœ์žญ์…˜์€ ๋งŒ๋ฃŒ ๋œ ๊ฒฝ์šฐ์—๋„ ํ•ด๋‹น ๋Œ€๊ธฐ์—ด์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์›”๊ฐ„ ๊ตฌ๋…์˜ ๊ฒฝ์šฐ ์•ฝ 5 ๋ถ„๋งˆ๋‹ค ์˜์ˆ˜์ฆ์„ ๋ฐ›์•„์•ผํ•ฉ๋‹ˆ๋‹ค. ๋ฌผ๊ฑด์„ ๊ตฌ์ž…ํ•˜๊ณ  ๋‹ค์Œ๋‚  ์•ฑ์œผ๋กœ ๋Œ์•„ ์˜ค๋ฉด ๋™์‹œ์— 5 ~ 6 ๊ฐœ์˜ ์˜์ˆ˜์ฆ์„ ๋ฐ›๊ฒŒ๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ WWDC ๋น„๋””์˜ค๋ฅผ ์‹œ์ฒญํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ •๋ง ๋„์›€์ด๋ฉ๋‹ˆ๋‹ค.

iOS์—์„œ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ํŠธ๋žœ์žญ์…˜์ด ์™„๋ฃŒ๋˜์ง€ ์•Š์•„ ๋Œ€๊ธฐ์—ด์ด ๋น„์–ด ์žˆ์ง€ ์•Š๊ณ  ์•ฑ์ด ์‹œ์ž‘๋  ๋•Œ๋งˆ๋‹ค ์˜์ˆ˜์ฆ์ด ๋‹ค์‹œ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ์„œ๋ฒ„ ์ธก์—์„œ ์˜์ˆ˜์ฆ์„ ํ™•์ธํ•˜๊ณ  ๊ฑฐ๋ž˜๋ฅผ ๋งˆ์ณค์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ๋‚ด ์ฝ”๋“œ๋ฅผ ๋ด์ฃผ์„ธ์š”

์•„๋ž˜์— ๋‚ด ์ฝ”๋“œ์˜ ์ผ๋ถ€๋ฅผ ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค ...

```
import RNIap, {
InAppPurchase,
์ƒ์„ฑ๋ฌผ,
PurchaseError,
์‹ ์ฒญ,
SubscriptionPurchase,
finishTransaction,
finishTransactionIOS,
purchaseErrorListener,
purchaseUpdatedListener,
clearTransactionIOS,
} 'react-native-iap'์—์„œ;

async componentDidMount () {
const ๊ฒฐ๊ณผ = ๋Œ€๊ธฐ RNIap.initConnection ();
const itemSubs = Platform.select ({
android : [
get (this.props, 'subscriptionStore.subscription.android_product_id', null)
],
ios : [
get (this.props, 'subscriptionStore.subscription.ios_product_id', null)
]
});

const ๊ตฌ๋… = await RNIap.getSubscriptions (itemSubs);
purchaseUpdateSubscription = purchaseUpdatedListener (
๋น„๋™๊ธฐ (๊ตฌ๋งค) => {
const ์˜์ˆ˜์ฆ = purchase.transactionReceipt;
let subscription = {
subscription_id : get (this.props, 'subscriptionStore.subscription.id', null)
};
if (Platform.OS === 'ios') {
๊ตฌ๋… = {
...์‹ ์ฒญ,
order_id : get (๊ตฌ๋งค, 'transactionId', null),
buy_token : get (purchase, 'originalTransactionIdentifierIOS', null),
์˜์ˆ˜์ฆ : get (purchase, 'transactionReceipt', null), // (ํ…์ŠคํŠธ์— ์ €์žฅ)
os : 'IOS'
}
} else if (Platform.OS === 'android') {
const ๋ฐ์ดํ„ฐ = JSON.parse (receipt);
๊ตฌ๋… = {
...์‹ ์ฒญ,
order_id : get (data, 'orderId', null),
purchase_token : get (๋ฐ์ดํ„ฐ, 'purchaseToken', null),
os : 'ANDROID'
}
}
{
finishTransaction (๊ตฌ๋งค, ๊ฑฐ์ง“); // ์ด๊ฒƒ์€ ์ž„์‹œ๋ฅผ ์œ„ํ•ด ์—ฌ๊ธฐ์— ์žˆ์œผ๋ฉฐ ๋‚˜์ค‘์— ์„ฑ๊ณต์— ๋ฐฐ์น˜๋ฉ๋‹ˆ๋‹ค.
this.props.notificationStore.showToast ( '๊ตฌ๋…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ๋งŒ ๊ธฐ๋‹ค๋ ค์ฃผ์‹ญ์‹œ์˜ค ...', '์„ฑ๊ณต', 5000);
const resp = await this.props.subscriptionStore.onPurchase (subscription); // ์„œ๋ฒ„ ๋์—์„œ ํŠธ๋žœ์žญ์…˜์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
if (resp.success) {// ์„ฑ๊ณต ์‘๋‹ต
this.props.userStore.setUser ({is_premium : 1});
this.props.navigation.replace ( 'FixFooter');
}
} catch (์˜ค๋ฅ˜) {
console.log ( "onPurchase API ์˜ค๋ฅ˜ :", ์˜ค๋ฅ˜);
}
}
)

purchaseErrorSubscription = purchaseErrorListener (
๋น„๋™๊ธฐ (์˜ค๋ฅ˜) => {
console.log ( '๊ตฌ๋งค ์˜ค๋ฅ˜ :', ์˜ค๋ฅ˜);
}
)
}

/ * onPurchase ๋ฒ„ํŠผ * /
async onPurchase () {
{
const request = await RNIap.requestSubscription (Platform.OS === 'android'?
get (this.props, 'subscriptionStore.subscription.android_product_id', null) :
get (this.props, 'subscriptionStore.subscription.ios_product_id', null))
} catch (์˜ค๋ฅ˜) {
console.log ( '์˜ค๋ฅ˜ :', ์˜ค๋ฅ˜)
}
}

@ sufyan297 ์„œ๋ฒ„ ์ธก ์ฝ”๋“œ์—์„œ ์Šค ๋‹ˆํŽซ์„ ๊ณต์œ ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ์˜์ˆ˜์ฆ ํ™•์ธ ํ•ญ๋ชฉ๋„ ์„ค์ •ํ•˜๋ ค๊ณ ํ•˜๋Š”๋ฐ Apple์˜ ๋ฌธ์„œ๊ฐ€ ๋งค์šฐ ํ˜ผ๋ž€ ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

@ziyoshams expo iap ๋ชจ๋“ˆ finishTransaction ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ null์„ ์–ป์Šต๋‹ˆ๊นŒ?

@bcbcbcbcbcl ์ €๋Š” expo ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜์—๊ฒŒ +1 ๊ทธ๊ฒƒ์€ ์ •์˜๋˜์ง€ ์•Š์€ ๋ฐ˜ํ™˜

@hyochan ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ์šฐ๋ฆฌ๋Š” ๊ฝค ์˜ค๋žซ๋™์•ˆ ๊ฐ‡ํ˜€ ์žˆ์—ˆ๊ณ  ์•ฑ์„ ๊ฒŒ์‹œ ํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š”. ์ตœ๊ทผ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ™œ๋™์ด์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ ๋˜์—ˆ์Šต๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ์—ฌ์ „ํžˆ ์ปค๋ฎค๋‹ˆํ‹ฐ์˜์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๊นŒ? ์ด ๋ฌธ์ œ๋Š” ๋” ์ด์ƒ ํ™œ๋™์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉด ์ข…๊ฒฐ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ "ํ† ๋ก  ์šฉ"๋˜๋Š” "์ข‹์€ ์ฒซ ๋ฒˆ์งธ ๋ฌธ์ œ"๋กœ ํ‘œ์‹œ ํ•  ์ˆ˜๋„ ์žˆ์œผ๋ฉฐ ์—ด์–ด ๋‘๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ๊ธฐ์—ฌ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰