Xamarin.iOS 中的 CloudKit

CloudKit 架構可簡化存取 iCloud 的應用程式開發。 這包括擷取應用程式數據和資產許可權,以及能夠安全地儲存應用程式資訊。 此套件可讓使用者使用其 iCloud 識別符存取應用程式,而不需共用個人資訊,來為使用者提供一層匿名性。

開發人員可以專注於其用戶端應用程式,並讓iCloud不需要撰寫伺服器端應用程式邏輯。 CloudKit 提供驗證、私人和公用資料庫,以及結構化數據和資產記憶體服務。

重要

Apple 提供工具協助開發人員適當地處理歐盟一般資料保護規定 (GDPR)。

需求

若要完成本文中說明的步驟,必須執行下列動作:

  • Xcode 和 iOS SDK – 必須在開發人員的電腦上安裝並設定 Apple 的 Xcode 和 iOS 8 API。
  • Visual Studio for Mac – 應在使用者裝置上安裝及設定最新版本的 Visual Studio for Mac。
  • iOS 8 裝置 – 執行最新版 iOS 8 的 iOS 裝置進行測試。

什麼是 CloudKit?

CloudKit 是讓開發人員存取 iCloud Server 的一種方式。 它為 iCloud 磁碟驅動器和 iCloud 相片媒體櫃提供了基礎。 macOS 和 iOS 裝置都支援 CloudKit。

How CloudKit is supported on both macOS and iOS devices

CloudKit 使用 iCloud 帳戶基礎結構。 如果有使用者在裝置上登入 iCloud 帳戶,CloudKit 會使用其標識碼來識別使用者。 如果沒有可用的帳戶,則會提供有限的唯讀存取權。

CloudKit 同時支援公用和私人資料庫的概念。 公用資料庫會提供用戶可存取之所有數據的「湯」。 私人資料庫是用來儲存系結至特定使用者的私人數據。

CloudKit 同時支持結構化和大量數據。 它可以順暢地處理大型文件傳輸。 CloudKit 負責有效率地在背景中的 iCloud Server 中傳送大型檔案,讓開發人員能夠專注於其他工作。

注意

請務必注意 CloudKit 是 傳輸技術。 它不提供任何持續性;它只會讓應用程式有效率地從伺服器傳送和接收資訊。

截至本文所述,Apple 一開始免費為 CloudKit 提供頻寬和記憶體容量的上限。 對於具有大型使用者群的大型專案或應用程式,Apple 已暗示將提供負擔得起的定價規模。

在 Xamarin 應用程式中啟用 CloudKit

在 Xamarin 應用程式可以使用 CloudKit 架構之前,必須先正確布建應用程式,如使用功能和使用權利指南中所述。

若要存取 CloudKit,Entitlements.plist 檔案必須包含 Enable iCloudKey-value storageCloudKit 許可權。

範例應用程式

CloudKitAtlas 範例示範如何搭配 Xamarin 使用 CloudKit。 下列步驟示範如何設定範例 – 它需要其他設定,而不需要CloudKit單獨執行:

  1. 在 Visual Studio for Mac 或 Visual Studio 中開啟專案。
  2. 在 方案總管 中,開啟 Info.plist 檔案,並確定套件組合識別碼符合在布建設定中建立的應用程式識別碼中所定義的標識碼。
  3. 向下卷動至 Info.plist 檔案底部,然後選取 [已啟用的背景模式]、[位置] 更新[遠端通知]。
  4. 以滑鼠右鍵按兩下方案中的 iOS 專案,然後選取 [ 選項]。
  5. 選取 [iOS 套件組合簽署],選取上面建立的 開發人員身分 識別和 布建配置檔
  6. 確定 Entitlements.plist 包含 Enable iCloudKey-value storageCloudKit
  7. 確定應用程式存在 Ubiquity 容器。 範例: iCloud.com.your-company.CloudKitAtlas
  8. 儲存對檔案所做的變更。

有了這些設定之後,範例應用程式現在即可存取 CloudKit Framework API 以及背景、位置和通知服務。

CloudKit API 概觀

在 Xamarin iOS 應用程式中實作 CloudKit 之前,本文將涵蓋 CloudKit Framework 的基本概念,其中包含下列主題:

  1. 容器 – iCloud 通訊的隔離尋址接收器。
  2. 資料庫 – 公用和私人可供應用程式使用。
  3. 記錄 – 結構化數據在 CloudKit 中移入和移出的機制。
  4. 記錄區域 – 是記錄群組。
  5. 記錄標識碼 – 已完全正規化,並代表記錄的特定位置。
  6. 參考 – 提供指定資料庫內相關記錄之間的父子關聯性。
  7. 資產 – 允許將大型非結構化數據的檔案上傳至 iCloud,並與指定的記錄相關聯。

容器

在 iOS 裝置上執行的指定應用程式一律會沿著該裝置上的其他應用程式和服務一起執行。 在用戶端裝置上,應用程式會以某種方式進行尋址或沙盒化。 在某些情況下,這是常值沙盒,而在某些情況下,應用程式只會在它自己的記憶體空間中執行。

將用戶端應用程式與其他用戶端分開執行的概念非常強大,並提供下列優點:

  1. 安全性 – 一個應用程式無法干擾其他用戶端應用程式或作業系統本身。
  2. 穩定性 – 如果用戶端應用程式當機,就無法取出 OS 的其他應用程式。
  3. 隱私權 – 每個用戶端應用程式對儲存在裝置內的個人資訊具有有限的存取權。

CloudKit 的設計目的是提供與上述相同的優點,並將它們套用至使用雲端式資訊:

CloudKit apps communicate using containers

就像應用程式是裝置上執行的一對多,所以應用程式與 iCloud 的通訊是一對多。 每個不同的通訊尋址接收器稱為容器。

容器會透過 CKContainer 類別在 CloudKit Framework 中公開。 根據預設,一個應用程式會與一個容器交談,而此容器會隔離該應用程式的數據。 這表示有數個應用程式可以將資訊儲存到相同的 iCloud 帳戶,但這項信息永遠不會相互關聯。

iCloud 數據的容器化也可讓 CloudKit 封裝用戶資訊。 如此一來,應用程式將有一些有限的 iCloud 帳戶存取權和儲存在內的使用者資訊,同時仍會保護用戶的隱私權和安全性。

容器完全由應用程式的開發人員透過WWDR入口網站進行管理。 容器的命名空間在所有Apple開發人員中都是全域的,因此容器不只對指定的開發人員應用程式而言是唯一的,而且對所有Apple開發人員和應用程式而言都必須是唯一的。

Apple 建議在建立應用程式容器的命名空間時使用反向 DNS 表示法。 範例: iCloud.com.company-name.application-name

雖然容器預設會將一對一系結至指定的應用程式,但可以跨應用程式共用這些容器。 因此,多個應用程式可以在單一容器上協調。 單一應用程式也可以與多個容器交談。

資料庫

CloudKit 的主要功能之一是採用應用程式的數據模型,並將該模型複寫至 iCloud 伺服器。 某些資訊適用於建立它的使用者,其他資訊則是可由用戶為公開使用而建立的公用數據(例如餐廳評論),或者可能是開發人員為應用程式發佈的資訊。 不論是哪一種情況,物件都不只是單一使用者,而是一個社群的人員。

CloudKit Container Diagram

首先,容器內部是公用資料庫。 這是所有公共資訊的生活和共同混在一起的地方。 此外,應用程式的每個使用者都有數個個別的私人資料庫。

在 iOS 裝置上執行時,應用程式只能存取目前登入 iCloud 用戶的資訊。 因此,應用程式的容器檢視如下所示:

The applications view of the container

它只能看到與目前登入的 iCloud 使用者相關聯的公用資料庫和私用資料庫。

資料庫會透過 CKDatabase 類別在 CloudKit Framework 中公開。 每個應用程式都可以存取兩個資料庫:公用資料庫和私用資料庫。

容器是 CloudKit 的初始進入點。 下列程式代碼可用來從應用程式的預設容器存取公用和私人資料庫:

using CloudKit;
//...

public CKDatabase PublicDatabase { get; set; }
public CKDatabase PrivateDatabase { get; set; }
//...

// Get the default public and private databases for
// the application
PublicDatabase = CKContainer.DefaultContainer.PublicCloudDatabase;
PrivateDatabase = CKContainer.DefaultContainer.PrivateCloudDatabase;

以下是資料庫類型之間的差異:

公用資料庫 Private Database
資料類型 共用資料 目前用戶的數據
配額 在開發人員配額中考慮 在使用者的配額中考慮
默認許可權 世界可讀取 用戶可讀取
編輯許可權 透過記錄類別層級的 iCloud 儀錶板角色 N/A

記錄

容器會保存資料庫,而資料庫內部是記錄。 記錄是結構化數據從 CloudKit 來回移動的機制:

Containers hold databases, and inside databases are records

記錄會透過 CKRecord 類別在 CloudKit Framework 中公開,以包裝索引鍵/值組。 應用程式中物件的實體相當於 CKRecord CloudKit 中的 。 此外,每個都有 CKRecord 一個記錄類型,這相當於 對象的類別。

記錄具有 Just-In-Time 架構,因此數據會先描述給 CloudKit,再交出進行處理。 此時,CloudKit 會解譯資訊,並處理儲存和擷取記錄的物流。

類別 CKRecord 也支援各種不同的元數據。 例如,記錄包含建立時的相關信息,以及建立它的使用者。 記錄也包含上次修改的時間和修改它的使用者相關信息。

記錄包含變更標籤的概念。 這是指定記錄修訂的舊版。 變更標籤是用來判斷客戶端和伺服器是否具有相同版本的指定記錄的輕量方式。

如上所述, CKRecords 包裝機碼/值組,因此,下列數據類型可以儲存在記錄中:

  1. NSString
  2. NSNumber
  3. NSData
  4. NSDate
  5. CLLocation
  6. CKReferences
  7. CKAssets

除了單一實值型別之外,記錄還可以包含上述任何所列類型的同質陣列。

下列程式代碼可用來建立新的記錄,並將其儲存在資料庫中:

using CloudKit;
//...

private const string ReferenceItemRecordName = "ReferenceItems";
//...

var newRecord = new CKRecord (ReferenceItemRecordName);
newRecord ["name"] = (NSString)nameTextField.Text;
await CloudManager.SaveAsync (newRecord);

記錄區域

記錄本身不存在於指定的資料庫內– 記錄群組會一起存在於記錄區域內。 記錄區域可以視為傳統關係資料庫中的數據表:

Groups of records exist together inside a Record Zone

指定記錄區域內可以有多個記錄,以及指定資料庫中的多個記錄區域。 每個資料庫都包含預設記錄區域:

Every database contains a Default Record Zone and Custom Zone

這是預設會儲存記錄的位置。 此外,也可以建立自定義記錄區域。 記錄區域代表完成不可部分完成認可和 變更追蹤 的基本粒度。

記錄標識碼

記錄標識符會以 Tuple 表示,其中包含用戶端提供的記錄名稱和記錄所在的區域。 記錄識別碼具有下列特性:

  • 它們是由用戶端應用程式所建立。
  • 它們會完全正規化,並代表記錄的特定位置。
  • 藉由將外部資料庫中記錄的唯一標識符指派給記錄名稱,即可用來橋接未儲存在 CloudKit 內的本機資料庫。

當開發人員建立新記錄時,他們可以選擇傳入記錄標識符。 如果未指定記錄標識碼,系統會自動建立 UUID 並指派給記錄。

當開發人員建立新的記錄標識元時,他們可以選擇指定每個記錄所屬的記錄區域。 如果未指定任何專案,則會使用預設記錄區域。

記錄標識符會透過 CKRecordID 類別在 CloudKit Framework 中公開。 下列程式代碼可用來建立新的記錄識別碼:

var recordID =  new CKRecordID("My Record");

參考資料

參考提供指定資料庫內相關記錄之間的關聯性:

References provide relationships between related Records within a given Database

在上述範例中,Parents 擁有 Children,讓 Child 是父記錄的子記錄。 Relationship 會從子記錄移至父記錄,並稱為「上一個 參考」

參考會透過 CKReference 類別在 CloudKit Framework 中公開。 它們是讓 iCloud 伺服器了解記錄之間關聯性的一種方式。

參考提供串聯刪除背後的機制。 如果從資料庫刪除父記錄,任何子記錄(如 Relationship 中所指定)也會自動從資料庫刪除。

注意

使用 CloudKit 時,懸空指標是可能的。 例如,當應用程式擷取記錄指標清單、選取記錄,然後要求記錄時,該記錄可能已不存在於資料庫中。 應用程式必須撰寫程式代碼,才能正常處理這種情況。

雖然不需要,但使用 CloudKit Framework 時,偏好使用 Back References。 蘋果已經微調了系統,使這種最有效率的參考類型。

建立參考時,開發人員可以提供已在記憶體中的記錄,或建立記錄標識碼的參考。 如果使用記錄標識碼,且指定的參考不存在於資料庫中,則會建立懸空指標。

以下是針對已知記錄建立參考的範例:

var reference = new CKReference(newRecord, new CKReferenceAction());

資產

資產允許將大型非結構化數據的檔案上傳至 iCloud,並與指定的記錄相關聯:

Assets allow for a file of large, unstructured data to be uploaded to iCloud and associated with a given Record

在用戶端上, CKRecord 會建立 描述要上傳至 iCloud 伺服器的檔案。 CKAsset會建立 ,以包含檔案,並連結到描述它的記錄。

當檔案上傳至伺服器時,記錄會放在資料庫中,並將檔案複製到特殊的大量 儲存體 資料庫。 記錄指標與上傳的檔案之間會建立連結。

資產會透過 CKAsset 類別公開在 CloudKit Framework 中,並用來儲存大型非結構化數據。 因為開發人員永遠不想在記憶體中擁有大型非結構化數據,所以資產是使用磁碟上的檔案來實作。

資產是由記錄所擁有,允許使用記錄作為指標從iCloud擷取資產。 如此一來,當擁有資產的記錄被刪除時,伺服器就可以垃圾收集資產。

因為 CKAssets 是用來處理大型數據檔,因此 Apple 設計了 CloudKit,以有效率地上傳和下載資產。

下列程式代碼可用來建立資產,並將它與記錄產生關聯:

var fileUrl = new NSUrl("LargeFile.mov");
var asset = new CKAsset(fileUrl);
newRecord ["name"] = asset;

我們現在已涵蓋 CloudKit 內的所有基本物件。 容器會與應用程式相關聯,並包含資料庫。 資料庫包含分組為記錄區域的記錄,並由記錄標識元指向。 使用 References 在記錄之間定義父子關聯性。 最後,大型檔案可以使用資產上傳並關聯至記錄。

CloudKit 便利 API

Apple 提供兩個不同的 API 集合來使用 CloudKit:

  • 作業 API – 提供 CloudKit 的每個功能。 針對更複雜的應用程式,此 API 提供對 CloudKit 的精細控制。
  • 便利 API – 提供一般預先設定的 CloudKit 功能子集。 它提供方便且容易存取的解決方案,讓您在iOS應用程式中包含CloudKit功能。

方便 API 通常是大多數 iOS 應用程式的最佳選擇,Apple 建議從它開始。 本節的其餘部分將討論下列便利 API 主題:

  • 儲存記錄。
  • 擷取記錄。
  • 更新記錄。

常見的安裝程序代碼

開始使用 CloudKit 便利 API 之前,需要一些標準設定程式碼。 從修改應用程式的 AppDelegate.cs 檔案開始,使其看起來如下:

using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using UIKit;
using CloudKit;

namespace CloudKitAtlas
{
    [Register ("AppDelegate")]
    public partial class AppDelegate : UIApplicationDelegate
    {
        public override UIWindow Window { get; set;}
        public CKDatabase PublicDatabase { get; set; }
        public CKDatabase PrivateDatabase { get; set; }

        public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
        {
            application.RegisterForRemoteNotifications ();

            // Get the default public and private databases for
            // the application
            PublicDatabase = CKContainer.DefaultContainer.PublicCloudDatabase;
            PrivateDatabase = CKContainer.DefaultContainer.PrivateCloudDatabase;

            return true;
        }

        public override void RegisteredForRemoteNotifications (UIApplication application, NSData deviceToken)
        {
            Console.WriteLine ("Registered for Push notifications with token: {0}", deviceToken);
        }

        public override void FailedToRegisterForRemoteNotifications (UIApplication application, NSError error)
        {
            Console.WriteLine ("Push subscription failed");
        }

        public override void ReceivedRemoteNotification (UIApplication application, NSDictionary userInfo)
        {
            Console.WriteLine ("Push received");
        }
    }
}

上述程式代碼會將公用和私人 CloudKit 資料庫公開為快捷方式,使其更容易在應用程式的其餘部分使用。

接下來,將下列程式代碼新增至將使用 CloudKit 的任何檢視或檢視容器:

using CloudKit;
//...

public AppDelegate ThisApp {
    get { return (AppDelegate)UIApplication.SharedApplication.Delegate; }
}

這會新增快捷方式, AppDelegate 以取得 ,並存取上面建立的公用和私人資料庫快捷方式。

在此程式代碼就緒后,讓我們來看看在 Xamarin iOS 8 應用程式中實作 CloudKit 便利 API。

儲存記錄

在討論記錄時,使用上述模式,下列程式代碼會建立新的記錄,並使用便利 API 將它儲存至公用資料庫:

private const string ReferenceItemRecordName = "ReferenceItems";
...

// Create a new record
var newRecord = new CKRecord (ReferenceItemRecordName);
newRecord ["name"] = (NSString)nameTextField.Text;

// Save it to the database
ThisApp.PublicDatabase.SaveRecord(newRecord, (record, err) => {
    // Was there an error?
    if (err != null) {
        ...
    }
});

上述程式代碼需要注意的三件事:

  1. 藉由呼叫 SaveRecordPublicDatabase方法,開發人員不需要指定數據的傳送方式、寫入的區域等等。便利 API 會負責所有這些詳細數據本身。
  2. 呼叫是異步的,而且會在呼叫完成時提供回呼例程,無論成功還是失敗。 如果呼叫失敗,則會提供錯誤訊息。
  3. CloudKit 不提供本機記憶體/持續性;它只是傳輸媒體。 因此,當要求儲存記錄時,它會立即傳送至 iCloud 伺服器。

注意

由於行動網路通訊的「遺失」性質,因此當使用 CloudKit 時,開發人員在處理 CloudKit 時必須進行的第一個考慮是錯誤處理,而聯機會持續中斷或中斷。

擷取記錄

在 iCloud 伺服器上建立並成功儲存 Record 之後,請使用下列程式代碼來擷取記錄:

// Create a record ID and fetch the record from the database
var recordID = new CKRecordID("MyRecordName");
ThisApp.PublicDatabase.FetchRecord(recordID, (record, err) => {
    // Was there an error?
    if (err != null) {
        ...
    }
});

就像儲存記錄一樣,上述程式代碼是異步、簡單且需要絕佳的錯誤處理。

更新記錄

從 iCloud 伺服器擷取 Record 之後,您可以使用下列程式代碼來修改 Record,並將變更儲存回資料庫:

// Create a record ID and fetch the record from the database
var recordID = new CKRecordID("MyRecordName");
ThisApp.PublicDatabase.FetchRecord(recordID, (record, err) => {
    // Was there an error?
    if (err != null) {

    } else {
        // Modify the record
        record["name"] = (NSString)"New Name";

        // Save changes to database
        ThisApp.PublicDatabase.SaveRecord(record, (r, e) => {
            // Was there an error?
            if (e != null) {
                 ...
            }
        });
    }
});

如果呼叫成功,則 FetchRecordPublicDatabase 方法會傳回 CKRecord 。 然後,應用程式會修改 Record 並再次呼叫 SaveRecord ,以將變更寫回資料庫。

本節顯示使用 CloudKit 便利 API 時,應用程式將使用的一般迴圈。 應用程式會將記錄儲存至 iCloud、從 iCloud 擷取這些記錄、修改記錄,並將這些變更儲存回 iCloud。

設計延展性

到目前為止,本文已探討從 iCloud 伺服器儲存和擷取應用程式的整個物件模型,每次使用時。 雖然這種方法適用於少量的數據和非常小的使用者群,但當資訊和/或使用者基底增加時,其規模不會良好。

巨量數據,小型裝置

應用程式越受歡迎,資料庫中的數據越多,在裝置上擁有該整個數據的快取越不可行。 下列技術可用來解決此問題:

  • 將大型數據保留在雲端 – CloudKit 的設計目的是要有效率地處理大型數據。
  • 客戶端應該只檢視該資料的 配量 – 降低在指定時間處理任何工作所需的最少數據。
  • 客戶端檢視可以變更 – 因為每個使用者有不同的喜好設定,所顯示數據的配量可能會從使用者變更為使用者,而使用者的任何指定配量個別檢視可能會不同。
  • 用戶端會使用查詢來聚焦觀點 – 查詢可讓用戶檢視存在於雲端內較大數據集的一小部分。

查詢

如上所述,查詢可讓開發人員選取雲端中較大數據集的一小部分。 查詢會透過 CKQuery 類別在 CloudKit Framework 中公開。

查詢結合了三個不同的項目:記錄類型( RecordType)、述詞( NSPredicate)以及選擇性的排序描述元( NSSortDescriptors)。 CloudKit 支援大部分 NSPredicate

支援的述詞

使用查詢時,CloudKit 支援下列型態的 NSPredicates

  1. 比對名稱等於變數中所儲存值的記錄:

    NSPredicate.FromFormat(string.Format("name = '{0}'", recordName))
    
  2. 允許根據動態索引鍵值進行比對,讓金鑰不必在編譯時期知道:

    NSPredicate.FromFormat(string.Format("{0} = '{1}'", key, value))
    
  3. 比對記錄值大於指定值的記錄:

    NSPredicate.FromFormat(string.Format("start > {0}", (NSDate)date))
    
  4. 比對記錄位置在指定位置 100 公尺內的記錄:

    var location = new CLLocation(37.783,-122.404);
    var predicate = NSPredicate.FromFormat(string.Format("distanceToLocation:fromLocation(Location,{0}) < 100", location));
    
  5. CloudKit 支援令牌化搜尋。 此呼叫會建立兩個令牌,一個用於 after ,另一個用於 session。 它會傳回包含這兩個令牌的 Record:

    NSPredicate.FromFormat(string.Format("ALL tokenize({0}, 'Cdl') IN allTokens", "after session"))
    
  6. CloudKit 支援使用 AND 運算符聯結的複合述詞。

    NSPredicate.FromFormat(string.Format("start > {0} AND name = '{1}'", (NSDate)date, recordName))
    

建立查詢

下列程式代碼可用來在 Xamarin iOS 8 應用程式中建立 CKQuery

var recordName = "MyRec";
var predicate = NSPredicate.FromFormat(string.Format("name = '{0}'", recordName));
var query = new CKQuery("CloudRecords", predicate);

首先,它會建立述詞,只選取符合指定名稱的記錄。 然後,它會建立查詢,以選取符合述詞之指定之記錄類型的記錄。

執行查詢

建立查詢之後,請使用下列程式代碼來執行查詢並處理傳回的記錄:

var recordName = "MyRec";
var predicate = NSPredicate.FromFormat(string.Format("name = {0}", recordName));
var query = new CKQuery("CloudRecords", predicate);

ThisApp.PublicDatabase.PerformQuery(query, CKRecordZone.DefaultRecordZone().ZoneId, (NSArray results, NSError err) => {
    // Was there an error?
    if (err != null) {
       ...
    } else {
        // Process the returned records
        for(nint i = 0; i < results.Count; ++i) {
            var record = (CKRecord)results[i];
        }
    }
});

上述程式代碼會採用上述建立的查詢,並針對公用資料庫執行它。 由於未指定任何記錄區域,因此會搜尋所有區域。 如果未發生任何錯誤,則會傳回 符合查詢參數的陣列 CKRecords

思考查詢的方式是,它們是輪詢,而且很擅長切割大型數據集。 不過,查詢不適合大型、大部分是靜態數據集,原因如下:

  • 它們對裝置電池使用時間不好。
  • 它們對網路流量而言很糟糕。
  • 由於他們看到的資訊受限於應用程式輪詢資料庫的頻率,所以對用戶體驗而言很糟糕。 使用者目前預期會在變更時收到推播通知。

訂用帳戶

處理大型、大部分是靜態數據集時,查詢不應該在用戶端裝置上執行,它應該代表用戶端在伺服器上執行。 查詢應該在背景執行,而且應該在每個單一記錄儲存之後執行,無論是由目前裝置還是觸碰相同資料庫的另一個裝置。

最後,執行伺服器端查詢時,應該將推播通知傳送至連結至資料庫的每個裝置。

訂用帳戶會透過 CKSubscription 類別在 CloudKit Framework 中公開。 它們結合了記錄類型( RecordType)、述詞( NSPredicate)和蘋果推播通知( Push)。

注意

CloudKit 推送會稍微增強,因為它們包含包含 CloudKit 特定資訊的承載,例如導致推送發生的原因。

訂用帳戶的運作方式

在 C# 程式代碼中實作訂用帳戶之前,讓我們快速概觀訂用帳戶的運作方式:

An overview of how subscriptions work

上圖顯示典型的訂用帳戶程式,如下所示:

  1. 用戶端裝置會建立新的訂用帳戶,其中包含將觸發訂閱的一組條件,以及觸發程式發生時將傳送的推播通知。
  2. 訂用帳戶會傳送至資料庫,而資料庫會新增至現有訂用帳戶的集合。
  3. 第二個裝置會建立新的 Record,並將該記錄儲存至資料庫。
  4. 資料庫會搜尋其訂用帳戶清單,以查看新記錄是否符合其任何條件。
  5. 如果找到相符專案,推播通知會傳送至註冊訂用帳戶的裝置,其中包含導致觸發訂閱的 Record 相關信息。

有了這項知識,讓我們來看看在 Xamarin iOS 8 應用程式中建立訂閱。

建立訂用帳戶

下列程式代碼可用來建立訂用帳戶:

// Create a new subscription
DateTime date;
var predicate = NSPredicate.FromFormat(string.Format("start > {0}", (NSDate)date));
var subscription = new CKSubscription("RecordType", predicate, CKSubscriptionOptions.FiresOnRecordCreation);

// Describe the type of notification
var notificationInfo = new CKNotificationInfo();
notificationInfo.AlertLocalizationKey = "LOCAL_NOTIFICATION_KEY";
notificationInfo.SoundName = "ping.aiff";
notificationInfo.ShouldBadge = true;

// Attach the notification info to the subscription
subscription.NotificationInfo = notificationInfo;

首先,它會建立述詞,以提供觸發訂閱的條件。 接下來,它會針對特定的 Record Type 建立訂用帳戶,並在測試觸發程式時設定 的 選項。 最後,它會定義觸發訂閱並附加訂用帳戶時所發生的通知類型。

儲存訂用帳戶

建立訂用帳戶之後,下列程式代碼會將它儲存至資料庫:

// Save the subscription to the database
ThisApp.PublicDatabase.SaveSubscription(subscription, (s, err) => {
    // Was there an error?
    if (err != null) {

    }
});

使用便利 API 時,呼叫是異步、簡單,並提供簡單的錯誤處理。

處理推播通知

如果開發人員先前已使用Apple推播通知 (APS),則處理CloudKit所產生的通知的程式應該很熟悉。

在 中 AppDelegate.cs,覆寫 ReceivedRemoteNotification 類別,如下所示:

public override void ReceivedRemoteNotification (UIApplication application, NSDictionary userInfo)
{
    // Parse the notification into a CloudKit Notification
    var notification = CKNotification.FromRemoteNotificationDictionary (userInfo);

    // Get the body of the message
    var alertBody = notification.AlertBody;

    // Was this a query?
    if (notification.NotificationType == CKNotificationType.Query) {
        // Yes, convert to a query notification and get the record ID
        var query = notification as CKQueryNotification;
        var recordID = query.RecordId;
    }
}

上述程式代碼會要求 CloudKit 將 userInfo 剖析為 CloudKit 通知。 接下來,會擷取警示的相關信息。 最後,會測試通知的類型,並據以處理通知。

本節示範如何使用查詢和訂用帳戶來回答上述巨量數據、小型裝置問題。 應用程式會將其大型數據保留在雲端中,並使用這些技術來提供此數據集的檢視。

CloudKit 用戶帳戶

如本文開頭所述,CloudKit 是以現有的 iCloud 基礎結構為基礎所建置。 下一節將詳細說明如何使用 CloudKit API 向開發人員公開帳戶。

驗證

處理使用者帳戶時,第一個考慮是驗證。 CloudKit 支援透過裝置上目前登入的 iCloud 使用者進行驗證。 驗證會在幕後進行,並由iOS處理。 如此一來,開發人員就不必擔心實作驗證的詳細數據。 他們只會測試使用者是否已登入。

用戶帳戶資訊

CloudKit 提供下列使用者資訊給開發人員:

  • 身分 識別 – 唯一識別使用者的方式。
  • 元數據 – 儲存和擷取使用者相關信息的能力。
  • 隱私權 – 所有信息都會在有隱私權 意識的莊園中處理。 除非使用者已同意,否則不會公開任何內容。
  • 探索 – 讓用戶能夠探索使用相同應用程式的朋友。

接下來,我們將詳細探討這些主題。

身分識別

如上所述,CloudKit 提供一種方式讓應用程式唯一識別指定的使用者:

Uniquely identifing a given user

在使用者的裝置和 CloudKit 容器內的所有特定使用者私人資料庫上執行用戶端應用程式。 用戶端應用程式將會連結到其中一個特定使用者。 這是以裝置本機登入 iCloud 的用戶為基礎。

由於這是來自 iCloud,因此有豐富的使用者資訊支援存放區。 而且,因為 iCloud 實際上是裝載容器,所以它可以讓使用者相互關聯。 在上圖中,iCloud 帳戶 user@icloud.com 連結至目前客戶端的使用者。

根據容器建立唯一且隨機產生的使用者標識符,並與使用者的 iCloud 帳戶相關聯(電子郵件位址)。 此使用者標識碼會傳回給應用程式,而且可以用開發人員認為適合的任何方式使用。

注意

針對相同 iCloud 使用者在同一個裝置上執行的不同應用程式將會有不同的使用者標識碼,因為它們會連線到不同的 CloudKit 容器。

下列程式代碼會取得裝置上目前登入 iCloud 使用者的 CloudKit 使用者識別碼:

public CKRecordID UserID { get; set; }
...

// Get the CloudKit User ID
CKContainer.DefaultContainer.FetchUserRecordId ((recordID, err) => {
    // Was there an error?
    if (err!=null) {
        Console.WriteLine("Error: {0}", err.LocalizedDescription);
    } else {
        // Save user ID
        UserID = recordID;
    }
});

上述程式代碼要求 CloudKit 容器提供目前登入使用者的識別碼。 由於這項資訊來自 iCloud Server,因此呼叫是異步的,而且需要錯誤處理。

中繼資料

CloudKit 中的每個使用者都有描述它們的特定元數據。 此元數據會以 CloudKit 記錄表示:

Each user in CloudKit has specific Metadata that describes them

在私人資料庫中查看容器的特定使用者,有一個記錄會定義該使用者。 公用資料庫中有許多用戶記錄,每個容器的使用者都有一筆。 其中一個記錄標識碼會符合目前登入用戶的記錄標識碼。

公用資料庫中的用戶記錄是世界可讀取的。 大部分情況下,它們會被視為一般記錄,而且有一種類型 CKRecordTypeUserRecord。 系統會保留這些記錄,不適用於查詢。

使用下列程式代碼來存取使用者記錄:

public CKRecord UserRecord { get; set; }
...

// Get the user's record
PublicDatabase.FetchRecord(UserID, (record ,er) => {
    //was there an error?
    if (er != null) {
        Console.WriteLine("Error: {0}", er.LocalizedDescription);
    } else {
        // Save the user record
        UserRecord = record;
    }
});

上述程式代碼會要求公用資料庫傳回我們上面所存取標識碼的用戶用戶記錄。 由於這項資訊來自 iCloud Server,因此呼叫是異步的,而且需要錯誤處理。

隱私權

根據預設,CloudKit 的設計是保護目前登入用戶的隱私權。 根據預設,不會公開使用者的個人識別資訊。 在某些情況下,應用程式需要有關使用者的資訊有限。

在這些情況下,應用程式可以要求使用者揭露這項資訊。 系統會向使用者顯示對話方塊,要求他們加入加入以公開其帳戶資訊。

探索

假設使用者加入加入以允許應用程式有限存取其用戶帳戶資訊,就可以探索到應用程式的其他使用者:

A user can be discoverable to other users of the application

用戶端應用程式正在與容器交談,而容器正在交談 iCloud 以存取使用者資訊。 使用者可以提供電子郵件位址,並使用 Discovery 來傳回使用者的相關信息。 您也可以選擇使用使用者識別碼來探索使用者的相關信息。

CloudKit 也提供一種方式,藉由查詢整個通訊簿,以探索任何可能為目前登入 iCloud 使用者之朋友的使用者相關信息。 CloudKit Process 會提取使用者的聯繫人簿,並使用電子郵件位址來查看是否可以找到符合這些位址的應用程式其他使用者。

這可讓應用程式利用使用者的聯繫人簿,而不需提供其存取權,或要求使用者核准聯繫人的存取權。 應用程式目前沒有任何連絡資訊可供使用,只有 CloudKit Process 可以存取。

若要回顧,有三種不同的輸入可供使用者探索使用:

  • 使用者記錄識別碼 – 您可以針對目前登入 CloudKit 使用者的使用者識別碼來完成探索。
  • 使用者電子郵件位址 – 使用者可以提供電子郵件位址,並可用於探索。
  • 聯繫人錄 – 使用者的通訊簿可用來探索應用程式的使用者,其電子郵件地址與聯繫人中所列的電子郵件位址相同。

使用者探索會傳回下列資訊:

  • 用戶記錄識別碼 - 公用資料庫中使用者的唯一標識碼。
  • 名字和姓氏 - 儲存在公用資料庫中。

此資訊只會針對已選擇加入探索的用戶傳回。

下列程式代碼會探索裝置上目前登入 iCloud 的使用者相關信息:

public CKDiscoveredUserInfo UserInfo { get; set; }
//...

// Get the user's metadata
CKContainer.DefaultContainer.DiscoverUserInfo(UserID, (info, e) => {
    // Was there an error?
    if (e != null) {
        Console.WriteLine("Error: {0}", e.LocalizedDescription);
    } else {
        // Save the user info
        UserInfo = info;
    }
});

使用下列程式代碼來查詢聯絡人簿中的所有使用者:

// Ask CloudKit for all of the user's friends information
CKContainer.DefaultContainer.DiscoverAllContactUserInfos((info, er) => {
    // Was there an error
    if (er != null) {
        Console.WriteLine("Error: {0}", er.LocalizedDescription);
    } else {
        // Process all returned records
        for(int i = 0; i < info.Count(); ++i) {
            // Grab a user
            var userInfo = info[i];
        }
    }
});

在本節中,我們已討論 CloudKit 可以提供給應用程式的用戶帳戶存取權的四個主要領域。 從取得使用者的身分識別和元數據,到 CloudKit 內建的隱私策略,最後,探索應用程式的其他使用者的能力。

開發和生產環境

CloudKit 為應用程式的記錄類型和數據提供個別的開發與生產環境。 開發環境是一個更具彈性的環境,僅適用於開發小組的成員。 當應用程式將新的欄位新增至記錄,並將該記錄儲存在開發環境中時,伺服器會自動更新架構資訊。

開發人員可以使用此功能在開發期間變更架構,以節省時間。 其中一個注意事項是,在欄位新增至記錄之後,無法以程式設計方式變更與該欄位相關聯的數據類型。 若要變更欄位的類型,開發人員必須刪除 CloudKit 儀錶板中的欄位,並再次新增新的類型。

在部署應用程式之前,開發人員可以使用 CloudKit 儀錶板將其架構和數據遷移至生產環境。 針對生產環境執行時,伺服器會防止應用程式以程式設計方式變更架構。 開發人員仍然可以使用 CloudKit 儀錶板 進行變更,但嘗試將欄位新增至生產環境中的記錄會導致錯誤。

注意

iOS 模擬器僅適用於 開發環境。 當開發人員準備好在 生產環境中測試應用程式時,需要實體 iOS 裝置。

運送已啟用 CloudKit 的應用程式

在傳送使用 CloudKit 的應用程式之前,必須先將它設定為以 Production CloudKit Environment 為目標,否則 Apple 將會拒絕應用程式。

執行下列操作:

  1. 在 Visual Studio for Ma 中,編譯發行> iOS 裝置的應用程式:

    Compile the application for Release

  2. 從 [ 建置] 功能表中,選取 [ 封存]:

    Select Archive

  3. 將會建立並顯示在 Visual Studio for Mac 中:

    The Archive will be created and displayed

  4. 啟動 Xcode

  5. 從 [ 視窗] 選單中,選取 [召集人]:

    Select Organizer

  6. 選取應用程式的封存,然後按下 [ 匯出...] 按鈕:

    The application's archive

  7. 選取匯出的方法,然後按下一 步[ 下一步] 按鈕:

    Select a method for export

  8. 從下拉式清單中選取開發小組,然後按兩下 [選擇] 按鈕:

    Select the Development Team from the dropdown list

  9. 從下拉式清單中選取 [生產] ,然後按下一 步[ 下一步] 按鈕:

    Select Production from the dropdown list

  10. 檢閱設定,然後按兩下 [ 匯出] 按鈕:

    Review the setting

  11. 選擇位置以產生產生的應用程式 .ipa 檔。

此程式與直接將應用程式提交至 iTunes 連線 類似,只要按兩下 [提交...] 按鈕,而不是 [匯出...]。在 [召集人] 視窗中選取 [封存] 之後。

使用 CloudKit 的時機

如本文所見,CloudKit 提供簡單的方法,讓應用程式從 iCloud 伺服器儲存和擷取資訊。 也就是說,CloudKit 不會過時或取代任何現有的工具或架構。

使用案例

下列使用案例應協助開發人員決定何時使用特定的 iCloud 架構或技術:

  • iCloud Key-Value Store – 以異步方式保持少量數據最新狀態,非常適合使用應用程式喜好設定。 不過,它受限於非常少量的資訊。
  • iCloud 磁碟驅動器 – 建置在現有的 iCloud 檔 API 之上,並提供簡單的 API,從文件系統同步非結構化數據。 它在 Mac OS X 上提供完整的離線快取,非常適合以檔為中心的應用程式。
  • iCloud Core 資料 – 允許在所有使用者裝置之間復寫數據。 數據是單一使用者,非常適合讓私人結構化數據保持同步。
  • CloudKit – 提供結構和大量公用數據,而且能夠同時處理大型數據集和大型非結構化檔案。 其會系結至使用者的 iCloud 帳戶,並提供客戶端導向數據傳輸。

請記住這些使用案例,開發人員應該挑選正確的 iCloud 技術,以提供目前所需的應用程式功能,並為未來的成長提供良好的延展性。

摘要

本文涵蓋 CloudKit API 的快速簡介。 它已示範如何布建及設定 Xamarin iOS 應用程式以使用 CloudKit。 它涵蓋 CloudKit 便利 API 的功能。 它示範如何使用查詢和訂用帳戶設計已啟用 CloudKit 的應用程式,以取得延展性。 最後,它已顯示 CloudKit 向應用程式公開的用戶帳戶資訊。