iOS2013. 12. 1. 16:01

일반적으로 cURL을 이용하여 HTTP 프로토콜 데이터를 POST 방식으로 보내는 PHP 함수는 다음과 같습니다.

  1. function https_post($uri$postdata)  
  2. {  
  3.     $ch = curl_init($uri);  
  4.     curl_setopt($ch, CURLOPT_POST, true);  
  5.     curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);  
  6.     $result = curl_exec($ch);  
  7.     curl_close($ch);  
  8.     return $result;  
  9. }  

하지만, 이 방식은 결과값이 전달 될 때 까지 블럭(block) 된다는 것이 문제입니다. 따라서 결과값이 불필요한 경우에는 요청을 보내고 잊어버리면 그만입니다. 아쉽게도 PHP의 cURL 라이브러리는 비동기 처리를 지원하지 않습니다. 따라서 직접 소켓을 오픈하여 요청을 보내야 합니다.

  1. function curl_request_async($url$params$type='POST')  
  2. {  
  3.     foreach ($params as $key => &$val)  
  4.     {  
  5.         if (is_array($val))  
  6.             $val = implode(','$val);  
  7.         $post_params[] = $key.'='.urlencode($val);  
  8.     }  
  9.     $post_string = implode('&'$post_params);  
  10.   
  11.     $parts=parse_url($url);  
  12.   
  13.     if ($parts['scheme'] == 'http')  
  14.     {  
  15.         $fp = fsockopen($parts['host'], isset($parts['port'])?$parts['port']:80, $errno$errstr, 30);  
  16.     }  
  17.     else if ($parts['scheme'] == 'https')  
  18.     {  
  19.         $fp = fsockopen("ssl://" . $parts['host'], isset($parts['port'])?$parts['port']:443, $errno$errstr, 30);  
  20.     }  
  21.   
  22.     // Data goes in the path for a GET request  
  23.     if('GET' == $type)  
  24.         $parts['path'] .= '?'.$post_string;  
  25.   
  26.     $out = "$type ".$parts['path']." HTTP/1.1\r\n";  
  27.     $out.= "Host: ".$parts['host']."\r\n";  
  28.     $out.= "Content-Type: application/x-www-form-urlencoded\r\n";  
  29.     $out.= "Content-Length: ".strlen($post_string)."\r\n";  
  30.     $out.= "Connection: Close\r\n\r\n";  
  31.     // Data goes in the request body for a POST request  
  32.     if ('POST' == $type && isset($post_string))  
  33.         $out.= $post_string;  
  34.   
  35.     fwrite($fp$out);  
  36.     fclose($fp);  
  37. }  

위 코드는 인터넷에 부유 중인 것을 HTTPS (HTTP Secure) 프로토콜도 지원하도록 수정 한 것입니다. 이 방법을 이용하면 전송 할 데이터를 소켓으로 방출 한 후에 곧바로 함수가 리턴됩니다. 즉, 데이터를 받기 위한 추가적인 처리를 프로세스가 감당 할 필요가 없다는 것을 의미합니다.

만약 빠른 응답 속도를 보장 받는 것이 최우선 과제라면 다음과 같이 프로세스를 백그라운드로 실행 하게 만들 수도 있겠습니다. 단, 아래 코드는 POSIX 계열에서만 사용 가능합니다.

  1. function curl_post_async($uri$params)  
  2. {  
  3.         $command = "curl ";  
  4.         foreach ($params as $key => &$val)  
  5.                 $command .= "-F '$key=$val' ";  
  6.         $command .= "$uri -s > /dev/null 2>&1 &";  
  7.         passthru($command);  
  8. }  

이 방식은 지체 없이 curl 프로세스를 백그라운드로 구동하기 때문에 소요 시간이 거의 없다고 볼 수 있습니다.

'iOS' 카테고리의 다른 글

apple push notification 쉽고 간단하게 구축하는 easy apns  (0) 2013.07.10
셀 높이 조절  (0) 2013.06.25
앱 정보 가져오기 (앱이름, 버전)  (0) 2013.06.19
스토리보드 커스텀 셀 (공개)  (0) 2013.06.12
유니코드 출력  (0) 2013.02.01
Posted by 다오나무
iOS2013. 7. 10. 15:08

PHP로 혹시 apple push notification service를 구축하려고 하시나요?

아마도 여러분께 이 포스팅이 유용할지도 모르겠네요.



최근 아이폰 어플리케이션을 런칭하면서 php로

apple push notification service를 구축하는 경험을 했습니다.


APNS(Apple Push Notification Service)는 애플 푸시 노티피케이션 서비스입니다.




아이폰에서 흔히 경험할 수 있는

어플리케이션에서 마치 문자메시지처럼 새로운 소식이나 메시지를 알려주는 서비스입니다.



대략적인 작동방식에 대한 설명을 드리자면

애플의 푸시 서버로 특정 애플 기기에 대한 token과 메시지 내용을 전달하면

애플의 푸시서버는 이를 받아 해당 token에 해당하는 기기로

푸시 메시지를 쏩니다.




APNS에 대한 애플의 문서를 번역한 자료입니다. 구축전에 한번 가볍게 읽어보시면 좋을것 같습니다.




자 그럼 이제 PHP버전의 APNS 라이브러리를 소개합니다.



1. Esay APNS




2. APNS-PHP




3. PHP-APNS





PHP의 APNS 라이브러리는 위의 3가지로 크게 나뉩니다.

그중에서도 제가 가장 강추하는 라이브러리는 1번에 소개된 EASY APNS 입니다.


추천하는 이유는 구축하기 가장 쉽고, 메뉴얼도 가장 깔끔합니다.


EASY APNS의 설치는 크게 4단계로 구분됩니다.


1. PHP 소스코드 업로드하기

2. mysql 테이블 생성하기

3. 노티피케이션 전송을 위한 cron job 설정하기

4. 아이폰 어플리케이션 소스코드에 APNS 적용하기



각각의 설치 방법은 웹사이트에 방문하시면 아주 친절하게 소개가 되어있습니다.

EASY APNS는 개발버전과 배포버전을 구분하여 push 보내기가 가능하며

사용자가 해당 어플리케이션을 삭제하였는지 feedback에 대한 처리도 하기 때문에

매우 유용합니다.


다만 이것을 구현하실 여러분들이 조금 더 수고해주셔야 하는부분은


EASY APNS의 매뉴얼대로 구축을 마치고 테스트를 하시면

EASY APNS는 사용자의 push 요청을 "큐"로 쌓아두고 있다가

cron job이 실행될때 이 쌓였던 push에 대한 요청들을 한꺼번에 처리합니다.


즉 cron job 설정을 한시간으로 해놓으면 push 가 매시각 한번씩 보내지는 것이고

1일단위로 설정해놓으셨다면 push가 일단위로 보내집니다.


그래서 혹시 즉시성을 요구하는 푸시 서비스를 구현하실때는

APNS 객체의 _pushMessage 메소드를 직접 호출하셔야 합니다.

이는 아마 소스코드 보시면 왠만한 PHP개발자 분들이라면 알수 있기에 자세한 설명은 넘어가겠습니다.



개발자분들의 칼퇴를 기원하며....


출처 : http://trend21c.tistory.com/1049

'iOS' 카테고리의 다른 글

PHP - cURL 비동기 통신  (0) 2013.12.01
셀 높이 조절  (0) 2013.06.25
앱 정보 가져오기 (앱이름, 버전)  (0) 2013.06.19
스토리보드 커스텀 셀 (공개)  (0) 2013.06.12
유니코드 출력  (0) 2013.02.01
Posted by 다오나무
iOS2013. 6. 25. 18:54

This sample code shows how we can create uitableviewcell height dynamically based on the text it consists.
Let assume we have UILabel in cell which contains some text, and code below  creates the appropriate cell in tableview depending on the label size :

1. Lets define some constants for the program:
      #define FONT_SIZE 14.0f
      #define CELL_CONTENT_WIDTH  305.0f
      #define CELL_CONTENT_MARGIN  8.0f

2. Return the height of each cell depending on its label size : 

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
        NSString *text =@"Read your text for each cell here (from Array or Dictionary)";
         // calculating the size of the text/string
        CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
        CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
  
         // Calculating the height of cell
              CGFloat height = MAX(size.height, 44.0f);
              return height + (CELL_CONTENT_MARGIN * 2);

}

3.  Now lets create cell having UILabel init:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    static NSString *CellIdentifier = @"Cell";
     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
    }
// Below two line code will insure that there will be no overlapping/blurr of custom views created inside cell
    for (UIView * view in cell.contentView.subviews) {
        [view removeFromSuperview];
    }


          NSString *text = @"Read your text for each cell here (from Array or Dictionary)";
          UILabel *descriptionLabel = [[UILabel alloc] initWithFrame: CGRectMake(10, 8, 278, 40)];
          // 40 choose the height of label double of normal label size
           descriptionLabel.adjustsFontSizeToFitWidth = NO;
           descriptionLabel.text = text;
             [cell.contentView addSubview:descriptionLabel];
             [descriptionLabel setNumberOfLines:0];
           CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
           CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
           [descriptionLabel setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 44.0f))];

 return cell;
    
}

Posted by 다오나무
iOS2013. 6. 19. 17:39

////////////////////////////////////////////////////////////////////////////////////

// 앱 정보 가져오기

NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary];


// 앱 버전

NSString *szAppVersion = [ infoDict objectForKey:@"CFBundleShortVersionString"];

// 빌드 버전

NSString *szAppBuildVer = [ infoDict objectForKey:@"CFBundleVersion"];

// 앱 이름

NSString *szAppName= [ infoDict objectForKey:@"CFBundleDisplayName"];

Posted by 다오나무
iOS2013. 6. 12. 16:00

파트 1

http://www.youtube.com/watch?annotation_id=annotation_989047&v=fnzkcV_XUw8&src_vid=0AsChJk422c&feature=iv


파트 2

https://www.youtube.com/watch?v=0AsChJk422c&noredirect=1

'iOS' 카테고리의 다른 글

셀 높이 조절  (0) 2013.06.25
앱 정보 가져오기 (앱이름, 버전)  (0) 2013.06.19
유니코드 출력  (0) 2013.02.01
[iPhone]keychain 을 이용한 id, password 저장  (0) 2013.01.16
[iPhone]keychain 을 이용한 id, password 저장  (0) 2012.12.18
Posted by 다오나무
iOS2013. 2. 1. 17:39

아이폰 어플을 개발하다 보면

그냥 키보드로 입력하는 문자이외에 유니코드에 들어있는 특수문자를 출력해야 할 필요가 생깁니다.

그럴 때 사용하는 필자의 방법인데요 별것 아니지만 혹시 생각이 안날까봐 적어둡니다.

1. 코드표를 확인한다.
2. unichar 변수에 코드값을 입력한다.
3. NSString로 변형한다.
4. 출력한다.


그럼 자세히 알아보죠..

1. 코드표를 확인한다.
여러가지 방법이 있겠지만 저같은 경우엔 맥북에서 확인할때 오픈오피스를 주로 사용합니다.


메뉴- 삽입 - 기호/문자표 를 클릭합니다.

필요한 특수문자를 잘 찾아봅니다. 폰트를 잘보시고요 아이폰에 있는 폰트를 선택해서 하셔야 하죠. 없는 폰트에서 고르면...
아이폰에서도 안나오겠죠?

2. unichar 변수에 코드값을 입력한다.

unichar unicode = 0x00A9;//©


3. NSString로 변형한다.

NSString * tmp = [NSString stringWithCharacters: &unicode length:1];


4. 출력한다.

NSLog(@"출력 %@",tmp);



쉽죠?
오늘은 여기까지..

Posted by 다오나무
iOS2013. 1. 16. 15:27

NSUserDefaults 에 사용자 정보를 저장하기에는 그렇고 별도로 암호화/복호화 하기도 번거롭고 해서
중요한 정보인 사용자 id, password를 저장해놓고 사용하기 위해 keychain을 사용하였다.


//애플 래퍼런스 문서 (해당 셈플코드에서 KeychainItemWrapper 클래스 소스를 가져다 쓰기바람 )


// framework 에 Security.framework 추가.

NSString *idKey = @"id";
NSString *pwKey = @"password";

KeychainItemWrapper * idKeychain = [[KeychainItemWrapper alloc] initWithIdentifier:idKey accessGroup:nil];
[idKeychain setObject:idValue forKey:(id)kSecAttrAccount];
KeychainItemWrapper * pwKeychain = [[KeychainItemWrapper alloc] initWithIdentifier:pwKey accessGroup:nil];
[pwKeychain setObject:pwValue forKey:(id)kSecValueData];
//[idKeychain resetKeychainItem];
//[pwKeychain resetKeychainItem];
NSLog(@"id  :  %@",[idKeychain objectForKey:(id)kSecAttrAccount]);
NSLog(@"pw :  %@",[pwKeychain objectForKey:(id)kSecValueData]);
[idKeychain release];
[pwKeychain release];

위와 같이 사용할 경우 id, pw를 저장 할 수 있으며 resetKeychainItem을 사용하여 초기화 시킬 수 도 있다.
해당 key(kSecAttrAccount,kSecValueData) 값당 하나의 데이터 밖에 저장할 수 없는 구조인거 같다.
자세한 내용은 문서와 셈플 코드를 참조...

Posted by 다오나무
iOS2012. 12. 18. 15:37

NSUserDefaults 에 사용자 정보를 저장하기에는 그렇고 별도로 암호화/복호화 하기도 번거롭고 해서
중요한 정보인 사용자 id, password를 저장해놓고 사용하기 위해 keychain을 사용하였다.


//애플 래퍼런스 문서 (해당 셈플코드에서 KeychainItemWrapper 클래스 소스를 가져다 쓰기바람 )


// framework 에 Security.framework 추가.

NSString *idKey = @"id";
NSString *pwKey = @"password";

KeychainItemWrapper * idKeychain = [[KeychainItemWrapper alloc] initWithIdentifier:idKey accessGroup:nil];
[idKeychain setObject:idValue forKey:(id)kSecAttrAccount];
KeychainItemWrapper * pwKeychain = [[KeychainItemWrapper alloc] initWithIdentifier:pwKey accessGroup:nil];
[pwKeychain setObject:pwValue forKey:(id)kSecValueData];
//[idKeychain resetKeychainItem];
//[pwKeychain resetKeychainItem];
NSLog(@"id  :  %@",[idKeychain objectForKey:(id)kSecAttrAccount]);
NSLog(@"pw :  %@",[pwKeychain objectForKey:(id)kSecValueData]);
[idKeychain release];
[pwKeychain release];

위와 같이 사용할 경우 id, pw를 저장 할 수 있으며 resetKeychainItem을 사용하여 초기화 시킬 수 도 있다.
해당 key(kSecAttrAccount,kSecValueData) 값당 하나의 데이터 밖에 저장할 수 없는 구조인거 같다.
자세한 내용은 문서와 셈플 코드를 참조...

Posted by 다오나무
iOS2012. 12. 18. 12:14

왼쪽 그림 하단의 버튼들은 상품카테고리를 나타낸다.  화면에 약 4개의 카테고리 밖에는 보여줄 수 없기 때문에 나머지 카테고리를 보여주기 위해 가로 스크롤뷰를 이용하여 좌우로 네비게시션이 가능하게 구성되어 있다.

아이폰 앱들 중 많은 것들이 상단이나 하단에 서브 메뉴의 형태로 가로 스크롤을 이용하는 것들이 많다. 예로 든 deal$의 경우에는 가로 스크롤에 추가로, 버튼을 클릭하였을 때 버튼의 크기를 키우는 효과를 추가로 사용하고 있다.

포스트에 첨부한 프로젝트 샘플은 간단히 가로 스크롤만을 구현한 것이다. 물론 개발은 비교적 쉽다. 기존의 스크롤뷰를   사용하면 된다.  

간단히 주석을 달아 놓았으니 HorizontalScrollMenuView와 HorizontalScrollMenuViewController 두 개의 클래스를 참고하면된다.













Posted by 다오나무
iOS2012. 10. 23. 13:44

원문(리스토어와 인엡 풀소스) - http://www.changwoo.net/bbs/bbsDetail.do?&num=545

애플의 정책이 바뀌어 non-consume in-app은 무조건 restore(복구) UI가 있어야 합니다, 안그러면 리젝사유가 되어 가슴아픈 경험을 하게 됩니다.

그에 따른 로직을 올립니다.

버튼에 이벤트로 
- (void) onClickRestore:(id)sender 를 호출하면
checkPurchasedItems -> 
 상황1 - 로그인 취소- > 
(void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error  
 상황2  - 로그인 성공 -> (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue

요런 로직입니당
로그인이 성공하면
paymentQueueRestoreCompletedTransactionsFinished함수에서 그동안 구입한 인엡에 대한 목록(product id)을 얻어옵니다
그러면 콜백받은 인엡목록과 본어플의 인엡의 코드(product id)를 검사해서 있는지 확인한후 처리 하시면 되겠습니다.




//복구 버튼 이벤트
- (
void) onClickRestore:(id)sender
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSArray *languages = [defaults objectForKey:@"AppleLanguages"];
    NSString *currentLanguage = [languages objectAtIndex:0];
     
    NSString *requestString = @"";
    //Language process
    if ([currentLanguage isEqualToString:@"ko"]) {
        //        requestString = @"복구 요청중";
    }else{
        //        requestString = @"Restore requesting";
    }
     
    HUD = [[MBProgressHUD alloc] initWithWindow:[[UIApplication sharedApplication] keyWindow]];
    //    HUD.center = CGPointMake(10, 110);
    [[[UIApplication sharedApplication] keyWindow] addSubview:HUD];
    HUD.delegate = self;
    HUD.labelText = requestString;
    [HUD show:YES];   
     
    [self checkPurchasedItems];
}
 
- (void) checkPurchasedItems
{
     
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
    [HUD show:NO];
     
}// Call This Function
 
- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions
{
    NSLog(@"- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions ");
}
// Sent when an error is encountered while adding transactions from the user's purchase history back to the queue.
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
    NSLog(@"- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error ");   
    [HUD hide:YES];
}
// Then this is called
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
    NSLog(@"%@",queue );
    NSLog(@"Restored Transactions are once again in Queue for purchasing %@",[queue transactions]); 
     
    NSMutableArray *purchasedItemIDs = [[NSMutableArray alloc] init];
    NSLog(@"received restored transactions: %i", queue.transactions.count);
     
     
    //결재 기록이 없을때 alert 뛰우기
    if(queue.transactions.count==0){
        //        NSString *fileMessage = NSLocalizedString(@"NOTRESTORE", @"restore");
         
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        NSArray *languages = [defaults objectForKey:@"AppleLanguages"];
        NSString *currentLanguage = [languages objectAtIndex:0];
         
        NSString *failMessage;
        //Language process
        if ([currentLanguage isEqualToString:@"ko"]) {
            failMessage = @"구매 기록이 없습니다.";
        }else{
            failMessage = @"There is no record of your purchase.";
        }
         
        UIAlertView *resultView = [[UIAlertView alloc] initWithTitle:@"Failed"
                                                             message:failMessage
                                                            delegate:self
                                                   cancelButtonTitle:nil
                                                   otherButtonTitles:@"OK", nil];
        [resultView show];
    }
     
    for (SKPaymentTransaction *transaction in queue.transactions)
    {
        NSString *productID = transaction.payment.productIdentifier;
        [purchasedItemIDs addObject:productID];
        NSLog (@"product id is %@" , productID);
        // here put an if/then statement to write files based on previously purchased items
        // example if ([productID isequaltostring: @"youruniqueproductidentifier]){write files} else { nslog sorry}
         
        if([productID isEqualToString:KONGLISH_PRODUCTID])
        {
            //재구입확인dh
            NSLog(@"already buy");
        }
    
     
    [HUD hide:YES];
     
}







  • 2012/06/25 11:57답글

    신고

    유용하게 잘 사용했습니다~
    더 요약하자면 핵심은 이거죠

    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];//영구복원 실행

    - (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
    {
    if(error.code!=SKErrorPaymentCancelled)
    {
    //에러
    }
    else {
    //유저 취소시
    }
    }

    // Then this is called
    - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
    {
    if(queue.transactions.count==0){
    //구매한 영구아이템이 없을경우
    return;
    }

    for (SKPaymentTransaction *transaction in queue.transactions)
    {
    //구매한 아이템들에 대한 복원 처리 


    }

  • 2012/07/02 22:15답글

    신고

    깔끔하군요 굿좝~~

Posted by 다오나무