Windows 10 UWP 8 of N: Contact user`s data

  • 812
  • 0
  • UAP
  • 2021-04-30

Windows 10 UWP 8 of N: Contact, appointments, message, user`s data

早在Windows Phone的時候很多APP就已經跟People hub (人員),藉由連結各個Contact provider的APP連結成一個聯絡人資訊。

主要跟user data非常相關的有以下幾個功能

appointment (行事曆)

calls(撥號)

contacts(聯絡人)

Email(電子信箱)

Text messages(簡訊)

User data accounts(使用者帳號[ Aka 新增帳戶 ])

在抓取這些資訊時必須先在Manifest[ Package.appmanifest檔案 ]做宣告。這邊不能用內建的UI介面做調整,需要使用XML開啟並在capabilities加入以下權限。

<Capabilities>
    <Capability Name="internetClient" />
    <uap:Capability Name="contacts"/>
</Capabilities>

預設情形會加入internetClient,需手動加入的是contacts。

接者來寫Code存取聯絡人資訊!

public async void GetContact(ContactStoreAccessType accessType)
{
	var contactStore = await ContactManager.RequestStoreAsync(accessType);
        if (contactStore == null)
        {
        return null;
        }
        var reader = contactStore.GetContactReader();
        var readerBatch = await reader.ReadBatchAsync();
        var contactList = new List<Contact>();
		while (readerBatch.Status == ContactBatchStatus.Success && readerBatch.Contacts.Count != 0)
		{
			foreach (var contact in readerBatch.Contacts)
			{
				contactList.Add(contact);
			}
			readerBatch = await reader.ReadBatchAsync();
		}
	return contactList;
}

這邊有幾點必須注意在抓取contact的資料時帶入存取的權限enum

 

public enum ContactStoreAccessType
    {
        //
        // Summary:
        //     Read and write contacts that belong to the app only.
        AppContactsReadWrite = 0,
        //
        // Summary:
        //     Read access to all app and system contacts.
        AllContactsReadOnly = 1,
        //
        // Summary:
        //     Read and write access to all app and system contacts.
        AllContactsReadWrite = 2
    }

存取權限可以分為->讀寫、唯讀、所以系統註冊之聯絡人讀寫。所有系統註冊就是包含其他開發人員所提供contact store!

接者是如果抓取失敗的時候會丟回null值。

讀取聯絡人方式需要用ContactReader來做讀取的物件並且讀取的方式是採用批次[Batch]的方式做讀取。

讀取成功後抓取聯絡人資料到ListView的畫面如下

image

PS:由於抓取我個人的Contact所以將上籃線遮蔽

接下來是建立自己的APP的Contact Store

public async Task CreateContactStoreAsync()
{
	var success = await TryOpenContactStoreAsync();
    if (!success)
    	return;
    var contactLists = await store.FindContactListsAsync();
    if (contactLists.Count != 0)
    {
        System.Diagnostics.Debug.WriteLine("Contact List exit");
    	return;
    }
    var simpleContactList = await store.CreateContactListAsync(contactListId);
    simpleContactList.IsHidden = false;
    simpleContactList.OtherAppReadAccess = ContactListOtherAppReadAccess.Full;
    simpleContactList.OtherAppWriteAccess = ContactListOtherAppWriteAccess.SystemOnly;
	await simpleContactList.SaveAsync();
}

這邊建立的方式需要先抓取系統的ContactStore並建立ContactList!

ContactList有以下幾點重要的API

Read-Only

屬性 存取層級 敘述
ChangeTracker Read-only 取得該ContactList的ContactChangeTracker
DisplayName Read/Write 顯示名稱
Id Read-Only 取得該ContactList的識別碼
IsHidden Read/Write 是否顯示ContactList在UI上
OtherAppReadAccess Read/Write 設定其他APP讀取該APP的權限
OtherAppWriteAccess Read/Write 設定其他APP寫入該APP的權限
SourceDisplayName Read-Only ContactList的提供來源字串
SupportsServerSearch Read-Only 是否能搜尋遠端伺服器
SyncManager Read-Only 與伺服器溝通物件
UserDataAccountId Read-Only 取得建立該contactlist的使用者帳號ID

這邊會有個非常強大的功能ChangeTracker!沒錯就像是版本控制相似的功能,可以抓取聯絡人資訊變更紀錄。在文章下半段會詳細介紹該API使用。

基本上調整IsHidden、OtherAppReadAccess和OtherAppWriteAccess就可以建立基本的ContactList了!

這邊關於OtherAppWriteAccess的權限要特別注意,因為這會取決於是否能夠藉由系統的APP來刪除以及修改聯絡人資訊。

以下程式碼來新增聯絡人

public async void InserNewContact()
{
    var contactInfo = new Contact();
    contactInfo.FirstName = "EW";
    contactInfo.LastName = "Taicho";
    contactInfo.Phones.Add(new ContactPhone() { Number = "0963600700" });
    contactInfo.Emails.Add(new ContactEmail() { Address = "testAc@msftUwp.com" });
    var contactList = await store.GetContactListAsync(contactListId);
	await contactList.SaveContactAsync(contactInfo);
}

image

加入之後重新抓取聯絡人列表就可以看到新增進去的EW的聯絡人了。

image

以及克制詳細的聯絡人資訊。

image

甚至在People的APP中可以看到建立該Contact的APP[ App1 ]

 


ContactTracker and ContactTrackerTrigger

接下來介紹的是ContactTracker的部分!

需要啟用ContactTracker在建立Contact的時候就將Tracker的功能開啟並註冊該事件就可以。

 

 

public async Task CreateContactStoreAsync()
{
    var success = await TryOpenContactStoreAsync();
	if (!success)
		return;

    var contactLists = await store.FindContactListsAsync();
    if (contactLists.Count != 0)
    {
        System.Diagnostics.Debug.WriteLine("Contact List exit");
        contactListId = contactLists.FirstOrDefault().Id;
    	return;
	}

    var simpleContactList = await store.CreateContactListAsync(contactDisplayName);
    contactListId = simpleContactList.Id;
    simpleContactList.IsHidden = false;
    simpleContactList.OtherAppReadAccess = ContactListOtherAppReadAccess.Full;
	simpleContactList.OtherAppWriteAccess = ContactListOtherAppWriteAccess.SystemOnly;

    store.ChangeTracker.Enable();
	store.ContactChanged += new Windows.Foundation.TypedEventHandler<ContactStore, ContactChangedEventArgs>(ContactStoreTrackerHandler);

	await simpleContactList.SaveAsync();
}

ContactChanged的事件註冊如下

private async void ContactStoreTrackerHandler(ContactStore sender, ContactChangedEventArgs args)
        {
            var defferal = args.GetDeferral();
            var reader = sender.ChangeTracker.GetChangeReader();
            var changes = await reader.ReadBatchAsync();
            while (changes.Count != 0)
            {
                foreach (var change in changes)
                {
                    switch (change.ChangeType)
                    {
                        case ContactChangeType.Created:
                        case ContactChangeType.Modified:
                        case ContactChangeType.Deleted:
                            var toastMessage = string.Format($"{change.Contact.FirstName}, {change.ChangeType}");
                            SentToast(toastMessage);
                            break;
                        case ContactChangeType.ChangeTrackingLost:
                            sender.ChangeTracker.Reset();
                            defferal.Complete();
                            break;
                        default:
                            break;
                    }
                }
                changes = await reader.ReadBatchAsync();
            }
            reader.AcceptChanges();
            defferal.Complete();
        }

這邊的Change type需要注意的是要有ChangeTrackingLost以及Default的預留!當系統出現問題或是進行聯絡人重新設定就會將ChangeTraker重新Refresh所以會Lost調ChangeTrack。至於留下Default則是之後有可能新增其他類型的Type作為預留空間。

 

當Foreground的event註冊好就可以新增資料來測試!如下就是Create[ Insert contact ]就會提示的Toast Notification。

image

 

接下來說明一下Background的TrackEvent是如何被觸發。

之前在前幾篇就有說明到Background的部分所以我就沿用之前的Code

 

await RegistrationBackgroundTaskHelper.RegisterBackgroundTasksAsync("SimpleBackgroundTask", typeof(ContactStoreTask), new ContactStoreNotificationTrigger());

註冊ContactStoreNotificationTrigger就可以抓取到ContactStore的Tracker。

寫個BackgroundTask的Class並使用以下的Code就可以收到Background的Contact Change的事件

 

public sealed class BackgroundToastTask : IBackgroundTask
    {
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            taskInstance.Canceled += TaskInstance_Canceled;
            if (taskInstance.TriggerDetails is ContactStoreNotificationTriggerDetails)
                ShowToast("Contact Changed!!");
        }

        private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
        {

        }

        private void ShowToast(string toastMessage)
        {
            var toastTemplate = ToastTemplateType.ToastText01;
            var toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
            var toastTextElements = toastXml.GetElementsByTagName("text");
            toastTextElements[0].AppendChild(toastXml.CreateTextNode(toastMessage));
            var toast = new ToastNotification(toastXml);
            ToastNotificationManager.CreateToastNotifier("App").Show(toast);
        }
    }

這邊比較可惜的是ContactStoreNotificationTriggerDetails目前只是空的Detail Object...所以沒辦法抓取ChangeType等資訊。

image

 


 

***以上Code以及說明都有可能隨著Windows 10 的版本以及Visual Studio 2015版本有所調整!***

參考資料 2-684 User Data: working with contacts, appointments, text message and more on Windows 10, MSDN Blogs

下次再分享Windows 10 的新技術拉~