SubSovereign
All guides

SubSovereign iOS पर — एकीकरण गाइड

यह गाइड आपके Apple ऐप (iPhone, iPad, Apple TV, या Mac) को "मुझे नहीं पता किसने भुगतान किया" से "मेरा ऐप सही उपयोगकर्ता के लिए सही सुविधाएँ अनलॉक करता है, मेरे अपने सर्वर पर सत्यापित" तक ले जाती है। इसे शुरू से अंत तक क्रम में पढ़ने के लिए लिखा गया है — सदस्यता टूलिंग का पूर्व अनुभव आवश्यक नहीं है।

SubSovereign आपके लिए क्या करता है

आपके उपयोगकर्ता App Store के माध्यम से सदस्यता लेते हैं। SubSovereign आपके ऐप के लिए एक सवाल का भरोसेमंद जवाब देता है: इस उपयोगकर्ता ने वास्तव में किसके लिए भुगतान किया है?

  • आपका ऐप SubSovereign से उपयोगकर्ता की अधिकार-प्राप्ति माँगता है — वह पहुँच जो उन्होंने अनलॉक की है।
  • रसीद सत्यापन सर्वर पर होता है, सीधे Apple (App Store Server API) के साथ, ताकि कोई संशोधित ऐप सदस्यता की नकल न कर सके।
  • पेवॉल — वह स्क्रीन जो आपकी योजनाएँ प्रस्तुत करती है — दूर से कॉन्फ़िगर की जाती है, इसलिए आप नया ऐप संस्करण जारी किए बिना कीमतें, ट्रायल, और शब्द बदल सकते हैं।
  • यह स्व-होस्टेड है: SubSovereign आपके अपने इन्फ्रास्ट्रक्चर पर चलता है, आपके उपयोगकर्ताओं का डेटा आपके पास रहता है, और राजस्व का कोई हिस्सा नहीं लिया जाता — आपके उपयोगकर्ता जो भुगतान करते हैं उसका 100% आपका है।

आप डिवाइस पर कभी भरोसा नहीं करते। डिवाइस अनुरोध करता है; सर्वर निर्णय लेता है। यही कोड iOS, tvOS (Apple TV), और macOS पर चलता है।

शुरू करने से पहले

आपको चाहिए होगा:

  1. एक चालू SubSovereign सर्वर (आपका स्व-होस्टेड डिप्लॉयमेंट) — SDK इसके URL की ओर इशारा करता है।
  2. डैशबोर्ड में पंजीकृत एक ऐप, जो आपको एक appId और एक API key (वह क्रेडेंशियल जिसका उपयोग आपका ऐप सर्वर से बात करने के लिए करता है) देता है।
  3. पहुँच स्तर बनाए गए — आपके ऐप द्वारा दिए जाने वाले पहुँच स्तर (टियर), जैसे pro, प्रत्येक डैशबोर्ड में App Store उत्पाद ID से जुड़ा हुआ जो आपके उपयोगकर्ता खरीदते हैं।
  4. StoreKit 2 सेटअप। SubSovereign खरीदारी को सत्यापित और ट्रैक करता है; यह StoreKit की जगह नहीं लेता। StoreKit 2 से खरीदारी सामान्य रूप से संभालें — SubSovereign एक सफल लेन-देन के ठीक बाद उसे सत्यापित और दर्ज करने के लिए आता है।

कोड की तरफ से आपको Swift concurrency (async/await) और iOS 15 / tvOS 15 / macOS 12 या बाद का डिप्लॉयमेंट लक्ष्य चाहिए।

चरण 1 — SDK जोड़ें

SubSovereign को Swift Package Manager से जोड़ें — Xcode में, File ▸ Add Packages… और इसे SubSovereign SDK पैकेज की ओर इंगित करें (या इसे अपनी Package.swift डिपेंडेंसी में जोड़ें)। फिर इसे इम्पोर्ट करें:

import SubSovereign

चरण 2 — एक बार कॉन्फ़िगर करें, जब आपका ऐप शुरू हो

SDK को एक ही बार कॉन्फ़िगर करें — इसके लिए अच्छी जगह है आपका App init, या उपयोगकर्ता के साइन इन करने के ठीक बाद। आप इसे अपनी API key, ऐप ID, सर्वर URL, इस उपयोगकर्ता के लिए एक स्थिर पहचानकर्ता, और उनकी भाषा देते हैं।

SubSovereign.shared.configure(
    SubSovereignConfig(
        apiKey:  "YOUR_APP_API_KEY",                 // from the dashboard
        appId:   "your-app-id",                      // from the dashboard
        baseURL: "https://subs.yourdomain.com/api/v1", // YOUR self-hosted server
        userId:  currentUser.id,                     // your own stable user id
        locale:  Locale.current.identifier           // the user's language
    )
)

कुछ ज़रूरी बातें:

  • userId आपका है। जो भी स्थिर ID आपके पास साइन-इन उपयोगकर्ता के लिए पहले से है उसका उपयोग करें, और हर बार वही मान दें, ताकि पहुँच उनके सभी डिवाइस पर उनके साथ चले। यदि कोई अलग उपयोगकर्ता साइन इन करे, तो नए userId के साथ फिर से configure कॉल करें।
  • baseURL आपके अपने सर्वर की ओर इशारा करता है — SDK का डिफ़ॉल्ट एक प्लेसहोल्डर है; अपना डिप्लॉयमेंट सेट करें।
  • SDK को @MainActor एनोटेट किया गया है, इसलिए इसे main actor से कॉल करें (SwiftUI views और .task ठीक हैं)।

चरण 3 — जाँचें कि उपयोगकर्ता क्या एक्सेस कर सकता है

उपयोगकर्ता ने क्या अनलॉक किया है यह जानने के लिए checkEntitlements() कॉल करें। इसे लॉन्च पर और खरीदारी के ठीक बाद करें। यह एक async कॉल है जो throw कर सकता है, इसलिए इसे do/catch में लपेटें:

do {
    let result = try await SubSovereign.shared.checkEntitlements()
    if result.hasAccess {
        unlockProFeatures()          // the user has paid access
    } else {
        showFreeExperience()         // free tier / show a paywall
    }
} catch {
    // Network hiccup or server error. Fail gracefully — usually keep the user on
    // whatever access they last had, and try again later.
    print("Entitlement check failed: \(error.localizedDescription)")
}

hasAccess त्वरित हाँ/नहीं का जवाब है। यदि आपके ऐप में एक से अधिक टियर हैं, तो result.entitlements के अंदर देखें — प्रत्येक सक्रिय पहुँच स्तर का नाम देता है:

let isPro = result.entitlements.contains { $0.isActive && $0.accessLevelId == "pro" }

प्रत्येक अधिकार-प्राप्ति में expiresAt, willRenew, और वह store भी होता है जहाँ से यह आया। यदि सर्वर संक्षेप में अनुपलब्ध था और SDK ने अपनी अंतिम-ज्ञात स्थिति से जवाब दिया, तो fromCache true होगा।

चरण 4 — सदस्यता बेचें

पेवॉल दिखाएँ

कीमतें हार्ड-कोड करने की बजाय सर्वर से पेवॉल प्राप्त करें, ताकि आप बिना रिलीज़ के कोई सेल चला सकें या ट्रायल बदल सकें:

if let paywall = try? await SubSovereign.shared.getPaywallConfig() {
    renderPaywall(paywall)   // headline, features, products…
} else {
    renderFallbackPaywall()  // your built-in default
}

PaywallConfig आपको एक headline, subheadline, features की सूची, पेश किए जाने वाले products (प्रत्येक में displayPrice, period, trialDays, और वैकल्पिक badge), call-to-action टेक्स्ट, और फ़ुटर टेक्स्ट देता है। आप वास्तविक स्क्रीन बनाते हैं — SubSovereign बताता है कि उस पर क्या लिखना है।

खरीदारी पूरी करें, फिर सत्यापित करें

खरीदारी StoreKit 2 के ज़रिए सामान्य रूप से चलाएँ। जब आपको एक सत्यापित Transaction वापस मिले, इसे SubSovereign को दें ताकि सर्वर सीधे Apple के साथ इसे सत्यापित कर पहुँच स्तर प्रदान कर सके:

// after `let result = try await product.purchase()` and verifying the transaction
if case .verified(let transaction) = verification {
    let granted = try await SubSovereign.shared.validateApplePurchase(
        transaction: transaction,
        accessLevelId: "pro"          // which tier this product grants
    )
    if granted {
        await SubSovereign.shared.finishTransaction(transaction) // tell StoreKit it's done
        _ = try await SubSovereign.shared.checkEntitlements()     // re-check, then unlock
    }
}

यही पूरा विश्वास मॉडल है: खरीदारी तभी वास्तविक होती है जब सर्वर ने Apple के साथ इसकी पुष्टि कर ली हो।

चरण 5 — गोपनीयता और GDPR

जहाँ आप सहमति लेते हैं वहाँ उसे दर्ज करें, और Apple की डेटा-अधिकार अपेक्षाओं का पालन करें — SDK सहमति, मिटाने, और निर्यात की सुविधा देता है:

try await SubSovereign.shared.recordConsent(purpose: "analytics", granted: true)

// If the user asks to be forgotten / to get their data:
try await SubSovereign.shared.requestErasure()
let myData = try await SubSovereign.shared.exportMyData()

jurisdiction का डिफ़ॉल्ट "GDPR" है और policyVersion का "1.0" — यदि आपका भिन्न हो तो अपना पास करें।

त्रुटियाँ संभालना

हर throwing कॉल एक typed SubSovereignError के साथ विफल होती है — .notConfigured, .networkError, .serverError(code, message), .decodingError, या .storeKitError। इसे catch करें और तय करें क्या करना है, बजाय इसके कि यह क्रैश के रूप में सामने आए:

  • सफलता — मान का उपयोग करें।
  • विफलता — इसे लॉग करें, उपयोगकर्ता को उनकी अंतिम-ज्ञात पहुँच पर रखें, बाद में पुनः प्रयास करें। किसी भुगतान करने वाले उपयोगकर्ता को क्षणिक नेटवर्क समस्या के कारण कभी लॉक आउट न करें।

सर्वोत्तम अभ्यास

  • लॉन्च पर जाँचें। जब ऐप शुरू हो तो checkEntitlements() कॉल करें (जैसे SwiftUI .task से) ताकि उपयोगकर्ता किसी लॉक फ़ीचर तक पहुँचने से पहले गेटिंग सही हो।
  • खरीदने के बाद फिर जाँचें। सफल validateApplePurchase के ठीक बाद checkEntitlements() फिर कॉल करें ताकि UI तुरंत अपडेट हो।
  • क्लाइंट पर भरोसा न करें। ऐप में "is pro" स्टोर करके उसे सत्य न मानें — सर्वर से पूछें; सर्वर ने Apple के साथ लेन-देन सत्यापित किया है।
  • प्रत्येक वास्तविक उपयोगकर्ता के लिए एक userId इसे स्थिर रखें ताकि पहुँच उपयोगकर्ता के सभी Apple डिवाइस पर उनके साथ चले, और साइन-इन उपयोगकर्ता बदलने पर पुनः कॉन्फ़िगर करें।

त्वरित संदर्भ

आप चाहते हैं… कॉल
SDK सेट करना SubSovereign.shared.configure(config)
उपयोगकर्ता ने क्या अनलॉक किया देखना try await checkEntitlements()EntitlementResult
दूरस्थ पेवॉल दिखाना try await getPaywallConfig()PaywallConfig
StoreKit 2 खरीदारी सत्यापित करना try await validateApplePurchase(transaction:accessLevelId:)
लेन-देन समाप्त करना await finishTransaction(transaction)
GDPR सहमति दर्ज करना try await recordConsent(purpose:granted:)
उपयोगकर्ता का डेटा मिटाना / निर्यात करना try await requestErasure() / exportMyData()

अगले कदम