我需要检查我的应用程序何时启动是否正在更新,因为我需要创建一个仅在首次安装应用程序时出现的视图,以便在更新后再次出现。
8 回答
您可以保存一个值(例如当前应用程序版本号)NSUserDefaults
并在每次用户启动应用程序时检查它。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ...
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *currentAppVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
NSString *previousVersion = [defaults objectForKey:@"appVersion"];
if (!previousVersion) {
// first launch
// ...
[defaults setObject:currentAppVersion forKey:@"appVersion"];
[defaults synchronize];
} else if ([previousVersion isEqualToString:currentAppVersion]) {
// same version
} else {
// other version
// ...
[defaults setObject:currentAppVersion forKey:@"appVersion"];
[defaults synchronize];
}
return YES;
}
swift-2版本如下所示:
let defaults = NSUserDefaults.standardUserDefaults()
let currentAppVersion = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") as! String
let previousVersion = defaults.stringForKey("appVersion")
if previousVersion == nil {
// first launch
defaults.setObject(currentAppVersion, forKey: "appVersion")
defaults.synchronize()
} else if previousVersion == currentAppVersion {
// same version
} else {
// other version
defaults.setObject(currentAppVersion, forKey: "appVersion")
defaults.synchronize()
}
swift-3版本如下所示:
let defaults = UserDefaults.standard
let currentAppVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
let previousVersion = defaults.string(forKey: "appVersion")
if previousVersion == nil {
// first launch
defaults.set(currentAppVersion, forKey: "appVersion")
defaults.synchronize()
} else if previousVersion == currentAppVersion {
// same version
} else {
// other version
defaults.set(currentAppVersion, forKey: "appVersion")
defaults.synchronize()
}
您可以在 NSUserDefaults 中存储应用程序版本号,并在每次启动应用程序时检查它。如果该号码不可用,则为全新安装。如果它被改变,它是一个升级。
只需在应用启动时初始化 AppVersionUpdateNotifier 并符合 AppUpdateNotifier 协议,享受。
使用: Swift 3.x
extension AppDelegate: AppUpdateNotifier {
func onVersionUpdate(newVersion: Int, oldVersion: Int) {
// do something
}
func onFirstLaunch() {
//do something
}
}
class AppVersionUpdateNotifier {
static let KEY_APP_VERSION = "key_app_version"
static let shared = AppVersionUpdateNotifier()
private let userDefault:UserDefaults
private var delegate:AppUpdateNotifier?
private init() {
self.userDefault = UserDefaults.standard
}
func initNotifier(_ delegate:AppUpdateNotifier) {
self.delegate = delegate
checkVersionAndNotify()
}
private func checkVersionAndNotify() {
let versionOfLastRun = userDefault.object(forKey: AppVersionUpdateNotifier.KEY_APP_VERSION) as? Int
let currentVersion = Int(Bundle.main.buildVersion)!
if versionOfLastRun == nil {
// First start after installing the app
delegate?.onFirstLaunch()
} else if versionOfLastRun != currentVersion {
// App was updated since last run
delegate?.onVersionUpdate(newVersion: currentVersion, oldVersion: versionOfLastRun!)
} else {
// nothing changed
}
userDefault.set(currentVersion, forKey: AppVersionUpdateNotifier.KEY_APP_VERSION)
}
}
protocol AppUpdateNotifier {
func onFirstLaunch()
func onVersionUpdate(newVersion:Int, oldVersion:Int)
}
extension Bundle {
var shortVersion: String {
return infoDictionary!["CFBundleShortVersionString"] as! String
}
var buildVersion: String {
return infoDictionary!["CFBundleVersion"] as! String
}
}
快速版本,对已接受的答案进行了重要改进:
- 使用
infoDictionary
而不是objectForInfoDictionaryKey
保证结果独立于设备语言,否则您可能会在极少数情况下最终认为有升级,而实际上它只是设备语言的更改 - 使用与主 Bundle infoDictionary 相同的 UserDefaults 键,以清楚地了解确切存储的内容
- 因式设置 currentVersion 代码
- 斯威夫特 3 语法
代码:
let standardUserDefaults = UserDefaults.standard
let shortVersionKey = "CFBundleShortVersionString"
let currentVersion = Bundle.main.infoDictionary![shortVersionKey] as! String
let previousVersion = standardUserDefaults.object(forKey: shortVersionKey) as? String
if previousVersion == currentVersion {
// same version
} else {
// replace with `if let previousVersion = previousVersion {` if you need the exact value
if previousVersion != nil {
// new version
} else {
// first launch
}
standardUserDefaults.set(currentVersion, forKey: shortVersionKey)
standardUserDefaults.synchronize()
}
我认为,当你有一个小规模的应用程序时,给定的答案是好的,但是当你在一个具有很长路线图的大型 iOS 应用程序上工作时,你肯定需要一个强大的未来解决方案,并具有类似的好处。
- 更好地比较适用于所有可能性(2.0/2.0.0 等)的逻辑。
- 在迁移过程中采取特定操作,假设用户从 1.0 版本迁移到 2.0 和 1.1 到 2.0。
- 当用户重置应用程序(注销)时重置缓存版本。
下面是我在我的一个 iOS 应用程序中使用的代码片段。
public enum VersionConfigResponse {
case freshInstalled
case versionGreater
case versionEqualOrLesser
case currentVersionEmpty
}
/*
Config manager responsible to handle the change needs to be done when user migrate from one Version to another Version.
*/
public class VersionConfig {
public static let shared = VersionConfig()
private init() { }
private let versionKey = "SAVED_SHORT_VERSION_STRING"
/*
Cache the existing version for compare during next app launch.
*/
private var storedVersion : String? {
get {
return UserDefaults.standard.object(forKey: versionKey) as? String
} set {
UserDefaults.standard.set(newValue, forKey: versionKey)
UserDefaults.standard.synchronize()
}
}
/*
Validate the current version with saved version, if greater do clean.
*/
public func validate(currentVersion: String?) -> VersionConfigResponse {
guard let currentVersion = currentVersion else {
return .currentVersionEmpty
}
guard let sVersion = storedVersion else {
self.storedVersion = currentVersion
self.freshInstalled()
return .freshInstalled
}
if currentVersion.compare(sVersion, options: .numeric, range: nil, locale: nil) == .orderedDescending {
self.storedVersion = currentVersion
self.userMigrated(fromVersion: sVersion, toVersion:currentVersion)
return .versionGreater
} else {
return .versionEqualOrLesser
}
}
private func userMigrated(fromVersion: String, toVersion: String) {
//take your action here...
}
private func freshInstalled() {
//take your action here...
}
/*
Remove saved version if user reset(logout) the app.
*/
public func reset() {
self.storedVersion = nil
}
}
//trigger version config with current version
VersionConfig.shared.validate(currentVersion: "1.0.0")
//reset when user logsout
VersionConfig.shared.reset()
这是一个简单的代码,用于了解当前版本是否不同(此代码也适用于模拟器。)
-(BOOL) needsUpdate
{
NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString* appID = infoDictionary[@"CFBundleIdentifier"];
NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"http://itunes.apple.com/lookup?bundleId=%@", appID]];
NSData* data = [NSData dataWithContentsOfURL:url];
NSDictionary* lookup = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if ([lookup[@"resultCount"] integerValue] == 1)
{
NSString* appStoreVersion = lookup[@"results"][0][@"version"];
NSString* currentVersion = infoDictionary[@"CFBundleShortVersionString"];
if (![appStoreVersion isEqualToString:currentVersion])
{
NSLog(@"Need to update [%@ != %@]", appStoreVersion, currentVersion);
return YES;
}
}
return NO;
}
注意:确保当您在 iTunes 中输入新版本时,该版本与您正在发布的应用程序中的版本相匹配。如果不是,那么无论用户是否更新,上述代码将始终返回 YES。
这对我有用..
func compareVersion(old:String,latest:String) -> Bool {
if latest.compare(old, options: .numeric) == .orderedDescending {
return true
}
return false
}
compareVersion(old: "3.1.5", latest: "3.2")
我创建了BundleInfoVersioning
swift 包来帮助我解决这个问题。
它适用于信息字典中的所有键,例如CFBundleVersion
orCFBundleShortVersionString
和自定义键路径,例如NSAgora/DatabaseVersion
.
例子:
let bundleInfoVersioning = BundleInfoVersioning(bundle: .main)
bundleInfoVersioning.check(forKeyPath: "CFBundleVersion") { (old: String?, new: String?) in
if old == nil {
Analytics.install(version: new)
}
else {
Analytics.update(from: old, to: new)
}
}
bundleInfoVersioning.check(forKeyPath: "CFBundleShortVersionString") { _ , newVersion in
self.showWhatsNew(in: newVersion)
}
bundleInfoVersioning.check(forKeyPath: "NSAgora/DatabaseVersion") { (old: Int?, new: Int?) in
self.resetDataBase()
}
您可以在https://github.com/nsagora/bundle-info-versioning在 github 上查看。