Kiểm tra xem ứng dụng của tôi có phiên bản mới trên AppStore không


112

Tôi muốn kiểm tra theo cách thủ công xem có bản cập nhật mới nào cho ứng dụng của mình khi người dùng đang ở trong đó không và nhắc anh ta tải xuống phiên bản mới. Tôi có thể thực hiện việc này bằng cách kiểm tra phiên bản ứng dụng của mình trong cửa hàng ứng dụng - theo chương trình không?


6
Bạn có thể đặt một trang ngẫu nhiên trên một máy chủ web chỉ trả về một biểu diễn chuỗi của phiên bản mới nhất. Tải xuống và so sánh khi khởi động ứng dụng và thông báo cho người dùng. (Cách nhanh chóng và dễ dàng)
LouwHopley

1
cảm ơn, nhưng tôi đã hy vọng một giải pháp tốt hơn như một số loại API mà tôi có thể gọi các chức năng của cửa hàng ứng dụng, như tìm kiếm số ứng dụng của tôi và lấy dữ liệu phiên bản. Tiết kiệm thời gian để duy trì một máy chủ web chỉ cho mục đích này, nhưng dù sao cũng cảm ơn con trỏ!
dùng542584

Tôi làm điều tương tự như nhận xét đầu tiên. Tôi đã viết một danh sách với một mục nhập: NSNumbersố phiên bản. Sau đó, tôi tải nó lên trang web của mình. Cùng một trang web mà tôi sử dụng cho các trang web ứng dụng và hỗ trợ ứng dụng của mình, sau đó viewDidLoad, tôi kiểm tra trang web để biết số phiên bản ở đó và kiểm tra phiên bản hiện tại trong ứng dụng của mình. Sau đó, tôi có một tiền được alertViewtạo sẵn tự động nhắc cập nhật ứng dụng. Tôi có thể cung cấp mã nếu bạn muốn.
Andrew

cảm ơn, tôi đoán tôi nên thử điều đó quá ..
user542584

Câu trả lời:


88

Đây là một đoạn mã đơn giản cho bạn biết nếu phiên bản hiện tại khác

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

Lưu ý: Đảm bảo rằng khi bạn nhập phiên bản mới trong iTunes, phiên bản này khớp với phiên bản trong ứng dụng bạn đang phát hành. Nếu không thì mã trên sẽ luôn trả về CÓ bất kể người dùng có cập nhật hay không.


4
siêu giải pháp tôi từng tìm thấy +1
Sanjay Changani

1
@MobeenAfzal, tôi nghĩ bạn chưa hiểu câu hỏi và giải pháp. Giải pháp trên so sánh phiên bản hiện tại với phiên bản trên cửa hàng. Nếu chúng không khớp thì nó trả về CÓ, ngược lại nó trả về KHÔNG. Bất kể lịch sử trên cửa hàng ứng dụng, phương pháp trên sẽ trả về CÓ nếu phiên bản hiện tại khác phiên bản cửa hàng ứng dụng. Sau khi người dùng cập nhật ... phiên bản hiện tại bằng với phiên bản cửa hàng ứng dụng. Phương thức trên sẽ luôn trả về CÓ nếu phiên bản của người dùng là 1.0 và phiên bản cửa hàng ứng dụng là 1.2.
datinc

1
@MobeenAfzal Tôi nghĩ rằng tôi hiểu được những gì bạn đang thấy. Trong mã phiên bản của bạn là 1.7, nhưng trong iTunes, bạn đã tải lên phiên bản là 1.6 để người dùng không biết bạn đã bỏ qua phiên bản. Đó là trường hợp? Nếu vậy thì ... những gì bạn cần là một máy chủ (DropBox sẽ làm) để cung cấp số phiên bản ứng dụng của bạn và sửa đổi mã của bạn để truy cập điểm cuối đó. Hãy cho tôi biết nếu đây là những gì bạn đang thấy và tôi sẽ thêm ghi chú cảnh báo vào bài đăng.
datinc,

1
@MobeenAfzal bạn nhận xét của bạn là sai lệch. Nếu phiên bản trên thiết bị của người dùng được phân tách bằng bất kỳ phiên bản nào trên appstore thì mã sẽ trả về CÓ như mong đợi. Ngay cả khi bạn phát hành phiên bản 1.0 sau đó là phiên bản 1.111, nó vẫn hoạt động hoàn hảo.
datinc

1
Chúng tôi chỉ nên hiển thị bản cập nhật khi phiên bản kho ứng dụng lớn hơn phiên bản hiện tại như sau. if ([appStoreVersion so sánh: currentVersion options: NSNumericSearch] == NSOrderedDescending) {NSLog (@ "\ n \ nCần cập nhật. Appstore phiên bản% @ lớn hơn% @", appStoreVersion, currentVersion); }
Nitesh Borad

52

Phiên bản 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
}

Tôi nghĩ tốt hơn nên tạo ra một lỗi thay vì trả về false, trong trường hợp này, tôi đã tạo VersionError nhưng nó có thể là một số khác do bạn xác định hoặc NSError

enum VersionError: Error {
    case invalidResponse, invalidBundleInfo
}

Cũng nên cân nhắc để gọi chức năng này từ một luồng khác, nếu kết nối chậm nó có thể chặn luồng hiện tại.

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

Cập nhật

Sử dụng URLSession:

Thay vì sử dụng Data(contentsOf: url)và chặn một chuỗi, chúng ta có thể sử dụng 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
}

thí dụ:

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

1
Câu trả lời này làm cho yêu cầu của nó một cách đồng bộ. Điều này có nghĩa là với kết nối kém, ứng dụng của bạn có thể không sử dụng được trong vài phút cho đến khi yêu cầu trả về.
uliwitness

4
Tôi không đồng ý, DispatchQueue.global()cung cấp cho bạn một hàng đợi nền, dữ liệu được tải trong hàng đợi đó và chỉ quay trở lại hàng đợi chính khi dữ liệu được tải.
juanjo

Rất tiếc. Bằng cách nào đó tôi đã bỏ qua đoạn mã thứ hai đó. Đáng buồn thay, có vẻ như tôi không thể xóa phiếu phản đối cho đến khi câu trả lời của bạn được chỉnh sửa lại :-( BTW - Given dataWithContentsOfURL: thực sự trải qua các lệnh gọi đồng bộ của NSURLConnection, đến lượt nó chỉ bắt đầu một chuỗi và khối không đồng bộ, nó có thể sẽ ít tốn kém hơn . chỉ cần sử dụng các cuộc gọi không đồng bộ NSURLSession Họ thậm chí còn muốn gọi cho bạn sao lưu vào các chủ đề chính một khi bạn đã hoàn tất.
uliwitness

@juanjo ,,,, không hoạt động với swift 3.0.1, vui lòng tải lên cập nhật cho swift được không ???
Kiran

2
Lưu ý nếu bạn chỉ liệt kê trong một cửa hàng cụ thể tôi đã phát hiện ra rằng bạn cần phải thêm mã quốc gia đến URL - ví dụ GB itunes.apple.com/(countryCode)/... )
Ryan Heitner

13

Cảm ơn Steve Moser về liên kết của anh ấy, đây là mã của tôi:

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
giải pháp rất tốt và chính xác, chỉ cần cập nhật nhỏ liên quan đến url là itunes.apple.com/en/lookup?bundleId=xxxxxxxxxx
SJ

Cảm ơn, nhận xét của bạn đã được áp dụng
Roozbeh Zabihollahi

4
Trên thực tế, nó không hoạt động với tôi với đường dẫn con /en/. Sau khi loại bỏ nó, nó làm việc
gasparuff

Câu trả lời này làm cho yêu cầu của nó một cách đồng bộ. Điều này có nghĩa là với kết nối kém, ứng dụng của bạn có thể không sử dụng được trong vài phút cho đến khi yêu cầu trả về.
uliwitness

1
Tôi đã phải sử dụng với / en / itunes.apple.com/lookup?bundleId=xxxxxxx , cảm ơn @gasparuff
Fernando Perez

13

Vì tôi đang đối mặt với vấn đề tương tự, tôi đã tìm thấy câu trả lời do Mario Hendricks cung cấp . Thật không may khi tôi cố gắng áp dụng mã của anh ấy trong dự án của mình, XCode đã phàn nàn về các vấn đề Truyền nói rằng "MDLMaterialProperty không có thành viên chỉ số dưới". Mã của anh ấy đang cố gắng đặt MDLMaterial này ... làm loại hằng số "lookupResult", khiến cho quá trình truyền thành "Int" không thành công mỗi lần. Giải pháp của tôi là cung cấp chú thích kiểu cho biến của tôi cho NSDictionary để rõ ràng về loại giá trị tôi cần. Với điều đó, tôi có thể truy cập "phiên bản" giá trị mà tôi cần.

Ám ảnh: Đối với YOURBUNDLEID này , bạn có thể lấy từ dự án Xcode của mình .... " Mục tiêu> Chung> Danh tính> Mã nhận dạng gói "

Vì vậy, đây là mã của tôi với một số đơn giản hóa:

  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
}

Tất cả các đề xuất để cải thiện mã này đều được hoan nghênh!


Câu trả lời này làm cho yêu cầu của nó một cách đồng bộ. Điều này có nghĩa là với kết nối kém, ứng dụng của bạn có thể không sử dụng được trong vài phút cho đến khi yêu cầu trả về.
uliwitness

@Yago Zardo, nếu không, hãy sử dụng chức năng so sánh khi người dùng tải lên app.apple đã kiểm tra thời gian hiển thị cập nhật alertview hoặc apple từ chối ứng dụng của bạn
Jigar Darji 15/02/18

Xin chào @Jigar, cảm ơn vì lời khuyên. Tôi hiện không sử dụng phương pháp này nữa trên ứng dụng của mình vì bây giờ chúng tôi đang tạo phiên bản cho mọi thứ trong máy chủ của mình. Dù sao, bạn có thể giải thích tốt hơn những gì bạn đã nói? Tôi không hiểu và nó thực sự có vẻ là một điều tốt để biết. Cảm ơn trước.
Yago Zardo

Cảm ơn @uliwitness về mẹo này, nó thực sự giúp tôi cải thiện mã của mình nói chung để tìm hiểu về các yêu cầu không đồng bộ và đồng bộ.
Yago Zardo

Liên kết đó là một viên ngọc!
B3none

13

Chỉ cần sử dụng ATAppUpdater . Nó là 1 dòng, an toàn và nhanh chóng. Nó cũng có các phương thức ủy quyền nếu bạn muốn theo dõi hành động của người dùng.

Đây là một ví dụ:

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

   return YES;
}

Các phương pháp ủy quyền tùy chọn:

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

1
Điều này sẽ hoạt động cho các phiên bản beta trong Testflight? Nếu không, có bất kỳ công cụ nào sẽ?
Lukasz Czerwinski

Không, nó sẽ không, nó chỉ so sánh phiên bản hiện tại với phiên bản mới nhất có trên AppStore.
emotality

Chúng ta có thể sử dụng điều này với Swift không?
Zorayr

11

Đơn giản hóa một câu trả lời tuyệt vời được đăng trên chủ đề này. Sử dụng 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
    }
  }

}

Và sau đó để sử dụng nó:

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

2
Ứng dụng của tôi đang tồn tại trên cửa hàng nhưng cùng một api không trả về thông tin phiên bản. Phản ứng:{ "resultCount":0, "results": [] }
technerd

Chỉ cần thêm ghi chú vào so sánh phiên bản, tôi muốn serverVersion = "2.7" let localVersion = "2.6.5" let isUpdateAvailable = serverVersion.compare (localVersion, options: .numeric) == .orderedDescending hơn là thay thế. với trống rỗng.
Chaitu

@Chaitu cảm ơn bạn đã gợi ý. Tôi đã kết thúc việc viết lại phần so sánh của mã
budidino

9

Đã cập nhật mã nhanh chóng 4 từ Anup Gupta

Tôi đã thực hiện một số thay đổi đối với mã này . Bây giờ các chức năng được gọi từ một hàng đợi nền, vì kết nối có thể chậm và do đó chặn luồng chính.

Tôi cũng đặt CFBundleName là tùy chọn, vì phiên bản được giới thiệu có "CFBundleDisplayName" có lẽ không hoạt động trong phiên bản của tôi. Vì vậy, bây giờ nếu nó không có mặt, nó sẽ không bị lỗi mà chỉ không hiển thị Tên ứng dụng trong cảnh báo.

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

Tôi thực hiện cuộc gọi này để thêm nút xác nhận:

AppUpdater.shared.showUpdate(withConfirmation: true)

Hoặc gọi nó được gọi như thế này để có tùy chọn cập nhật lực lượng trên:

AppUpdater.shared.showUpdate(withConfirmation: false)

Bất kỳ ý tưởng về cách kiểm tra điều này? Nếu nó không hoạt động bình thường, cách duy nhất để gỡ lỗi là bằng cách nào đó gỡ lỗi phiên bản cũ hơn trong cửa hàng ứng dụng.
David Hiệu trưởng

2
À, đừng bận tâm đến câu hỏi. Tôi chỉ cần thay đổi phiên bản cục bộ của mình thành "cũ hơn".
David Hiệu trưởng

Tôi rất ấn tượng với mã @Vasco của bạn. Một câu hỏi đơn giản, tại sao bạn lại sử dụng 'http' thay vì https trong url đó?
Master AgentX

Cảm ơn rất nhiều vì đã chia sẻ giải pháp này @Vasco! Tôi thích nó :) Tại sao bạn không sử dụng: let config = URLSessionConfiguration.background (withIdentifier: "com.example.MyExample.background") cho URLSession để đạt được yêu cầu nền?
mc_plectrum

Bạn cũng có thể loại bỏ lực mở ra, vì bạn đã kiểm tra xem liệu let appStoreAppVersion = info? .Version và tương tự cho trackURL.
mc_plectrum

7

Đây là phiên bản của tôi sử dụng Swift 4 và thư viện Alamofire phổ biến (tôi vẫn sử dụng nó trong các ứng dụng của mình). Yêu cầu không đồng bộ và bạn có thể chuyển một lệnh gọi lại để được thông báo khi hoàn tất.

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

Cách sử dụng rất đơn giản như sau:

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

1
vấn đề với việc sử dụng ourVersion! = appVersion là nó kích hoạt khi nhóm Đánh giá của App Store kiểm tra phiên bản mới của ứng dụng. Chúng tôi chuyển đổi các chuỗi phiên bản đó thành số và sau đó isNew = appVersion> ourVersion.
budidino

@budidino bạn nói đúng, tôi chỉ đưa ra cách tiếp cận phổ biến bằng cách sử dụng Alamofire. Cách bạn diễn giải phiên bản hoàn toàn phụ thuộc vào ứng dụng và cấu trúc phiên bản của bạn.
Đội trưởng phương Bắc

Chỉ cần thêm ghi chú vào so sánh phiên bản, tôi thích, hãy để serverVersion = "2.7" let localVersion = "2.6.5" let isUpdateAvailable = serverVersion.compare (localVersion, options: .numeric) == .orderedDescending hơn là so sánh với bằng
Chaitu

6

Tôi có thể gợi ý thư viện nhỏ này không: https://github.com/nicklockwood/iVersion

Mục đích của nó là đơn giản hóa việc xử lý các plists từ xa để kích hoạt thông báo.


3
Bạn có thể kiểm tra App Store trực tiếp để biết Số phiên bản thay vì lưu trữ tệp plist ở đâu đó. Hãy xem câu trả lời sau: stackoverflow.com/a/6569307/142358
Steve Moser

1
iVersion hiện sử dụng phiên bản cửa hàng ứng dụng tự động - Danh sách là tùy chọn nếu bạn muốn chỉ định các ghi chú phát hành khác nhau cho các ghi chú trên iTunes, nhưng bạn không cần phải sử dụng nó.
Nick Lockwood

1
Mã này có thể sử dụng một số cải tiến, nhưng tốt hơn nhiều so với các câu trả lời khác gửi yêu cầu đồng bộ. Tuy nhiên, cách nó thực hiện phân luồng là một phong cách tồi. Tôi sẽ gửi các vấn đề trên Github.
uliwitness

Dự án hiện không được dùng nữa 😢
Zorayr

5

Swift 3.1

func needsUpdate() -> Bool {
    let infoDictionary = Bundle.main.infoDictionary
    let appID = infoDictionary!["CFBundleIdentifier"] as! String
    let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(appID)")
    guard let data = try? Data(contentsOf: url) else {
      print("There is an error!")
      return false;
    }
    let lookup = (try? JSONSerialization.jsonObject(with: data! , options: [])) as? [String: Any]
    if let resultCount = lookup!["resultCount"] as? Int, resultCount == 1 {
        if let results = lookup!["results"] as? [[String:Any]] {
            if let appStoreVersion = results[0]["version"] as? String{
                let currentVersion = infoDictionary!["CFBundleShortVersionString"] as? String
                if !(appStoreVersion == currentVersion) {
                    print("Need to update [\(appStoreVersion) != \(currentVersion)]")
                    return true
                }
            }
        }
    }
    return false
}

Sự cố này xảy ra khi bạn không có kết nối internet. let data = try? Dữ liệu (contentOf: url!) Sẽ trả về nil và ở dòng tiếp theo, bạn nhập dữ liệu!
Joris Mans

@JorisMans thx tôi sẽ cập nhật nó không có tai nạn khả năng kết nối internet
Kassem Itani

Đừng làm điều này. Sử dụng URLSession.
JAL

4

Câu trả lời này là sửa đổi cho câu trả lời của datinc https://stackoverflow.com/a/25210143/2735358 .

datinc's funtion so sánh phiên bản bằng cách so sánh chuỗi. Vì vậy, nó sẽ không so sánh phiên bản lớn hơn hoặc nhỏ hơn.

Tuy nhiên, chức năng đã sửa đổi này so sánh phiên bản của NSNumericSearch (so sánh số) .

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

Sử dụng:

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

3
Câu trả lời này làm cho yêu cầu của nó một cách đồng bộ. Điều này có nghĩa là với kết nối kém, ứng dụng của bạn có thể không sử dụng được trong vài phút cho đến khi yêu cầu trả về.
uliwitness

NSURLSession tự động hoạt động trên các luồng nền trừ khi chúng tôi chỉ định khác.
Sebastian Dwornik

4

Tôi đã thấy nhiều cách để kiểm tra cập nhật ứng dụng. vì vậy dựa trên nhiều câu trả lời, tôi kết hợp chúng và tạo ra giải pháp của tôi có sẵn trên GitHub Nếu có yêu cầu cập nhật Vui lòng cho tôi biết. Mã này cho Swift 4

Liên kết GitHub Tới mã này. 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)
    }
}

Tham chiếu: https://stackoverflow.com/a/48810541/5855888https://github.com/emotality/ATAppUpdater

Mã hóa vui vẻ 👍 😊


@Rob Vui lòng kiểm tra GitHub Liên kết github.com/anupgupta-arg/iOS-Swift-ArgAppUpdater
Anup Gupta

3

Hãy thử điều này với một lệnh gọi hàm duy nhất:

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

Chức năng cảnh báo để mở URL AppStore:

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)

}

Cách gọi hàm trên:

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

Để biết thêm chi tiết, hãy thử liên kết dưới đây với mã đầy đủ:

AppStoreUpdate.swift

ItunesAppInfoResult.swift

ItunesAppInfoItunes.swift

Tôi hy vọng điều này sẽ hữu ích!


2

Đây là một phương pháp nhanh chóng thực hiện những gì một số câu trả lời Objective-C gợi ý. Rõ ràng, khi bạn nhận được thông tin từ cửa hàng ứng dụng JSON, bạn có thể trích xuất các ghi chú phát hành, nếu bạn muốn.

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 là url của ứng dụng trong appstore?
iamthevoid

@Mario Hendricks tính năng này không hoạt động trong thời gian nhanh chóng 3. Nó có một số lỗi. Bạn có thể vui lòng cập nhật cho swift 3 không?
George Asda

Câu trả lời này làm cho yêu cầu của nó một cách đồng bộ. Điều này có nghĩa là với kết nối kém, ứng dụng của bạn có thể không sử dụng được trong vài phút cho đến khi yêu cầu trả về.
uliwitness

2

Nếu bạn không đặt loại nội dung trong NSUrlRequest thì chắc chắn bạn sẽ không nhận được phản hồi, vì vậy hãy thử đoạn mã dưới đây, nó hoạt động tốt đối với tôi. Hy vọng nó giúp....

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

Câu trả lời này làm cho yêu cầu của nó một cách đồng bộ. Điều này có nghĩa là với kết nối kém, ứng dụng của bạn có thể không sử dụng được trong vài phút cho đến khi yêu cầu trả về.
uliwitness

2

Đến từ một ứng dụng kết hợp POV, đây là một ví dụ về javascript, tôi có chân trang Có sẵn Cập nhật trên menu chính của mình. Nếu có bản cập nhật (tức là số phiên bản của tôi trong tệp cấu hình ít hơn phiên bản được truy xuất, hãy hiển thị chân trang) Sau đó, điều này sẽ hướng người dùng đến cửa hàng ứng dụng, nơi người dùng có thể nhấp vào nút cập nhật.

Tôi cũng nhận được dữ liệu mới (tức là Ghi chú phát hành) và hiển thị chúng trong một phương thức khi đăng nhập nếu đây là lần đầu tiên trên phiên bản này.

Phương pháp Cập nhật Có sẵn có thể được chạy thường xuyên nếu bạn muốn. Của tôi được chạy mỗi khi người dùng điều hướng đến màn hình chính.

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

}

Gọi lại: Apple có một API, rất dễ lấy

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

Cảnh báo: Hầu hết các câu trả lời được đưa ra đều truy xuất đồng bộ URL (sử dụng -dataWithContentsOfURL:hoặc -sendSynchronousRequest:. Điều này không tốt, vì nó có nghĩa là ứng dụng của bạn sẽ không phản hồi trong vài phút nếu kết nối di động bị ngắt trong khi yêu cầu đang được thực hiện. Không bao giờ truy cập internet đồng bộ trên luồng chính.

Câu trả lời đúng là sử dụng API không đồng bộ:

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

Thời gian chờ mặc định cho các kết nối mạng là vài phút và ngay cả khi yêu cầu được thực hiện, nó có thể đủ chậm so với kết nối EDGE kém để mất nhiều thời gian như vậy. Bạn không muốn ứng dụng của mình không sử dụng được trong trường hợp đó. Để kiểm tra những thứ như thế này, sẽ rất hữu ích khi chạy mã mạng của bạn với Network Link Conditioner của Apple.


Cảm ơn cho câu hỏi này giữ sống :-)
byJeevan

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
}

để so sánh chuỗi phiên bản:

https://github.com/eure/AppVersionMonitor


2

ĐỐI VỚI SWIFT 4 và 3.2:

Đầu tiên, chúng ta cần lấy id gói từ từ điển thông tin gói, đặt isUpdaet là 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
       }

Sau đó, chúng ta cần gọi một cuộc gọi urlSession để lấy phiên bản từ 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()

MÃ ĐẦY ĐỦ SẼ LÀ NHƯ THẾ NÀY:

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

Sau đó, chúng ta có thể gọi hàm bất kỳ phần mềm nào chúng ta cần.

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

2

Tương đương C # của @datinc, ngang với việc lấy phiên bản Apple App Store. Mã bao gồm để lấy phiên bản cho cả gói hoặc tệp AssemblyInfo.

CHỈNH SỬA :: Vui lòng lưu ý khu vực, "/ us /", được bao gồm trong chuỗi url. Mã quốc gia này sẽ cần được xử lý / thay đổi cho phù hợp.

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

Câu hỏi này được hỏi vào năm 2011, tôi đã tìm thấy câu hỏi này vào năm 2018 khi đang tìm kiếm một số cách để không chỉ kiểm tra phiên bản ứng dụng mới trong App Store mà còn thông báo cho người dùng về nó.

Sau khi nghiên cứu nhỏ, tôi đã rút ra kết luận rằng câu trả lời của juanjo (liên quan đến Swift 3) https://stackoverflow.com/a/40939740/1218405 là giải pháp tối ưu nếu bạn muốn tự làm điều này bằng mã.

Ngoài ra, tôi có thể đề xuất hai dự án tuyệt vời trên GitHub (hơn 2300 sao mỗi dự án)

Ví dụ cho Siren (AppDelegate.swift)

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

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

      return true
    }
  • Bạn cũng có thể hiển thị các loại cảnh báo khác nhau về phiên bản mới (cho phép bỏ qua phiên bản hoặc buộc người dùng cập nhật)
  • Bạn có thể chỉ định tần suất kiểm tra phiên bản sẽ diễn ra (hàng ngày / hàng tuần / ngay lập tức)
  • Bạn có thể chỉ định bao nhiêu ngày sau khi phiên bản mới phát hành cho cửa hàng ứng dụng, cảnh báo sẽ xuất hiện

Các liên kết đến một câu trả lời hiện có không phải là câu trả lời. Ngoài ra, liên kết đến thư viện cũng không phải là câu trả lời trừ khi bạn thêm rõ ràng cách liên kết trả lời câu hỏi vào câu trả lời của bạn (thêm ví dụ về mã, v.v.).
JAL

1

Swift 4

Chúng tôi có thể sử dụng cái mới JSONDecoderđể phân tích cú pháp phản hồi từ itunes.apple.com/lookup và biểu diễn nó bằng các lớp hoặc cấu trúc có thể giải mã:

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

class AppInfo: Decodable {
    var version: String
}

Chúng tôi cũng có thể thêm các thuộc tính khác vào AppInfotrong trường hợp chúng tôi cầnreleaseNotes hoặc một số thuộc tính khác.

Bây giờ chúng ta có thể tạo yêu cầu không đồng bộ bằng cách sử dụng 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
}

Hàm này nhận một bao đóng hoàn thành sẽ được gọi khi yêu cầu được hoàn thành và trả về một URLSessionDataTasktrong trường hợp chúng ta cần hủy yêu cầu và có thể được gọi như thế này:

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

Bạn đã đặt mã này ở đâu? Tôi thấy rằng bạn đặt LookupResult và AppInfo thành có thể giải mã được, nhưng tôi không thấy chúng được lưu ở đâu. Tôi còn thiếu gì ở đây?
jessi

Bạn khai báo LookupResultAppInfocác lớp học ở đâu đó trong dự án của bạn, trong một file riêng biệt tốt: Chúng được sử dụng khi bạn giải mã các phản ứng: JSONDecoder().decode(LookupResult.self, from: data)và chúng chứa chuỗi phiên bản
Juanjo

Dựa trên câu trả lời của bạn tôi có thể tạo một tập tin sử dụng mã của bạn Vui lòng kiểm tra rằng iOS-Swift-ArgAppUpdater
Anup Gupta

@jessi xin vui lòng kiểm tra mã của tôi trên GitHub tôi đăng ở đó giải pháp của bạn
Anup Gupta

0

Đề xuất mã của tôi. Dựa trên câu trả lời của @datinc và @ Mario-Hendricks

Tất nhiên, bạn nên thay thế dlog_Errorbằng cuộc gọi func ghi nhật ký của mình.

Loại cấu trúc mã này sẽ ngăn ứng dụng của bạn bị treo trong trường hợp có lỗi. Đối với việc tìm nạp, appStoreAppVersionkhông bắt buộc và không nên dẫn đến các lỗi nghiêm trọng. Chưa hết, với loại cấu trúc mã này, bạn sẽ vẫn ghi được lỗi không nghiêm trọng của mình.

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
Câu trả lời này làm cho yêu cầu của nó một cách đồng bộ. Điều này có nghĩa là với kết nối kém, ứng dụng của bạn có thể không sử dụng được trong vài phút cho đến khi yêu cầu trả về.
uliwitness

-1

Đã cập nhật cho swift 3:

nếu bạn muốn kiểm tra phiên bản hiện tại của ứng dụng của mình, hãy sử dụng mã đơn giản bên dưới:

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

  let version = object as! String
  print("version: \(version)")
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.