Introduction
Fullstory for Mobile Apps SDK can now automatically generate selectors for SwiftUI Views. Selector generations happen at runtime, but because SwiftUI relies on the compiled type of a View to support model data dependencies, the mechanism can't function unless the compiled representation changes. Fullstory has provided a tool to automatically instrument the Views at build time which you can add to your project.
Getting Started
This feature is in Preview and subject to change in future versions of the Fullstory SDK
Make sure you have installed the Fullstory SDK as described in our Getting Started with iOS Data Capture.
Note that the User Script Sandboxing build setting must be set to NO
.
Installation
Next, update your Info.plist
to include the following in the FullStory
dictionary:
-
SwiftUIEnabled
typeBoolean
toYES
-
SwiftUISelectorVersion
typeNumber
to3
-
SwiftUISelectorPreview
typeNumber
to2
Finally, run the included FullStorySwiftUITransformer
either using Build Rules, which doesn't modify the source in your repository, OR Build Phase, which modifies the source in your repository, but supports the use of debug breakpoints.
Swift Packages, however, can only be transformed using Build Phase.
Transformation using Build Rules
Repeat this step for every Xcode Target that contains custom SwiftUI Views (structs that implement the View protocol). This step does not instrument Swift Packages - please use the steps for Build Phase, below, to instrument packages.
- In the project navigator, select your App’s Project, then select your Target in the editor panel
-
Open the Build Rules tab, click the + button (next to "All") to add a rule to the top
- Choose to process Swift source files using Custom script and paste the script below, including all quotes, as a single line, to run
FullStorySwiftUITransformer
in Fullstory SDK'stools
folder (sample below shows when Fullstory is added via Swift Package Manager):"${BUILD_DIR%Build/*}SourcePackages/artifacts/fullstory-swift-package-ios/FullStory/tools/FullStorySwiftUITransformer" "$SCRIPT_INPUT_FILE" "$DERIVED_FILE_DIR/${INPUT_FILE_BASE}_transformed.swift"
- Under "Output Files" section of the rule, click + and edit the rule to say $(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE)_transformed.swift
- Choose to process Swift source files using Custom script and paste the script below, including all quotes, as a single line, to run
- Click the + button again to add another rule above the one you just added. Choose to process Source files with names matching and enter *_transformed.swift
Resulting Build Rules should look like below (note that the ordering is important).
Run the Build and in the Build output, you should see your source being transformed and the transformed source files generated by Swift compiler:
Note that FullStorySwiftUITransformer
generates new source files that are not checked into the source repository. Because of this, debugging breakpoints added to the original source will not be hit. If this is not desired, one way to work around this is to remove the build step in a Git branch, and checkout this branch whenever debugging is needed. (Make sure to rebase the branch as needed to keep it up to date!)
The Build output pane in Xcode will allow you to view the transformed files (e.g. go to All Messages and double-click on a Compile MyView_transformed.swift message).
The instructions above add the _transformed suffix to each file's name before the file extension; for example, MyView.swift becomes MyView_transformed.swift. This will change the way the files are reported by any tools that use the compiled file names, for example, in crash reports. However, the FullStorySwiftUITransformer
should preserve the existing line numbers of your files for crash reporting or other purposes. In addition, type names will remain the same, and the only change to a variable is made to the body property of each SwiftUI View struct.
You may use a different suffix than _transformed if you wish, as long as it will uniquely identify transformed SwiftUI files. For example, if none of your SwiftUI files end in an underscore _ , you could make the suffix just the underscore character.
Pre-transformation using Build Phase
With this method, you can support Swift Packages and/or Debug Breakpoints by pre-transforming the source in your project, which means all transformations will remain in your source repository. All transformations live within /*Fullstory_XFORM_start*/
and /*Fullstory_XFORM_end*/
for easy identification and removal, if needed. The Build phase can transform the Swift Package source artifacts and/or pre-transform the source in your project.
- In the project navigator, select your App’s Project, then select your Target in the editor panel
- Open the Build Phases tab, click the + button to add a New Run Script Phase
- Drag the phase to the top of the list of phases, before Compile Sources
- To transform Swift Packages, paste the script below, including all quotes, as a single line, to run
FullStorySwiftUITransformer
in Fullstory SDK'stools
folder (sample below shows when Fullstory is added via Swift Package Manager):
find "${BUILD_DIR%Build/*}SourcePackages/checkouts" -type f -name "*.swift" | tr \\n \\0 | xargs -S 1048576 -P $(sysctl -n hw.ncpu) -0 -n 1 -I % "${BUILD_DIR%Build/*}SourcePackages/artifacts/fullstory-swift-package-ios/FullStory/tools/FullStorySwiftUITransformer" "%" "%"
- To transform your project's source code, similarly paste the script below, including all quotes, as a single line:
find . -type f -name "*.swift" | tr \\n \\0 | xargs -S 1048576 -P $(sysctl -n hw.ncpu) -0 -n 1 -I % "${BUILD_DIR%Build/*}SourcePackages/artifacts/fullstory-swift-package-ios/FullStory/tools/FullStorySwiftUITransformer" "%" "%"
In addition, when transforming Swift Packages, it may help to reset package caches before building. Otherwise, your app may build with a cached copy of the package instead of the transformed package source.
Additional Notes
Not every View type is supported in this preview release. If an unknown View type is encountered, the class .fs-unknownview will be applied to the View and the sub-hierarchy beneath will be skipped. This can occur because support has not been added for said View type, because it behaves unexpectedly, or because you have not used the SwiftUIViewTransformer on a custom view type. You can still write selectors based on this unknown view; for example, you could write a privacy rule to mask all unknown views. The captured view hierarchy may change in future releases of Fullstory as support for SwiftUI is improved.
To skip transforming a file, add the string //Fullstory_XFORM_disable
(no spaces) to the file.
If you have any questions, run into any issues, or have requests to add support for a view, please contact support! We will be very happy to help.