原文: Auto updater for my side loaded UWP apps

As I described before, i have a few tasks to solve for my home automation project. One of the things I wanted to do is to be able to update my application on the different devices easily. I could publish my home automation app to the store, but it’s hard to provide a test environment for the store testers and it takes a while when the app gets certified before i can roll it out to all my devices. Of course I can sign up for an Intune account and use regular MDM to manage my apps, but 1st i need to have this Intune environment which I think is a bit over the top, and 2nd I would be depending on an internet connection. This is also a topic which comes up with some of my customers so I thought I could solve this differently.

Since the app is going to be side loaded I am allowed to use restricted capabilities. The store app uses these capabilities to be able to download and update apps from the store so what APIs are used by this app? It uses (among others) the PackageManager class. This API is protected by the restricted capability packageManagement.

So the first experiment I tried was to build an update button in a test app and I tried to update myself. I created a version 1.0.0.0 (Project, Store, Create App Package and set the version to 1.0.0.0, I also created a version 2.0.0.0) In my code I added the following line in the click event:

 
1
2
PackageManager packagemanager = new PackageManager();
await packagemanager.UpdatePackageAsync(new Uri(packageLocation), null, DeploymentOptions.ForceApplicationShutdown);

Where the packageLocation pointed to a file on my disk (but could also be a URL to a website). But updating yourself didn’t work. So the next idea I had was to write a little app which I could call with app2app communication and the only thing that little app would do was update the calling app. This works perfectly. So I created a new project called AppUpdate (Blank App). I added another project to the solution called AppUpdaterService (Windows Runtime Component).  I defined 2 parameters (I only use 1 currently) to be passed to this background service and that’s the package family name and the package location.

The entire code of this class looks like this:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.AppService;
using Windows.ApplicationModel.Background;
using Windows.Foundation.Collections;
using Windows.Management.Deployment;
 
namespace AppUpdaterService
{
    public sealed class BackGroundUpdaterTask : IBackgroundTask
    {
        BackgroundTaskDeferral serviceDeferral;
        AppServiceConnection connection;
 
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            //Take a service deferral so the service isn't terminated
            serviceDeferral = taskInstance.GetDeferral();
            taskInstance.Canceled += OnTaskCanceled;
 
            //initialize my stuff
 
            var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
            connection = details.AppServiceConnection;
 
            //Listen for incoming app service requests
            connection.RequestReceived += OnRequestReceived;
        }
 
        private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
        {
            if (serviceDeferral != null)
            {
                //Complete the service deferral
                serviceDeferral.Complete();
            }
        }
 
        async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
        {
            //Get a deferral so we can use an awaitable API to respond to the message
            var messageDeferral = args.GetDeferral();
 
            ValueSet message = args.Request.Message;
            ValueSet returnData = new ValueSet();
 
            try
            {
                string packageFamilyName = message["PackageFamilyName"] as string;
                string packageLocation = message["PackageLocation"] as string;
                PackageManager packagemanager = new PackageManager();
                await packagemanager.UpdatePackageAsync(new Uri(packageLocation), null, DeploymentOptions.ForceApplicationShutdown);
 
                //Don't need to send anything back since the app is killed during updating but you might want this if you ask to update another app instead
                //of yourself.
 
                //returnData.Add("Status", "OK");
                //await args.Request.SendResponseAsync(returnData);
            }
            finally
            {
                //Complete the message deferral so the platform knows we're done responding
                messageDeferral.Complete();
            }
        }
    }
}

Make sure you add the reference to this project to your AppUpdater project.

Inside my dashboard app I call the following code to update myself through the updater app:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
private AppServiceConnection updaterService;
private async void button_Click(object sender, RoutedEventArgs e)
{
    if (this.updaterService == null)
    {
        this.updaterService = new AppServiceConnection();
        this.updaterService.AppServiceName = "net.hoekstraonline.appupdater";
        this.updaterService.PackageFamilyName = "be122157-6d1a-47b8-a505-4d6b276b1973_f6s3q6fqr0004";
 
        var status = await this.updaterService.OpenAsync();
        if (status != AppServiceConnectionStatus.Success)
        {
            txtOutput.Text = "Failed to connect!";
            updaterService = null;
            return;
        }
    }
    try
    {
        //Uri updatePackage = new Uri("C:\\Users\\matth\\Documents\\Visual Studio 15\\Projects\\MyAppForUpdateTest\\MyAppForUpdateTest\\AppPackages\\MyAppForUpdateTest_2.0.0.0_Debug_Test\\MyAppForUpdateTest_2.0.0.0_x86_Debug.appxbundle");
        Uri updatePackage = new Uri("<a href="http://192.168.2.250/MyAppForUpdateTest_2.0.0.0_Debug_Test/MyAppForUpdateTest_2.0.0.0_arm_Debug.appxbundle&quot;);">http://192.168.2.250/MyAppForUpdateTest_2.0.0.0_Debug_Test/MyAppForUpdateTest_2.0.0.0_arm_Debug.appxbundle");</a>
        var message = new ValueSet();
        message.Add("PackageFamilyName", Windows.ApplicationModel.Package.Current.Id.FamilyName);
        message.Add("PackageLocation", updatePackage.ToString());
 
        AppServiceResponse response = await this.updaterService.SendMessageAsync(message);
 
        if (response.Status == AppServiceResponseStatus.Success)
        {
            txtOutput.Text = "Update started, time to say goodbye" + response.Message["Status"];
 
        }
    }
    catch (Exception ex)
    {
        txtOutput.Text = ex.Message;
    }
 
}

The cool thing that happens is my app is closed when the update starts and automatically restarted after the update. This works on both Desktop as Mobile. I still need to test this on my RPI3 and in combination with Assigned Access/Kiosk mode on mobile.

So what’s left? I need to implement something which checks for a new version regularly. I am still debating if I am going to use the updater app to get registrations from other apps and checks if there is an update and if it finds one starts updating the app, it is more generic this way. On the other hand, the app might know better when it should be updating or not and implement the logic itself and just uses the appupdater to do the update.

I was also thinking about using some kind of broadcast in the app to send an update command to the apps on all devices to be able to force an update after I published a newer version on my internal website.

How I need to check for a newer version could be as simple as providing a little text file on the webserver with the latest version number. If the app has a lower version it will update. Or perhaps I should test what happens if I call the update command and the version of the app on the server is the same. If the update is ignored i don’t need to write any specific code to handle this. It might not be the most optimal solution, although we only download the changes in packages.

Auto updater for my side loaded UWP apps的更多相关文章

  1. New Windows 10 SDK - Multi-instance UWP apps

    概述 前面一篇 About Windows 10 SDK Preview Build 17110 中,我们简单介绍了 Multi-instance UWP Apps,今天结合开发过程详细讲解一下. 在 ...

  2. 设置UWP程序自启动(Automate launching Windows 10 UWP apps)

    在开发UWP程序的过程中,有时候需要设置程序的自启.本人实现的步骤如下: 1.在VS中激活Protocol (Package.appxmanifest --> Declarations --&g ...

  3. DEPLOYING NATIVE UWP (UNIVERSAL WINDOWS PLATFORM) APPS FOR JAVA DEVELOPERS & PUBLISHING THEM TO THE MICROSOFT STORE

    原文: DEPLOYING NATIVE UWP (UNIVERSAL WINDOWS PLATFORM) APPS FOR JAVA DEVELOPERS & PUBLISHING THEM ...

  4. [UWP]XAML中的响应式布局技术

    响应式布局的概念是一个页面适配多个终端及不同分辨率.在针对特定屏幕宽度优化应用 UI 时,我们将此称为创建响应式设计.WPF设计之初响应式设计的概念并不流行,那时候大部分网页设计师都按着宽度960像素 ...

  5. 从淘宝 UWP 的新功能 -- 比较页面来谈谈 UWP 的窗口多开功能

    前言 之前在 剁手党也有春天 -- 淘宝 UWP ”比较“功能诞生记 这篇随笔中介绍了一下 UWP 淘宝的“比较”新功能呱呱坠地的过程.在鲜活的文字背后,其实都是程序员不眠不休的血泪史(有血有泪有史) ...

  6. 揭秘Windows10 UWP中的httpclient接口[2]

    阅读目录: 概述 如何选择 System.Net.Http Windows.Web.Http HTTP的常用功能 修改http头部 设置超时 使用身份验证凭据 使用客户端证书 cookie处理 概述 ...

  7. Windows10的革命之路-全新UWP开发平台

    众所周知,最近几年,微软一直在操作系统上进行统一化的尝试.第一次尝试的产品——Windows 8/8.1操作系统完全谈不上成功.请看下图: 我个人认为,这并不意味着操作系统统一化的策略是错误的,只能算 ...

  8. Viewbox在UWP开发中的应用

    Windows 8.1 与Windows Phone 8.1的UAP应用,终于在Windows 10上统一到了UWP之下.原来3个不同的project也变为一个.没有了2套xaml页面,我们需要用同一 ...

  9. 为 UWP 应用提供的 .NET 网络 API

    [编者按]本文作者是 Windows networking 团队项目经理 Sidharth Nabar.在微软 Build 2015 大会上,.NET Core 5 作为开发 UWP(Universa ...

随机推荐

  1. request.getSession().getServletContext().getRealPath()的一些坑

    今天是学校机房的服务器上对之前的一个网站升级时发现了一个bug,我自己的机器上用的tomcat8,机房上是tomcat7,结果一运行就开始报找不到文件,最后发现是文件分隔符的问题 原来在代码中涉及到路 ...

  2. Java反射xml数据类

    我们做自己的自动化测试.遇到使用xml存储数据,然而,这些数据可以被封装成一个类.将数据传递.通过下面的实际例子,展示给大家.请欣赏. 第一步:xml数据存储将被使用 第二步:读取xml文件的方法 第 ...

  3. C# WinForm开发系列 - Report

    http://www.cnblogs.com/peterzb/archive/2009/07/11/1521331.html

  4. 经典卷积神经网络的学习(三)—— Inception Net

    Google Inception Net 首次出现在 ILSVRC 2014 的比赛中(和 VGGNet 同年),就以较大优势拔得头筹.那届比赛中的 Inception Net 一般被称为 Incep ...

  5. 卷积神经网络(CNN)的细节问题(滤波器的大小选择)

    0. 滤波器的大小选择 大部分卷积神经网络都会采用逐层递增(1⇒ 3 ⇒ 5 ⇒ 7)的方式. 每经过一次池化层,卷积层过滤器的深度都会乘以 2: 1. 权值共享:减轻过拟合 & 降低计算量 ...

  6. Hibernate——(5)持久化对象和一级缓存机制

    一.对象的三种状态 1.暂时态:当对象刚创建,和Session没有发生任何关系时,当程序运行完就即刻消失,被称为暂时态. 2.持久态:当执行如下代码时,对象变为持久态 Emp e = new Emp( ...

  7. Method for performing cache coherency in a computer system

    In a computing system, cache coherency is performed by selecting one of a plurality of coherency pro ...

  8. Modbus 通信协议详解

    一.Modbus 协议简介     Modbus 协议是应用于电子控制器上的一种通用语言.通过此协议,控制器相互之间.控制器经由网络(例如以太网)和其它设备之间可以通信.它已经成为一通用工业标准.有了 ...

  9. Spring 的 ApplicationEvent and ApplicationListener

    什么是ApplicationContext? 它是Spring的核心,Context我们通常解释为上下文环境,可是理解成容器会更好些. ApplicationContext则是应用的容器. Sprin ...

  10. 各种工具的使用 tricks

    1. 搜狗搜索引擎 因为搜狗与腾讯的合作关系,搜狗搜索引擎提供了"微信"的搜索选项,可直接定位到相关文章,或者公众号. weixin.sougou.com 2. PyCharm P ...