Fetch and Display Content Cards

This tutorial explains how to fetch and display content cards in your application.

Pre-requisites

Integrate and register the AEPMessaging extension in your app.

Fetch Content Cards

To fetch the content cards for the surfaces configured in Adobe Journey Optimizer campaigns, call the updatePropositionsForSurfaces API. You should batch requests for multiple surfaces in a single API call when possible. The returned content cards are cached in-memory by the Messaging extension and persist through the application's lifecycle.

data-slots=heading, code
data-repeat=1

Swift

let homePageSurface = Surface(path: "homepage")
Messaging.updatePropositionsForSurfaces([homePageSurface])

Retrieve Content Cards

To retrieve the content cards for a specific surface, call getContentCardsUI. This API returns an array of ContentCardUI objects representing content cards for which the user is qualified.

ContentCardUI objects are created only for content cards with templates recognized by the Messaging extension. The array of ContentCardUI objects may contain multiple content card template types.

data-slots=heading, code
data-repeat=1

Swift

let homePageSurface = Surface(path: "homepage")
Messaging.getContentCardsUI(surface: homePageSurface) { result in
    switch result {
    case .success(let contentCards):
        // use the contentCards array to display content cards in your application
    case .failure(let error):
        // handle error here
    }
}
data-variant=info
data-slots=text
Note - Only content cards for which the user has qualified are returned by the getContentCardUI API. User qualification is determined by the delivery rules configured in Adobe Journey Optimizer.

Display Content Cards

To display content cards in your app, use the ContentCardUI objects returned by the getContentCardsUI API. The ContentCardUI objects provide the user interface for templated content cards in your application. Whether your application is built using SwiftUI or UIKit, you can seamlessly incorporate and display these content cards using the ContentCardUI objects.

SwiftUI Application

Below is an example of how to display content cards in a SwiftUI application:

data-slots=heading, code
data-repeat=1

Swift

struct HomePage: View {

    @State var savedCards : [ContentCardUI] = []

    var body: some View {
        ScrollView (.vertical, showsIndicators: false) {
            LazyVStack(spacing: 20) {
                 ForEach(savedCards) { card in
                     card.view
                         .frame(height: 120)
                }
            }
        }
        .padding()
        .onAppear() {
            // Retrieve the content cards for the homepage surface
            let homePageSurface = Surface(path: "homepage")
            Messaging.getContentCardsUI(for: homePageSurface) { result in
                switch result {
                case .success(let cards):
                    savedCards = cards

                case .failure(let error):
                    // handle error here
                }
            }
        }
    }
}

Refer to this TestApp for a complete example of how to display, customize and listen to UI events from content cards in a SwiftUI application.

UIKit Application

Below is an example of how to display content cards in a UIKit application using a UITableView:

data-slots=heading, code
data-repeat=1

Swift

class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet var tableView : UITableView!
    var savedCards : [ContentCardUI] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self

        // Retrieve the content cards for the homepage surface
        let homePageSurface = Surface(path: "homepage")
        Messaging.getContentCardsUI(for: homePageSurface) { result in
            switch result {
            case .success(let cards):
                self.savedCards = cards
                DispatchQueue.main.async {
                    self.tableView.reloadData()
                }

            case .failure(let error):
                // handle error here
            }
        }
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.contentView.subviews.forEach { $0.removeFromSuperview() }

        // Get the SwiftUI view for the content card
        let contentCard = savedCards[indexPath.row]
        let swiftUIView = contentCard.view

        // Wrap the SwiftUI view in a UIHostingController
        let hostingController = UIHostingController(rootView: swiftUIView)
        hostingController.view.translatesAutoresizingMaskIntoConstraints = false

        // Add the hosting controller's view to the cell's content view
        cell.contentView.addSubview(hostingController.view)

        // Set up constraints to make the SwiftUI view fill the cell
        NSLayoutConstraint.activate([
            hostingController.view.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor, constant: 10),
            hostingController.view.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor, constant: -10),
            hostingController.view.topAnchor.constraint(equalTo: cell.contentView.topAnchor, constant: 10),
            hostingController.view.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -10)
        ])

        return cell
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return savedCards.count
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 120
    }
}

Refer to this TestApp for a complete example of how to display, customize, and listen to UI events from content cards in a UIKit application.