Skip to content

Commit

Permalink
Added data action type
Browse files Browse the repository at this point in the history
  • Loading branch information
Ankmara committed Feb 2, 2024
1 parent 07be7c8 commit 71e3b2f
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 32 deletions.
23 changes: 23 additions & 0 deletions Documentation/APP_INBOX.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,26 @@ If you want to avoid to consider tracking, you may use `Exponea.shared.trackAppI
To track an invoking of action, you should use method `Exponea.shared.trackAppInboxClick(MessageItemAction, MessageItem)` with clicked message action and data.
The behaviour of `trackAppInboxClick` may be affected by the tracking consent feature, which in enabled mode considers the requirement of explicit consent for tracking. Read more in [tracking consent documentation](./TRACKING_CONSENT.md).
If you want to avoid to consider tracking, you may use `Exponea.shared.trackAppInboxClickWithoutTrackingConsent` instead. This method will do track event ignoring tracking consent state.

## Determine button action URL handling behaviour for HTML message

Button action URLs are automatically processed by SDK based on URL like: if URL starts with `http` or `https`, action type is set to `browser`, else is set to `deep-link` value. To force behaviour based on your expectation, you can specify optional attribude `data-actiontype` with following values:

* `browser` - for Web URL to open browser
* `deep-link` - for custom URL scheme and Universal Link to process it

You can do it in HTML builder by inserting the param to specific action button as described in example below:

```html
<div class="bee-block bee-block-4 bee-button">
<div data-link="https://example.com" data-actiontype="browser" style="font-size: 14px; background-color: #f84cac; border-bottom: 0px solid transparent; border-left: 0px solid transparent; border-radius: 4px; border-right: 0px solid transparent; border-top: 0px solid transparent; color: #ffffff; direction: ltr; font-family: inherit; font-weight: 700; max-width: 100%; padding-bottom: 4px; padding-left: 18px; padding-right: 18px; padding-top: 4px; width: auto; display: inline-block;" class="bee-button-content"><span style="word-break: break-word; font-size: 14px; line-height: 200%;">Action</span></div>
</div>
```

> This atrribute is also supported for `<a`, due to compatibility with Visual builder.
```html
<div class="bee-block bee-block-4 bee-button">
<a data-link="https://example.com" data-actiontype="deep-link">Click me</a>
</div>
```
35 changes: 35 additions & 0 deletions Documentation/IN_APP_CONTENT_BLOCKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,38 @@ class CustomView: UIViewController, InAppCbViewDelegate {
```

That is all, now your CustomView will receive all In-app Content Block data.

## Determine button action URL handling behaviour for HTML message

Button action URLs are automatically processed by SDK based on URL like: if URL starts with `http` or `https`, action type is set to `browser`, else is set to `deep-link` value. To force behaviour based on your expectation, you can specify optional attribude `data-actiontype` with following values:

* `browser` - for Web URL to open browser
* `deep-link` - for custom URL scheme and Universal Link to process it

You can do it in HTML builder by inserting the param to specific action button as described in example below:

```html
<div class="bee-block bee-block-4 bee-button">
<div data-link="https://example.com" data-actiontype="browser" style="font-size: 14px; background-color: #f84cac; border-bottom: 0px solid transparent; border-left: 0px solid transparent; border-radius: 4px; border-right: 0px solid transparent; border-top: 0px solid transparent; color: #ffffff; direction: ltr; font-family: inherit; font-weight: 700; max-width: 100%; padding-bottom: 4px; padding-left: 18px; padding-right: 18px; padding-top: 4px; width: auto; display: inline-block;" class="bee-button-content"><span style="word-break: break-word; font-size: 14px; line-height: 200%;">Action</span></div>
</div>
```

> This atrribute is also supported for `<a`, due to compatibility with Visual builder.
```html
<div class="bee-block bee-block-4 bee-button">
<a data-link="https://example.com" data-actiontype="deep-link">Click me</a>
</div>
```

You can do it in Visual builder as well as described in example below:

Steps:

1) Click on the button you want to setup a URL
2) On the right side in editor scroll down
3) Under "Attributes" section click on `ADD NEW ATTRIBUTE`
4) Select `data-actiontype`
5) Insert a value ( `browser` or `deep-link`)

![Screenshot](/ExponeaSDK/Example/Resources/beefree-actiontype.png)
35 changes: 35 additions & 0 deletions Documentation/IN_APP_MESSAGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,38 @@ Method `trackInAppMessageClose` will track a 'close' event with 'interaction' fi
> The behaviour of `trackInAppMessageClick` and `trackInAppMessageClose` may be affected by the tracking consent feature, which in enabled mode considers the requirement of explicit consent for tracking. Read more in [tracking consent documentation](./TRACKING_CONSENT.md).
> Note: Invoking of `Exponea.anonymize` does fetch In-apps immediately but `Exponea.identifyCustomer` needs to be sent to backend successfully. The reason is to register customer IDs on backend properly to correctly assign an In-app messages. If you have set other then `Exponea.flushMode = FlushMode.IMMEDIATE` you need to call `Exponea.flushData()` to finalize `identifyCustomer` process and trigger a In-app messages fetch.
## Determine button action URL handling behaviour for HTML message

Button action URLs are automatically processed by SDK based on URL like: if URL starts with `http` or `https`, action type is set to `browser`, else is set to `deep-link` value. To force behaviour based on your expectation, you can specify optional attribude `data-actiontype` with following values:

* `browser` - for Web URL to open browser
* `deep-link` - for custom URL scheme and Universal Link to process it

You can do it in HTML builder by inserting the param to specific action button as described in example below:

```html
<div class="bee-block bee-block-4 bee-button">
<div data-link="https://example.com" data-actiontype="browser" style="font-size: 14px; background-color: #f84cac; border-bottom: 0px solid transparent; border-left: 0px solid transparent; border-radius: 4px; border-right: 0px solid transparent; border-top: 0px solid transparent; color: #ffffff; direction: ltr; font-family: inherit; font-weight: 700; max-width: 100%; padding-bottom: 4px; padding-left: 18px; padding-right: 18px; padding-top: 4px; width: auto; display: inline-block;" class="bee-button-content"><span style="word-break: break-word; font-size: 14px; line-height: 200%;">Action</span></div>
</div>
```

> This atrribute is also supported for `<a`, due to compatibility with Visual builder.
```html
<div class="bee-block bee-block-4 bee-button">
<a data-link="https://example.com" data-actiontype="deep-link">Click me</a>
</div>
```

You can do it in Visual builder as well as described in example below:

Steps:

1) Click on the button you want to setup a URL
2) On the right side in editor scroll down
3) Under "Attributes" section click on `ADD NEW ATTRIBUTE`
4) Select `data-actiontype`
5) Insert a value ( `browser` or `deep-link`)

![Screenshot](/ExponeaSDK/Example/Resources/beefree-actiontype.png)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions ExponeaSDK/ExponeaSDK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@
05FEBDC023A7BA2A007C2372 /* InAppMessageTrackingDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05FEBDBF23A7BA2A007C2372 /* InAppMessageTrackingDelegate.swift */; };
05FEBDC223A7C940007C2372 /* MockInAppMessageTrackingDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05FEBDC123A7C940007C2372 /* MockInAppMessageTrackingDelegate.swift */; };
23E725E4214AA7A900B552B8 /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23E725E3214AA7A900B552B8 /* Reachability.swift */; };
315DCDFF2B6A67E9004BD7A7 /* beefree-actiontype.png in Resources */ = {isa = PBXBuildFile; fileRef = 315DCDFE2B6A67E9004BD7A7 /* beefree-actiontype.png */; };
318B552A2A80E52B00934902 /* DeeplinkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318B55292A80E52B00934902 /* DeeplinkManager.swift */; };
31C7B4242A822848001BA5E2 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C7B4232A822848001BA5E2 /* Coordinator.swift */; };
31C7B4262A822FE7001BA5E2 /* ExponeaTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C7B4252A822FE7001BA5E2 /* ExponeaTabBarController.swift */; };
Expand Down Expand Up @@ -709,6 +710,7 @@
05FEBDBF23A7BA2A007C2372 /* InAppMessageTrackingDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppMessageTrackingDelegate.swift; sourceTree = "<group>"; };
05FEBDC123A7C940007C2372 /* MockInAppMessageTrackingDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockInAppMessageTrackingDelegate.swift; sourceTree = "<group>"; };
23E725E3214AA7A900B552B8 /* Reachability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reachability.swift; sourceTree = "<group>"; };
315DCDFE2B6A67E9004BD7A7 /* beefree-actiontype.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "beefree-actiontype.png"; sourceTree = "<group>"; };
318B55292A80E52B00934902 /* DeeplinkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeeplinkManager.swift; sourceTree = "<group>"; };
31C7B4232A822848001BA5E2 /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; };
31C7B4252A822FE7001BA5E2 /* ExponeaTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExponeaTabBarController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1749,6 +1751,7 @@
C0EA5FCD20CE95EE00660802 /* Resources */ = {
isa = PBXGroup;
children = (
315DCDFE2B6A67E9004BD7A7 /* beefree-actiontype.png */,
C0F6C4E92098A1AC00834E21 /* Assets.xcassets */,
C0F6C4EE2098A1AC00834E21 /* Info.plist */,
C0F6C4EB2098A1AC00834E21 /* LaunchScreen.storyboard */,
Expand Down Expand Up @@ -2534,6 +2537,7 @@
files = (
55EFD79B292245A5002569FB /* Localizable.strings in Resources */,
C0F6C4ED2098A1AC00834E21 /* LaunchScreen.storyboard in Resources */,
315DCDFF2B6A67E9004BD7A7 /* beefree-actiontype.png in Resources */,
C03B23D421AAF34000360EE6 /* beep.wav in Resources */,
C0F6C4EA2098A1AC00834E21 /* Assets.xcassets in Resources */,
C0F6C4E82098A1AB00834E21 /* Main.storyboard in Resources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,20 @@ public final class StaticInAppContentBlockView: UIView, WKNavigationDelegate {
}

private func determineActionType(_ action: ActionInfo) -> InAppContentBlockActionType {
if action.actionUrl == "https://exponea.com/close_action" {
return .close
}
if action.actionUrl.starts(with: "http://") || action.actionUrl.starts(with: "https://") {
switch action.actionType {
case .browser:
return .browser
case .deeplink:
return .deeplink
case .unknown:
if action.actionUrl == "https://exponea.com/close_action" {
return .close
}
if action.actionUrl.starts(with: "http://") || action.actionUrl.starts(with: "https://") {
return .browser
}
return .deeplink
}
return .deeplink
}

// directly calls `contentReadyCompletion` with given contentReady flag
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ final class InAppMessageWebView: UIView, InAppMessageView {
private var inAppContentBlocksManager: InAppContentBlocksManagerType = InAppContentBlocksManager.manager

var normalizedPayload: NormalizedResult?

var actionManager: WebActionManager?

required init(
Expand Down Expand Up @@ -133,17 +133,24 @@ final class InAppMessageWebView: UIView, InAppMessageView {
private func toPayloadButton(_ action: ActionInfo) -> InAppMessagePayloadButton {
InAppMessagePayloadButton(
buttonText: action.buttonText,
rawButtonType: detectActionType(action.actionUrl.cleanedURL()!).rawValue,
rawButtonType: detectActionType(action).rawValue,
buttonLink: action.actionUrl,
buttonTextColor: nil,
buttonBackgroundColor: nil
)
}

private func detectActionType(_ url: URL) -> InAppMessageButtonType {
if url.scheme == "http" || url.scheme == "https" {
private func detectActionType(_ action: ActionInfo) -> InAppMessageButtonType {
switch action.actionType {
case .browser:
return .browser
case .deeplink:
return .deeplink
case .unknown:
if action.actionUrl.cleanedURL()!.scheme == "http" || action.actionUrl.cleanedURL()!.scheme == "https" {
return .browser
}
return .deeplink
}
return .deeplink
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,5 @@ public struct InAppMessagePayloadButton: Codable, Equatable {
public enum InAppMessageButtonType: String {
case cancel
case deeplink = "deep-link"
case browser = "browser"
case browser
}
43 changes: 39 additions & 4 deletions ExponeaSDK/ExponeaSDK/Classes/Others/HtmlNormalizer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class HtmlNormalizer {
private let closeButtonAttrDef = "data-actiontype='close'"
private let closeButtonSelector = "[data-actiontype='close']"
private let actionButtonAttr = "data-link"
private let dataLinkTypeAttr = "data-actiontype"
private let datalinkButtonSelector = "[data-link]"
private let anchorlinkButtonSelector = "a[href]"

Expand Down Expand Up @@ -132,16 +133,31 @@ public class HtmlNormalizer {

private func ensureActionButtons() throws -> [ActionInfo] {
var result: [String: ActionInfo] = [:]

guard let document = document else {
Exponea.logger.log(.warning, message: "[HTML] Document has not been initialized, no Action buttons")
return []
}
// collect 'data-link' first as it may update href
try collectDataLinkButtons(document).forEach { action in
result[action.actionUrl] = action
var existingResult = result[action.actionUrl]
if existingResult == nil {
result[action.actionUrl] = ActionInfo(buttonText: action.buttonText, actionUrl: action.actionUrl, actionType: action.actionType)
} else {
existingResult?.actionUrl = action.actionUrl
existingResult?.buttonText = action.buttonText
result[action.actionUrl] = existingResult
}
}
try collectAnchorLinkButtons(document).forEach { action in
result[action.actionUrl] = action
var existingResult = result[action.actionUrl]
if existingResult == nil {
result[action.actionUrl] = ActionInfo(buttonText: action.buttonText, actionUrl: action.actionUrl, actionType: action.actionType)
} else {
existingResult?.actionUrl = action.actionUrl
existingResult?.buttonText = action.buttonText
result[action.actionUrl] = existingResult
}
}
return Array(result.values)
}
Expand All @@ -151,11 +167,12 @@ public class HtmlNormalizer {
let anchorlinkButtons = try document.select(anchorlinkButtonSelector)
for actionButton in anchorlinkButtons.array() {
let targetAction = try actionButton.attr(hrefAttr)
let actionType: ActionType = .init(try actionButton.attr(dataLinkTypeAttr))
if targetAction.isEmpty {
Exponea.logger.log(.error, message: "[HTML] Action button found but with empty action")
continue
}
result.append(ActionInfo(buttonText: try actionButton.text(), actionUrl: targetAction))
result.append(ActionInfo(buttonText: try actionButton.text(), actionUrl: targetAction, actionType: actionType))
}
return result
}
Expand All @@ -165,6 +182,7 @@ public class HtmlNormalizer {
let datalinkButtons = try document.select(datalinkButtonSelector)
for actionButton in datalinkButtons.array() {
let targetAction = try actionButton.attr(actionButtonAttr)
let dataLinkType: ActionType = .init(try actionButton.attr(dataLinkTypeAttr))
if targetAction.isEmpty {
Exponea.logger.log(.error, message: "[HTML] Action button found but with empty action")
continue
Expand All @@ -184,7 +202,7 @@ public class HtmlNormalizer {
""")
try actionButton.wrap("<a href='\(targetAction)' class='\(actionButtonHrefClass)'></a>")
}
result.append(ActionInfo(buttonText: try actionButton.text(), actionUrl: targetAction))
result.append(ActionInfo(buttonText: try actionButton.text(), actionUrl: targetAction, actionType: dataLinkType))
}
return result
}
Expand Down Expand Up @@ -555,6 +573,23 @@ public struct NormalizedResult {
public struct ActionInfo {
public var buttonText: String
public var actionUrl: String
public var actionType: ActionType

public init(buttonText: String, actionUrl: String, actionType: ActionType = .unknown) {
self.buttonText = buttonText
self.actionUrl = actionUrl
self.actionType = actionType
}
}

public enum ActionType: String {
case unknown
case deeplink = "deep-link"
case browser

init(_ type: String) {
self = .init(rawValue: type) ?? .unknown
}
}

public struct HtmlNormalizerConfig {
Expand Down
Loading

0 comments on commit 71e3b2f

Please sign in to comment.