使用 MonoTouch 制作自更新 iOS 应用程序有哪些选项?

发布于 2024-12-08 14:13:12 字数 2606 浏览 6 评论 0原文

我正在尝试制作一个 iPad/iPhone 应用程序(使用 MonoTouch),它首先检查当前版本与自定义 Web 服务报告的最新版本。如果应用程序已过时,则应从 Web 服务下载新版本的二进制文件并替换当前版本。

该应用程序可以临时分发或通过企业部署进行分发,因此它不受 Apple 的验证或 AppStore 的版本控制系统的约束。

我正在考虑制作两个应用程序,一个引导程序和真正的应用程序。在 Windows 下,引导程序将使用简单的文件操作来替换真实的应用程序,但在 iOS 下,我不太确定这是可能的,如果可能的话,我不知道如何做到这一点。

那么,问题来了:使用 MonoTouch for iOS 制作自动更新应用程序的“正确”方法是什么

谢谢。


更新

看来我已经可以正常工作了,至少在模拟器中是这样。

基本思想是在引导程序中实现最低限度的功能,例如 Main() 方法和 AppDelegate,然后使用反射从位于应用程序包外部的二进制文件加载导航控制器和其他所有内容,这将受到自更新操作。

下面是引导程序代码:

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

实际应用程序代码:

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

在模拟器中,它显示“Working!”标签,我只是希望也能在真实设备上运行。


更新2

上述方法仅适用于模拟器,在iOS设备上它会在Assembly.Load上崩溃。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

兰花执着 2024-12-15 14:13:12

您不能这样做 - 至少不能替换可执行二进制文件,因为包已签名(如果位于应用程序包之外,更新数据不会成为问题)。

但是您仍然可以这样做(正确的方法):

  • 检查更新(例如使用网络服务);并
  • 通过提供更新链接帮助用户更新(例如通知他们)。

这可以手动完成(即通过您自己的代码)或使用 TestFlight SDK(查找 应用内更新)。

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

嗫嚅 2024-12-15 14:13:12

Poupou的回答几乎涵盖了这一点。

不过,我想补充一点,您仍然可以远程配置应用程序功能。例如,应用程序可以检查服务器上的配置文件,然后根据该文件允许或拒绝对某些功能的访问。

这当然意味着计划发布的任何功能都必须已经包含在内。

它不会涵盖所有用例,但它允许您保留某个功能,直到每个用户都安装了最新的二进制文件,以便每个人都可以同时访问该功能。

另一种方法是将尽可能多的功能转移到脚本中,这些脚本可以随时交换或增强。不过,以这种方式开始还需要做更多的工作。

最后,您可以实现一种机制,检查新版本是否可用并停用大部分应用程序功能(可能在宽限期后),以强制用户升级到新版本。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文