本文章是由機器翻譯。

Windows Phone

建立 Windows Phone 8 公司中樞應用程式

Tony Champion

下載代碼示例

之前的 Windows Phone 8 發佈,公司有只有幾個選項用於將企業應用程式部署到雇員的設備。他們可能釋放到 Windows Phone 存儲的應用程式,需要使用者身份驗證,允許的應用程式,同時確保他們的用法要成功部署。當然,app 將會可用存儲區中並可供公眾下載。另一種方法是利用行動裝置管理 (MDM) 解決方案來直接管理的設備。Microsoft 現在提供了兩個 MDMs:Windows Intune 和系統中心 2012年組態管理員。雖然 MDMs 仍有許多大型企業的首選的方法,但他們不可能與公司的部署目標對齊。

Windows Phone 8 帶來一種新的非託管部署企業應用程式的選項,允許設備安裝的應用程式直接從電子郵件附件或從 URL 下載 app。這種部署企業應用程式的直接方法打開企業應用程式開發和部署到更多的公司。

此非託管方法的缺點是,安裝和 app 管理的使用者不是一共直觀。當談到行動裝置時,使用者期望,以便能夠安裝的應用程式,按下按鈕。無需手動安裝應用程式,從電子郵件或 Web 網站違背正常的應用程式和經驗,可以在使用者和 IT 人員的培訓問題導致的不確定性。幸運的是,有一個解決方案 — — 公司集線器 app。

Windows Phone 8 包括一些增補到 SDK 支援這個新的概念。公司樞紐 app 給企業介紹和交付給使用者進行安裝的應用程式的機制。它使使用者熟悉的經驗,發現和安裝公司的應用程式。

公司中心應用程式的要求

您可以向您的員工發佈公司集線器 app 之前,有幾個需要採取行政步驟。第一步是關於 Windows Phone 開發中心公司帳戶註冊。註冊過程是類似的常規發展帳戶,但經過一些額外的帳戶驗證的公司帳戶。

創建帳戶後,您必須購買企業移動代碼簽章憑證從賽門鐵克公司。證書採購流程需要有效的賽門鐵克 ID 從 Dev 中心,所以這才能完成後的公司帳戶已經建立和驗證。一旦證書是購買並安裝在一台機器上,您需要匯出的 PFX 格式包含私密金鑰的證書。生成一個應用程式註冊權杖 (AET) 和簽署任何由本公司開發的應用程式將使用此證書。在開發電腦上安裝證書,時,重要的是要遵循的步驟概述了在 bit.ly/1287H8j。否則,你就會用不會正確驗證部署過程不完整的 PFX 檔。跳過這些步驟是許多開發人員常見頭痛。

AET 必須安裝在設備上之前,設備可以安裝任何應用程式的公司開發的。通過安裝 AET,設備先前建立的公司帳戶中登記。Windows Phone SDK 8.0 包括工具,AETGenerator,可以用於創建 AET 從匯出的證書。產生器創建 AET 的三種不同的形式:AET MDM Windows Intune 或系統中心 2012年組態管理員 (.aet) 和一種 XML 格式,可以直接通過電子郵件或互聯網瀏覽器 (.aetx) 在設備上安裝與使用 Base64 編碼的版本的 XML 格式 (.xml),其中包含原始版本。

當決定要使用分發 AET 和您的公司應用程式的方法,有一點是很重要考慮。當設備安裝 AET 時,有效期直至其到期日期,其中,預設情況下是一年。一旦 AET 過期後,設備將無法運行任何簽署並由公司分配的應用程式 — — 包括集線器的應用程式 — — 直到安裝了新的、 有效的 AET。這將創建兩個專案,您需要添加到您的部署的戰略規劃。

首先是如何處理的 AET 失效。如果您使用的 MDM 來管理您的設備,可以直接從 MDM.到設備發佈更新的 AET這將有助於在設備上的原始 AET 的失效的影響降到最低。如果非託管進程通過安裝 AET — — 電子郵件或 Internet Explorer — — 新 AET 將需要由使用者手動安裝。因為使用者不能運行任何應用程式從公司,包括集線器 app,一旦 AET 過期,它是一個好的做法,來創建和分發新 AET 原始到期之前。這將阻止使用者失去對公司的應用程式的訪問。

要考慮的第二項是清除 AET,以及任何公司在設備上安裝的應用程式。在當前帶來您自己的設備 (BYOD) 世界中,這可以的主要考慮因素。使用 MDM 給的公司的設備安裝其應用程式的完全控制。可以直接從 MDM.遠端刪除應用程式和澳大利亞東部標準時間但是,在非託管的部署中,這不可能。一旦 AET 添加到設備中,它是有效的和其到期之前不能刪除。同樣,SDK 不會提供從設備通過代碼刪除應用程式的方法。解決這一問題的最佳做法要求使用者對公司的所有應用程式進行身份驗證。這使您可以防止使用者帳戶啟動的應用程式。雖然這不是相同,不能刪除該應用程式,它不會給你的方法來管理您的應用程式的安全,一旦部署到設備。

您的初始步驟完成之後,你準備好要開始創建的應用程式可以部署到您公司的員工而無需通過商店去。你會找到更完整的看看創建公司帳戶、 獲得企業移動代碼簽章憑證和生成在 AET bit.ly/SBN6Tf

為發展作準備

公司樞紐 app,需要更多比大多數 Windows Phone 應用程式的設置。為一件事,是要有至少幾個應用程式可用於安裝和使用應用程式中的測試案例作為相當方便。雖然他們自己的應用程式可以是空白的 Windows Phone 應用程式,它們都必須有一個共同點:發行者 id。

如果您已經創建了一個 Windows Phone 應用程式,你可能熟悉 Windows Phone 應用程式清單檔,它在預設情況下是位於解決方案的屬性資料夾中的 WMAppManifest.xml 檔。此檔包含 Windows Phone 和資訊存儲需要瞭解您的應用程式。打開 WMAppManifest.xml 檔從 Visual Studio 內的啟動設計器,使它易於維護的檔。設計器包含四個選項卡,其中之一就是包裝選項卡。

包裝選項卡提供了應用程式、 版本控制資訊和支援的語言的開發人員資訊。這篇文章的目的,為版本、 產品識別碼 和發行者 ID 是最重要的專案,在此選項卡上。預設情況下,Windows Phone 專案範本生成新的 GUID 的產品識別碼 和發行者 ID 在創建專案時。工作時與 app 等公司的樞紐,app 將有只到其他應用程式具有相同的發行者 ID,它的知名度。此發行者 ID 通常設置為發佈伺服器 GUID 是分配給您的開發人員帳戶中開發中心。Dev 中心帳戶摘要頁面上可以找到發行者的 GUID。

這篇文章的可下載檔案包含七個解決方案。第六個被命名為 CDSAPP [1-6]。這些應用程式的每個從 Windows Phone 應用程式專案範本創建的是僅有的主頁面上的應用程式標題和發行者 ID 修改。如果你要使用這些應用程式為您的測試,它是重要的為您公司的集線器應用程式使用相同的發行者 ID,或要更改你的 app Id。

版本和產品識別碼 是兩部分的重要資訊要知道何時創建公司的樞紐解決方案。版本允許您確定當應用程式需要在設備上,升級和產品識別碼 用於標識應用程式。

接下來要考慮是您的測試方法。一般情況下,你可以在 Windows Phone 模擬器上測試大部分。它做的很好,並允許您測試的事情,你需要在開發過程中測試的大多數。測試公司集線器 app 的難處是您的應用程式需要有在模擬程式來測試與安裝的附加程式。然而,每次啟動新實例的模擬程式,它從作業系統的乾淨版本開始。這意味著什麼你以前安裝的測試不再存在。

有兩種方法可以解決此問題。第一是離開運行模擬器,安裝一些測試的應用程式,,然後做貴公司的發展樞紐 app 模擬程式仍在運行。當然,如果出於任何原因重新開機模擬程式獲取你要重新安裝這些應用程式開始再次測試。

首選的方法是做你發展針對真正的設備進行測試。這為您的測試提供一個更穩定的平臺。如果你要做你直播設備上進行測試,您需要確保該設備的發行者 ID 對應的發行者 id,您的帳戶。

公司樞紐 SDK

Windows Phone SDK 8.0 包括兩類,主要負責管理以及與公司應用程式安裝在機器上進行交互。雖然有一些會將向您介紹沿途的支持對象,瞭解這兩個類給你集線器的應用至關重要。

包類每個設備上安裝的應用程式由包類表示,位於 Windows.ApplicationModel 命名空間中。包類包含幾個重要的成員,我會在這裡討論。首先是返回 PackageId 類的 Id 屬性。該類包含了大部分的清單資料被輸入到包裝選項卡中的清單設計器,其中包括被分配了到 app、 應用程式名稱、 發佈資訊和當前版本的產品 Id。

包類的其他重要成員是發射的方法,使您能夠啟動包表示從當前應用程式的應用程式。這不僅是一個偉大的工具構建樞紐公司 app,也可以為其他業務線 (LOB) 應用程式非常有用。

InstallationManager 類 InstallationManager,在 Windows.Phone.Management.Deployment 命名空間,是負責在設備上安裝的包的類。這是通過 AddPackageAsync 方法來實現的。FindPackagesFromCurrentPublisher 方法返回從當前的應用程式,包括包表示當前應用程式中,作為同一 PublisherId 的所有應用程式的清單。此外,還可以使用類讓任何應用程式具有相同的 PublisherId 的安裝進度。

建築公司集線器 App

我要把你介紹給開發公司集線器 app,核心原則使用演示所示圖 1。演示包含三頁全景 app,列出可用公司在三個類別的應用程式:目前沒有可用的更新與安裝、 應用程式和已安裝的最新版本的應用程式的應用程式。此外,應用程式將有詳細頁面,提供了有關應用程式的資訊,並提供的命令來安裝最新版本和啟動應用程式從內部集線器。可以找到工作的解決方案作為一個可下載的資源,從 archive.msdn.microsoft.com/mag201307Hub


圖 1 公司集線器 App

什麼是缺少出於完整性的考慮,它是重要的是要指出幾個專案並不包含在演示應用程式,但將必須創建任何真實世界的解決方案。第一是公司可用的應用程式源。如果您檢查的 CompanyPackage 類,您就會看到它包含 GenerateData 的一種方法。此方法用於生成安裝的公司在設備上的應用程式清單、 修改的一些資料和創建一些虛構的資料,以及由假公司可用的應用程式。

第二個缺失片斷是網站主辦的.xap 檔中下載並安裝在設備上。為公司的集線器才能正常工作,它必須能夠從某些位置下載的應用程式。此 Web 解決方案會以及創建。

CompanyPackage 類為了代表清單中可用的應用程式,要安裝在設備上,首先要定義是仿照包類的 CompanyPackage 類。CompanyPackage 類包含顯示資訊和位置的安裝套裝程式:

public class CompanyPackage
{
  public string Id { get; set; }
  public string Name { get; set; }
  public string Description { get; set; }
  public string Thumbnail { get; set; }
  public string Version { get; set; }
  public Uri SourceUri { get; set; }
  public CompanyPackageStatus Status { get; set; }
}

Status 屬性用於確定當前安裝在設備上的 app 如果有一個較新的版本。 CompanyPackageStatus 是 enum 類型的值,在本文的後面,我將探討:

public enum CompanyPackageStatus
{
  Unknown,
  New,
  Update,
  Installed
};

創建視圖模型 這個公司集線器 App,您必須創建一個單一視圖模型,CompanyPackageViewModel,所示 圖 2。 視圖模型應該有三個屬性,返回的 CompanyPackage 物件 IEnumerable 集合:NewPackage、 UpdatePackages 和 InstalledPackages。 NewPackage 屬性包含任何可用的應用程式,不當前安裝在機器上。 UpdatePackages 表示當前已安裝在電腦上,但有較新的版本可用的任何應用程式。 最後,InstalledPackages 包含所有當前已安裝且最新的設備上的應用程式。

圖 2 CompanyPackage 視圖模型

public class CompanyPackageViewModel : INotifyPropertyChanged
{
  private IEnumerable<CompanyPackage> _packages;
  public CompanyPackageViewModel()
  {
    LoadData();       
  }
  private void LoadData()
  {
    // Get list of packages and populate properties
    _packages = CompanyPackage.GenerateData();
    UpdatePackageStatus();
  }
  private IEnumerable<CompanyPackage> _newPackages;
  public IEnumerable<CompanyPackage> NewPackages
  {
    get
    {
      return _newPackages;
    }
  }
  private IEnumerable<CompanyPackage> _updatePackages;
  public IEnumerable<CompanyPackage> UpdatePackages
  {
    get
    {
      return _updatePackages;
    }
  }
  private IEnumerable<CompanyPackage> _installedPackages;
  public IEnumerable<CompanyPackage> InstalledPackages
  {
    get
    {
      return _installedPackages;
    }
  }
  public event PropertyChangedEventHandler PropertyChanged;
  private void NotifyPropertyChanged(String propertyName)
  {
    PropertyChangedEventHandler handler = PropertyChanged;
    if (null != handler)
    {
      handler(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}

定義的三種狀態你可以填充的三個不同屬性的視圖模型之前,您需要生成代表作為集合的 CompanyPackages 的可用應用程式清單。 在所示的視圖模型圖 2,載入並在 LoadData 方法中填充資料。 LoadData 方法拉扯試驗資料的清單,並將其存儲私人 _packages 變數中。 然後,它調用 UpdatePackageStatus 方法所示圖 3

圖 3 種方法確定每個 CompanyPackage 的狀態

public void UpdatePackageStatus()
{
  var devicePkgs = 
    InstallationManager.FindPackagesForCurrentPublisher();
  foreach (var pkg in _packages)
  {
    var qry = devicePkgs.Where(p => p.Id.ProductId == pkg.Id);
    if (qry.Count() > 0)
    {
      var devicePkg = qry.First();
      var devicePkgVersion =
        PackageVersionHelper.VersionToString(devicePkg.Id.Version);
      pkg.Status = PackageVersionHelper.IsNewer(
        pkg.Version, devicePkgVersion) ?
CompanyPackageStatus.Update : CompanyPackageStatus.Installed;
    }
    else
    {
      pkg.Status = CompanyPackageStatus.New;
    }
  }
  _newPackages = _packages.Where(
     p => p.Status == CompanyPackageStatus.New).ToList();
  _updatePackages = _packages.Where(
     p => p.Status == CompanyPackageStatus.Update).ToList();
  _installedPackages = _packages.Where(
     p => p.Status == CompanyPackageStatus.Installed).ToList();
  // Fire notifications for all properties
  NotifyPropertyChanged("NewPackages");
  NotifyPropertyChanged("UpdatePackages");
  NotifyPropertyChanged("InstalledPackages");
}

UpdatePackageStatus 方法有兩個職責:確定每個可用的 CompanyPackage 類的目前狀態,然後填充三個集合屬性的這種地位所基於的視圖模型。

Status 屬性確定通過比較每個 CompanyPackage 反對在設備當前安裝的應用程式。 從 InstallationManager.FindPackagesForCurrentPublisher 的靜態方法獲得的已安裝應用程式的清單。 如果具有相同的 Id CompanyPackage 包物件不存在,它與"新"狀態標記。

如果不存在具有相同 Id 的包,然後包版本屬性相比的 CompanyPackage 版本。 PackageId 版本屬性返回的 PackageVersion 結構。 不同的 System.Version 類,此結構缺少的兩個特點。 第一個特徵是能力結構轉換為字串表示形式。 如果您調用 ToString 方法,它返回的類型名稱和不實際的版本號。 第二個缺失功能是進行比較以確定哪一個是較新的 PackageVersion 的兩個實例的能力。

圖 4 顯示了實現這些缺失的功能有兩個説明器類。 VersionToString 方法返回 PackageVersion 的正確的字串表示形式。 IsNewer 方法採用兩個版本號的字串表示形式,並確定是否豐田參數是較新的 oldVersion 參數比。 它通過將字串轉換為 System.Version 物件,並使用可用 CompareTo 方法來實現這一點。

圖 4 為 PackageVersion 的的説明器類

public static class PackageVersionHelper
{
  public static string VersionToString(PackageVersion version)
  {
    return String.Format("{0}.{1}.{2}.{3}",
                         version.Major,
                         version.Minor,
                         version.Build,
                         version.Revision);
  }
  public static bool IsNewer(string newVersion, 
    string oldVersion)
  {
    var newVer = Version.Parse(newVersion);
    var oldVer = Version.Parse(oldVersion);
    return newVer.CompareTo(oldVer) > 0;
  }
}

一旦 UpdatePackageStatus 方法計算了 Status 屬性,每個公司­包物件時,它將填充三個集合的屬性,使用 LINQ 查詢。 最後,視圖模型引發 PropertyChanged 事件的每個屬性。

顯示應用程式清單中的具有三個全景全景控制項內顯示三個可用的應用程式清單­專案,每個包含初選­選擇器綁定到的清單。 每個使用相同的 DataTemplate 顯示 CompanyPackage 和完整的全景 XAML 可以發現在圖 5。 在可下載的專案中,您將看到的全景控制項的 DataCoNtext 繼承父 PhoneApplicationPage,它被設置為 CompanyPackageViewModel 的實例的 DataCoNtext。 你看到的這個結果圖 1

圖 5 全景圖,以顯示可用的應用程式

<phone:Panorama Title="my company hub">
  <phone:Panorama.Resources>
    <DataTemplate x:Key="listItemTemplate">
      <StackPanel Margin="0,-6,0,12" Orientation="Horizontal">
        <Image  Source="{Binding Thumbnail,
          Converter={StaticResource debugConv}}"/>
        <TextBlock Text="{Binding Name}" TextWrapping="Wrap"
          VerticalAlignment="Center"
          Style="{StaticResource PhoneTextExtraLargeStyle}"
          FontSize="{StaticResource PhoneFontSizeExtraLarge}"/>
      </StackPanel>
    </DataTemplate>
  </phone:Panorama.Resources>
  <!--Panorama New Apps-->
  <phone:PanoramaItem Header="New Apps">
    <!--Single line list with text wrapping-->
    <phone:LongListSelector Margin="0,0,-22,0"
      ItemsSource="{Binding NewPackages}"
      SelectionChanged="ItemSelected"
      ItemTemplate="{StaticResource listItemTemplate}"/>
  </phone:PanoramaItem>
  <!--Panorama Update Apps-->
  <phone:PanoramaItem Header="Update Apps">
    <!--Single line list with text wrapping-->
    <phone:LongListSelector Margin="0,0,-22,0"
      ItemsSource="{Binding UpdatePackages}"
      SelectionChanged="ItemSelected"
      temTemplate="{StaticResource listItemTemplate}"/>
  </phone:PanoramaItem>
  <!--Panorama Installed Apps-->
  <phone:PanoramaItem Header="Installed Apps">
    <!--Single line list with text wrapping-->
    <phone:LongListSelector Margin="0,0,-22,0"
      ItemsSource="{Binding InstalledPackages}"
      SelectionChanged="ItemSelected"
      ItemTemplate="{StaticResource listItemTemplate}"/>
  </phone:PanoramaItem>
</phone:Panorama>

CompanyPackage 詳細資訊視圖

每個 LongListSelector 共用相同的事件處理 SelectionChanged 事件,ItemSelected。 事件處理常式使用 NavigationService 來導航到明細 PhoneApplicationPage,PackagePage,和 CompanyPackage 的 Id 在傳遞。 因為當前頁面將被緩存在導航中,LongListSelector 的 SelectedItem 被重置為 null,以確保適當的事件,觸發每個時間:

private void ItemSelected(object sender, 
  SelectionChangedEventArgs e)
{
  if (e.AddedItems.Count > 0 && e.AddedItems[0] != null)
  {
    var pkg = e.AddedItems[0] as CompanyPackage;
    NavigationService.Navigate(
      new Uri("/PackagePage.xaml?id=" + pkg.Id, 
      UriKind.Relative));
    (sender as LongListSelector).SelectedItem = null;
  }
}

PackagePage 類只接收的 CompanyPackage 要顯示的 Id,因為它具有使用該 Id 來查找適當的物件。 這是通過向 CompanyPackageViewModel 添加一個 FindPackage 的方法:

public CompanyPackage FindPackage(string id)
{
  return _packages.Where(p => p.Id == id).FirstOrDefault();
}

Windows Phone 全景 App 專案公開一個全域視圖模型由 ViewModel 屬性添加到該應用程式類。這一專案使用該屬性公開其向主視圖模型和詳細資訊頁。

PackagePage 類重寫 OnNavigatedTo 方法,以將其 DataCoNtext 設置為匹配提供的 id CompanyPackage然後,它調用 UpdateUI 方法的可見度和內容的兩個按鈕添加到基於 CompanyPackage 的狀態螢幕之間切換。每個狀態類型的結果可以看到在圖 6


圖 6 不同詳細頁

兩個按鈕將公開可用的公司集線器類內的兩個操作。第一是啟動應用程式的能力。如果在設備上當前安裝的 app,啟動按鈕是可見的。該按鈕的事件處理常式查找正確的包物件匹配當前的 CompanyPackage,並且調用啟動的方法:

private void btnLaunch_Click(
  object sender, RoutedEventArgs e)
{
  var pkg = DataContext as CompanyPackage;
  var devicePkgs = InstallationManager.
FindPackagesForCurrentPublisher();
  var devicePkg = devicePkgs.Where(p =>
    p.Id.ProductId == pkg.Id).FirstOrDefault();
  if (devicePkg != null)
  {
    devicePkg.Launch("");
  }        
}

如果 CompanyPackage 的狀態為"新建"或"更新",安裝按鈕是在頁上可見。 此按鈕的事件處理常式將嘗試安裝最新版本的應用程式從提供的源中的 Uri­CompanyPackage 的 Uri 屬性。 這是使用 InstallationManager.AddPackageAsync 方法來完成。 是否正在更新應用程式或新安裝它的調用相同的方法。 此方法可以是非常喜怒無常,您需要確保要照顧的生成的任何錯誤。 圖 7 顯示事件處理常式和安裝過程。 如果應用程式安裝成功,UpdatePackage­CompanyPackageView 狀態方法­模型調用來更新顯示在主頁面和頁面更新頁面 UpdateUI 方法的狀態集合。

圖 7 安裝和更新按鈕事件處理常式

private async void btnInstall_Click(object sender, RoutedEventArgs e)
{
  var pkg = DataContext as CompanyPackage;
  if (MessageBox.Show("Install " + pkg.Name + "?", "Install app",  
   MessageBoxButton.OKCancel) == MessageBoxResult.OK)
  {
    try
    {
      var result =
        await InstallationManager.AddPackageAsync(pkg.Name, pkg.SourceUri);
      if (result.InstallState ==
        Windows.Management.Deployment.PackageInstallState.Installed)
      {
        MessageBox.Show(pkg.Name + " was installed.");
        App.ViewModel.UpdatePackageStatus();
        UpdateUI();
      }
      else
      {
        MessageBox.Show("An error occurred during installation.");
      }
    }
    catch (Exception)
    {
      MessageBox.Show("An error occurred during installation.");
    }
  }
}

下一個步驟

在這篇文章我快速看了暴露詳細資訊的同時開發公司集線器 app 需要創建一個更強健的解決方案。 一些被省去了簡明扼要的詳細資訊可以包括下載中找到。 然而,它是重要的是要記住這只是個開始。

有很多的功能,可以將其添加到公司集線器,以便向您的使用者,如利用活的瓷磚,新的應用程式可用時通知使用者提供極大的好處。 您可以創建僅公開向某些使用者基於他們的角色在公司內的某些應用程式的解決方案。 應用程式可以提供附加功能,例如公司新聞和通知。 雖然可能性不可能是無限的但有足夠多,相當一段時間就會讓你忙。

Tony Champion 是冠軍 DS 的總統,是微軟最有價值球員,並積極參與社會的揚聲器、 博主和作者。他堅持在博客上的 tonychampion.net 可以通過電子郵件在到達 tony@tonychampion.net

感謝以下技術專家對本文的審閱:懸崖 Strom (Microsoft)