Make sure you have installed the minimum package version: 1.17.0
If your LogRocket server is self hosted, mobile SDK version 1.17.0 requires a minimum server version of 16.462.0
About Swift UI
The LogRocket SDK will work with SwiftUI in the same way as the existing iOS SDK outlined in these iOS docs, with the following known limitations.
SwiftUI Differences from UIKit
View Names
As with UIKit, LogRocket can automatically infer information about the view hierarchy in SwiftUI. Because views are defined declaratively in SwiftUI, which handles management of the rendered view hierarchy under the hood, automatically detected view selectors contain the more generic names of the underlying views that comprise the rendered interface, rather than custom SwiftUI View names or the SwiftUI Library names for declarative views. Manually tagged view names will be injected into these selectors, and searchable in LogRocket filters.
Custom view tags are added using the lrAddClass
modifier, which takes a string value that is treated as the ID for a given View in its selector.
func lrAddClass(_ viewSelector: LocalizedStringKey) -> some View
Parameters
viewSelector
The string to be included in the View's recorded selector
Return Value
A view with an associated string detectable by the LogRocket SDK for selector generation
Navigation
As with UIKit, SwiftUI screens may not be meaningful on their own. As such, we recommend using the Manual Page Identification API to best track navigation events.
Individual view redaction
Because the SwiftUI accessibilityIdentifier
modifier does not apply the passed value to the views comprising the rendered application interface, it cannot be used to apply redactionTags
to individual private views. Instead, our custom lrHide
modifier can be used to mark SwiftUI Views for redaction.
// Definition
func lrHide() -> some View
// Example Usage
Text("Green").foregroundColor(.green).tag(Color.green).lrHide()
Return Value
A view with an associated redaction-indicator detectable by the LogRocket SDK to prevent said view and its contents from being recorded
Individual view allowlisting
Individual subviews of redacted SwiftUI Views can be allowed for view capture using our customer lrShow
modifier
// Definition
func lrShow() -> some View
// Example Usage
// Label icon and first button are captured, label text and second button are not
ScrollView {
Label(title: {
Text("Hidden Label Text").lrHide()
}, icon: {
Image(systemName: "text.magnifyingglass")
}).lrShow()
Button("Allowed Button", action: {}).lrShow()
Button("Hidden Button", action: {})
}.lrHide()
Return Value
A view with an associated allow-indicator detectable by the LogRocket SDK to allow capture of said view and its contents.
Limitations
SwiftUI Previews
We are aware of a compatibility issue with SwiftUI View Previews when importing LogRocket, and are working on resolving it. At this time, you can view previews locally by importing LogRocket conditionally on non-debug builds, or you can simply comment out LogRocket code when needing to view previews.
Sanitization and view tagging
While complete masking rules still apply, such as Automatically Sanitize Text and Sanitize Network Data,, there are current limitations with redacting individual views.
Container Views
Because the following SwiftUI view types do not comprise actual views, and are instead strictly function as layout information handlers for constructing the hierarchy of their contained views, tagging and redaction is not currently supported for them. Tags and sanitization must be applied directly to individual non-container views. Container views include:
- Form
- ForEach
- Grids (Grid, LazyHGrid, LazyVGrid)
- Group
- LabeledContent
- List
- Stacks (HStack, VStack, ZStack, LazyHStack, LazyVStack)
- ViewThatFits
Custom Views
In order to redact a custom SwiftUI View from session replay, lrHide
must be applied inside of the body
definition for the custom View. Applying the modifier to the invocation of the custom may not redact all contents of the custom View.
This same limitation also applies to manual view tagging. In order for all contents of a custom view to include the passed string in their recorded selectors, the lrAddClass
must be applied inside of the custom view's body
definition, not to the invocation of the custom view inside of another view's body
Example
struct LandmarkItem: View {
var landmarkName: String
var shouldHide: Bool?
func getBody() -> any View {
if shouldHide == true {
return (
ScrollView{
Image(landmarkName.lowercased())
Spacer()
Text(landmarkName)
}.padding(.horizontal).lrHide()
)
}
return (
ScrollView{
Image(landmarkName.lowercased())
Spacer()
Text(landmarkName)
}.padding(.horizontal)
)
}
var body: some View {
AnyView(getBody())
}
}
struct ContentView: View {
var body: some View {
VStack {
// INCORRECT
// This line redacts only part of the entire LandmarkItem view,
// the Text portion in this case
LandmarkItem(landmarkName: "Chincoteague").lrHide()
// CORRECT
// This line redacts the entire LandmarkItem by applying lrHide
// to the outermost SwiftUI library View, HStack in this case
LandmarkItem(landmarkName: "Umbagog", shouldHide: true)
}
}
}
Picker with pickerStyle(.menu)
pickerStyle(.menu)
When a Picker element with the style menu
is tagged to be hidden with lrHide
, the SDK does not automatically redact the contents of the dropdown. Because the manner in which SwiftUI's rendering of the actual menu piece that appears after tapping on the Picker's target element does not allow for us to programmatically detect the appearance of that menu view, context menus must be redacted altogether from session recordings (meaning all context menus across the application are redacted) or not at all. Redacting context menus requires the additional SDK.initialize
configuration value redactMenus: true
Example
In the following view implementation, the target (outlined in teal) for the Color Menu view will always be redacted from session recordings, because the Picker
view is modified with lrHide
. The target for the Number Menu view will not be redacted from session recordings.
When redactMenus: true
is included in the Configuration
sent to SDK.initialize
, both Context Menus will be redacted from session recordings (regardless of whether the Picker
element by which they were generated has the lrHide
modifier.
When redactMenus: false
or redactMenus
is excluded from the Configuration
, neither Context Menu will be redacted, despite the Picker
element that generates the Color Menu being modified with lrHide
.
var body: some View {
VStack {
Text("Pick a color, any color of the rainbow")
Picker("Color Menu", selection: $color) {
Text("Red").tag(Color.red)
Text("Orange").tag(Color.orange)
Text("Yellow").tag(Color.yellow)
Text("Green").tag(Color.green)
Text("Blue").tag(Color.blue)
Text("Indigo").tag(Color.indigo)
Text("Purple").tag(Color.purple)
}.pickerStyle(.menu).lrHide()
Text("Pick a number between 1 and 5")
Picker("Number Menu", selection: $number) {
Text("1").tag(1)
Text("2").tag(2)
Text("3").tag(3)
Text("4").tag(4)
Text("5").tag(5)
}.pickerStyle(.menu)
}.onAppear({
SDK.initialize(
Configuration(
appID: 'my-org/my-app',
redactMenus: true
)
)
})
}