iCloud Guide (XCode iCloud 적용가이드)


iOS/아이폰 프로그래밍 2012.07.17 10:14



https://docs.google.com/document/pub?id=1LrykTGpUq9jMWB7g3Ne6uHpIgIRciPWwHMJVCnFuZo0

통해서 업데이트됩니다. 


iCloud Code Review


Jung Chang Hwan
shakejj@gmail.com
mnworld.co.kr

목적 : iCloud 백업을 통해 여러 기기에 설치되어 있는 동일한 앱들 간에 Data를 주고 받는다.  (예: 게임의 Save File, 케릭터 등 파일)

- iCloud는 Document라는 다양한 파일을 저장할 수 있는 공간이 있다. (파일 형식 제한 없음)
이 Document는 MAC과 iOS 둘 다 접근이 가능하며 URL 형태로 Access하여 파일을 읽고 쓸 수 있다.













iCloud가 설정되어 있다면(설정에서 iCloud 계정 입력 및 도큐먼트 및 데이터 백업이 켜져있다면) App은 Entitlement파일(기능파일)에 적어놓은 iCloud키를 통해 Local의 iCloud Folder에 Access가 가능하다. 액세스가 성공하면 Online, Offline에 상관 없이 Sync가 되는 iCloud Folder에 파일을 지우고 쓸 수 있다(Online이 되면 자동으로 Sync). 

따라서 네트워크 상태와는 상관이 없으며, iCloud가 설정되어 있지 않다면(iCloud설정 자체가 되어 있지 않는 경우)에는 iCloud Folder가 아닌 Local Folder를 사용해야 한다. 

Sync가 이루어지는 iCloud Folder는 아래 그림을 참조한다. Mac이나 iOS 두 앱 모두 Sandbox를 적용해야 하기 때문에, 본인이 가진 Document이외에는 Access가 불가능하다. (절대경로를 통해 아래의 폴더에 Access하는 것은 바람적이지 않다) 아래 적용방법을 통해 Access한다.











- iOS iCloud 적용방법 
1) Apple Developer 에서 해당 App ID의 “iCloud”를 “Enbled” 시켜준다.
(http://developer.apple.com)

2) XCode - Project - Summary의 하단 부분에서 ‘Enable Entitlements’를 Check 한다

: Enable Entitlements를 체크한 후, “iCloud Key-Value Store” 을 체크한다. 
iCloud Key - Value Store, iCloud Containers, keychain Access Groups에는 모두 동일한 키를 넣어준다. 넣어줄 키는 TEAM_ID.Bundle Identifier의 형식으로 적어준다. 

* Team_ID을 알아내기 위해서는 XCode - Window - Orgranizor - [Devices Tab] - 왼쪽의 메뉴 중 Provisioning Profiles를 클릭하면, 사용하고자 하는 프로필의 App Identifier을 적어주면 된다. 
10자리의 고유한 형태로 이루어져 있다. (EX: M23JF1JEZK)
* Bundle Identifier은 Project - Summary에서 알 수 있다. 


위와 같이 Bundle Identifier에 있는 값을 넣어준다 (EX: com.회사이름.AppID)

iCloud Key - Value Store, iCloud Containers, keychain Access Groups 모두 예를 들면 (M23JF1JEZK.com.회사이름.AppID)을 넣어준다.

!주의 : 위와 같이 설정 후 Device를 통해 Run 을 했을 때 (Simulator는 iCloud에 Access할 수 없음) 정상적으로 실행되지 않고 Entitlement오류가 난다면, Developer 계정에서 Provisioning File을 Recreate한 후 XCode의 Profile들을 지운 후 Refresh 한다. 

3) 정상적으로 실행 된다면, iCloud를 사용하기 위한 환경설정은 완료된 것 이다.

iCloud에 정상적으로 접근하여 파일을 저장하고 지우기 위해서는 다음 코드를 참고한다. 


Path 가 아닌 containerID를 통해 (Entitlement에 기록된, Summary에서 설정을 해놓은) URL로 접근해서 파일을 쓰고 지울 수 있다. 
(NSURL이 아닌 Query를 통해 iCloud에 저장되어 있는 파일을 로컬로 저장하는 등의 방법도 가능하다) 

// 파일 삭제 시 
NSURL *url = [self getiCloudURLFor:filename containerID:nil]; //leaving nil so it is auto filled from entitlements
   if (url) {     //정상적으로 iCloud 에 Access가 되었다면...

        NSError *error;

        if (![[NSFileManager defaultManager] removeItemAtURL:url error:&error]) {

            NSLog(@"Error downloading/syncing %@ (%@)",[url path],[error description]);                

        }else{

            NSLog(@"Started 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]);  

    }

//==================iCloud OSX & iOS =====================

- (NSURL*)getiCloudURLFor:(NSString*)fileName containerID:(NSString*)containerID

{  

 NSFileManager *fm = [NSFileManager defaultManager];  
NSURL *rootURL = [fm URLForUbiquityContainerIdentifier:containerID];    

   

    if (rootURL) {

    NSURL *directoryURL = [rootURL URLByAppendingPathComponent:@"Documents"];
                   //dirURL은 mobileDocuments

       

 if (![fm fileExistsAtPath:[directoryURL path]]) { 
                    //filemanager경로를 MobileDocument로 변경
 [fm createDirectoryAtURL:directoryURL withIntermediateDirectories:NO attributes:nil error:NULL];

 }

NSURL *cloudURL = [directoryURL URLByAppendingPathComponent:fileName]; 
                    //CloudUrl은 MoibleDoucment의 Image파일

       

  if (![fm isUbiquitousItemAtURL:cloudURL]){

                     //filemager가 ImageFile을 쓴다.

       NSLog(@"!NO Cloud ");

}

  //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;

}

// 파일 추가 시 
 NSURL *url = [self getiCloudURLFor:filename containerID:nil];

    if (url) {

      NSError *error;

 if (![[NSFileManager defaultManager] startDownloadingUbiquitousItemAtURL:url error:&error]) 
//startDownloadingUbiQuitousItemAtURL 파일 저장

{

        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]);  

   }

   [self goToScene:SCENE_LOCKER];

}


//========iCloud OSX & iOS===========//

- (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]);              

  }      

}

파일 탐색 시에도 URL 을 통해 탐색이 가능하며, NSPred Query를 통해 탐색하는 방법과 NSUrl 을 통해 탐색하는 방법이 있다. (아래는 NSUrl 을 통해 탐색하는 방식)

  NSFileManager* kFileManager = [NSFileManager defaultManager];

 NSURL *rootURL = [kFileManager URLForUbiquityContainerIdentifier:nil];

 NSURL *directoryURL = [rootURL URLByAppendingPathComponent:@"Documents"];

 NSLog(@"directoryURL is %@", directoryURL); //DirectoryURL은 iCloud의 Document폴더

   

 if ( directoryURL != nil ) {

NSLog(@"iCloud Folder URL Access");

NSArray* kSavedFile =  [kFileManager contentsOfDirectoryAtURL:directoryURL includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsHiddenFiles error:nil];

NSLog(@"This kSavedFile is %@", kSavedFile);

       

for (NSURL* kUrl in kSavedFile)      {

NSError *error;           
// 파일 탐색 후 탐색 된 파일들을 다운로드 받는 예제

  if (![[NSFileManager defaultManager] startDownloadingUbiquitousItemAtURL:kUrl error:&error])     {                

NSLog(@"Error downloading/syncing %@ (%@)",[kUrl path],[error description]);                            

   }else{                

NSLog(@"Started downloading/syncing %@",[kUrl path]);              

 }      

 NSString *kFile = kUrl.path;  
           //URL 을 String 으로 바꾸어서 원하는 대로 사용이 가능함 (Path를 통해)

 NSLog(@"File Path  : %@", kFile);

 NSString* filePath = kFile;

  }

}


- MAC iCloud 적용 방법

MAC의 경우에도 코드는 iOS와 같은 방식으로 적용하며, 설정방법도 동일하다.

아래 그림과 같이 “Code Sign Application” Check, 
“Enable Entitlement” Check,
iCloud Key-store Value Check 한 후,

만약 iOS 와 같은 iCloud Container를 사용하고 싶다면, iOS에서 설정해준,

 TEAMID.BundleIdentifier을 입력하면 동일한 iCloud Document에 접근이 가능하다.


-  Reference

http://icloudintegration.blogspot.kr/

http://stackoverflow.com/questions/7795629/icloud-basics-and-code-sample

http://samvermette.com/312

https://daw.apple.com/cgi-bin/WebObjects/DSAuthWeb.woa/wa/login?appIdKey=4a75046cda87eab6386a9eae8caabb9824e328b9abc988119b39296495ec184c&path=/login.jspa#565586

http://stackoverflow.com/questions/9032901/nsdocument-sync-with-icloud-where-is-there-a-sample-code

http://www.raywenderlich.com/6015/beginning-icloud-in-ios-5-tutorial-part-1


저작자 표시 비영리 변경 금지
신고

WRITTEN BY
ShakeJ

0 ,