xamarin.iOS ile iCloud kullanma
iOS 5'teki iCloud depolama API'si, uygulamaların kullanıcı belgelerini ve uygulamaya özgü verileri merkezi bir konuma kaydetmesine ve bu öğelere kullanıcının tüm cihazlarından erişmesine olanak tanır.
Dört tür depolama alanı vardır:
Anahtar-Değer depolaması - kullanıcının diğer cihazlarında uygulamanızla küçük miktarlarda veri paylaşmak için.
UIDocument depolama - UIDocument'ın alt sınıfını kullanarak belgeleri ve diğer verileri kullanıcının iCloud hesabında depolamak için.
CoreData - SQLite veritabanı depolama alanı.
Tek tek dosyalar ve dizinler - çok sayıda farklı dosyayı doğrudan dosya sisteminde yönetmek için.
Bu belgede ilk iki tür (Anahtar-Değer çiftleri ve UIDocument alt sınıfları) ve Xamarin.iOS'ta bu özelliklerin nasıl kullanılacağı açıklanır.
Önemli
Gereksinimler
- Xamarin.iOS'un en son kararlı sürümü
- Xcode 10
- Mac için Visual Studio veya Visual Studio 2019.
iCloud geliştirmeye hazırlanma
Uygulamalar hem Apple Sağlama Portalı'nda hem de projenin kendisinde iCloud kullanacak şekilde yapılandırılmalıdır. iCloud için geliştirmeden önce (veya örnekleri denemeden) önce aşağıdaki adımları izleyin.
Bir uygulamayı iCloud'a erişecek şekilde doğru yapılandırmak için:
TeamID'nizi bulun - developer.apple.com oturum açın ve Ekip Kimliğinizi (veya tek geliştiriciler için Bireysel Kimliği) almak için Üye Merkezi > Hesabınız > Geliştirici Hesabı Özeti'ni ziyaret edin. 10 karakterlik bir dize ( örneğin A93A5CM278 ) olacaktır. Bu, "kapsayıcı tanımlayıcısının" bir parçasını oluşturur.
Yeni uygulama kimliği oluşturma - Uygulama kimliği oluşturmak için Cihaz Sağlama kılavuzunun Mağaza Teknolojileri için Sağlama bölümünde açıklanan adımları izleyin ve iCloud'u izin verilen bir hizmet olarak denetlemeyi unutmayın:
Yeni sağlama profili oluşturma - Sağlama Profili oluşturmak için Cihaz Sağlama kılavuzunda özetlenen adımları izleyin.
Kapsayıcı Tanımlayıcısı'nı Entitlements.plist'e ekleyin; kapsayıcı tanımlayıcı biçimi şeklindedir
TeamID.BundleID
. Daha fazla bilgi için Yetkilendirmelerle çalışma kılavuzuna bakın.Proje özelliklerini yapılandırma - Info.plist dosyasında, Uygulama Kimliği oluştururken Paket Tanımlayıcısının Paket Kimliği kümesiyle eşleştiğinden emin olun; iOS Paket İmzalama, iCloud App Service ve Özel Yetkilendirmeler dosyasının seçili olduğu bir Uygulama Kimliği içeren bir Sağlama Profili kullanır. Bunların tümü Proje Özellikleri bölmesinin altındaki Visual Studio'da yapılabilir.
Cihazınızda iCloud'un etkinleştirilmesi - Ayarlar > iCloud'a gidin ve cihazın oturum açtığından emin olun. Belgeler ve Veriler seçeneğini belirleyin ve açın.
iCloud'ı test etmek için bir cihaz kullanmanız gerekir- Simülatör'de çalışmaz. Aslında, iCloud'u çalışır durumda görmek için hepsi aynı Apple kimliğiyle oturum açmış iki veya daha fazla cihaza ihtiyacınız vardır.
Anahtar-Değer Depolama
Anahtar-değer depolama, bir kullanıcının kitap veya dergide görüntülediği son sayfa gibi cihazlarda kalıcı hale geldiğini düşünebileceği az miktarda veriye yöneliktir. Anahtar-değer depolama, verileri yedeklemek için kullanılmamalıdır.
Anahtar-değer depolama kullanılırken dikkat edilmesi gereken bazı sınırlamalar vardır:
En büyük anahtar boyutu - Anahtar adları 64 bayttan uzun olamaz.
En büyük değer boyutu - Tek bir değerde 64 kilobayttan fazla depolayamazsınız.
Bir uygulama için en büyük anahtar-değer deposu boyutu - Uygulamalar toplamda yalnızca 64 kilobayt kadar anahtar-değer verisi depolayabilir. Bu sınırı aşan anahtarları ayarlama denemeleri başarısız olur ve önceki değer kalıcı olur.
Veri türleri - Yalnızca dizeler, sayılar ve boole'lar gibi temel türler depolanabilir.
iCloudKeyValue örneği nasıl çalıştığını gösterir. Örnek kod, her cihaz için adlı bir anahtar oluşturur: Bu anahtarı bir cihazda ayarlayabilir ve değerin başkalarına yayılmasını izleyebilirsiniz. Ayrıca, herhangi bir cihazda düzenlenebilen "Paylaşılan" adlı bir anahtar da oluşturur - aynı anda birçok cihazda düzenleme yaparsanız, iCloud hangi değerin "kazanacağını" (değişiklikte bir zaman damgası kullanarak) karar verir ve yayılır.
Bu ekran görüntüsü kullanımdaki örneği gösterir. iCloud'dan değişiklik bildirimleri alındığında, bunlar ekranın en altındaki kaydırma metin görünümünde yazdırılır ve giriş alanlarında güncelleştirilir.
Verileri ayarlama ve alma
Bu kod, bir dize değerinin nasıl ayarlandığını gösterir.
var store = NSUbiquitousKeyValueStore.DefaultStore;
store.SetString("testkey", "VALUE IN THE CLOUD"); // key and value
store.Synchronize();
Eşitleme çağrısı değerin yalnızca yerel disk depolamada kalıcı olmasını sağlar. iCloud'a eşitleme arka planda gerçekleşir ve uygulama kodu tarafından "zorlanamaz". İyi ağ bağlantısı ile eşitleme genellikle 5 saniye içinde gerçekleşir, ancak ağ zayıfsa (veya bağlantısı kesilirse) bir güncelleştirme çok daha uzun sürebilir.
Bu kodla bir değer alabilirsiniz:
var store = NSUbiquitousKeyValueStore.DefaultStore;
display.Text = store.GetString("testkey");
Değer yerel veri deposundan alınır - bu yöntem "en son" değeri almak için iCloud sunucularına başvurmaya çalışmaz. iCloud, yerel veri deposunu kendi zamanlamasına göre güncelleştirir.
Veri silme
Anahtar-değer çiftini tamamen kaldırmak için Aşağıdaki gibi Remove yöntemini kullanın:
var store = NSUbiquitousKeyValueStore.DefaultStore;
store.Remove("testkey");
store.Synchronize();
Değişiklikleri Gözlemleme
Bir uygulama, değerleri iCloud tarafından değiştirildiğinde de öğesine bir gözlemci NSNotificationCenter.DefaultCenter
ekleyerek bildirim alabilir.
KeyValueViewController.cs ViewWillAppear
yönteminden alınan aşağıdaki kod, bu bildirimleri dinlemeyi ve hangi anahtarların değiştirildiğinin listesini oluşturmayı gösterir:
keyValueNotification =
NSNotificationCenter.DefaultCenter.AddObserver (
NSUbiquitousKeyValueStore.DidChangeExternallyNotification, notification => {
Console.WriteLine ("Cloud notification received");
NSDictionary userInfo = notification.UserInfo;
var reasonNumber = (NSNumber)userInfo.ObjectForKey (NSUbiquitousKeyValueStore.ChangeReasonKey);
nint reason = reasonNumber.NIntValue;
var changedKeys = (NSArray)userInfo.ObjectForKey (NSUbiquitousKeyValueStore.ChangedKeysKey);
var changedKeysList = new List<string> ();
for (uint i = 0; i < changedKeys.Count; i++) {
var key = changedKeys.GetItem<NSString> (i); // resolve key to a string
changedKeysList.Add (key);
}
// now do something with the list...
});
Kodunuz daha sonra değiştirilen anahtarların listesiyle ilgili olarak yerel bir kopyasını güncelleştirme veya kullanıcı arabirimini yeni değerlerle güncelleştirme gibi bazı eylemler gerçekleştirebilir.
Olası değişiklik nedenleri şunlardır: ServerChange (0), InitialSyncChange (1) veya QuotaViolationChange (2). Nedene erişebilir ve gerekirse farklı işlemler gerçekleştirebilirsiniz (örneğin, QuotaViolationChange sonucunda bazı anahtarları kaldırmanız gerekebilir).
Belge Depolama
iCloud Belge Depolama, uygulamanız (ve kullanıcı için) için önemli olan verileri yönetmek için tasarlanmıştır. Uygulamanızın çalıştırması gereken dosyaları ve diğer verileri yönetmek için kullanılırken, aynı zamanda kullanıcının tüm cihazlarında iCloud tabanlı yedekleme ve paylaşım işlevselliği sağlar.
Bu diyagramda, bunların birbirine nasıl uyduğu gösterilmektedir. Her cihazda yerel depolama alanına kaydedilmiş veriler vardır (UbiquityContainer) ve işletim sisteminin iCloud Daemon'ı bulutta veri gönderme ve alma işlemini üstlenir. Eşzamanlı erişimi önlemek için UbiquityContainer'a tüm dosya erişimi FilePresenter/FileCoordinator aracılığıyla yapılmalıdır. sınıfı UIDocument
bunları sizin için uygular; bu örnekte UIDocument'ın nasıl kullanılacağı gösterilmektedir.
iCloudUIDoc örneği, tek bir metin alanı içeren basit UIDocument
bir alt sınıf uygular. Metin bir UITextView
içinde işlenir ve düzenlemeler iCloud tarafından kırmızı renkte gösterilen bir bildirim iletisiyle diğer cihazlara yayılır. Örnek kod, çakışma çözümü gibi daha gelişmiş iCloud özellikleriyle ilgilenmez.
Bu ekran görüntüsünde örnek uygulama gösterilmektedir. Metni değiştirdikten ve UpdateChangeCount tuşuna bastıktan sonra belge iCloud aracılığıyla diğer cihazlarla eşitlenir.
iCloudUIDoc örneğinin beş bölümü vardır:
UbiquityContainer'a erişme - iCloud'un etkinleştirilip etkinleştirilmediğini ve etkinleştirilip etkinleştirilmediğini uygulamanızın iCloud depolama alanına giden yolu belirleyin.
UIDocument alt sınıfı oluşturma - iCloud depolama alanı ile model nesneleriniz arasında ara sınıf oluşturma.
iCloud belgelerini bulma ve açma -
NSFileManager
NSPredicate
iCloud belgelerini bulmak ve açmak için ve kullanın.iCloud belgelerini görüntüleme - kullanıcı arabirimi denetimleriyle etkileşim kurabilmeniz için özelliklerinizi
UIDocument
kullanıma sunar.iCloud belgelerini kaydetme - Kullanıcı arabiriminde yapılan değişikliklerin diskte ve iCloud'da kalıcı olduğundan emin olun.
Bir şeyin gerçekleşmesini beklerken engellememeleri için tüm iCloud işlemleri zaman uyumsuz olarak çalıştırılır (veya çalıştırılmalıdır). Örnekte bunu yapmanın üç farklı yolunu göreceksiniz:
İş parçacıkları - AppDelegate.FinishedLaunching
için ilk çağrıdaGetUrlForUbiquityContainer
, ana iş parçacığının engellenmesini önlemek için başka bir iş parçacığında yapılır.
NotificationCenter - tamamlandı gibi NSMetadataQuery.StartQuery
zaman uyumsuz işlemler tamamlandığında bildirimlere kaydolma.
Tamamlama İşleyicileri - gibi UIDocument.Open
zaman uyumsuz işlemleri tamamlarken çalıştırılacak yöntemleri geçirme.
UbiquityContainer'a erişme
iCloud Belge Depolama'yı kullanmanın ilk adımı, iCloud'un etkinleştirilip etkinleştirilmediğini ve etkinse "yaygınlık kapsayıcısının" konumunu (iCloud özellikli dosyaların cihazda depolandığı dizin) belirlemektir.
Bu kod, örneğin yöntemindedir AppDelegate.FinishedLaunching
.
// GetUrlForUbiquityContainer is blocking, Apple recommends background thread or your UI will freeze
ThreadPool.QueueUserWorkItem (_ => {
CheckingForiCloud = true;
Console.WriteLine ("Checking for iCloud");
var uburl = NSFileManager.DefaultManager.GetUrlForUbiquityContainer (null);
// OR instead of null you can specify "TEAMID.com.your-company.ApplicationName"
if (uburl == null) {
HasiCloud = false;
Console.WriteLine ("Can't find iCloud container, check your provisioning profile and entitlements");
InvokeOnMainThread (() => {
var alertController = UIAlertController.Create ("No \uE049 available",
"Check your Entitlements.plist, BundleId, TeamId and Provisioning Profile!", UIAlertControllerStyle.Alert);
alertController.AddAction (UIAlertAction.Create ("OK", UIAlertActionStyle.Destructive, null));
viewController.PresentViewController (alertController, false, null);
});
} else { // iCloud enabled, store the NSURL for later use
HasiCloud = true;
iCloudUrl = uburl;
Console.WriteLine ("yyy Yes iCloud! {0}", uburl.AbsoluteUrl);
}
CheckingForiCloud = false;
});
Örnek bunu yapmasa da Apple, bir uygulama ön plana geldiğinde GetUrlForUbiquityContainer'ı çağırmanızı önerir.
UIDocument Alt Sınıfı Oluşturma
Tüm iCloud dosyaları ve dizinleri (yani UbiquityContainer dizininde depolanan her şey) NSFileManager yöntemleri kullanılarak yönetilmeli, NSFilePresenter protokolü uygulanmalıdır ve bir NSFileCoordinator aracılığıyla yazılmalıdır. Bunların tümünü yapmanın en basit yolu, kendiniz yazmak değil, her şeyi sizin için yapan UIDocument alt sınıfıdır.
iCloud ile çalışmak için UIDocument alt sınıfında uygulamanız gereken yalnızca iki yöntem vardır:
LoadFromContents - Model sınıfınıza/es'inize paketi açmanız için dosyanın içeriğinin NSData'sını geçirir.
ContentsForType - Diske (ve Buluta) kaydedilecek model sınıfınızın/es'inizin NSData gösterimini sağlamanızı isteyin.
iCloudUIDoc\MonkeyDocument.cs'dan alınan bu örnek kod, UIDocument'ın nasıl uygulandığını gösterir.
public class MonkeyDocument : UIDocument
{
// the 'model', just a chunk of text in this case; must easily convert to NSData
NSString dataModel;
// model is wrapped in a nice .NET-friendly property
public string DocumentString {
get {
return dataModel.ToString ();
}
set {
dataModel = new NSString (value);
}
}
public MonkeyDocument (NSUrl url) : base (url)
{
DocumentString = "(default text)";
}
// contents supplied by iCloud to display, update local model and display (via notification)
public override bool LoadFromContents (NSObject contents, string typeName, out NSError outError)
{
outError = null;
Console.WriteLine ("LoadFromContents({0})", typeName);
if (contents != null)
dataModel = NSString.FromData ((NSData)contents, NSStringEncoding.UTF8);
// LoadFromContents called when an update occurs
NSNotificationCenter.DefaultCenter.PostNotificationName ("monkeyDocumentModified", this);
return true;
}
// return contents for iCloud to save (from the local model)
public override NSObject ContentsForType (string typeName, out NSError outError)
{
outError = null;
Console.WriteLine ("ContentsForType({0})", typeName);
Console.WriteLine ("DocumentText:{0}",dataModel);
NSData docData = dataModel.Encode (NSStringEncoding.UTF8);
return docData;
}
}
Bu örnekteki veri modeli çok basittir- tek bir metin alanı. Veri modeliniz, xml belgesi veya ikili veri gibi gerektiği kadar karmaşık olabilir. UIDocument uygulamasının birincil rolü, model sınıflarınız ile diske kaydedilebilen/yüklenebilen bir NSData gösterimi arasında çeviri yapmaktır.
iCloud Belgelerini Bulma ve Açma
Örnek uygulama yalnızca tek bir dosyayla (test.txt) ilgilenir, bu nedenle AppDelegate.cs içindeki kod özel olarak bu dosya adını aramak için bir NSPredicate
ve NSMetadataQuery
oluşturur. zaman NSMetadataQuery
uyumsuz olarak çalışır ve tamamlandığında bir bildirim gönderir. DidFinishGathering
bildirim gözlemcisi tarafından çağrılır, sorguyu durdurur ve dosyayı yükleyip içinde MonkeyDocumentViewController
görüntülemeye çalışmak için tamamlama işleyicisi ile yöntemini kullanan UIDocument.Open
LoadDocument'ı çağırır.
string monkeyDocFilename = "test.txt";
void FindDocument ()
{
Console.WriteLine ("FindDocument");
query = new NSMetadataQuery {
SearchScopes = new NSObject [] { NSMetadataQuery.UbiquitousDocumentsScope }
};
var pred = NSPredicate.FromFormat ("%K == %@", new NSObject[] {
NSMetadataQuery.ItemFSNameKey, new NSString (MonkeyDocFilename)
});
Console.WriteLine ("Predicate:{0}", pred.PredicateFormat);
query.Predicate = pred;
NSNotificationCenter.DefaultCenter.AddObserver (
this,
new Selector ("queryDidFinishGathering:"),
NSMetadataQuery.DidFinishGatheringNotification,
query
);
query.StartQuery ();
}
[Export ("queryDidFinishGathering:")]
void DidFinishGathering (NSNotification notification)
{
Console.WriteLine ("DidFinishGathering");
var metadataQuery = (NSMetadataQuery)notification.Object;
metadataQuery.DisableUpdates ();
metadataQuery.StopQuery ();
NSNotificationCenter.DefaultCenter.RemoveObserver (this, NSMetadataQuery.DidFinishGatheringNotification, metadataQuery);
LoadDocument (metadataQuery);
}
void LoadDocument (NSMetadataQuery metadataQuery)
{
Console.WriteLine ("LoadDocument");
if (metadataQuery.ResultCount == 1) {
var item = (NSMetadataItem)metadataQuery.ResultAtIndex (0);
var url = (NSUrl)item.ValueForAttribute (NSMetadataQuery.ItemURLKey);
doc = new MonkeyDocument (url);
doc.Open (success => {
if (success) {
Console.WriteLine ("iCloud document opened");
Console.WriteLine (" -- {0}", doc.DocumentString);
viewController.DisplayDocument (doc);
} else {
Console.WriteLine ("failed to open iCloud document");
}
});
} // TODO: if no document, we need to create one
}
iCloud Belgelerini Görüntüleme
UIDocument'ın görüntülenmesi başka bir model sınıfından farklı olmamalıdır. Özellikler kullanıcı tarafından düzenlenmiş ve sonra modele geri yazılan kullanıcı arabirimi denetimlerinde görüntülenir.
Örnekte iCloudUIDoc\MonkeyDocumentViewController.cs içinde MonkeyDocument metnini UITextView
görüntüler. ViewDidLoad
yönteminde MonkeyDocument.LoadFromContents
gönderilen bildirimi dinler. LoadFromContents
iCloud dosya için yeni veriye sahip olduğunda çağrılır, böylece bildirim belgenin güncelleştirildiğini gösterir.
NSNotificationCenter.DefaultCenter.AddObserver (this,
new Selector ("dataReloaded:"),
new NSString ("monkeyDocumentModified"),
null
);
Örnek kod bildirim işleyicisi, herhangi bir çakışma algılama veya çözüm olmadan kullanıcı arabirimini güncelleştirmek için bir yöntem çağırır.
[Export ("dataReloaded:")]
void DataReloaded (NSNotification notification)
{
doc = (MonkeyDocument)notification.Object;
// we just overwrite whatever was being typed, no conflict resolution for now
docText.Text = doc.DocumentString;
}
iCloud Belgelerini Kaydetme
iCloud'a UIDocument eklemek için doğrudan arayabilir UIDocument.Save
(yalnızca yeni belgeler için) veya kullanarak mevcut bir dosyayı taşıyabilirsiniz NSFileManager.DefaultManager.SetUbiquitious
. Örnek kod, bu kodla doğrudan yaygınlık kapsayıcısında yeni bir belge oluşturur (burada biri işlem için, diğeri Open için Save
olmak üzere iki tamamlama işleyicisi vardır):
var docsFolder = Path.Combine (iCloudUrl.Path, "Documents"); // NOTE: Documents folder is user-accessible in Settings
var docPath = Path.Combine (docsFolder, MonkeyDocFilename);
var ubiq = new NSUrl (docPath, false);
var monkeyDoc = new MonkeyDocument (ubiq);
monkeyDoc.Save (monkeyDoc.FileUrl, UIDocumentSaveOperation.ForCreating, saveSuccess => {
Console.WriteLine ("Save completion:" + saveSuccess);
if (saveSuccess) {
monkeyDoc.Open (openSuccess => {
Console.WriteLine ("Open completion:" + openSuccess);
if (openSuccess) {
Console.WriteLine ("new document for iCloud");
Console.WriteLine (" == " + monkeyDoc.DocumentString);
viewController.DisplayDocument (monkeyDoc);
} else {
Console.WriteLine ("couldn't open");
}
});
} else {
Console.WriteLine ("couldn't save");
}
Belgedeki sonraki değişiklikler doğrudan "kaydedilmez", bunun yerine ile UpdateChangeCount
değiştirildiğini söyleriz UIDocument
ve otomatik olarak diske kaydetme işlemi zamanlar:
doc.UpdateChangeCount (UIDocumentChangeKind.Done);
iCloud Belgelerini Yönetme
Kullanıcılar, iCloud belgelerini uygulamanızın dışındaki "ubiquity kapsayıcısının" Documents dizininde Ayarlar aracılığıyla yönetebilir; dosya listesini görüntüleyebilir ve silmek için çekebilirler. Uygulama kodu, belgelerin kullanıcı tarafından silindiği durumu işleyebilmelidir. İç uygulama verilerini Belgeler dizininde depolamayın.
Kullanıcılar ayrıca, iCloud özellikli bir uygulamayı cihazlarından kaldırmaya çalıştıklarında, bu uygulamayla ilgili iCloud belgelerinin durumunu bildirmek için farklı uyarılar alır.
iCloud Backup
iCloud'a yedekleme, geliştiriciler tarafından doğrudan erişilen bir özellik olmasa da, uygulamanızı tasarlama şekliniz kullanıcı deneyimini etkileyebilir. Apple, geliştiricilerin iOS uygulamalarında izlemesi için iOS Veri Depolama Yönergeleri sağlar.
En önemli nokta, uygulamanızın kullanıcı tarafından oluşturulmayan büyük dosyaları depolayıp depolamadığıdır (örneğin, sorun başına yüz artı megabayt içerik depolayan bir dergi okuyucu uygulaması). Apple, bu tür verileri iCloud'a yedeklenecek ve kullanıcının iCloud kotasını gereksiz yere dolduracak şekilde depolamamanızı tercih eder.
Bunun gibi büyük miktarda veri depolayan uygulamalar, bu verileri yedeklenmemiş kullanıcı dizinlerinden birinde depolamalıdır (örn. önbellekler veya tmp) veya iCloud'un yedekleme işlemleri sırasında bunları yoksayması için bu dosyalara bayrak uygulamak için kullanın NSFileManager.SetSkipBackupAttribute
.
Özet
Bu makalede, iOS 5'te yer alan yeni iCloud özelliği tanıtıldı. Projenizi iCloud kullanacak şekilde yapılandırmak için gereken adımları inceledi ve ardından iCloud özelliklerinin nasıl uygulandığına ilişkin örnekler sağladı.
Anahtar-değer depolama örneği, ICloud'un NSUserPreferences'ın depolandığı gibi az miktarda veriyi depolamak için nasıl kullanılabileceğini göstermiştir. UIDocument örneği, iCloud aracılığıyla birden çok cihazda ne kadar karmaşık verilerin depolanabileceğini ve eşitlenebileceğini gösterdi.
Son olarak, iCloud Backup'ın eklenmesinin uygulama tasarımınızı nasıl etkilediği hakkında kısa bir tartışma içeriyor.