Skip to content

Commit

Permalink
Merge pull request #370 from Iterable/6.2.10
Browse files Browse the repository at this point in the history
6.2.10
  • Loading branch information
roninopf committed Sep 2, 2020
2 parents 5868252 + 21593b3 commit 71230ac
Show file tree
Hide file tree
Showing 15 changed files with 891 additions and 113 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,10 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## 6.2.10
#### Added
- An option to pause automatic in-app displaying has been added. To pause, set `IterableAPI.inAppManager.isAutoDisplayPaused` to `true` (default: `false`).

## 6.2.9
#### Fixed
- In rare instances `regiserDeviceToken` API can cause crash. This should fix it.
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.9"
s.version = "6.2.10"
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.9"
s.version = "6.2.10"
s.summary = "Iterable's official SDK for iOS"

s.description = <<-DESC
Expand Down
8 changes: 8 additions & 0 deletions swift-sdk/Internal/EmptyInAppManager.swift
Expand Up @@ -16,6 +16,14 @@ class EmptyInAppManager: IterableInternalInAppManagerProtocol {
return nil
}

var isAutoDisplayPaused: Bool {
get {
false
}

set {}
}

func getMessages() -> [IterableInAppMessage] {
return []
}
Expand Down
14 changes: 7 additions & 7 deletions swift-sdk/Internal/InAppInternal.swift
Expand Up @@ -6,7 +6,6 @@
import Foundation

protocol InAppFetcherProtocol {
// Fetch from server and sync
func fetch() -> Future<[IterableInAppMessage], Error>
}

Expand All @@ -33,6 +32,10 @@ class InAppFetcher: InAppFetcherProtocol {
self.apiClient = apiClient
}

deinit {
ITBInfo()
}

func fetch() -> Future<[IterableInAppMessage], Error> {
ITBInfo()

Expand All @@ -44,13 +47,10 @@ class InAppFetcher: InAppFetcherProtocol {
return InAppHelper.getInAppMessagesFromServer(apiClient: apiClient, number: numMessages).mapFailure { $0 }
}

private weak var apiClient: ApiClientProtocol?
// MARK: - Private/Internal

deinit {
ITBInfo()
}
private weak var apiClient: ApiClientProtocol?

// how many messages to fetch
private let numMessages = 100
}

Expand All @@ -71,7 +71,7 @@ struct InAppMessageContext {
inboxSessionId: inboxSessionId)
}

// For backward compatibility, assume .inApp
/// For backward compatibility, assume .inApp
static func from(messageId: String, deviceMetadata _: DeviceMetadata) -> InAppMessageContext {
return InAppMessageContext(messageId: messageId,
saveToInbox: false,
Expand Down
147 changes: 91 additions & 56 deletions swift-sdk/Internal/InAppManager.swift
Expand Up @@ -81,16 +81,20 @@ class InAppManager: NSObject, IterableInternalInAppManagerProtocol {
notificationCenter.removeObserver(self)
}

func start() -> Future<Bool, Error> {
ITBInfo()
// MARK: - IterableInAppManagerProtocol

var isAutoDisplayPaused: Bool {
get {
autoDisplayPaused
}

if messagesMap.values.filter({ $0.saveToInbox == true }).count > 0 {
callbackQueue.async {
self.notificationCenter.post(name: .iterableInboxChanged, object: self, userInfo: nil)
set {
autoDisplayPaused = newValue

if !autoDisplayPaused {
_ = scheduleSync()
}
}

return scheduleSync()
}

func getMessages() -> [IterableInAppMessage] {
Expand All @@ -109,32 +113,6 @@ class InAppManager: NSObject, IterableInternalInAppManagerProtocol {
return getInboxMessages().filter { $0.read == false }.count
}

func createInboxMessageViewController(for message: IterableInAppMessage, withInboxMode inboxMode: IterableInboxViewController.InboxMode, inboxSessionId: String? = nil) -> UIViewController? {
guard let content = message.content as? IterableHtmlInAppContent else {
ITBError("Invalid Content in message")
return nil
}

let parameters = IterableHtmlMessageViewController.Parameters(html: content.html,
padding: content.edgeInsets,
messageMetadata: IterableInAppMessageMetadata(message: message, location: .inbox),
isModal: inboxMode == .popup,
inboxSessionId: inboxSessionId)
let createResult = IterableHtmlMessageViewController.create(parameters: parameters)
let viewController = createResult.viewController

createResult.futureClickedURL.onSuccess { url in
ITBInfo()

// in addition perform action or url delegate task
self.handle(clickedUrl: url, forMessage: message, location: .inbox)
}

viewController.navigationItem.title = message.inboxMetadata?.title

return viewController
}

func show(message: IterableInAppMessage) {
ITBInfo()

Expand All @@ -150,12 +128,6 @@ class InAppManager: NSObject, IterableInternalInAppManagerProtocol {
}
}

func remove(message: IterableInAppMessage) {
ITBInfo()

removePrivate(message: message)
}

func remove(message: IterableInAppMessage, location: InAppLocation) {
ITBInfo()

Expand Down Expand Up @@ -186,25 +158,56 @@ class InAppManager: NSObject, IterableInternalInAppManagerProtocol {
return messagesMap[id]
}

func isOkToShowNow(message: IterableInAppMessage) -> Bool {
guard message.didProcessTrigger == false else {
ITBInfo("message with id: \(message.messageId) is already processed")
return false
// MARK: - IterableInternalInAppManagerProtocol

func start() -> Future<Bool, Error> {
ITBInfo()

if messagesMap.values.filter({ $0.saveToInbox }).count > 0 {
callbackQueue.async {
self.notificationCenter.post(name: .iterableInboxChanged, object: self, userInfo: nil)
}
}

guard InAppManager.getWaitTimeInterval(fromLastTime: lastDismissedTime, currentTime: dateProvider.currentDate, gap: retryInterval) <= 0 else {
ITBInfo("can't display within retryInterval window")
return false
return scheduleSync()
}

func createInboxMessageViewController(for message: IterableInAppMessage,
withInboxMode inboxMode: IterableInboxViewController.InboxMode,
inboxSessionId: String? = nil) -> UIViewController? {
guard let content = message.content as? IterableHtmlInAppContent else {
ITBError("Invalid Content in message")
return nil
}

guard InAppManager.getWaitTimeInterval(fromLastTime: lastDisplayTime, currentTime: dateProvider.currentDate, gap: retryInterval) <= 0 else {
ITBInfo("can't display within retryInterval window")
return false
let parameters = IterableHtmlMessageViewController.Parameters(html: content.html,
padding: content.edgeInsets,
messageMetadata: IterableInAppMessageMetadata(message: message, location: .inbox),
isModal: inboxMode == .popup,
inboxSessionId: inboxSessionId)
let createResult = IterableHtmlMessageViewController.create(parameters: parameters)
let viewController = createResult.viewController

createResult.futureClickedURL.onSuccess { url in
ITBInfo()

// in addition perform action or url delegate task
self.handle(clickedUrl: url, forMessage: message, location: .inbox)
}

return true
viewController.navigationItem.title = message.inboxMetadata?.title

return viewController
}

func remove(message: IterableInAppMessage) {
ITBInfo()

removePrivate(message: message)
}

// MARK: - Private/Internal

@objc private func onAppEnteredForeground(notification _: Notification) {
ITBInfo()

Expand Down Expand Up @@ -301,14 +304,15 @@ class InAppManager: NSObject, IterableInternalInAppManagerProtocol {
case let .notShown(reason):
ITBError("Could not show message: \(reason)")
case let .shown(futureClickedURL):
// set read
ITBDebug("in-app shown")

set(read: true, forMessage: message)

updateMessage(message, didProcessTrigger: true, consumed: consume)

futureClickedURL.onSuccess { url in
ITBDebug("in-app clicked")

// call the client callback, if present
_ = callback?(url)

Expand Down Expand Up @@ -350,10 +354,11 @@ class InAppManager: NSObject, IterableInternalInAppManagerProtocol {
}
}

@discardableResult private func updateMessage(_ message: IterableInAppMessage,
read: Bool? = nil,
didProcessTrigger: Bool? = nil,
consumed: Bool? = nil) -> Future<Bool, IterableError> {
@discardableResult
private func updateMessage(_ message: IterableInAppMessage,
read: Bool? = nil,
didProcessTrigger: Bool? = nil,
consumed: Bool? = nil) -> Future<Bool, IterableError> {
ITBDebug()

let result = Promise<Bool, IterableError>()
Expand Down Expand Up @@ -478,7 +483,10 @@ class InAppManager: NSObject, IterableInternalInAppManagerProtocol {
}

// From client side
private func removePrivate(message: IterableInAppMessage, location: InAppLocation = .inApp, source: InAppDeleteSource? = nil, inboxSessionId: String? = nil) {
private func removePrivate(message: IterableInAppMessage,
location: InAppLocation = .inApp,
source: InAppDeleteSource? = nil,
inboxSessionId: String? = nil) {
ITBInfo()

updateMessage(message, didProcessTrigger: true, consumed: true)
Expand Down Expand Up @@ -545,6 +553,7 @@ class InAppManager: NSObject, IterableInternalInAppManagerProtocol {
private var syncResult: Future<Bool, Error>?
private var lastSyncTime: Date?
private let moveToForegroundSyncInterval: Double = 1.0 * 60.0 // don't sync within sixty seconds
private var autoDisplayPaused = false
}

extension InAppManager: InAppNotifiable {
Expand Down Expand Up @@ -613,3 +622,29 @@ extension InAppManager: InAppNotifiable {
return result
}
}

extension InAppManager: InAppDisplayChecker {
func isOkToShowNow(message: IterableInAppMessage) -> Bool {
guard !isAutoDisplayPaused else {
ITBInfo("automatic in-app display has been paused")
return false
}

guard !message.didProcessTrigger else {
ITBInfo("message with id: \(message.messageId) is already processed")
return false
}

guard InAppManager.getWaitTimeInterval(fromLastTime: lastDismissedTime, currentTime: dateProvider.currentDate, gap: retryInterval) <= 0 else {
ITBInfo("can't display within retryInterval window")
return false
}

guard InAppManager.getWaitTimeInterval(fromLastTime: lastDisplayTime, currentTime: dateProvider.currentDate, gap: retryInterval) <= 0 else {
ITBInfo("can't display within retryInterval window")
return false
}

return true
}
}
10 changes: 4 additions & 6 deletions swift-sdk/Internal/InAppPersistence.swift
Expand Up @@ -6,8 +6,8 @@
import Foundation
import UIKit

// This is needed because String(describing: ...) returns wrong
// value for this enum when it is exposed to Objective C
/// This is needed because String(describing: ...) returns the
/// wrong value for this enum when it is exposed to Objective-C
extension IterableInAppContentType: CustomStringConvertible {
public var description: String {
switch self {
Expand Down Expand Up @@ -36,8 +36,8 @@ extension IterableInAppContentType {
}
}

// This is needed because String(describing: ...) returns wrong
// value for this enum when it is exposed to Objective C
/// This is needed because String(describing: ...) returns the
/// wrong value for this enum when it is exposed to Objective-C
extension IterableInAppTriggerType: CustomStringConvertible {
public var description: String {
switch self {
Expand All @@ -52,7 +52,6 @@ extension IterableInAppTriggerType: CustomStringConvertible {
}

extension IterableInAppTriggerType {
// Internal
static func from(string: String) -> IterableInAppTriggerType {
switch string.lowercased() {
case String(describing: IterableInAppTriggerType.immediate).lowercased():
Expand Down Expand Up @@ -366,7 +365,6 @@ class InAppFilePersister: InAppPersistenceProtocol {
private let ext: String
}

// Files Utility class
struct FileHelper {
static func getUrl(filename: String, ext: String) -> URL? {
guard let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
Expand Down
13 changes: 9 additions & 4 deletions swift-sdk/IterableAPI.swift
Expand Up @@ -9,7 +9,7 @@ import UIKit

@objcMembers public final class IterableAPI: NSObject {
// Current SDK Version.
public static let sdkVersion = "6.2.9"
public static let sdkVersion = "6.2.10"

// MARK: Initialization

Expand All @@ -27,9 +27,14 @@ import UIKit
initialize(apiKey: apiKey, launchOptions: nil, config: config)
}

/// You should call this method and not call the init method directly.
/// - parameter apiKey: Iterable API Key.
/// - parameter launchOptions: The launchOptions coming from application:didLaunching:withOptions
/// An SDK initializer taking in the Iterable Mobile API key to be utilized and the
/// `launchOptions` passed on from the app delegate, using default SDK settings
///
/// - Parameters:
/// - apiKey: The Iterable Mobile API key to be used with the SDK
/// - launchOptions: The `launchOptions` coming from `application(_:didFinishLaunchingWithOptions:)`
///
/// - SeeAlso: IterableConfig
public static func initialize(apiKey: String,
launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
initialize(apiKey: apiKey, launchOptions: launchOptions, config: IterableConfig())
Expand Down

0 comments on commit 71230ac

Please sign in to comment.