React-native-iap: `android.test.canceled` ์ œํ’ˆ์„ ๊ตฌ๋งคํ•˜๋ฉด ์•ฑ์ด ๋‹ค์šด ๋จ

์— ๋งŒ๋“  2019๋…„ 01์›” 28์ผ  ยท  5์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: dooboolab/react-native-iap

react-native-iap ๋ฒ„์ „

2.4.0- ๋ฒ ํƒ€ 8

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

0.55.4

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

๊ธฐ๊ณ„์  ์ธ์กฐ ์ธ๊ฐ„

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

E_USER_CANCELLED, "Cancelled." ๊ตฌ๋งค ์•ฝ์†์ด ๊ฑฐ๋ถ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์‹ค์ œ ํ–‰๋™

์•ฑ ์ถฉ๋Œ :

01-28 11:21:58.177 2773-2919/ D/RNIapModule: buyItemByType (type: inapp, sku: android.test.canceled, oldSku: null, prorationMode: 0) responseCode: 0(OK)
01-28 11:22:03.509 2773-2919/ D/RNIapModule: Purchase Updated Listener
01-28 11:22:03.509 2773-2919/ D/RNIapModule: responseCode: 0

                                                                       --------- beginning of crash
01-28 11:22:03.510 2773-2919/ E/AndroidRuntime: FATAL EXCEPTION: mqt_native_modules
                                                                          Process: , PID: 2773
                                                                          java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference
                                                                              at com.dooboolab.RNIap.RNIapModule$11.onPurchasesUpdated(RNIapModule.java:436)
                                                                              at com.android.billingclient.api.BillingClientImpl$1.onReceiveResult(BillingClientImpl.java:151)
                                                                              at android.os.ResultReceiver$MyRunnable.run(ResultReceiver.java:50)
                                                                              at android.os.Handler.handleCallback(Handler.java:789)
                                                                              at android.os.Handler.dispatchMessage(Handler.java:98)
                                                                              at android.os.Looper.loop(Looper.java:164)
                                                                              at com.facebook.react.bridge.queue.MessageQueueThreadImpl$3.run(MessageQueueThreadImpl.java:192)
                                                                              at java.lang.Thread.run(Thread.java:764)

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

์‹ค์ œ ์žฅ์น˜

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

  • Android ์ •์  ํ…Œ์ŠคํŠธ ์ œํ’ˆ ๊ตฌ๋งค android.test.canceled
  • onPurchasesUpdated ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด purchases ๊ฐ€ @Nullable ์ด๊ณ  ย null ์ด๊ณ  responseCode ์ด๋ฏ€๋กœ 436 ํ–‰ Purchase purchase = purchases.get(0); ์—์„œ NPE๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค responseCode ๋Š” 0์ž…๋‹ˆ๋‹ค.
๐Ÿ› bug ๐Ÿšถ๐Ÿป stale ๐Ÿค– android

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

@johnmartel ๋„ค. ๋‚˜๋Š” ํ•ญ์ƒ ์ผ๋ถ€ ํ…Œ์ŠคํŠธ ๋ชจ๋“ˆ์„ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์ง€๋งŒ ํ˜„์žฌ๋Š” ํ•ญ์ƒ ์‹œ๊ฐ„์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค ๐Ÿ˜ฟ. ๋ฆด๋ฆฌ์Šคํ•˜๊ธฐ ์ „์— ์ง์ ‘ ๋Ÿฐํƒ€์ž„์„ ํ™•์ธํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

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

์†”๋ฃจ์…˜์— ๋ฌธ์ œ๋ฅผ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. @johnmartel ๋ฌธ์ œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ด๋ฏธ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด PR ๋ฅผ ์ฃผ์…จ์œผ๋ฉด ํ•ฉ๋‹ˆ๋‹ค.

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

@johnmartel ๋„ค. ๋‚˜๋Š” ํ•ญ์ƒ ์ผ๋ถ€ ํ…Œ์ŠคํŠธ ๋ชจ๋“ˆ์„ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์ง€๋งŒ ํ˜„์žฌ๋Š” ํ•ญ์ƒ ์‹œ๊ฐ„์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค ๐Ÿ˜ฟ. ๋ฆด๋ฆฌ์Šคํ•˜๊ธฐ ์ „์— ์ง์ ‘ ๋Ÿฐํƒ€์ž„์„ ํ™•์ธํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

purchases ์ด null ํ•˜๋Š” ๊ฒƒ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

  PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
    <strong i="8">@Override</strong>
    public void onPurchasesUpdated(int responseCode, <strong i="9">@Nullable</strong> List<Purchase> purchases) {
      Log.d(TAG, "Purchase Updated Listener");
      Log.d(TAG, "responseCode: " + responseCode);

      if (responseCode != BillingClient.BillingResponse.OK) {
        rejectPromisesWithBillingError(PROMISE_BUY_ITEM, responseCode);
        return;
      }

+      if (purchases == null) {
+        rejectPromisesWithBillingError(PROMISE_BUY_ITEM , responseCode);
+       return;
+      }

      Purchase purchase = purchases.get(0);

     // ...

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

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