Tag Archives: iPhone

아이폰4 범퍼 장착후에도 사용가능한 유니버셜독 개조하기

사용자 삽입 이미지
저에게는 자그마치 6만9천원이라는 거금을 들여서 구매한 유니버셜독이 있습니다. 그리고 이번에 3GS에서 아이폰4로 갈아타는 행위(?)를 벌였습니다. 그런데 이게 무슨일이란 말입니까… 공짜로 받아온 정품 범퍼를 장착했더니 정품유니버셜독에 꼽을수 있는 방법이 없더군요. 애플은 항상 정품 악세서리에 어떤 불편함을 주어서 다른 악세서리 회사들의 매출을 올릴수 있는 방법을 고려하는것만 같습니다ㅠㅠ

그래서 고민하던중에 독 어댑터중 하나를 이용하여 아이폰4에 딱 들어맞는 유니버셜 독을 만들어 보기로 하였습니다. 지금부터 적을 말들은 하나같이 쉬운 내용인데 막상 해보면 힘듭니다..저도 완성할때쯤엔 바닥의 신문지가 땀으로 젖었다는…ㄷㄷㄷ

사용자 삽입 이미지철물점에 들러 위의 준비물을 준비합시다. 물론 (1)은 철물점에서 파는것이 아닙니다. (2)은 쇠톱으로써 천원입니다. 옆의 사포(3)은 600원을 주었습니다. 총 들인 비용은 1,600원이 되겠습니다.

사용자 삽입 이미지위에서 보았던 유니버셜독 어댑터는 9호입니다. 저 위치에 9라고 써있습니다. 유니버셜독을 구매하면 다양한 어댑터가 이미 들어있는데요 그중에 가장 큰 홈입니다. 아마도 아이팟 클래식 용인듯 합니다.

사용자 삽입 이미지이제 아래쪽을 톱을 썰어냅니다. 이거 생각보다 둥글둥글해서 잘라내기 힘듭니다.

사용자 삽입 이미지자르실때 유의하실점은 위의 숫자가 적힌 부분들을 잘라서는 안된다는 것입니다. 위의 사진은 흔들려서 잘 안보이지만 (2)와 (3)에 유니버셜독에 고정되기 위한 홈이 나와있습니다. 거기만 딱 살아남을 정도로 잘라내시면 됩니다.

사용자 삽입 이미지결과적으로 위와 같은 모습을 가지게 됩니다. 여기서는 홈이 좀 보이네요. 위와 아래의 저 3개의 홈들이 멀쩡히 살아있어야 합니다. 그리고 나머지는 최대한 깎아내셔야 합니다. 물론 적당히 톱질한 다음에 사포질을 꾸준히 하시면 되겠습니다.

사용자 삽입 이미지완성이 되면 대충 이정도의 느낌입니다. 아래쪽정도는 쑥 들어갈 정도가 되면 완성이라고 보시면 되겠습니다.

사용자 삽입 이미지이제 유니버셜독에 장착해 보았습니다. 장착후에 떨어지지 않고 잘 붙어있으면 성공입니다. 여기에 아이폰4를 꼽아보시면 잘 장착이 됩니다. 장착화면은 젤 처음 화면에 있으니 참고하시면 되겠네요. 그런데 아주 작은 문제점은 아이폰4를 껴두시면 독과 직접적으로 맞닫는 부분이 살짝 찍히곤 합니다. 물론 범퍼의 고무부분인데요. 계속 써보니 별로 신경쓸만한 부분은 아닙니다. 빼서 가지고 다니면 금세 원상복귀 되더군요.

이런 눈에 잘 띄지도 않는 찍히는 자국에 민감하신분이라면 이 시도는 안하시는게 좋겠습니다.

결과적으로는 아주 대 만족입니다. 유니버셜독을 팔아야 하나 고민중이었는데 아주 좋네요 -_-b

[iPhone/Java] 내가 만든 어플에 Push Notification 적용하기

사용자 삽입 이미지
오늘은 애플사에서 제공하는 Apple Push Notification Service 줄여서 APNS를 사용해서 나의 어플리케이션이 메시지를 푸싱하는것에 대해 간단하게 정리해 보겠습니다. 애플에서 제공하는 푸시의 경우 위의 프리젠테이션에서 볼 수 있듯이 써드파티의 서버에서 APNS서버로 메시지를 보내면 APNS에서 해당 디바이스에 직접적으로 메시지를 전달해주는 일을 합니다. 실제로 테스트 해본 결과 단 몇초안에 메시지가 전달이 되더군요. 와우!

1. 인증서 준비

사용자 삽입 이미지
위의 화면은 개발자 사이트의 Provisioning Portal – App IDs 에 들어가면 볼 수 있는 화면입니다. 두번째 부분이 Push Notification에 대한 설정인데요. 첫번째 App ID의 경우에는 현재 APNS설정을 할 수 있는 상태입니다. 그리고 두번쨰는 아예 설정이 불가능한 경우입니다. 이 경우는 App ID의 Identifier에 *가 들어간 경우에 해당됩니다. 꼭 어플과 App ID가 1:1매치가 되어야 하겠죠. 3번째는 예상하시다시피 이미 설정이 끝난경우 입니다.

사용자 삽입 이미지
Configure를 눌러 들어간 화면에는 위와같은 화면이 나옵니다. Enable을 눌러주시면 아래의 Configure 버튼이 활성화가 됩니다. 보시면 대충 Push를 보내기 위한 관련 인증서를 발급 받는 부분이라는것을 아실수 있으실텐데요 두가지가 있네요. 한가지는 개발용 하나는 실제 서비스용입니다. 우선은 시범적으로 개발용만 발급받아보겠습니다. 실제 서비스때는 밑의 것을 발급받아 사용하시면 됩니다.

사용자 삽입 이미지
위와 같은 화면이 나옵니다. 아마 대부분의 개발자분들이 이 화면을 보시면 어떤것이 필요한 것인지 감이 오실것이라 생각되네요. 잘 모르시겠다면 [Apple Program 이용가이드]의 인증서 등록 부분을 참고하시면 될것 같네요. 화면이 요즘과 좀 많이 달라지긴 했지만 참고하시는데에는 무리가 없을것입니다. 저때에 사용하셨던 CSR파일을 그대로 이용하시면 됩니다.

사용자 삽입 이미지
잠시후에 자동으로 인증서가 발급됩니다. 위와같이 화면이 뜨게 됩니다.

사용자 삽입 이미지
이제 인증서를 다운받을 수 있게 되는데요, 위에 보이는 Download버튼을 눌러 인증서를 다운 받습니다. 그리고 더블클릭하여 시스템의 인증서로 등록하여 줍니다.

aps_developer_identity.cer – 개발용 인증서
aps_production_identity.cer – 실서비스용 인증서

맥의 유틸리티 – 인증서 메뉴에 가보면 위와 같이 Push Service에 대한 인증서가 등록된것을 확인하실 수 있습니다. 이제 해당 인증서와 아래에 선택한것과 같이 CSR 발급에 사용되었던 개인키(Private Key)를 동시에 선택을 한후에 마우스 오른쪽 버튼을 눌러 “외부로 보내기”(기억이 확실치 않네요; 아무튼 Export입니다)를 하여 줍니다. p12라는 확장자의 파일로 저장이 가능합니다. 이때에 암호를 정할 수 있는데 적절한 암호를 입력하여 줍니다.

2. 아이폰 어플리케이션 수정

이제 아이폰 어플리케이션에 Push Service를 등록할 수 있도록 몇가지 추가를 해야 합니다. -AppDelegate.m 파일에 다음의 내용을 추가합니다.

- (void)application:(UIApplication *)application 
    didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken 
{ 
 NSMutableString *deviceId = [NSMutableString string]; 
 const unsigned char* ptr = (const unsigned char*) [deviceToken bytes]; 

 for(int i = 0 ; i < 32 ; i++) 
 { 
  [deviceId appendFormat:@"%02x", ptr[i]]; 
 } 

 NSLog(@"APNS Device Token: %@", deviceId); 
}

위의 추가된 코드는 어플리케이션이 최초 실행될때에 어플리케이션이 푸시서비스를 이용함을 알리고 허용할지를 물어보게 하고 사용자의 동의를 얻었을 경우 실행됩니다. APNS에 디바이스 정보를 등록하고 64바이트의 문자열을 받아오게 됩니다. 마지막에 NSLog로 확인을 하게 되는 deviceId를 써드파티 서비스의 서버로 전송하여 관리하시면 됩니다.

- (void)application:(UIApplication *)application
    didReceiveRemoteNotification:(NSDictionary *)userInfo
{ 
 NSString *string = [NSString stringWithFormat:@"%@", userInfo]; 
 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil 
                             message:string delegate:nil
                             cancelButtonTitle:@"OK"
                             otherButtonTitles:nil]; 
 [alert show]; 
 [alert release]; 
}

위의 새로 추가된 메서드는 어플리케이션이 푸시를 받았을 경우 호출되는 메서드입니다. 그냥 받은 메시지를 그대로 찍도록 해보았습니다. 넘어오는 데이터에 대해서는 직접 한번 디버깅하여 보시길 추천해드립니다.

사용자 삽입 이미지

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
 NSDictionary *userInfo = [launchOptions objectForKey:
              UIApplicationLaunchOptionsRemoteNotificationKey]; 

 if(userInfo != nil) 
 { 
  [self application:application didFinishLaunchingWithOptions:userInfo]; 
 } 

 // APNS에 디바이스를 등록한다. 
 [[UIApplication sharedApplication] registerForRemoteNotificationTypes: 
  UIRemoteNotificationTypeAlert| 
  UIRemoteNotificationTypeBadge| 
  UIRemoteNotificationTypeSound]; 

 return YES; 
}

이제 하이라이트입니다. 위의 메서드는 어플리케이션이 실행될때에 호출이 됩니다. 요즘은 URI 스키마 혹은 푸시 서비스를 통해 어플리케이션을 실행할 수 있게 되었고 관련 옵션들이 launchOptions인자로 넘어오게 됩니다.

위의 경우에는 어플리케이션이 실행되어있지 않은 경우 푸시를 받아서 어플리케이션이 실행될때 관련 정보가 launchOptions에 담겨오게 되며 그 정보를 가지고 didFinishLaunchingWithOptions를 재호출하는 로직입니다. 그 뒤에 보면 나와있는 APNS등록 부분이 사용자에게 푸시를 허용할지 물어보는 부분이 되겠습니다.

이때에 알아두실 점은 위의 메서드가 구현된 시점부터 원래 사용되던 다음의 메서드는 사용되지 않습니다.

- (void)applicationDidFinishLaunching:(UIApplication *)application 
{ 
 // didFinishLaunchingWithOptions를 구현할 경우 사용되지 않는다. 
}

3. 푸시 서버 준비

이 블로깅에서는 푸시 서버를 Java기반에서 개발하는것으로 설명합니다. 검색해 보면 PHP, Ruby, Python등 매우 다양한 언어로 이미 포팅되어 잘 만들어진 라이브러리도 많이 있더군요. 저도 역시나 잘 만들어진(실제로 여러 포럼에서 추천받는) javapns를 사용하도록 하겠습니다.

필요한 JAR 파일은 다음과 같습니다.

javapns
log4j
bcprov-ext
commons-io
commons-lang

 

이제 해당 홈페이지에 나와있는 간단한 예제를 실행해 보도록 하겠습니다. 다음 소스에서 사용되는 iPhoneId의 경우 didRegisterForRemoteNotificationsWithDeviceToken 메서드에서 언급되었던 deviceId값이며 certificate의 경우 인증서 준비단계에서 만들었던 p12확장자 파일을 뜻합니다. passwd는 p12를 만들당시에 물어보았던 비밀번호입니다.

public class Push {
     // APNs Server Host & port
     private static final String HOST = "gateway.sandbox.push.apple.com";
     private static final int PORT = 2195;

     // Badge
     private static final int BADGE = 66;

     // iPhone's UDID (64-char device token)
     private static String iPhoneId = "2ed202ac08ea9...cf8d55910df290567037dcc4";
     private static String certificate = "/absolute/path/to/my/certificate";
     private static String passwd = "mycertificatepassword";

     public static void main( String[] args ) throws Exception {

        System.out.println( "Setting up Push notification" );

        try {
             // Setup up a simple message
             PayLoad aPayload = new PayLoad();
             aPayload.addBadge( BADGE );
             aPayload.addAlert("Hello World!");
             aPayload.addSound("default");
             System.out.println( "Payload setup successfull." );

             System.out.println ( aPayload );

             // Get PushNotification Instance
             PushNotificationManager pushManager = 
                PushNotificationManager.getInstance();

             // Link iPhone's UDID (64-char device token) to a stringName
             pushManager.addDevice("iPhone", iPhoneId);
             System.out.println( "iPhone UDID taken." );

             System.out.println( "Token: " +
                pushManager.getDevice( "iPhone" ).getToken() );

             // Get iPhone client
             Device client = pushManager.getDevice( "iPhone" );
             System.out.println( "Client setup successfull." );

             // Initialize connection
             pushManager.initializeConnection( HOST, PORT, certificate, passwd, 
                SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);
             System.out.println( "Connection initialized..." );

             // Send message
             pushManager.sendNotification( client, aPayload );
             System.out.println( "Message sent!" );

             System.out.println( "# of attempts: " +
                pushManager.getRetryAttempts() );
             pushManager.stopConnection();

             System.out.println( "done" );

         } catch (Exception e) {
             e.printStackTrace();
         }
     }
 }

사용자 삽입 이미지

예제코드에 이어 바로 결과 화면을 붙여보았습니다. 위와같이 메시지를 전송하면 잠자고 있던 아이팟이 알람을 울리게 됩니다.

여기서 한가지 더 알아두셔야 할 점으로 Feedback이라는 것이 있습니다. 위와 같은 Push의 경우에는 해당 사용자에게 제대로 메시지가 전달 되었는지 여부를 확인할 길이 없습니다. 만약에 10만명의 푸시 사용자가 가입을 했고 5만명이 해당 어플의 푸시를 받지 않겠다고 설정을 바꾸었거나 삭제를 했다면 서비스는 일일이 받지 않는 사용자에게 푸시를 날리느라 시간을 낭비하게 되겠죠. 그래서 이 Feedback을 이용하여 사용하지 않는 사용자의 리스트를 받아오게 됩니다.

public class Feedback {
     // APNs Server Host & port
     private static final String HOST = "feedback.push.apple.com";
     private static final int PORT = 2196;

     private static String certificate = "/absolute/path/to/certificate";
     private static String passwd = "certificatePassword";

     public static void main( String[] args ) throws Exception {

        try {
             // Get FeedbackServiceManager Instance
             FeedbackServiceManager feedbackManager = 
                FeedbackServiceManager.getInstance();

             // Initialize connection
             LinkedList<Device> devices = feedbackManager.getDevices( HOST, PORT, 
                certificate, passwd, SSLConnectionHelper.KEYSTORE_TYPE_PKCS12 );
             System.out.println( "Connection initialized..." );

             System.out.println( "Devices returned: " + devices.size() );

             ListIterator<Device> itr = devices.listIterator();
             while ( itr.hasNext() ) {
                 Device device = itr.next();
                 System.out.println( "Device: id=[" + device.getId() +
                " token=[" + device.getToken() + "]" );
             }

             System.out.println( "done" );

         } catch (Exception e) {
             e.printStackTrace();
         }
     }
}

사용자 삽입 이미지

테스트 몇번 해보았을 뿐이라 사용하지 않는 사용자는 존재하지 않는군요. 위와같은 명령을 하루 한번정도의 텀으로 주기적으로 실행하여 발송 목록에서 제거하는 등의 처리를 하시면 되겠습니다. 더 많은 관련 문서는 javapns의 WIKI 페이지에 잘 나와있습니다^^