Inlines

Overview

As of v6.0.0, the Granify SDK will support display of inline campaigns.

Inline campaigns display via views embedded in your application’s user interface. Initially, these views are hidden, but are expanded with an animation to reveal the campaign. They will usually contain a headline and a message. The below image shows an example inline campaign in the red box.

Implementation

To enable the Granify SDK to display inline campaigns you must add at least one GranifyInlineView to your app. Doing so requires the following steps:

  1. Add the parentView parameter to your Granify.trackPageView(...) calls
  2. Add the GranifyInlineView to your UI
  3. Set the expand and collapse handlers on the GranifyInlineView through GranifyInlineView.setExpandHandler(expandHandler:) and GranifyInlineView.setCollapseHandler(collapseHandler:)
  4. Set the GranifyInlineViewLabel through GranifyInlineView.setLabel(label:)

The following sections will go through these steps in greater detail

Add the parentView parameter to your trackPageView calls

Inlines require a parent UIView to be passed through Granify.trackPageView(...) in the parentView parameter. This parent view must be a superview containing all the subviews on the current page. We require this view to locate all the GranifyInlineView on the page.

Adding a GranifyInlineView to your UI

Inline campaign support requires clients to add a GranifyInlineView to every position on a page where it is desired for an inline to appear. The GranifyInlineView class extends UIView and can be added to your user interface in the same way. In the most common case, a GranifyInlineView will not initially be visible in your UI. If you are using interface builder and storyboards the easiest way to achieve this is by setting the height constraint to be 0.

The following are recommended constraints if you are using interface builder and storyboards.

  • Height constraint of 0
  • Top of the GranifyInlineView constrained to the bottom of the view above
  • Bottom of the GranifyInlineView constrained to the top of the view below

If you are adding the GranifyInlineView to a UIStackView then only the height constraint of 0 is needed

Please note that the above are only recommendations. The only requirements for an inline to be displayed in a GranifyInlineView are that they are initially 0 height and can be expanded/collapsed via a handler. Your user interface may require different constraints to meet these conditions.

Setting GranifyInlineView Expand And Collapse Handlers

As mentioned in the previous section, a GranifyInlineView will not initially be visible in your UI. As a result, Granify requires clients to pass in two handlers:

  1. An expand handler of type GranifyInlineViewExpander that will expand the GranifyInlineView allowing an inline campaign to appear. All views below the GranifyInlineView must accommodate the expansion and must be updated accordingly. The expanded height of the GranifyInlineView will be determined by Granify.
  2. A collapse handler of type GranifyInlineViewCollapser that will collapse the GranifyInlineView back to its initial state

Expand handlers are passed through GranifyInlineView.setExpandHandler(expandHandler:). Collapse handlers are passed through GranifyInlineView.setCollapseHandler(collapseHandler:). We recommend that GranifyInlineView.setExpandHandler(expandHandler:) and GranifyInlineView.setCollapseHandler(collapseHandler:) are called in viewDidLoad() of the current view controller. If handlers are not set in the GranifyInlineView, inlines cannot be displayed. The Granify SDK handles animation of the inlines internally. Do NOT add any additional animation handling.

Alternatively, if a GranifyInlineView is created programatically, these handlers can be passed in during initialization.

If you are using the recommended constraints from above, we recommend using the handlers below. However, depending on your application’s views you may need more complex handlers.

extension UIView {
    var heightConstraint: NSLayoutConstraint? {
        return constraints.first(where: {
            $0.firstAttribute == .height && $0.relation == .equal
        })
    }

    // expand handler (pass into `GranifyInlineView.setExpandHandler(expandHandler:)`)
    func expandZeroHeightConstraint(toHeight: CGFloat) {
        self.heightConstraint?.constant = toHeight
        self.frame = CGRect(x: self.frame.minX, y: self.frame.minY, width: self.frame.width, height: toHeight)
    }

    // collapse handler (pass into `GranifyInlineView.setCollapseHandler(collapseHandler:)`
    func collapseZeroHeightConstraint() {
        self.heightConstraint?.constant = 0
        self.frame = CGRect(x: self.frame.minX, y: self.frame.minY, width: self.frame.width, height: 0)
    }
}

Setting the GranifyInlineViewLabel

Additionally, a GranifyInlineViewLabel must be applied to each GranifyInlineView via GranifyInlineView.setLabel(label:).

A GranifyInlineViewLabel has three fields:

  • name: Required field. Identifies the associated GranifyInlineView. This field must be unique per location on a parent view. If a parent view containing a GranifyInlineView is reused in several places only one unique name is required.
  • productId: The ID of the associated product. Required when theGranifyInlineView is located on a product page, or on any page where it is associated with a specific product (ie. inlines associated with a cart product).
  • sku: Field that is required when the associated GranifyInlineView is associated with a specific productID/SKU combination.

For example, a GranifyInlineView located on a product page must use the name and productId parameters.

On a cart page, a GranifyInlineView not associated with any product (for example at the top of the page) would only require the name field in the GranifyInlineViewLabel. However, if the GranifyInlineView was associated with a product in the cart, then the name and productId fields would be required. The sku field would also be required if there are multiple skus for that productId. If these labels are not properly created, inline display will not work properly.

For a dynamically created GranifyInlineView, such as those in a UITableView or UICollectionView, the GranifyInlineViewLabel must be reapplied any time the view content is updated to account for recycling of the GranifyInlineView. In essence, if the contents of the superview of a GranifyInlineView change, the GranifyInlineView should be assigned a new GranifyInlineViewLabel to reflect the new content of its superview (e.g. product id, sku).

A list of names used in GranifyInlineViewLabel must be given back to a Granify Product Manager or Account Manager so that we can create campaigns targeted at those labels.

Testing your GranifyInlineView

Because a GranifyInlineView is embedded into your user interface it is imperative that they be tested extensively to make sure that expanding them does not interfere with any of your other views.

The Granify.overrideGranifyInlineView(label:) function can be used to test inline campaigns. This function takes in a JSON object specifying the details of a GranifyInlineViewLabel. Example JSON objects for a product page or cart page can be seen below.

Product Page

{ "name": "aboveProductPageProductPhoto", "product_id": <product id> }

Cart Page Inline associated with product

{ "name": "bottomOfListedProduct", "product_id": <cart product id>, "sku": <cart product sku>}

Inline not associated with a product

{ "name": "aboveCartPageTotal"}

Ideally, you would have a text box in a debug menu that calls Granify.overrideGranifyInlineView(label:) when the JSON object is input. Using this override makes any matched inline campaign appear in the GranifyInlineView with the GranifyInlineViewLabel you specified. Using this in conjunction with Granify.showConcept(conceptId:) can be used to display a specific campaign in your desired GranifyInlineView.

Inlines and Restricted States

Please note that inlines are not hidden when a restricted state is set; they persist regardless of restricted states.

Troubleshooting

  • Using Interface Builder to change a UIView to custom class GranifyInlineView results in GranifyInlineView not being found.
    • Use GFYGranifyInlineView instead of GranifyInlineView in the Custom Class -> Class field in interface builder to avoid this error.