1. Preparing Apps for Distribution
If you simply take a .xap file (whether
downloaded via Internet Explorer or attached to an email), the phone
won’t install the app without the .xap being in a special form that
involves two separate steps: precompiling for the phone and signing the
code. The most straightforward way to accomplish this is with an
included Powershell Script.
You will need to run PowerShell as an
administrator and navigate to a subdirectory of the Program Files (x86)
directory called Microsoft SDKs\Windows
Phone\v8.0\Tools\MDILXAPCompile. Although the script exists in that
directory, you can’t run it by default because PowerShell scripts are
disabled by default. To enable them, you need to run the following
command:
set-executionpolicy RemoteSigned
Calling this command will ask you whether you
want to allow remotely signed scripts (like the one shipped with the
SDK) to be able to be executed. You simply need to press Enter to allow
it. After scripts are allowed, you can then call the script that will
precompile and sign your application.
To call the script, you must supply three parameters:
• -xapfilename: The path to the xap (this must be a full path, not just the filename, even if you’re in the same directory)
• -pfxfilename: The path to the .pfx file that you created your AET from earlier
• -password: The password to access the .pfx file
For example, to precompile and sign a xap file, do the following:
./BuildMDILXap.ps1 -xapfilename c:\yourproject\your.xap -pfxfilename
D:\wmcerts\yourcert.pfx -password yourpwd
When the command
completes, you will have a new .xap file in the same directory with the
name of the xap appended with “_new” (that is, “your_new.xap”). This is
the .xap that you need to deploy to the phones. You can send them to
the phones via an email message or URL like the .aetx file. If you give
the phone access to a precompiled/signed xap, your users will be
prompted as to whether they want to install the app, as shown in Figure 1.
FIGURE 1 Confirming a company app’s installation
Although you can deploy your
applications in this way, a better way is by using a Company Hub, as
you’ll see in the next section.
2. Building a Company Hub
What is a Company Hub? This is an
application you write (and precompile/sign) that works as the starting
point for your company. This is typically a place where you can enable
users to install any enterprise applications you
are creating, as well as get other information from the company (for
example, news, alerts, and so on). The Company Hub is usually deployed
via email or URL as shown in the earlier section, but this should be
required only for this first application. The Company Hub should be the
application responsible for installing the rest of the applications for
users. The Company Hub ends up just becoming a bootstrap application
installed to enable installation (and uninstallation) of your company’s
apps on the phones.
When you create your own Company Hub, it’s
important that you know that this application will be responsible for
installing and updating your own enterprise applications. This
typically means you will need to be able to let the Company Hub request
the list of applications (and versions) from a central location (for
example, a web service). After you have a list of the applications, you
can show the application list and enable your users to install an
application directly from your Hub. This is accomplished by using the InstallationManager
class’s AddPackageAsync
method. This method takes the name of the app and an URI to the prepared .xap file, usually on your server. For example:
InstallationManager.AddPackageAsync("Your App",
new Uri(installationUrl));
When you call this method, it prompts the user
with an approval to install the app (refer to Figure 1).
But other than the approval, there is no UI for telling the user the
app is being installed. Instead, you should handle the return value
from the AddPackageAsync
method. This method returns an IAsyncOperatoinWithProgress<PackageInstallResult, uint>
object. This interface is used to enable you to handle both completion
and progress callbacks from the asynchronous operations. For example:
IAsyncOperationWithProgress<PackageInstallResult, uint> result;
result = InstallationManager.AddPackageAsync("YourApp",
new Uri(installationUrl));
// Use the result to handle progress and completion
result.Completed = (info, status) =>
{
if (status == AsyncStatus.Completed)
{
// ...
}
else if (status == AsyncStatus.Error)
{
// ...
}
};
result.Progress = (info, progress) =>
{
// ...
};
The return value of the AddPackageAsync
method can be used to handle the Completed
and Progress
delegates. In the case of the Completed
delegate, you can test whether the installation succeeded or failed. The Progress
can be used to show the user the ongoing status of the installation. In
both of these cases, these delegates aren’t guaranteed to be called on
the UI thread, so you should protect any data change that could affect
the user interface with the Dispatcher. For example, showing the
progress percentage by changing a view model should be protected by
wrapping it in a call to the Dispatcher, like so:
result.Progress = (info, progress) =>
{
Dispatcher.BeginInvoke(() =>
{
app.Status = string.Format("Installing: {0}% done",
progress);
});
};
Before you install an application, though, you might be interested in whether it is already installed. The same InstallationManager
class comes to the rescue. You can use the InstallationManager’s FindPackagesForCurrentPublisher
method to get all the apps that are installed for your company (you’re considered a “publisher”):
var packages = InstallationManager.FindPackagesForCurrentPublisher();
This method returns an enumerable list of Package
objects. The Package
class contains information about each installed application. Information about the installed app (or Package
) is contained in the Id
property of the Package
class. This property contains a structure called PackageId
. The PackageId
class contains information such as the Name
, Version
, and ProductId
. With these three pieces of information, you can make decisions about whether a particular application is installed. The ProductId
is the identifier (for example, Guid) that is contained in the WMAppManifest.xml
file of each Windows Phone applications. You should use this to
uniquely identify each application your enterprise produces. This way,
when you compare the list of applications that your company makes
available, you can simply use a LINQ query to find out whether the app
is installed, like so:
var packages = InstallationManager.FindPackagesForCurrentPublisher();
foreach (var app in yourApps)
{
// Determine if installed
var package = packages.FirstOrDefault(p =>
p.Id.ProductId == app.ProductId);
if (package != null)
{
app.IsInstalled = true;
}
}
You can see in this example that you can search through the packages returned by the InstallationManager
to match up the ProductId
’s to see whether it is already installed. The Package
object itself can be used to launch the application directly from your Company Hub. This is accomplished using the Package.Launch
method:
var package = packages.FirstOrDefault(p =>
p.Id.ProductId == app.ProductId);
if (package != null)
{
// Launch without initialization parameters
package.Launch("");
}
The Launch
method enables you to specify start-p parameters (usually the starting
page of an app). Calling it with an empty string launches it as if the
user tapped the icon on the phone itself.
Lastly, you can use the PackageId
’s Version
property to determine whether the latest version is installed. To
update an enterprise application, you simply install a newer version of
the .xap file using the same InstallationManager.AddPackageAsync
method:
var packages = InstallationManager.FindPackagesForCurrentPublisher();
var package = packages.FirstOrDefault(p => p.Id.ProductId == app.
ProductId);
if (package != null)
{
if (app.Version != package.Id.Version.ToString())
{
InstallationManager.AddPackageAsync("YourApp",
new Uri(installationUrl));
}
}
By calling AddPackageAsync
with a
new version of the app, the system will update the currently installed
app (although the user will still get a confirmation dialog box).
By using the built-in support for
iterating, installation, and upgrading your enterprise applications
from your own servers, you can create a Company Hub that will manage
all the applications you need on the phone for your own users.