原文: 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. nuklear(A single-header ANSI C gui library,界面还不错)

    Nuklear This is a minimal state immediate mode graphical user interface toolkit written in ANSI C an ...

  2. OpenGL学习一

    作者:朱金灿 来源:http://blog.csdn.net/clever101 回家计划学习OpenGL开发.没有开发机子,用的是别人的笔记本,不想装庞大的VS,于是选择小巧一点的codeblock ...

  3. Wpf的布局舍入属性(可以解决软件字体模糊的问题)

    原文:Wpf的布局舍入属性(可以解决软件字体模糊的问题) 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/HK_JY/article/details/ ...

  4. ORACLE中死锁

    ORACLE中死锁的知识点总结   死锁的概念 什么是死锁呢? 其实我们生活中也有很多类似死锁的例子. 我先举一个生活中的例子:过年回家,父亲买了一把水弹枪,儿子和侄子争抢着要先玩,谁也不让谁,拆开包 ...

  5. 详细阐述Web开发中的图片上传问题

    Web开发中,图片上传是一种极其常见的功能.但是呢,每次做上传,都花费了不少时间. 一个"小功能"花费我这么多时间,真心不愉快. So,要得认真分析下原因. 1.在最初学习Java ...

  6. 链表与哈希表基本概念及Java常用集合

    -链表- 是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的.链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成.每个结点包括两个 ...

  7. 【64.52%】【codeforces 697D】Puzzles

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  8. Opencv目标跟踪—CamShift算法

    CamShift算法全称是"Continuously Adaptive Mean-Shift"(连续的自适应MeanShift算法),是对MeanShift算法的改进算法,可以在跟 ...

  9. less - 循环 loop

    .avatar-loop(@n, @i:1, @level) when (@i <= @n) { &:nth-child(@{level}) .item.item-@{i} { .ava ...

  10. android模拟器上不了网的解决办法

    Android模拟器默认的地址是10.0.2.3,默认的DNS也是10.0.2.3,对于在家里上网学习Android的人来讲,一般电脑的IP都是192.168.1.100之类的,不在同一个网段.所以就 ...