Govaadiyo
Govaadiyo

Reputation: 6082

iOS not getting accurate App version from iTunes

Actually Just want to implement functionality like if new version of the app is available on AppStore then end user will be notified for update the App.

There are so many answers on google but look at below my code.

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/in/lookup?bundleId=\(identifier)") else {
                throw VersionError.invalidBundleInfo
        }
        print(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]
                 if let a = ((json?["results"] as? [Any])?.first) as? [String: Any] {
                print(a["version"] as? String ?? "")
            }
                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
    }

and calling this function

 _ = try? appDelegate.isUpdateAvailable { (update, error) in
            if let error = error {
                print(error)
            } else if let update = update {
                if update {
                    let alert = UIAlertController(title: "New Version Available", message: "New version of application is available please update now!", preferredStyle: UIAlertControllerStyle.alert)
                    alert.addAction(UIAlertAction(title: "Update", style: .default, handler: { (actionOk) in

                        if let url = URL(string: "itms-apps://itunes.apple.com/app/idXXXXXXXXX"),
                            UIApplication.shared.canOpenURL(url){
                            UIApplication.shared.open(url, options: [:])
                        }
                    }))
                    self.present(alert, animated: true, completion: nil)
                }
            }
        }

Problem is that If new version of app is ready to sell and I open old version of app then popup will open and when I click on update button, It will redirect on AppStore. But on AppStore rather then display "Update" button, it display "Open" button

So I checked in my code.

When I run below URL manually on browser

http://itunes.apple.com/in/lookup?bundleId=com.mycompany.appname

Then download .txt file and got accurate App version But In my code print(a["version"] as? String ?? "") it returns wrong version number.

Where I'm going wrong? Please correct me.

NOTE: I also used http://itunes.apple.com/lookup?bundleId=com.mycompany.appname means removed country code from URL but not worked for me.

Upvotes: 4

Views: 2125

Answers (6)

Aravind
Aravind

Reputation: 32

You can now use data and time along with the url to get upto date result

http://itunes.apple.com/in/lookup?bundleId=com.mycompany.appname&_=${newDate().getTime()}

Upvotes: 0

Igor Jorin
Igor Jorin

Reputation: 191

My solution for delaying up-to-date version information of the app is...

class AppVersion {
    let major   :Int
    let middle  :Int
    let minor   :Int
    
    internal init(major: Int, middle: Int, minor: Int) {
        self.major = major
        self.middle = middle
        self.minor = minor
    }
    
    convenience init?(withString string:String) {
        let clearString = string.replacingOccurrences(of: " ", with: "")
        var digitsArray = clearString.components(separatedBy: ".")
        AppVersion.appendDigitsIfRequired(data: &digitsArray)
        if digitsArray.count != 3 {return nil}
        guard let major = Int(digitsArray[0]), let middle = Int(digitsArray[1]), let minor = Int(digitsArray[2]) else {
            return nil
        }
        self.init(major: major, middle: middle, minor: minor)
    }
    
    private static func appendDigitsIfRequired(data: inout [String]) {
        if data.count >= 3 {return}
        if data.count == 1 {
            data.append("0")
            data.append("0")
        }
        if data.count == 2 {
            data.append("0")
        }
    }
    
    fileprivate static func isUpdateRequired(bundleVersion:AppVersion, appStoreVersion:AppVersion) -> Bool {
        if bundleVersion.major < appStoreVersion.major {
            return true
        }
        if bundleVersion.middle < appStoreVersion.middle {
            return true
        }
        if bundleVersion.minor < appStoreVersion.minor {
            return true
        }
        return false
    }
}

Usage

    guard let current = AppVersion(withString: currentVersion), let appStore = AppVersion(withString: version) else {
        return false
    }
    
    return AppVersion.isUpdateRequired(bundleVersion: current, appStoreVersion: appStore)

Upvotes: 0

Ghazi Tozri
Ghazi Tozri

Reputation: 170

If anyone still getting this problem, make sure you are doing these 3 steps:

  • Your request cache policy should be : .reloadIgnoringLocalCacheData

    urlRequest.cachePolicy = .reloadIgnoringLocalCacheData

  • Your link scheme should be https, not http

  • Calling the url "https://itunes.apple.com/lookup?bundleId=(appID)" will get you the latest update after 24H. Update your link to "https://itunes.apple.com/us/lookup?bundleId=(appID)" to get instant updates. The path /us makes a difference, it's weird i know, but it works.

Note: For the third check, if you call the general link (without /us) from web navigator, it will gives you valid version. Calling it programmatically won't. That's why you need to add the /us path.

Upvotes: 1

Jogendar Choudhary
Jogendar Choudhary

Reputation: 3494

You can try this:

   func isAppUpdateAvailable() throws -> Bool {
        let yourAppleID = "12454364536" //This is demo id, you can get your apple id for a specific app from the appinformation tab of itunesconnect account 
        guard let info = Bundle.main.infoDictionary,
            let currentVersion = info["CFBundleShortVersionString"] as? String,
            let url = URL(string: "http://itunes.apple.com/lookup?id=\(yourAppleID)") 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 {
            print("version in app store", version,currentVersion);

            return version != currentVersion
        }
        throw VersionError.invalidResponse
    }

This is check for sending it on appstore: //This is you appstore URL of respective app, you can direct put your appstore URL here

 let appStoreURl = "https://itunes.apple.com/sg/app/AppName/idXXXXXXXXXX?ls=1&mt=8"
 if let url = URL(string: appStoreURl),
                                UIApplication.shared.canOpenURL(url){
    UIApplication.shared.open(url, options: [:])
 }

Upvotes: 2

iPatel
iPatel

Reputation: 47099

This is headache issue for all iOS Developer to detect version of the App and notify to users for new update. BTW @Cœur and @Alexis O explained well so I don't think to explain more. Just follow my code.

By calling below URL you will be got .txt file

http://itunes.apple.com/in/lookup?bundleId=com.mycompany.appname

In the file you also will find currentVersionReleaseDate, Use this data and time and compare with current date and time if it is grater then 24 hours? then you should display popup for update the App.

Changed your code:

if let a = ((json?["results"] as? [Any])?.first) as? [String: Any] {
                    print(a["version"] as? String ?? "")
                    let currentVersionDate = a["currentVersionReleaseDate"] as? String ?? ""
                    let dateFormatter = DateFormatter()
                    dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
                    dateFormatter.locale = Locale(identifier: "en_US_POSIX")

                    if let myDate = dateFormatter.date(from: currentVersionDate) {
                        let diff = Calendar.current.dateComponents([.hour], from: myDate, to: Date()).hour ?? 0
                        if diff < 24 {
                            completion(false, nil)
                            return
                        }
                    }
                }

Changed in If statement . Check it.

Upvotes: 2

Alexis O
Alexis O

Reputation: 282

Your code looks correct. As Coeur said, Apple puts out the new update gradually and it won't be immediate. The update is usually finished after 24 hours.

Personally, I won't go with this approach. It's better to fetch the version from your server and you can update that value after 24 hours when the App is released. You'll have more control over it. Supposedly your new app is buggy. You have a choice of not prompting your user to update to that version.

Side tip:

  • Make sure you only show the popup once.
  • Don't show the popup if server version is lower. Another freedom to support "not" prompting the user to update.

Upvotes: 1

Related Questions