iOS App Store Subscription Integration Guide
To enable native App Store subscriptions for your application, you need to modify your iOS project (Xcode) source code.
1. Capabilities & StoreKit
Ensure your App ID has In-App Purchase capability enabled in Apple Developer Portal. In Xcode, add the In-App Purchase capability to your target.
2. Create the Purchase Manager (Swift)
Create a helper class to handle StoreKit 2 interactions and bridge to the WebView.
import StoreKit
import WebKit
class PurchaseManager: NSObject, SKPaymentTransactionObserver {
static let shared = PurchaseManager()
weak var webView: WKWebView?
// Map web product IDs to App Store Product IDs
let productMap: [String: String] = [
"monthly": "com.jtdrecipe.pro.monthly",
"6month": "com.jtdrecipe.pro.6month",
"yearly": "com.jtdrecipe.pro.yearly"
]
override init() {
super.init()
SKPaymentQueue.default().add(self)
}
func purchase(webProductId: String) {
guard let appStoreId = productMap[webProductId] else { return }
if SKPaymentQueue.canMakePayments() {
let request = SKMutablePayment()
request.productIdentifier = appStoreId
SKPaymentQueue.default().add(request)
}
}
// Handle Transactions
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchased:
verifyReceipt(transaction: transaction)
SKPaymentQueue.default().finishTransaction(transaction)
case .failed:
SKPaymentQueue.default().finishTransaction(transaction)
// Notify web of failure if needed
case .restored:
verifyReceipt(transaction: transaction)
SKPaymentQueue.default().finishTransaction(transaction)
default: break
}
}
}
func verifyReceipt(transaction: SKPaymentTransaction) {
guard let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
let receiptData = try? Data(contentsOf: appStoreReceiptURL) else { return }
let receiptString = receiptData.base64EncodedString(options: [])
// Send to your backend function
verifyOnBackend(receipt: receiptString)
}
func verifyOnBackend(receipt: String) {
// Construct JSON payload
let json: [String: Any] = ["receiptData": receipt]
guard let jsonData = try? JSONSerialization.data(withJSONObject: json) else { return }
// Your backend endpoint
let url = URL(string: "https://YOUR-APP.base44.app/functions/verifyAppStorePurchase")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// Note: You need to handle auth token injection if your function requires "user" context from Base44
// Or you can pass userId in body and handle it with service role in backend (less secure but easier for wrappers)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { return }
// On success, notify WebView
DispatchQueue.main.async {
self.webView?.evaluateJavaScript("if(window.onPurchaseSuccess) window.onPurchaseSuccess();", completionHandler: nil)
}
}
task.resume()
}
}
3. Inject JavaScript Bridge
In your ViewController where you setup the WKWebView, add the script message handler.
import WebKit
class ViewController: UIViewController, WKScriptMessageHandler {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let contentController = WKUserContentController()
// Register the handler name 'purchaseSubscription'
contentController.add(self, name: "purchaseSubscription")
let config = WKWebViewConfiguration()
config.userContentController = contentController
webView = WKWebView(frame: view.bounds, configuration: config)
PurchaseManager.shared.webView = webView
// ... load your URL ...
}
// Handle calls from JavaScript
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "purchaseSubscription",
let body = message.body as? [String: Any],
let productId = body["productId"] as? String {
// Trigger purchase
PurchaseManager.shared.purchase(webProductId: productId)
}
}
}
4. Backend Configuration
Don't forget to set the APPLE_SHARED_SECRET in your Base44 App Secrets. You can get this from App Store Connect under the "Users and Access" or App-specific Shared Secret section.