Реализация Apple iCloud в приложениях Mac
Вопрос
Я знаю, что у iOS есть API для интеграции iCloud для приложений. Могу ли я интегрировать iCloud в приложения Mac? Будет ли реализация отличаться для приложений Mac для интеграции iCloud? Если да, есть ли учебные пособия и т. Д. или Справочные сайты?
Решение
Да. iCloud доступен на Mac.
Но документация Apple по этой теме все еще не очень полна. Единственные официальные ресурсы, которые я мог найти, где WWDC 2011 Сессия 107 Видео И некоторые заметки в "Что нового в Mac OS X"
Когда Lion & Icloud все еще были под NDA, я опубликовал свои выводы в DevForums Apple.
Это отредактированная версия эта почта:
Я использую модифицированную версию кода WWDC 2011 Session 107. (Переписано из видео) Мне пришлось удалить ручную экземпляр NSFileCoordinator, чтобы заставить образец работы (говорящий упоминает, что координатор «может не понадобиться в будущем»):::
- (IBAction)moveToOrFromCloud:(id)sender
{
NSFileManager* fm = [NSFileManager defaultManager];
NSURL* fileURL = [[self document] fileURL];
BOOL shouldMakeUbiquitous = [sender tag] == 1;
NSURL* destinationURL;
if(shouldMakeUbiquitous)
{
NSURL* rootURL = [fm URLForUbiquityContainerIdentifier:@"app.example"];
NSURL* directoryURL = [rootURL URLByAppendingPathComponent:@"Documents"];
[fm createDirectoryAtURL:directoryURL withIntermediateDirectories:NO attributes:nil error:NULL];
destinationURL = [directoryURL URLByAppendingPathComponent:[fileURL lastPathComponent]];
}
else
{
destinationURL = [[[fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] objectAtIndex:0] URLByAppendingPathComponent:[fileURL lastPathComponent]];
}
NSError* error;
if(![fm setUbiquitous:shouldMakeUbiquitous itemAtURL:fileURL destinationURL:destinationURL error:&error])
{
[[self document] presentError:error modalForWindow:[[self document] windowForSheet] delegate:nil didPresentSelector:NULL contextInfo:NULL];
}
else
{
[[self document] setFileURL:destinationURL];
[[self document] setFileModificationDate:nil];
}
}
Вышеуказанная апонтизация подключена к nsmenuitem, который проверяет, находится ли документ в iCloud или если его нужно загрузить:
- (BOOL)validateMenuItem:(NSMenuItem*)item
{
SEL action = [item action];
if (action == @selector(moveToOrFromCloud:))
{
BOOL isUbiquitous = [[NSFileManager defaultManager] isUbiquitousItemAtURL:[[self document] fileURL]];
[item setTitle:isUbiquitous ? @"Remove from Cloud": "Move to Cloud"];
[item setTag:isUbiquitous?0:1];
return [self.document fileURL] != nil;
}
return YES;
}
Контрольный список для неверных задач, которые необходимы для работы с хранением документов iCloud:
- Проверьте, активируется ли поддержка ICLOUD в утилите сертификата разработчика
- Создайте идентификатор контейнера в Abiquity в утилите сертификата разработчика
- Идентификатор контейнера в повсеместном распространении начинается с идентификатора/индивидуального идентификатора вашей команды (см. Вкладку учетной записи в Центре членов)
- Включить права в XCODE
- Добавьте свой идентификатор контейнера в повсеместном распространении в файл Valiements (как описано здесь «Запрашивая права на хранение iCloud».)
- Мой идентификатор пакета PLIST должен был соответствовать идентификатору контейнера повсеместного использования (за исключением идентификатора команды)
- Я не смог добавить суффиксы (например, "app.example.osx", "app.example.ipad", ... как предложено в DOC выше)
- Создать профиль подготовки
- Убедитесь, что профиль установлен на вашем Dev Machine и отображается в XCode & System Preferences
- Включите подписание кода в настройках сборки приложений
Другие советы
Есть документ Apple, который подробно описан во всех аспектах http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/icloud/icloud.html
Одна важная проблема с кодом, размещенным здесь, заключается в том, что в нем нет команды в идентификаторе, предоставленной UrlForubiquityContainerIdentifier, даже если он упоминается в контрольном списке, оставляя его вообще, чтобы быть автоматически заполненным из прав, кажется лучшим потуханием.
Лично единственные изменения, которые мне пришлось внести, чтобы Icloud пошел в мое приложение, были:
- Проверьте кнопку «Использовать iCloud» на веб -сайте разработчика для идентификатора моего приложения
- Загрузите регенерированное положение для этого идентификатора приложения
- Проверьте «Включить право» в кратком изложении XCODE
Это было все, вот, надеюсь, более четкий пример кода (должен работать как для iOS, так и для OSX):
NSURL *url = [self getiCloudURLFor:@"foo.bar" containerID:nil]; //leaving nil so it is auto filled from entitlements
if (url) {
NSError *error;
if (![[NSFileManager defaultManager] startDownloadingUbiquitousItemAtURL:url error:&error]) {
NSLog(@"Error downloading/syncing %@ (%@)",[url path],[error description]);
}else{
NSLog(@"Started downloading/syncing %@",[url path]);
}
}
NSArray *conflicts = [NSFileVersion unresolvedConflictVersionsOfItemAtURL:url];
for (NSFileVersion *conflict in conflicts) {
NSLog(@"Conflicting %@ at %@ by %@ from %@",[url path],[conflict URL],[conflict localizedNameOfSavingComputer],[conflict modificationDate]);
}
- (NSURL*)getiCloudURLFor:(NSString*)fileName containerID:(NSString*)containerID
{
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *rootURL = [fm URLForUbiquityContainerIdentifier:containerID];
if (rootURL) {
NSURL *directoryURL = [rootURL URLByAppendingPathComponent:@"Documents"];
if (![fm fileExistsAtPath:[directoryURL path]]) [fm createDirectoryAtURL:directoryURL withIntermediateDirectories:NO attributes:nil error:NULL];
NSURL *cloudURL = [directoryURL URLByAppendingPathComponent:fileName];
if (![fm isUbiquitousItemAtURL:cloudURL]) [self makeUbiquitousItemAtURL:cloudURL];//this only runs once per filename when it is first added to iCloud
return cloudURL;
}else{
return [[[fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] objectAtIndex:0] URLByAppendingPathComponent:fileName]; //no cloud
}
return nil;
}
- (void)makeUbiquitousItemAtURL:(NSURL*)cloudURL
{
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *localURL = [[[fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] objectAtIndex:0] URLByAppendingPathComponent:[cloudURL lastPathComponent]];
if (![fm fileExistsAtPath:[localURL path]]) [fm createFileAtPath:[localURL path] contents:nil attributes:nil];
NSError *error;
if(![fm setUbiquitous:YES itemAtURL:localURL destinationURL:cloudURL error:&error]) {
NSLog(@"Error making %@ ubiquituous at %@ (%@)",[localURL path],[cloudURL path],[error description]);
}else{
NSLog(@"Made %@ ubiquituous at %@",[localURL lastPathComponent],[cloudURL path]);
}
}