Auto updater for my side loaded UWP apps
原文: 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");">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的更多相关文章
- New Windows 10 SDK - Multi-instance UWP apps
概述 前面一篇 About Windows 10 SDK Preview Build 17110 中,我们简单介绍了 Multi-instance UWP Apps,今天结合开发过程详细讲解一下. 在 ...
- 设置UWP程序自启动(Automate launching Windows 10 UWP apps)
在开发UWP程序的过程中,有时候需要设置程序的自启.本人实现的步骤如下: 1.在VS中激活Protocol (Package.appxmanifest --> Declarations --&g ...
- 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 ...
- [UWP]XAML中的响应式布局技术
响应式布局的概念是一个页面适配多个终端及不同分辨率.在针对特定屏幕宽度优化应用 UI 时,我们将此称为创建响应式设计.WPF设计之初响应式设计的概念并不流行,那时候大部分网页设计师都按着宽度960像素 ...
- 从淘宝 UWP 的新功能 -- 比较页面来谈谈 UWP 的窗口多开功能
前言 之前在 剁手党也有春天 -- 淘宝 UWP ”比较“功能诞生记 这篇随笔中介绍了一下 UWP 淘宝的“比较”新功能呱呱坠地的过程.在鲜活的文字背后,其实都是程序员不眠不休的血泪史(有血有泪有史) ...
- 揭秘Windows10 UWP中的httpclient接口[2]
阅读目录: 概述 如何选择 System.Net.Http Windows.Web.Http HTTP的常用功能 修改http头部 设置超时 使用身份验证凭据 使用客户端证书 cookie处理 概述 ...
- Windows10的革命之路-全新UWP开发平台
众所周知,最近几年,微软一直在操作系统上进行统一化的尝试.第一次尝试的产品——Windows 8/8.1操作系统完全谈不上成功.请看下图: 我个人认为,这并不意味着操作系统统一化的策略是错误的,只能算 ...
- Viewbox在UWP开发中的应用
Windows 8.1 与Windows Phone 8.1的UAP应用,终于在Windows 10上统一到了UWP之下.原来3个不同的project也变为一个.没有了2套xaml页面,我们需要用同一 ...
- 为 UWP 应用提供的 .NET 网络 API
[编者按]本文作者是 Windows networking 团队项目经理 Sidharth Nabar.在微软 Build 2015 大会上,.NET Core 5 作为开发 UWP(Universa ...
随机推荐
- iOS开发- Xcode插件- 规范凝视生成器VVDocumenter 自己的见解
xcode升级 VVDocumenter 插件失效怎么办?? 首先给个完整的安装參考:http://www.th7.cn/Program/IOS/201405/212030.shtml 參考这个能 ...
- 检索 04 --Stack栈 Queue队列 Hashtable哈希表
//Stack 先进后出 没有索引 Stack st = new Stack(); st.Push(12); st.Push(11); st.Push(22); st.Push(34); st.Pus ...
- CentOS7 下的mysql安装与配置
之前虽然也安装过多次mysql,但每次都会遇到各种小问题,这次记录下来,以备后查. 首先是下载与安装 # wget http://dev.mysql.com/get/mysql-community-r ...
- htmlunit 模拟登录 数字验证码
使用htmlunit的好处有两点,相比httpclient,htmlunit是对浏览器的模拟,比如你定位一个按钮,就可以执行click()方法,此外不需要象在httpclient中一样编写复杂的代码, ...
- 一个简易版的Function.prototype.bind实现
重新看<JavaScript设计模式与开发实践>一书,第32页发现个简易版的Function.prototype.bind实现,非常容易理解,记录在这了. Function.prototy ...
- PHP中的加密方式有如下几种
1. MD5加密 string md5 ( string $str [, bool $raw_output = false ] ) 参数 str -- 原始字符串. raw_output -- ...
- 熟知MySQL存储过程
存储过程(Stored Procedure)是一组为了完毕特定功能的SQL语句集,经编译后存储在数据库中.用户通过指定存储过程的名字并给定參数(假设该存储过程带有參数)来调用运行它. MySQL 存储 ...
- 微信公众平台自定义菜单接口API指南
微信公众平台开发模式自定义菜单接口API指南 简介 开发者获取使用凭证(如何获取凭证)后,可以使用该凭证对公众账号的自定义菜单进行创建.查询和删除等操作. 自定义菜单接口可实现以下类型按钮: clic ...
- Chrome浏览器离线安装 Postman 5.X 报错
下载和安装请参考 博友文章http://www.cnblogs.com/wangfeng520/p/5892125.html 尝试安装此扩展程序时出现以下警告: Ignored insecure CS ...
- Linux性能测试 strace命令
1 功能说明 strace 命令是一种强大的工具 , 能够显示任何由用户空间程式发出的系统调用 . strace 显示这些调用的参数并返回符号形式的值 . strace 从内核接收信息 , ...