הצעות מבצעיות למנויים קיימים: הגדרה ואינטגרציה

כאשר מנויים מבטלים את המנוי שלהם, השבתם חזרה יכולה להיות מאתגרת. אנו מגדירים Promotional Offers—הצעות מותאמות אישית לשמירה והחזרת משתמשים. הצוות שלנו מספק אינטגרציה מלאה, כולל חתימה בצד השרת באמצעות ECDSA, עם תמיכה מתמשכת.

פיתוח ותמיכה בכל סוגי היישומים הניידים:

יישומים ניידים למידע ובידור
אפליקציות חדשות, משחקים, מדריכים, קטלוגים מקוונים, אפליקציות מזג אוויר, אפליקציות כושר ובריאות, אפליקציות נסיעות, אפליקציות חינוכיות, רשתות חברתיות ומסנג'רים, חידונים, בלוגים ופודקאסטים, פורומים, אגרגטורים
יישומים ניידים למסחר אלקטרוני
חנויות מקוונות, אפליקציות B2B, מרקטפלייסים, בורסות מקוונות, שירותי קאשבק, בורסות, פלטפורמות דרופשיפינג, תוכניות נאמנות, משלוחי מזון ומוצרים, מערכות תשלום.
יישומים ניידים לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, ניהול פרויקטים, כלים לצוותי מכירות, ניהול פיננסי, ניהול ייצור, ניהול לוגיסטיקה ומשלוחים, ניהול משאבי אנוש, מערכות ניטור נתונים
יישומים ניידים לשירותים אלקטרוניים
פלטפורמות מודעות מסווגות, בתי ספר מקוונים, בתי קולנוע מקוונים, פלטפורמות שירות אלקטרוניות, פלטפורמות קאשבק, אירוח וידאו, פורטלים נושאיים, פלטפורמות הזמנות ותזמון מקוונות, פלטפורמות מסחר מקוונות

אלה הם רק חלק מסוגי היישומים הניידים שאנו עובדים איתם, ולכל אחד מהם עשויים להיות מאפיינים ופונקציונליות ספציפיים משלו, המותאמים לצרכים ולמטרות הספציפיות של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 1734 השירותים
הצעות מבצעיות למנויים קיימים: הגדרה ואינטגרציה
בינוני
~3-5 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית מובייל עבור FEEDME
    פיתוח אפליקציית מובייל עבור FEEDME
    971
  • פיתוח אפליקציית מובייל עבור XOOMER
    פיתוח אפליקציית מובייל עבור XOOMER
    868
  • פיתוח אפליקציית מובייל עבור RHL
    פיתוח אפליקציית מובייל עבור RHL
    1288
  • פיתוח אפליקציית מובייל עבור ZIPPY
    פיתוח אפליקציית מובייל עבור ZIPPY
    1143
  • פיתוח אפליקציית מובייל עבור Affhome
    פיתוח אפליקציית מובייל עבור Affhome
    1076
  • פיתוח אפליקציית מובייל עבור חברת FLAVORS
    פיתוח אפליקציית מובייל עבור חברת FLAVORS
    677

הטמעת הצעות קידום למנויים קיימים באפליקציות מובייל

לעתים קרובות אנו נתקלים באתגר: כיצד להחזיר משתמש שביטל את המנוי שלו, או למנוע ביטול מלכתחילה? במקרים כאלה, אנו משתמשים בהצעות קידום (Promotional Offers)—הנחות מותאמות אישית למשתמשים שהיה להם בעבר מנוי. בניגוד להצעות היכרות (Introductory Offers), שפועלות רק למנויים חדשים פעם אחת, ניתן להציע הצעות קידום מספר פעמים למנויים לשעבר ולמנויים נוכחיים. תרחישים אופייניים: החזרת משתמש לאחר ביטול, מניעת ביטול (תקופת חסד) עם תקופה חינמית, ושדרוג לדרגה גבוהה יותר עם הנחה.

מדוע חתימה בצד השרת היא קריטית

Apple דורשת שכל הצעת קידום תיחתם עם מפתח פרטי ECDSA (P-256). החתימה נוצרת בשרת שלך באמצעות קובץ ה-.p8 מ-App Store Connect. בלעדיה, StoreKit 2 מחזיר שגיאת invalidSignature. אנו מבטיחים יצירת חתימה נכונה, תוך עמידה בכל דרישות Apple. במשך יותר מ-5 שנים, הטמענו הצעות קידום ביותר מ-20 פרויקטים, והגדלנו את שיעור ההמרה להחזרת משתמשים ב-30% בממוצע.

ההבדל בין הצעות קידום להצעות היכרות

הצעת היכרות הצעת קידום
למי מנויים חדשים מנויים קיימים/לשעבר
כמה פעמים פעם אחת מספר פעמים
דורש חתימת שרת לא כן—חובה
תצורה App Store Connect App Store Connect + שרת

חתימה בצד השרת היא ההבדל המרכזי. Apple דורשת שההצעה תיחתם עם מפתח פרטי שנוצר ב-App Store Connect. בלעדיה, ההצעה לא תחול—StoreKit מחזיר שגיאת invalidSignature.

כיצד להגדיר הצעת קידום ב-App Store Connect

  1. מנויים (Subscriptions) → [המנוי] → הצעות קידום (Promotional Offers) → +
  2. הגדר את שם הייחוס (Reference Name), מזהה ההצעה (Offer ID), סוג (freeTrial / payAsYouGo / payUpFront), משך ומחיר
  3. שמור את מזהה ההצעה—הוא יידרש בעת יצירת החתימה

במקביל: מפתחות (Keys) → מפתח מנוי (Subscription Key) → צור מפתח, הורד את קובץ ה-.p8, ושים לב למזהה המפתח (Key ID).

חתימה בצד השרת: אלגוריתם ופרמטרים

השרת יוצר חתימה באמצעות ECDSA עם מפתח .p8. פרמטרים:

  • appBundleId — מזהה ה-Bundle של האפליקציה
  • keyIdentifier — מזהה המפתח מ-App Store Connect
  • productIdentifier — מזהה המוצר
  • offerIdentifier — מזהה ההצעה
  • applicationUsername — מזהה המשתמש במערכת שלך (אופציונלי אך מומלץ)
  • nonce — UUID, נוצר בצד השרת
  • timestamp — זמן נוכחי במילישניות

החתימה נוצרת על ידי שרשור ערכים אלה עם \n, וחתימה עם SHA-256 ECDSA:

# Python-пример для сервера (упрощённо)
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
import base64, uuid, time

def generate_signature(bundle_id, key_id, product_id, offer_id, username):
    nonce = str(uuid.uuid4()).lower()
    timestamp = str(int(time.time() * 1000))
    message = "\n".join([bundle_id, key_id, product_id, offer_id, username, nonce, timestamp])
    private_key = serialization.load_pem_private_key(PRIVATE_KEY_PEM, password=None)
    signature = private_key.sign(message.encode(), ec.ECDSA(hashes.SHA256()))
    encoded = base64.b64encode(signature).decode()
    return {"nonce": nonce, "timestamp": timestamp, "signature": encoded, "keyIdentifier": key_id}

השרת מחזיר נתונים אלה ללקוח; הלקוח משתמש בהם בעת השלמת הרכישה.

הטמעה בצד הלקוח (StoreKit 2)

import StoreKit

// Получаем параметры подписи с сервера
let signatureData = try await apiClient.fetchPromoOfferSignature(
    productId: "premium_monthly",
    offerId: "win_back_30_percent"
)

// Получаем продукт
guard let product = try? await Product.products(for: ["premium_monthly"]).first else { return }

// Находим оффер по ID
guard let offer = product.subscription?.promotionalOffers.first(where: { $0.id == "win_back_30_percent" }) else { return }

// Создаём объект подписанного оффера
let signedOffer = try await offer.purchase(
    confirmIn: self, // WindowScene или UIViewController
    options: [
        .promotionalOffer(
            offerIdentifier: signatureData.offerId,
            keyIdentifier: signatureData.keyIdentifier,
            nonce: UUID(uuidString: signatureData.nonce)!,
            signature: Data(base64Encoded: signatureData.signature)!,
            timestamp: signatureData.timestamp
        )
    ]
)

לפרטים נוספים, ראה תיעוד StoreKit 2 של Apple

כיצד לבדוק זכאות?

הזכאות היא באחריות המפתח. Apple לא בודקת אם מותר לך להציג הצעה. אנו מיישמים בדיקות זכאות בצד השרת: אנו בודקים את היסטוריית העסקאות דרך Apple Server Notifications v2 או מנתחים את הקבלה (receipt). משתמש מקבל את ההצעה אם הוא היה מנוי לפחות פעם אחת. זה מונע יישום שגוי ומגן מפני דליפת הכנסות.

טעויות נפוצות והניסיון שלנו

זיהינו שלוש בעיות תכופות:

  • חותמת זמן שפגה. החתימה תקפה ל-24 שעות. אם היא נשמרת במטמון זמן רב יותר, Apple מחזירה שגיאה. צור את החתימה ממש לפני הצגת ה-paywall, לא בעת השקת האפליקציה.
  • Nonce שגוי. ה-nonce חייב להיות באותיות קטנות (# Python-пример для сервера (упрощённо) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ec import base64, uuid, time def generate_signature(bundle_id, key_id, product_id, offer_id, username): nonce = str(uuid.uuid4()).lower() timestamp = str(int(time.time() * 1000)) message = "\n".join([bundle_id, key_id, product_id, offer_id, username, nonce, timestamp]) private_key = serialization.load_pem_private_key(PRIVATE_KEY_PEM, password=None) signature = private_key.sign(message.encode(), ec.ECDSA(hashes.SHA256())) encoded = base64.b64encode(signature).decode() return {"nonce": nonce, "timestamp": timestamp, "signature": encoded, "keyIdentifier": key_id} ). רישיות משפיעה על תקינות החתימה.
  • הצגת ההצעה לכולם. בדיקת זכאות להצעות קידום היא באחריות המפתח. Apple לא חוסמת את הרכישה אם הזכאות לא אומתה. יש צורך בבדיקת היסטוריית עסקאות בצד השרת: האם המשתמש היה מנוי לפחות פעם אחת?

השוואה: הגישה שלנו עם חתימה בצד השרת אמינה ב-30% יותר מיישום מלא בצד הלקוח (שבלתי אפשרי, אבל חלק מנסים לעקוף ללא חתימה—ניסיונות כאלה נכשלים בוודאות בסביבת הייצור).

מה כלול בעבודה במפתח מוכן

  • הגדרת הצעת הקידום ב-App Store Connect
  • Endpoint בשרת ליצירת חתימה (ECDSA)
  • אינטגרציה של StoreKit 2 בצד הלקוח עם אפשרויות import StoreKit // Получаем параметры подписи с сервера let signatureData = try await apiClient.fetchPromoOfferSignature( productId: "premium_monthly", offerId: "win_back_30_percent" ) // Получаем продукт guard let product = try? await Product.products(for: ["premium_monthly"]).first else { return } // Находим оффер по ID guard let offer = product.subscription?.promotionalOffers.first(where: { $0.id == "win_back_30_percent" }) else { return } // Создаём объект подписанного оффера let signedOffer = try await offer.purchase( confirmIn: self, // WindowScene или UIViewController options: [ .promotionalOffer( offerIdentifier: signatureData.offerId, keyIdentifier: signatureData.keyIdentifier, nonce: UUID(uuidString: signatureData.nonce)!, signature: Data(base64Encoded: signatureData.signature)!, timestamp: signatureData.timestamp ) ] )
  • בדיקת זכאות (היסטוריית עסקאות בצד השרת)
  • בדיקות בסביבת Sandbox באמצעות StoreKit Configuration File
רשימת בדיקה לדוגמה לשלב הבדיקות - בדוק חתימה עם חותמת זמן שפגה - בדוק חתימה עם nonce שגוי - בדוק רכישה ללא זכאות - בדוק שימוש חוזר בהצעה

לוחות זמנים ועלות

לוחות זמנים משוערים: 3–5 ימים, כולל עבודת שרת. אם תשתית השרת כבר קיימת, 2–3 ימים. העלות מחושבת באופן אישי—צור קשר להערכת פרויקט. קבל ייעוץ ואחריות על אינטגרציה נכונה.