Display building floor plans in iOS with Swift
An example showing how to configure PSPDFKit to display a building floor plan. Get additional resources by visiting our blog on working with PDFs in a construction application.
//// Copyright © 2021-2025 PSPDFKit GmbH. All rights reserved.//// The Nutrient sample applications are licensed with a modified BSD license.// Please see License for details. This notice may not be removed from this file.//
import PSPDFKitimport PSPDFKitUI
/// This example uses the following Nutrient features:/// - Viewer/// - Annotations/// - Indexed Search/// - Replies////// See https://www.nutrient.io/sdk/ios for the complete list of Nutrient iOS SDK’s features.
class ConstructionExample: IndustryExample {
override init() { super.init()
title = "Construction" contentDescription = "Shows how to configure Nutrient to display a building floor plan." category = .industryExamples priority = 5 extendedDescription = """ This example shows how to customize the annotation toolbar for the construction industry by adding the following custom tools:
1. The drop pin tool — this lets the user create tasks on specific areas of the building floor plan. 2. The file attachment tool — this lets the user attach documents to the floor plan document. """ url = URL(string: "https://www.nutrient.io/blog/industry-solution-construction-ios/")! image = UIImage(systemName: "building.2.crop.circle") }
override func invoke(with delegate: ExampleRunnerDelegate) -> UIViewController { return ConstructionPDFViewController(with: self) }}
/// Custom PDF view controller class.private class ConstructionPDFViewController: PDFViewController, PDFViewControllerDelegate, PDFDocumentPickerControllerDelegate {
/// Document picker shown while adding a file annotation. var documentPickerController: PDFDocumentPickerController?
/// The point where the page view is long pressed to show the menu. /// Used to calculate the file annotation's bounding box. var longPressedPoint: CGPoint?
/// Bar button item used for showing annotation list. private lazy var annotationListButtonItem: UIBarButtonItem = UIBarButtonItem(image: SDK.imageNamed("document_annotations")!, style: outlineButtonItem.style, target: outlineButtonItem.target, action: outlineButtonItem.action)
/// Used for showing the more info alert. private var moreInfo: MoreInfoCoordinator!
init(with example: IndustryExample) { let document = AssetLoader.writableDocument(for: .floorPlan, overrideIfExists: false) document.title = "Building Floor Plan" document.overrideClass(StampAnnotation.self, with: PinStampAnnotation.self)
let emailConfiguration = DocumentSharingConfiguration.defaultConfiguration(forDestination: .email).configurationUpdated { $0.destination = .email $0.fileFormatOptions = [.PDF, .image] $0.annotationOptions = [.embed, .remove] $0.pageSelectionOptions = [.all] }
let configuration = PDFConfiguration { // Register the custom subclass of `AnnotationToolbar` to customize the annotation toolbar. $0.overrideClass(AnnotationToolbar.self, with: ConstructionAnnotationToolbar.self)
// Customize the sharing experience if available. if MFMailComposeViewController.canSendMail() { $0.sharingConfigurations = [emailConfiguration] }
// Miscellaneous configuration options. $0.backgroundColor = UIColor.psc_secondarySystemBackground $0.thumbnailBarMode = .none $0.spreadFitting = .fit $0.isPageLabelEnabled = false $0.documentLabelEnabled = .NO $0.isTextSelectionEnabled = false
// We handle the navigation bar title manually. $0.allowToolbarTitleChange = false }
super.init(document: document, configuration: configuration)
moreInfo = MoreInfoCoordinator(with: example, presentationContext: self) delegate = self
documentPickerController = PDFDocumentPickerController(directory: "/Bundle/Samples", includeSubdirectories: true, library: SDK.shared.library) documentPickerController?.delegate = self
// Configure custom default color presets. // See https://www.nutrient.io/guides/ios/annotations/customizing-presets/ for more details. let presets = [ ColorPreset(color: .red), ColorPreset(color: .black), ColorPreset(color: .green), ColorPreset(color: .blue) ] setDefault(colorPresets: presets, defaultColor: .red) }
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
override init(document: Document?, configuration: PDFConfiguration?) { super.init(document: document, configuration: configuration) moreInfo = MoreInfoCoordinator(with: ConstructionExample(), presentationContext: self) }
override func viewDidLoad() { super.viewDidLoad()
// Customize the navigation bar. // See https://www.nutrient.io/guides/ios/user-interface/main-toolbar for more details. navigationItem.leftBarButtonItems = [moreInfo.barButton, toggleAnnotationVisibilityBarButtonItem] navigationItem.leftItemsSupplementBackButton = true
// Only show the annotations list in the document info. // See https://www.nutrient.io/guides/ios/customizing-the-interface/customizing-the-available-document-information/ for more details. documentInfoCoordinator.availableControllerOptions = [.annotations]
// Only support the right position for the annotation toolbar. let annotationToolbar = annotationToolbarController!.annotationToolbar annotationToolbar.supportedToolbarPositions = .right annotationToolbar.toolbarPosition = .right annotationToolbar.isDragEnabled = false
// Use white buttons and a black background for the annotation toolbar. let appearance = UIToolbarAppearance() appearance.backgroundColor = UIColor(white: 0.2, alpha: 0.98) annotationToolbar.standardAppearance = appearance annotationToolbar.compactAppearance = appearance annotationToolbar.tintColor = UIColor(white: 0.95, alpha: 0.98)
// Setup a tap gesture recognizer that adds a pin annotation to the page if the pin annotation tool is selected. let addPinAnnotationGestureRecognizer = UITapGestureRecognizer() addPinAnnotationGestureRecognizer.addTarget(self, action: #selector(addPinAnnotationGestureRecognizerDidChangeState))
// Make it work simultaneously with all built-in interaction components. interactions.allInteractions.allowSimultaneousRecognition(with: addPinAnnotationGestureRecognizer) // Add the gesture recognizer to the document view controller's view. documentViewController?.view.addGestureRecognizer(addPinAnnotationGestureRecognizer)
setUpdateSettingsForBoundsChange { [weak self] _ in self?.updateNavigationBar() } }
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) updateNavigationBar() }
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) moreInfo.showAlertIfNeeded() }
// MARK: Customization
private func updateNavigationBar() { let availableWidth = view.bounds.inset(by: view.safeAreaInsets).width
// Show more items on wide screens. 440 is the minimum width needed to show 6 items including the back button. // Hide the title in the navigation bar if space is constrained and enable the floating document label in the document. if availableWidth > 440 { navigationItem.rightBarButtonItems = [activityButtonItem, annotationButtonItem, annotationListButtonItem] updateConfiguration { $0.documentLabelEnabled = .NO } navigationItem.title = document?.title } else { navigationItem.rightBarButtonItems = [annotationButtonItem, annotationListButtonItem] updateConfiguration { $0.documentLabelEnabled = .YES } navigationItem.title = nil } }
// MARK: FlexibleToolbarContainerDelegate
override func flexibleToolbarContainerWillShow(_ container: FlexibleToolbarContainer) { // If the annotations visibility is disabled, we force enable it when annotation toolbar becomes visible. if toggleAnnotationVisibilityBarButtonItem.title == "show" { didTapToggleAnnotationVisibilityBarButtonItem(toggleAnnotationVisibilityBarButtonItem) } }
override func flexibleToolbarContainerDidHide(_ container: FlexibleToolbarContainer) { if let annotationToolbar = annotationToolbarController?.annotationToolbar as? ConstructionAnnotationToolbar { annotationToolbar.deselectAllTools() } }
override func flexibleToolbarContainerContentRect(_ container: FlexibleToolbarContainer, for position: FlexibleToolbar.Position) -> CGRect { if [.pad, .mac].contains(container.traitCollection.userInterfaceIdiom) { let estimatedHeight: CGFloat = container.traitCollection.userInterfaceIdiom == .pad ? 600 : 456 let safeArea = view.bounds.inset(by: view.safeAreaInsets).inset(by: UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)) return CGRect(x: safeArea.minX, y: safeArea.minY, width: safeArea.width, height: min(estimatedHeight, safeArea.height)) } else { return super.flexibleToolbarContainerContentRect(container, for: position) } }
// MARK: Private
private lazy var toggleAnnotationVisibilityBarButtonItem: UIBarButtonItem = { let toggleAnnotationVisibility = UIBarButtonItem(image: UIImage(namedInCatalog: "hide"), style: .plain, target: self, action: #selector(didTapToggleAnnotationVisibilityBarButtonItem)) toggleAnnotationVisibility.title = "hide" return toggleAnnotationVisibility }()
@objc func didTapToggleAnnotationVisibilityBarButtonItem(_ sender: UIBarButtonItem) { // Let link annotations be always visible. if sender.title == "hide" { setVisibleAnnotationTypes(.link) sender.title = "show" sender.image = UIImage(namedInCatalog: "show") } else { setVisibleAnnotationTypes(.all) sender.title = "hide" sender.image = UIImage(namedInCatalog: "hide") } }
private func setVisibleAnnotationTypes(_ types: Annotation.Kind) { // Update the render types. document?.renderAnnotationTypes = types // Clear the cache so that pages are re-rendered once updated. PSPDFKit.SDK.shared.cache.remove(for: document) for pageView in visiblePageViews { pageView.updateAnnotationViews(animated: false) pageView.update() } }
private func setDefault(colorPresets: [ColorPreset]?, defaultColor: UIColor?) { let line = Annotation.ToolVariantID(tool: .line) let arrow = Annotation.ToolVariantID(tool: .line, variant: .lineArrow) let ink = Annotation.ToolVariantID(tool: .ink) let circle = Annotation.ToolVariantID(tool: .circle) let square = Annotation.ToolVariantID(tool: .square) let cloudyCircle = Annotation.ToolVariantID(tool: .circle, variant: Annotation.Variant(rawValue: "Cloudy Ellipse")) let dashedCircle = Annotation.ToolVariantID(tool: .circle, variant: Annotation.Variant(rawValue: "Dashed Ellipse")) let cloudyRectangle = Annotation.ToolVariantID(tool: .square, variant: Annotation.Variant(rawValue: "Cloudy Rectangle")) let dashedRectangle = Annotation.ToolVariantID(tool: .square, variant: Annotation.Variant(rawValue: "Dashed Rectangle")) let freeText = Annotation.ToolVariantID(tool: .freeText) let freeTextCallout = Annotation.ToolVariantID(tool: .freeText, variant: .freeTextCallout)
let styleManager = SDK.shared.styleManager styleManager.setDefaultPresets(colorPresets, forKey: line, type: .colorPreset) styleManager.setDefaultPresets(colorPresets, forKey: arrow, type: .colorPreset) styleManager.setDefaultPresets(colorPresets, forKey: ink, type: .colorPreset) styleManager.setDefaultPresets(colorPresets, forKey: circle, type: .colorPreset) styleManager.setDefaultPresets(colorPresets, forKey: square, type: .colorPreset) styleManager.setDefaultPresets(colorPresets, forKey: cloudyCircle, type: .colorPreset) styleManager.setDefaultPresets(colorPresets, forKey: dashedCircle, type: .colorPreset) styleManager.setDefaultPresets(colorPresets, forKey: cloudyRectangle, type: .colorPreset) styleManager.setDefaultPresets(colorPresets, forKey: dashedRectangle, type: .colorPreset) styleManager.setDefaultPresets(colorPresets, forKey: freeText, type: .colorPreset) styleManager.setDefaultPresets(colorPresets, forKey: freeTextCallout, type: .colorPreset)
// Set the default color for all the tools in the annotation toolbar. // See https://www.nutrient.io/guides/ios/annotations/changing-default-values-for-color-and-text-size-of-annotations/ for more details. styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: line) styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: arrow) styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: ink) styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: circle) styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: square) styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: cloudyCircle) styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: dashedCircle) styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: cloudyRectangle) styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: dashedRectangle) styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: freeText) styleManager.setLastUsedValue(defaultColor, forProperty: "color", forKey: freeTextCallout) }
// MARK: Gesture recognizer action.
@objc func addPinAnnotationGestureRecognizerDidChangeState(_ gestureRecognizer: UITapGestureRecognizer) { guard gestureRecognizer.state == .ended, let annotationToolbar = annotationToolbarController?.annotationToolbar as? ConstructionAnnotationToolbar, annotationToolbar.pinStampButton.isSelected, let documentViewController, let pageView = documentViewController.visiblePageView(at: gestureRecognizer.location(in: documentViewController.view)) else { // Return since we do not want to add a pin stamp in this case. return }
let viewPoint = gestureRecognizer.location(in: pageView)
// Don't create overlapping pins. if (pageView.annotationSelectionView?.bounds.contains(viewPoint)) != nil { return }
// Convert the point to PDF coordinates. // See https://www.nutrient.io/guides/ios/faq/coordinate-spaces/ for more details. let pdfPoint = pageView.convert(viewPoint, to: pageView.pdfCoordinateSpace)
// Programmatically create the pin stamp annotation and add it to the document. // See https://www.nutrient.io/guides/ios/annotations/programmatically-creating-annotations/#stamp-annotations for more details. let pinDropURL = Bundle(for: ConstructionPDFViewController.self).resourceURL!.appendingPathComponent("pin_drop_red.pdf") let pinStamp = PinStampAnnotation() pinStamp.boundingBox = CGRect(origin: pdfPoint, size: CGSize(width: 32, height: 32)) pinStamp.appearanceStreamGenerator = FileAppearanceStreamGenerator(fileURL: pinDropURL) pinStamp.pageIndex = pageIndex
// Store custom data to distinguish between a pin stamp and a regular stamp annotation. // See https://www.nutrient.io/guides/ios/annotations/custom-data-in-annotations/#storing-custom-data for more details. pinStamp.customData = ["isPinStampAnnotation": true]
let formatter = DateFormatter() formatter.timeStyle = .short formatter.dateStyle = .short pinStamp.contents = "Created on \(formatter.string(from: Date()))" document?.add(annotations: [pinStamp])
// Present the note annotation view controller immediately. let noteAnnotationViewController = NoteAnnotationViewController(annotation: pinStamp) noteAnnotationViewController.modalPresentationStyle = .popover pageView.selectedAnnotations = [pinStamp] let annotationView = pageView.annotationView(for: pinStamp) present(noteAnnotationViewController, options: [.closeButton: true], animated: true, sender: annotationView) }
// MARK: - PDFViewControllerDelegate
func pdfViewController(_ pdfController: PDFViewController, shouldShow controller: UIViewController, options: [String: Any]? = nil, animated: Bool) -> Bool { if controller.isKind(of: StampViewController.self) { return false } return true }
func pdfViewController(_ sender: PDFViewController, menuForAnnotations annotations: [Annotation], onPageView pageView: PDFPageView, appearance: EditMenuAppearance, suggestedMenu: UIMenu) -> UIMenu { // Keep only Comments, Delete, Inspector and Preview File actions. suggestedMenu .keep(actions: [.PSPDFKit.comments, .PSPDFKit.delete, .PSPDFKit.inspector, .PSPDFKit.previewFile]) }
func pdfViewController(_ sender: PDFViewController, menuForCreatingAnnotationAt point: CGPoint, onPageView pageView: PDFPageView, appearance: EditMenuAppearance, suggestedMenu: UIMenu) -> UIMenu { let attachFileAction = UIAction(title: "Attach File", image: UIImage(systemName: "paperclip")) { [self] _ in // Store the long pressed point in PDF coordinates to be used to set // the bounding box of the newly created file annotation. longPressedPoint = pageView.pdfCoordinateSpace.convert(point, from: pageView) // Present the document picker. present(self.documentPickerController!, options: [.closeButton: true], animated: true, sender: nil) } // Keep only the Paste action and prepend our custom action. return suggestedMenu .keep(actions: [.paste]) .prepend([attachFileAction]) }
func pdfViewControllerDidDismiss(_ pdfController: PDFViewController) { // Restore default presets to not affect other examples. setDefault(colorPresets: nil, defaultColor: nil) }
// MARK: - PDFDocumentPickerControllerDelegate
func documentPickerController(_ controller: PDFDocumentPickerController, didSelect document: Document, pageIndex: PageIndex, search searchString: String?) { let fileURL = document.fileURL let fileDescription = document.fileURL?.lastPathComponent
// Create the file annotation and its embedded file let fileAnnotation = FileAnnotation() fileAnnotation.pageIndex = pageIndex fileAnnotation.boundingBox = CGRect(x: (self.longPressedPoint?.x)!, y: (self.longPressedPoint?.y)!, width: 32, height: 32) let embeddedFile = EmbeddedFile(fileURL: fileURL!, fileDescription: fileDescription) fileAnnotation.embeddedFile = embeddedFile
// Add the embedded file to the document. self.document?.add(annotations: [fileAnnotation]) // Dismiss the document picker. controller.dismiss(animated: true, completion: nil) }}
/// Custom annotation toolbar class to allow the annotation toolbar customization./// See https://www.nutrient.io/guides/ios/customizing-the-interface/customizing-the-annotation-toolbar/ for more details.private class ConstructionAnnotationToolbar: AnnotationToolbar {
public var pinStampButton: ToolbarSelectableButton = ToolbarSelectableButton()
override init(annotationStateManager: AnnotationStateManager) { super.init(annotationStateManager: annotationStateManager)
typealias Item = AnnotationToolConfiguration.ToolItem typealias Group = AnnotationToolConfiguration.ToolGroup
let image = Item(type: .image) let ink = Item(type: .ink)
let distance = Item(type: .line, variant: .distanceMeasurement) { _, _, _ in SDK.imageNamed("line_distancemeasurement")!.withRenderingMode(.alwaysTemplate) } let perimeter = Item(type: .polyLine, variant: .perimeterMeasurement) { _, _, _ in SDK.imageNamed("polyline_perimetermeasurement")!.withRenderingMode(.alwaysTemplate) } let ellipticalArea = Item(type: .circle, variant: .ellipticalAreaMeasurement) { _, _, _ in SDK.imageNamed("circle_ellipticalareameasurement")!.withRenderingMode(.alwaysTemplate) } let rectangularArea = Item(type: .square, variant: .rectangularAreaMeasurement) { _, _, _ in SDK.imageNamed("square_rectangularareameasurement")!.withRenderingMode(.alwaysTemplate) } let polygonArea = Item(type: .polygon, variant: .polygonalAreaMeasurement) { _, _, _ in SDK.imageNamed("polygon_polygonalareameasurement")!.withRenderingMode(.alwaysTemplate) }
let circle = Item(type: .circle) let cloudyCircle = Item(type: .circle, variant: Annotation.Variant(rawValue: "Cloudy Ellipse")) { _, _, _ in UIImage(namedInCatalog: "ellipse_cloudy")! } let dashedCircle = Item(type: .circle, variant: Annotation.Variant(rawValue: "Dashed Ellipse")) { _, _, _ in UIImage(namedInCatalog: "ellipse_dashed")! } let square = Item(type: .square) let cloudySquare = Item(type: .square, variant: Annotation.Variant(rawValue: "Cloudy Rectangle")) { _, _, _ in UIImage(namedInCatalog: "rectangle_cloudy")! } let dashedSquare = Item(type: .square, variant: Annotation.Variant(rawValue: "Dashed Rectangle")) { _, _, _ in UIImage(namedInCatalog: "rectangle_dashed")! }
let line = Item(type: .line) let arrow = Item(type: .line, variant: .lineArrow, configurationBlock: Item.lineConfigurationBlock())
let freeText = Item(type: .freeText) let freeTextCallout = Item(type: .freeText, variant: .freeTextCallout) {_, _, _ in return SDK.imageNamed("freetext_callout")!.withRenderingMode(.alwaysTemplate) }
let note = Item(type: .note) let selectionTool = Item(type: .selectionTool)
let compactGroups = [ Group(items: [distance, perimeter, line, arrow, ink, freeText, freeTextCallout, note]), Group(items: [cloudySquare, cloudyCircle, dashedSquare, dashedCircle, polygonArea, ellipticalArea, rectangularArea, square, circle]), Group(items: [selectionTool]), Group(items: [image]) ]
let compactConfiguration = AnnotationToolConfiguration(annotationGroups: compactGroups)
let regularGroups = [ Group(items: [line, arrow, ink]), Group(items: [distance, perimeter, polygonArea, ellipticalArea, rectangularArea]), Group(items: [cloudySquare, cloudyCircle, dashedSquare, dashedCircle, square, circle]), Group(items: [freeText, freeTextCallout, note]), Group(items: [selectionTool]), Group(items: [image]) ] let regularConfiguration = AnnotationToolConfiguration(annotationGroups: regularGroups)
configurations = [compactConfiguration, regularConfiguration]
let fileAnnotationButton = ToolbarButton() fileAnnotationButton.accessibilityLabel = "Attach File" fileAnnotationButton.image = SDK.imageNamed("document_attachments")!.withRenderingMode(.alwaysTemplate) fileAnnotationButton.addTarget(self, action: #selector(fileAnnotationButtonButtonPressed(_:)), for: .touchUpInside)
pinStampButton.accessibilityLabel = "Add Pin" pinStampButton.image = UIImage(namedInCatalog: "pin_drop")!.withRenderingMode(.alwaysTemplate) pinStampButton.addTarget(self, action: #selector(pinStampButtonButtonPressed(_:)), for: .touchUpInside) pinStampButton.highlightsSelection = true self.additionalButtons = [pinStampButton, fileAnnotationButton] }
override func annotationStateManager(_ manager: AnnotationStateManager, didChangeState oldState: Annotation.Tool?, to newState: Annotation.Tool?, variant oldVariant: Annotation.Variant?, to newVariant: Annotation.Variant?) { if newState == .square || newState == .circle { // Update the annotation state manager's border effect property when the variant changes. if let variantValue = newVariant?.rawValue { if variantValue.hasPrefix("Cloudy") { // The border effect intensity needs to be non-zero when using the cloudy border effect. manager.borderEffectIntensity = 1 manager.borderEffect = .cloudy } else if variantValue.hasPrefix("Dashed") { manager.borderEffectIntensity = 0 manager.borderEffect = .noEffect manager.dashArray = [2] } } else { manager.borderEffectIntensity = 0 manager.borderEffect = .noEffect manager.dashArray = nil } }
// Deselect the custom pin button when changing the state. pinStampButton.setSelected(false, animated: true) super.annotationStateManager(manager, didChangeState: oldState, to: newState, variant: oldVariant, to: newVariant) }
override func done(_ sender: Any?) { super.done(sender)
// Deselect the custom pin button when closing the annotation toolbar. deselectAllTools() }
public func deselectAllTools() { // Deselect any previously selected tool in the annotation toolbar. annotationStateManager.state = nil pinStampButton.setSelected(false, animated: false) }
// MARK: Custom annotation toolbar buttons actions.
@objc func pinStampButtonButtonPressed(_ sender: ToolbarSelectableButton) { // Deselect any previously selected tool in the annotation toolbar. annotationStateManager.state = nil sender.setSelected(!sender.isSelected, animated: true) }
@objc func fileAnnotationButtonButtonPressed(_ sender: ToolbarButton) { // Deselect any previously selected tool in the annotation toolbar. annotationStateManager.state = nil pinStampButton.setSelected(false, animated: true)
let pdfController = annotationStateManager.pdfController as! ConstructionPDFViewController let pageSize = pdfController.document?.pageInfoForPage(at: 0)?.size pdfController.longPressedPoint = CGPoint(x: pageSize!.width / 2, y: pageSize!.height / 2) pdfController.present(pdfController.documentPickerController!, options: [.closeButton: true], animated: true, sender: nil) }}
// Hide the note icon for the pin stamp annotation.// See https://www.nutrient.io/guides/ios/annotations/customize-annotation-rendering/#customize-or-hide-the-note-icon for more details.private class PinStampAnnotation: StampAnnotation { override var shouldDrawNoteIconIfNeeded: Bool { let isPinStampAnnotation = customData?["isPinStampAnnotation"] as? Bool ?? false if isPinStampAnnotation { return false } else { return super.shouldDrawNoteIconIfNeeded } }
override class var supportsSecureCoding: Bool { true }}
This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.