Integrate the Tealeaf SDK into your iOS app
Use the Tealeaf iOS SDK to instrument your native and hybrid iOS applications for logging and analysis.
Requirements
- Acoustic Tealeaf. To use the library, your company must have an active Tealeaf subscription.
- Development environment. You can integrate the Tealeaf SDK into native iOS applications build on Swift and Objective-C. You will need Xcode 15 with Command Line Tools.
- Mobile app compatibility. The library can capture user experience data on end users' devices running iOS 12 and later. On iPadOS, only single-window applications are currently supported.
Initial setup
We recommend installing the SDK using a dependency manager.
You can add the Tealeaf SDK to your iOS app using the CocoaPods dependency manager. This option requires a recent version of CocoaPods.
Here are steps to follow:
- If you don't have a Podfile in your Xcode project directory, create one.
- Open the Podfile in a text editor and make sure the iOS version is 12.0 or later. Then uncomment
use_frameworks!
. - In the same Podfile, set
pod
to eitherTealeaf
orTealeafDebug
, depending on the build you want to use.
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '12.0'
target 'SwiftUIMindBlowing' do
use_frameworks!
pod 'Tealeaf'
end
- In a terminal emulator, navigate to your project directory.
- Install the pods. Make sure the command is completed with no errors. If you get an error, run the same command with the
--verbose
option and share the error log with our services team.
pod install
Important notes:
- Sometimes CocoaPods fails to load the latest version. So you may need to pull it using
pod update
. - Use the
$(inherited)
flag in your application target's "Other Linker Settings". This will ensure all the Pods are linked correctly.
You can add the Tealeaf iOS SDK to your app using the Carthage dependency manager.
- Create a Cartfile in your Xcode project directory if you don't have one yet.
touch Cartfile
- Open the Cartfile in a text editor and add the following lines for the release build. To use the debug build, update the file names: instead of TealeafDebug.json use TealeafDebug.json and instead of EOCore.json use EOCoreDebug.json.
binary "https://raw.githubusercontent.com/acoustic-analytics/Tealeaf/master/Tealeaf.json"
binary "https://raw.githubusercontent.com/acoustic-analytics/EOCore/master/EOCore.json"
Warning
Never use the release and debug builds together in the same project.
- From the root project directory, run the command
carthage update --platform iOS
. Make sure it completes without errors. - In a file manager, navigate to
/Carthage/Build
inside your project directory and select two bundles:EOCore.xcframework
andTealeaf.xcframework
.
![Tealeaf bundles to select](https://files.readme.io/30a944d-tealeaf-libraries-to-copy.png)
- Select the primary project target. Drag and drop the bundles to Frameworks, Libraries, and Embedded Content in the target settings. Select Embed & Sign for each bundle.
![Tealeaf libraries in the project](https://files.readme.io/3024e3d-tealeaf-libraries-added.png)
- Switch to the Build Phases tab and make sure the bundles appear under Embed Frameworks. If they don't, you will need to add them as frameworks.
![Frameworks in build settings](https://files.readme.io/32ed0da-embed-frameworks-ts.png)
- Rebuild the project.
You can add the Tealeaf iOS SDK as a Swift Package.
- In your Xcode project, go to File > Add Package Dependencies.
![Add package dependencies](https://files.readme.io/550184c-add-package-deoendencies.png)
- Search for
https://github.com/go-acoustic/Tealeaf-SP
. For the debug build, replaceTealeaf-SP
withTealeafDebug-SP
. Never use both versions in the same project.
![Adding Tealeaf Swift Package](https://files.readme.io/26c5247-add-tealeaf-sp.png)
- Select the target to add the library to.
Note:
If using the debug version, you can edit your project's scheme in XCode and add the following environmental variables:
EODebug
with the value of1
andTLF_DEBUG
with the value of1
.This will enable debug logs in your Xcode console window. Whenever you report an issue to our support team, make sure you share these logs.
Set up the iOS SDK with your project
- Add import statements to your bridging header file
Any class that is listed in the bridging header file can be accessed from your Swift classes.
- Create a bridging header file if your project does not have one. To create a bridging header, go to File > New > File.
- From the iOS template options, go to Source and select the Header File.
- Name your file as <ProjectName>/<ProjectName>-Bridging-Header.h and click Create. If Xcode offers to create an Objective-C bridging header file, accept it.
- Navigate to your project Build Settings > Swift Compiler - General section. Next to Objective-C Bridging Header, add the name/path of your header file. If your file resides in your project's root folder, put the name of the header file there.
For example: <ProjectName>/<ProjectName>/-Bridging-Header.h or <ProjectName>-Bridging-Header.h. - Open the bridging header file and add the following import statements:
Note:
ASIdentifierManager.h
is required if you want your application to capture Apple identifier for advertisers (IDFA) data using the TealeafAdvertisingId
property.
#import <Tealeaf/TLFApplicationHelper.h>
#import <Tealeaf/TLFCustomEvent.h>
#import <Tealeaf/TLFPublicDefinitions.h>
#import <AdSupport/ASIdentifierManager.h>
Any class that is listed in the bridging header file can be accessed from your Objective-C classes.
- Create a bridging header file if your project does not have one. To create a bridging header, go to File > New > File.
- From the iOS template options, go to Other and select the PCH File.
- Name your file as <ProjectName>-Prefix.pch and click Create.
- Navigate to your project Build Settings and select All. Find the Prefix Header field and add the name/path of your header file.
For example: <ProjectName>/<ProjectName>/-Prefix.pch. - Open the <ProjectName>-Prefix.pch file and add the following import statements:
Note:
ASIdentifierManager.h
is required if you want your application to capture Apple identifier for advertisers (IDFA) data using the TealeafAdvertisingId
property.
- Set the Objective-C linker flag.
a. Go to the Build Settings for your project.
b. In the search box, enter Other Linker Flags.
c. If the -ObjC flag is not listed as an Other Linker Flags entry, double-click the row and select the +, then enter -ObjC. - Configure your properties file to point to your target server
Go to Tealeaf.framework/TLFResources.bundle/TealeafBasicConfig.plist file and edit the PostMessageUrl to point to your target server.
Integrate the iOS SDK
- Enable the Tealeaf framework.
Note:
If
DynamicConfigurationEnabled
in EOCoreBasicConfig.plist is set toNO
you do not have to complete this task.- For Swift:
Open the AppDelegate.swift file and add one of the following code to the
didFinishLaunchingWithOptions
function:
Option 1://Tealeaf TLFApplicationHelper.sharedInstance().enableTealeafFramework() //Tealeaf EndOption 2:
If you want your application to capture Apple identifier for advertisers (IDFA) data using the TealeafAdvertisingId
property, add the following code snippet:TLFApplicationHelper.sharedInstance().setCXAAdvertisingId(ASIdentifierManager.shared().advertisingIdentifier.uuidString) TLFApplicationHelper.sharedInstance().enableTealeafFramework() - For Swift UI:
- Your application will require an
UIApplicationDelegate
implementation. To implement theUIApplicationDelegate
for your application, you can- Open the swift App class file and add the following code. or
- Create a new AppDelegate file with the following code.
- You must create a SceneDelegate.swift file if it doesn't already exist for your project and add the following code:
- Create a Info.plist file if it doesn't already exist for your project as follows:
class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Option 1 TLFApplicationHelper.sharedInstance().enableTealeafFramework() // Option 2 - If you want to capture Apple Identifier for advertisders (IDFA) data using Tealeaf // TLFApplicationHelper.sharedInstance().setCXAAdvertisingId(ASIdentifierManager.shared().advertisingIdentifier.uuidString) // TLFApplicationHelper.sharedInstance().enableTealeafFramework() return true } // 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) } }Note:
If you want your application to capture Apple identifier for advertisers (IDFA) data using the Tealeaf AdvertisingId property, you must add the following code:
TLFApplicationHelper.sharedInstance().setCXAAdvertisingId(ASIdentifierManager.shared().advertisingIdentifier.uuidString)
In the example code provided, you must comment out Option 1 and uncomment option 2 to enable the code.
import UIKit import SwiftUI class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). // Use a UIHostingController as window root view controller if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = UIHostingController(rootView: HomeView()) self.window = window window.makeKeyAndVisible() } } }Note:
The
rootViewController
may differ depending on the class names in your project. - Your application will require an
- For Swift:
TLF_DEBUG
, EODebug
and set the variable value to 1
.Set the UIApplication class to track UI control events
The UIApplication
class allows the UI control events to be tracked by the SDK.
- In your Swift application, open the AppDelegate.swift file and comment out the following:
- For Swift:
@UIApplicationMain
line. - For Swift UI:
@main
- For Swift:
- Override the
sendAction
andsendEvent
methods. Create a HelloSwiftApplication.swift file and add the following code to the file:import Foundation import UIKit import Tealeaf class HelloSwiftApplication: UIApplication { override func sendEvent(_ event: UIEvent) { TLFApplicationHelper.sharedInstance().send(event) super.sendEvent(event) } override func sendAction(_ action: Selector, to target: Any?, from sender: Any?, for event: UIEvent?) -> Bool { TLFApplicationHelper.sharedInstance().sendAction(action, to: target, from: sender, for: event) return super.sendAction(action, to: target, from: sender, for: event) } } - Create main.swift file and add the following code:
import Foundation import UIKit UIApplicationMain (CommandLine.argc, CommandLine.unsafeArgv, NSStringFromClass (HelloSwiftApplication.self), NSStringFromClass(AppDelegate.self))
- Open the Info.plist file and add the following:
Note:
For Swift UI, you must create the info.plist file as described in an earlier step.
Key "Principal Class" with value: "HelloSwiftApplication".Auto-log Swift app crashes and exceptions
You can log Swift app crashes and exceptions when the following debugging and testing functions included in your application are called:
- func assert(()
- func assertionFailure(()
- func precondition(()
- func preconditionFailure(()
- func fatalError(()
To auto-log the swift crash and exception, you must add a swift file with the following lines of code in your Swift application project. The added file will be compiled into your application and globally listen to the function in the Swift application. Then it will log information to Tealeaf and call the original Swift function.
// // Copyright (C) 2022 Acoustic, L.P. All rights reserved. // // NOTICE: This file contains material that is confidential and proprietary to // Acoustic, L.P. and/or other developers. No license is granted under any intellectual or // industrial property rights of Acoustic, L.P. except as may be provided in an agreement with // Acoustic, L.P. Any unauthorized copying or distribution of content from this file is // prohibited. // // TLFatalErrorUtil.swift // SwiftUIMindBlowing // // Created by Omar Hernandez on 11/17/22. // import Foundation import Tealeaf // overrides Swift global `assert` public func assert(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = String(), file: StaticString = #file, line: UInt = #line) { TLFCustomEvent.sharedInstance().logAssertErrorEvent(nil, condition: condition(), message: message(), file: String(describing: file), line: UInt32(line)) Swift.assert(condition(), message(), file: file, line: line) } // overrides Swift global `assertionFailure` public func precondition(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = String(), file: StaticString = #file, line: UInt = #line) { TLFCustomEvent.sharedInstance().logPreconditionErrorEvent(nil, condition: condition(), message: message(), file: String(describing: file), line: UInt32(line)) Swift.precondition(condition(), message(), file: file, line: line) } // overrides Swift global `assertionFailure` @inlinable public func assertionFailure(_ message: @autoclosure () -> String = String(), file: StaticString = #file, line: UInt = #line) { TLFCustomEvent.sharedInstance().logAssertionFailureErrorEvent(nil, message: message(), file: String(describing: file), line: UInt32(line)) Swift.assertionFailure(message(), file: file, line: line) } // overrides Swift global `preconditionFailure` public func preconditionFailure(_ message: @autoclosure () -> String = String(), file: StaticString = #file, line: UInt = #line) -> Never { TLFCustomEvent.sharedInstance().logPreconditionFailureErrorEvent(nil, message: message(), file: String(describing: file), line: UInt32(line)) Swift.preconditionFailure(message(), file: file, line: line) } // overrides Swift global `fatalError` public func fatalError(_ message: @autoclosure () -> String = String(), file: StaticString = #file, line: UInt = #line) -> Never { TLFCustomEvent.sharedInstance().logFatalErrorEvent(nil, message: message(), file: String(describing: file), line: UInt32(line)) Swift.fatalError(message(), file: file, line: line) }For more information, check out the Sample appwith the Swift file added.
- In the main.m file, add the following code to initialize
TLFApplication
, and pass the reference toUIApplicationMain
.NSString *tealeafSDK = NSStringFromClass([TLFApplication class]); return UIApplicationMain(argc, argv, tealeafSDK, NSStringFromClass([AppDelegate class])); - Enable the Tealeaf framework.
Note:
If
DynamicConfigurationEnabled
in EOCoreBasicConfig.plist is set toFalse
you can skip this step.Open the AppDelegate.m file and add one of the following code to the
didFinishLaunchingWithOptions
function:
Option 1:[[TLFApplicationHelper sharedInstance] enableTealeafFramework];Option 2:
If you want your application to capture Apple identifier for advertisers (IDFA) data using the TealeafAdvertisingId
property, add the following code snippet:[[TLFApplicationHelper sharedInstance] setCXAAdvertisingId:[[[ ASIdentifierManager sharedManager]advertisingIdentifier] UUIDString]];
Set the UIApplication class to track UI control events
The UIApplication
class allows the UI control events to be tracked by the SDK. Depending on whether your project implements a custom UIApplication
class or not, complete the following:
If your application does not have its own custom UIApplication
class, set the UIApplication
class to use the Tealeaf Application class TLFApplication
.
- In your main.m file, find
return UIApplicationMain(argc, argv, nil, NSStringFromClass);
- Replace the third argument,
nil
, with the name of theTLFApplication
class. The code should now look like this:return UIApplicationMain(argc, argv, NSStringFromClass ([TLFApplication class]), NSStringFromClass([AppDelegate class]));
If your project implements a custom UIApplication
class (for example, named CustomerUIApplication
), modify your custom UIApplication
class as follows:
- If there are no
sendAction
andsendEvent
methods, add thesendAction
andsendEvent
methods to your customUIApplication
class. The Tealeaf methods have logging built into them.@implementation CustomerUIApplication - (void)sendEvent:(UIEvent *)event { [[TLFApplicationHelper sharedInstance] sendEvent:event]; [super sendEvent:event]; } - (BOOL)sendAction:(SEL)action to:(id)target from:(id)sender forEvent: (UIEvent *)event { [[TLFApplicationHelper sharedInstance] sendAction:action to:target from:sender forEvent:event]; return [super sendAction:action to:target from:sender forEvent:event]; } - If there are
sendAction
andsendEvent
methods, you can modify them to point to the TealeafsendAction
andsendEvent
methods.
For example,- Add the following line to the
sendEvent
method:[[TLFApplicationHelper sharedInstance] sendEvent:event]; - Add the following line to the
sendAction
method:[[TLFApplicationHelper sharedInstance] sendAction:action to:target from:sender forEvent:event];
- Add the following line to the
Final project preparation
When using Tealeaf to capture a mobile session, images from the mobile application are sent to the Tealeaf server. If the images from the mobile application are already stored on the replay server, the mobile application does not upload the images during an active session. Uploading the images to the replay server reduces the amount of data sent from the mobile device and can display the images when you replay a native mobile session.
The Tealeaf SDK does screenshots of your app and the screenshots are used for replay.
To enable enhanced replay, go to the Tealeaf.framework/TLFResources.bundle/TealeafLayoutConfig.json file and configure the Autolayout
settings as follows:
- Set the
screenshot
totrue
- Set
CaptureScreenshotOn
value. For example,2
.
The Acoustic Tealeaf Image Tool is included with the Tealeaf iOS SDK and can be used to extract images from your mobile application.
Running the image capture tool extracts the images from your project source, hashes the image names from your project source, and replaces the image names in your project source with the new hashed names. After the image capture tool finishes processing, you can copy the hashed images to the replay server.
To run the image capture tool:
- Open TLFImageTool.app.
- Select Source and enter or select the path for the project source you are using to create your mobile application; then, select Choose.
- Select Destination and enter the path to store the hashed images extracted from your project; then, select Choose.
- Click one of the following depending on the type of the hash library you are using:
- Extract MD5 if you are using MD5 hashing libraries.
- Extract SHA256 if you are not using either the MD5 or SHA512 hashing libraries.
- Extract SHA512 if you are using SHA512 hasing libraries.
The image tool crawls your application code subfolders, looks for the corresponding image files, and copies the image files to the destination folder by computing each image file's hash. When all files are copied, a confirmation message Copied: 100% files displays.
Note:
If you select SHA512 or SHA256 and you used the image tool before with MD5, you must generate MD5 images in addition to the SHA512 or SHA256 files. This step is required because some iOS application users will not update your iOS application to the latest version. If you can force your iOS users to update their apps to the latest version, you can skip regenerating the MD5 library when selecting SHA512 or SHA256.
Wait for the image tool to finish copying files to the Destination folder before copying any other libraries.
Extracting PDF Vector Images in an iOS project
You can set a PDF image to UIImageView
through storyboard or programmatically.
- Programmatic
If the PDF image is set toUIImageView
programmatically, no additional steps are needed to extract the images. - Storyboard
If the PDF image is set toUIImageView
through storyboard, additional steps are needed to extract that image:- Set a user-defined runtime attribute for the
UIImageView
with the keytlfFileReference
and the name of the PDF image as the value. - Now run the image capture tool. You should see the PDF images along with other images in your designated folder.
- Set a user-defined runtime attribute for the
You can define any User-defined runtime
attributes for any NSKeyValueCoding
protocol compliant object using either of the following ways:
- Select the desired element (
UIImageView
instance in this case) in the storyboard and open Identity Inspector. Go to the User Defined Runtime Attributes section and add a new property. - Set programmatically by calling
setValue:forkeypath:
method of the object (UIImageView
instance in this case) in theviewDidLoad:
method of the object'sUIViewController
.
Note:
You must use the iOS image Capture tool as the primary tool to capture images in your application. However, if the iOS Image Capture tool cannot support your image replay experience, you can use the target simulator tool.
Upload to replay server
For application replay, the images that you added to your application should be copied to the replay server. When the images are on the replay server, the images do not need to be sent in the payload which could cause performance issues. Instead, replay uses a unique identifier for each image to retrieve the needed images from the replay server.
- Create the images.zip file. Go to your destination folder and create a zip file called images.zip. The .zip file should contain the contents of the destination folder. Do not create any other folder hierarchies while creating the zip.
- To ensure the format is correct, unzip the images.zip file somewhere on your computer and check to see that all images are extracted to a folder named images.
Note:
The zip file must be named images.zip. Tealeaf server requires one imagez.zip file for all your applications across all the native mMobile platforms. For this reason, if you have multiple applications on multiple nNative mMobile pPlatforms, such as iOS, iPadOS, Android, run the respective image tool for each application on the iOS and on Android platforms. After you copy all images from all applications, create one images.zip folder with the flat folder hierarchy.
- Copy the images.zip file to the replay server.
Tealeaf SAAS
If you are using Tealeaf SaaS, upload the zip file to Admin > Company settings > Native replay files > Image package Upload file. For more information, see Copy native and hybrid application images to the replay serverTealeaf On Premises
If you are using Tealeaf OnPrem, add the images.zip file under Replay Server. For more information, see Replay mobile app sessions as screen captures
Updated about 19 hours ago