- Print
- DarkLight
Information
Information React Native (iOS)
Before following this guide make sure you've setup the Accounts SDK in your React Native App detailed here: https://ignite.ticketmaster.com/docs/clone-react-native-accounts-sdk
This guide will show you how to use Swift Delegates with Native Modules in React Native to let your app know about Authentication State, Tickets State, Analytics and Module changes/information.
In your AccountsSDK.swift class extend TMAuthenticationDelegate
@objc(AccountsSDK)
class AccountsSDK: NSObject, TMAuthenticationDelegate {
At the start of a method make the class the delegate of TMAuthentication with the following line code
TMAuthentication.shared.delegate = self
This has to be done before you can receive any state information logs, so it is best you do it during Accounts SDK configuration, or you can create a new native method to be called on React Native on component mount in a useEffect()
Here is an example of setting up the delegate using the configureAccountsSDK() method we wrote in theAccounts SDK guide
@objc public func configureAccountsSDK(_ resolve: @escaping (String) -> Void, reject: @escaping (_ code: String, _ message: String, _ error: NSError) -> Void) {
TMAuthentication.shared.delegate = self
// build a combination of Settings and Branding
let tmxServiceSettings = TMAuthentication.TMXSettings(apiKey: "[APIKEY]",
region: .US)
let branding = TMAuthentication.Branding(displayName: "My Team",
backgroundColor: .red,
theme: .light)
let brandedServiceSettings = TMAuthentication.BrandedServiceSettings(tmxSettings: tmxServiceSettings,
branding: branding)
...
To get over the Type ‘[CLASS NAME]’ does not conform to protocol 'TMAuthenticationDelegate' error, paste in the below method inside the AccountsSDK class
func onStateChanged(backend: TicketmasterAuthentication.TMAuthentication.BackendService?, state: TicketmasterAuthentication.TMAuthentication.ServiceState, error: (Error)?) {
print("Backend TicketmasterAuthentication \(state.rawValue)")
switch state{
case .serviceConfigurationStarted:
return
case .serviceConfigured:
return
case .serviceConfigurationCompleted:
return
case .loginStarted:
return
case .loginPresented:
return
case .loggedIn:
return
case .loginAborted:
return
case .loginFailed:
return
case .loginLinkAccountPresented:
return
case .loginCompleted:
return
case .tokenRefreshed:
return
case .logoutStarted:
return
case .loggedOut:
return
case .logoutCompleted:
return
@unknown default:
return
}
}
When there is a change in the Authentication state, the code block of that case will run. You can use Event Emitters to sent this event to React Native
Event emitters
Import the below into your <[Project-Name]>-Bridging-Header.h file
#import <React/RCTEventEmitter.h>
In AccountsSDK.swift instead of NSObject extend RCTEventEmitter
class AccountsSDK: RCTEventEmitter, TMAuthenticationDelegate {
Override a function called supportedEvents by pasting in the following method inside the AccountsSDK class:
override func supportedEvents() -> [String]! {
return [];
}
Replace the return of the loginStarted switch case with:
self.sendEvent(withName: "loginStarted", body: ["loginStarted:": "loginStarted event sent"])
onStateChanged should look similar to this:
func onStateChanged(backend: TicketmasterAuthentication.TMAuthentication.BackendService?, state: TicketmasterAuthentication.TMAuthentication.ServiceState, error: (Error)?) {
print("Backend TicketmasterAuthentication \(state.rawValue)")
switch state{
...
case .loginStarted:
self.sendEvent(withName: "loginStarted", body: ["loginStarted:": "loginStarted event sent"])
...
@unknown default:
return
}
}
Now add loginStarted to the returned array in the overriding supportedEvents()
override func supportedEvents() -> [String]! {
return [“loginStarted”];
}
Now implement RCTEventEmitter in your Objective-C implementation file by importing the below inside AccountsSDK.m
#import "React/RCTEventEmitter.h"
Export RCTEventEmitter to expose it to React Native
@interface RCT_EXTERN_MODULE(AccountsSDK, RCTEventEmitter)
The start of your AccountsSDK.m should look similar to the below:
#import "React/RCTBridgeModule.h"
#import "React/RCTEventEmitter.h"
@interface RCT_EXTERN_MODULE(AccountsSDK, RCTEventEmitter)
- (dispatch_queue_t)methodQueue
{
...
On the React Native side:
In your file where you are calling the Native Accounts SDK methods import
import {NativeEventEmitter} from 'react-native'
If you’re using React Navigation standard navigation.navigate() navigation won’t trigger a standard useEffects unmount code, so a useCallback can be used with a useFocusEffect to trigger unmount code as shown below
import React, {useCallback} from 'react'
import {useFocusEffect} from '@react-navigation/native'
const accountsSdkEventEmitter = new NativeEventEmitter(NativeModules.AccountsSDK)
const Home = () => {
…
useFocusEffect(
useCallback(() => {
accountsSdkEventEmitter.addListener('loginStarted', result => {
console.log('loginStarted event received', result)
})
console.log('useFocusEffect mount called')
return () => {
accountsSdkEventEmitter.removeAllListeners('accountsSdkEventEmitter')
console.log('useFocusEffect unmount called')
}
}, []),
)
return (
…
)
}
For more delegates and the needed functions to implement per delegate see here: https://ignite.ticketmaster.com/docs/information
You can also extend multiple delegates in an NSObject/RCTEventEmitter class
class IgniteO: RCTEventEmitter, TMAuthenticationDelegate, TMTicketsOrderDelegate {
…
}
Android
- Min SDK: 23
- Compile SDK: 33
- Kotlin Version: 1.8.2
- Gradle Build Tools: 7.4.2
//build.gradle (Module:app)
implementation 'androidx.datastore:datastore-preferences:1.0.0'
implementation 'androidx.datastore:datastore-preferences-rxjava2:1.0.0'
implementation "io.insert-koin:koin-core:3.2.2"
implementation "io.insert-koin:koin-android:3.2.2"
Retail SDK Implementation
//build.gradle (Module:app)
implementation "com.ticketmaster.retail:purchase:1.0.8"
implementation "com.ticketmaster.retail:prepurchase:1.0.5"
implementation "com.ticketmaster.retail:discoveryapi:1.0.2"
Make sure you have the following:
// build.gradle (Module: app)
android {
.........
buildFeatures {
dataBinding = true
}
}
<!-- Base application theme within app/src/main/res/values/styles.xml -->
<style name "AppTheme" parent="...">
..............
..............
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item> (add if you're using AppCompatActivity)
</style>