Information
  • 17 Jul 2023
  • 5 Minutes to read
  • Contributors
  • Dark
    Light

Information

  • Dark
    Light

Article summary

Authentication SDK State

iOS

Example Swift Code:

TMAuthentication.shared.delegate = self

extension MainMenuViewController: TMAuthenticationDelegate {
    
    func onStateChanged(
            backend: TMAuthentication.BackendService?, 
            state: TMAuthentication.ServiceState, 
            error: (Error)?) {
            
        if let backend = backend {
            if let error = error {
                print("Authentication State: .\(state.rawValue) forBackend: \(backend.description) Error: \(error.localizedDescription)")
            } else {
                print("Authentication State: .\(state.rawValue) forBackend: \(backend.description)")
            }
        } else {
            if let error = error {
                print("Authentication State: .\(state.rawValue) Error: \(error.localizedDescription)")
            } else {
                print("Authentication State: .\(state.rawValue)")
            }
        }
        
        switch state {
        case .serviceConfigurationStarted:
            // configuration process has started, ``serviceConfigured`` state may be called multiple times
            break
        case .serviceConfigured:
            // given ``TMAuthentication/BackendService`` has been configured, however configuration is still processing
            break
        case .serviceConfigurationCompleted:
            // configuration process has completed
            break
            
        case .loginStarted:
            // login process has started, ``loggedIn`` state may be called multiple times
            break
        case .loginPresented:
            // user has been presented a login page for the given ``TMAuthentication/BackendService``, so login is still processing
            break
        case .loggedIn:
            // user has logged in to given ``TMAuthentication/BackendService``, however login is still processing
            break
        case .loginAborted:
            // user has manually aborted a login, however login is still processing
            break
        case .loginFailed:
            /// login has failed with an error, however login is still processing
            break
        case .loginLinkAccountPresented:
            // user has been presented link account, so login is still processing
            break
        case .loginCompleted:
            // login process has completed, including link account process
            break
            
        case .tokenRefreshed:
            // user's ``TMAuthToken`` has been refreshed, may be called multiple times during lifetime of application
            break
            
        case .logoutStarted:
            // logout process has started, ``loggedOut`` state may be called multiple times
            break
        case .loggedOut:
            // user has logged out of given ``TMAuthentication/BackendService``, however logout is still processing
            break
        case .logoutCompleted:
            // logout process has completed
            break
            
        @unknown default:
            // additional states may be added in the future
            break
        }
    }
}

Tickets SDK State

iOS

Example Swift Code:

TMTickets.shared.orderDelegate = self

extension MainMenuViewController: TMTicketsOrderDelegate {

    func presentClientAppPage(deeplink: String) {
        // TODO: open deeplink (if supported), otherwise ignore
        print("presentClientAppPage deeplink: \(deeplink)")
    }
    
    func handleNavBarButtonAction(
            page: TicketmasterTickets.TMTickets.Analytics.Page, screenTitleName: String?, 
            event: TicketmasterTickets.TMPurchasedEvent?) {
            
        if let event = event {
            if let name = screenTitleName {
                print("User Pressed NavBar Button on Page: \(page.rawValue) Named: \(name) Event: \(event.info.identifier)")
            } else {
                print("User Pressed NavBar Button on Page: \(page.rawValue) Event: \(event.info.identifier)")
            }
        } else if let name = screenTitleName {
            print("User Pressed NavBar Button on Page: \(page.rawValue) Named: \(name)")
        } else {
            print("User Pressed NavBar Button on Page: \(page.rawValue)")
        }
    }
    
    func didUpdateEvents(events: [TicketmasterTickets.TMPurchasedEvent], fromCache: Bool) {
        // list of user's purchased Events were updated
        print("Events Updated: \(events.count) Cached: \(fromCache ? "true" : "false")")
    }
    
    func didUpdateTickets(event: TicketmasterTickets.TMPurchasedEvent, fromCache: Bool) {
        // Tickets for a specific Event were updated
        print("Event Updated with Tickets: \(event.info.identifier) Cached: \(fromCache ? "true" : "false")")
    }
    
    func didClearEventsTicketsCache(backend: TMAuthentication.BackendService) {
        print("Events Removed for Backend: \(backend.description)")
    }
}

User Analytics

Android

To implement user analytics tracking, it is necessary to register an observer with the observeForever function. By calling this method, the observer will always receive the analytics events regardless of the current state of the Application / Activity.

To start tracking, call observeForever in the onCreate method of your Application or Activity.

Example Kotlin Code:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_tickets_sdk_host)
    ...
    setupAnalytics()
  }

private fun setupAnalytics() {
    //Initialize observer that will handle the analytics events
    //Must be called the observeForever as this will kept alive the observer until
    //the Activity is destroyed
    UserAnalyticsDelegate.handler.getLiveData().observeForever(userAnalyticsObserver)
  }
  
  private val userAnalyticsObserver = Observer<UserAnalyticsDelegate.AnalyticsData?> {
    it?.let {
      Log.d("Analytics", "Action name: ${it.actionName}, data: ${it.data}")
    }
  }

Don't forget to call removeObserver, after the Application has been terminated or the Activity destroyed.
Example Kotlin Code:

override fun onDestroy() {
    super.onDestroy()
    //Remove the observer in the onDestroy, as it won't be needed to keep traking
    //the analytics events.
    UserAnalyticsDelegate.handler.getLiveData().removeObserver(userAnalyticsObserver)
  }

iOS

Example Swift Code:

TMTickets.shared.analyticsDelegate = self

extension MainMenuViewController: TMTicketsAnalyticsDelegate {
    
    func userDidView(
            page: TMTickets.Analytics.Page, 
            metadata: TMTickets.Analytics.MetadataType) {
            
        print("userDidViewPage: \(page.rawValue)")

        // different Pages return different types of metadata
        switch metadata {
        case .events(let events):
            print(" - events: \(events.count)")
        case .event(let event):
            print(" - event: \(event.info.identifier)")
        case .eventTickets(let event, let tickets):
            print(" - event: \(event.info.identifier) tickets: \(tickets.count)")
        case .eventTicket(event: let event, let ticket):
            let ticketSummary = "\(ticket.sectionName ?? "_") \(ticket.rowName ?? "_") \(ticket.seatName ?? "_")"
            print(" - event: \(event.info.identifier) ticket: \(ticketSummary)")
        case .module(let event, let identifier):
            print(" - module: \(identifier) event: \(event.info.identifier)")
        case .moduleButton(let event, let module, let button):
            print(" - module: \(module.identifier) button: \(button.title)(\(button.callbackValue) event: \(event.info.identifier)")
        case .empty:
            print(" - empty")
        @unknown default:
            print(" - empty")
        }
    }
    
    func userDidPerform(
            action: TMTickets.Analytics.Action, 
            metadata: TMTickets.Analytics.MetadataType) {
            
        print("userDidPerformAction: \(action.rawValue)")
        
        // different Actions return different types of metadata
        switch metadata {
        case .events(let events):
            print(" - events: \(events.count)")
        case .event(let event):
            print(" - event: \(event.info.identifier)")
        case .eventTickets(let event, let tickets):
            print(" - event: \(event.info.identifier) tickets: \(tickets.count)")
        case .eventTicket(event: let event, let ticket):
            let ticketSummary = "\(ticket.sectionName ?? "_") \(ticket.rowName ?? "_") \(ticket.seatName ?? "_")"
            print(" - event: \(event.info.identifier) ticket: \(ticketSummary)")
        case .module(let event, let identifier):
            print(" - module: \(identifier) event: \(event.info.identifier)")
        case .moduleButton(let event, let module, let button):
            print(" - module: \(module.identifier) button: \(button.title)(\(button.callbackValue) event: \(event.info.identifier)")
        case .empty:
            print(" - empty")
        @unknown default:
            print(" - empty")
        }
    }
}

Modules

Only a very basic example, see Modules Overview

Android

private fun setModuleDelegate() {
    TicketsSDKSingleton.moduleDelegate = object : TicketsModuleDelegate {
        override fun getCustomModulesLiveData(order: TicketsOrder): LiveData<List<TicketsSDKModule>> {
            val modules: ArrayList<TicketsSDKModule> = ArrayList()
            
            // add prebuilt modules (optional)
            modules.addAll(addPrebuiltModules(order))
            
            // add custom modules (optional)
            modules.addAll(addCustomModules(order))
            
            // return a live data of a list of modules
            return MutableLiveData(modules)
        }

        override fun userDidPressActionButton(buttonTitle: String?, callbackValue: String?, eventOrders: EventOrders?) {
            Log.d("userDidPressAction", eventOrders.toString())
        }
    }
}

iOS

Example Swift Code:

TMTickets.shared.moduleDelegate = self

extension MainMenuViewController: TMTicketsModuleDelegate {
            
    func addCustomModules(
            event: TMPurchasedEvent, 
            completion: @escaping ([TMTicketsModule]?) -> Void) {
            
        print("Add Modules...")
        var modules: [TMTicketsModule] = []
        
        // add prebuilt modules (optional)
        modules.append(contentsOf: addPreBuiltModules(event: event))
        
        // add custom modules (optional)
        modules.append(contentsOf: addCustomModules(event: event))
        
        // return list of modules (in the order you want them displayed)
        completion(modules)
    }
    
    func handleModuleActionButton(
            event: TMPurchasedEvent, 
            module: TMTicketsModule, 
            button: TMTicketsModule.ActionButton, 
            completion: @escaping (TMTicketsModule.WebpageSettings?) -> Void) {
            
        // Tickets SDK won't call this method unless it is not sure what to do with the given module
        // to get analytics about all modules, see userDidPerform(action:metadata:)
        print("\(module.identifier): \(button.callbackValue)")
    }
}

Was this article helpful?