במהלך בדיקות IAP לפני העלאה, נתקלנו בתקלה קלאסית אבל מאוד מבלבלת:
- המשתמש לוחץ על „המשך רכישה”
- הכפתור עובר למצב „מעבד”
- אחרי כמה שניות הוא חוזר ל„המשך רכישה”
- חלון אישור הרכישה של App Store לא מופיע
במאמר הזה מתועד מסלול החקירה המלא, הלוגים הקריטיים, גורם השורש ודרך תיקון פרקטית שמתאימה לשלב שלפני השקה.
1. התופעה
רשימת המוצרים במסך הרכישה נטענה כרגיל, אבל אחרי לחיצה על רכישה:
- נקראה הפונקציה
purchase() - לא הופיע חלון מערכת
- ה‑UI חזר בסוף למצב „לא נרכש”
במבט ראשון נראה היה ש„תהליך הרכישה בכלל לא התחיל”, אבל הלוגים הראו תמונה אחרת.
2. בדיקה ראשונה: האם זרימת הרכישה באמת רצה
הוספנו לוגים לכל נקודות המפתח בזרימת הרכישה:
- פרמטרים של לחיצה על הכפתור
- כניסה ל‑
purchaseSelectedProduct()וענפיguard - לפני/אחרי
product.purchase() Transaction.updatesrefreshEntitlements()Transaction.currentEntitlementsTransaction.latest(for:)
התוצאה:
purchase()החזירה.success- אימות העסקה הצליח, וגם
transaction.finish()רץ - אבל
entitledIDsנשאר ריק
המסקנה: זו לא בעיה של „הרכישה לא התחילה”, אלא של „אחרי רכישה ההרשאות לא מזוהות”.
3. ממצאים קריטיים אחרי העמקה
אחרי הרחבת הלוגים הופיעו כמה סימנים מכריעים:
- מספר האיטרציות של
Transaction.currentEntitlementsהיה0 -
Transaction.latest(for: monthly)החזירה רשומה תקינה, אבל פגת תוקף - חשוב יותר: לפני הרכישה היו עסקאות ישנות בתוך
Transaction.unfinished - ה‑
purchase()הנוכחי החזיר עסקה משרשרת ישנה, ולא מרכישה אינטראקטיבית חדשה
זה מסביר למה „אין חלון קופץ”:
- StoreKit מחזירה קודם עסקה ישנה שניתנת לעיבוד (unfinished / שרשרת היסטורית)
- הקוד שלכם מסיים אותה עם
finish() - הבקשה נראית „מוצלחת”, אבל לא עוברת במסלול אישור רכישה חדש שהמשתמש מצפה לו
4. סיכום גורם השורש
לא מדובר בכשל נקודתי אחד, אלא בשילוב של שני גורמים:
- עסקאות לא גמורות (
unfinished transaction) שמפריעות לזרימת הרכישה - שרשרת מנוי Sandbox במצב פג תוקף (גם אם קיימת
latest transaction, זה לא בהכרח entitlement פעיל)
ולכן ההתנהגות הסופית: אין חלון אישור, הצלחה לכאורה, וההרשאות נשארות ריקות.
5. אסטרטגיית תיקון (נבדקה בפועל)
5.1 ניקוי יזום של unfinished לפני רכישה
בעת הפעלת האפליקציה ולפני לחיצה על רכישה, סרקו את Transaction.unfinished והפעילו finish() על עסקאות מאומתות, כדי למנוע מעסקאות ישנות „לחטוף” את הזרימה החדשה.
5.2 להשאיר ולחזק לוגים דיאגנוסטיים (מומלץ לפני השקה)
כדאי להשאיר את הלוגים הבאים פעילים עד העלאה:
- Snapshot של
unfinished transaction subscription status(state, renewal info)- ספירת איטרציות של
currentEntitlements - פרטי
transaction/expirationמתוךlatest(for:)
5.3 אימות הרשאות ב„ערוץ כפול” (שדרוג אופציונלי)
אם בסביבות מסוימות currentEntitlements ריק זמנית, אפשר להשתמש ב‑latest(for:) כ‑fallback (תוך אימות שהסטטוס עדיין פעיל).
6. צ’קליסט IAP לפני השקה
- לפני כל בדיקה, אשרו את מצב המנוי של חשבון ה‑Sandbox (פג תוקף או לא)
- הדפיסו את כמות ה‑
unfinishedבנתיבים הקריטיים - בדקו שלושה תרחישים: „רכישה ראשונה / חידוש אחרי פקיעה / שחזור רכישות”
- ודאו עקביות בין
currentEntitlementsל‑latest - אם יש „בלי חלון”, בדקו קודם אם הזרימה נפלה על שרשרת עסקה ישנה
7. סיכום
„ללחוץ קנייה בלי חלון” לא בהכרח אומר בעיית UI או טיימינג של הקריאה.
ב‑StoreKit 2, מצב העסקאות, תור unfinished ומחזור החיים של המנוי משפיעים ישירות על ההתנהגות בפועל.
הוספת הלוגים והניקוי האלה לפני השקה מצמצמת משמעותית תקלות IAP שקשה לשחזר בפרודקשן.