检查我的应用在AppStore上是否有新版本


112

我想手动检查用户在我的应用程序中是否有新更新,并提示他下载新版本。我可以通过编程方式在应用商店中检查应用的版本来做到这一点吗?


6
您可以在网络服务器上放置一个随机页面,该页面仅返回最新版本的字符串表示形式。下载它并在应用启动时进行比较并通知用户。(快速简便的方法)
LouwHopley 2011年

1
谢谢,但是我希望有一个更好的解决方案,例如某种API,可以用来调用应用商店功能,例如搜索我的应用编号并获取版本数据。为此节省了维护Web服务器的时间,但是仍然感谢您的指导!
user542584 2011年

我做与第一条评论相同的事情。我写了一个带有一个条目的列表:一个NSNumber版本号。然后我将其上传到我的网站。我用于应用程序支持和应用程序网页的网站相同,然后在中viewDidLoad,检查网站的版本号,并检查应用程序中的当前版本。然后我有一个预制的alertView,可以自动提示您更新应用程序。如果您愿意,我可以提供代码。
安德鲁

谢谢,我想我应该尝试太..
user542584

Answers:


88

这是一个简单的代码段,可让您知道当前版本是否不同

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

注意:请确保在iTunes中输入新版本时,该版本与您要发布的应用程序中的版本匹配。如果不是,那么无论用户是否进行更新,上述代码将始终返回YES。


4
我找到的超级解决方案+1
Sanjay Changani 2015年

1
@MobeenAfzal,我想您想念的问题和解决方案。上面的解决方案将当前版本与商店中的版本进行比较。如果它们不匹配,则将其调为YES,否则返回NO。无论应用商店上的历史记录是什么,如果当前版本与应用商店版本不同,上述方法将返回YES。用户更新后,当前版本等于应用商店版本。如果用户的版本为1.0,而应用程序商店的版本为1.2,则上述方法应始终返回YES。
datinc

1
@MobeenAfzal我想我明白您所看到的。在代码中,您的版本是1.7,但是在iTunes中,您将版本上载为1.6,因此用户不知道您跳过了一个版本。是这样吗 如果是这样,那么...您需要的是一台服务器(DropBox会这样做)来为您的应用提供版本号,并修改您的代码以访问该端点。让我知道这是否是您看到的内容,我会在帖子中添加警告说明。
datinc 2015年

1
@MobeenAfzal,您的评论令人误解。如果用户设备上的版本与appstore上的版本之间用任意分隔,则代码将按预期返回YES。即使您先发布1.0版,再发布1.111版,它仍然可以正常运行。
datinc

1
我们仅应在appstore版本大于当前版本时显示更新,如下所示。如果([appStoreVersion比较:currentVersion选项:NSNumericSearch] == NSOrderedDescending){NSLog(@“ \ n \ n需要更新。Appstore版本%@大于%@”,appStoreVersion,currentVersion);}
Nitesh Borad'Mar

52

Swift 3版本:

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
}

我认为最好抛出一个错误而不是返回false,在这种情况下,我创建了一个VersionError,但是它可以是您定义的其他错误或NSError

enum VersionError: Error {
    case invalidResponse, invalidBundleInfo
}

还可以考虑从另一个线程调用此函数,如果连接速度很慢,它可能会阻塞当前线程。

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

更新资料

使用URLSession:

而不是使用 Data(contentsOf: url)和阻塞线程,我们可以使用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
}

例:

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

1
该答案同步发出其请求。这意味着在连接不良的情况下,您的应用可能在几分钟内无法使用,直到请求返回。
uliwitness

4
我不同意,DispatchQueue.global()给您一个后台队列,将数据加载到该队列中,并且仅在加载数据时才返回主队列。
juanjo

哎呀 我以某种方式忽略了第二个代码段。可悲的是,似乎直到我再次编辑您的答案之前,我才能删除下降投票:-(顺便说一句,鉴于dataWithContentsOfURL:实际上经过了NSURLConnection的同步调用,这反过来只是启动了一个异步线程并阻塞了,这可能会减少开销。只使用异步调用NSURLSession他们会甚至打电话给你的主线程回来一次就大功告成了。
uliwitness

@juanjo ,,,,对于swift 3.0.1不起作用,请您上传对swift进行更新的???
Kiran jadhav'7

2
请注意,如果你只在一个特定的商店上市我发现,你需要一个国家代码添加到URL -例如GB itunes.apple.com/(countryCode)/...
瑞安Heitner

13

感谢Steve Moser的链接,这是我的代码:

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
非常好的和正确的解决方案,关于url的更新很少,是itunes.apple.com/en/lookup?bundleId=xxxxxxxxxx
SJ

谢谢,您的评论得到了应用
Roozbeh Zabihollahi 2014年

4
实际上,对于/en/子路径,它对我不起作用。删除后,它起作用了
gasparuff

该答案同步发出其请求。这意味着在连接不良的情况下,您的应用可能在几分钟内无法使用,直到请求返回。
uliwitness

1
我不得不使用/ en / itunes.apple.com/lookup?bundleId=xxxxxxx,谢谢@gasparuff
Fernando Perez

13

由于我遇到了同样的问题,因此我找到了Mario Hendricks提供的答案。不幸的是,当我尝试在他的项目中使用他的代码时,XCode确实抱怨说Casting问题说“ MDLMaterialProperty没有下标成员”。他的代码试图将MDLMaterial ...设置为常量“ lookupResult”的类型,从而使对“ Int”的转换每次都失败。我的解决方案是为NSDictionary的变量提供类型注释以明确我需要的值的种类。这样,我就可以访问所需的值“版本”。

Obs:对于您的YOURBUNDLEID,您可以从Xcode项目中获取...。“ Targets> General> Identity> Bundle Identifier

所以这也是我的代码,也有一些简化:

  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
}

欢迎提供所有改进此代码的建议!


该答案同步发出其请求。这意味着在连接不良的情况下,您的应用可能在几分钟内无法使用,直到请求返回。
uliwitness

@Yago Zardo请使用否则当用户上传app.apple测试比较功能时显示更新alertview或苹果拒绝您的应用程序
Jigar Darji

嘿@Jigar,谢谢您的建议。我目前在我的应用中不再使用此方法,因为现在我们正在对服务器中的所有内容进行版本控制。无论如何,您能更好地解释您的言论吗?我不明白,这确实是一件好事。提前致谢。
Yago Zardo

谢谢@uliwitness的技巧,它确实帮助我总体上改进了代码,以了解异步和同步请求。
Yago Zardo

那个链接是一颗宝石!
B3none

13

只需使用ATAppUpdater即可。它是1行,线程安全且快速。如果您想跟踪用户操作,它也具有委托方法。

这是一个例子:

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

   return YES;
}

可选的委托方法:

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

1
这对Testflight中的beta版本有效吗?如果没有,是否有任何工具可以使用?
Lukasz Czerwinski 2015年

不,它不会,它只会将当前版本与AppStore上的最新版本进行比较。
情绪化,2015年

我们可以在Swift中使用它吗?
佐拉尔

11

简化此线程上发布的一个很好的答案。使用Swift 4Alamofire

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

}

然后使用它:

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

2
我的应用程序位于商店中,但是相同的api不返回版本信息。回应:{ "resultCount":0, "results": [] }
technerd

只需在版本比较中添加注释,我更喜欢让serverVersion =“ 2.7”让localVersion =“ 2.6.5”让isUpdateAvailable = serverVersion.compare(localVersion,options:.numeric)== .orderedDescending而不是替换。与空。
Chaitu

@Chaitu谢谢您的建议。我最终重写了代码的比较部分
budidino

9

更新了Anup Guptaswift 4代码

我已经对该代码进行了一些更改。现在,从后台队列调用函数,因为连接可能很慢,因此阻塞了主线程。

我还使CFBundleName为可选,因为显示的版本具有“ CFBundleDisplayName”,可能在我的版本中不起作用。因此,如果现在不存在,它将不会崩溃,而不会在警报中显示“应用程序名称”。

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

我打电话也要添加确认按钮:

AppUpdater.shared.showUpdate(withConfirmation: true)

或这样称呼它,以便在其中启用强制更新选项:

AppUpdater.shared.showUpdate(withConfirmation: false)

关于如何测试的任何想法?如果它无法正常工作,则调试它的唯一方法是以某种方式调试比应用商店中的旧版本。
David Rector

2
啊,没关系。我可以简单地将本地版本更改为“较旧”。
David Rector

您的代码@Vasco给我留下了深刻的印象。只是一个简单的问题,为什么在该URL中使用了“ http”而不是https?
Master AgentX

非常感谢您分享此解决方案@Vasco!我喜欢它:)为什么不使用:let config = URLSessionConfiguration.background(withIdentifier:“ com.example.MyExample.background”)用于实现后台请求的URLSession?
mc_plectrum

您还可以摆脱强制展开的麻烦,因为您已经检查了是否让appStoreAppVersion = info?.version与trackURL相同。
mc_plectrum

7

这是我使用Swift 4和流行的Alamofire库的版本(无论如何,我都会在我的应用程序中使用它)。请求是异步的,您可以传递回调以在完成时得到通知。

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

用法很简单,如下所示:

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

1
使用ourVersion!= appVersion的问题在于,它会在App Store审核小组检查该应用的新版本时触发。我们将这些版本字符串转换为数字,然后isNew = appVersion> ourVersion。
budidino

@budidino你是对的,我只是展示了使用Alamofire的常用方法。您如何解释版本完全取决于您的应用和版本结构。
北上尉

只是在版本比较中添加注释,我希望让serverVersion =“ 2.7” let localVersion =“ 2.6.5” let isUpdateAvailable = serverVersion.compare(localVersion,options:.numeric)== .orderedDescending而不是等于
猜图

6

我可以建议这个小图书馆吗:https : //github.com/nicklockwood/iVersion

其目的是简化对远程通知触发通知的处理。


3
您可以直接在App Store中查看版本号,而不是在某个位置托管plist文件。看看这个答案:stackoverflow.com/a/6569307/142358
史蒂夫·摩泽

1
iVersion现在自动使用应用程序商店版本-如果您要为iTunes上的发行说明指定不同的发行说明,则Plist是可选的,但您无需使用它。
尼克·洛克伍德

1
该代码可以使用一些改进,但是比其他发送同步请求的答案要好得多。尽管如此,它执行线程的方式还是不好的风格。我将在Github上提出问题。
uliwitness

该项目现在已经过时😢
Zorayr

5

斯威夫特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
}

当您没有互联网连接时,这会崩溃。让数据=尝试?Data(contentsOf:url!)将返回nil,然后在下一行中执行数据!
Joris Mans

thx @JorisMans我将对其进行更新,以确保没有互联网连接崩溃
Kassem

不要这样 使用URLSession
JAL

4

此答案是对datinc答案的修改https://stackoverflow.com/a/25210143/2735358

datinc的功能通过字符串比较来比较版本。因此,它不会比较大于或小于的版本。

但是,该修改的函数通过NSNumericSearch比较版本(数字比较)

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

用:

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

3
该答案同步发出其请求。这意味着在连接不良的情况下,您的应用可能在几分钟内无法使用,直到请求返回。
uliwitness

除非我们另外指定,否则NSURLSession会自动在后台线程上工作。
塞巴斯蒂安·德沃尼克

4

我看到了许多检查应用程序更新的方法。因此,基于许多答案,我将它们混合在一起并创建我的解决方案,该解决方案可在GitHub上获得。如果需要任何更新,请告诉我。此代码为Swift 4

GitHub链接至此代码。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)
    }
}

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

快乐编码



3

尝试使用一个函数调用:

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:

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)

}

如何调用以上函数:

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

有关更多详细信息,请尝试下面的完整代码链接:

AppStoreUpdate.swift

ItunesAppInfoResult.swift

ItunesAppInfoItunes.swift

我希望这会有所帮助!


2

这是一种快速方法,可以完成一些Objective-C答案所建议的工作。显然,一旦从应用商店JSON获取信息,就可以提取发行说明。

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是应用商店中应用的网址吗?
iamthevoid

@Mario Hendricks这在swift 3中不起作用。它引发了一些错误。您能更新一下Swift 3吗?
乔治·阿斯达

该答案同步发出其请求。这意味着在连接不良的情况下,您的应用可能在几分钟内无法使用,直到请求返回。
uliwitness

2

如果您未在NSUrlRequest中设置内容类型,那么请确保您不会收到响应,因此请尝试以下代码,它对我来说效果很好。希望能帮助到你....

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

该答案同步发出其请求。这意味着在连接不良的情况下,您的应用可能在几分钟内无法使用,直到请求返回。
uliwitness

2

来自混合应用程序POV,这是一个javascript示例,我的主菜单上有一个Update Available页脚。如果有可用更新(即,我的配置文件中的版本号小于检索到的版本,请显示页脚),然后将用户定向到应用商店,然后用户可以在其中单击更新按钮。

我还获得了最新的数据(即发行说明),并在登录时以模态形式显示了这些数据(如果是此版本上的第一次)。

可以根据需要多次运行“可用更新”方法。每当用户导航到主屏幕时,都会运行Mine。

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

}

回调:Apple有一个API,因此非常容易获得

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

警告:大多数给出的答案同步获取URL(使用-dataWithContentsOfURL:-sendSynchronousRequest:这是不好的,因为这意味着如果移动连接中断,同时请求过程中您的应用程序将停止响应几分钟。从来没有做互联网接入同步上主线程。

正确的答案是使用异步API:

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

            if ([appStoreVersion compare:currentVersion options:NSNumericSearch] == NSOrderedDescending) {
                // *** Present alert about updating to user ***
            }
        }
    }];
    [theTask resume];

网络连接的默认超时为几分钟。即使请求通过,由于EDGE连接不好,它可能也很慢,因此需要很长时间。在这种情况下,您不希望您的应用无法使用。为了测试这样的事情,使用Apple的Network Link Conditioner运行网络代码非常有用。


感谢您让这个问题继续存在:-)
Jeevan 2017年

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
}

比较版本字符串:

https://github.com/eure/AppVersionMonitor


2

对于SWIFT 4和3.2:

首先,我们需要从包信息字典中获取包ID,将isUpdaet设置为false。

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

然后,我们需要调用urlSession调用以从iTunes获取版本。

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

像这样的完整代码:

func checkForUpdate(completion:@escaping(Bool)->()){

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

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

然后,我们可以将函数调用所需的任何软件。

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

2

@datinc的C#等效性,以及获得Apple App Store版本的等效性。包含的代码,用于获取包或AssemblyInfo文件的版本。

编辑::请注意urlString中包含的区域“ / us /”。该国家/地区代码将需要进行相应的处理/更改。

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

在2011年提出了这个问题,我在2018年找到了这个问题,当时他在寻找某种方法,不仅可以检查App Store中应用的新版本,还可以将其通知用户。

经过细致的研究,我得出的结论是,如果您想自己在代码中进行操作,那么juanjo的答案(与Swift 3相关) https://stackoverflow.com/a/40939740/1218405是最佳解决方案

我也可以在GitHub上推荐两个很棒的项目(每个星标超过2300)

警笛示例(AppDelegate.swift)

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

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

      return true
    }
  • 您还可以显示有关新版本的不同类型的警报(允许跳过版本或强制用户更新)
  • 您可以指定版本检查的频率(每天/每周/立即)
  • 您可以指定发布到应用商店的新版本警报应出现的天数

指向现有答案的链接不是答案。此外,指向库的链接也不是答案,除非您明确地将链接如何将问题回答到答案中(添加代码示例等)。
JAL

1

斯威夫特4

我们可以使用new JSONDecoder解析来自itunes.apple.com/lookup的响应,并用Decodable类或结构表示它:

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

class AppInfo: Decodable {
    var version: String
}

AppInfo如果需要,我们还可以添加其他属性releaseNotes或其他属性。

现在我们可以使用发出异步请求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
}

此函数接收完成关闭,当请求完成时将调用该关闭,并URLSessionDataTask在需要取消请求的情况下返回,可以这样调用:

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

您将此代码放在哪里?我看到您将LookupResult和AppInfo设置为可解码,但是我看不到它们保存在任何地方。我在这里想念什么?
jessi

您最好在项目的某个地方,在一个单独的文件中声明LookupResultand AppInfo类:解码响应时将使用它们:JSONDecoder().decode(LookupResult.self, from: data)并且它们包含版本字符串
juanjo

根据您的回答,我使用您的代码创建一个文件,请检查iOS-Swift-ArgAppUpdater
Anup Gupta

@jessi,请检查我在GitHub上的代码,我在其中发布了您的解决方案
Anup Gupta,

0

我的代码建议。基于@datinc和@ Mario-Hendricks的答案

您当然应该dlog_Error用日志记录函数调用代替。

这种代码结构应防止您的应用在发生错误时崩溃。对于获取,appStoreAppVersion不是必须的,并且不应导致致命的错误。但是,使用这种代码结构,您仍然会记录非致命错误。

class func appStoreAppVersion() -> String?
{
    guard let bundleInfo = NSBundle.mainBundle().infoDictionary else {
        dlog_Error("Counldn't fetch bundleInfo.")
        return nil
    }
    let bundleId = bundleInfo[kCFBundleIdentifierKey as String] as! String
    // dbug__print("bundleId = \(bundleId)")

    let address = "http://itunes.apple.com/lookup?bundleId=\(bundleId)"
    // dbug__print("address = \(address)")

    guard let url = NSURLComponents.init(string: address)?.URL else {
        dlog_Error("Malformed internet address: \(address)")
        return nil
    }
    guard let data = NSData.init(contentsOfURL: url) else {
        if Util.isInternetAvailable() {
            dlog_MajorWarning("Web server request failed. Yet internet is reachable. Url was: \(address)")
        }// else: internet is unreachable. All ok. It is of course impossible to fetch the appStoreAppVersion like this.
        return nil
    }
    // dbug__print("data.length = \(data.length)")

    if data.length < 100 { //: We got 42 for a wrong address. And aproximately 4684 for a good response
        dlog_MajorWarning("Web server message is unexpectedly short: \(data.length) bytes")
    }

    guard let response = try? NSJSONSerialization.JSONObjectWithData(data, options: []) else {
        dlog_Error("Failed to parse server response.")
        return nil
    }
    guard let responseDic = response as? [String: AnyObject] else {
        dlog_Error("Not a dictionary keyed with strings. Response with unexpected format.")
        return nil
    }
    guard let resultCount = responseDic["resultCount"] else {
        dlog_Error("No resultCount found.")
        return nil
    }
    guard let count = resultCount as? Int else { //: Swift will handle NSNumber.integerValue
        dlog_Error("Server response resultCount is not an NSNumber.integer.")
        return nil
    }
    //:~ Determine how many results we got. There should be exactly one, but will be zero if the URL was wrong
    guard count == 1 else {
        dlog_Error("Server response resultCount=\(count), but was expected to be 1. URL (\(address)) must be wrong or something.")
        return nil
    }
    guard let rawResults = responseDic["results"] else {
        dlog_Error("Response does not contain a field called results. Results with unexpected format.")
        return nil
    }
    guard let resultsArray = rawResults as? [AnyObject] else {
        dlog_Error("Not an array of results. Results with unexpected format.")
        return nil
    }
    guard let resultsDic = resultsArray[0] as? [String: AnyObject] else {
        dlog_Error("Not a dictionary keyed with strings. Results with unexpected format.")
        return nil
    }
    guard let rawVersion = resultsDic["version"] else {
        dlog_Error("The key version is not part of the results")
        return nil
    }
    guard let versionStr = rawVersion as? String else {
        dlog_Error("Version is not a String")
        return nil
    }
    return versionStr.e_trimmed()
}

extension String {
    func e_trimmed() -> String
    {
        return stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
    }
}

1
该答案同步发出其请求。这意味着在连接不良的情况下,您的应用可能在几分钟内无法使用,直到请求返回。
uliwitness

-1

迅速更新3:

如果要检查应用程序的当前版本,请在以下简单代码中使用:

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

  let version = object as! String
  print("version: \(version)")
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.