जांचें कि क्या मेरे ऐप का AppStore पर एक नया संस्करण है


112

यदि उपयोगकर्ता इसमें है तो मैं अपने ऐप के लिए नए अपडेट को मैन्युअल रूप से जांचना चाहूंगा, और उसे नया संस्करण डाउनलोड करने के लिए संकेत दूंगा। क्या मैं ऐप स्टोर में अपने ऐप के संस्करण की जांच करके - प्रोग्रामेटिक रूप से कर सकता हूं?


6
आप एक वेब-सर्वर पर एक यादृच्छिक पृष्ठ रख सकते हैं जो केवल नवीनतम संस्करण का एक स्ट्रिंग प्रतिनिधित्व लौटाता है। इसे डाउनलोड करें और ऐप स्टार्टअप पर तुलना करें और उपयोगकर्ता को सूचित करें। (त्वरित और आसान तरीका)
लौवहोपले

1
धन्यवाद, लेकिन मैं एपीआई के कुछ प्रकार की तरह एक बेहतर समाधान की उम्मीद कर रहा था जिसके साथ मैं ऐप स्टोर की कार्यक्षमता को कॉल कर सकता हूं, जैसे कि मेरे ऐप नंबर की खोज करें और संस्करण डेटा प्राप्त करें। इस प्रयोजन के लिए एक वेबसर्वर बनाए रखने के लिए समय बचाता है, लेकिन वैसे भी सूचक के लिए धन्यवाद!
user542584

मैं पहली टिप्पणी के रूप में एक ही बात करते हैं। मैंने एक प्रविष्टि के साथ एक प्लिस्ट लिखा: एक NSNumberसंस्करण संख्या। फिर मैंने इसे अपनी वेबसाइट पर अपलोड कर दिया। वही वेबसाइट viewDidLoadजिसका उपयोग मैं अपने ऐप सपोर्ट और ऐप वेबपेज के लिए करता हूं, फिर , मैं वहां संस्करण संख्या के लिए वेबसाइट की जांच करता हूं और अपने ऐप में वर्तमान संस्करण की जांच करता हूं। फिर मेरे पास एक प्रीमेड है alertViewजो स्वचालित रूप से ऐप को अपडेट करने का संकेत देता है। यदि आप चाहें तो मैं कोड प्रदान कर सकता हूं।
एंड्रयू

धन्यवाद, मुझे लगता है कि मुझे भी कोशिश करनी चाहिए ..
user542584

जवाबों:


88

यहां एक सरल कोड स्निपेट दिया गया है, जो आपको बता सकता है कि वर्तमान संस्करण अलग है या नहीं

-(BOOL) needsUpdate{
    NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary];
    NSString* appID = infoDictionary[@"CFBundleIdentifier"];
    NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"http://itunes.apple.com/lookup?bundleId=%@", appID]];
    NSData* data = [NSData dataWithContentsOfURL:url];
    NSDictionary* lookup = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

    if ([lookup[@"resultCount"] integerValue] == 1){
        NSString* appStoreVersion = lookup[@"results"][0][@"version"];
        NSString* currentVersion = infoDictionary[@"CFBundleShortVersionString"];
        if (![appStoreVersion isEqualToString:currentVersion]){
            NSLog(@"Need to update [%@ != %@]", appStoreVersion, currentVersion);
            return YES;
        }
    }
    return NO;
}

नोट: सुनिश्चित करें कि जब आप iTunes में नया संस्करण दर्ज करते हैं, तो यह उस ऐप के संस्करण से मेल खाता है जिसे आप जारी कर रहे हैं। यदि नहीं, तो उपर्युक्त कोड हमेशा उपयोगकर्ता की परवाह किए बिना हां को वापस कर देगा।


4
सुपर सॉल्यूशन मैंने कभी +1 पाया
संजय चंगानी

1
@MobeenAfzal, मुझे लगता है कि आपको याद है सवाल और समाधान समझ में आया। उपरोक्त समाधान स्टोर पर संस्करण के साथ वर्तमान संस्करण की तुलना करता है। यदि वे मेल नहीं खाते हैं, तो यह हाँ को वापस ले लेता है, अन्यथा यह नहीं लौटाता है। कोई फर्क नहीं पड़ता कि ऐप स्टोर पर इतिहास उपरोक्त विधि YES को वापस कर देगा यदि वर्तमान संस्करण अलग है तो ऐप स्टोर संस्करण। उपयोगकर्ता द्वारा अपडेट किए जाने के बाद ... वर्तमान संस्करण ऐप स्टोर संस्करण के बराबर है। यदि उपयोगकर्ता का संस्करण 1.0 और ऐप स्टोर का संस्करण 1.2 है, तो उपरोक्त विधि हमेशा YES को लौटाएगी।
१६:१५

1
@MobeenAfzal मुझे लगता है कि मुझे वही मिल रहा है जो आप देख रहे हैं। कोड में आपका संस्करण 1.7 है, लेकिन आईट्यून्स में आपने संस्करण को 1.6 के रूप में अपलोड किया है ताकि आपके उपयोगकर्ता नहीं जानते कि आपने संस्करण को छोड़ दिया है। क्या यह मामला है? यदि ऐसा है तो ... आपको जो कुछ भी चाहिए वह सर्वर है (ड्रॉपबॉक्स) आपके एप्लिकेशन संस्करण संख्या की सेवा करेगा और उस समापन बिंदु तक पहुंचने के लिए अपने कोड को संशोधित करेगा। मुझे बताएं कि क्या यह आप देख रहे हैं और मैं पोस्ट में चेतावनी का एक नोट जोड़ूंगा।
रात्रि

1
@MobeenAfzal आप अपनी टिप्पणी भ्रामक है। यदि उपयोगकर्ता के डिवाइस पर संस्करण एपस्टोर पर किसी भी संस्करण से अलग हो जाता है तो कोड उम्मीद के मुताबिक YES को लौटा देगा। यहां तक ​​कि अगर आप संस्करण १.१ जारी करते हैं तो १.१११ संस्करण के बाद भी यह पूरी तरह से काम करेगा।
डेटासिन

1
हमें केवल तभी अपडेट दिखाना चाहिए जब ऐपस्टोर संस्करण वर्तमान संस्करण की तुलना में अधिक है। अगर ([appStoreVersion तुलना करें: currentVersion विकल्प: NSNumericSearch] == NSOrderedDescending) {NSLog (@ "\ n \ n अद्यतन करने के लिए। Appstore संस्करण% @% @ से अधिक है", appStoreVersion, currentVersion)। }
नितेश बोरड़

52

स्विफ्ट 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
}

मुझे लगता है कि झूठी वापसी के बजाय एक त्रुटि को फेंकना बेहतर है, इस मामले में मैंने एक संस्करण बनाया, लेकिन यह कुछ और हो सकता है जिसे आप परिभाषित करते हैं या NSError

enum VersionError: Error {
    case invalidResponse, invalidBundleInfo
}

इस फ़ंक्शन को किसी अन्य थ्रेड से कॉल करने पर विचार करें, यदि कनेक्शन धीमा है, तो यह वर्तमान थ्रेड को ब्लॉक कर सकता है।

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

अपडेट करें

URLSession का उपयोग:

Data(contentsOf: url)एक धागे का उपयोग करने और ब्लॉक करने के बजाय , हम उपयोग कर सकते हैं URLSession:

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

उदाहरण:

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

1
यह उत्तर इसके अनुरोध को समकालिक बनाता है। खराब कनेक्शन के साथ इसका मतलब है, अनुरोध वापस होने तक आपका ऐप मिनटों के लिए अनुपयोगी हो सकता है।
उलिवाह

4
मैं असहमत हूं, DispatchQueue.global()आपको एक पृष्ठभूमि कतार देता है, डेटा उस कतार में लोड होता है और डेटा लोड होने पर केवल मुख्य कतार में वापस जाता है।
जुआनजो

ओह। किसी तरह मैंने उस दूसरे कोड स्निपेट को अनदेखा कर दिया। अफसोस की बात है, ऐसा लगता है कि मैं तब तक डाउनवोट नहीं निकाल सकता, जब तक कि आपका जवाब फिर से संपादित नहीं किया जाता :-( BTW - डेटा दिया गया है । बस अतुल्यकालिक NSURLSession कॉल का उपयोग करने वे भी आप मुख्य थ्रेड पर वापस फोन संपन्न कर लिए जाने चाहते हैं।
uliwitness

@ जुआनजो ,,,, स्विफ्ट 3.0.1 के लिए काम नहीं कर रहा है, कृपया यू स्विफ्ट के लिए अपडेट किया जा सकता है ???
किरण जाधव

2
ध्यान दें कि यदि आप केवल एक विशिष्ट स्टोर में सूचीबद्ध हैं, तो मैंने पाया है कि आपको URL में एक देश कोड जोड़ना होगा - जैसे GB itunes.apple.com/(countryCode)/… )
रयान हेइटनर

13

स्टीव मोजर को उनके लिंक के लिए धन्यवाद, यहाँ मेरा कोड है:

NSString *appInfoUrl = @"http://itunes.apple.com/en/lookup?bundleId=XXXXXXXXX";

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:appInfoUrl]];
[request setHTTPMethod:@"GET"];

NSURLResponse *response;
NSError *error;
NSData *data = [NSURLConnection  sendSynchronousRequest:request returningResponse: &response error: &error];
NSString *output = [NSString stringWithCString:[data bytes] length:[data length]];

NSError *e = nil;
NSData *jsonData = [output dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error: &e];

NSString *version = [[[jsonDict objectForKey:@"results"] objectAtIndex:0] objectForKey:@"version"];

1
बहुत अच्छा और सही समाधान, url के बारे में बस थोड़ा सा अपडेट itunes.apple.com/en/lookup?bundleId=xxxxxxxxxx
SJ

धन्यवाद, आपकी टिप्पणी लागू हुई
रूजबेह ज़ाबिओलाही

4
वास्तव में यह मेरे लिए /en/उपपथ के साथ काम नहीं करता था । इसे हटाने के बाद, इसने काम किया
गैस्पारफ

यह उत्तर इसके अनुरोध को समकालिक बनाता है। खराब कनेक्शन के साथ इसका मतलब है, अनुरोध वापस होने तक आपका ऐप मिनटों के लिए अनुपयोगी हो सकता है।
अल्विहार्ट

1
मुझे / en / itunes.apple.com/lookup?bundleId=xxxxxxx के साथ प्रयोग करना था , धन्यवाद @gasparuff
फर्नांडो पेरेज़

13

चूंकि मैं उसी समस्या का सामना कर रहा था, इसलिए मुझे मारियो हेंड्रिक द्वारा प्रदान किया गया उत्तर मिला । अनफॉर्नेटली जब मैंने अपने प्रोजेक्ट पर उनके कोड को आगे बढ़ाने का प्रयास किया, तो XCode ने कास्टिंग समस्याओं के बारे में शिकायत करते हुए कहा "MDLMaterialProperty के पास कोई सबस्क्रिप्ट सदस्य नहीं हैं"। उनका कोड इस MDLMaterial को सेट करने की कोशिश कर रहा था ... निरंतर "लुकअपResult" के प्रकार के रूप में, हर एक बार "इंट" को विफल करने के लिए कास्टिंग बनाता है। मेरे समाधान करने के लिए मेरे चर के लिए एक प्रकार का एनोटेशन प्रदान करना था NSDictionary मूल्य की तरह मैं जरूरत के बारे में स्पष्ट किया जाना है। उस के साथ, मैं मूल्य "संस्करण" तक पहुंच सकता था जो मुझे चाहिए था।

अवलोकन करें: इस मूल उद्देश्य के लिए , आप अपने 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
}

इस कोड में सुधार के सभी सुझावों का स्वागत है!


यह उत्तर इसके अनुरोध को समकालिक बनाता है। खराब कनेक्शन के साथ इसका मतलब है, अनुरोध वापस होने तक आपका ऐप मिनटों के लिए अनुपयोगी हो सकता है।
अल्विहार्ट

@ यागो जरदो कृपया फंक्शन तुलना का उपयोग करें अन्यथा जब उपयोगकर्ता ऐप अपलोड करें। परीक्षण किया गया समय प्रदर्शन अपडेट अद्यतन चेतावनी या ऐप्पल आपके ऐप को अस्वीकार कर दें
जिगर दरजी

अरे @ जीगर, सलाह के लिए धन्यवाद। मैं वर्तमान में अपने ऐप पर इस पद्धति का उपयोग नहीं कर रहा हूं, क्योंकि अब हम अपने सर्वर में सब कुछ संस्करण कर रहे हैं। वैसे भी, आप बेहतर बता सकते हैं कि आपने क्या कहा? मुझे समझ नहीं आया और यह वास्तव में एक अच्छी बात है। अग्रिम में धन्यवाद।
यागो जरदो

टिप के लिए @uliwitness धन्यवाद, इसने वास्तव में मुझे अतुल्यकालिक और तुल्यकालिक अनुरोधों के बारे में जानने के लिए अपने कोड को सामान्य रूप से सुधारने में मदद की।
यागो जार्डो

वह लिंक एक रत्न है!
B3none

13

बस ATAPUpdater का उपयोग करें । यह 1 पंक्ति, धागा-सुरक्षित और तेज है। यदि आपके पास उपयोगकर्ता कार्रवाई को ट्रैक करना चाहते हैं, तो इसके प्रतिनिधि तरीके भी हैं।

यहाँ एक उदाहरण है:

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

   return YES;
}

वैकल्पिक प्रतिनिधि तरीके:

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

1
क्या यह टेस्टफेलाइट में बीटा वर्जन के लिए काम करेगा? यदि नहीं, तो क्या कोई उपकरण है?
लुकाज़ सेज़रविंस्की

नहीं, यह नहीं होगा, यह केवल वर्तमान संस्करण की तुलना नवीनतम संस्करण के साथ करता है जो AppStore पर है।
भावुकता

क्या हम स्विफ्ट के साथ इसका इस्तेमाल कर सकते हैं?
जोरावर

11

इस धागे पर पोस्ट किए गए एक महान जवाब को सरल बनाया । का उपयोग कर Swift 4और Alamofire

import Alamofire

class VersionCheck {

  public static let shared = VersionCheck()

  func isUpdateAvailable(callback: @escaping (Bool)->Void) {
    let bundleId = Bundle.main.infoDictionary!["CFBundleIdentifier"] as! String
    Alamofire.request("https://itunes.apple.com/lookup?bundleId=\(bundleId)").responseJSON { response in
      if let json = response.result.value as? NSDictionary, let results = json["results"] as? NSArray, let entry = results.firstObject as? NSDictionary, let versionStore = entry["version"] as? String, let versionLocal = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
        let arrayStore = versionStore.split(separator: ".")
        let arrayLocal = versionLocal.split(separator: ".")

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

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

}

और फिर इसका उपयोग करने के लिए:

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

2
मेरा आवेदन स्टोर पर लाइव है लेकिन वही एपीआई संस्करण जानकारी नहीं लौटा रहा है। प्रतिक्रिया:{ "resultCount":0, "results": [] }
टेक्नीशियन

संस्करण तुलना में एक नोट जोड़ते हुए, मैं पसंद करूंगा, ServerVersion = "2.7" let localVersion = "2.6.5" let isUpdateAvailable = serverVersion.compare (localVersion, विकल्प: .numeric ===orderedDescending) को बदलने के बजाय। खाली के साथ।
चैतू

सुझाव के लिए @Chaitu धन्यवाद। मैंने कोड के तुलनात्मक भाग को फिर से लिखना समाप्त कर दिया है
budidino

9

अनूप गुप्ता से स्विफ्ट 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)

यह कैसे परीक्षण करने के लिए पर कोई विचार? यदि यह सही काम करने में विफल रहता है, तो इसे डिबग करने का एकमात्र तरीका किसी पुराने संस्करण को डिबग करना है, जो ऐप स्टोर में है।
डेविड रेक्टर

2
आह, सवाल का कभी बुरा मत मानना। मैं बस अपने स्थानीय संस्करण को "पुराना" होने के लिए बदल सकता हूं।
डेविड रेक्टर

मैं आपके कोड @Vasco से प्रभावित हूं। बस एक आसान सा सवाल, आपने उस url में https के बजाय 'http' का उपयोग क्यों किया है?
मास्टर एजेंटएक्स

इस समाधान को साझा करने के लिए बहुत बहुत धन्यवाद @Vasco! मुझे यह पसंद है :) आप इसका उपयोग क्यों नहीं करते हैं: पृष्ठभूमि अनुरोध प्राप्त करने के लिए URLSession के लिए config = URLSessionConfiguration.background (withIdentifier: "com.example.MyExample.background") दें?
mc_plectrum

यदि आप पहले से ही जांच कर लेते हैं, तो अगर आप appStoreAppVersion = info .version और trackURL के लिए भी ऐसा ही करते हैं, तो आप पहले से जाँच कर सकते हैं।
mc_plectrum

7

यहां स्विफ्ट 4 और लोकप्रिय अलमोफ़ायर लाइब्रेरी का उपयोग करके मेरा संस्करण है (मैं वैसे भी अपने ऐप में इसका उपयोग करता हूं)। अनुरोध अतुल्यकालिक है और जब किया जाता है तो आप कॉलबैक को अधिसूचित कर सकते हैं।

import Alamofire

class VersionCheck {

    public static let shared = VersionCheck()

    var newVersionAvailable: Bool?
    var appStoreVersion: String?

    func checkAppStore(callback: ((_ versionAvailable: Bool?, _ version: String?)->Void)? = nil) {
        let ourBundleId = Bundle.main.infoDictionary!["CFBundleIdentifier"] as! String
        Alamofire.request("https://itunes.apple.com/lookup?bundleId=\(ourBundleId)").responseJSON { response in
            var isNew: Bool?
            var versionStr: String?

            if let json = response.result.value as? NSDictionary,
               let results = json["results"] as? NSArray,
               let entry = results.firstObject as? NSDictionary,
               let appVersion = entry["version"] as? String,
               let ourVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
            {
                isNew = ourVersion != appVersion
                versionStr = appVersion
            }

            self.appStoreVersion = versionStr
            self.newVersionAvailable = isNew
            callback?(isNew, versionStr)
        }
    }
}

उपयोग इस तरह सरल है:

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

1
हमारे विसर्जन का उपयोग करने में समस्या! = appVersion यह है कि यह तब ट्रिगर होता है जब ऐप स्टोर की समीक्षा टीम ऐप के नए संस्करण की जांच करती है। हम उन संस्करण स्ट्रिंग्स को संख्याओं में परिवर्तित करते हैं और फिर नया = appVersion> ourVersion।
मित्रो

@budidino आप सही कह रहे हैं, मैंने सिर्फ Alamofire का उपयोग करके सामान्य दृष्टिकोण दिखाया। आप कैसे व्याख्या करते हैं संस्करण पूरी तरह से आपके ऐप और संस्करण की संरचना पर निर्भर करता है।
उत्तरी कप्तान

बस संस्करण तुलना के लिए एक नोट जोड़ने, मैं, पसंद करेंगे serverVersion जाने = "2.7" जाने localVersion = "2.6.5" जाने isUpdateAvailable = serverVersion.compare (localVersion, विकल्प: .numeric) == बजाय .orderedDescending बराबर के साथ तुलना
चैतू

6

क्या मैं इस छोटी सी लाइब्रेरी का सुझाव दे सकता हूं: https://github.com/nicklockwood/iVersion

इसका उद्देश्य सूचनाओं को ट्रिगर करने के लिए दूरदराज के पौधों की हैंडलिंग को सरल बनाना है।


3
आप कहीं भी एक प्लिस्ट फ़ाइल की मेजबानी करने के बजाय संस्करण संख्या के लिए सीधे ऐप स्टोर की जांच कर सकते हैं। इस उत्तर को देखें: stackoverflow.com/a/6569307/142358
स्टीव मोजर

1
iVersion अब ऐप स्टोर संस्करण को स्वचालित रूप से उपयोग करता है - प्लैटिन वैकल्पिक है यदि आप आईट्यून्स पर अलग-अलग रिलीज़ नोट्स निर्दिष्ट करना चाहते हैं, लेकिन आपको इसका उपयोग करने की आवश्यकता नहीं है।
निक लॉकवुड

1
यह कोड कुछ सुधारों का उपयोग कर सकता है, लेकिन एक तुल्यकालिक अनुरोध भेजने वाले अन्य उत्तरों की तुलना में बहुत बेहतर है। फिर भी, जिस तरह से यह थ्रेडिंग करता है वह खराब शैली है। मैं गितुब पर मुद्दों को दर्ज करूँगा।
उलिवाह

इस परियोजना को अब 😢
Zorayr

5

स्विफ्ट 3.1

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

यह तब क्रैश होता है जब आपके पास कोई इंटरनेट कनेक्शन नहीं होता है। चलो डेटा = प्रयास करें? डेटा (contentOf: url!) शून्य वापस आ जाएगा, और अगली पंक्ति में आप डेटा करते हैं!
जोरिस मैन्स

THX @JorisMans मुझे कोई इंटरनेट कनेक्टिविटी दुर्घटना के लिए यह अद्यतन करेगा
Kassem Itani

यह मत करो। का उपयोग करें URLSession
जाल

4

यह उत्तर डेटासिन के उत्तर 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
    }
}];

3
यह उत्तर इसके अनुरोध को समकालिक बनाता है। खराब कनेक्शन के साथ इसका मतलब है, अनुरोध वापस होने तक आपका ऐप मिनटों के लिए अनुपयोगी हो सकता है।
उलिवाह

NSURLSession स्वचालित रूप से पृष्ठभूमि थ्रेड्स पर काम करता है जब तक कि हम अन्यथा निर्दिष्ट न करें।
सेबस्टियन डोरोनिक

4

मैंने ऐप अपडेट को जांचने के कई तरीके देखे। इसलिए कई उत्तरों के आधार पर मैं उन्हें मिलाता हूं और अपना समाधान बनाता हूं जो कि GitHub पर उपलब्ध है यदि किसी भी अपडेट की आवश्यकता है तो कृपया मुझे बताएं। स्विफ्ट 4 के लिए यह कोड

GitHub इस कोड से लिंक करें। https://github.com/anupgupta-arg/iOS-Swift-ArgAppUpdater

   import UIKit

enum VersionError: Error {
    case invalidBundleInfo, invalidResponse
}

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

class AppInfo: Decodable {
    var version: String
    var trackViewUrl: String
    //let identifier = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String,
    // You can add many thing based on "http://itunes.apple.com/lookup?bundleId=\(identifier)"  response
    // here version and trackViewUrl are key of URL response
    // so you can add all key beased on your requirement.

}

class ArgAppUpdater: NSObject {
    private static var _instance: ArgAppUpdater?;

    private override init() {

    }

    public static func getSingleton() -> ArgAppUpdater {
        if (ArgAppUpdater._instance == nil) {
            ArgAppUpdater._instance = ArgAppUpdater.init();
        }
        return ArgAppUpdater._instance!;
    }

    private func getAppInfo(completion: @escaping (AppInfo?, Error?) -> Void) -> URLSessionDataTask? {
        guard let identifier = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String,
            let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(identifier)") else {
                DispatchQueue.main.async {
                    completion(nil, VersionError.invalidBundleInfo)
                }
                return nil
        }
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            do {
                if let error = error { throw error }
                guard let data = data else { throw VersionError.invalidResponse }

                print("Data:::",data)
                print("response###",response!)

                let result = try JSONDecoder().decode(LookupResult.self, from: data)

                let dictionary = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves)

                print("dictionary",dictionary!)


                guard let info = result.results.first else { throw VersionError.invalidResponse }
                print("result:::",result)
                completion(info, nil)
            } catch {
                completion(nil, error)
            }
        }
        task.resume()

        print("task ******", task)
        return task
    }
    private  func checkVersion(force: Bool) {
        let info = Bundle.main.infoDictionary
        let currentVersion = info?["CFBundleShortVersionString"] as? String
        _ = getAppInfo { (info, error) in

            let appStoreAppVersion = info?.version

            if let error = error {
                print(error)



            }else if appStoreAppVersion!.compare(currentVersion!, options: .numeric) == .orderedDescending {
                //                print("needs update")
               // print("hiiii")
                DispatchQueue.main.async {
                    let topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!

                    topController.showAppUpdateAlert(Version: (info?.version)!, Force: force, AppURL: (info?.trackViewUrl)!)
            }

            }
        }


    }

    func showUpdateWithConfirmation() {
        checkVersion(force : false)


    }

    func showUpdateWithForce() {
        checkVersion(force : true)
    }



}

extension UIViewController {


    fileprivate func showAppUpdateAlert( Version : String, Force: Bool, AppURL: String) {
        print("AppURL:::::",AppURL)

        let bundleName = Bundle.main.infoDictionary!["CFBundleDisplayName"] as! String;
        let alertMessage = "\(bundleName) Version \(Version) is available on AppStore."
        let alertTitle = "New Version"


        let alertController = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .alert)


        if !Force {
            let notNowButton = UIAlertAction(title: "Not Now", style: .default) { (action:UIAlertAction) in
                print("Don't Call API");


            }
            alertController.addAction(notNowButton)
        }

        let updateButton = UIAlertAction(title: "Update", style: .default) { (action:UIAlertAction) in
            print("Call API");
            print("No update")
            guard let url = URL(string: AppURL) else {
                return
            }
            if #available(iOS 10.0, *) {
                UIApplication.shared.open(url, options: [:], completionHandler: nil)
            } else {
                UIApplication.shared.openURL(url)
            }

        }

        alertController.addAction(updateButton)
        self.present(alertController, animated: true, completion: nil)
    }
}

Refrence: https://stackoverflow.com/a/48810541/5855888 और https://github.com/emotality/ATAppUpdater

हैप्पी कोडिंग 👍 👍



3

एकल फ़ंक्शन कॉल के साथ इसे आज़माएं:

func showAppStoreVersionUpdateAlert(isForceUpdate: Bool) {

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

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

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

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

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

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

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

AppStore URL खोलने के लिए फंक्शन अलर्ट:

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

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

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

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

    }))

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

}

उपरोक्त फ़ंक्शन को कैसे कॉल करें:

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

अधिक विस्तार के लिए नीचे दिए गए लिंक को पूर्ण कोड के साथ देखें:

AppStoreUpdate.swift

ItunesAppInfoResult.swift

ItunesAppInfoItunes.swift

मुझे आशा है कि इससे मदद मिलेगी!


2

यहां एक स्विफ्ट विधि है जो कुछ उद्देश्य-सी उत्तर का सुझाव देती है। जाहिर है, एक बार जब आप ऐप स्टोर JSON से जानकारी प्राप्त करते हैं, तो आप रिलीज़ नोट्स निकाल सकते हैं, यदि आप उन्हें चाहते हैं।

func appUpdateAvailable(storeInfoURL: String) -> Bool
{
    var upgradeAvailable = false

    // Get the main bundle of the app so that we can determine the app's version number
    let bundle = NSBundle.mainBundle()
    if let infoDictionary = bundle.infoDictionary {
        // The URL for this app on the iTunes store uses the Apple ID for the  This never changes, so it is a constant
        let urlOnAppStore = NSURL(string: storeInfoURL)
        if let dataInJSON = NSData(contentsOfURL: urlOnAppStore!) {
            // Try to deserialize the JSON that we got
            if let lookupResults = try? NSJSONSerialization.JSONObjectWithData(dataInJSON, options: NSJSONReadingOptions()) {
                // Determine how many results we got. There should be exactly one, but will be zero if the URL was wrong
                if let resultCount = lookupResults["resultCount"] as? Int {
                    if resultCount == 1 {
                        // Get the version number of the version in the App Store
                        if let appStoreVersion = lookupResults["results"]!![0]["version"] as? String {
                            // Get the version number of the current version
                            if let currentVersion = infoDictionary["CFBundleShortVersionString"] as? String {
                                // Check if they are the same. If not, an upgrade is available.
                                if appStoreVersion != currentVersion {
                                    upgradeAvailable = true                      
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return upgradeAvailable
}

storeInfoURL appstore में app का url है?
IAMthevoid

@Mario Hendricks यह तेजी से काम नहीं कर रहा है। यह कुछ त्रुटियों को फेंकता है। क्या आप कृपया स्विफ्ट 3 के लिए अपडेट कर सकते हैं?
जॉर्ज असदा

यह उत्तर इसके अनुरोध को समकालिक बनाता है। खराब कनेक्शन के साथ इसका मतलब है, अनुरोध वापस होने तक आपका ऐप मिनटों के लिए अनुपयोगी हो सकता है।
उलिवाह

2

यदि आप NSUrlRequest में सामग्री प्रकार सेट नहीं कर रहे हैं, तो सुनिश्चित करें कि आपको प्रतिक्रिया नहीं मिलेगी, इसलिए नीचे दिए गए कोड को आज़माएं, यह मेरे लिए ठीक काम करता है। आशा करता हूँ की ये काम करेगा....

-(BOOL) isUpdateAvailable{
    NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary];
    NSString* appID = infoDictionary[@"CFBundleIdentifier"];
    NSString *urlString = [NSString stringWithFormat:@"https://itunes.apple.com/lookup?bundleId=%@",appID];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:urlString]];
    [request setHTTPMethod:@"GET"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

    NSURLResponse *response;
    NSError *error;
    NSData *data = [NSURLConnection  sendSynchronousRequest:request returningResponse: &response error: &error];
    NSError *e = nil;
    NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error: &e];

    self.versionInAppStore = [[[jsonDict objectForKey:@"results"] objectAtIndex:0] objectForKey:@"version"];

    self.localAppVersion = infoDictionary[@"CFBundleShortVersionString"];

    if ([self.versionInAppStore compare:self.localAppVersion options:NSNumericSearch] == NSOrderedDescending) {
        // currentVersion is lower than the version
        return YES;
    }
    return NO;
}

यह उत्तर इसके अनुरोध को समकालिक बनाता है। खराब कनेक्शन के साथ इसका मतलब है, अनुरोध वापस होने तक आपका ऐप मिनटों के लिए अनुपयोगी हो सकता है।
उलिवाह

2

हाइब्रिड एप्लिकेशन POV से आ रहा है, यह एक जावास्क्रिप्ट उदाहरण है, मेरे पास मेरे मुख्य मेनू पर एक अद्यतन उपलब्ध पाद लेख है। यदि कोई अपडेट उपलब्ध है (यानी, कॉन्फ़िगर फ़ाइल के भीतर मेरा संस्करण संख्या पुनर्प्राप्त किए गए संस्करण से कम है, तो पाद प्रदर्शित करें) यह तब उपयोगकर्ता को ऐप स्टोर पर निर्देशित करेगा, जहां उपयोगकर्ता फिर अपडेट बटन पर क्लिक कर सकता है।

मुझे व्हाट्स न्यू डेटा भी मिलता है (यानी रिलीज़ नोट्स) और लॉगिन पर एक मोडल में प्रदर्शित करें यदि इस संस्करण पर पहली बार।

अद्यतन उपलब्ध पद्धति को जितनी बार चाहें उतनी बार चलाया जा सकता है। हर बार जब उपयोगकर्ता होम स्क्रीन पर नेविगेट करता है तो मेरा भाग जाता है।

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

}

कॉलबैक: ऐप्पल के पास एक एपीआई है, इसलिए इसे प्राप्त करना बहुत आसान है

function isUpdateAvailable_iOS (data) {
    var storeVersion = data.version;
    var releaseNotes = data.releaseNotes;
    // Check store Version Against My App Version ('1.14.3' -> 1143)
    var _storeV = parseInt(storeVersion.replace(/\./g, ''));
    var _appV = parseInt(appVersion.substring(1).replace(/\./g, ''));
    $('#ft-main-menu-btn').off();
    if (_storeV > _appV) {
        // Update Available
        $('#ft-main-menu-btn').text('Update Available');
        $('#ft-main-menu-btn').click(function () {
           // Open Store      
           window.open('https://itunes.apple.com/us/app/appname/idUniqueID', '_system');
        });

    } else {
        $('#ft-main-menu-btn').html('&nbsp;');
        // Release Notes
        settings.updateReleaseNotes('v' + storeVersion, releaseNotes);
    }
}

2

चेतावनी: दिए गए अधिकांश उत्तर URL को सिंक्रोनाइज़ करते हैं (उपयोग कर रहे हैं -dataWithContentsOfURL:या -sendSynchronousRequest:यह खराब है, क्योंकि इसका अर्थ है कि आपका एप्लिकेशन कई मिनटों के लिए अनुत्तरदायी होगा, यदि मोबाइल कनेक्शन ड्रॉप हो जाता है, तो अनुरोध प्रगति पर है। कभी भी इंटरनेट एक्सेस को सिंक्रोनाइज़ नहीं करें । मुख्य सूत्र।

सही उत्तर अतुल्यकालिक एपीआई का उपयोग करना है:

    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 कनेक्शन पर काफी धीमा हो सकता है। आप नहीं चाहते कि आपका ऐप उस मामले में अनुपयोगी हो। इस तरह की चीजों का परीक्षण करने के लिए, ऐप्पल के नेटवर्क लिंक कंडीशनर के साथ अपना नेटवर्किंग कोड चलाना उपयोगी है।


इस सवाल को जीवित रखने के लिए धन्यवाद :-)
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
}

संस्करण स्ट्रिंग की तुलना करने के लिए:

https://github.com/eure/AppVersionMonitor


2

स्विफ्ट 4 और 3.2 के लिए:

सबसे पहले, हमें बंडल आईडी को बंडल जानकारी शब्दकोश से प्राप्त करने की आवश्यकता है, isUpdaet को गलत के रूप में सेट करें।

    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
       }

फिर हमें itunes से संस्करण प्राप्त करने के लिए एक urlSession कॉल करने की आवश्यकता है।

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

पूरा कोड इस तरह होगा:

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

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

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

तब हम फ़ंक्शन को किसी भी जरूरत के लिए कॉल कर सकते हैं।

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

2

Apple ऐप स्टोर संस्करण प्राप्त करने में, @datinc की C # समतुल्यता। बंडल या असेंबलीइन्फो फ़ाइल के लिए संस्करण प्राप्त करने के लिए शामिल कोड।

EDIT :: कृपया इस क्षेत्र को ध्यान दें, "/ us /", urlString में शामिल। इस देश कोड को तदनुसार संभाला / बदलना होगा।

string GetAppStoreVersion()
{
    string version = "";

    NSDictionary infoDictionary = NSBundle
        .MainBundle
        .InfoDictionary;

    String appID = infoDictionary["CFBundleIdentifier"].ToString();

    NSString urlString = 
        new NSString(@"http://itunes.apple.com/us/lookup?bundleId=" + appID);
    NSUrl url = new NSUrl(new System.Uri(urlString).AbsoluteUri);

    NSData data = NSData.FromUrl(url);

    if (data == null)
    {
        /* <-- error obtaining data from url --> */
        return "";
    }

    NSError e = null;
    NSDictionary lookup = (NSDictionary)NSJsonSerialization
        .Deserialize(data, NSJsonReadingOptions.AllowFragments, out e);

    if (lookup == null)
    {
        /* <-- error, most probably no internet or bad connectivity --> */
        return "";
    }

    if (lookup["resultCount"].Description.Equals("1"))
    {
        NSObject nsObject = lookup["results"];
        NSString nsString = new NSString("version");
        String line = nsObject
            .ValueForKey(nsString)
            .Description;

        /* <-- format string --> */
        string[] digits = Regex.Split(line, @"\D+");
        for (int i = 0; i < digits.Length; i++)
        {
            if (int.TryParse(digits[i], out int intTest))
            {
                if (version.Length > 0)
                    version += "." + digits[i];
                else
                    version += digits[i];
            }
        }
    }

    return version;
}

string GetBundleVersion()
{
        return NSBundle
            .MainBundle
            .InfoDictionary["CFBundleShortVersionString"]
            .ToString();
}

string GetAssemblyInfoVersion()
{
        var assembly = typeof(App).GetTypeInfo().Assembly;
        var assemblyName = new AssemblyName(assembly.FullName);
        return assemblyName.Version.ToString();
}

1

यह प्रश्न 2011 में पूछा गया था, मैंने इसे 2018 में खोजा, जबकि न केवल ऐप स्टोर में ऐप के नए संस्करण की जांच करने के लिए, बल्कि इसके बारे में उपयोगकर्ता को सूचित करने के लिए भी।

छोटे शोध के बाद मैं निष्कर्ष पर आया कि जुआनो का उत्तर (स्विफ्ट 3 से संबंधित) https://stackoverflow.com/a/40939740/1218405 यदि आप अपने द्वारा कोड में ऐसा करना चाहते हैं तो यह सबसे उपयुक्त समाधान है।

इसके अलावा मैं GitHub पर दो महान परियोजनाओं का सुझाव दे सकता हूं (प्रत्येक 2300+ सितारे)

सायरन के लिए उदाहरण (AppDelegate.swift)

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

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

      return true
    }
  • आप नए संस्करण के बारे में विभिन्न प्रकार के अलर्ट दिखा सकते हैं (संस्करण को छोड़ना या उपयोगकर्ता को अपडेट करने के लिए मजबूर करना)
  • आप निर्दिष्ट कर सकते हैं कि कितनी बार संस्करण की जाँच होनी चाहिए (दैनिक / साप्ताहिक / तुरंत)
  • आप यह निर्दिष्ट कर सकते हैं कि ऐप स्टोर अलर्ट के लिए जारी किए गए नए संस्करण कितने दिनों के बाद दिखाई दें

मौजूदा उत्तर के लिंक उत्तर नहीं हैं। इसके अतिरिक्त, पुस्तकालयों के लिंक भी उत्तर नहीं हैं जब तक कि आप स्पष्ट रूप से यह नहीं जोड़ते हैं कि लिंक आपके प्रश्न का उत्तर कैसे देता है (कोड उदाहरण जोड़ें, आदि)।
जाल

1

स्विफ्ट 4

हम itunes.apple.com/lookupJSONDecoder से प्रतिक्रिया को पार्स करने के लिए नए का उपयोग कर सकते हैं और इसे डीकोडेबल क्लासेस या स्ट्रक्चर के साथ प्रस्तुत कर सकते हैं:

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

class AppInfo: Decodable {
    var version: String
}

AppInfoजिस स्थिति में हमें आवश्यकता होती है, हम अन्य गुण भी जोड़ सकते हैंreleaseNotes या किसी अन्य संपत्ति की आवश्यकता होती है।

अब हम उपयोग करके एक async अनुरोध कर सकते हैं 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")
        }
    }
}

आपने यह कोड कहां रखा है? II देखें कि आपने LookupResult और AppInfo को डिकोडेबल पर सेट किया है, लेकिन मैं उन्हें कहीं भी सहेजता नहीं देखता। मुझे यहां क्या समझ नहीं आ रहा है?
जेसी

आप अपनी परियोजना में कहीं LookupResultऔर AppInfoकक्षाओं की घोषणा करते हैं , एक अलग फ़ाइल में अधिमानतः: उनका उपयोग तब किया जाता है जब आप प्रतिक्रिया को डिकोड करते हैं: JSONDecoder().decode(LookupResult.self, from: data)और वे संस्करण स्ट्रिंग होते हैं
जुआनो

आपके उत्तर के आधार पर मैं आपके कोड का उपयोग करके एक फ़ाइल बनाता हूं कृपया जाँच करें कि iOS-Swift-ArgAppUpdater
अनूप गुप्ता

@jessi कृपया GitHub पर मेरा कोड जांचें कि मैंने आपका समाधान
अनूप गुप्ता

0

मेरा कोड प्रस्ताव। @Datinc और @ मारियो-हेंड्रिक के जवाबों के आधार पर

आपको निश्चित रूप से प्रतिस्थापित करना चाहिए dlog_Error अपने लॉगिंग फ़ेक कॉल से ।

इस तरह की कोड संरचना आपके ऐप को त्रुटि की स्थिति में दुर्घटनाग्रस्त होने से बचाती है। के लिए लाने के appStoreAppVersionलिए जरूरी नहीं है, और घातक त्रुटियों के लिए नेतृत्व नहीं करना चाहिए। और फिर भी, इस तरह की कोड संरचना के साथ, आप अभी भी अपनी गैर-घातक त्रुटि लॉग करेंगे।

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

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

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

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

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

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

1
यह उत्तर इसके अनुरोध को समकालिक बनाता है। खराब कनेक्शन के साथ इसका मतलब है, अनुरोध वापस होने तक आपका ऐप मिनटों के लिए अनुपयोगी हो सकता है।
उलिवाह

-1

स्विफ्ट 3 के लिए अपडेट किया गया:

यदि आप अपने एप्लिकेशन के वर्तमान संस्करण की जांच करना चाहते हैं, तो सरल कोड के नीचे उपयोग किया जाता है:

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

  let version = object as! String
  print("version: \(version)")
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.