Uygulamamın AppStore'da yeni bir sürümü olup olmadığını kontrol edin


114

Kullanıcı içindeyken uygulamam için yeni güncellemelerin olup olmadığını manuel olarak kontrol etmek ve ondan yeni sürümü indirmesini istemek istiyorum. Bunu, programlı olarak uygulama mağazasında uygulamamın sürümünü kontrol ederek yapabilir miyim?


7
Bir web sunucusuna, yalnızca en son sürümün dize temsilini döndüren rastgele bir sayfa koyabilirsiniz. İndirin ve uygulama başlangıcında karşılaştırın ve kullanıcıyı bilgilendirin. (Hızlı ve kolay yol)
LouwHopley

1
teşekkürler, ancak uygulama numaramı aramak ve sürüm verilerini almak gibi uygulama mağazası işlevlerini arayabileceğim bir tür API gibi daha iyi bir çözüm umuyordum. Sadece bu amaç için bir web sunucusunu korumak için zaman kazandırır, ancak yine de işaretçi için teşekkürler!
user542584

İlk yorumla aynı şeyi yapıyorum. Tek girişli bir plist yazdım: NSNumbersürüm numarası. Sonra web siteme yükledim. Uygulama desteğim ve uygulama web sayfalarım için kullandığım aynı web sitesi, daha sonra viewDidLoad, oradaki sürüm numarası için web sitesini kontrol ediyorum ve uygulamamdaki mevcut sürümü kontrol ediyorum. Ardından alertView, uygulamayı otomatik olarak güncellememi isteyen bir hazırım var. İsterseniz kod sağlayabilirim.
Andrew

teşekkürler, sanırım bunu da denemeliyim ..
user542584

Yanıtlar:


89

İşte mevcut sürümün farklı olup olmadığını bilmenizi sağlayan basit bir kod parçacığı

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

Not: iTunes'a yeni sürümü girdiğinizde bunun, yayınladığınız uygulamadaki sürümle eşleştiğinden emin olun. Aksi takdirde, yukarıdaki kod, kullanıcı güncelleme yapıp yapmadığına bakılmaksızın her zaman YES döndürür.


4
bulduğum süper çözüm +1
Sanjay Changani

1
@MobeenAfzal, soruyu ve çözümü anlamayı özlediğini düşünüyorum. Yukarıdaki çözüm, mevcut sürümü mağazadaki sürümle karşılaştırır. Eşleşmezlerse EVET'i yeniden açar, aksi takdirde HAYIR döndürür. Uygulama mağazasındaki geçmiş ne olursa olsun, yukarıdaki yöntem, geçerli sürüm uygulama mağazası sürümünden farklıysa EVET döndürür. Kullanıcı güncelledikten sonra ... mevcut sürüm, uygulama mağazası sürümüne eşittir. Kullanıcının sürümü 1.0 ve uygulama mağazası sürümü 1.2 ise yukarıdaki yöntem her zaman YES döndürmelidir.
tarih

1
@MobeenAfzal Gördüğünü anladığımı düşünüyorum. Kodda sürümünüz 1.7'dir, ancak iTunes'da sürümü 1.6 olarak yüklediniz, böylece kullanıcılarınız bir sürümü atladığınızı bilmiyor. Durum bu mu? Öyleyse, ihtiyacınız olan şey, uygulamalarınızın sürüm numarasını sunmak ve bu uç noktaya erişmek için kodunuzu değiştirmek için bir sunucudur (DropBox yapardı). Gördüğünüz şey buysa bana haber verin, gönderiye bir uyarı notu ekleyeceğim.
tarih

1
@MobeenAfzal yorumunuz yanıltıcı. Kullanıcının cihazındaki sürüm, uygulama mağazasındaki sürümden herhangi biriyle ayrılmışsa, kod beklendiği gibi EVET'i döndürecektir. 1.0 sürümünü ve ardından 1.111 sürümünü yayınlasanız bile, yine de mükemmel şekilde çalışır.
datinc

1
Güncellemeyi yalnızca aşağıdaki gibi appstore sürümü mevcut sürümden daha büyük olduğunda göstermeliyiz. if ([appStoreVersion Compare: currentVersion options: NSNumericSearch] == NSOrderedDescending) {NSLog (@ "\ n \ nGüncelleme gerekiyor. Appstore sürümü% @,% @ 'den büyük, appStoreVersion, currentVersion); }
Nitesh Borad

52

Swift 3 versiyonu:

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
}

Yanlış döndürmek yerine bir hata atmanın daha iyi olacağını düşünüyorum, bu durumda bir VersionError oluşturdum ama sizin tanımladığınız başka bir hata veya NSError olabilir

enum VersionError: Error {
    case invalidResponse, invalidBundleInfo
}

Ayrıca bu işlevi başka bir iş parçacığından çağırmayı da düşünün, bağlantı yavaşsa mevcut iş parçacığını engelleyebilir.

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

Güncelleme

URLSession Kullanımı:

Data(contentsOf: url)Bir iş parçacığı kullanmak ve engellemek yerine kullanabiliriz 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
}

misal:

_ = try? isUpdateAvailable { (update, error) in
    if let error = error {
        print(error)
    } else if let update = update {
        print(update)
    }
}

1
Bu cevap, isteğini eşzamanlı olarak yapar. Bu, kötü bir bağlantıyla, istek geri dönene kadar uygulamanızın dakikalarca kullanılamayacağı anlamına gelir.
uliwitness

4
Katılmıyorum, DispatchQueue.global()size bir arka plan kuyruğu verir, veriler bu kuyruğa yüklenir ve yalnızca veri yüklendiğinde ana kuyruğa geri döner.
juanjo

Hata. Bir şekilde o ikinci kod parçacığını gözden kaçırdım. Maalesef, cevabınız tekrar düzenlenene kadar olumsuz oyu kaldıramayacağım gibi görünüyor :-( BTW - Verilen dataWithContentsOfURL: aslında NSURLConnection'ın eşzamanlı çağrılarından geçiyor, bu da sırayla bir eşzamansız iş parçacığı ve blok başlatıyor, muhtemelen daha az ek yük olacak sadece eşzamansız NSURLSession çağrılarını kullanmak için.
İşiniz

@juanjo ,,,, hızlı 3.0.1 için çalışmıyor, lütfen hızlı için güncellenmiş yükleyebilir misiniz ???
Kiran jadhav

2
Not: Yalnızca belirli bir mağazada listelenmişseniz, URL'ye bir ülke kodu eklemeniz gerektiğini fark ettim - örneğin, GB itunes.apple.com/(countryCode)/… )
Ryan Heitner

13

Steve Moser'a bağlantısı için teşekkürler, işte kodum:

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"];

1
çok iyi ve doğru çözüm, url ile ilgili sadece küçük bir güncelleme itunes.apple.com/en/lookup?bundleId=xxxxxxxxxx
SJ

Teşekkürler, yorumunuz uygulandı
Roozbeh Zabihollahi

4
Aslında /en/alt yolda benim için işe yaramadı .
Çıkardıktan

Bu cevap, isteğini eşzamanlı olarak yapar. Bu, kötü bir bağlantıyla, istek geri dönene kadar uygulamanızın dakikalarca kullanılamayacağı anlamına gelir.
uliwitness

1
/ En / itunes.apple.com/lookup?bundleId=xxxxxxx ile kullanmak zorunda kaldım , teşekkürler @gasparuff
Fernando Perez

13

Aynı problemle karşılaştığım için Mario Hendricks tarafından verilen cevabı buldum . Ne yazık ki kendi kodunu projeme uygulamaya çalıştığımda, XCode "MDLMaterialProperty'nin alt simge üyeleri yok" diyerek Döküm sorunları hakkında şikayet etti. Onun kodu, bu MDLMaterial'ı "lookupResult" sabitinin türü olarak ayarlamaya çalışıyordu ve her seferinde "Int" atamasının başarısız olmasına neden oluyordu. Benim çözümüm, ihtiyacım olan değerin türü hakkında net olmak için değişkenimin NSDictionary için bir tür ek açıklaması sağlamaktı . Bununla, ihtiyacım olan "versiyon" değerine erişebildim.

Gözlem : Bunun için YOURBUNDLEID , Xcode projenizden alabilirsiniz .... " Hedefler> Genel> Kimlik> Paket Tanımlayıcı "

İşte bazı basitleştirmelerle birlikte benim kodum:

  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
}

Bu kodun iyileştirilmesi için tüm önerilere açığız!


Bu cevap, isteğini eşzamanlı olarak yapar. Bu, kötü bir bağlantıyla, istek geri dönene kadar uygulamanızın dakikalarca kullanılamayacağı anlamına gelir.
uliwitness

@Yago Zardo, aksi takdirde, kullanıcı app.apple test zamanını görüntülediğinde veya apple uygulamanızı reddettiğinde karşılaştırma işlevini kullanın
Jigar Darji

Hey @Jigar, tavsiye için teşekkürler. Şu anda bu yöntemi uygulamamda kullanmıyorum çünkü şimdi sunucumuzdaki her şeyin versiyonunu oluşturuyoruz. Neyse, söylediklerini daha iyi açıklayabilir misin? Anlamadım ve gerçekten bilmek güzel görünüyor. Şimdiden teşekkürler.
Yago Zardo

Teşekkürler @uliwitness bahşiş için, asenkron ve senkronize istekler hakkında bilgi edinmek için genel olarak kodumu geliştirmeme gerçekten yardımcı oldu.
Yago Zardo

Bu bağlantı bir mücevher!
B3none

13

ATAppUpdater'ı kullanmanız yeterlidir . 1 satır, iş parçacığı güvenli ve hızlıdır. Ayrıca, kullanıcı eylemini izlemek istiyorsanız, temsilci yöntemlerine de sahiptir.

İşte bir örnek:

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

   return YES;
}

İsteğe bağlı temsilci yöntemleri:

- (void)appUpdaterDidShowUpdateDialog;
- (void)appUpdaterUserDidLaunchAppStore;
- (void)appUpdaterUserDidCancel;

1
Bu, Testflight'taki beta sürümleri için çalışacak mı? Değilse, işe yarayacak herhangi bir araç var mı?
Lukasz Czerwinski

Hayır olmaz, sadece mevcut sürümü AppStore'daki en son sürümle karşılaştırır.
emotality

Bunu Swift ile kullanabilir miyiz?
Zorayr

11

Bu ileti dizisinde yayınlanan harika bir yanıt basitleştirildi . Kullanılması Swift 4ve 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: ".")
        let arrayLocal = versionLocal.split(separator: ".")

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

        // check each segment of the version
        for (key, value) in arrayLocal.enumerated() {
          if Int(value)! < Int(arrayStore[key])! {
            callback(true)
          }
        }
      }
      callback(false) // no new version or failed to fetch app store version
    }
  }

}

Ve sonra kullanmak için:

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

2
Uygulamam mağazada yayında, ancak aynı api sürüm bilgilerini döndürmüyor. Yanıt:{ "resultCount":0, "results": [] }
technerd

Sadece sürüm karşılaştırmasına bir not ekleyerek, tercih ederim, izin vermek için serverVersion = "2.7" let localVersion = "2.6.5" let isUpdateAvailable = serverVersion.compare (localVersion, options: .numeric) == .orderedDescending yerine. boş.
Chaitu

@Chaitu öneri için teşekkür ederim. Kodun karşılaştırma kısmını yeniden
yazdım

9

Anup Gupta'nın Swift 4 kodu güncellendi

Bu kodda bazı değişiklikler yaptım . Bağlantı yavaş olabileceğinden ve bu nedenle ana iş parçacığını engelleyebileceğinden artık işlevler bir arka plan sırasından çağrılır.

Ayrıca CFBundleName'i isteğe bağlı yaptım, çünkü sunulan sürümde muhtemelen benim sürümümde çalışmayan "CFBundleDisplayName" vardı. Yani şimdi mevcut değilse çökmeyecek, ancak uyarıda Uygulama Adını göstermeyecek.

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 ""
        }
    }
}

Bu aramayı onay düğmesini de eklemek için yapıyorum:

AppUpdater.shared.showUpdate(withConfirmation: true)

Veya güncelleme zorla seçeneğinin açık olması için böyle çağrılsın:

AppUpdater.shared.showUpdate(withConfirmation: false)

Bunu nasıl test edeceğiniz konusunda bir fikriniz var mı? Doğru çalışmazsa, hata ayıklamanın tek yolu, uygulama mağazasında olduğundan daha eski bir sürümün hatalarını bir şekilde ayıklamaktır.
David Rektör

2
Ah, soruyu boşver. Yerel sürümümü "daha eski" olacak şekilde değiştirebilirim.
David Rektör

@Vasco kodunuzdan etkilendim. Sadece basit bir soru, neden o url'de https yerine 'http' kullandınız?
Master AgentX

Bu çözümü @Vasco paylaştığınız için çok teşekkürler! Hoşuma gitti :) Neden arka plan isteğini gerçekleştirmek için URLSession için let config = URLSessionConfiguration.background (withIdentifier: "com.example.MyExample.background") kullanmıyorsunuz?
mc_plectrum

Ayrıca, appStoreAppVersion = info? .Version ve trackURL için aynı olup olmadığını kontrol ettiğinizde, zorla sarmadan da kurtulabilirsiniz.
mc_plectrum

7

İşte Swift 4 ve popüler Alamofire kitaplığını kullanan sürümüm (yine de uygulamalarımda kullanıyorum). İstek eşzamansızdır ve tamamlandığında bildirim almak için bir geri aramayı geçebilirsiniz.

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)
        }
    }
}

Kullanımı şu şekilde basit:

VersionCheck.shared.checkAppStore() { isNew, version in
        print("IS NEW VERSION AVAILABLE: \(isNew), APP STORE VERSION: \(version)")
    }

1
ourVersion! = appVersion kullanımıyla ilgili sorun, App Store İnceleme ekibi uygulamanın yeni sürümünü kontrol ettiğinde tetiklenmesidir. Bu sürüm dizelerini sayılara ve ardından isNew = appVersion> ourVersion'a dönüştürüyoruz.
budidino

@budidino haklısın, Alamofire kullanarak ortak yaklaşımı gösterdim. Sürümü nasıl yorumlayacağınız tamamen uygulamanıza ve sürüm yapınıza bağlıdır.
Kuzey Kaptan

Sadece sürüm karşılaştırmasına bir not ekleyerek, tercih ederim, eşit ile karşılaştırmak yerine serverVersion = "2.7" let localVersion = "2.6.5" let isUpdateAvailable = serverVersion.compare (localVersion, options: .numeric) == .orderedDescending
Chaitu

6

Bu küçük kütüphaneyi önerebilir miyim: https://github.com/nicklockwood/iVersion

Amacı, bildirimleri tetiklemek için uzaktaki listelerin işlenmesini basitleştirmektir.


3
Bir yerde bir plist dosyası barındırmak yerine App Store'u doğrudan Sürüm numarası için kontrol edebilirsiniz. Bu yanıta göz atın: stackoverflow.com/a/6569307/142358
Steve Moser

1
iVersion artık uygulama mağazası sürümünü otomatik olarak kullanıyor - iTunes'dakilerden farklı sürüm notları belirtmek istiyorsanız Plist isteğe bağlıdır, ancak kullanmanız gerekmez.
Nick Lockwood

1
Bu kod bazı iyileştirmeler kullanabilir, ancak eşzamanlı istek gönderen diğer yanıtlardan çok daha iyidir. Yine de, iş parçacığı açma şekli kötü bir tarz. Github'da sorunları bildireceğim.
uliwitness

Proje artık kullanımdan kaldırıldı 😢
Zorayr

5

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
}

İnternet bağlantınız olmadığında bu kilitlenir. izin veri = dene? Veriler (contentOf: url!) Geri dönecek ve sonraki satırda veri yapacaksınız!
Joris Mans

thx @JorisMans İnternet bağlantısı çökmesi olmaması için güncelleyeceğim
Kassem Itani

Bunu yapma. Kullanın URLSession.
JAL

4

Bu cevap, datinc'in cevabının https://stackoverflow.com/a/25210143/2735358 değiştirilmesidir .

datinc'in işlevi, sürümü dize karşılaştırmasına göre karşılaştırır. Bu nedenle, sürümü daha büyük veya daha küçük için karşılaştırmayacaktır.

Ancak, bu değiştirilmiş işlev sürümü NSNumericSearch ile karşılaştırır (sayısal karşılaştırma) .

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

Kullanım:

[self checkForUpdateWithHandler:^(BOOL isUpdateAvailable) {
    if (isUpdateAvailable) {
        // show alert
    }
}];

3
Bu cevap, isteğini eşzamanlı olarak yapar. Bu, kötü bir bağlantıyla, istek geri dönene kadar uygulamanızın dakikalarca kullanılamayacağı anlamına gelir.
uliwitness

NSURLSession, aksini belirtmedikçe arka plan iş parçacıklarında otomatik olarak çalışır.
Sebastian Dwornik

4

Uygulama güncellemesini kontrol etmenin birçok yolunu gördüm. Bu yüzden birçok cevaba dayanarak onları karıştırıyorum ve GitHub'da bulunan çözümümü oluşturuyorum Herhangi bir güncelleme gerekiyorsa lütfen bana bildirin. Swift 4 için bu kod

GitHub bağlantısı Bu koda. 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)
    }
}

Referans: https://stackoverflow.com/a/48810541/5855888 Ve https://github.com/emotality/ATAppUpdater

Mutlu Kodlama 👍 😊


@Rob GitHub Bağlantı Kontrol Lütfen github.com/anupgupta-arg/iOS-Swift-ArgAppUpdater
Anup Gupta

3

Bunu tek bir işlev çağrısıyla deneyin:

func showAppStoreVersionUpdateAlert(isForceUpdate: Bool) {

    do {
        //Get Bundle Identifire from Info.plist
        guard let bundleIdentifire = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String else {
            print("No Bundle Info found.")
            throw CustomError.invalidIdentifires
        }

        // Build App Store URL
        guard let url = URL(string:"http://itunes.apple.com/lookup?bundleId=" + bundleIdentifire) else {
            print("Isse with generating URL.")
            throw CustomError.invalidURL
        }

        let serviceTask = URLSession.shared.dataTask(with: url) { (responseData, response, error) in

            do {
                // Check error
                if let error = error { throw error }
                //Parse response
                guard let data = responseData else { throw CustomError.jsonReading }
                let result = try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
                let itunes = ItunesAppInfoItunes.init(fromDictionary: result as! [String : Any])
                print(itunes.results)
                if let itunesResult = itunes.results.first {
                    print("App Store Varsion: ",itunesResult.version)

                    //Get Bundle Version from Info.plist
                    guard let appShortVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else {
                        print("No Short Version Info found.")
                        throw CustomError.invalidVersion
                    }

                    if appShortVersion == itunesResult.version {
                        //App Store & Local App Have same Version.
                        print("Same Version at both side")
                    } else {
                        //Show Update alert
                        var message = ""
                        //Get Bundle Version from Info.plist
                        if let appName = Bundle.main.infoDictionary?["CFBundleName"] as? String {
                            message = "\(appName) has new version(\(itunesResult.version!)) available on App Store."
                        } else {
                            message = "This app has new version(\(itunesResult.version!)) available on App Store."
                        }

                        //Show Alert on the main thread
                        DispatchQueue.main.async {
                            self.showUpdateAlert(message: message, appStoreURL: itunesResult.trackViewUrl, isForceUpdate: isForceUpdate)
                        }
                    }
                }
            } catch {
                print(error)
            }
        }
        serviceTask.resume()
    } catch {
        print(error)
    }
}

AppStore URL'sini açmak için Uyarı İşlevi:

func showUpdateAlert(message : String, appStoreURL: String, isForceUpdate: Bool) {

    let controller = UIAlertController(title: "New Version", message: message, preferredStyle: .alert)

    //Optional Button
    if !isForceUpdate {
        controller.addAction(UIAlertAction(title: "Later", style: .cancel, handler: { (_) in }))
    }

    controller.addAction(UIAlertAction(title: "Update", style: .default, handler: { (_) in
        guard let url = URL(string: appStoreURL) else {
            return
        }
        if #available(iOS 10.0, *) {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
        } else {
            UIApplication.shared.openURL(url)
        }

    }))

    let applicationDelegate = UIApplication.shared.delegate as? AppDelegate
    applicationDelegate?.window?.rootViewController?.present(controller, animated: true)

}

Yukarıdaki işlev nasıl çağrılır:

AppStoreUpdate.shared.showAppStoreVersionUpdateAlert(isForceUpdate: false/true)

Daha fazla ayrıntı için tam kod içeren aşağıdaki bağlantıyı deneyin:

AppStoreUpdate.swift

ItunesAppInfoResult.swift

ItunesAppInfoItunes.swift

Umarım bu yardımcı olur!


2

İşte bazı Objective-C yanıtlarının önerdiği şeyi yapan hızlı bir yöntem. Açıkçası, JSON uygulama mağazasından bilgi aldıktan sonra, isterseniz sürüm notlarını çıkarabilirsiniz.

func appUpdateAvailable(storeInfoURL: String) -> Bool
{
    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 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
}

storeInfoURL, uygulama mağazasındaki uygulamanın url'si mi?
iamthevoid

@Mario Hendricks bu hızlı çalışmıyor 3. Bazı hatalar atıyor. Lütfen Swift 3 için güncelleme yapabilir misiniz?
George Asda

Bu cevap, isteğini eşzamanlı olarak yapar. Bu, kötü bir bağlantıyla, istek geri dönene kadar uygulamanızın dakikalarca kullanılamayacağı anlamına gelir.
uliwitness

2

NSUrlRequest'te içerik türünü ayarlamıyorsanız, kesinlikle yanıt almayacaksınız, bu nedenle aşağıdaki kodu deneyin, benim için iyi çalışıyor. Umarım yardımcı olur....

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

Bu cevap, isteğini eşzamanlı olarak yapar. Bu, kötü bir bağlantıyla, istek geri dönene kadar uygulamanızın dakikalarca kullanılamayacağı anlamına gelir.
uliwitness

2

Bir Karma Uygulama POV'sinden geliyorsa, bu bir javascript örneğidir, ana menümde Güncelleştirilebilir bir altbilgi var. Bir güncelleme mevcutsa (yani, yapılandırma dosyasındaki sürüm numaram alınan sürümden daha azsa, altbilgiyi görüntüleyin) Bu daha sonra kullanıcıyı uygulama mağazasına yönlendirecek ve burada kullanıcı daha sonra güncelleme düğmesine tıklayabilir.

Ayrıca neyin yeni verilerini (yani Sürüm Notlarını) alırım ve bu sürümde ilk defa giriş yaptığımda bunları bir modalda görüntülerim.

Güncelleme Kullanılabilir yöntemi istediğiniz sıklıkta çalıştırılabilir. Benimki, kullanıcı ana ekrana her gittiğinde çalıştırılır.

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

}

Geri arama: Apple'ın bir API'si var, bu yüzden edinmesi çok kolay

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('&nbsp;');
        // Release Notes
        settings.updateReleaseNotes('v' + storeVersion, releaseNotes);
    }
}

2

Uyarı: Verilen yanıtların çoğu URL'yi eşzamanlı olarak alır ( -dataWithContentsOfURL:veya kullanarak -sendSynchronousRequest:. Bu kötüdür, çünkü istek devam ederken mobil bağlantı kesilirse uygulamanız birkaç dakika boyunca yanıt vermeyecektir. İnternet erişimini asla eşzamanlı olarak yapmayın. ana konu.

Doğru cevap, zaman uyumsuz API kullanmaktır:

    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];

Ağ bağlantıları için varsayılan zaman aşımı birkaç dakikadır ve istek gerçekleşse bile, kötü bir EDGE bağlantısı üzerinden bu kadar uzun sürecek kadar yavaş olabilir. Bu durumda uygulamanızın kullanılamaz olmasını istemezsiniz. Bunun gibi şeyleri test etmek için, ağ kodunuzu Apple'ın Network Link Conditioner'ı ile çalıştırmak yararlıdır.


Bu soruyu canlı tuttuğunuz için teşekkürler :-)
yazanCeevan

2
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
}

sürüm dizesini karşılaştırmak için:

https://github.com/eure/AppVersionMonitor


2

SWIFT 4 ve 3.2 İÇİN:

İlk olarak, paket kimliğini paket bilgi sözlüğünden almalıyız, isUpdaet'i yanlış olarak ayarlayın.

    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
       }

Ardından itunes'tan sürüm almak için bir urlSession çağrısı yapmamız gerekiyor.

    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()

TAM KOD BU GİBİ OLACAKTIR:

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

Daha sonra ihtiyacımız olan herhangi bir yazılımın fonksiyonunu çağırabiliriz.

    checkForUpdate { (isUpdate) in
        print("Update needed:\(isUpdate)")
        if isUpdate{
            DispatchQueue.main.async {
                print("new update Available")
            }
        }
    }

2

Apple App Store sürümünü edinmek kadar @datinc'in C # eşdeğeri. Hem paket hem de AssemblyInfo dosyası için sürüm elde etmek için kod dahil edildi.

DÜZENLEME :: Lütfen urlString'de bulunan "/ us /" bölgesine dikkat edin. Bu ülke kodunun buna göre işlenmesi / değiştirilmesi gerekecektir.

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

Bu soru 2011'de soruldu, 2018'de sadece App Store'daki uygulamanın yeni sürümünü kontrol etmek için değil, aynı zamanda kullanıcıyı bilgilendirmek için bir yol ararken buldum.

Küçük bir araştırmadan sonra, juanjo'nun (Swift 3 ile ilgili) cevabının https://stackoverflow.com/a/40939740/1218405'in cevabının, bunu kendiniz kodla yapmak istiyorsanız en uygun çözüm olduğu sonucuna vardım.

Ayrıca GitHub'da iki harika proje önerebilirim (her biri 2300+ yıldız)

Siren Örneği (AppDelegate.swift)

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

      let siren = Siren.shared
      siren.checkVersion(checkType: .immediately)

      return true
    }
  • Ayrıca yeni sürüm hakkında farklı türde uyarılar da gösterebilirsiniz (sürümü atlamaya veya kullanıcıyı güncellemeye zorlamaya izin verir)
  • Sürüm kontrolünün ne sıklıkla yapılması gerektiğini belirleyebilirsiniz (günlük / haftalık / hemen)
  • Yeni sürümün uygulama mağazasında yayınlanmasından kaç gün sonra uyarının görünmesi gerektiğini belirtebilirsiniz

Mevcut bir cevaba bağlantılar cevap değildir. Ayrıca, bağlantının soruyu yanıtınıza nasıl yanıtladığını açıkça eklemediğiniz sürece (kod örnekleri vb. Ekleyin), kitaplıklara bağlantılar da yanıt değildir.
JAL

1

Swift 4

Yeni kullanabilirsiniz JSONDecoderyanıtı ayrıştırmak itunes.apple.com/lookup çözülebilir sınıfları veya yapılar ile ve temsil:

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

class AppInfo: Decodable {
    var version: String
}

AppInfoİhtiyaç duymamız durumunda başka mülkler de ekleyebiliriz .releaseNotes veya başka bir mülke .

Şimdi aşağıdakileri kullanarak bir asenkron istek yapabiliriz 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
}

bu işlev, istek tamamlandığında çağrılacak bir tamamlama kapanışı alır ve isteği URLSessionDataTaskiptal etmemiz gerektiğinde bir döndürür ve şu şekilde çağrılabilir:

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")
        }
    }
}

Bu kodu nereye koydunuz? LookupResult ve AppInfo'yu çözülebilir olarak ayarladığınızı görüyorum, ancak bunların hiçbir yere kaydedildiğini görmüyorum. Burada neyi özlüyorum?
jessi

LookupResultVe AppInfosınıflarını projenizde bir yerde, tercihen ayrı bir dosyada beyan edersiniz: Yanıtı çözdüğünüzde kullanılırlar: JSONDecoder().decode(LookupResult.self, from: data)ve sürüm dizesini içerirler
juanjo

Cevabınıza göre kodunuzu kullanarak bir dosya oluşturuyorum Lütfen iOS-Swift-ArgAppUpdater
Anup Gupta

@jessi lütfen GitHub'daki kodumu kontrol edin Çözümünüzü oraya gönderdim
Anup Gupta

0

Kod önerim. @Datinc ve @ Mario-Hendricks tarafından verilen cevaplara göre

Tabii ki değiştirmelisin dlog_Error logging func çağrınızla değiştirmelisiniz.

Bu tür bir kod yapısı, bir hata durumunda uygulamanızın kilitlenmesini önlemelidir. Getirmek için appStoreAppVersionzorunlu değildir ve ölümcül hatalara yol açmamalıdır. Yine de, bu tür bir kod yapısıyla, ölümcül olmayan hatanızın günlüğe kaydedilmesini sağlayacaksınız.

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

1
Bu cevap, isteğini eşzamanlı olarak yapar. Bu, kötü bir bağlantıyla, istek geri dönene kadar uygulamanızın dakikalarca kullanılamayacağı anlamına gelir.
uliwitness

-1

Swift 3 için güncellendi:

Uygulamanızın mevcut sürümünü kontrol etmek istiyorsanız, aşağıdaki basit kodu kullanın:

 let object = Bundle.main.infoDictionary?["CFBundleShortVersionString"]

  let version = object as! String
  print("version: \(version)")
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.