Check if my application has a new version in the AppStore

I would like to manually check if there are new updates for my application when the user is in it, and ask him to download the new version. Can I do this by checking the version of my application in the application store - programmatically?

+80
ios iphone xcode app-store version
Jun 06 '11 at 19:03
source share
24 answers

Here is a simple snippet of code that lets you know if the current version is different

-(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; } 

Note. Make sure that when you enter the new version in iTunes, this matches the version in the application that you are releasing. If not, the above code will always return YES regardless of whether the user is being updated.

+80
Aug 08 '14 at 18:38
source share

Swift 3 version:

 func isUpdateAvailable() throws -> Bool { guard let info = Bundle.main.infoDictionary, let currentVersion = info["CFBundleShortVersionString"] as? String, let identifier = info["CFBundleIdentifier"] as? String, let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(identifier)") else { throw VersionError.invalidBundleInfo } let data = try Data(contentsOf: url) guard let json = try JSONSerialization.jsonObject(with: data, options: [.allowFragments]) as? [String: Any] else { throw VersionError.invalidResponse } if let result = (json["results"] as? [Any])?.first as? [String: Any], let version = result["version"] as? String { return version != currentVersion } throw VersionError.invalidResponse } 

I think it's better to throw an error instead of returning false, in this case I created a VersionError version, but it could be some other one you define, or NSError

 enum VersionError: Error { case invalidResponse, invalidBundleInfo } 

We also consider the possibility of calling this function from another thread, if the connection is slow, it can block the current thread.

 DispatchQueue.global().async { do { let update = try self.isUpdateAvailable() DispatchQueue.main.async { // show alert } } catch { print(error) } } 

Update

Using URLSession:

Instead of using Data(contentsOf: url) and blocking the stream, we can use URLSession :

 func isUpdateAvailable(completion: @escaping (Bool?, Error?) -> Void) throws -> URLSessionDataTask { guard let info = Bundle.main.infoDictionary, let currentVersion = info["CFBundleShortVersionString"] as? String, let identifier = info["CFBundleIdentifier"] as? String, let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(identifier)") else { throw VersionError.invalidBundleInfo } Log.debug(currentVersion) let task = URLSession.shared.dataTask(with: url) { (data, response, error) in do { if let error = error { throw error } guard let data = data else { throw VersionError.invalidResponse } let json = try JSONSerialization.jsonObject(with: data, options: [.allowFragments]) as? [String: Any] guard let result = (json?["results"] as? [Any])?.first as? [String: Any], let version = result["version"] as? String else { throw VersionError.invalidResponse } completion(version != currentVersion, nil) } catch { completion(nil, error) } } task.resume() return task } 

Example:

 _ = try? isUpdateAvailable { (update, error) in if let error = error { print(error) } else if let update = update { print(update) } } 
+32
Dec 02 '16 at 19:39
source share

Since I had the same problem, I found the answer provided by Mario Hendricks . Unfornatelly, when I tried to evaluate its code in my project, Xcode really complained about casting problems, saying: "MDLMaterialProperty has no substring members." His code tried to set this MDLMaterial ... as the type of the constant "lookupResult", causing the casting "Int" to fail every time. My solution was to provide type annotation for my NSDictionary variable in order to clarify what value I need. In doing so, I could access the value "version" that I needed.

Discuss: For this you can get YOURBUNDLEID from your Xcode project .... "Objectives> General> Identification> Package Identifier>

So here is my code with some simplifications:

  func appUpdateAvailable() -> Bool { let storeInfoURL: String = "http://itunes.apple.com/lookup?bundleId=YOURBUNDLEID" var upgradeAvailable = false // Get the main bundle of the app so that we can determine the app version number let bundle = NSBundle.mainBundle() if let infoDictionary = bundle.infoDictionary { // The URL for this app on the iTunes store uses the Apple ID for the This never changes, so it is a constant let urlOnAppStore = NSURL(string: storeInfoURL) if let dataInJSON = NSData(contentsOfURL: urlOnAppStore!) { // Try to deserialize the JSON that we got if let dict: NSDictionary = try? NSJSONSerialization.JSONObjectWithData(dataInJSON, options: NSJSONReadingOptions.AllowFragments) as! [String: AnyObject] { if let results:NSArray = dict["results"] as? NSArray { if let version = results[0].valueForKey("version") as? String { // Get the version number of the current version installed on device if let currentVersion = infoDictionary["CFBundleShortVersionString"] as? String { // Check if they are the same. If not, an upgrade is available. print("\(version)") if version != currentVersion { upgradeAvailable = true } } } } } } } return upgradeAvailable } 

Any suggestions for improving this code are welcome!

+13
Sep 26 '16 at 18:11
source share

Thanks to Steve Moser for his link, here is my code:

 NSString *appInfoUrl = @"http://itunes.apple.com/en/lookup?bundleId=XXXXXXXXX"; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; [request setURL:[NSURL URLWithString:appInfoUrl]]; [request setHTTPMethod:@"GET"]; NSURLResponse *response; NSError *error; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse: &response error: &error]; NSString *output = [NSString stringWithCString:[data bytes] length:[data length]]; NSError *e = nil; NSData *jsonData = [output dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error: &e]; NSString *version = [[[jsonDict objectForKey:@"results"] objectAtIndex:0] objectForKey:@"version"]; 
+12
Nov 01 '13 at 16:47
source share

Just use ATAppUpdater . This is 1 line, thread safe and fast. It also has delegation methods if you want to track user activity.

Here is an example:

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [[ATAppUpdater sharedUpdater] showUpdateWithConfirmation]; // 1 line of code // or [[ATAppUpdater sharedUpdater] showUpdateWithForce]; // 1 line of code return YES; } 

Additional delegate methods:

 - (void)appUpdaterDidShowUpdateDialog; - (void)appUpdaterUserDidLaunchAppStore; - (void)appUpdaterUserDidCancel; 
+11
Jul 30 '15 at 21:29
source share

Can I suggest this small library: https://github.com/nicklockwood/iVersion

Its purpose is to simplify the processing of remote plists to trigger notifications.

+7
Aug 16 '11 at 16:21
source share

Here is my version using Swift 4 and the popular Alamofire library (I use it in my applications anyway). The request is asynchronous, and you can pass a callback to receive a notification when this is done.

 import Alamofire class VersionCheck { public static let shared = VersionCheck() var newVersionAvailable: Bool? var appStoreVersion: String? func checkAppStore(callback: ((_ versionAvailable: Bool?, _ version: String?)->Void)? = nil) { let ourBundleId = Bundle.main.infoDictionary!["CFBundleIdentifier"] as! String Alamofire.request("https://itunes.apple.com/lookup?bundleId=\(ourBundleId)").responseJSON { response in var isNew: Bool? var versionStr: String? if let json = response.result.value as? NSDictionary, let results = json["results"] as? NSArray, let entry = results.firstObject as? NSDictionary, let appVersion = entry["version"] as? String, let ourVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String { isNew = ourVersion != appVersion versionStr = appVersion } self.appStoreVersion = versionStr self.newVersionAvailable = isNew callback?(isNew, versionStr) } } } 

Usage is simple:

 VersionCheck.shared.checkAppStore() { isNew, version in print("IS NEW VERSION AVAILABLE: \(isNew), APP STORE VERSION: \(version)") } 
+6
Oct 05 '18 at 17:11
source share

Updated swift 4 code from Anup Gupta

I made some changes to this code . Functions are now called from the background queue because the connection can be slow and therefore block the main thread.

I also made CFBundleName optional since the version I submitted had "CFBundleDisplayName", which probably didn't work in my version. So now, if it is absent, it will not crash, but simply will not display the application name in the notification.

 import UIKit enum VersionError: Error { case invalidBundleInfo, invalidResponse } class LookupResult: Decodable { var results: [AppInfo] } class AppInfo: Decodable { var version: String var trackViewUrl: String } class AppUpdater: NSObject { private override init() {} static let shared = AppUpdater() func showUpdate(withConfirmation: Bool) { DispatchQueue.global().async { self.checkVersion(force : !withConfirmation) } } private func checkVersion(force: Bool) { let info = Bundle.main.infoDictionary if let currentVersion = info?["CFBundleShortVersionString"] as? String { _ = getAppInfo { (info, error) in if let appStoreAppVersion = info?.version{ if let error = error { print("error getting app store version: ", error) } else if appStoreAppVersion == currentVersion { print("Already on the last app version: ",currentVersion) } else { print("Needs update: AppStore Version: \(appStoreAppVersion) > Current version: ",currentVersion) DispatchQueue.main.async { let topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController! topController.showAppUpdateAlert(Version: (info?.version)!, Force: force, AppURL: (info?.trackViewUrl)!) } } } } } } private func getAppInfo(completion: @escaping (AppInfo?, Error?) -> Void) -> URLSessionDataTask? { guard let identifier = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String, let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(identifier)") else { DispatchQueue.main.async { completion(nil, VersionError.invalidBundleInfo) } return nil } let task = URLSession.shared.dataTask(with: url) { (data, response, error) in do { if let error = error { throw error } guard let data = data else { throw VersionError.invalidResponse } let result = try JSONDecoder().decode(LookupResult.self, from: data) guard let info = result.results.first else { throw VersionError.invalidResponse } completion(info, nil) } catch { completion(nil, error) } } task.resume() return task } } extension UIViewController { @objc fileprivate func showAppUpdateAlert( Version : String, Force: Bool, AppURL: String) { let appName = Bundle.appName() let alertTitle = "New Version" let alertMessage = "\(appName) Version \(Version) is available on AppStore." let alertController = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .alert) if !Force { let notNowButton = UIAlertAction(title: "Not Now", style: .default) alertController.addAction(notNowButton) } let updateButton = UIAlertAction(title: "Update", style: .default) { (action:UIAlertAction) in guard let url = URL(string: AppURL) else { return } if #available(iOS 10.0, *) { UIApplication.shared.open(url, options: [:], completionHandler: nil) } else { UIApplication.shared.openURL(url) } } alertController.addAction(updateButton) self.present(alertController, animated: true, completion: nil) } } extension Bundle { static func appName() -> String { guard let dictionary = Bundle.main.infoDictionary else { return "" } if let version : String = dictionary["CFBundleName"] as? String { return version } else { return "" } } } 

I make this call to add a confirmation button:

 AppUpdater.shared.showUpdate(withConfirmation: true) 

Or call it so that it includes the forced update option:

 AppUpdater.shared.showUpdate(withConfirmation: false) 
+5
Dec 04 '18 at 17:29
source share

This answer is a modification of the datinc answer https://stackoverflow.com/a/464632/

datinc funtion compares version using string comparison. Thus, it will not compare the version more or less.

But this modified function compares the version using NSNumericSearch (numerical comparison) .

 - (void)checkForUpdateWithHandler:(void(^)(BOOL isUpdateAvailable))updateHandler { NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary]; NSString *appID = infoDictionary[@"CFBundleIdentifier"]; NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://itunes.apple.com/lookup?bundleId=%@", appID]]; NSLog(@"iTunes Lookup URL for the app: %@", url.absoluteString); NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *theTask = [session dataTaskWithRequest:[NSURLRequest requestWithURL:url] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSDictionary *lookup = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSLog(@"iTunes Lookup Data: %@", lookup); if (lookup && [lookup[@"resultCount"] integerValue] == 1){ NSString *appStoreVersion = lookup[@"results"][0][@"version"]; NSString *currentVersion = infoDictionary[@"CFBundleShortVersionString"]; BOOL isUpdateAvailable = [appStoreVersion compare:currentVersion options:NSNumericSearch] == NSOrderedDescending; if (isUpdateAvailable) { NSLog(@"\n\nNeed to update. Appstore version %@ is greater than %@",appStoreVersion, currentVersion); } if (updateHandler) { updateHandler(isUpdateAvailable); } } }]; [theTask resume]; } 

Application:

 [self checkForUpdateWithHandler:^(BOOL isUpdateAvailable) { if (isUpdateAvailable) { // show alert } }]; 
+4
Mar 01 '17 at 13:03 on
source share

Swift 3.1

 func needsUpdate() -> Bool { let infoDictionary = Bundle.main.infoDictionary let appID = infoDictionary!["CFBundleIdentifier"] as! String let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(appID)") guard let data = try? Data(contentsOf: url) else { print("There is an error!") return false; } let lookup = (try? JSONSerialization.jsonObject(with: data! , options: [])) as? [String: Any] if let resultCount = lookup!["resultCount"] as? Int, resultCount == 1 { if let results = lookup!["results"] as? [[String:Any]] { if let appStoreVersion = results[0]["version"] as? String{ let currentVersion = infoDictionary!["CFBundleShortVersionString"] as? String if !(appStoreVersion == currentVersion) { print("Need to update [\(appStoreVersion) != \(currentVersion)]") return true } } } } return false } 
+4
Nov 16 '17 at 10:06
source share

Here is a quick method that does what some of Objective-C offer. Obviously, once you get the information from the JSON app store, you can extract the release notes if you want.

 func appUpdateAvailable(storeInfoURL: String) -> Bool { var upgradeAvailable = false // Get the main bundle of the app so that we can determine the app version number let bundle = NSBundle.mainBundle() if let infoDictionary = bundle.infoDictionary { // The URL for this app on the iTunes store uses the Apple ID for the This never changes, so it is a constant let urlOnAppStore = NSURL(string: storeInfoURL) if let dataInJSON = NSData(contentsOfURL: urlOnAppStore!) { // Try to deserialize the JSON that we got if let lookupResults = try? NSJSONSerialization.JSONObjectWithData(dataInJSON, options: NSJSONReadingOptions()) { // Determine how many results we got. There should be exactly one, but will be zero if the URL was wrong if let resultCount = lookupResults["resultCount"] as? Int { if resultCount == 1 { // Get the version number of the version in the App Store if let appStoreVersion = lookupResults["results"]!![0]["version"] as? String { // Get the version number of the current version if let currentVersion = infoDictionary["CFBundleShortVersionString"] as? String { // Check if they are the same. If not, an upgrade is available. if appStoreVersion != currentVersion { upgradeAvailable = true } } } } } } } } return upgradeAvailable } 
+2
Jan 10 '16 at 16:23
source share

If you do not specify the content type in NSUrlRequest, then of course you will not get an answer, so try the code below, it works fine for me. Hope this helps ...

 -(BOOL) isUpdateAvailable{ NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary]; NSString* appID = infoDictionary[@"CFBundleIdentifier"]; NSString *urlString = [NSString stringWithFormat:@"https://itunes.apple.com/lookup?bundleId=%@",appID]; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; [request setURL:[NSURL URLWithString:urlString]]; [request setHTTPMethod:@"GET"]; [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; NSURLResponse *response; NSError *error; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse: &response error: &error]; NSError *e = nil; NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error: &e]; self.versionInAppStore = [[[jsonDict objectForKey:@"results"] objectAtIndex:0] objectForKey:@"version"]; self.localAppVersion = infoDictionary[@"CFBundleShortVersionString"]; if ([self.versionInAppStore compare:self.localAppVersion options:NSNumericSearch] == NSOrderedDescending) { // currentVersion is lower than the version return YES; } return NO; } 
+2
Jun 14 '16 at 14:02
source share

Coming from a POV hybrid application, this is a javascript example, I have an Update Available footer in my main menu. If an update is available (i.e., my version number in the configuration file is less than the version found, display the footer). He will then direct the user to the application store, where the user can click the update button.

I also get new data (e.g. release notes) and display it in a modal name if it is the first time in this version.

The available Update method can be run as often as you like. Mine is launched every time the user goes to the main screen.

 function isUpdateAvailable() { $.ajax('https://itunes.apple.com/lookup?bundleId=BUNDLEID', { type: "GET", cache: false, dataType: 'json' }).done(function (data) { _isUpdateAvailable(data.results[0]); }).fail(function (jqXHR, textStatus, errorThrown) { commsErrorHandler(jqXHR, textStatus, false); }); } 

Callback: Apple has an API, so it’s very easy to get

 function isUpdateAvailable_iOS (data) { var storeVersion = data.version; var releaseNotes = data.releaseNotes; // Check store Version Against My App Version ('1.14.3' -> 1143) var _storeV = parseInt(storeVersion.replace(/\./g, '')); var _appV = parseInt(appVersion.substring(1).replace(/\./g, '')); $('#ft-main-menu-btn').off(); if (_storeV > _appV) { // Update Available $('#ft-main-menu-btn').text('Update Available'); $('#ft-main-menu-btn').click(function () { // Open Store window.open('https://itunes.apple.com/us/app/appname/idUniqueID', '_system'); }); } else { $('#ft-main-menu-btn').html(' '); // Release Notes settings.updateReleaseNotes('v' + storeVersion, releaseNotes); } } 
+2
Nov 30 '16 at 17:20
source share

Warning:. Most of the responses you received receive a synchronous URL (using -dataWithContentsOfURL: or -sendSynchronousRequest: This is bad, because it means your application will not respond for several minutes if the mobile connection drops during the execution of the request. Never connect Internet access to the main stream.

The correct answer is to use an asynchronous API:

  NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary]; NSString* appID = infoDictionary[@"CFBundleIdentifier"]; NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"http://itunes.apple.com/lookup?bundleId=%@", appID]]; NSURLSession * session = [NSURLSession sharedSession]; NSURLSessionDataTask * theTask = [session dataTaskWithRequest: [NSURLRequest requestWithURL: url] completionHandler: ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSDictionary<NSString*,NSArray*>* lookup = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; if ([lookup[@"resultCount"] integerValue] == 1) { NSString* appStoreVersion = lookup[@"results"].firstObject[@"version"]; NSString* currentVersion = infoDictionary[@"CFBundleShortVersionString"]; if ([appStoreVersion compare:currentVersion options:NSNumericSearch] == NSOrderedDescending) { // *** Present alert about updating to user *** } } }]; [theTask resume]; 

The default timeout for network connections is a few minutes. And even if the request passes, it can be slow enough compared to the poor EDGE connection to take so long. In this case, you do not want your application to be unusable. To test such things, it is useful to run network code using the Apple Network Link Conditioner.

+2
Mar 03 '17 at 10:26
source share
 func isUpdateAvailable() -> Bool { guard let info = Bundle.main.infoDictionary, let identifier = info["CFBundleIdentifier"] as? String, let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(identifier)"), let data = try? Data(contentsOf: url), let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any], let results = json?["results"] as? [[String: Any]], results.count > 0, let versionString = results[0]["version"] as? String else { return false } return AppVersion(versionString) > AppVersion.marketingVersion } 

to compare version string:

https://github.com/eure/AppVersionMonitor

+1
Jun 01 '17 at 8:52
source share

This question was asked in 2011, I found it in 2018, looking for some way to not only check the new version of the application in the App Store, but also notify the user about it.

After a bit of research, I came to the conclusion that the juanjo answer (related to Swift 3) https://stackoverflow.com/a/4148772/ is a good solution if you want to do this in code yourself

I can also offer two large projects on GitHub (2300+)

Example for Siren (AppDelegate.swift)

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { let siren = Siren.shared siren.checkVersion(checkType: .immediately) return true } 
  • You can also show different types of warnings about the new version (allowing you to skip the version or force the user to upgrade)
  • You can specify how often version checking is performed (daily / weekly / immediately)
  • You can specify how many days after the new version for the notification about the application store should appear
+1
Jan 17 '18 at 6:09
source share

Swift 4

We can use the new JSONDecoder to parse the response from itunes.apple.com/lookup and present it using Decodable classes or structures:

 class LookupResult: Decodable { var results: [AppInfo] } class AppInfo: Decodable { var version: String } 

We can also add other AppInfo properties in case we need releaseNotes or some other property.

Now we can make an async request using the URLSession :

 func getAppInfo(completion: @escaping (AppInfo?, Error?) -> Void) -> URLSessionDataTask? { guard let identifier = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String, let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(identifier)") else { DispatchQueue.main.async { completion(nil, VersionError.invalidBundleInfo) } return nil } let task = URLSession.shared.dataTask(with: url) { (data, response, error) in do { if let error = error { throw error } guard let data = data else { throw VersionError.invalidResponse } let result = try JSONDecoder().decode(LookupResult.self, from: data) guard let info = result.results.first else { throw VersionError.invalidResponse } completion(info, nil) } catch { completion(nil, error) } } task.resume() return task } enum VersionError: Error { case invalidBundleInfo, invalidResponse } 

this function receives a completion close, which will be called when the request is completed, and returns a URLSessionDataTask in case we need to cancel the request, and it can be called as follows:

 func checkVersion() { let info = Bundle.main.infoDictionary let currentVersion = info?["CFBundleShortVersionString"] as? String _ = getAppInfo { (info, error) in if let error = error { print(error) } else if info?.version == currentVersion { print("updated") } else { print("needs update") } } } 
+1
Feb 15 '18 at 15:18
source share

I have seen many ways to check for application updates. therefore, based on many answers, I mix them and create my solution, which is available on GitHub. If any update is required. Please let me know. This code is for Swift 4

GitHub Link To this code. https://github.com/anupgupta-arg/iOS-Swift-ArgAppUpdater

  import UIKit enum VersionError: Error { case invalidBundleInfo, invalidResponse } class LookupResult: Decodable { var results: [AppInfo] } class AppInfo: Decodable { var version: String var trackViewUrl: String //let identifier = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String, // You can add many thing based on "http://itunes.apple.com/lookup?bundleId=\(identifier)" response // here version and trackViewUrl are key of URL response // so you can add all key beased on your requirement. } class ArgAppUpdater: NSObject { private static var _instance: ArgAppUpdater?; private override init() { } public static func getSingleton() -> ArgAppUpdater { if (ArgAppUpdater._instance == nil) { ArgAppUpdater._instance = ArgAppUpdater.init(); } return ArgAppUpdater._instance!; } private func getAppInfo(completion: @escaping (AppInfo?, Error?) -> Void) -> URLSessionDataTask? { guard let identifier = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String, let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(identifier)") else { DispatchQueue.main.async { completion(nil, VersionError.invalidBundleInfo) } return nil } let task = URLSession.shared.dataTask(with: url) { (data, response, error) in do { if let error = error { throw error } guard let data = data else { throw VersionError.invalidResponse } print("Data:::",data) print("response###",response!) let result = try JSONDecoder().decode(LookupResult.self, from: data) let dictionary = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) print("dictionary",dictionary!) guard let info = result.results.first else { throw VersionError.invalidResponse } print("result:::",result) completion(info, nil) } catch { completion(nil, error) } } task.resume() print("task ******", task) return task } private func checkVersion(force: Bool) { let info = Bundle.main.infoDictionary let currentVersion = info?["CFBundleShortVersionString"] as? String _ = getAppInfo { (info, error) in let appStoreAppVersion = info?.version if let error = error { print(error) }else if appStoreAppVersion!.compare(currentVersion!, options: .numeric) == .orderedDescending { // print("needs update") // print("hiiii") DispatchQueue.main.async { let topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController! topController.showAppUpdateAlert(Version: (info?.version)!, Force: force, AppURL: (info?.trackViewUrl)!) } } } } func showUpdateWithConfirmation() { checkVersion(force : false) } func showUpdateWithForce() { checkVersion(force : true) } } extension UIViewController { fileprivate func showAppUpdateAlert( Version : String, Force: Bool, AppURL: String) { print("AppURL:::::",AppURL) let bundleName = Bundle.main.infoDictionary!["CFBundleDisplayName"] as! String; let alertMessage = "\(bundleName) Version \(Version) is available on AppStore." let alertTitle = "New Version" let alertController = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .alert) if !Force { let notNowButton = UIAlertAction(title: "Not Now", style: .default) { (action:UIAlertAction) in print("Don't Call API"); } alertController.addAction(notNowButton) } let updateButton = UIAlertAction(title: "Update", style: .default) { (action:UIAlertAction) in print("Call API"); print("No update") guard let url = URL(string: AppURL) else { return } if #available(iOS 10.0, *) { UIApplication.shared.open(url, options: [:], completionHandler: nil) } else { UIApplication.shared.openURL(url) } } alertController.addAction(updateButton) self.present(alertController, animated: true, completion: nil) } } 

Refrence: qaru.site/questions/114145/... https://github.com/emotality/ATAppUpdater

πŸ‘ 😊

+1
04 . '18 12:17
source share

SWIFT 4 3.2:

-, , isUpdaet false.

  var isUpdate = false guard let bundleInfo = Bundle.main.infoDictionary, let currentVersion = bundleInfo["CFBundleShortVersionString"] as? String, //let identifier = bundleInfo["CFBundleIdentifier"] as? String, let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(identifier)") else{ print("something wrong") completion(false) return } 

urlSession itunes.

  let task = URLSession.shared.dataTask(with: url) { (data, resopnse, error) in if error != nil{ completion(false) print("something went wrong") }else{ do{ guard let reponseJson = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any], let result = (reponseJson["results"] as? [Any])?.first as? [String: Any], let version = result["version"] as? String else{ completion(false) return } print("Current Ver:\(currentVersion)") print("Prev version:\(version)") if currentVersion != version{ completion(true) }else{ completion(false) } } catch{ completion(false) print("Something went wrong") } } } task.resume() 

:

 func checkForUpdate(completion:@escaping(Bool)->()){ guard let bundleInfo = Bundle.main.infoDictionary, let currentVersion = bundleInfo["CFBundleShortVersionString"] as? String, //let identifier = bundleInfo["CFBundleIdentifier"] as? String, let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(identifier)") else{ print("some thing wrong") completion(false) return } let task = URLSession.shared.dataTask(with: url) { (data, resopnse, error) in if error != nil{ completion(false) print("something went wrong") }else{ do{ guard let reponseJson = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any], let result = (reponseJson["results"] as? [Any])?.first as? [String: Any], let version = result["version"] as? String else{ completion(false) return } print("Current Ver:\(currentVersion)") print("Prev version:\(version)") if currentVersion != version{ completion(true) }else{ completion(false) } } catch{ completion(false) print("Something went wrong") } } } task.resume() } 

.

  checkForUpdate { (isUpdate) in print("Update needed:\(isUpdate)") if isUpdate{ DispatchQueue.main.async { print("new update Available") } } } 
+1
09 . '18 11:46
source share

# @datinc, , Apple App Store. , AssemblyInfo.

:: , "/us/", urlString. / .

 string GetAppStoreVersion() { string version = ""; NSDictionary infoDictionary = NSBundle .MainBundle .InfoDictionary; String appID = infoDictionary["CFBundleIdentifier"].ToString(); NSString urlString = new NSString(@"http://itunes.apple.com/us/lookup?bundleId=" + appID); NSUrl url = new NSUrl(new System.Uri(urlString).AbsoluteUri); NSData data = NSData.FromUrl(url); if (data == null) { /* <-- error obtaining data from url --> */ return ""; } NSError e = null; NSDictionary lookup = (NSDictionary)NSJsonSerialization .Deserialize(data, NSJsonReadingOptions.AllowFragments, out e); if (lookup == null) { /* <-- error, most probably no internet or bad connectivity --> */ return ""; } if (lookup["resultCount"].Description.Equals("1")) { NSObject nsObject = lookup["results"]; NSString nsString = new NSString("version"); String line = nsObject .ValueForKey(nsString) .Description; /* <-- format string --> */ string[] digits = Regex.Split(line, @"\D+"); for (int i = 0; i < digits.Length; i++) { if (int.TryParse(digits[i], out int intTest)) { if (version.Length > 0) version += "." + digits[i]; else version += digits[i]; } } } return version; } string GetBundleVersion() { return NSBundle .MainBundle .InfoDictionary["CFBundleShortVersionString"] .ToString(); } string GetAssemblyInfoVersion() { var assembly = typeof(App).GetTypeInfo().Assembly; var assemblyName = new AssemblyName(assembly.FullName); return assemblyName.Version.ToString(); } 
+1
14 . '19 18:49
source share

. @datinc @Mario-Hendricks

, dlog_Error .

. appStoreAppVersion . , , .

 class func appStoreAppVersion() -> String? { guard let bundleInfo = NSBundle.mainBundle().infoDictionary else { dlog_Error("Counldn't fetch bundleInfo.") return nil } let bundleId = bundleInfo[kCFBundleIdentifierKey as String] as! String // dbug__print("bundleId = \(bundleId)") let address = "http://itunes.apple.com/lookup?bundleId=\(bundleId)" // dbug__print("address = \(address)") guard let url = NSURLComponents.init(string: address)?.URL else { dlog_Error("Malformed internet address: \(address)") return nil } guard let data = NSData.init(contentsOfURL: url) else { if Util.isInternetAvailable() { dlog_MajorWarning("Web server request failed. Yet internet is reachable. Url was: \(address)") }// else: internet is unreachable. All ok. It is of course impossible to fetch the appStoreAppVersion like this. return nil } // dbug__print("data.length = \(data.length)") if data.length < 100 { //: We got 42 for a wrong address. And aproximately 4684 for a good response dlog_MajorWarning("Web server message is unexpectedly short: \(data.length) bytes") } guard let response = try? NSJSONSerialization.JSONObjectWithData(data, options: []) else { dlog_Error("Failed to parse server response.") return nil } guard let responseDic = response as? [String: AnyObject] else { dlog_Error("Not a dictionary keyed with strings. Response with unexpected format.") return nil } guard let resultCount = responseDic["resultCount"] else { dlog_Error("No resultCount found.") return nil } guard let count = resultCount as? Int else { //: Swift will handle NSNumber.integerValue dlog_Error("Server response resultCount is not an NSNumber.integer.") return nil } //:~ Determine how many results we got. There should be exactly one, but will be zero if the URL was wrong guard count == 1 else { dlog_Error("Server response resultCount=\(count), but was expected to be 1. URL (\(address)) must be wrong or something.") return nil } guard let rawResults = responseDic["results"] else { dlog_Error("Response does not contain a field called results. Results with unexpected format.") return nil } guard let resultsArray = rawResults as? [AnyObject] else { dlog_Error("Not an array of results. Results with unexpected format.") return nil } guard let resultsDic = resultsArray[0] as? [String: AnyObject] else { dlog_Error("Not a dictionary keyed with strings. Results with unexpected format.") return nil } guard let rawVersion = resultsDic["version"] else { dlog_Error("The key version is not part of the results") return nil } guard let versionStr = rawVersion as? String else { dlog_Error("Version is not a String") return nil } return versionStr.e_trimmed() } extension String { func e_trimmed() -> String { return stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) } } 
0
09 . '16 1:08
source share

3:

, :

  let object = Bundle.main.infoDictionary?["CFBundleShortVersionString"] let version = object as! String print("version: \(version)") 
0
21 . '17 6:24
source share

. Swift 4 Alamofire .

 import Alamofire class VersionCheck { public static let shared = VersionCheck() func isUpdateAvailable(callback: @escaping (Bool)->Void) { let bundleId = Bundle.main.infoDictionary!["CFBundleIdentifier"] as! String Alamofire.request("https://itunes.apple.com/lookup?bundleId=\(bundleId)").responseJSON { response in if let json = response.result.value as? NSDictionary, let results = json["results"] as? NSArray, let entry = results.firstObject as? NSDictionary, let appStoreVersion = entry["version"] as? String, let installedVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String { if let installed = Int(installedVersion.replacingOccurrences(of: ".", with: "")), let appStore = Int(appStoreVersion.replacingOccurrences(of: ".", with: "")), appStore > installed { callback(true) } } } } } 

:

 VersionCheck.shared.isUpdateAvailable() { (hasUpdates) in print("is update available: \(hasUpdates)") } 
0
24 . '19 8:59
source share

AppStore

swift 3.0

 func appUpdateAvailable() -> Bool { let storeInfoURL: String = "http://itunes.apple.com/lookup?bundleId=YOURBUNDLEID" var upgradeAvailable = false // Get the main bundle of the app so that we can determine the app version number let bundle = Bundle.main if let infoDictionary = bundle.infoDictionary { // The URL for this app on the iTunes store uses the Apple ID for the This never changes, so it is a constant let urlOnAppStore = NSURL(string: storeInfoURL) if let dataInJSON = NSData(contentsOf: urlOnAppStore! as URL) { // Try to deserialize the JSON that we got if let dict: NSDictionary = try! JSONSerialization.jsonObject(with: dataInJSON as Data, options: JSONSerialization.ReadingOptions.allowFragments) as! [String: AnyObject] as NSDictionary? { if let results:NSArray = dict["results"] as? NSArray { if let version = ((results[0] as! NSDictionary).value(forKey: "version")!) as? String { // Get the version number of the current version installed on device if let currentVersion = infoDictionary["CFBundleShortVersionString"] as? String { // Check if they are the same. If not, an upgrade is available. print("\(version)") if version != currentVersion { upgradeAvailable = true } } } } } } } return upgradeAvailable } 
-5
05 . '17 11:30
source share



All Articles