DevOps for IoT ( Part 2) – Installing an app from within an app
In this blogpost I’m going into details for a specific part of the End-To-End implementation – how to install apps from within an app. In a previous post I described the allover scenario to set up a full CI/CD chain for an IoT application running on Windows 10 IoT Core, orchestrated by Visual Studio Team Services. If you are already familiar with UWP apps you might wonder how installation of a new application is realized on Windows IoT Core. (If you are not working with Windows 10 IoT Core as your IoT platform you may have to come up with a similar solution for your device/platform. )
On Windows 10 devices in general capabilities of Universal Windows Apps are limited per default for security reasons. Part of the unavailable functionality is installation of software directly from a downloaded file, this means it is not possible to simply download an app and then trigger the installation of that downloaded app from within a running application without user interaction. To recap: This is exactly what we want in our IoT Scenario. I want to update the application without any user interaction based on a downloaded file.
However Windows 10 IoT Core gives you (the developer) control over the device and you can access additional capabilities if you explicitly allow them for your application. So what I basically have to do is two things.
- I have to add additional capabilities within the app manifest
- In this specific case I have have to add a special registry key on all devices to allow installation of apps from within an app
While #1 is not a problem at all and clearly just a developer task #2 might make you frown because you could think it is something that has to be done manually. If we stick with the refrigerator sample this would mean I have to add registry keys in millions of refrigerators. First it’s important to know that this has to be done only once per devices. Second of course this isn’t something you would do manually instead you could e.g. put this into a custom Windows 10 IoT Image you might be providing for your device anyway.
It’s important to note that besides the application which will be the IoT application you are really working on (e.g. the refrigerator control) I’m using a second application which handles installation and updates of the refrigerator control. While the Refrigerator App is really “just” a normal app, the second Installer App” has extended capabilities. This app is also required to communicate with IoT Hub.
Modifing the *.appxmanifest
To add the additional capabilities add the following namespaces in your app manifest of your Installer app.
xmlns:iot=" https://schemas.microsoft.com/appx/manifest/iot/windows10" xmlns:rescap= https://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities
and add iot and rescap to the list of ignorable namespaces. You have to do this in XML there’s no UI for that. Use the context menu to switch between code view and design view.
After adding the namespaces add the following capabilities in the capabilities section of your manifest:
<iot:Capability Name="systemManagement" />
<rescap:Capability Name="packageQuery" />
Modifing the device registry
Now you have to modify the registry on your IoT Device. You need the installation folder of your application. Therefore you can either simply deploy your app to the device and remote into the system (e.g. via Powershell) to find out the path or you guess it based on the default values.
You add the key by running a command like this on Powershell remoted into your device :
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\EmbeddedMode\ProcessLauncher" /v AllowedExecutableFilesList /t REG_MULTI_SZ /d "c:\windows\system32\applyupdate.exe\0c:\windows\system32\deployappx.exe\0c:\installer\appinstall.cmd\0c:\Data\Users\DefaultAccount\AppData\Local\Packages\PACKAGEFAMILYNAME\LocalState\installer\AppInstall\appinstall.cmd\0"
This key contains executables which are allowed to run. You have to add the correct path to your executable which executes the installation. In my case I’m downloading the appinstall.cmd and the app from FTP into the LocalState folder of my installer app. Therefore I have to adjust the path using the Package Family Name of the installer App (as found in appxmanifest, see below) and had to adjust the path to the *.cmd depending on the directory structure I’m using in my downloaded files.
When you have completed this you made sure your installer app is now able and allowed to install apps on your target device.
Installing an app from within an app
To trigger the installation what you do is just call the process launcher and pass in the path to your executable which installs the app. In my case as stated above, this is the appinstall.cmd file.
// var cmd = something like …\LocalState\installer\AppInstall\appinstall.cmd” depending on your structure
var result = await ProcessLauncher.RunToCompletionAsync(cmd, args);
You may wonder where I got that appinstall.cmd file from. This is something that my private build agent creates which has the Windows 10 ADK installed.
This post showed you how to set up an installer app which can install and update another app. This is one of the key “tricks” to get the scenario working if you’re using Windows 10 IoT Core. If you’re not using Windows 10 IoT Core you might have to deal with challenges differently to get an app installed without user interaction. I will point out other interesting aspects of the full DevOps scenario in a subsequent post.