×
Namespaces

Variants
Actions
(Difference between revisions)

How to create a Company Hub app for Windows Phone

From Nokia Developer Wiki
Jump to: navigation, search
GuruuMeditation (Talk | contribs)
(GuruuMeditation - Developing a Company Hub for Windows Phone)
GuruuMeditation (Talk | contribs)
(GuruuMeditation -)
Line 1: Line 1:
[[Category:Draft]][[Category:Windows Phone 8]]
+
[[Category:Draft]][[Category:Windows Phone 8]][[Category:XAML]]
 
{{Abstract|This article explains how to develop a Company Hub for Windows Phone.
 
{{Abstract|This article explains how to develop a Company Hub for Windows Phone.
 
It will not cover MDM (Mobile Devices Management) systems like Intune.
 
It will not cover MDM (Mobile Devices Management) systems like Intune.

Revision as of 21:46, 6 October 2013

This article explains how to develop a Company Hub for Windows Phone. It will not cover MDM (Mobile Devices Management) systems like Intune.


SignpostIcon XAML 40.png
WP Metro Icon WP8.png
SignpostIcon Code 52.png
Article Metadata
Code ExampleTested with
SDK: Windows Phone 8.0 SDK
Devices(s): Nokia Lumia 920
Compatibility
Platform(s):
Windows Phone 8
Platform Security
Signing Required: Symantec Certificate
Article
Created: User:Guruumeditation (06 Oct 2013)
Updated: User:Guruumeditation (06 Oct 2013)
Last edited: GuruuMeditation (06 Oct 2013)

Contents

Introduction

These are the steps covered in this Wiki :

  • Register as company
  • Get a Symantec Certificate
  • Develop company hub
  • Develop company apps
  • Sign hub and apps
  • Create app discovery service
  • Send the certificate and the company app to users

There is, at the end, the source code of a Company Hub sample :

HubExample.png

Register as company

When you create your developer account, you should create a company one, not an individual. Once the company verification is done, you’ll get a Symantec ID :

CompanyHub1.jpg

Get a Symantec Certificate

Once you have your Symantec ID, you have to buy a $299/year certificate here : https://products.websecurity.symantec.com/orders/enrollment/microsoftCert.do

Develop company hub

The company hub is just like a regular application. you can do anything you want. Of course, it would be quite useless if there isn’t a company app discovery page where you can see which company apps are available to download and a page where you can launch the already installed apps. A company news or user company profile page wouldn’t hurt either.

There are 5 methods specially there for company hub :


I’ll give a simple example (sources given at the end) of a company hub with a 2 tabs panorama. One tab show already installed app. You can launch them with a tap. The other tab is a list of available company apps. Tap to install.

This is the PacketInfo class I use. It gives all the information I need about available apps (ID, name, description, URL, icon,…) and has also some ViewModel-like properties (I want to make the things simple) :

    [Serializable]
[DataContract]
public class PackageInfo
{
[DataMember]
public Guid ID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public string Thumbnail { get; set; }
[DataMember]
public string XAPPath { get; set; }
[DataMember]
public object Icon { get; set; }
// To simplify the app, let's make this class a kind of VM with those properties :
[DataMember]
public bool Downloading { get; set; }
[DataMember]
public uint Progress { get; set; }
[DataMember]
public string ProgressString { get; set; }
[DataMember]
public object Package { get; set; }
}

This is the part where I load the two lists : the available app list and the already installed app list :

 // Clear the ObservableCollections
InstalledPackages.Clear();
AvailablePackages.Clear();[/br]
// Get all packages from web service
var allpackages = await GetPackageListAsync();
// get all package installed with same PublisherID as the Company hub
var installed = InstallationManager.FindPackagesForCurrentPublisher().ToList();
// Company Hub ProductID. Use to remove it from the installed list we just got
var hubid = "{27ed8894-9f3b-4bef-89c6-75e25bb6520a}";
 
foreach (var app in installed.Where(d => !d.Id.ProductId.Equals(hubid,StringComparison.OrdinalIgnoreCase)))
{
// get thumbnail token, and copy the file in local folder
var thumbtoken = app.GetThumbnailToken();
var name = SharedStorageAccessManager.GetSharedFileName(thumbtoken);
 
await SharedStorageAccessManager.CopySharedFileAsync(ApplicationData.Current.LocalFolder
, name,NameCollisionOption.ReplaceExisting, thumbtoken);
var file = await ApplicationData.Current.LocalFolder.GetFileAsync(name);
 
var stream = await file.OpenStreamForReadAsync();
 
var bitmap = new BitmapImage();
bitmap.SetSource(stream);
// create a package info and add it to the collection
var packageinfo = new PackageInfo { ID = new Guid(app.Id.ProductId),
Name = app.Id.Name, Icon = bitmap, Package = app };
 
InstalledPackages.Add(packageinfo);
}
 
foreach (var package in allpackages)
{
// if available package is already installed, do nothing
if (installed.Any(d => d.Id.ProductId.Equals(string.Format("{{{0}}}", package.ID.ToString()),
StringComparison.OrdinalIgnoreCase)))
continue;
// otherwise add it the the vailable collection
AvailablePackages.Add(package);
}

I get the available app list from my webservice. I get the installed app list with the FindPackagessForCurrentPublisher method.

For each app installed, I get the thumbnail (icon) and copy it locally. I create a PackageInfo with all the info needed and add it to a list. As the company hub itself will be listed, it is better to remove it from the list

For each packages available, I check if it is already installed ('by comparing product IDs). If not I add. So there will only be in that list the apps that are not installed yet

This is what my available package list look like in XAML :

 <phone:LongListSelector Margin="0,-38,-22,2"
ItemsSource="{Binding AvailablePackages}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid Margin="0,-6,0,12"
d:DataContext="{d:DesignInstance entrepriseService:PackageInfo}"
toolkit:TiltEffect.IsTiltEnabled="True"
Tap="Package_OnTap">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image Source="{Binding Thumbnail}"
Width="80"
Height="80"
Grid.RowSpan="2"
Margin="10"
VerticalAlignment="Top" />
<TextBlock Text="{Binding Name}"
Grid.Column="1"
TextWrapping="Wrap"
Style="{StaticResource PhoneTextExtraLargeStyle}"
FontSize="{StaticResource PhoneFontSizeExtraLarge}" />
<TextBlock Grid.Row="1"
Grid.Column="1"
Text="{Binding Description}"
Visibility="{Binding Downloading,Converter={StaticResource BoolToInvertedVisibilityConverter}}"
Foreground="DarkGray"
TextWrapping="Wrap"
Margin="15,0,0,0" />
<StackPanel Orientation="Vertical"
Grid.Column="1"
Grid.Row="1"
x:Name="IntallStackPanel">
<ProgressBar IsIndeterminate="False"
x:Name="IntallProgressBar"
Value="{Binding Progress}"
Visibility="{Binding Downloading,Converter={StaticResource BoolToVisibilityConverter}}" />
<TextBlock Text="{Binding ProgressString}" />
</StackPanel>
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>

Just a simple LongListSelector. When you tap on an item, the app is installed :

        // Install app
private void Package_OnTap(object sender, GestureEventArgs e)
{
// Get package info
var package = (sender as Grid).DataContext as PackageInfo;
 
try
{
package.Downloading = true;
// install app package
var result = InstallationManager.AddPackageAsync(package.Name, new Uri(package.XAPPath, UriKind.Absolute));
 
result.Progress += (info, progressInfo) => Dispatcher.BeginInvoke(() =>
{
package.Progress = progressInfo;
package.ProgressString = string.Format("Installing ({0}%)...", progressInfo);
});
 
result.Completed = (info, status) => Dispatcher.BeginInvoke(async () =>
{
MessageBox.Show(info.ErrorCode == null
? string.Format("{0} installed", package.Name)
: string.Format("Error installing : {0}", info.ErrorCode.Message));
package.Downloading = false;
await LoadingPackagesListAsync();
});
 
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
 
}

I use InstallationManager.AddPackageAsync to add the package. It returns a IAsyncOperationWithProgress<PackageInstallResult, UInt32>, so I can follow the progress thanks to the Progress event. I use the Completed delegate to warn user it is installed or if there was an error.

Note.pngNote: The Progress event will be called 4 times only. At 5% (Phone asking confirmation ot the user), 10% (User accepted), 55% (Download done) and 100% (Installation done)

Warning.pngWarning: There is something subtle with Completed : it is a delegate, not an event ! Use = and not +=. If you have weird exception when you’re on that line, it is probably you made the mistake

To launch an app is straightforward:

// Lauch app
private void LaunchApp_OnTap(object sender, GestureEventArgs e)
{
var packageInfo = (sender as Grid).DataContext as PackageInfo;
 
var package = packageInfo.Package as Package;
 
package.Launch("");
}

Develop company apps

Nothing special to say. It is just like regular app.

Sign hub and apps

Before you deploy everything, you need to sign the app.

To do so, you have to install the certificate you got from Symantec and export it as PFX (example here : http://msdn.microsoft.com/en-us/library/gg432987.aspx). Then you can generate the AET (Application Enrollment Token) that you will have to send to the users. They have to install it on their phone in order to use your apps. There is an AET generator with the Phone SDK. To launch :

%ProgramFiles(x86)%\Microsoft SDKs\Windows Phone\v8.0\Tools\AETGenerator\AETGenerator.exe PFXFile Password

It will generate 3 files. It is the AET.aetx that you send to users. The AET.aet is for MDM systems. The other is raw AET in XML. More info here : http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj735576(v=vs.105).aspx)

Now to sign your apps, there are several ways as explained here : http://msdn.microsoft.com/en-us/library/windowsphone/develop/dn168929(v=vs.105).aspx

The easiest is to use the BuildMDILXap.ps1 that is in the %ProgramFiles(x86)%\Microsoft SDKs\Windows Phone\v8.0\Tools\MDILXAPCompile as it does all the steps for you.

I added it in post build that way :

CompanyHub2.jpg

Here is it, for one of the example company app :

del "$(TargetDir)\AriesApp_new.xap"
powershell.exe -ExecutionPolicy ByPass -File "%ProgramFiles(x86)%\Microsoft SDKs\Windows Phone\v8.0\Tools\
MDILXAPCompile\BuildMDILXap.ps1" -xapfilename "$(TargetDir)\AriesApp.xap"
–pfxfilename "$(SolutionDir)\Keys\mycert.pfx" -password mypassword
copy /y "$(TargetDir)\AriesApp_new.xap" "$(SolutionDir)\WcfService1\XAP\AriesApp.xap"

I delete the older version of the signed xap, I execute the script (my keys are stored in a Keys directory) and finally I copy the xap on my service website, where it can be downloaded by the users.

Tip.pngTip: Don’t forget to set your publisher ID in the manifest of the apps. The publisher ID can be generated that way : take your Symantec ID (Example : 541255) . Convert it to hex (0x84247) and create a GUID out of it : 00084247-0000-0000-000000000000)

Create app discovery service

It is not necessarily a service. It can be XML file,etc…

I made a very simple one, it just read, deserialize an XML file and send it :

 public class EntrepriseService : IEntrepriseService
{
public List<PackageInfo> GetEntreprisePackages()
{
// just read the XML file, deserialize it and then send
var appPath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
 
PackageInfo[] packages;
 
using (var sr = new StreamReader(appPath + "/Packages.xml"))
{
var dcs = new XmlSerializer(typeof(PackageInfo[]), new[] { typeof(PackageInfo) });
packages = dcs.Deserialize(sr.BaseStream) as PackageInfo[];
}
 
return packages.ToList();
}
}

The XML is like this :

<?xml version="1.0" encoding="utf-8" ?>
<ArrayOfPackageInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PackageInfo>
<ID>{16823216-c5b1-4613-a50c-9fb9bbddc571}</ID>
<Name>Aries</Name>
<Description>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In aliquam convallis elit, ac aliquam neque vulputate eget. Sed consequat non nibh quis pharetra. </Description>
<Thumbnail>http://192.168.0.110:19475/Thumb/Astro-Aries.png</Thumbnail>
<XAPPath>http://192.168.0.110:19475/XAP/AriesApp.XAP</XAPPath>
</PackageInfo>
<PackageInfo>
<ID>{52957e14-91ef-485d-9fb4-e69086facb6e}</ID>
<Name>Taurus</Name>
<Description>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In aliquam convallis elit, ac aliquam neque vulputate eget. Sed consequat non nibh quis pharetra. </Description>
<Thumbnail>http://192.168.0.110:19475/Thumb/Astro-Taurus.png</Thumbnail>
<XAPPath>http://192.168.0.110:19475/XAP/TaurusApp.XAP</XAPPath>
</PackageInfo>
</ArrayOfPackageInfo>

Send the certificate and the company app to users

Send the keys and the app to the user by email. Or have them download it from a website. Anyway, do it securely.

To install the AET, just double click on it.

Conclusion

Well, side loading company app is way easier than with Windows 8. In the sense you don’t need extra license, or specific version of Windows (Entreprise),... It is a complain I heard a lot from companies who are interested in Windows side loading. I hope for Windows 9, the system will get inspired by the WP team one.

HubExample.png

File:MyCompanyHub.zip

128 page views in the last 30 days.