Question

I am trying to make an iPad/iPhone application (with MonoTouch) which starts by checking the current version versus the latest version reported by a custom web service. If the application is out of date it should download the binaries of the new version from the web service and replace the current one.

The application would be distributed either ad-hoc or via enterprise deployment, so it's not subject to Apple's validation or to AppStore's versioning system.

I was thinking of making two applications, a bootstrapper and the real application. Under Windows, the bootstrapper would use simple file operations to replace the real application but under iOS I'm not so sure this is possible and, if possible, I don't know how to do it.

So, here's the question: which is the "right" way to make a self-updating application with MonoTouch for iOS?

Thanks.


UPDATE

Seems like I've got this working, at least in simulator.

The basic idea is to implement a bare minimum in the bootstrapper, like the Main() method, and the AppDelegate, then use reflection to load the Navigation controller and everything else from a binary file located outside the application bundle, which would be subject to self-update operations.

Here's the bootstrapper code:

Main.cs

namespace Bootstrapper
{
    public class Application
    {
        static void Main (string[] args)
        {
            UIApplication.Main (args,null,"AppDelegate");
        }
    }
}

AppDelegate.cs

namespace Bootstrapper
{
    [Register("AppDelegate")]
    public class AppDelegate : UIApplicationDelegate
    {
        // Connect window and navigationController stuff
        // ...

        public override bool FinishedLaunching (UIApplication app, NSDictionary options)
        {
            Assembly asm = Assembly.LoadFile(@"/Users/sorincom/Projects/SelfUpdate/TheApp/bin/Debug/TheApp.dll");

            navigationController = (UINavigationController)Activator.CreateInstance(asm.GetType("TheApp.NavigationController"));

            window.AddSubview (navigationController.View);
            window.MakeKeyAndVisible ();

            return true;
        }
    }
}

Real application code:

NavigationController.cs

namespace TheApp
{
    [Register("NavigationController")]
    public class NavigationController : UINavigationController
    {
        // Connect view stuff
        // ...

        // Constructors
        // ...

        void Initialize ()
        {   
            this.PushViewController(new HomeController(), true);
        }
    }
}

HomeController.cs

namespace TheApp
{
    [Register("HomeController")]
    public class HomeController : UIViewController
    {
        // Connect view stuff
        // ...

        // Constructors
        // ...

        void Initialize ()
        {   
            View = new UIView();

            var label = new UILabel();
            label.Frame = new System.Drawing.RectangleF(50f, 50f, 200f, 200f);
            label.Text = "Working!";
            View.AddSubview(label);
        }
    }
}

In the simulator it displays the "Working!" label, i just hope to function on the real device as well.


UPDATE 2

The above approach works only in simulator, on iOS device it crashes on Assembly.Load.

Was it helpful?

Solution

You can't do this - at least not replace the executable binaries since the package is signed (updating data would not be an issue, if located outside the application bundle).

However you can still do (a right way):

  • checks for updates (e.g. using a web service); and
  • help users to update (e.g. notify them) by providing links to updates.

This can be done manually (i.e. by your own code) or by using the TestFlight SDK (look for In-App Updates).

OTHER TIPS

Poupou's answer pretty much covers it.

I'd like to add however that you still might be able to configure the apps functionality remotely. For example the app could check for a configuration file on your server and then allow or deny access to some features, according to that file.

That means of course that any functionality intended for a scheduled release must be already included.

It won't cover all use cases, but it would allow you to, for example, hold a certain feature back until every user has installed the latest binary, so that everyone is granted access to that feature at the same time.

Another approach would be to shift as much functionality as possible into scripts, which could be exchanged or enhanced at any time. Much more work would be required for getting started this way, though.

Finally, you could implement a mechanism which checks if a new version is available and deactivates most of the apps functionality (after a grace period, maybe), to force users to upgrade to the new version.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top