Skip to content

Commit

Permalink
Merge pull request #475 from Iterable/next-version
Browse files Browse the repository at this point in the history
[MOB-2775] SDK version 6.2.22
  • Loading branch information
roninopf committed Apr 30, 2021
2 parents 118fd9e + 59b8ece commit ee0eb49
Show file tree
Hide file tree
Showing 23 changed files with 464 additions and 155 deletions.
15 changes: 0 additions & 15 deletions .travis.yml

This file was deleted.

13 changes: 13 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,19 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## 6.2.22
#### Added
- In-app message prioritization - Ordering the display of in-app messages based on a priority you select in Iterable when creating in-app campaigns

#### Fixed
- The authentication flow, with JWT, now does the proper order of operations to avoid a false negative when setting the user (with `setEmail` or `setUser`)
- The empty inbox message will now properly wraparound
- An inbox message that has its read state changed will now only animate the unread dot

#### Removed
- Removed device fingerprinting as a cautionary measure for iOS 14.5 policy updates - note: we still keep the system generated UUID
- Removed deferred deep linking feature

## 6.2.21
#### Added
- Support for syncing in-app message read state across multiple devices:
Expand Down
2 changes: 1 addition & 1 deletion Iterable-iOS-AppExtensions.podspec
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = "Iterable-iOS-AppExtensions"
s.module_name = "IterableAppExtensions"
s.version = "6.2.21"
s.version = "6.2.22"
s.summary = "App Extensions for Iterable SDK"

s.description = <<-DESC
Expand Down
2 changes: 1 addition & 1 deletion Iterable-iOS-SDK.podspec
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = "Iterable-iOS-SDK"
s.module_name = "IterableSDK"
s.version = "6.2.21"
s.version = "6.2.22"
s.summary = "Iterable's official SDK for iOS"

s.description = <<-DESC
Expand Down
16 changes: 6 additions & 10 deletions swift-sdk.xcodeproj/project.pbxproj
Expand Up @@ -16,6 +16,7 @@
5531CDAE22A9C992000D05E2 /* ClassExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5531CDAD22A9C992000D05E2 /* ClassExtensionsTests.swift */; };
5536781F2576FF9000DB3652 /* IterableUtilTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5536781E2576FF9000DB3652 /* IterableUtilTests.swift */; };
556FB1EA244FAF6A00EDF6BD /* InAppPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 556FB1E9244FAF6A00EDF6BD /* InAppPresenter.swift */; };
55705A6925A78BF3009BDEE2 /* InAppPriorityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55705A6825A78BF3009BDEE2 /* InAppPriorityTests.swift */; };
557AE6BF24A56E5E00B57750 /* Auth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557AE6BE24A56E5E00B57750 /* Auth.swift */; };
5585DF8F22A73390000A32B9 /* IterableInboxViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5585DF8E22A73390000A32B9 /* IterableInboxViewControllerTests.swift */; };
55AEA95925F05B7D00B38CED /* InAppMessageProcessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55AEA95825F05B7D00B38CED /* InAppMessageProcessorTests.swift */; };
Expand Down Expand Up @@ -363,6 +364,7 @@
5531CDAD22A9C992000D05E2 /* ClassExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClassExtensionsTests.swift; sourceTree = "<group>"; };
5536781E2576FF9000DB3652 /* IterableUtilTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IterableUtilTests.swift; sourceTree = "<group>"; };
556FB1E9244FAF6A00EDF6BD /* InAppPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppPresenter.swift; sourceTree = "<group>"; };
55705A6825A78BF3009BDEE2 /* InAppPriorityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = InAppPriorityTests.swift; path = "tests/swift-sdk-swift-tests/InAppPriorityTests.swift"; sourceTree = SOURCE_ROOT; };
557AE6BE24A56E5E00B57750 /* Auth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Auth.swift; sourceTree = "<group>"; };
5585DF8E22A73390000A32B9 /* IterableInboxViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IterableInboxViewControllerTests.swift; sourceTree = "<group>"; };
5585DF9022A877E6000A32B9 /* IterableInboxViewControllerUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IterableInboxViewControllerUITests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -676,13 +678,6 @@
path = "swift-sdk/misc";
sourceTree = "<group>";
};
55A8F6E92613E0B800184ECC /* Recovered References */ = {
isa = PBXGroup;
children = (
);
name = "Recovered References";
sourceTree = "<group>";
};
AC0248062279132400495FB9 /* Dwifft */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -739,7 +734,6 @@
ACDA975A23159C37004C412E /* inbox-ui-tests-app */,
ACFCA72920EB02DB00BFB277 /* tests */,
5550F22324217CFC0014456A /* misc */,
55A8F6E92613E0B800184ECC /* Recovered References */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -961,13 +955,14 @@
55B37FC0229620D20042F13A /* CommerceItemTests.swift */,
55E6F45E238E066400808BCE /* DeepLinkTests.swift */,
551E5C0F234D485A005FEE9E /* DeprecatedFunctionsTests.swift */,
AC750A49234CD67900561902 /* InAppHelperTests.swift */,
55AEA95825F05B7D00B38CED /* InAppMessageProcessorTests.swift */,
ACC3FD9D2536D7A30004A2E0 /* InAppFilePersistenceTests.swift */,
AC750A49234CD67900561902 /* InAppHelperTests.swift */,
AC6FDD8B20F56309005D811E /* InAppParsingTests.swift */,
55B37FED229F59290042F13A /* InAppPersistenceTests.swift */,
55CC257A2462064F00A77FD5 /* InAppPresenterTests.swift */,
55705A6825A78BF3009BDEE2 /* InAppPriorityTests.swift */,
ACA8D1A821965B7D001B1332 /* InAppTests.swift */,
ACC3FD9D2536D7A30004A2E0 /* InAppFilePersistenceTests.swift */,
55B549852397462300243E87 /* InboxImpressionTrackerTests.swift */,
55B37FC722975A840042F13A /* InboxMessageViewModelTests.swift */,
55B5498323973B5C00243E87 /* InboxSessionManagerTests.swift */,
Expand Down Expand Up @@ -1767,6 +1762,7 @@
AC89661E2124FBCE0051A6CD /* IterableAutoRegistrationTests.swift in Sources */,
ACA8D1A921965B7D001B1332 /* InAppTests.swift in Sources */,
00B6FACC210E8484007535CF /* APNSTypeCheckerTests.swift in Sources */,
55705A6925A78BF3009BDEE2 /* InAppPriorityTests.swift in Sources */,
AC8F35A2239806B500302994 /* InboxViewControllerViewModelTests.swift in Sources */,
AC995F9A2166EEB50099A184 /* CommonMocks.swift in Sources */,
5585DF8F22A73390000A32B9 /* IterableInboxViewControllerTests.swift in Sources */,
Expand Down
10 changes: 10 additions & 0 deletions swift-sdk/Constants.swift
Expand Up @@ -56,6 +56,15 @@ public enum Const {
static let payloadExpiration = 24
static let attributionInfoExpiration = 24
}

enum PriorityLevel {
static let critical = 100.0
static let high = 200.0
static let medium = 300.0
static let low = 400.0

static let unassigned = 300.5
}
}

public protocol JsonKeyValueRepresentable {
Expand Down Expand Up @@ -106,6 +115,7 @@ public enum JsonKey: String, JsonKeyRepresentable {
case inAppLocation = "location"
case clickedUrl
case read
case priorityLevel

case inboxSessionStart
case inboxSessionEnd
Expand Down
4 changes: 2 additions & 2 deletions swift-sdk/Internal/AuthManager.swift
Expand Up @@ -102,11 +102,11 @@ class AuthManager: IterableInternalAuthManagerProtocol {

storeAuthToken()

queueAuthTokenExpirationRefresh(authToken)

if authToken != nil {
onSuccess?(authToken)
}

queueAuthTokenExpirationRefresh(authToken)
}

private func queueAuthTokenExpirationRefresh(_ authToken: String?) {
Expand Down
5 changes: 4 additions & 1 deletion swift-sdk/Internal/InAppManager+Functions.swift
Expand Up @@ -70,7 +70,10 @@ struct MessagesProcessor {
}

private func getFirstProcessableTriggeredMessage() -> IterableInAppMessage? {
messagesMap.values.filter(MessagesProcessor.isProcessableTriggeredMessage).first
messagesMap.values
.filter(MessagesProcessor.isProcessableTriggeredMessage)
.sorted { $0.priorityLevel < $1.priorityLevel }
.first
}

private static func isProcessableTriggeredMessage(_ message: IterableInAppMessage) -> Bool {
Expand Down
4 changes: 2 additions & 2 deletions swift-sdk/Internal/InAppManager.swift
Expand Up @@ -220,7 +220,7 @@ class InAppManager: NSObject, IterableInternalInAppManagerProtocol {
.map { self.processMergedMessages(appIsReady: appIsReady, mergeMessagesResult: $0) }
}

// messages are new messages coming from the server
/// `messages` are new messages coming from the server
private func mergeMessages(_ messages: [IterableInAppMessage]) -> MergeMessagesResult {
MessagesObtainedHandler(messagesMap: messagesMap, messages: messages).handle()
}
Expand All @@ -232,7 +232,7 @@ class InAppManager: NSObject, IterableInternalInAppManagerProtocol {
messagesMap = mergeMessagesResult.messagesMap
}

// track in app delivery
// track in-app delivery
mergeMessagesResult.deliveredMessages.forEach {
_ = apiClient?.track(inAppDelivery: InAppMessageContext.from(message: $0, location: nil))
}
Expand Down
4 changes: 3 additions & 1 deletion swift-sdk/Internal/InAppMessageParser.swift
Expand Up @@ -104,6 +104,7 @@ struct InAppMessageParser {
let createdAt = parseTime(withKey: .inboxCreatedAt, fromJson: json)
let expiresAt = parseTime(withKey: .inboxExpiresAt, fromJson: json)
let read = json[JsonKey.read.jsonKey] as? Bool ?? false
let priorityLevel = json[JsonKey.priorityLevel.jsonKey] as? Double ?? Const.PriorityLevel.unassigned

return .success(IterableInAppMessage(messageId: messageId,
campaignId: campaignId,
Expand All @@ -114,7 +115,8 @@ struct InAppMessageParser {
saveToInbox: saveToInbox,
inboxMetadata: inboxMetadata,
customPayload: customPayload,
read: read))
read: read,
priorityLevel: priorityLevel))
}

private static func parseTime(withKey key: JsonKey, fromJson json: [AnyHashable: Any]) -> Date? {
Expand Down
6 changes: 5 additions & 1 deletion swift-sdk/Internal/InAppPersistence.swift
Expand Up @@ -235,6 +235,7 @@ extension IterableInAppMessage: Codable {
case read
case trigger
case content
case priorityLevel
}

enum ContentCodingKeys: String, CodingKey {
Expand Down Expand Up @@ -266,6 +267,7 @@ extension IterableInAppMessage: Codable {

let trigger = (try? container.decode(IterableInAppTrigger.self, forKey: .trigger)) ?? .undefinedTrigger
let content = IterableInAppMessage.decodeContent(from: container)
let priorityLevel = (try? container.decode(Double.self, forKey: .priorityLevel)) ?? Const.PriorityLevel.unassigned

self.init(messageId: messageId,
campaignId: campaignId,
Expand All @@ -276,7 +278,8 @@ extension IterableInAppMessage: Codable {
saveToInbox: saveToInbox,
inboxMetadata: inboxMetadata,
customPayload: customPayload,
read: read)
read: read,
priorityLevel: priorityLevel)

self.didProcessTrigger = didProcessTrigger
self.consumed = consumed
Expand All @@ -295,6 +298,7 @@ extension IterableInAppMessage: Codable {
try? container.encode(didProcessTrigger, forKey: .didProcessTrigger)
try? container.encode(consumed, forKey: .consumed)
try? container.encode(read, forKey: .read)
try? container.encode(priorityLevel, forKey: .priorityLevel)

if let inboxMetadata = inboxMetadata {
try? container.encode(inboxMetadata, forKey: .inboxMetadata)
Expand Down
55 changes: 51 additions & 4 deletions swift-sdk/Internal/InboxViewControllerViewModel.swift
Expand Up @@ -6,9 +6,18 @@
import Foundation
import UIKit

enum RowDiff {
case insert(IndexPath)
case delete(IndexPath)
case update(IndexPath)
case sectionInsert(IndexSet)
case sectionDelete(IndexSet)
case sectionUpdate(IndexSet)
}

protocol InboxViewControllerViewModelView: AnyObject {
// All these methods should be called on the main thread
func onViewModelChanged(diff: [SectionedDiffStep<Int, InboxMessageViewModel>])
func onViewModelChanged(diffs: [RowDiff])
func onImageLoaded(for indexPath: IndexPath)
var currentlyVisibleRowIndexPaths: [IndexPath] { get }
}
Expand Down Expand Up @@ -239,13 +248,51 @@ class InboxViewControllerViewModel: InboxViewControllerViewModelProtocol {
ITBInfo()
newSectionedMessages = sortAndFilter(messages: getMessages())

let diff = Dwifft.diff(lhs: sectionedMessages, rhs: newSectionedMessages)
if diff.count > 0 {
view?.onViewModelChanged(diff: diff)
let dwifftDiffs = Dwifft.diff(lhs: sectionedMessages, rhs: newSectionedMessages)
if dwifftDiffs.count > 0 {
let rowDiffs = Self.dwifftDiffsToRowDiffs(dwifftDiffs: dwifftDiffs)
view?.onViewModelChanged(diffs: rowDiffs)
updateVisibleRows()
}
}

private static func dwifftDiffsToRowDiffs(dwifftDiffs: [SectionedDiffStep<Int, InboxMessageViewModel>]) -> [RowDiff] {
var result = [RowDiff]()
var rowDeletes = [IndexPath: Int]()
var sectionDeletes = [Int: Int]()

for (pos, dwiffDiff) in dwifftDiffs.enumerated() {
switch dwiffDiff {
case let .delete(section, row, _):
let indexPath = IndexPath(row: row, section: section)
result.append(.delete(indexPath))
rowDeletes[indexPath] = pos
case let .insert(section, row, _):
let indexPath = IndexPath(row: row, section: section)
if let pos = rowDeletes[indexPath] {
result.remove(at: pos)
rowDeletes.removeValue(forKey: indexPath)
result.append(.update(indexPath))
} else {
result.append(.insert(indexPath))
}
case let .sectionDelete(section, _):
result.append(.sectionDelete(IndexSet(integer: section)))
sectionDeletes[section] = pos
case let .sectionInsert(section, _):
if let pos = sectionDeletes[section] {
result.remove(at: pos)
sectionDeletes.removeValue(forKey: section)
result.append(.sectionUpdate(IndexSet(integer: section)))
} else {
result.append(.sectionInsert(IndexSet(integer: section)))
}
}
}

return result
}

@objc private func onAppWillEnterForeground(notification _: NSNotification) {
ITBInfo()
if sessionManager.startSessionWhenAppMovesToForeground {
Expand Down

0 comments on commit ee0eb49

Please sign in to comment.