Superwall-iOS icon indicating copy to clipboard operation
Superwall-iOS copied to clipboard

🐞 Bug Report: SuperwallDelegate Not Receiving Events (SDK 4.3.3)

Open mobidev412 opened this issue 8 months ago • 4 comments

Environment • SDK Version: 4.3.3 • Platform: iOS • Integration method: CocoaPods

Expected Behavior SuperwallDelegate methods such as handleSuperwallEvent(withInfo:) should be triggered when Superwall events occur (e.g., sessionStart, paywallOpen, transactionComplete, etc.).

Actual Behavior SuperwallDelegate is assigned and held as a strong reference from AppDelegate, but no events are being received inside handleSuperwallEvent(withInfo:).

mobidev412 avatar May 01 '25 12:05 mobidev412

@mobidev412 Any code you can share? Can you confirm that this was working for you previously on another version?

anglinb avatar May 01 '25 17:05 anglinb

@mobidev412 Any code you can share? Can you confirm that this was working for you previously on another version?

few days ago its working fine. but now in all sdk its not working. some of events coming some of not like paywall open , abandon , restore purchase fail etc.

Here my AppDelegate class.

`import UIKit import IQKeyboardManager import UserNotifications import Mixpanel import SuperwallKit import StoreKit import Firebase import FirebaseAnalytics

@main class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

let db = DatabaseManager.shared
var morningSchedule: String = ""
var eveningSchedule: String = ""
let swDelegate = SWDelegate()

/// This method is called when the app finishes launching.
/// It initializes third-party services, configures notifications, and tracks app launch events.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Enable keyboard manager to handle keyboard appearances automatically
    IQKeyboardManager.shared().isEnabled = true

    // Set the notification delegate to self
    UNUserNotificationCenter.current().delegate = self
    
    // Configure Firebase
    FirebaseApp.configure()
    Analytics.setAnalyticsCollectionEnabled(true)

    // Schedule daily notifications
    //scheduleNotifications()

    // Initialize Mixpanel for analytics tracking
    MixpanelManager.initializeMixpanel()
    
    // Track whether the app is launching for the first time
    if UserPreferences.isAppFirstTimeLaunch {
        MixpanelManager.trackEvent(MixPanelEvents.App_Splash_Launched)
    } else {
        
        MixpanelManager.trackEvent(MixPanelEvents.App_First_Splash_Launched)
        UserPreferences.isAppFirstTimeLaunch = true
    }
    
    // Configure Superwall (Paywall SDK) with options
    //Superwall.configure(apiKey: "pk_0d80415acde80eefdc94f8dfc69797ca7ca1e4bc24cda17f")
    let options = SuperwallOptions()
    options.paywalls.shouldPreload = true
    options.paywalls.automaticallyDismiss = true
    options.paywalls.shouldShowPurchaseFailureAlert = true
    
    Superwall.configure(apiKey: SuperWallKeys.registerKey, options: options)
    Superwall.shared.delegate = swDelegate
    Superwall.shared.preloadAllPaywalls()
    
    self.fetchAndApplyRemoteConfig()
    return true
}

private func fetchAndApplyRemoteConfig() {
    let remoteConfig = RemoteConfig.remoteConfig()
    let settings = RemoteConfigSettings()
    settings.minimumFetchInterval = 0
    remoteConfig.configSettings = settings
    
    remoteConfig.fetchAndActivate { status, error in
        if let error = error {
            let logMessage = "API Key and Voice ID Remote Config Fetch Error: \(error.localizedDescription)"
            logMessage.crashlyticsLogError()

            print("API Key and Voice ID Remote Config Fetch Status: \(status)")
            return
        }

        APIConstant.updateVoiceAPIKeyAndVoiceID(from: remoteConfig)
    }
}

// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    // Called when a new scene session is being created.
    // Use this method to select a configuration to create the new scene with.
    return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
    // Called when the user discards a scene session.
    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
        
// MARK: UNUserNotificationCenterDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    
    let identifier = notification.request.identifier
    center.removeDeliveredNotifications(withIdentifiers: [identifier])
    
    // Show the notification while the app is in the foreground
    completionHandler([.banner, .sound, .badge])
}

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    let userInfo = response.notification.request.content.userInfo
    print("User clicked on notification: \(userInfo)")
    completionHandler()
}

func applicationWillTerminate(_ application: UIApplication) {
    Mixpanel.sharedInstance()?.flush()
}

func applicationDidEnterBackground(_ application: UIApplication) {
    Mixpanel.sharedInstance()?.flush()
}

}`

Here is SWDelegate.swift

`// // SWDelegate.swift // AI_Affirmations_Mental_Health_App // // Created by floming dev on 15/04/25. //

import SuperwallKit

class SWDelegate: SuperwallDelegate { func handleSuperwallEvent(withInfo eventInfo: SuperwallEventInfo) { print("Defaultevent: (eventInfo.event.description)") switch eventInfo.event {

    case .firstSeen:
        print("SuperwallEvent: firstSeen")
     
    case .appOpen:
        print("SuperwallEvent: appOpen")
       
    case .appLaunch:
        print("SuperwallEvent: appLaunch")
        
    case .identityAlias:
        print("SuperwallEvent: identityAlias")
       
    case .appInstall:
        print("SuperwallEvent: appInstall")
      
    case .sessionStart:
        print("SuperwallEvent: sessionStart")
       
       // MixpanelManager.trackEvent("SuperwallEvent: sessionStart")
    case .deviceAttributes(let attributes):
        print("SuperwallEvent: deviceAttributes - \(attributes)")
      
    case .subscriptionStatusDidChange:
        print("SuperwallEvent: subscriptionStatusDidChange")
       
    case .appClose:
        print("SuperwallEvent: appClose")
      
    case .deepLink(let url):
        print("SuperwallEvent: deepLink - \(url)")
        
    case .triggerFire(let placementName, let result):
        print("SuperwallEvent: triggerFire - \(placementName), result: \(result)")
       
    case .paywallOpen(let paywallInfo):

// MixpanelManager.trackEvent("Superwall - Transaction Start", properties: [ // "paywall_id": paywallInfo.identifier, // "paywall_name": paywallInfo.name // ]) print("SuperwallEvent: paywallOpen - (paywallInfo)")

    case .paywallClose(let paywallInfo):
        print("SuperwallEvent: paywallClose - \(paywallInfo)")
       
    case .paywallDecline(let paywallInfo):
        print("SuperwallEvent: paywallDecline - \(paywallInfo)")
        
    case .transactionStart(let product, let paywallInfo):
        print("SuperwallEvent: transactionStart - product: \(product), paywall: \(paywallInfo)")
        MixpanelManager.trackEvent("Superwall - Transaction Start", properties: [
            "product_id": product.productIdentifier,
            "paywall_id": paywallInfo.identifier,
            "paywall_name": paywallInfo.experiment ?? ""
        ])
       
    case .transactionFail(let error, let paywallInfo):
        print("SuperwallEvent: transactionFail - error: \(error), paywall: \(paywallInfo)")
        MixpanelManager.trackEvent("Superwall - Transaction Fail", properties: [
            "error": error.localizedDescription,
            "paywall_id": paywallInfo.identifier,
            "paywall_name": paywallInfo.experiment ?? ""
        ])
        
    case .transactionAbandon(let product, let paywallInfo):
        print("SuperwallEvent: transactionAbandon - product: \(product), paywall: \(paywallInfo)")
        MixpanelManager.trackEvent("Superwall - Transaction Abandon", properties: [
            "product_id": product.productIdentifier,
            "paywall_id": paywallInfo.identifier,
            "paywall_name": paywallInfo.experiment ?? ""
        ])

    case .transactionComplete(let transaction, let product, let type, let paywallInfo):
        print("SuperwallEvent: transactionComplete - transaction: \(transaction), product: \(product), type: \(type), paywall: \(paywallInfo)")
        MixpanelManager.trackEvent("Superwall - Transaction Complete", properties: [
            "transaction_id": transaction?.storeTransactionId ?? "",
            "product_id": product.productIdentifier,
            "type": "\(type)",
            "paywall_id": paywallInfo.identifier,
            "paywall_name": paywallInfo.experiment ?? ""
        ])

    case .subscriptionStart(let product, let paywallInfo):
        print("SuperwallEvent: subscriptionStart - product: \(product), paywall: \(paywallInfo)")
        MixpanelManager.trackEvent("Superwall - Subscription Start", properties: [
            "product_id": product.productIdentifier,
            "paywall_id": paywallInfo.identifier,
            "paywall_name": paywallInfo.experiment ?? ""
        ])

    case .freeTrialStart(let product, let paywallInfo):
        print("SuperwallEvent: freeTrialStart - product: \(product), paywall: \(paywallInfo)")
        MixpanelManager.trackEvent("Superwall - Free Trial Start", properties: [
            "product_id": product.productIdentifier,
            "paywall_id": paywallInfo.identifier,
            "paywall_name": paywallInfo.experiment ?? ""
        ])

    case .transactionRestore(let restoreType, let paywallInfo):
        print("SuperwallEvent: transactionRestore - type: \(restoreType), paywall: \(paywallInfo)")
        MixpanelManager.trackEvent("Superwall - Transaction Restore", properties: [
            "restore_type": "\(restoreType)",
            "paywall_id": paywallInfo.identifier,
            "paywall_name": paywallInfo.experiment ?? ""
        ])

    case .transactionTimeout(let paywallInfo):
        print("SuperwallEvent: transactionTimeout - \(paywallInfo)")
        MixpanelManager.trackEvent("Superwall - Transaction Timeout", properties: [
            "paywall_id": paywallInfo.identifier,
            "paywall_name": paywallInfo.experiment ?? ""
        ])

    case .userAttributes(let attributes):
        print("SuperwallEvent: userAttributes - \(attributes)")
    case .nonRecurringProductPurchase(let product, let paywallInfo):
        print("SuperwallEvent: nonRecurringProductPurchase - product: \(product), paywall: \(paywallInfo)")
    case .paywallResponseLoadStart(let triggeredPlacementName):
        print("SuperwallEvent: paywallResponseLoadStart - placement: \(triggeredPlacementName ?? "")")
    case .paywallResponseLoadNotFound(let triggeredPlacementName):
        print("SuperwallEvent: paywallResponseLoadNotFound - placement: \(triggeredPlacementName ?? "")")
    case .paywallResponseLoadFail(let triggeredPlacementName):
        print("SuperwallEvent: paywallResponseLoadFail - placement: \(triggeredPlacementName ?? "")")
    case .paywallResponseLoadComplete(let triggeredPlacementName, let paywallInfo):
        print("SuperwallEvent: paywallResponseLoadComplete - placement: \(triggeredPlacementName ?? ""), paywall: \(paywallInfo)")
    case .paywallWebviewLoadStart(let paywallInfo):
        print("SuperwallEvent: paywallWebviewLoadStart - \(paywallInfo)")
    case .paywallWebviewLoadFail(let paywallInfo):
        print("SuperwallEvent: paywallWebviewLoadFail - \(paywallInfo)")
    case .paywallWebviewLoadComplete(let paywallInfo):
        print("SuperwallEvent: paywallWebviewLoadComplete - \(paywallInfo)")
    case .paywallWebviewLoadTimeout(let paywallInfo):
        print("SuperwallEvent: paywallWebviewLoadTimeout - \(paywallInfo)")
    case .paywallWebviewLoadFallback(let paywallInfo):
        print("SuperwallEvent: paywallWebviewLoadFallback - \(paywallInfo)")
    case .paywallProductsLoadStart(let triggeredPlacementName, let paywallInfo):
        print("SuperwallEvent: paywallProductsLoadStart - placement: \(triggeredPlacementName ?? ""), paywall: \(paywallInfo)")
    case .paywallProductsLoadFail(let triggeredPlacementName, let paywallInfo):
        print("SuperwallEvent: paywallProductsLoadFail - placement: \(triggeredPlacementName ?? ""), paywall: \(paywallInfo)")
    case .paywallProductsLoadComplete(let triggeredPlacementName):
        print("SuperwallEvent: paywallProductsLoadComplete - placement: \(triggeredPlacementName ?? "")")
    case .paywallProductsLoadRetry(let triggeredPlacementName, let paywallInfo, let attempt):
        print("SuperwallEvent: paywallProductsLoadRetry - placement: \(triggeredPlacementName ?? ""), attempt: \(attempt), paywall: \(paywallInfo)")
    case .surveyResponse(let survey, let selectedOption, let customResponse, let paywallInfo):
        print("SuperwallEvent: surveyResponse - survey: \(survey), selected: \(String(describing: selectedOption)), custom: \(String(describing: customResponse)), paywall: \(paywallInfo)")
    case .paywallPresentationRequest(let status, let reason):
        print("SuperwallEvent: paywallPresentationRequest - status: \(status), reason: \(reason)")
    case .touchesBegan:
        print("SuperwallEvent: touchesBegan")
    case .surveyClose:
        print("SuperwallEvent: surveyClose")
    case .reset:
        print("SuperwallEvent: reset")
    case .restoreStart:
        print("SuperwallEvent: restoreStart")
        MixpanelManager.trackEvent("Superwall - Restore Start")

    case .restoreFail(let message):
        print("SuperwallEvent: restoreFail - message: \(message)")
        MixpanelManager.trackEvent("Superwall - Restore Fail", properties: [
            "message": message
        ])

    case .restoreComplete:
        print("SuperwallEvent: restoreComplete")
        MixpanelManager.trackEvent("Superwall - Restore Complete")
        
    case .configRefresh:
        print("SuperwallEvent: configRefresh")
    case .customPlacement(let name, let params, let paywallInfo):
        print("SuperwallEvent: customPlacement - name: \(name), params: \(params), paywall: \(paywallInfo)")
    case .configAttributes:
        print("SuperwallEvent: configAttributes")
    case .confirmAllAssignments:
        print("SuperwallEvent: confirmAllAssignments")
    case .configFail:
        print("SuperwallEvent: configFail")
    case .adServicesTokenRequestStart:
        print("SuperwallEvent: adServicesTokenRequestStart")
    case .adServicesTokenRequestFail(let error):
        print("SuperwallEvent: adServicesTokenRequestFail - error: \(error)")
    case .adServicesTokenRequestComplete(let token):
        print("SuperwallEvent: adServicesTokenRequestComplete - token: \(token)")
    case .shimmerViewStart:
        print("SuperwallEvent: shimmerViewStart")
    case .shimmerViewComplete:
        print("SuperwallEvent: shimmerViewComplete")
    case .redemptionStart:
        print("SuperwallEvent: redemptionStart")
    case .redemptionComplete:
        print("SuperwallEvent: redemptionComplete")
    case .redemptionFail:
        print("SuperwallEvent: redemptionFail")
    case .enrichmentStart:
        print("SuperwallEvent: enrichmentStart")
    case .enrichmentComplete(userEnrichment: let userEnrichment, deviceEnrichment: let deviceEnrichment):
        print("SuperwallEvent: enrichmentComplete")
    case .enrichmentFail:
        print("SuperwallEvent: enrichmentFail")
    }
}

}`

mobidev412 avatar May 02 '25 03:05 mobidev412

Hi, I'm not able to reproduce this, everything is working expected from our side and I don't see any issues with your code. Are you able to reproduce this within our example app?

yusuftor avatar May 02 '25 14:05 yusuftor

Hi, I'm not able to reproduce this, everything is working expected from our side and I don't see any issues with your code. Are you able to reproduce this within our example app?

I will check example app. but there is 100% something issue. because i check multiple time with different devices only few events working. paywall open, paywall closed, restore purchase failed etc events not working.

mobidev412 avatar May 03 '25 06:05 mobidev412

Hi did you check the example app? I'm going to close this as I haven't heard back for a while and can't reproduce the issues you're seeing.

yusuftor avatar May 30 '25 09:05 yusuftor

Same problem here in 4.6.0

j-jiseophan avatar Jul 29 '25 09:07 j-jiseophan