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

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

134386 次浏览

我能建议这个小图书馆吗: Https://github.com/nicklockwood/iversion

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

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

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

-(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,无论用户是否更新。

ATAppUpdater。它是一行,线程安全和快速。如果您希望跟踪用户操作,它还具有委托方法。

这里有一个例子:

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

这里有一个快速的方法,可以完成某些 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
}

如果你没有在 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;
}

由于我面临着同样的问题,我找到了由 马里奥 · 亨德里克斯提供的 回答。不幸的是,当我试图将他的代码应用到我的项目中时,XCode 确实抱怨了铸造问题,说“ MDLMaterials Property 没有下标成员”。他的代码试图将这个 MDLMaterials... ... 设置为常量“ lookupResult”的类型,使得对“ Int”的强制转换每次都会失败。我的解决方案是为 NSDictionary的变量提供一个类型注释,以便清楚地了解我需要的值的类型。有了它,我就可以访问我需要的值“ version”。

观察: 对于这个 Yourundleid,您可以从您的 Xcode 项目中获得... ... “ 目标 > 一般 > 身份证 > 捆绑标识符

下面是我的代码,也进行了一些简化:

  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
}

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

我的代码建议,基于@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())
}
}

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

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

更新可用方法可以随时运行。每当用户导航到主屏幕时,都会运行 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);
});


}

回复: 苹果有一个 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);
}
}

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: "https://itunes.apple.com/lookup?bundleId=\(identifier)") else {
throw VersionError.invalidBundleInfo
}
let data = try Data(contentsOf: url)
guard let json = try JSONSerialization.jsonObject(with: data, options: [.allowFragments]) as? [String: Any] else {
throw VersionError.invalidResponse
}
if let result = (json["results"] as? [Any])?.first as? [String: Any], let version = result["version"] as? String {
return version != currentVersion
}
throw VersionError.invalidResponse
}

我认为最好抛出一个错误而不是返回 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)和阻塞线程:

func isUpdateAvailable(completion: @escaping (Bool?, Error?) -> Void) throws -> URLSessionDataTask {
guard let info = Bundle.main.infoDictionary,
let currentVersion = info["CFBundleShortVersionString"] as? String,
let identifier = info["CFBundleIdentifier"] as? String,
let url = URL(string: "https://itunes.apple.com/lookup?bundleId=\(identifier)") else {
throw VersionError.invalidBundleInfo
}
Log.debug(currentVersion)
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
do {
if let error = error { throw error }
guard let data = data else { throw VersionError.invalidResponse }
let json = try JSONSerialization.jsonObject(with: data, options: [.allowFragments]) as? [String: Any]
guard let result = (json?["results"] as? [Any])?.first as? [String: Any], let version = result["version"] as? String else {
throw VersionError.invalidResponse
}
completion(version != currentVersion, nil)
} catch {
completion(nil, error)
}
}
task.resume()
return task
}

例如:

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

这个答案是对数据公司答案 https://stackoverflow.com/a/25210143/2735358的修改。

函数通过字符串比较来比较版本。因此,它不会比较大于或小于。

但是,这个修改过的函数 通过 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
}
}];

警告: 给出的大多数答案同步地检索 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 连接上也会慢到需要这么长时间。你不希望你的应用程序在这种情况下不能使用。为了测试这样的东西,使用苹果的网络链接调节器来运行你的网络代码是很有用的。

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

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
}

Swift 4

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

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

我看到了许多检查应用程序更新的方法。因此,基于许多答案,我混合他们,并创建我的解决方案,这是可用的 GitHub如果有任何更新要求,请让我知道。 这是 < strong > Swift 4的代码

到这个代码的 GitHub 链接

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

参考文献: < a href = “ https://stackoverflow. com/a/48810541/5855888”> https://stackoverflow.com/a/48810541/5855888 还有一个 https://github.com/emotality/atappupdater

编码愉快

对于 SWIFT 4和3.2:

首先,我们需要从 bundle info dictionary 获取 bundle 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")
}
}
}

这里是我的版本使用 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)")
}

Anup Gupta更新了 迅猛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)

C # 相当于@datinc,就像获取苹果应用商店版本一样。包含获取 bundle 或 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();
}

简化的 很棒的回答张贴在这个线程。使用 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: ".").compactMap { Int($0) }
let arrayLocal = versionLocal.split(separator: ".").compactMap { Int($0) }


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


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

}

然后使用它:

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

尝试使用单个函数调用:

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

ItunesAppInfoResults. swift

ItunesAppInfoItunesSwift

我希望这会有帮助!

我想从 回答我开始添加一些行,当您更改中间数字版本(例如从1.0.10到1.1.0)时,这些行很有用。

回答我的反应就像1.0.10比1.1.0更新,所以这就是我的替代解决方案:

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


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


}

用法总是相同的:

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

Swift 5(缓存问题已解决)

enum VersionError: Error {
case invalidResponse, invalidBundleInfo
}


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

let request = URLRequest(url: url, cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalCacheData)
    

let task = URLSession.shared.dataTask(with: request) { (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 lastVersion = result["version"] as? String else {
throw VersionError.invalidResponse
}
completion(lastVersion > currentVersion, nil)
} catch {
completion(nil, error)
}
}
    

task.resume()
return task
}

实施

            try? isUpdateAvailable {[self] (update, error) in
if let error = error {
print(error)
} else if update ?? false {
// show alert
}
}

你需要:

  1. 服务器端逻辑/服务,以维护版本号每当您提交新版本的应用程序(ipa)到应用程序商店。这还允许您将版本提取到客户端。
  2. 客户端逻辑

如果来自服务器的版本高于设备上安装的版本,提示用户更新应用程序。

这里 是一个代码片段,用于检查/比较遵循数字格式和点格式(比如1.2.0)的版本号

var currVer = "1.2.0";
var newVer = "1.2.1";
var arr1 = currVer.split(".");
var arr2 = newVer.split(".");
var intArray1 = arr1.map(function(txt){return (txt.length===0?0:parseInt(txt));});
var intArray2 = arr2.map(function(txt){return (txt.length===0?0:parseInt(txt));});
var l1 = intArray1.length;
var l2 = intArray2.length;
var isOutdated=false;






if(l1>0){
if(l2>0){
// compare both currentversion and new version is not empty
if(l1==l2){
for(i=0;i<l1;i++){
if(intArray2[i]>intArray1[i]){
// tag as outdated if matched digit of newVersion is greater than the matching digit of current version
isOutdated=true;
break;
}
        

}
      

}
else{
if((l2-l1)>0){
for(i=0;i<(l2-l1);i++){
intArray1.push(0);
}
        

}
if((l1-l2)>0){
for(i=0;i<(l1-l2);i++){
intArray2.push(0);
}
        

}
l1 = intArray1.length;
l2 = intArray2.length;
      

for(i=0;i<l1;i++){
if(intArray2[i]>intArray1[i]){
// tag as outdated if matched digit of newVersion is greater than the matching digit of current version
isOutdated=true;
break;
}
        

}
}
}
else{
// if there's no new version, tag as not outdated
isOutdated = false;
}
  

}
else{
// if current version is empty, tag as not outdated
isOutdated = false;
}


document.getElementById("versionTxt").innerHTML = currVer + " -> " + JSON.stringify(intArray1);




document.getElementById("versionTxt2").innerHTML = newVer + " -> " + JSON.stringify(intArray2);


document.getElementById("isOutdatedTxt").innerHTML = "Outdated? " + isOutdated.toString();
<span id="versionTxt"></span> <br />
<span id="txtLength"></span> <br />
<span id="versionTxt2"></span> <br />
<span id="txtLength2"></span> <br />


<span id="lengthCompare"></span> <br />


<span id="isOutdatedTxt"></span>

 -(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]){
float appVersion = [appStoreVersion floatValue];
float ourVersion = [currentVersion floatValue];
if (appVersion <= ourVersion) {
return NO;
}
NSLog(@"Need to update [%@ != %@]", appStoreVersion, currentVersion);
return YES;
}
}
return NO;
}

有时这个 URL 显示 http://itunes.apple.com/lookup?bundleId的旧版本。所以弹出窗口不会消失。添加这些行

float appVersion = [appStoreVersion floatValue];
float ourVersion = [currentVersion floatValue];
if (appVersion <= ourVersion) {
return NO;
}
    

func isUpdateAvailableOrNot() 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 {
        print("version in app store", version,currentVersion);
        
        return version != currentVersion
    }
    throw VersionError.invalidResponse
}






//Now on your first view controller write this code on viewdidload()


 DispatchQueue.global().async {
            do {
                let update = try self.globalObjectHome.isUpdateAvailableOrNot()
                
                print("update",update)
                DispatchQueue.main.async {
                    if update{
                        self.AlertBox();
                    }
                    
                }
            } catch {
                print(error)
            }
        }




 func AlertBox(){
        var versionInfo = ""
        do {
            versionInfo = try self.globalObjectHome.getAppStoreVersion()
        }catch {
            print(error)
        }
 
        
        let alertMessage = "A new version of  APPNAME Application is available,Please update to version "+versionInfo;
        let alert = UIAlertController(title: "New Version Available", message: alertMessage, preferredStyle: UIAlertControllerStyle.alert)
  
        let okBtn = UIAlertAction(title: "Update", style: .default, handler: {(_ action: UIAlertAction) -> Void in
            if let url = URL(string: “Your application App Store Url”),
                UIApplication.shared.canOpenURL(url){
                if #available(iOS 10.0, *) {
                    UIApplication.shared.open(url, options: [:], completionHandler: nil)
                } else {
                    UIApplication.shared.openURL(url)
                }
            }
        })
        let noBtn = UIAlertAction(title:"Skip this Version" , style: .destructive, handler: {(_ action: UIAlertAction) -> Void in
        })
        alert.addAction(okBtn)
        alert.addAction(noBtn)
        self.present(alert, animated: true, completion: nil)
        
    }

以下是来自@aloha as Publisher的回答:

func isUpdateAvailable() -> AnyPublisher<Bool, VersionError> {
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 {
return Fail<Bool, VersionError>(error: VersionError.invalidBundleInfo)
.eraseToAnyPublisher()
}


return URLSession.shared
.dataTaskPublisher(for: URLRequest(url: url, cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalCacheData))
.tryMap { data, response -> Bool in
guard let json = try? JSONSerialization.jsonObject(with: data, options: [.allowFragments]) as? [String: Any],
let result = (json["results"] as? [Any])?.first as? [String: Any],
let lastVersion = result["version"] as? String
else {
throw VersionError.invalidResponse
}
return lastVersion > currentVersion
}
.mapError { _ in
VersionError.invalidResponse
}
.eraseToAnyPublisher()
}

我为此做了个豆荚

pod 'Up2Dater'

快照

样本:

   #import Up2Dater


let updater = Up2Dater()
updater.isNewVersionAvailable { result in
switch result {
case.success(let model):
// if the model is nil, there's no new version
print(model?.version, model?.releaseNotes, model?.appStorePath)
case .failure(let error):
print(error.description)
}
}

比较字符串版本比使用关系运算子(如 <>=)更好(例如“3.1.7”< “3.1.10”)

    func isNewer(_ version: String,
then bundleVersion: String) -> Bool {
switch version.compare(bundleVersion, options: .numeric) {
case .orderedSame,
.orderedAscending:
return false
case .orderedDescending:
return true
}
}