Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f6590001df |
@@ -256,24 +256,24 @@
|
||||
attributes = {
|
||||
LastSwiftMigration = 0700;
|
||||
LastSwiftUpdateCheck = 0730;
|
||||
LastUpgradeCheck = 0820;
|
||||
LastUpgradeCheck = 0900;
|
||||
ORGANIZATIONNAME = "Sabintsev iOS Projects";
|
||||
TargetAttributes = {
|
||||
55EC36461E6BB98A00726F13 = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
LastSwiftMigration = 0820;
|
||||
LastSwiftMigration = 0900;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
8E3A6C031D07CB6F00A8B7CF = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 0800;
|
||||
LastSwiftMigration = 0900;
|
||||
TestTargetID = 8EC391801A58B465001C121E;
|
||||
};
|
||||
8EC391801A58B465001C121E = {
|
||||
CreatedOnToolsVersion = 6.1.1;
|
||||
DevelopmentTeam = HT94948NDD;
|
||||
DevelopmentTeamName = "Arthur Sabintsev";
|
||||
LastSwiftMigration = 0800;
|
||||
LastSwiftMigration = 0900;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -432,7 +432,7 @@
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
@@ -461,7 +461,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
@@ -480,7 +480,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.sabintsev.SirenTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SirenExample.app/SirenExample";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -499,7 +499,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.sabintsev.SirenTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SirenExample.app/SirenExample";
|
||||
};
|
||||
name = Release;
|
||||
@@ -512,14 +512,20 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -558,14 +564,20 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -598,7 +610,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.apple.itunesconnect.mobile;
|
||||
PRODUCT_NAME = SirenExample;
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -613,7 +625,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.apple.itunesconnect.mobile;
|
||||
PRODUCT_NAME = SirenExample;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0820"
|
||||
LastUpgradeVersion = "0900"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@@ -36,6 +37,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0820"
|
||||
LastUpgradeVersion = "0900"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
@@ -55,6 +56,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
@@ -22,7 +22,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
return true
|
||||
}
|
||||
|
||||
func setupSiren() {
|
||||
@objc func setupSiren() {
|
||||
let siren = Siren.shared
|
||||
|
||||
// Optional
|
||||
@@ -75,28 +75,28 @@ extension AppDelegate: SirenDelegate
|
||||
print(#function, alertType)
|
||||
}
|
||||
|
||||
func sirenUserDidCancel() {
|
||||
@objc func sirenUserDidCancel() {
|
||||
print(#function)
|
||||
}
|
||||
|
||||
func sirenUserDidSkipVersion() {
|
||||
@objc func sirenUserDidSkipVersion() {
|
||||
print(#function)
|
||||
}
|
||||
|
||||
func sirenUserDidLaunchAppStore() {
|
||||
@objc func sirenUserDidLaunchAppStore() {
|
||||
print(#function)
|
||||
}
|
||||
|
||||
func sirenDidFailVersionCheck(error: NSError) {
|
||||
@objc func sirenDidFailVersionCheck(error: NSError) {
|
||||
print(#function, error)
|
||||
}
|
||||
|
||||
func sirenLatestVersionInstalled() {
|
||||
@objc func sirenLatestVersionInstalled() {
|
||||
print(#function, "Latest version of app is installed")
|
||||
}
|
||||
|
||||
// This delegate method is only hit when alertType is initialized to .none
|
||||
func sirenDidDetectNewVersionWithoutAlert(message: String) {
|
||||
@objc func sirenDidDetectNewVersionWithoutAlert(message: String) {
|
||||
print(#function, "\(message)")
|
||||
}
|
||||
}
|
||||
|
||||
+18
-18
@@ -14,12 +14,12 @@ import UIKit
|
||||
public final class Siren: NSObject {
|
||||
|
||||
/// Current installed version of your app.
|
||||
internal var currentInstalledVersion: String? = {
|
||||
@objc internal var currentInstalledVersion: String? = {
|
||||
return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
|
||||
}()
|
||||
|
||||
/// The error domain for all errors created by Siren.
|
||||
public let SirenErrorDomain = "Siren Error Domain"
|
||||
@objc public let SirenErrorDomain = "Siren Error Domain"
|
||||
|
||||
/// The SirenDelegate variable, which should be set if you'd like to be notified:
|
||||
///
|
||||
@@ -35,7 +35,7 @@ public final class Siren: NSObject {
|
||||
|
||||
/// The debug flag, which is disabled by default.
|
||||
/// When enabled, a stream of print() statements are logged to your console when a version check is performed.
|
||||
public lazy var debugEnabled = false
|
||||
@objc public lazy var debugEnabled = false
|
||||
|
||||
/// Determines the type of alert that should be shown.
|
||||
/// See the Siren.AlertType enum for full details.
|
||||
@@ -70,36 +70,36 @@ public final class Siren: NSObject {
|
||||
|
||||
/// The name of your app.
|
||||
/// By default, it's set to the name of the app that's stored in your plist.
|
||||
public lazy var appName: String = Bundle.main.bestMatchingAppName()
|
||||
@objc public lazy var appName: String = Bundle.main.bestMatchingAppName()
|
||||
|
||||
/// The region or country of an App Store in which your app is available.
|
||||
/// By default, all version checks are performed against the US App Store.
|
||||
/// If your app is not available in the US App Store, set it to the identifier of at least one App Store within which it is available.
|
||||
public var countryCode: String?
|
||||
@objc public var countryCode: String?
|
||||
|
||||
/// Overrides the default localization of a user's device when presenting the update message and button titles in the alert.
|
||||
/// See the Siren.LanguageType enum for more details.
|
||||
public var forceLanguageLocalization: Siren.LanguageType?
|
||||
|
||||
/// Overrides the tint color for UIAlertController.
|
||||
public var alertControllerTintColor: UIColor?
|
||||
@objc public var alertControllerTintColor: UIColor?
|
||||
|
||||
/// When this is set, the alert will only show up if the current version has already been released for X days
|
||||
/// Defaults to 1 day to avoid an issue where Apple updates the JSON faster than the app binary propogates to the App Store.
|
||||
public var showAlertAfterCurrentVersionHasBeenReleasedForDays: Int = 1
|
||||
@objc public var showAlertAfterCurrentVersionHasBeenReleasedForDays: Int = 1
|
||||
|
||||
/// The current version of your app that is available for download on the App Store
|
||||
public internal(set) var currentAppStoreVersion: String?
|
||||
@objc public internal(set) var currentAppStoreVersion: String?
|
||||
|
||||
internal var updaterWindow: UIWindow?
|
||||
@objc internal var updaterWindow: UIWindow?
|
||||
fileprivate var appID: Int?
|
||||
fileprivate var lastVersionCheckPerformedOnDate: Date?
|
||||
fileprivate lazy var alertViewIsVisible: Bool = false
|
||||
|
||||
/// The App's Singleton
|
||||
public static let shared = Siren()
|
||||
@objc public static let shared = Siren()
|
||||
|
||||
@available(*, deprecated: 1.2.0, unavailable, renamed: "shared")
|
||||
@objc @available(*, deprecated: 1.2.0, unavailable, renamed: "shared")
|
||||
public static let sharedInstance = Siren()
|
||||
|
||||
override init() {
|
||||
@@ -138,7 +138,7 @@ public final class Siren: NSObject {
|
||||
///
|
||||
/// - User clicked the `Update` button in the UIAlertController modal.
|
||||
/// - Developer built a custom alert modal and needs to be able to call this function when the user chooses to update the app in the aforementioned custom modal.
|
||||
public func launchAppStore() {
|
||||
@objc public func launchAppStore() {
|
||||
guard let appID = appID,
|
||||
let iTunesURL = URL(string: "https://itunes.apple.com/app/id\(appID)") else {
|
||||
return
|
||||
@@ -291,7 +291,7 @@ private extension Siren {
|
||||
}
|
||||
|
||||
func showAlert() {
|
||||
let updateAvailableMessage = Bundle().localizedString(stringKey: "Update Available", forceLanguageLocalization: forceLanguageLocalization)
|
||||
let updateAvailableMessage = Bundle.localizedString(stringKey: "Update Available", forceLanguageLocalization: forceLanguageLocalization)
|
||||
let newVersionMessage = localizedNewVersionMessage()
|
||||
|
||||
let alertController = UIAlertController(title: updateAvailableMessage, message: newVersionMessage, preferredStyle: .alert)
|
||||
@@ -396,7 +396,7 @@ private extension Siren {
|
||||
private extension Siren {
|
||||
func localizedNewVersionMessage() -> String {
|
||||
let newVersionMessageToLocalize = "A new version of %@ is available. Please update to version %@ now."
|
||||
let newVersionMessage = Bundle().localizedString(stringKey: newVersionMessageToLocalize, forceLanguageLocalization: forceLanguageLocalization)
|
||||
let newVersionMessage = Bundle.localizedString(stringKey: newVersionMessageToLocalize, forceLanguageLocalization: forceLanguageLocalization)
|
||||
|
||||
guard let currentAppStoreVersion = currentAppStoreVersion else {
|
||||
return String(format: newVersionMessage, appName, "Unknown")
|
||||
@@ -406,22 +406,22 @@ private extension Siren {
|
||||
}
|
||||
|
||||
func localizedUpdateButtonTitle() -> String {
|
||||
return Bundle().localizedString(stringKey: "Update", forceLanguageLocalization: forceLanguageLocalization)
|
||||
return Bundle.localizedString(stringKey: "Update", forceLanguageLocalization: forceLanguageLocalization)
|
||||
}
|
||||
|
||||
func localizedNextTimeButtonTitle() -> String {
|
||||
return Bundle().localizedString(stringKey: "Next time", forceLanguageLocalization: forceLanguageLocalization)
|
||||
return Bundle.localizedString(stringKey: "Next time", forceLanguageLocalization: forceLanguageLocalization)
|
||||
}
|
||||
|
||||
func localizedSkipButtonTitle() -> String {
|
||||
return Bundle().localizedString(stringKey: "Skip this version", forceLanguageLocalization: forceLanguageLocalization)
|
||||
return Bundle.localizedString(stringKey: "Skip this version", forceLanguageLocalization: forceLanguageLocalization)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpers (Version)
|
||||
|
||||
extension Siren {
|
||||
func isAppStoreVersionNewer() -> Bool {
|
||||
@objc func isAppStoreVersionNewer() -> Bool {
|
||||
var newVersionExists = false
|
||||
|
||||
if let currentInstalledVersion = currentInstalledVersion,
|
||||
|
||||
@@ -11,21 +11,23 @@ import Foundation
|
||||
// MARK: - Bundle Extension for Siren
|
||||
|
||||
internal extension Bundle {
|
||||
@objc
|
||||
class func bundleID() -> String? {
|
||||
return Bundle.main.bundleIdentifier
|
||||
}
|
||||
|
||||
func sirenBundlePath() -> String {
|
||||
@objc
|
||||
class func sirenBundlePath() -> String {
|
||||
return Bundle(for: Siren.self).path(forResource: "Siren", ofType: "bundle") as String!
|
||||
}
|
||||
|
||||
func sirenForcedBundlePath(forceLanguageLocalization: Siren.LanguageType) -> String {
|
||||
class func sirenForcedBundlePath(forceLanguageLocalization: Siren.LanguageType) -> String {
|
||||
let path = sirenBundlePath()
|
||||
let name = forceLanguageLocalization.rawValue
|
||||
return Bundle(path: path)!.path(forResource: name, ofType: "lproj")!
|
||||
}
|
||||
|
||||
func localizedString(stringKey: String, forceLanguageLocalization: Siren.LanguageType?) -> String {
|
||||
class func localizedString(stringKey: String, forceLanguageLocalization: Siren.LanguageType?) -> String {
|
||||
var path: String
|
||||
let table = "SirenLocalizable"
|
||||
if let forceLanguageLocalization = forceLanguageLocalization {
|
||||
@@ -37,6 +39,7 @@ internal extension Bundle {
|
||||
return Bundle(path: path)!.localizedString(forKey: stringKey, value: stringKey, table: table)
|
||||
}
|
||||
|
||||
@objc
|
||||
func bestMatchingAppName() -> String {
|
||||
let bundleDisplayName = Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String
|
||||
let bundleName = Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String) as? String
|
||||
@@ -48,7 +51,7 @@ internal extension Bundle {
|
||||
// MARK: - Bundle Extension for Testing Siren
|
||||
|
||||
extension Bundle {
|
||||
func testLocalizedString(stringKey: String, forceLanguageLocalization: Siren.LanguageType?) -> String {
|
||||
return Bundle().localizedString(stringKey: stringKey, forceLanguageLocalization: forceLanguageLocalization)
|
||||
class func testLocalizedString(stringKey: String, forceLanguageLocalization: Siren.LanguageType?) -> String {
|
||||
return Bundle.localizedString(stringKey: stringKey, forceLanguageLocalization: forceLanguageLocalization)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,15 +11,15 @@ import Foundation
|
||||
// MARK: - Helpers (Testing Target)
|
||||
|
||||
extension Siren {
|
||||
func testSetCurrentInstalledVersion(version: String) {
|
||||
@objc func testSetCurrentInstalledVersion(version: String) {
|
||||
currentInstalledVersion = version
|
||||
}
|
||||
|
||||
func testSetAppStoreVersion(version: String) {
|
||||
@objc func testSetAppStoreVersion(version: String) {
|
||||
currentAppStoreVersion = version
|
||||
}
|
||||
|
||||
func testIsAppStoreVersionNewer() -> Bool {
|
||||
@objc func testIsAppStoreVersionNewer() -> Bool {
|
||||
return isAppStoreVersionNewer()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import Foundation
|
||||
// MARK: - UIAlertController Extension for Siren
|
||||
|
||||
internal extension UIAlertController {
|
||||
func show() {
|
||||
@objc func show() {
|
||||
let window = UIWindow(frame: UIScreen.main.bounds)
|
||||
window.rootViewController = SirenViewController()
|
||||
window.windowLevel = UIWindowLevelAlert + 1
|
||||
|
||||
Reference in New Issue
Block a user