Check if my app has a new version on AppStore

123,570

Solution 1

Here is a simple code snippet 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 app you are releasing. If not then the above code will always return YES regardless if the user updates.

Solution 2

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: "https://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 is better to throw an error instead of returning false, in this case I created a VersionError but it can be some other you define or NSError

enum VersionError: Error {
    case invalidResponse, invalidBundleInfo
}

Also consider to call 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 block a thread, 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: "https://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)
    }
}

Solution 3

Simplified a great answer posted on this thread. Using Swift 4 and 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 versionStore = entry["version"] as? String, let versionLocal = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
        let arrayStore = versionStore.split(separator: ".").compactMap { Int($0) }
        let arrayLocal = versionLocal.split(separator: ".").compactMap { Int($0) }

        if arrayLocal.count != arrayStore.count {
          callback(true) // different versioning system
          return
        }

        // check each segment of the version
        for (localSegment, storeSegment) in zip(arrayLocal, arrayStore) {
          if localSegment < storeSegment {
            callback(true)
            return
          }
        }
      }
      callback(false) // no new version or failed to fetch app store version
    }
  }
  
}

And then to use it:

VersionCheck.shared.isUpdateAvailable() { hasUpdates in
  print("is update available: \(hasUpdates)")
}

Solution 4

Updated the swift 4 code from Anup Gupta

I have made some alterations to this code. Now the functions are called from a background queue, since the connection can be slow and therefore block the main thread.

I also made the CFBundleName optional, since the version presented had "CFBundleDisplayName" which didn't work probably in my version. So now if it's not present it won't crash but just won't display the App Name in the alert.

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 for also adding the confirmation button:

AppUpdater.shared.showUpdate(withConfirmation: true)

Or call it to be called like this to have the force update option on:

AppUpdater.shared.showUpdate(withConfirmation: false)

Solution 5

Since I was facing the same problem, I found the answer provided by Mario Hendricks. Unfornatelly when I tryed to aply his code on my project, XCode did complain about Casting problems saying "MDLMaterialProperty has no subscript members". His code was trying to set this MDLMaterial... as the type of the constant "lookupResult", making the casting to "Int" failing every single time. My solution was to provide a type annotation for my variable to NSDictionary to be clear about the kind of value I needed. With that, I could access the value "version" that I needed.

Obs: For this YOURBUNDLEID, you can get from your Xcode project.... "Targets > General > Identity > Bundle Identifier"

So here is the my code with some simplifications as well:

  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's 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
}

All suggestions for improvement of this code are welcome!

Share:
123,570
user542584
Author by

user542584

Updated on April 22, 2022

Comments

  • user542584
    user542584 about 2 years

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

    • Pangolin
      Pangolin almost 13 years
      You could put a random page on a web-server which only returns a string representation of the latest version. Download it and compare upon app startup and notify the user. (Quick and easy way)
    • user542584
      user542584 almost 13 years
      thanks, but I was hoping for a better solution like some sort of API with which I can call the app store functionalities, like search for my app number and get the version data. Saves time to maintain a webserver just for this purpose, but thanks for the pointer anyway!
    • Andrew
      Andrew almost 13 years
      I do the same thing as the first comment. I wrote a plist with one entry: an NSNumber version number. Then I uploaded it to my website. The same website I use for my app support and app webpages, then in viewDidLoad, I check the website for the version number there and I check the current version in my app. Then I have a premade alertView that automatically prompts to update the app. I can provide code if you would like.
    • user542584
      user542584 almost 13 years
      thanks, I guess I should try that too..
    • Stefanos Christodoulides
      Stefanos Christodoulides almost 3 years
      I have implemented a solution using Google Firebase. I use remoteConfig to hold a value of the required version and when the app opens I cross check the version of the app with the version which is set to the Firebase. If the version of the app is smaller than the version of the Firebase I show the user an alert. This way I can have on demand force update of the application.
    • Leo Dabus
      Leo Dabus about 2 years
      Better to use Swift native type OperatingSystemVersion Compare app versions after update using decimals like 2.5.2
  • Steve Moser
    Steve Moser about 12 years
    You can check the App Store directly for Version number instead of hosting a plist file somewhere. Check out this answer: stackoverflow.com/a/6569307/142358
  • Nick Lockwood
    Nick Lockwood about 12 years
    iVersion now uses the app store version automatically - the Plist is optional if you want to specify different release notes to the ones on iTunes, but you don't need to use it.
  • S.J
    S.J about 10 years
    very good and correct solution, just little update regarding the url is itunes.apple.com/en/lookup?bundleId=xxxxxxxxxx
  • Roozbeh Zabihollahi
    Roozbeh Zabihollahi about 10 years
    Thanks, your comment applied
  • Sanjay Changani
    Sanjay Changani about 9 years
    super solution I ever Found +1
  • Mobeen Afzal
    Mobeen Afzal over 8 years
    This solution is not considered to be best or Super as it has one FLAW in it. e.g. if you have live version 1.0 on store and you want to update new version you submitted 1.1 so if it approves it will work good but in the case if you see 1.1 has some bug or crash or apple rejected it then you need to update to 1.2 so after 1.0 your version on store is 1.2 in this way it always return TRUE and show notify even user downloads the latest version.
  • datinc
    datinc over 8 years
    @MobeenAfzal, I think you miss understood the question and solution. The above solution compares the current version with the version on the store. If they do not match then it retunes YES, else it returns NO. No matter the history on the app store the above method will return YES if the current version is different then the app store version. Once the user updates... the current version is equal to the app store version. The above method should always return YES if the user's version is 1.0 and the app store version is 1.2.
  • Mobeen Afzal
    Mobeen Afzal over 8 years
    @datinc yes, obviously it always return yes and that is what the problem is.The problem is you push the new version with CFBundleversion 1.7 from code and you have in itunes like 1.6 version. It means according to itunes your version is latest and according to code you already use 1.6 so you cannot upload it will be redundant binary and on itunes you have to made 1.6 because past was 1.5. so in this case even latest version is live but it always return YES YES and all the logic based on YES will always stay.
  • datinc
    datinc over 8 years
    @MobeenAfzal I think I get what you are seeing. In code your version is 1.7, But in iTunes you uploaded the version as 1.6 so that your users don't know you skipped a version. Is that the case? If so then... what you need is a server (DropBox would do) to serve your apps version number and modify your code to access that endpoint. Let me know if this is what you are seeing and I will add a note of warning to the post.
  • Mobeen Afzal
    Mobeen Afzal over 8 years
    @datinc yes I know for that i need to implement Proper version controlling.Your solution will work best if the versions will always be 1 time greater then the previous version. if the gap increases from 1 it will stuck to true always. :) Cheers.
  • datinc
    datinc over 8 years
    @MobeenAfzal you your comment is misleading. If the version on the user's device is separated by any from the version on the appstore then the code will return YES as expected. Even if you release version 1.0 followed by version 1.111 it would still work perfectly.
  • Mobeen Afzal
    Mobeen Afzal over 8 years
    @datinc I know it will return yes. Itunes version 1.1 Code version 1.3 It always Return TRUE, because bundle version will be 1.1 and in code it will be 1.3 it can never be synced and get true and all the logic on that functionality will always APPEAR even if no more version is available to download from appstore. I hope I it is clear now
  • Lukasz Czerwinski
    Lukasz Czerwinski over 8 years
    Will this work for beta versions in Testflight? If not, is there any tool that will?
  • emotality
    emotality over 8 years
    No it will not, it only compares the current version with the latest version that is on the AppStore.
  • Itachi
    Itachi about 8 years
    I tried to open the destination url with a common bundld id in chrome for mac, it said "errorMessage":"Invalid value(s) for key(s): [country]", "queryParameters":{"output":"json", "callback":"A javascript function to handle your search results", "country":"ISO-2A country code", "limit":"The number of search results to return", "term":"A search string", "lang":"ISO-2A language code"}"
  • gasparuff
    gasparuff almost 8 years
    Actually it didn't work for me with the /en/ subpath. After removing it, it worked
  • iamthevoid
    iamthevoid over 7 years
    storeInfoURL is the url of app in appstore?
  • George Asda
    George Asda over 7 years
    @Mario Hendricks this is not working in swift 3. It throws some errors. Can you please update for swift 3?
  • Nitesh Borad
    Nitesh Borad about 7 years
    We should show update only when appstore version is greater than current version as follows. if ([appStoreVersion compare:currentVersion options:NSNumericSearch] == NSOrderedDescending) { NSLog(@"\n\nNeed to update. Appstore version %@ is greater than %@",appStoreVersion, currentVersion); }
  • uliwitness
    uliwitness about 7 years
    This answer makes its request synchronously. This means with a bad connection, your app could be unusable for minutes until the request returns.
  • uliwitness
    uliwitness about 7 years
    This answer makes its request synchronously. This means with a bad connection, your app could be unusable for minutes until the request returns.
  • uliwitness
    uliwitness about 7 years
    This answer makes its request synchronously. This means with a bad connection, your app could be unusable for minutes until the request returns.
  • uliwitness
    uliwitness about 7 years
    This answer makes its request synchronously. This means with a bad connection, your app could be unusable for minutes until the request returns.
  • uliwitness
    uliwitness about 7 years
    This answer makes its request synchronously. This means with a bad connection, your app could be unusable for minutes until the request returns.
  • uliwitness
    uliwitness about 7 years
    This answer makes its request synchronously. This means with a bad connection, your app could be unusable for minutes until the request returns.
  • uliwitness
    uliwitness about 7 years
    This answer makes its request synchronously. This means with a bad connection, your app could be unusable for minutes until the request returns.
  • uliwitness
    uliwitness about 7 years
    This answer makes its request synchronously. This means with a bad connection, your app could be unusable for minutes until the request returns.
  • uliwitness
    uliwitness about 7 years
    This code could use some improvements, but is a lot better than the other answers that send a synchronous request. Still, the way it does threading is bad style. I'll file issues on Github.
  • byJeevan
    byJeevan about 7 years
    Thanks for keeping this question alive :-)
  • juanjo
    juanjo about 7 years
    I disagree, DispatchQueue.global() gives you a background queue, the data is loaded in that queue and only goes back to the main queue when the data is loaded.
  • uliwitness
    uliwitness about 7 years
    Whoops. Somehow I overlooked that second code snippet. Sadly, it seems I can't remove the downvote until your answer is edited again :-( BTW - Given dataWithContentsOfURL: actually goes through NSURLConnection's synchronous calls, which in turn just start an async thread and block, it'd probably be less overhead to just use the asynchronous NSURLSession calls. They'd even call you back on the main thread once you're done.
  • Kiran Jadhav
    Kiran Jadhav almost 7 years
    @juanjo,,,, not working for swift 3.0.1 , please can u upload updated for swift ???
  • juanjo
    juanjo almost 7 years
    Is working for me with swift 3.1, what is the error?
  • Ryan Heitner
    Ryan Heitner over 6 years
    Note if you are only listed in a specific store I have found that you need to add a country code to the URL - eg GB itunes.apple.com/(countryCode)/…)
  • Pramod
    Pramod over 6 years
    super solution +1
  • leshow
    leshow over 6 years
    NSURLSession works on background threads automatically unless we specify otherwise.
  • JAL
    JAL over 6 years
    Links to an existing answer are not answers. Additionally, links to libraries are also not answers unless you explicitly add how the link answers the question to your answer (add code examples, etc).
  • Jigar
    Jigar about 6 years
    @Yago Zardo please use compare function otherwise when user upload app.apple tested time display update alertview or apple reject your app
  • Jigar
    Jigar about 6 years
    please use compare function otherwise when user upload app.apple tested time display update alertview or apple reject your app
  • Yago Zardo
    Yago Zardo about 6 years
    Hey @Jigar, thanks for the advice. I'm currently not using this method anymore on my app because now we are versioning everything in our server. Anyway, could you explain better what you said? I did not understand and it really looks a good thing to know. Thanks in advance.
  • Yago Zardo
    Yago Zardo about 6 years
    Thank you @uliwitness for the tip, it really helped me to improve my code in general to learn about asynchronous and synchronous requests.
  • jessi
    jessi about 6 years
    Where did you put this code? II see that you set LookupResult and AppInfo to decodable, but I don't see them saved anywhere. What am I missing here?
  • juanjo
    juanjo about 6 years
    You declare the LookupResult and AppInfo classes somewhere in your project, in a separate file preferably: They are used when you decode the response: JSONDecoder().decode(LookupResult.self, from: data) and they contain the version string
  • Anup Gupta
    Anup Gupta about 6 years
    Based on your answer I create One file using your code Please check that iOS-Swift-ArgAppUpdater
  • Anup Gupta
    Anup Gupta about 6 years
    @jessi please check My code on GitHub I posted there your solution
  • Anup Gupta
    Anup Gupta almost 6 years
    @Rob Please Check GitHub Link github.com/anupgupta-arg/iOS-Swift-ArgAppUpdater
  • Joris Mans
    Joris Mans almost 6 years
    This crashes when you have no internet connection. let data = try? Data(contentsOf: url!) will return nil, and in the next line you do data!
  • Kassem Itani
    Kassem Itani almost 6 years
    thx @JorisMans I will update it for no internet connectivity crash
  • JAL
    JAL almost 6 years
    Don't do this. Use URLSession.
  • B3none
    B3none over 5 years
    That link is a gem!
  • adamjansch
    adamjansch over 5 years
    Love that pyramid. (Take a look at using guard instead of if.)
  • David Rector
    David Rector over 5 years
    Any ideas on how to test this? If it fails to work right, the only way to debug it is to somehow debug an older version than is in the app store.
  • David Rector
    David Rector over 5 years
    Ah, never mind the question. I can simply change my local version to be "older".
  • Master AgentX
    Master AgentX about 5 years
    I'm impressed with your code @Vasco. Just a simple question, why you have used 'http' instead of https in that url?
  • budiDino
    budiDino almost 5 years
    problem with using ourVersion != appVersion is that it triggers when the App Store Review team checks the new version of the app. We convert those version strings to numbers and then isNew = appVersion > ourVersion.
  • Northern Captain
    Northern Captain almost 5 years
    @budidino you are right, I just showed the common approach using Alamofire. How you interpret the version is totally dependent on your app and version structure.
  • technerd
    technerd almost 5 years
    My application is live on store but same api not returning version information. Response :{ "resultCount":0, "results": [] }
  • mc_plectrum
    mc_plectrum over 4 years
    Thanks a lot for sharing this solution @Vasco! I like it :) Why do you not use: let config = URLSessionConfiguration.background(withIdentifier: "com.example.MyExample.background") for the URLSession to achieve the background request?
  • mc_plectrum
    mc_plectrum over 4 years
    You can also get rid of the force unwrap, as you check already if if let appStoreAppVersion = info?.version and same for the trackURL.
  • Muju
    Muju over 4 years
    @juanjo your code is working. But I have one problem when the update is available I want to redirect it to loginVC How can I do that
  • juanjo
    juanjo over 4 years
    Hi, that depends on the structure of your controllers, I recommend you to ask another question to solve that and change the code inside the isUpdateAvailable completion closure
  • Fernando Perez
    Fernando Perez over 4 years
    I had to use with the /en/ itunes.apple.com/lookup?bundleId=xxxxxxx, thanks @gasparuff
  • Chaitu
    Chaitu about 4 years
    Just adding a note to version comparision, I would prefer, let serverVersion = "2.7" let localVersion = "2.6.5" let isUpdateAvailable = serverVersion.compare(localVersion, options: .numeric) == .orderedDescending rather than replacing the . with empty.
  • Chaitu
    Chaitu about 4 years
    Just adding a note to version comparision, I would prefer, let serverVersion = "2.7" let localVersion = "2.6.5" let isUpdateAvailable = serverVersion.compare(localVersion, options: .numeric) == .orderedDescending rather than comparing with equal
  • budiDino
    budiDino about 4 years
    @Chaitu thank you for the suggestion. I ended up rewriting the comparison part of the code
  • Zorayr
    Zorayr almost 4 years
    Could we use this with Swift?
  • Zorayr
    Zorayr almost 4 years
    The project is now deprecated 😢
  • Itachi
    Itachi over 3 years
    Actually it's not a numeric style version always, so it should expose the version comparison outside.
  • emotality
    emotality over 3 years
    @Itachi it was 5.5 years ago :) Package is not even being maintained anymore..
  • Markv07
    Markv07 about 3 years
    I just tested this in swift 5. It works well. I am currious how to know .version is the version available from the App Store (Bundle.main.InfoDictionary)? or how to know the CFBundleVersionString is the current app plist version number? I can't make sense of apple documentation. It would be nice to know if there are other fields that could be used from the App Store, such as what is the description of changes in the new version. That would help the user know if they should update. But thats not in any plist so probably not available..
  • Genevios
    Genevios almost 3 years
    Do you know what happened if AppStore get info with old version of app? I already clean cache but no one result. in JSON file new version but Apple give old version by key [result][0][version]
  • Admin
    Admin over 2 years
    Please add further details to expand on your answer, such as working code or documentation citations.
  • Libor Zapletal
    Libor Zapletal over 2 years
    There should be return after some callbacks.
  • budiDino
    budiDino over 2 years
    @LiborZapletal thanks. Fixed the issue and also updated the code a bit
  • Laszlo
    Laszlo over 2 years
    instead of _ = you should always add @discardableResult for the function.
  • Awais Fayyaz
    Awais Fayyaz over 2 years
    I am facing a very weird issue. If i use the http version of the URL, it is returning me previous version which was uploaded on the App Store. However, if i use the https version of the url, the version is correct. Does any one know what might be the reason ?
  • stackich
    stackich over 2 years
    Looks like this code returns only first two numbers of app version, for example: If its a 1.2.3 version on the App Store, the code will return just 1.2. Is there a way to get the last number too? Tnx.
  • stackich
    stackich over 2 years
    pozz @budiDino. Looks like this code returns only first two numbers of app version, for example: If its a 1.2.3 version on the App Store, the code will return just 1.2. Is there a way to get the last number too? Tnx.
  • budiDino
    budiDino over 2 years
    @stackich did you try checking the "version" returned from the itunes API: https://itunes.apple.com/lookup?bundleId=\(bundleId) and also your local version: Bundle.main.infoDictionary?["CFBundleShortVersionString"]? Not sure why any of those would return just first two segments if 3 segments exist :/
  • stackich
    stackich over 2 years
    @budiDino my fault. I made a mistake putting http instead of https in iTunes url. The http works but somehow returns the previous version of my app which was in my case without 3 segments(only two). Seems like switching to https kinda removes cache and returns the latest app version. Thanks however :)
  • Aloha
    Aloha over 2 years
    @Laszlo thanks for the heads up