How to update ios6 enterprise apps over the air
Asked Answered
B

5

14

Hello we have developed our first enterprise app recently. We are using the "In-House" option to create the distribution certificate. Client is not using the app yet. But he will be using it soon. Meanwhile i got a question. He will use the app and in future if there are any updates to the app from our side, we want the client to have it updated on his side as well . Like right now I have apps installed on my iPhone. I get update from AppStore saying the XYZ app has been updated. So i install the update. Now if our client is using the app and has saved some data on it(our app uses core data, and we built it in a way that client can store some data on the device) we want to send an update to him that would install the update, but not erase any existing client data.Is that possible? How do i do it?I am using over the air installation right now to install the app. We have a secure server, where the .ipa and .plist files are present and we have a download html page. Client clicks the link and the app gets installed. Please let me know if you need more information. Thanks.

Boarhound answered 4/12, 2012 at 20:13 Comment(1)
check this other question #8439627Expressage
R
27

Yes, it is possible. When you deploy an Enterprise application it requires a plist that contains metadata about the application. This metadata includes the version number that you can use to check for updates.

BOOL updateAvailable = NO;
NSDictionary *updateDictionary = [NSDictionary dictionaryWithContentsOfURL:
                                  [NSURL URLWithString:@"http://www.example.com/pathToPlist"]];

if(updateDictionary)
{
    NSArray *items = [updateDictionary objectForKey:@"items"];
    NSDictionary *itemDict = [items lastObject];

    NSDictionary *metaData = [itemDict objectForKey:@"metadata"];
    NSString *newversion = [metaData valueForKey:@"bundle-version"];
    NSString *currentversion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];

    updateAvailable = [newversion compare:currentversion options:NSNumericSearch] == NSOrderedDescending;
}

Once you detect the update is available navigate the user to the download URL

itms-services://?action=download-manifest&url=<url-path-to-plist>

and it will install over the existing version leaving all data in-tact and even upgrade the CoreData database if you setup auto migration and make changes.

Rubstone answered 4/12, 2012 at 20:20 Comment(5)
@Joe.Thank you.I looked at the .plist file and at the very top i see plist version="1.0". Now, where do i write the code that you put here?Boarhound
You could generate it from the Organzier in Xcode, manually input it, or create a script that populates it for automated deployments.Rubstone
@Joe.I am new to iOS development.All I used in Organizer in Xcode is to generate new scheme and distribute button. I do the save for enterprise distribution,give application url(...1.0.ipa),name,image urls and get the .ipa and .plist files. So when i have a new update,change the Bundle version in Xcode's .plist file to suppose 2.0 and do this process again(click distributte button,save for enterprise..etc) and get the new .ipa and .plist and replace the old ..1.0.ipa ,..1.0.plist with ..2.0.ipa, ..2.0.plist files?What do you mean when you say "generate it from Organizer in Xcode".Boarhound
You set the bundle version number in Xcode under your targets settings in the Summary tab. When you archive your application in Organizer and save for distribution it will generate a plist file with the bundle version you set in Xcode. All you will need to do is replace that plist on the server and the code above will be able to detect the version change. The code above is synchronous and I run it in a separate thread on app launch. I recommend you do the same.Rubstone
Had some trouble on the version comparison. Turns out "CFBundleVersion" returns the build number (not version). To compare versions, I replaced it with "CFBundleShortVersionString".Tripody
M
6

Thanks to Joe for a fantastic response. Here is the extended version translated to swift. You can put it inside of the viewDidLoad of your main view controller

let plistUrl = "https://example.com/example.plist"
let installationUrl = "itms-services://?action=download-manifest&amp;url=https://example.com/example.plist"


override func viewDidLoad() {
    super.viewDidLoad()

    //Check for the updates        
    checkForUpdates()
}

func checkForUpdates() {
    let qualityOfServiceClass = QOS_CLASS_BACKGROUND
    let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
    dispatch_async(backgroundQueue, {
        let updateDictionary = NSDictionary(contentsOfURL: NSURL(string: self.plistUrl)!)!

        let items = updateDictionary["items"]
        let itemDict = items?.lastObject as! NSDictionary
        let metaData = itemDict["metadata"] as! NSDictionary
        let serverVersion = metaData["bundle-version"] as! String
        let localVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
        let updateAvailable = serverVersion.compare(localVersion, options: .NumericSearch) == .OrderedDescending;

        if updateAvailable {
            self.showUpdateDialog(serverVersion)
        }
    })
}

func showUpdateDialog(serverVersion: String) {
    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        let alertController = UIAlertController(title: "New version of Example available!", message:
            "Example \(serverVersion) has been released. Would you like to download it now?", preferredStyle: UIAlertControllerStyle.Alert)
        alertController.addAction(UIAlertAction(title: "Not now", style: .Cancel,handler: nil))
        alertController.addAction(UIAlertAction(title: "Update", style: .Default, handler: { (UIAlertAction) in
            UIApplication.sharedApplication().openURL(NSURL(string: self.installationUrl)!)
        }))

        self.presentViewController(alertController, animated: true, completion: nil)
    })
}
Medical answered 1/4, 2016 at 23:37 Comment(0)
A
1

Just distribute the update the same way you distribute the original. The user retains the data from the earlier version.

Amberambergris answered 4/12, 2012 at 20:17 Comment(0)
S
1

Updated answer of @Vlad in swift 4

 var plistUrl = "https://xxxxxxxxxxxxxxfgfgf/ex.plist"

var installationUrl = URL(string : "itms-services://?action=download-manifest&url=https://xxxxxxxxxxxxxxfgfgf/ex.plist")


   func checkForUpdates() {
       let qos = DispatchQoS(qosClass: .background, relativePriority: 0)
       let backgroundQueue = DispatchQueue.global(qos: qos.qosClass)
    backgroundQueue.async(execute: {
        let updateDictionary = NSDictionary(contentsOf: NSURL(string: self.plistUrl)! as URL)!

           let items = updateDictionary["items"]
        let itemDict = (items as AnyObject).lastObject as! NSDictionary
           let metaData = itemDict["metadata"] as! NSDictionary
           let serverVersion = metaData["bundle-version"] as! String

        print ("serverVersion=",serverVersion)
        let localVersion = Bundle.main.infoDictionary!["CFBundleVersion"] as! String
        print ("localVersion=",localVersion)

           let updateAvailable = serverVersion.compare(localVersion, options: .numeric) == .orderedDescending
        print("version is newer")

           if updateAvailable {
            self.showUpdateDialog(serverVersion: serverVersion)
           }
       })
   }

   func showUpdateDialog(serverVersion: String) {
       DispatchQueue.main.async { () -> Void in
           let alertController = UIAlertController(title: "New version of  App  available!", message:
            "MCD \(serverVersion) has been released. Would you like to download it now?", preferredStyle: UIAlertController.Style.alert)
        alertController.addAction(UIAlertAction(title: "Not now", style: .cancel,handler: nil))
        alertController.addAction(UIAlertAction(title: "Update", style: .default, handler: { (UIAlertAction) in
            UIApplication.shared.open(self.installationUrl!, options: [:], completionHandler: nil)
           }))

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

but this is only onetime need more modification for everytime

Silvestro answered 28/4, 2020 at 7:57 Comment(0)
F
0

For app updates, the existing app data persists if the bundle ID for the app stays the same.

Apple explains Enterprise App Deployment and app updates here: http://help.apple.com/iosdeployment-apps/mac/1.1/#app43ad802c

I'd also recommend including an update checker in-app.

To do that, iVersion is a ios library by Nick Lockwood (aka Charcoal Design) that will help you to do this. It's available here: https://github.com/nicklockwood/iVersion

Franchescafranchise answered 22/1, 2014 at 17:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.