Skip to main content

storekit/
store_context.rs

1use serde::Deserialize;
2
3use crate::app_store::AppStore;
4use crate::app_transaction::AppTransaction;
5use crate::error::StoreKitError;
6use crate::ffi;
7use crate::product::Product;
8use crate::receipt_validator::{AppReceipt, ReceiptValidator};
9use crate::storefront::Storefront;
10use crate::transaction::{Transaction, TransactionStream};
11use crate::verification_result::VerificationResult;
12
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct StoreContext {
15    pub bundle_identifier: Option<String>,
16    pub bundle_name: Option<String>,
17    pub bundle_version: Option<String>,
18    pub receipt_url: Option<String>,
19    pub can_make_payments: bool,
20    pub device_verification_id: Option<String>,
21    pub is_bundled: bool,
22    pub executable_path: Option<String>,
23}
24
25impl StoreContext {
26    pub fn current() -> Result<Self, StoreKitError> {
27        let mut context_json = core::ptr::null_mut();
28        let mut error_message = core::ptr::null_mut();
29        let status = unsafe { ffi::sk_store_context_json(&mut context_json, &mut error_message) };
30        if status != ffi::status::OK {
31            return Err(unsafe { crate::private::error_from_status(status, error_message) });
32        }
33        let payload = unsafe {
34            crate::private::parse_json_ptr::<StoreContextPayload>(context_json, "store context")
35        }?;
36        Ok(payload.into_store_context())
37    }
38
39    pub fn can_make_payments() -> Result<bool, StoreKitError> {
40        AppStore::can_make_payments()
41    }
42
43    pub fn device_verification_id() -> Result<Option<String>, StoreKitError> {
44        AppStore::device_verification_id()
45    }
46
47    pub fn current_products<I, S>(identifiers: I) -> Result<Vec<Product>, StoreKitError>
48    where
49        I: IntoIterator<Item = S>,
50        S: AsRef<str>,
51    {
52        Product::products_for(identifiers)
53    }
54
55    pub fn current_entitlements() -> Result<TransactionStream, StoreKitError> {
56        Transaction::current_entitlements()
57    }
58
59    pub fn transaction_updates() -> Result<TransactionStream, StoreKitError> {
60        Transaction::updates()
61    }
62
63    pub fn current_storefront() -> Result<Option<Storefront>, StoreKitError> {
64        Storefront::current()
65    }
66
67    pub fn app_transaction() -> Result<VerificationResult<AppTransaction>, StoreKitError> {
68        AppTransaction::shared()
69    }
70
71    pub fn receipt() -> Result<Option<AppReceipt>, StoreKitError> {
72        ReceiptValidator::current_receipt()
73    }
74}
75
76#[derive(Debug, Deserialize)]
77struct StoreContextPayload {
78    #[serde(rename = "bundleIdentifier")]
79    bundle_identifier: Option<String>,
80    #[serde(rename = "bundleName")]
81    bundle_name: Option<String>,
82    #[serde(rename = "bundleVersion")]
83    bundle_version: Option<String>,
84    #[serde(rename = "receiptURL")]
85    receipt_url: Option<String>,
86    #[serde(rename = "canMakePayments")]
87    can_make_payments: bool,
88    #[serde(rename = "deviceVerificationID")]
89    device_verification_id: Option<String>,
90    #[serde(rename = "isBundled")]
91    is_bundled: bool,
92    #[serde(rename = "executablePath")]
93    executable_path: Option<String>,
94}
95
96impl StoreContextPayload {
97    fn into_store_context(self) -> StoreContext {
98        StoreContext {
99            bundle_identifier: self.bundle_identifier,
100            bundle_name: self.bundle_name,
101            bundle_version: self.bundle_version,
102            receipt_url: self.receipt_url,
103            can_make_payments: self.can_make_payments,
104            device_verification_id: self.device_verification_id,
105            is_bundled: self.is_bundled,
106            executable_path: self.executable_path,
107        }
108    }
109}