Windows上的人员

Windows 是第三方应用用于集成其顶级联系人的理想平台。 通过此集成,用户可以与用于各种用户体验的模拟角色进行交互。 Windows 现在为第三方 WinUI 和其他应用提供 程序包标识 和 API 来存储其所有联系人。

应用在 Windows 中存储其联系人后,用户将能够在 Windows 的 “共享 ”面板中看到这些联系人建议,以便与其顶级联系人无缝共享。 有关“共享”面板的详细信息,请参阅如何在 Windows 上的 文件资源管理器中共享文件。

为人脉合约创建 UserDataAccount

首先创建用户数据帐户。 第三方应用需要创建一个 UserDataAccount,其中 UserDisplayName"com.microsoft.peoplecontract"

UserDataAccountStore udas =
    await UserDataAccountManager.RequestStoreAsync(UserDataAccountStoreAccessType.AppAccountsReadWrite);
UserDataAccount uda = await udas.CreateAccountAsync("com.microsoft.peoplecontract");

接下来,将 "com.microsoft.windows.system" 添加到帐户的 ExplictReadAccessPackageFamilyNames 列表中。 这将限制第三方联系人对 Windows 体验的访问权限。

uda.ExplictReadAccessPackageFamilyNames.Add("com.microsoft.windows.system");
await uda.SaveAsync();

存储联系人

存储联系人的第一步是创建联系人列表。 为此,第三方应用必须在 Windows UserDataAccount 中为 a 创建新的联系人列表。 应用可以选择保留联系人列表的默认 OtherAppReadAccess 访问类型,同时将其 None 设置为阻止其他应用访问这些联系人。 有关可用访问类型的完整列表,请参阅 ContactListOtherAppReadAccess 枚举。

ContactStore store = await ContactManager.RequestStoreAsync(ContactStoreAccessType.AppContactsReadWrite);
this.contactList = await store.CreateContactListAsync(contactListsName, uda.Id);
contactList.OtherAppReadAccess = ContactListOtherAppReadAccess.None;
await contactList.SaveAsync();

存储联系人时,第三方应用程序必须包括 Windows 体验所需的所有相关信息,以支持某个联系人

存储联系人时需要以下字段:

  • FirstName
  • RemoteId
  • DisplayPicture

以下字段是可选的:

  • LastName
  • Phones
  • Emails

此代码片段演示如何存储联系人:

foreach (var appContact in AppContacts)
{
  var cont = new Contact
  {
    FirstName = appContact.FirstName,
    LastName = appContact.LastName,
    RemoteId = appContact.Id,
    SourceDisplayPicture = RandomAccessStreamReference.CreateFromUri(new Uri(appContact.ProfilePicPath)),
    Phones = { new ContactPhone { Number = appContact.Phone } }
  };

  await this.contactList.SaveContactAsync(cont);
}

注意

DisplayName 是使用 FirstNameLastName 构造的。 如果未提供姓氏, DisplayName 则与为名字提供的字符串相同。

存储联系人的分级

可以为 UserDataAccount 创建注释列表,以存储联系人的排名。 应用可以通过向联系人添加批注来存储其顶级联系人的排名。 这些批注作为批注列表的一部分存储在联系人信息库中。

ContactAnnotationStore annotationStore = await
    ContactManager.RequestAnnotationStoreAsync(ContactAnnotationStoreAccessType.AppAnnotationsReadWrite);
this.contactAnnotationList = await annotationStore.CreateAnnotationListAsync(uda.Id);

可以使用联系人上的批注来存储顶级联系人的排名。 在联系人注释中,排名作为 ProviderProperties 的一部分存储。 除了排名之外,应用还必须将联系人注释上的 SupportedOperations 设置为 Share

foreach (var appContact in topAppContacts)
{
  Contact contact = await list.GetContactFromRemoteIdAsync(topAppContact.RemoteID);
  var annotation = new ContactAnnotation
  {
    ContactId = contact.Id,
    SupportedOperations = ContactAnnotationOperations.Share
  };
  annotation.ProviderProperties.Add("Rank", rank);
  await annotationsLst.TrySaveAnnotationAsync(annotation);
}

更新联系人排名

在更新存储在 Windows 中的联系人的排名时,应用可自由决定。 Windows 建议定期更新排名列表,以提供最佳用户体验。 每当需要更新排名列表时,都需要执行几个步骤。

  1. 删除 ContactAnnotationList

    应用程序获得顶级联系人的更新列表后,可以删除原有的批注列表,并创建一个包含更新的顶级联系人批注的新批注列表。

    await this.contactAnnotationList.DeleteAsync();
    
  2. 创建新的 ContactAnnotationList。 按照“存储联系人排名”部分中的步骤,创建一个新的批注列表,为你的顶级联系人存储排名。

排名最佳做法

若要在“共享工作表建议”行中最大化应用联系人的相关性,请遵循以下排名原则:

按连续度和频率进行排名

将排名计算为以下各项的组合:

  • 最近互动时间:用户上次与每位联系人互动的时间
  • 频率:用户与每个联系人交互的频率

例如,昨天发送的用户的联系人可能排名为 95,而 2 周前发送的联系人可能排名为 60。

// lastInteraction and interactionCount come from your app's own interaction
// telemetry. The Windows Contact class does not expose interaction history.
private int CalculateRank(DateTime lastInteraction, int interactionCount)
{
    TimeSpan daysSinceLastInteraction = DateTime.Now - lastInteraction;
    int frequencyScore = interactionCount * 10; // Max ~100
    int recencyScore = Math.Max(0, 100 - (daysSinceLastInteraction.Days * 3));

    return (recencyScore + frequencyScore) / 2;
}

删除过时的联系人

用户未在 30 天内与之交互的联系人应显著删除或降级。 这让建议保持最新且相关:

private async Task PruneStaleContactsAsync()
{
    var now = DateTime.Now;
    var staleCutoff = now.AddDays(-30);
    
    foreach (var contact in this.AllTrackedContacts)
    {
        if (contact.LastInteractionDate < staleCutoff)
        {
            // Remove the annotation or set rank to 0
            var annotation = await GetAnnotationForContactAsync(contact);
            if (annotation != null)
            {
                annotation.ProviderProperties["Rank"] = 0;
                await this.contactAnnotationList.TrySaveAnnotationAsync(annotation);
            }
        }
    }
}

定期更新排名

按照适合您应用的频率安排排名更新——即时通讯应用可每日更新,电子邮件应用可每周更新,日历应用可每月更新。 必要时,使用后台任务:

// Example: Update ranks when the app comes to foreground or on a timer
private async void UpdateRanksOnAppActivated()
{
    var topContacts = GetTopContactsByRecentActivity(50);
    await UpdateAnnotationRanksAsync(topContacts);
}

仅添加明确的联系人

你的应用应仅提供用户已明确添加或授权的联系人。 从不

  • 上传整个通讯簿
  • 未经用户同意自动同步联系人
  • 在没有显式权限的情况下共享公司目录中的联系人

在人员系统中存储联系人之前请求权限:

private async Task<bool> RequestContactStoreAccessAsync()
{
    // Requesting a writable ContactStore prompts the user for consent.
    // Your app must declare the contacts capability in its manifest.
    ContactStore store = await ContactManager.RequestStoreAsync(
        ContactStoreAccessType.AppContactsReadWrite);
    return store != null;
}

尊重用户隐私设置

允许用户:

  • 选择要与Windows共享的联系人
  • 停用 People 集成
  • 随时从Windows中删除其联系人
// Provide a setting to disable sync
if (this.ShouldSyncContactsWithWindows)
{
    await SyncContactsAsync();
}
else
{
    // Clear contacts if the user disables sync
    await ClearWindowsContactsAsync();
}

与分享面板集成

使用上述指导对联系人进行排名和维护时,用户将在Windows共享工作表的建议行中看到应用的主要联系人。 此路径当前支持个人联系人。

若要确保您的联系人显示出来:

  1. 使用 DisplayName = "com.microsoft.peoplecontract" 创建 UserDataAccount
  2. 存储具有必填字段的联系人(FirstNameRemoteIdDisplayPicture
  3. 创建带有排名的 ContactAnnotationList
  4. 在每个批注上设置SupportedOperations = Share
  5. 根据时效性和频率定期更新排名
  6. 在超过 30 天后清理过期联系人

有关完整的共享表单集成指南,请参阅 从您的应用中共享内容在您的应用中接收内容