SwiftWarplyFramework Client Documentation
🚀 5-Minute Setup Guide
Get started with SwiftWarplyFramework in just 5 minutes!
Version: 2.1.0 | Minimum iOS: 17.0 | Swift: 5.0+
📋 Quick Navigation
🚀 5-Minute Setup ← Start Here!
📦 Installation
⚙️ Configuration
🔧 Initialization
📱 First API Call
✅ Verification
📚 Complete Documentation
🔐 Authentication
🎯 Campaigns
🎫 Coupons
🏪 Market Pass
📡 Events
📱 Push Notifications
⚠️ Error Handling
🔄 Migration Guide
🚀 5-Minute Setup Guide
Prerequisites
Before you start, make sure you have:
- ✅ iOS 17.0+ project
- ✅ Swift 5.0+
- ✅ CocoaPods installed
- ✅ Web ID and Merchant ID from Warply
Step 1: Installation
1.1 Add to Podfile
Open your Podfile
and add:
platform :ios, '17.0'
target 'YourApp' do
use_frameworks!
pod 'SwiftWarplyFramework', :git => 'https://git@git.warp.ly/open-source/warply_sdk_framework.git', :tag => ‘2.1.0’
end
1.2 Install Framework
Run in terminal:
pod install
1.3 Open Workspace
open YourApp.xcworkspace
✅ Verification: Framework should appear in your Pods project
Step 2: Configuration
2.1 Import Framework
In your AppDelegate.swift
:
import SwiftWarplyFramework
2.2 Configure in AppDelegate
Add this to didFinishLaunchingWithOptions
:
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 🔧 Configure the SDK
WarplySDK.shared.configure(
webId: "YOUR_WEB_ID", // Replace with your Web ID
merchantId: "YOUR_MERCHANT_ID", // Replace with your Merchant ID
environment: .production // Use .development for testing
)
return true
}
}
✅ Verification: No compilation errors after adding this code
Step 3: Initialization
3.1 Initialize SDK
Add this right after the configure call:
// 🚀 Initialize the SDK
WarplySDK.shared.initialize { success in
if success {
print("✅ WarplySDK initialized successfully")
} else {
print("❌ WarplySDK initialization failed")
}
}
3.2 Complete AppDelegate Example
Your complete AppDelegate.swift
should look like this:
import UIKit
import SwiftWarplyFramework
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 🔧 Configure the SDK
WarplySDK.shared.configure(
webId: "YOUR_WEB_ID",
merchantId: "YOUR_MERCHANT_ID",
environment: .production
)
// 🚀 Initialize the SDK
WarplySDK.shared.initialize { success in
if success {
print("✅ WarplySDK initialized successfully")
} else {
print("❌ WarplySDK initialization failed")
}
}
return true
}
}
✅ Verification: Run your app and check console for "✅ WarplySDK initialized successfully"
Step 4: First API Call
4.1 Test in a ViewController
Add this to any ViewController's viewDidLoad
:
import SwiftWarplyFramework
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// 📱 Test API call
testWarplySDK()
}
func testWarplySDK() {
// Simple completion handler approach
WarplySDK.shared.getCampaigns(language: "en") { campaigns in
DispatchQueue.main.async {
if let campaigns = campaigns {
print("🎉 Success! Retrieved \(campaigns.count) campaigns")
// TODO: Update your UI here
} else {
print("⚠️ No campaigns received")
}
}
}
}
}
4.2 Modern Async/Await Approach (Recommended)
For modern Swift development:
func testWarplySDKAsync() {
Task {
do {
let campaigns = try await WarplySDK.shared.getCampaigns(language: "en")
print("🎉 Success! Retrieved \(campaigns.count) campaigns")
// Update UI on main thread
await MainActor.run {
// TODO: Update your UI here
}
} catch {
print("❌ Error: \(error.localizedDescription)")
}
}
}
✅ Verification: Run your app and check console for "🎉 Success! Retrieved X campaigns"
Step 5: Verification
5.1 Check Console Output
You should see:
✅ WarplySDK initialized successfully
🎉 Success! Retrieved X campaigns
5.2 Common Issues & Quick Fixes
Issue | Solution |
---|---|
"❌ WarplySDK initialization failed" | Check your Web ID and Merchant ID |
"⚠️ No campaigns received" | Verify network connection and credentials |
Compilation errors | Make sure iOS deployment target is 17.0+ |
Pod install fails | Update CocoaPods: sudo gem install cocoapods
|
5.3 Next Steps
🎉 Congratulations! Your SwiftWarplyFramework is now set up and working!
What's next?
- 🔐 Set up user authentication
- 🎯 Load and display campaigns
- 🎫 Implement coupon functionality
- 📡 Add event handling
📚 Complete Documentation
The sections below provide detailed information for advanced usage
⚙️ Configuration
Environment Setup
// Production environment (default)
WarplySDK.shared.configure(
webId: "your-production-web-id",
merchantId: "your-production-merchant-id",
environment: .production
)
// Development environment
WarplySDK.shared.configure(
webId: "your-development-web-id",
merchantId: "your-development-merchant-id",
environment: .development
)
SDK Properties
// Language setting (default: "el")
WarplySDK.shared.applicationLocale = "en" // or "el"
// Dark mode support
WarplySDK.shared.isDarkModeEnabled = true
// Analytics tracking
WarplySDK.shared.trackersEnabled = true
// Network status
let networkStatus = WarplySDK.shared.getNetworkStatus()
// Returns: 1 = connected, 0 = disconnected, -1 = unknown
🔐 Authentication
User Login
// Completion handler approach
WarplySDK.shared.verifyTicket(guid: "user-guid", ticket: "user-ticket") { response in
if let response = response, response.getStatus == 1 {
print("Login successful")
// User is authenticated
} else {
print("Login failed")
}
}
// Async/await approach
Task {
do {
let response = try await WarplySDK.shared.verifyTicket(guid: "user-guid", ticket: "user-ticket")
if response.getStatus == 1 {
print("Login successful")
}
} catch {
print("Login error: \(error)")
}
}
User Logout
// Completion handler
WarplySDK.shared.logout { response in
if let response = response, response.getStatus == 1 {
print("Logout successful")
// Clear user data
}
}
// Async/await
Task {
do {
let response = try await WarplySDK.shared.logout()
print("Logout successful")
} catch {
print("Logout error: \(error)")
}
}
Token Management
// Update tokens after authentication
WarplySDK.shared.updateRefreshToken(
accessToken: "new-access-token",
refreshToken: "new-refresh-token"
)
🎯 Campaign Management
Get All Campaigns
// Basic campaign retrieval
WarplySDK.shared.getCampaigns(language: "en") { campaigns in
guard let campaigns = campaigns else { return }
for campaign in campaigns {
print("Campaign: \(campaign.title ?? "No title")")
print("Description: \(campaign.subtitle ?? "No description")")
print("Image URL: \(campaign.logo_url ?? "No image")")
}
}
// With filters
let filters: [String: Any] = [
"communication_category": "offers",
"extra_fields": [
"category": "food",
"location": "athens"
]
]
WarplySDK.shared.getCampaigns(language: "en", filters: filters) { campaigns in
// Handle filtered campaigns
}
Get Personalized Campaigns
// Async/await example
Task {
do {
let personalizedCampaigns = try await WarplySDK.shared.getCampaignsPersonalized(language: "en")
// Display personalized content
for campaign in personalizedCampaigns {
print("Personalized campaign: \(campaign.title ?? "")")
}
} catch {
print("Error getting personalized campaigns: \(error)")
}
}
Get Supermarket Campaign
WarplySDK.shared.getSupermarketCampaign(language: "en") { campaign in
if let campaign = campaign {
print("Supermarket campaign available: \(campaign.title ?? "")")
// Show supermarket offers
} else {
print("No supermarket campaign available")
}
}
Campaign Interaction
// Get single campaign details
WarplySDK.shared.getSingleCampaign(sessionUuid: "campaign-session-uuid") { response in
if let response = response, response.getStatus == 1 {
print("Campaign marked as read")
}
}
// Construct campaign URL for web view
let campaignUrl = WarplySDK.shared.constructCampaignUrl(campaign)
let campaignParams = WarplySDK.shared.constructCampaignParams(campaign)
// Open campaign in web view
let webView = WKWebView()
if let url = URL(string: campaignUrl) {
let request = URLRequest(url: url)
webView.load(request)
}
Campaign State Management
// Get cached campaigns
let cachedCampaigns = WarplySDK.shared.getCampaignList()
let allCampaigns = WarplySDK.shared.getAllCampaignList()
let carouselCampaigns = WarplySDK.shared.getCarouselList()
🎫 Coupon System
Get User Coupons
// Completion handler approach
WarplySDK.shared.getCoupons(language: "en", completion: { coupons in
guard let coupons = coupons else { return }
for coupon in coupons {
print("Coupon: \(coupon.name ?? "No name")")
print("Discount: \(coupon.discount ?? 0)%")
print("Expires: \(coupon.expiration ?? "No expiration")")
print("Status: \(coupon.status == 1 ? "Active" : "Used")")
}
}, failureCallback: { errorCode in
print("Failed to get coupons: \(errorCode)")
})
// Async/await approach
Task {
do {
let coupons = try await WarplySDK.shared.getCoupons(language: "en")
// Filter active coupons
let activeCoupons = coupons.filter { $0.status == 1 }
print("Active coupons: \(activeCoupons.count)")
} catch let error as WarplyError {
print("Coupon error: \(error.localizedDescription)")
} catch {
print("Unknown error: \(error)")
}
}
Get Coupon Sets
// Available coupon categories/sets
WarplySDK.shared.getCouponSets { couponSets in
guard let couponSets = couponSets else { return }
for couponSet in couponSets {
print("Coupon Set: \(couponSet.name ?? "No name")")
print("Description: \(couponSet.short_description ?? "No description")")
}
}
// Async/await
Task {
do {
let couponSets = try await WarplySDK.shared.getCouponSets()
// Handle coupon sets
} catch {
print("Error getting coupon sets: \(error)")
}
}
Check Coupon Availability
WarplySDK.shared.getAvailableCoupons { availabilityData in
guard let availabilityData = availabilityData else { return }
for (couponSetId, availability) in availabilityData {
print("Coupon set \(couponSetId): \(availability) available")
}
}
Coupon State Management
// Get cached coupons
let activeCoupons = WarplySDK.shared.getCouponList()
let usedCoupons = WarplySDK.shared.getOldCouponList()
let allOldCoupons = WarplySDK.shared.getAllOldCouponList()
🏪 Market Pass
Get Market Pass Details
// Completion handler
WarplySDK.shared.getMarketPassDetails(completion: { marketPass in
guard let marketPass = marketPass else { return }
print("Market Pass Balance: \(marketPass.balance ?? 0)")
print("Points: \(marketPass.points ?? 0)")
print("Status: \(marketPass.status ?? "Unknown")")
}, failureCallback: { errorCode in
print("Market pass error: \(errorCode)")
})
// Async/await
Task {
do {
let marketPass = try await WarplySDK.shared.getMarketPassDetails()
print("Market Pass retrieved successfully")
// Access market pass data
let balance = marketPass.balance ?? 0
let points = marketPass.points ?? 0
} catch {
print("Market pass error: \(error)")
}
}
Get Supermarket History
Task {
do {
let history = try await WarplySDK.shared.getRedeemedSMHistory(language: "en")
print("Total redeemed value: \(history._totalRedeemedValue)")
print("Redeemed coupons: \(history._redeemedCouponList.count)")
for coupon in history._redeemedCouponList {
print("Redeemed: \(coupon.name ?? "") on \(coupon.redeemed_date ?? Date())")
}
} catch {
print("History error: \(error)")
}
}
Market Pass UI Integration
// Open supermarket map
WarplySDK.shared.openSupermarketsMap(self) // Pass current view controller
// Open supermarket flow
WarplySDK.shared.openSuperMarketsFlow(self)
// Get map URL for custom implementation
let mapUrl = WarplySDK.shared.getMarketPassMapUrl()
📡 Event System
The framework supports both modern EventDispatcher and legacy SwiftEventBus for backward compatibility.
Using Modern EventDispatcher (Recommended)
import SwiftWarplyFramework
class ViewController: UIViewController {
private var eventSubscriptions: [EventSubscription] = []
override func viewDidLoad() {
super.viewDidLoad()
setupEventListeners()
}
private func setupEventListeners() {
// Subscribe to campaigns retrieved event
let subscription = WarplySDK.shared.subscribe(CampaignsRetrievedEvent.self) { event in
print("Campaigns retrieved: \(event.data ?? "No data")")
DispatchQueue.main.async {
// Update UI
self.refreshCampaignsList()
}
}
eventSubscriptions.append(subscription)
// Subscribe to market pass events
let marketSubscription = WarplySDK.shared.subscribe(MarketPassDetailsEvent.self) { event in
print("Market pass details updated")
DispatchQueue.main.async {
self.updateMarketPassUI()
}
}
eventSubscriptions.append(marketSubscription)
}
deinit {
// Subscriptions are automatically cleaned up
eventSubscriptions.removeAll()
}
}
Using SwiftEventBus (Legacy Support)
import SwiftEventBus
class LegacyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Subscribe to events
SwiftEventBus.onMainThread(self, name: "campaigns_retrieved") { result in
print("Campaigns retrieved via SwiftEventBus")
// Handle event
}
SwiftEventBus.onMainThread(self, name: "coupons_fetched") { result in
print("Coupons fetched via SwiftEventBus")
// Handle event
}
}
deinit {
SwiftEventBus.unregister(self)
}
}
Available Events
Event Name | EventDispatcher Type | Description |
---|---|---|
campaigns_retrieved |
CampaignsRetrievedEvent |
Campaigns data loaded |
coupons_fetched |
CouponsRetrievedEvent |
Coupons data loaded |
market_pass_details_fetched |
MarketPassDetailsEvent |
Market pass data loaded |
ccms_retrieved |
CCMSRetrievedEvent |
CCMS campaigns loaded |
seasonals_retrieved |
SeasonalsRetrievedEvent |
Seasonal campaigns loaded |
dynatrace |
DynatraceEvent |
Analytics events |
📱 Push Notifications
Setup
// In AppDelegate
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
WarplySDK.shared.updateDeviceToken(tokenString)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
// Check if it's a Warply notification
if WarplySDK.shared.checkForLoyaltySDKNotification(userInfo) {
print("Warply notification handled")
} else {
// Handle other notifications
}
}
Handle Notifications
// Manual notification handling
WarplySDK.shared.handleNotification(notificationPayload)
// Check if notification belongs to Warply SDK
let isWarplyNotification = WarplySDK.shared.checkForLoyaltySDKNotification(payload)
⚠️ Error Handling
WarplyError Types
public enum WarplyError: Error {
case networkError // Network request failed
case invalidResponse // Invalid response received
case authenticationFailed // Authentication failed
case dataParsingError // Failed to parse response data
case unknownError(Int) // Unknown error with code
}
Error Handling Patterns
// Async/await error handling
Task {
do {
let campaigns = try await WarplySDK.shared.getCampaigns(language: "en")
// Success
} catch let error as WarplyError {
switch error {
case .networkError:
showNetworkErrorAlert()
case .authenticationFailed:
redirectToLogin()
case .invalidResponse:
showGenericErrorAlert()
case .dataParsingError:
logParsingError()
case .unknownError(let code):
logUnknownError(code: code)
}
} catch {
print("Unexpected error: \(error)")
}
}
// Completion handler error handling
WarplySDK.shared.getCoupons(language: "en", completion: { coupons in
if let coupons = coupons {
// Success
} else {
// Handle nil response
showErrorAlert("Failed to load coupons")
}
}, failureCallback: { errorCode in
// Handle specific error codes
switch errorCode {
case 401:
redirectToLogin()
case 500:
showServerErrorAlert()
default:
showGenericErrorAlert()
}
})
Network Status Checking
func checkNetworkAndProceed() {
let networkStatus = WarplySDK.shared.getNetworkStatus()
switch networkStatus {
case 1:
// Connected - proceed with API calls
loadData()
case 0:
// Disconnected - show offline message
showOfflineAlert()
case -1:
// Unknown - try anyway or show warning
showNetworkWarning()
default:
break
}
}
🔄 Migration Guide
From Legacy SwiftEventBus to EventDispatcher
Before:
SwiftEventBus.onMainThread(self, name: "campaigns_retrieved") { result in
// Handle event
}
After:
let subscription = WarplySDK.shared.subscribe(CampaignsRetrievedEvent.self) { event in
// Handle event with type safety
}
From Completion Handlers to Async/Await
Before:
WarplySDK.shared.getCampaigns(language: "en") { campaigns in
if let campaigns = campaigns {
// Handle success
} else {
// Handle failure
}
}
After:
Task {
do {
let campaigns = try await WarplySDK.shared.getCampaigns(language: "en")
// Handle success
} catch {
// Handle error with proper error types
}
}
Gradual Migration Strategy
- Keep existing code working - No breaking changes required
- Add async/await gradually - Start with new features
- Migrate events when convenient - EventDispatcher provides better type safety
- Update error handling - Use structured WarplyError types
💡 Best Practices
1. Initialization
// ✅ Good: Initialize in AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
WarplySDK.shared.configure(webId: "...", merchantId: "...")
WarplySDK.shared.initialize { success in
// SDK ready
}
return true
}
// ❌ Bad: Initialize in view controllers
override func viewDidLoad() {
WarplySDK.shared.configure(...) // Too late!
}
2. Error Handling
// ✅ Good: Comprehensive error handling
Task {
do {
let campaigns = try await WarplySDK.shared.getCampaigns(language: "en")
updateUI(with: campaigns)
} catch let error as WarplyError {
handleWarplyError(error)
} catch {
handleUnexpectedError(error)
}
}
// ❌ Bad: Ignoring errors
Task {
let campaigns = try? await WarplySDK.shared.getCampaigns(language: "en")
// Silently fails
}
3. Event Management
// ✅ Good: Proper subscription management
class ViewController: UIViewController {
private var eventSubscriptions: [EventSubscription] = []
private func setupEvents() {
let subscription = WarplySDK.shared.subscribe(CampaignsRetrievedEvent.self) { event in
// Handle event
}
eventSubscriptions.append(subscription)
}
deinit {
eventSubscriptions.removeAll() // Automatic cleanup
}
}
// ❌ Bad: Memory leaks
class BadViewController: UIViewController {
override func viewDidLoad() {
WarplySDK.shared.subscribe(CampaignsRetrievedEvent.self) { event in
// This creates a retain cycle!
self.handleEvent(event)
}
}
}
4. UI Updates
// ✅ Good: Main thread UI updates
Task {
let campaigns = try await WarplySDK.shared.getCampaigns(language: "en")
await MainActor.run {
self.updateCampaignsUI(campaigns)
}
}
// ✅ Also good: Using completion handlers
WarplySDK.shared.getCampaigns(language: "en") { campaigns in
DispatchQueue.main.async {
self.updateCampaignsUI(campaigns)
}
}
5. Caching Strategy
// ✅ Good: Use SDK's built-in caching
func loadCampaigns() {
// First, show cached data
let cachedCampaigns = WarplySDK.shared.getCampaignList()
if !cachedCampaigns.isEmpty {
updateUI(with: cachedCampaigns)
}
// Then, fetch fresh data
Task {
do {
let freshCampaigns = try await WarplySDK.shared.getCampaigns(language: "en")
updateUI(with: freshCampaigns)
} catch {
// Handle error, keep cached data
}
}
}
🔧 Troubleshooting
Common Issues
1. SDK Not Initializing
Problem: SDK initialization fails
WarplySDK.shared.initialize { success in
if !success {
print("Initialization failed")
}
}
Solutions:
- Check network connectivity
- Verify webId and merchantId are correct
- Ensure proper environment configuration
2. No Data Returned
Problem: API calls return nil or empty arrays
Solutions:
// Check authentication status
WarplySDK.shared.verifyTicket(guid: "...", ticket: "...") { response in
if response?.getStatus != 1 {
print("User not authenticated")
}
}
// Check network status
let networkStatus = WarplySDK.shared.getNetworkStatus()
if networkStatus != 1 {
print("Network issue")
}
// Check language parameter
WarplySDK.shared.getCampaigns(language: "en") // Try different language
3. Events Not Firing
Problem: Event listeners not receiving events
Solutions:
// Ensure proper subscription
let subscription = WarplySDK.shared.subscribe(CampaignsRetrievedEvent.self) { event in
print("Event received: \(event)")
}
// Keep subscription reference
self.eventSubscriptions.append(subscription)
// For SwiftEventBus, ensure proper registration
SwiftEventBus.onMainThread(self, name: "campaigns_retrieved") { result in
print("SwiftEventBus event received")
}
4. Memory Issues
Problem: Memory leaks or crashes
Solutions:
// Use weak references in closures
WarplySDK.shared.getCampaigns(language: "en") { [weak self] campaigns in
self?.updateUI(campaigns)
}
// Proper event cleanup
deinit {
SwiftEventBus.unregister(self)
eventSubscriptions.removeAll()
}
Debug Mode
// Enable debug logging
WarplySDK.shared.trackersEnabled = true
// Check SDK state
print("App UUID: \(WarplySDK.shared.appUuid)")
print("Merchant ID: \(WarplySDK.shared.merchantId)")
print("Language: \(WarplySDK.shared.applicationLocale)")
print("Network Status: \(WarplySDK.shared.getNetworkStatus())")
Performance Optimization
// Batch API calls when possible
Task {
async let campaigns = WarplySDK.shared.getCampaigns(language: "en")
async let coupons = WarplySDK.shared.getCoupons(language: "en")
async let marketPass = WarplySDK.shared.getMarketPassDetails()
do {
let (campaignData, couponData, marketData) = try await (campaigns, coupons, marketPass)
// Update UI with all data
} catch {
// Handle errors
}
}
📞 Support
Getting Help
- Documentation: Refer to this guide and inline code documentation
- Sample Code: Check the examples in this documentation
- Error Messages: Use the structured WarplyError types for debugging
-
Network Issues: Check
getNetworkStatus()
before API calls
Reporting Issues
When reporting issues, please include:
-
Framework Version:
2.1.0
- iOS Version: Minimum 17.0
- Error Details: Full error messages and stack traces
- Code Sample: Minimal reproducible example
-
Network Status: Result of
getNetworkStatus()
- Configuration: Environment and setup details (without sensitive data)
Framework Information
// Get framework version and status
print("Framework Version: 2.1.0")
print("SDK Initialized: \(WarplySDK.shared != nil)")
print("Network Status: \(WarplySDK.shared.getNetworkStatus())")
print("Current Language: \(WarplySDK.shared.applicationLocale)")
🎉 Conclusion
The SwiftWarplyFramework provides a comprehensive solution for loyalty programs, campaigns, coupons, and market pass functionality. With both modern async/await patterns and legacy completion handler support, you can integrate the framework at your own pace while maintaining backward compatibility.
Key Benefits:
- ✅ Modern Swift Patterns - Async/await, structured error handling
- ✅ Backward Compatibility - Existing code continues to work
- ✅ Type Safety - Comprehensive error types and event system
- ✅ Performance - Built-in caching and efficient networking
- ✅ Flexibility - Multiple API patterns and event systems
Start with the Quick Start guide and gradually adopt the advanced features as needed. The framework is designed to grow with your application's requirements.
Happy Coding! 🚀