Reputation: 6082
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
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
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
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
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
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
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:
Upvotes: 1