- Print
- DarkLight
React Native Retail SDK - Purchase
Retail SDK - Purchase
React Native (iOS)
Create a new .swift file, the name in this guide is "PurchaseSDK" but call it whatever you like.
If it is the first time making a .swift file, Xcode will prompt you to make a Bridging-Header.h file, press "Create Bridging Header". A Bridging-Header.h will expose Objective-C public headers to Swift.
In [PROJECT-NAME]-Bridging-Header.h file add
#import <React/RCTBridgeModule.h>
In your PurchaseSDK.swift create a class and extend NSObject like below:
@objc(PurchaseSDK)
class PurchaseSDK: NSObject {
}
Import TicketmasterAuthentication, TicketmasterTickets, TicketmasterDiscoveryAPI and TicketmasterPurchase which should have been made available after adding the Ticketmaster Frameworks
import TicketmasterAuthentication
import TicketmasterTickets
import TicketmasterPurchase
import TicketmasterDiscoveryAPI
Declare a loadSDKView function which will accept the eventId
@objc public static func loadSDKView(_ eventId: String) {
}
Configure the Authentication SDK (needed for Tickets and Retails SDK’s) and Ticket’s SDK. Use an API key generated via the developer account.
@objc public static func loadSDKView(_ eventId: String) {
let apiKey = RNCConfig.env(for: "API_KEY") ?? ""
let tmxServiceSettings = TMAuthentication.TMXSettings(apiKey: apiKey,
region: .US)
let defaultBrandColor = UIColor(hexString: "026cdf") // TM blue
let branding = TMAuthentication.Branding(displayName: "My Team",
backgroundColor: .init(hexString: "#026cdf"),
theme: .light)
let brandedServiceSettings = TMAuthentication.BrandedServiceSettings(tmxSettings: tmxServiceSettings,
branding: branding)
TMPurchase.shared.configure(apiKey: apiKey, completion: {
isPurchaseApiSet in
print("Purchase api key set result: \(isPurchaseApiSet)")
TMDiscoveryAPI.shared.configure(apiKey: apiKey, completion: { isDiscoveryApiSet in
print("Discovery api key set result: \(isDiscoveryApiSet)")
TMAuthentication.shared.configure(brandedServiceSettings: brandedServiceSettings) { backendsConfigured in
TMPurchase.shared.brandColor = UIColor(red: 2, green: 108, blue: 223, alpha: 1.00)
TMTickets.shared.configure {
let edpNav = TMPurchaseNavigationController.eventDetailsNavigationController(eventIdentifier: eventId, marketDomain: .US)
edpNav.modalPresentationStyle = .fullScreen
UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.rootViewController?.present(edpNav, animated: true)
} failure: { error in
// something went wrong, probably TMAuthentication was not configured correctly
print(" - Tickets SDK Configuration Error: \(error.localizedDescription)")
}
} failure: { error in
// something went wrong, probably the wrong apiKey+region combination
print(" - Authentication SDK Configuration Error: \(error.localizedDescription)")
}
})
})
}
Presenting the Purchase view
Create a RetailSDK class in RetailSDK.swift file at the root of the project and add a function for presenting the purchase flow.
@objc(RetailSDK)
class RetailSDK: NSObject {
@objc public func presentPurchase(_ eventId: String) {
PurchaseSDK.loadSDKView(eventId)
}
}
The RetailSDK class might also have a function for presenting the prepurchase flow if needed (check out the Pre-Purchase documentation for reference).
Exposing Native View to React Native
Create a new .m file for RetailSDK - RetailSDK.m. Paste in the below inside RetailSDK.m:
#import "React/RCTBridgeModule.h"
@interface RCT_EXTERN_MODULE(RetailSDK, NSObject)
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
+ (BOOL)requiresMainQueueSetup {
return true;
}
RCT_EXTERN_METHOD(presentPurchase:(NSString *)eventId)
@end
Show the Native View in React Native
For the Pre-Purchase and Purchase SDK there isn't an embedded view like the Ticket's SDK as these SDK's Native header are not configurable as they need back button for users to "go back" during event and venue navigations.
In your React Native project, in any file, paste:
import {NativeModules} from 'react-native'
const showSDKView = async () => {
await NativeModules.RetailSDK.presentPrePurchaseVenue(id)
}
Customized Branding
You can customize branding of the Retail SDK in your ViewController file. Another example can be seen here: https://ignite.ticketmaster.com/docs/customize-branding
Analytics
To setup delegates in React Native iOS see: https://ignite.ticketmaster.com/docs/react-native-accounts-information
After setting up Delegates in your Accounts SDK NSObject/RCTEventEmitter class you can follow: https://ignite.ticketmaster.com/v1/docs/analytics-ios-1
React Native Display Event Detail Page (Android)
Create a listener that implements TMPurchaseNavigationListener. You will use this to handle callbacks
class PurchaseNavigationListener(private val closeScreen: () -> Unit) :
TMPurchaseNavigationListener {
override fun errorOnEventDetailsPage(error: Exception) {}
override fun onPurchaseClosed() {
closeScreen.invoke()
}
}
Create a PrePurchaseActivity
class PurchaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.venue_layout)
if (savedInstanceState == null) {
val tmPurchase = TMPurchase(
apiKey = BuildConfig.API_KEY,
brandColor = ContextCompat.getColor(
this,
R.color.black
)
)
val tmPurchaseWebsiteConfiguration = TMPurchaseWebsiteConfiguration(
intent.getStringExtra("eventId").orEmpty(),
TMMarketDomain.US,
)
val factory = TMPurchaseFragmentFactory(
tmPurchaseNavigationListener = PurchaseNavigationListener {
finish()
}
).apply {
supportFragmentManager.fragmentFactory = this
}
val tmAuthenticationParams = TMAuthenticationParams(
apiKey = BuildConfig.API_KEY,
clientName = "client name",
region = TMXDeploymentRegion.US
)
val bundle = tmPurchase.getPurchaseBundle(
tmPurchaseWebsiteConfiguration,
tmAuthenticationParams
)
val purchaseEDPFragment = factory.instantiatePurchase(ClassLoader.getSystemClassLoader()).apply {
arguments = bundle
}
supportFragmentManager.beginTransaction()
.add(R.id.venue_container, purchaseEDPFragment)
.commit()
}
}
Create a new ReactMethod in ReactContextBaseJavaModule:
class AccountsSDKModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
@ReactMethod
fun navigateToPurchase(eventId: String) {
val context = currentActivity
val intent = Intent(context, PurchaseActivity::class.java)
intent.putExtra("eventId", eventId)
context?.startActivity(intent)
}
}
You can invoke the React method in your react native:
import {NativeModules} from 'react-native';
const {AccountsSDK} = NativeModules;
AccountsSDK.presentPurchase("eventId");
Make sure you have PurchaseActivity added to your AndroidManifest.xml
<activity
android:name=".retail.PurchaseActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Customized Branding
You can customize branding of the Retail SDK in your Fragment file. Another example can be seen here: https://ignite.ticketmaster.com/docs/customize-branding
Analytics
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}")
}
}
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)
}