先mark一下吧,以后肯定能用上。
iCloud Document Storage开发
测试
iCloud目前只能在真实设备中测试,不能在Simulator中测试
Display Set
在iTunesConnect中新建"iCloud Manage Display Sets",iCloud的文档和数据存储在display sets中。多个应用可以引用和存储数据到同一个display set。(iTunesConnect手册上有这一步,但是很多教程,包括iOS App Programming Guide也没有提到,可能不需要了)
APP ID 和 开发证书
iOS Provisioning Portal中,创建启用iCloud的App ID,现有的App ID也可以编辑并启用iCloud,App ID必须不包含通配符"*"
针对上面的App ID,创建新的Development Provisioning Profile,下载后双击使用Xcode打开完成安装,并设置Code Signing。
Xcode entitlements
在Xcode中配置应用的iCloud Entitlements,Target->Summary->Entitlements,勾选后Xcode会自动生成
iCloud Key-Value Store:
com.company.App
iCloud Containers:
com.company.App
Keychain Access Groups:
com.company.App
这里 Xcode自动生成的Entitlements使用了通配符,我们需要手工修改PROJECT.Entitlements文件:
iCloud Key-Value Store: TeamIdentifier.com.company.App
iCloud Containers:
TeamIdentifier
.com.company.App
Keychain Access Groups:
ApplicationIdentifierPre fix
.com.company.App
其中TeamIdentifier是申请 IDP 时拿到的标识,可以在MemberCenter -> Your Account -> Account Summary中找到( http://developer.apple.com/membercenter/index.action )
ApplicationIdentifierPre fix 则是注册App ID时使用的前缀。
其实简单的办法是用编辑器打开上面下载的Development Provisioning Profile,直接在里面就可以找到这两个字符串。
源代码定义Ubiquity Container URL
定义一个常量字符串,我们代码里面使用它来构造iCloud storage的URL,实际上和Entitlement中定义的字符串是一样的。
#define UBIQUITY_CONTAINER_URL @"ABCDEF12345.com.yourdomain.icloudapp
UIDocument
iOS 5为iCloud引入的file presenter,创建和管理文档及其内容,极大地方便了开发。对本地文件使用UIDocument也能带来一些好处。如后台队列的异步读写、处理版本冲突、自动文档保存等。
继承UIDocument
contentsForType:error:
UIDocument对象将数据写入文件或文档时调用,这个方法负责收集要写入的数据,并返回NSData或NSFileWrapper对象。
loadFromContents:ofType:error:
UIDocument对象从文件或文档中读取数据时调用,并传递从文件或文档中已经读取到的数据给这个方法。方法负责把这些数据装载到应用的内部数据model
文档状态和冲突解决
文档状态:
UIDocumentStateNormal – 文档已打开并允许用户编辑
UIDocumentStateClosed – 文档当前已关闭,读取文档时出错也可能是这个状态
UIDocumentStateInConflic t – 检测到文档的多个版本冲突
UIDocumentStateSavingErr or – 试图保存文档时出错
UIDocumentStateEditingDi sabled – 文档繁忙,当前编辑不安全
文档状态变化时会发送 UIDocumentStateChangedNo tification 通知,注册这个通知就能监测文档状态,及时处理出错、冲突等。
解决冲突:
理想情况下,应该允许用户指定哪些文件存储在iCloud,哪些文件存储在本地
之前已经添加到iCloud的文档,不能使用绝对路径来访问!应用应该通过名字在iCloud storage中查找文档。
存储到iCloud的文档,应该放在应用的Documents目录
使用 URLForUbiquityContainerI dentifier: 方法检测iCloud是否可用,传递已经定义好的Container URL,也可以传递nil,表示Entitlements中定义的第一个URL。方法返回nil表示iCloud不可用,返回URL表示可用。
拿到这个URL后,再对它调用 URLByAppendingPathCompon ent:@"Documents" 来组建一个路径。
默认情况下,当前应用的iCloud storage中并没有这个Documents目录,因此我们需要首先创建它。
然后再使用 NSMetadataQuery 查找iCloud中是否存在我们要的文档,查找过程会在另一个线程中进行,完成后会通过 NSMetadataQueryDidFinish GatheringNotification 通知告诉你注册的observer
本地文件移动到iCloud
调用 setUbiquitous: itemAtURL: 方法,传递YES表示本地文件移动到iCloud,传递NO则表示反向移动。
设备配置
在 Settings 应用中启用设备的iCloud Document and Data Storage,运行程序测试,此时可以在 Settings 应用中看到已经上传到iCloud中的文档
完整例子
MyDocument.h
@interface MyDocument : UIDocument
{
NSString *userText;
}
@property (strong, nonatomic) NSString *userText;
MyDocument.m
-(id)contentsForType:(NSString *)typeName error:(NSError *__autoreleasing *)outError
{
return [NSData dataWithBytes:[self.userText UTF8String] length:[self.userText length]];
}
-(BOOL) loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError *__autoreleasing *)outError
{
if ( [contents length] > 0) {
self.userText = [[NSString alloc] initWithBytes:[contents bytes] length:[contents length] encoding:NSUTF8StringEncoding];
} else {
self.userText = @"";
}
return YES;
}
iCloudStoreViewControlle r.h
@interface iCloudStoreViewControlle r : UIViewController
{
MyDocument *document;
NSURL *documentURL;
NSURL *ubiquityURL;
UITextView *textView;
NSMetadataQuery *metadataQuery;
}
@property (strong, nonatomic) IBOutlet UITextView *textView;
@property (strong, nonatomic) NSURL *documentURL;
@property (strong, nonatomic) MyDocument *document;
@property (strong, nonatomic) NSURL *ubiquityURL;
@property (strong, nonatomic) NSMetadataQuery *metadataQuery;
-(IBAction)saveDocument;
iCloudStoreViewControlle r.m
- (void)saveDocument
{
self.document.userText = textView.text;
[self.document saveToURL:ubiquityURL forSaveOperation:UIDocumentSaveForOverwri ting
completionHandler:^(BOOL success) {
if (success){
NSLog(@"Saved to cloud for overwriting");
} else {
NSLog(@"Not saved to cloud for overwriting");
}
}];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *dirPaths = NSSearchPathForDirectori esInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
NSString *dataFile = [docsDir stringByAppendingPathCom ponent: @"document.doc"];
self.documentURL = [NSURL fileURLWithPath:dataFile];
NSFileManager *filemgr = [NSFileManager defaultManager];
ubiquityURL = [[filemgr URLForUbiquityContainerI dentifier:UBIQUITY_CONTAINER_URL] URLByAppendingPathCompon ent:@"Documents"];
NSLog(@"iCloud path = %@", [ubiquityURL path]);
if ([filemgr fileExistsAtPath:[ubiquityURL path]] == NO)
{
NSLog(@"iCloud Documents directory does not exist");
[filemgr createDirectoryAtURL:ubiquityURL withIntermediateDirector ies:YES attributes:nil error:nil];
} else {
NSLog(@"iCloud Documents directory exists");
}
ubiquityURL = [ubiquityURL URLByAppendingPathCompon ent:@"document.doc"];
NSLog(@"Full ubiquity path = %@", [ubiquityURL path]);
// Search for document in iCloud storage
metadataQuery = [[NSMetadataQuery alloc] init];
[metadataQuery setPredicate: [NSPredicate predicateWithFormat: @"%K like 'document.doc'",
NSMetadataItemFSNameKey]];
[metadataQuery setSearchScopes:[NSArray arrayWithObjects:NSMetadataQueryUbiquitou sDocumentsScope,nil]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(metadataQueryDidFinishGa thering:)
name:NSMetadataQueryDidFinish GatheringNotification
object:metadataQuery];
NSLog(@"starting query");
[metadataQuery startQuery];
}
- (void)metadataQueryDidFinishGa thering:(NSNotification *)notification
{
NSMetadataQuery *query = [notification object];
[query disableUpdates];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinish GatheringNotification object:query];
[query stopQuery];
NSArray *results = [[NSArray alloc] initWithArray:[query results]];
if ([results count] == 1)
{
NSLog(@"File exists in cloud");
ubiquityURL = [[results objectAtIndex:0] valueForAttribute:NSMetadataItemURLKey];
self.document = [[MyDocument alloc] initWithFileURL:ubiquityURL];
//self.document.userText = @"";
[document openWithCompletionHandle r:
^(BOOL success) {
if (success){
NSLog(@"Opened cloud doc");
textView.text = document.userText;
} else {
NSLog(@"Not opened cloud doc");
}
}];
} else {
NSLog(@"File does not exist in cloud");
self.document = [[MyDocument alloc] initWithFileURL:ubiquityURL];
[document saveToURL:ubiquityURL
forSaveOperation: UIDocumentSaveForCreatin g
completionHandler:^(BOOL success) {
if (success){
NSLog(@"Saved to cloud");
} else {
NSLog(@"Failed to save to cloud");
}
}];
}
}
发布与提交
开发测试完成后,在 iOS Provisioning Portal 中为 App ID
创建新的Distribution Provisioning Profile,打包并Submit应用
原文地址:【iOS开发】iCloud开发 共享的两种方式
作者:一棵草Telen
---------------------------------------------
另一篇相关日志:
【iOS开发】iCloud开发 分析 :
http://blog.sina.com.cn/s/blog_693de6100101jur4.html
---------------------------------------------
iCloud Document Storage 和 Key-Value Data Storage 教程与简单示例
--------------------------------------------------
UIDocument
--------------------------------------------------
测试
iCloud目前只能在真实设备中测试,不能在Simulator中测试
Display Set
在iTunesConnect中新建"iCloud Manage Display Sets",iCloud的文档和数据存储在display sets中。多个应用可以引用和存储数据到同一个display set。(iTunesConnect手册上有这一步,但是很多教程,包括iOS App Programming Guide也没有提到,可能不需要了)
APP ID 和 开发证书
iOS
针对上面的App ID,创建新的Development Provisioning Profile,下载后双击使用Xcode打开完成安装,并设置Code Signing。
Xcode entitlements
在Xcode中配置应用的iCloud Entitlements,Target->Summary->Entitlements,勾选后Xcode会自动生成
iCloud Key-Value Store:
iCloud Containers:
Keychain Access Groups:
这里 Xcode自动生成的Entitlements使用了通配符,我们需要手工修改PROJECT.Entitlements文件:
iCloud Key-Value Store:
iCloud Containers:
Keychain Access Groups:
其中TeamIdentifier是申请 IDP 时拿到的标识,可以在MemberCenter -> Your Account -> Account Summary中找到( http://developer.apple.com/membercenter/index.action )
ApplicationIdentifierPre
其实简单的办法是用编辑器打开上面下载的Development Provisioning Profile,直接在里面就可以找到这两个字符串。
源代码定义Ubiquity Container URL
定义一个常量字符串,我们代码里面使用它来构造iCloud storage的URL,实际上和Entitlement中定义的字符串是一样的。
#define UBIQUITY_CONTAINER_URL @"ABCDEF12345.com.yourdomain.icloudapp
UIDocument
iOS 5为iCloud引入的file presenter,创建和管理文档及其内容,极大地方便了开发。对本地文件使用UIDocument也能带来一些好处。如后台队列的异步读写、处理版本冲突、自动文档保存等。
继承UIDocument
contentsForType:error:
UIDocument对象将数据写入文件或文档时调用,这个方法负责收集要写入的数据,并返回NSData或NSFileWrapper对象。
loadFromContents:ofType:error:
UIDocument对象从文件或文档中读取数据时调用,并传递从文件或文档中已经读取到的数据给这个方法。方法负责把这些数据装载到应用的内部数据model
文档状态和冲突解决
文档状态:
UIDocumentStateNormal – 文档已打开并允许用户编辑
UIDocumentStateClosed – 文档当前已关闭,读取文档时出错也可能是这个状态
UIDocumentStateInConflic
UIDocumentStateSavingErr
UIDocumentStateEditingDi
文档状态变化时会发送
解决冲突:
- 如果可行,合并冲突版本
- 如果不丢失数据,丢弃冲突版本
- 提示用户,选择要保留的版本
理想情况下,应该允许用户指定哪些文件存储在iCloud,哪些文件存储在本地
之前已经添加到iCloud的文档,不能使用绝对路径来访问!应用应该通过名字在iCloud storage中查找文档。
存储到iCloud的文档,应该放在应用的Documents目录
使用
拿到这个URL后,再对它调用
默认情况下,当前应用的iCloud storage中并没有这个Documents目录,因此我们需要首先创建它。
然后再使用
本地文件移动到iCloud
调用
设备配置
在 Settings 应用中启用设备的iCloud Document and Data Storage,运行程序测试,此时可以在 Settings 应用中看到已经上传到iCloud中的文档
完整例子
MyDocument.h
@interface MyDocument : UIDocument
{
}
@property (strong, nonatomic) NSString *userText;
MyDocument.m
-(id)contentsForType:(NSString *)typeName error:(NSError *__autoreleasing *)outError
{
}
-(BOOL) loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError *__autoreleasing *)outError
{
}
iCloudStoreViewControlle
@interface iCloudStoreViewControlle
{
}
@property (strong, nonatomic) IBOutlet UITextView *textView;
@property (strong, nonatomic) NSURL *documentURL;
@property (strong, nonatomic) MyDocument *document;
@property (strong, nonatomic) NSURL *ubiquityURL;
@property (strong, nonatomic) NSMetadataQuery *metadataQuery;
-(IBAction)saveDocument;
iCloudStoreViewControlle
- (void)saveDocument
{
}
- (void)viewDidLoad
{
}
- (void)metadataQueryDidFinishGa
{
}
发布与提交
开发测试完成后,在 iOS Provisioning Portal 中为 App ID
--------------------------------------------------
NSUbiquitousKeyValueStor e
--------------------------------------------------
iCloud Key-Value Data Storage开发
iCloud Key-Value Data Storage主要用于应用的小量非关键数据在多个设备间共享,支持的数据包括:NSString, NSDate, NSArray, NSData, Boolean, NSDictionary, NSNumber等对象
NSUbiquitousKeyValueStor e类
NSUbiquitousKeyValueStor e *keyStore =
[[NSUbiquitousKeyValueStor e alloc] init];
[keyStore setString:@”Saved String” forKey:@"MyString"];
然后调用:
[keyStore synchronize];
保存在本地,以便稍后同步到iCloud,但是调用synchronize方法并不会立即将本地保存的数据同步到iCloud。iOS自己会在适当的时候将这些本地数据同步到iCloud Key-value Data Storage
获取key-value值:
NSString *storedString = [keyStore stringForKey:@"MyString"];
iCloud Key-Value不会产生冲突,最后上传的总是最新的值。
observer可以通过 NSUbiquitousKeyValueStor eDidChangeExternallyNoti fication 通知来监听key-value storage的变化。
key-value存储超出限制时也会递送这个通知,并传递给你 NSUbiquitousKeyValueStor eQuotaViolationChange 常量。
完整例子
iCloudKeysViewController .h
@interface iCloudKeysViewController : UIViewController {
UITextField *textField;
NSUbiquitousKeyValueStor e *keyStore;
}
@property (strong, nonatomic) IBOutlet UITextField *textField;
-(IBAction)saveKey;
@end
iCloudKeysViewController .m
-(void)saveKey
{
[keyStore setString:textField.text forKey:@"MyString"];
[keyStore synchronize];
NSLog(@"Save key");
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
keyStore = [NSUbiquitousKeyValueStor e defaultStore];
NSString *storedString = [keyStore stringForKey:@"MyString"];
if (storedString != nil)
{
textField.text = storedString;
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(ubiquitousKeyValueStoreD idChange:)
name:NSUbiquitousKeyValueStor eDidChangeExternallyNoti fication
object:keyStore];
}
-(void) ubiquitousKeyValueStoreD idChange: (NSNotification *)notification
{
NSLog(@"External Change detected");
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Change detected"
message:@"Change detected"
delegate:nil
cancelButtonTitle:@"Ok"
otherButtonTitles:nil, nil];
[alert show];
textField.text = [keyStore stringForKey:@"MyString"];
}
iCloud Key-Value Data Storage主要用于应用的小量非关键数据在多个设备间共享,支持的数据包括:NSString, NSDate, NSArray, NSData, Boolean, NSDictionary, NSNumber等对象
NSUbiquitousKeyValueStor
NSUbiquitousKeyValueStor
[[NSUbiquitousKeyValueStor
[keyStore setString:@”Saved String” forKey:@"MyString"];
然后调用:
[keyStore synchronize];
保存在本地,以便稍后同步到iCloud,但是调用synchronize方法并不会立即将本地保存的数据同步到iCloud。iOS自己会在适当的时候将这些本地数据同步到iCloud Key-value Data Storage
获取key-value值:
NSString *storedString = [keyStore stringForKey:@"MyString"];
iCloud Key-Value不会产生冲突,最后上传的总是最新的值。
observer可以通过
key-value存储超出限制时也会递送这个通知,并传递给你
完整例子
iCloudKeysViewController
@interface iCloudKeysViewController
UITextField *textField;
NSUbiquitousKeyValueStor
}
@property (strong, nonatomic) IBOutlet UITextField *textField;
-(IBAction)saveKey;
@end
iCloudKeysViewController
-(void)saveKey
{
}
- (void)viewDidLoad
{
// Do any additional setup after loading the view, typically from a nib.
}
-(void) ubiquitousKeyValueStoreD
{
}
--------------------------------------------------
--------------------------------------------------
在《萌塔塔》项目采用
NSUbiquitousKeyValueStor e,借鉴userdefault的用法,有效解决。
难点在c++与oc之间准确的进行数据转换。