Friday, 21 October 2011

[DEV] iPhone iAd Programming - 마소


iAd는 iOS4부터 등장한 광고 방식의 하나다(스티브 잡스가 WWDC 2010에서 iAd로 만든 애플리케이션을 갖고 나와 직접 시연을 하기도 했다). 기존에 아이폰에서는 광고를 노출하는 방법으로 admob이라는 것이 많이 쓰였다(www.admob.com, 현재는 구글이 인수한 상태다). 이 admob과 iAd는 사용자에게 노출되는 초기 화면에 배너 형태의 뷰를 채택했다.
두 가지 방식 모두 아이폰 개발자들에게 개발킷을 제공하고 있다. 두 가지 방식 모두 아이폰 개발자들에게 개발킷을 제공하고 있다.
<화면 1> iAd의 일반적인 형태(좌)와 iAd의 예(출처 : www.admob.com)>
iAd JS
애플은 iAd를 
사용해 광고를 작성하는 사람들을 위해 샘플로 iAdTester 애플리케이션과 여러 가지 샘플 리소스를 제공하고 있다. iAd JS가 바로 그것이다. iAd JS를 설치하고 iAd가 동작하는 원리를 알아보자.

iAd JS는 iOS4와 같이 제공되는 iAd를 위한 개발킷이
다. JS라는 이름에서도 알 수 있듯이 JavaScript 라이브러리와 Web Kit 기반의 브라우저 모듈로 구성돼 있다. 현재 설치를 위해 필요한 사항은 다음과 같다.  
Xcode 3.2.3 이상 맥 OS X v10.6, 아이폰4 SDK(iPhone simulator)
설치를 위해서는 애플의 개발자 사이트에서 해당 SDK를 다운받아 설치하면 된다. 현재 얻을 수 있는 최신 버전은 4.0.2다.

Xcode 설치 후에 iAd 
JS를 설치한다. 설치 후 디렉토리는 <화면 2>와 같이 구성된다.

iAdJS라는 디렉토리의 하위 디렉토리에 iAd에서 사용되는 
각종 버튼이나 리소스들이 포함돼 있다. 각 디렉토리의 성격은 <표 1>과 같다.
<표1> 각 디렉토리 정보
이제 iAd 테스트 프로그램을 아이폰에 설치하고 샘플용으로 제작된 iAd 애플리케이션을 실행해 보자. 이것을 통해 iAd 배너로 아이폰에서 표현될 수 있는 여러 가지 광고 형태를 알 수 있다.
sample.ad의 설치와 활용
iAdTester.app를 아이튠즈를 이용해 설치한다. 테스트 애플리케이션은 단지 
아이튠즈의 ‘응용 프로그램’ 디렉토리로 드래그&드롭하는 것으로 끝이다. <화면 5>와 같은 형태로 설치된다. 동기화 시켜주는 것을 기억하자.
<화면 3> iAdTester 애플리케이션의 설치
동기화되면 아이폰에서 <화면 4>의 왼쪽과 같이 애플리케이션 아이콘이 나타난다. 실행하면 오른쪽과 같은 화면을 볼 수 있다. 일반적으로 Xcode로 애플리케이션을 만들 때는 iAd 버튼이 Object 창에 포함돼 있다. 따라서 IB로 원하는 위치로 가져와 배치할 수도 있다.
<화면 4> 테스트 프로그램의 아이콘(좌)과 iAd tester 프로그램 초기화면
iAdTester.app 애플리케이션이 설치된 후에는 iAdJS/ samples/ 디렉토리 아래에 있는 sample.ad라는 디렉토리 전체를 zip으로 압축, iTunes의 iAd Tester 도큐멘트 디렉토리에 드래그&드롭한다. 그리고 동기화해 sample.ad.zip 파일이 아이폰으로 전송되도록 한다.
<화면 5> 아이튠즈를 통해 iAd 샘플 전송하기
iAd JS 패키지에 포함된 iAdTester.app 프로그램으로 사용자는 간단한 동작 테스트를 해 볼 수 있다. <화면 4>의 오른쪽 화면을 보면 ‘Pick Ad’라는 버튼이 있는데, 이것으로 패키지에 포함된 샘플 파일을 테스트할 수 있다.

이 과정에서도 알 수 있지만 실제 iAd를 위한 화면은 *.ad라는 확장자를 가진 번들 파
일로 구성된다. *.ad 파일은 압축된 형태로, 아이튠즈를 통해 아이폰으로 전송될 수 있으며, 원격지에 있는 파일들도 접근할 수 있게 된다. 
*.ad 파일의 구조
압축된 형태로 된 *.ad 파일은 <화면 6>과 같은 디렉토리 구조로 돼 있다. <화면 6>이 
iAd의 기본이 되는 디렉토리 형태다.
<화면 6> iAd sample 디렉토리
sample.ad의 각 디렉토리와 파일을 살펴보자. 
● AdUnit
이곳에 iAd의 최초 페이지
가 위치하게 된다(index.html 파일로 시작된다).
● Creatives
이 디렉토리 아래에 사용자가 원하는 형태의 배너 버튼 등을 
둘 수 있다. 만약 개발자가 이미지 형태의 버튼을 보여주고 싶으면 이 디렉토리 아래에 서브 디렉토리를 두고 해당 contents를 넣으면 된다. 
● iAd.plist
이 파일은 배너의 여러 가지 속성을 갖고 있는 xml 파일이다. <화면 7>과 같은 속성들을 갖
고 있다.
<화면 7> iAd.plist의 default 구성
version="1.0" encoding="UTF-8"?>
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">


   background-color
  
ffffff
   action
   landing-page
   initial-orientation
  
portrait
   supported-orientations
   portrait
   scrolling
 
 
   accessibility-description
   A Sample Ad
<리스트 1> plist의 xml 파일 내용
● action
화면상에서 사용자가 배너를 터치할 경우 동작에 관한 키다. landing-page, web, call과 같은 값이 있
다. landing-page는 Ad 화면을 iAd 뷰 화면에서 보여주고, web은 웹페이지로 이동하게 된다. call은 전화를 할 수 있도록 한다. <화면 8>과 같이 사용할 수 있다. 
<화면 8> sample ad 최초 화면(좌)과 Ad View 여부 문의
● initial-orientation
최초로 iAd가 실행되었을 경우 초기화 위치를 보여준다. 
portrait, landscape가 사용된다.
● supported-orientation
사용 중에 센서에 의한 iAd 화면의 가로, 세로, 모든 방향의 
지원 여부를 정의해 준다. portrait, landscape, all이 사용된다.
● scrolling
ad 페이지의 스크롤 지원 여부를 결정한다. 
TRUE, FALSE가 사용된다.
● background-color
배너를 터치한 후에 ad페이지로 변경될 때의 화면 색상을 hex 포맷으로 입력
하도록 한다.
● accessibility-description
accessibility가 사용 가능할 때 사용자에게 정보 문구 등을 보여주도록 하는 
키다.
● external-url
ad 번들 내에 있는 것과 다른 ad host의 URL을 사용하고 싶을 때 사용하면 된다. <화면 9>는 
http://www.google.com/을 키 값으로 설정했을 때의 iAd 화면이다.
<화면 9> external-url 설정시
이상으로 iAd에서 사용되는 디렉토리와 속성을 나타내는 plist 파일의 내용을 살펴봤다. 향후 iAd를 통한 광고를 하기 위해 각 사이트마다 모바일 페이지를 별도로 만드는 작업이 필요할 것이다. 
iAd의 구성요소들
이제 iAd의 구성요소들을 살펴보자.
● iAd 배너 프레임의 사이즈
기본적으로 세로로 보
여질 때는 320×50 픽셀 사이즈의 배너가 존재하고 가로로 보여질 때는 480×32 픽셀 사이즈의 배너가 보여진다. iAd를 작성하는 사람들은 배너의 사이즈를 고려해서 작성해야 한다.
● 지원되는 이미지 파일과 소리 파일
배너를 위해 사용될 수 있
는 이미지 파일의 형식은 세 가지인데  GIF, JPG, PNG 등을 지원한다. 각 파일은 투명도 등을 임의로 지정할 수 있다. 이 중에서 PNG 파일의 형식이 가장 높은 해상도를 유지할 수 있는데, 파일의 사이즈는 가장 크다. 백그라운드로 사용할 때 이것을 극복하기 위해 CSS 파일에 타일형태로 지정하거나 WebKit 그라데이션을 이용할 수 있다.
소리파일은 WAV, AIF, MP3, AAC-LC 
등을 지원한다. 가장 적당한 오디오 포맷은 AAC다. 또한 아이폰은 MPEG-4 비디오를 재생하기 위해 H.264 코덱을 사용하고 있다.
iAd는 <표 2>와 같은 비디오 포맷과 사이즈를 지원한다(출처: iAd Design Guidelines). 
<표 2> iAd 지원 비디오 해상도의 정보
● 비주얼 효과들
배너에서는 
WebKit에서 제공되는 비주얼 효과들을 지원한다(3D Fold Out, 3D Boxes, Plane Flip, Drop, Fade In, Wipe). iAd 배너 내부의 Contents가 변경되는 경우도 마찬가지로 3D Box Rotation, 3D Switch, Drop, Fade, Wipe, Panel Flip)과 같은 비주얼 효과들을 지원한다. 
● 웹 기반의 배너 표시
HTML과 JavaScript를 사용해서 다이내믹하게 iAd 버튼을 장식할 수 있다(RSS 
feed로부터의 Headlines, XML feed로부터 스포츠 스코어를 볼 수도 있다. Time of day로 현재 시간을 표시하는 것도 가능하다).
iAd JS 컴포넌트의 활용
iAd JS 컴포넌트의 활용법을 알아보자. 
● 인라인 비디오
기존에 아이폰의 비디오 플레이어
에서 한 페이지로 보여지던 비디오 창이 iAd에서는 HTML5의 도록 한다. 기존 방식과 다른 점은 백그라운드로 애플리케이션이 실행되고 있다는 것이다. core Ad에서 사용되는 비디오 클립은 속도나 여러 가지 이유로 2분을 넘지 않는 것이 좋다.
<화면 10> 비디오 스트리밍
● 인라인 오디오
<화면 11>과 같이 Audio data를 표시하는 오디
오 인디케이터 아이콘 등이 iAd JS를 통해 제공된다.
<화면 11> 오디오 인디케이터 아이콘(출처 : iAd_Design_Guide)
iAd JS에 포함된 컴포넌트 테스트
iAd JS에서 사용되는 여러 가지 컴
포넌트들이 iAdJS/tests 디렉토리에 들어있다. 이들은 iAd.css, iAd.js에 기술돼 있는 스크립트를 읽어서 동작하게 된다. 대표적인 iAd 컴포넌트를 살펴보자.
● Button
버튼은 <화면 12>와 같은 효과를 낼 수 있도록 돼 있다. 
<화면 12> 버튼효과
● CarouselView
<
화면 13>과 같이 돌아가는 아이템 선택 버튼을 가진 뷰를 표시한다. 화면 상에 보이는 영역을 flip하면 메뉴들이 회전하는 애니메이션을 볼 수 있다.
<화면 13> 세로 회전 테이블(좌)와 가로 회전 테이블
NavigationBar
상단에 <화면 14>와 같은 control을 위한 버튼과 바가 표시되는 컴포넌트다. 
<화면 14> NavigationBar
NavigationController
<화면 15>는 툴바 버튼과 네비게이션 바를 애니메이션 효과와 함께 토글하는 컴포넌트다. 
<화면 15> NavigationController
<화면 16> PickerView
PickerView
아이폰에서 사용되는 PickerView와 같은 동작을 하는 컴포넌트다.

이 밖에도 Progress 바를 표시하는 
ProgressView, 아이템의 등급을 별로 표시하는 Rating, 화면의 스크롤 타입을 정의해 놓은 ScrollView, SearchBar를 포함하는 뷰, 아이템을 특정 바(bar) 위에 올려서 분리해 놓은 SegmentedControl, 스위치를 끄고 켜는 형태의 Switch, 옆으로 밀어내기 방식으로 화면 뷰를 변경하는 Slider, 테이블 뷰를 재현한 TableView, 툴바와 탭바의 형식을 보여주는 Toolbar 등의 컴포넌트가 있다.
● TableView
<화면 17>과 같이 여러 개의 개별 셀로 구성된 화면으로 만들 수도 있고, 아이템을 Group
형태로 표현할 수도 있다(<화면 18> 참조).
<화면 17> TableView
<화면 18> Group Table
● ViewScale
화면에 보여질 뷰의 해상도를 조절할 수 있도록 하는 컴포넌트다. 
상단에 폭과 높이를 설정할 수 있는 버튼이 있다.
● 지도와 위치 정보 표시
iAd를 활용해 광고를 할 때, 소비자들에게 쇼핑
할 수 있는 가게의 위치 정보 등을 제공할 때 맵을 사용하면 유용하다. 전체적인 지도 UI는 아이폰에 있는 지도 애플리케이션에서 사용하는 것과 유사하다. 이것을 위해 <화면 19>와 같이 지도와 위치 정보를 표시할 수 있다. 또한 tel 태그를 사용해 전화번호를 사용자에게 제공, 아이폰의 전화 기능과 연동하는 것도 가능하다.
<화면 19> 지도 표지(좌), 전화와 email(출처 : iAd_Design_Guide)
Xcode에서 iAd의 구현
최신 버전의 아이폰 
SDK에는 iAd를 자신의 애플리케이션에 적용하기 위한 Framework와 Object가 제공된다. 애플에서 제공한 iAd 배너를 활용해 iAd test 프로그램을 만들어 보자. 여기서 사용된 Xcode SDK의 버전은 다음과 같다. 3.2.3 버전부터 iAd 배너 Object가 포함되어 있다.
프로젝트의 생성 
새로운 프로젝트로 View-based Application을 선택하고 프로젝트의 이름은 iOS4iAd로 했다. 
IB에서 iAd 배너 Object 가져오기
Xcode 소스 tree에서 iOS4iAdViewController를 선택해 IB를 시작한다. Xcode 3.2.3과 함께 
배포된 IB에서는 <화면 20>과 같은 iAd Object가 추가된 것을 확인할 수 있다. 이것을 IB의 뷰로 드래그해 구성한다. 
<화면 20> iAd Object
iAd framework 추가
 
이제는 아이폰 SDK 4.0에 추가로 제공된 iAd Framework을 추가해야 한다. <화면 21>과 같이 Groups & Files 
트리에서 Frameworks 항목에 추가한다. 
<화면 21> iAd .framework Add
빌드와 테스트 iAd 배너 확인
빌드하면 <화면 22>와 같은 배너가 표시되고, 클릭했
을 때 애플에서 제공하는 테스트 광고를 볼 수 있다(테스트 광고를 보기 위해서는 반드시 인터넷에 연결돼 있어야 한다).
<화면 22> Test App 빌드
<화면 23> 배너를 클릭했을 때의 초기화면
Delegate와 배너 이벤트
iAd 배너를 클릭하면 기존의 애플리케이션과 델리게이트를 통해 상호 동작하게 된다(현재 iAd 
Delegate는 계속 개발 중이다). iAd의 Delegate 함수들은 ADBannerView.h에 정의돼 있다. 따라서 개발자가 Delegate를 구현하지 않아도 기본적인 배너 이벤트는 동작하게 된다. iAd Delegate를 사용하기 위해 다음과 같이 추가한다. 
bannerViewDidLoadAd: 새로운 배너가 로드됐을 때 불려진다.
- bannerViewActionShouldBegin:willLeaveApplication: 배너 뷰
가 실행되기 전에 실행된다.
- bannerViewActionDidFinish: 배너 뷰가 종료됐을 때 불려진다.
bannerView:didFailToReceiveAdWithError: 배너 뷰를 실행하다가 에러가 발생했을 경우 불려진다.  
이 외에도 다음과 같이 배너의 사이즈를 정의해 둔 선언도 있다. 
extern NSString * const ADBannerContentSizeIdentifier320×50
extern NSString * const ADBannerContentSizeIdentifier480×32
<리스트 2>는 iAd 배너가 처음으로 로드될 때 delegate 함수가 어떻게 호출되는지 보여준다. 
- 에서 ADBannerViewDelegate를 추가한다.
#import

#import
@interface iOS4iAdViewController : UIViewController {
  
ADBannerView *banner;
}
@property (nonatomic, retain) IBOutlet ADBannerView *banner;
@end
-
에 @synthesize로 banner를 선언한다.
@synthesize banner;
- 메인 뷰가 로드될 때 iAd banner의
delegate를 등록한다.
- (void)viewDidLoad {
     [super viewDidLoad];
     banner.delegate = self;
}
 <리스트 2> delegate 함수의 호출 방법
<리스트 2>에 앞서 언급한 delegate 함수들이 동작하는지 테스트 코드를 작성해 봤다. iAd 배너가 로드되는 경우와 되지 않을 때로 나눠 함수를 호출하게 된다(인터넷 연결 여부에 따라서 iAd 동작이 달라진다).
- (void)bannerView:(ADBannerView*)banner didFailToReceiveAdWithError:(NSError *)error
{
  
NSLog(@"배너가 로드되지 않았습니다.");
   UIAlertView *alert; = [[UIAlertView alloc]
   initWithTitle:@""
  
message:@"iAd배너가 로드되지 않았습니다."
   delegate:self
   cancelButtonTitle:@"확인"
   otherButtonTitles:nil
 
  [alert show];
   [alert release];
}
<리스트 3> iAd 배너 load fail 예외 처리
<화면 24> 네트워크가 사용 불가능한 상황
(void)bannerViewDidLoadAd:(ADBannerView
*)banner {
   NSLog(@"배너가 로드되었습니다.");
   UIAlertView *alert; = [[UIAlertView alloc]
  
initWithTitle:@""
   message:@"iAd 배너가 로드되었습니다."
   delegate:self
   cancelButtonTitle:@"확인"
  
otherButtonTitles:nil
   [alert show];
   [alert release];
}
<리스트 4> iAd 배너 load enable 상태
<화면 25> 네트워크가 사용 가능한 상황
이번 호에 사용된 소스코드들은 <이달의 디스켓>을 통해 확인해 보길 바란다.
참고자료
1. 
ADBannerView_Ref.pdf
2. ADBannerViewDelegate_Ref.pdf
3. iAd_Design_Guide.pdf
4. iAd_Guide.pdf
5. iAd_ReferenceCollection.pdf

[Dev] 모바일 광고 솔루션 '카울리' 튜토리얼 -마소


국내 첫 번째 모바일 광고 솔루션 ‘카울리’퓨쳐스트림네트웍스에서는 국내 최초로 모바일 광고 솔루션인 카울리 시스템을 지난 4월에 오픈했다. 카울리 시스템을 활용해 광고 수익을 얻는 방법을 알아보자.

먼저, 카울리 광고 시스템을 적용하는 절차를 살펴보자
- 카울리 홈페이지에 애플리케이션 등록(카울리 홈페이지 주소 : http://www.cauly.net)
- 카울리 SDK를 자신의 앱에 적용(SDK는 홈페이지에서 애플리케이션을 등록하면 다운 받을 수 있다)
여기서는 SDK를 본인의 애플리케이션에 적용하는 방법을 중점적으로 살펴본다. 자신의 애플리케이션을 카울리 홈페이지에 등록하는 방법은 가이드 페이지에 친절히 설명돼 있기 때문에 각자 방문해 살펴보는 것으로 대신한다(카울리 가이드 페이지: http://www.cauly.net/guide_index.jsp).

현재 카울리 SDK는 아이폰용 SDK만을 출시한 상태로, 조만간 안드로이드용 SDK와 아이패드용 SDK도 출시할 예정이니 개발자가 선택할 폭이 더욱 넓어질 전망이다. 현재 출시된 아아폰용 SDK를 기준으로 설명을 진행한다. 
카울리 SDK의 구성 및 설치
SDK의 구성
애플리케이션을 성공적으로 등록했다면 이미 카울리 SDK를 다운로드가 됐다. 현재 SDK는 1.0.3 버전까지 출시돼 있지만 버전은 수시로 업그레이드됨으로 항상 새로운 카울리 소식에 귀 기울이도록 하자.

SDK를 다운로드 하면 2개의 압축 파일이 있다.
- CaulySDK- 실제 SDK가 들어있는 파일(압축을 풀면 include 디렉터리가 나옴)
- Cauly-example - 카울리 SDK를 적용한 간단한 예제 프로젝트
설치
카울리 SDK를 적용시키기 위해선 다음 프레임워크를 프로젝트에 포함시켜야 하며, <화면 1>은 프레임워크를 포함시킨 모습이다.

CaulySDK의 압축을 풀고 안에 있는 include 디렉터리를 개발하는 앱에 포함시킨다(<화면 2> 참조).
 Foundation
 UIKit
 CoreGraphics
 MapKit
 QuartzCore
<리스트 1> 카울리 SDK 적용을 위해 포함시킬 프레임워크
<화면 1> 카울리를 위한 프레임워크들을 add시킨 화면
<화면 2> 개발하려는 앱에 카울리 파일들을 add시킨 화면
카울리 SDK적용
카울리 SDK는 광고가 보이는 영역인 카울리 뷰를 제공하는 작업을 수행한다. 개발자는 생성된 카울리 뷰를 자신이 원하는 뷰에 붙여 광고를 노출시키면 되는데, 이때 카울리 뷰를 붙일 객체는 카울리 프로토콜을 따르도록 구현해야 한다. <리스트 2>와 <리스트 3>은 카울리 프로토콜과 카울리 뷰 객체의 인터페이스다.
 @protocol CaulyProtocol
 @required
 - (NSString *) devKey;
 @optional
 - (NSString *) gender; // male, female, all
 - (NSString *) age; // 10, 20, 30, 40, 50, all
 - (NSString *) gps; // 위도, 경도
 - (REFRESH_PERIOD) rollingPeriod;
 // CPC광고 교체주기 REFRESH_PERIOD Type값을 설정.
 - (ANIMATION_TYPE) animationType;
 // CPC광고 교체시 광고가 나오는 애니메이션 설정 ANIMATION_TYPE type값을 설정.
 // 아래의 함수를 정의하면, 광고를 정상적으로 수신하고
 // 뷰를 생성한 후 마지막으로 AdReceiveCompleted를 호출한다.
 // 뷰의 위치를 지정하거나 사이즈를 조정하는 목적으로 활용이 가능하다.
 - (void)AdReceiveCompleted:(CaulyView *)adView;
 // 아래 함수는 CPM광고를 클릭해 CPM광고가 사라지고 나서 호출된다.
 - (void)closeCPMAd;
 @end
<리스트 2> 카울리 프로토콜
 @protocol CaulyProtocol;
 @interface CaulyView : UIView {
 }
 // CPC View 요청
 + (CaulyView *)requestADWithProtocol:(id)delegate;
 // CPM View 요청
 + (CaulyView *)requestFullADWithProtocol:(id)delegate;
 + (NSString *)version;
 @end
<리스트 3> 카울리 뷰
카울리 뷰를 붙이기 위해선 카울리 뷰를 붙이려는 뷰가 카울리 프로토콜을 따라야 한다. 예제 프로젝트에 있는 내용을 통해 카울리 뷰를 담고 있는 뷰 컨트롤러에서 카울리 프로토콜을 작성한 예들을 살펴보자(<리스트 4>, <리스트 5> 참조).
 @interface Cauly_exampleViewController : UIViewController {
     UIWindow *window;
 }
 - (void)init:(UIWindow*)aWindow;
 - (void)AddCPM;
 @end
<리스트 4> 헤더파일
 #pragma mark CaulyProtocol method
 - (NSString *) devKey
 {
    return @"CAULY"; // CAULY는 테스트용 개발코드다. 제품 배포 시에는 발급받은 애플리케이션 고유개발코드로 변환해야 한다.
 }
 // 성별 값을 리턴한다. “male”, “female”, “all”
 - (NSString *) gender
 {
    return @"all";
 }
 // 현재 애플이 실행되는 위치정보값을 리턴한다. “위도, 경도”
 - (NSString *) gps
 {
    return @" ";
 }
 // 광고 교체주기값을 설정한다.
 - (REFRESH_PERIOD) rollingPeriod {
    return TEN_SEC;
 }
 // 광고가 바뀔 때의 효과를 설정한다.
 - (ANIMATION_TYPE) animationType {
    return CURLUP;
 }
 // 광고 데이터를 받고나면 호출된다.
 - (void)AdReceiveCompleted:(CaulyView *)adView {
    NSLog(@"AdReceiveCompleted.");
 }
 // 전면광고를 종료시키면 호출된다.
 // 전면광고와 배너광고를 동시에 노출시킬 수 없기에 전면광고가 종료된 뒤 배너광고를 노출시켜야 한다.
 - (void)closeCPMAd {
 // [caulyCPM removeFromSuperview];
    CaulyView *cauly = nil;
    //CPC 광고 예제 : 320*48 사이즈
    cauly = [CaulyView requestADWithProtocol:self];
    cauly.frame = [self.view convertRect:CGRectMake(0, 20, 320, 48) fromView:self.view.superview];     
    [self.view addSubview:cauly];
 }
 #pragma mark -
<리스트 5> 소스파일(카울리 프로토콜을 구현한 부분)
헤더파일을 통해 알 수 있듯, 카울리 뷰를 담고 있는 객체는 카울리 프로토콜을 구현해야 한다. 카울리 프로토콜에서 반드시 구현해야 하는 메소드는 바로 devKey 메소드다.

이 메소드는 개발자가 개발한 앱의 고유식별자(APP ID)를 리턴하는 메소드로서, 카울리 홈페이지에서 애플리케이션 등록 시 카울리 시스템에서 발급하는 APP ID를 넣어주면 된다. 만일 이 값이 잘못된 값일 경우 광고노출이 정상적으로 이루어지지 않으므로 주의해야 한다.

그 외에 성별, 위치(GPS)정보를 리턴하는 메소드가 있다. 이 메소드들은 옵션사항이지만 이들 정보를 넣어두면 좀 더 타겟팅 된 광고를 제공할 수 있어 사용자들이 광고를 보다 많이 터치하게 돼 그에 따른 개발자의 수익이 증가한다. 따라서 가급적 해당정보를 넣어 두는 것이 좋다.

rollingPeriod 메소드는 광고의 변경주기를 설정하는 메소드다. 만약 메소드를 작성하지 않으면 기본값으로 10초가 설정된다. 설정값은 CaulyProtocol.h에 정의돼, 현재는 10초와 무변경(NONE), 두 가지 옵션만 제공된다(<리스트 6> 참조).
 typedef enum {
    TEN_SEC = 0,
    NONE,
 } REFRESH_PERIOD;
<리스트 6> rollingPeriod 메소드
animationType 메소드는 광고가 바뀔 때 나오는 애니메이션 효과를 설정하는 값을 리턴하는 메소드로 네 가지 애니메이션 효과와 효과없음으로 설정할 수 있다. 설정값은 동일하게 Cauly Protocol.h에 정의돼 있다.
 typedef enum {
    CURLUP = 0,          // 위로 감아올리는 애니메이션
    CURLDOWN,            // 아래로 감아내리는 애니메이션
    FLIPFROMLEFT,        // 왼쪽 방향으로 뒤집는 애니메이션
    FLIPFROMRIGHT,       // 오른쪽 방향으로 뒤집는 애니메이션
    NOANIMATION          // 애니메이션 생략
 } ANIMATION_TYPE;
<리스트 7> animationType 메소드
카울리 프로토콜은 2개의 callBack 메소드를 제공하는데, 하나는 카울리 광고정보를 전달 받았을 때 호출되는 AdReceive Completed 메소드이고 다른 하나는 전면광고를 터치(또는 종료버튼 터치)해 전면광고가 종료될 때 호출되는 closeCPMAd 메소드이다.

현재 카울리는 한 화면에 하나의 배너광고만을 보이도록 제한하고 있다. 또 전면광고와 배너광고를 동시에 보이는 것도 제한하고 있다. 따라서 전면광고가 보인 후 바로 배너광고를 보여주려면 closeCPMAd 메소드를 통해 전면광고가 종료되는 시점을 설정한다.

인터페이스의 사용법은 간단하다. 가장 핵심적인 메소드로서 배너광고(CPC)를 요청하는 requestADWithProtocol 메소드와 전면광고를 요청하는 requestFullADWithProtocol 메소드가 있는데 각 메소드 별 사용법을 <리스트 8>과 <리스트 9>에 작성했다.
    CaulyView* cauly = nil;
    cauly = [CaulyView requestFullADWithProtocol :self];
    cauly.frame = [window convertRect:CGRectMake (0, 0, 320, 480) fromView:window.superview];
    [window addSubview:cauly];
<리스트 8> requestFullADWithProtocol 메소드(전면광고)
requestFullADWithProtocol 메소드를 호출하면 SDK 내부에서 카울리 뷰 객체를 생성해 리턴한다. 이때 카울리 뷰가 이용할 델리게이트 객체를 메소드 인자로 넘겨주게 되는데(<리스트 7>에서는 self객체) 해당 객체는 카울리 프로토콜에서 정의한 메소드들을 구현해놔야 한다. 그 후 생성된 객체를 받아서 프레임을 설정하고 어떤 뷰에 붙일 것인지를 결정해서 붙이면 된다.
    CaulyView* cauly = nil;
    cauly = [CaulyView requestADWithProtocol :self];
    cauly.frame = [self.view convertRect:CGRect Make(0, 20, 320, 48) fromViewelf.view.superview];       
    [self.view addSubview:cauly];
 <리스트 9> requestADWithProtocol 메소드(배너광고)
배너광고도 전면광고와 거의 동일하다. 단지 배너광고는 광고크기가 320x48 이므로 프레임 설정을 이에 맞추면 된다. 성공적으로 광고를 붙였다면 <화면 3>같이 광고가 나오는 실제화면을 만날 수 있다. 
<화면 3> 성공적으로 카울리 뷰를 붙인 화면
고려해야 할 사항
앞서 말했듯 카울리 뷰를 붙일 때는 고려해야 할 사항이 있다. 우선 전면광고의 경우 특별한 제약이 없지만 이미지를 서버로부터 받아와야 하므로 너무 잦은 광고요청을 할 경우 네트워크 사용량이 늘어난다. 배너광고의 경우 하나의 뷰에 광고 하나만 붙이도록 제한을 둔 것은 악의를 갖고 광고를 악용하는 것(이하 어뷰징)을 방지하기 위함이다. 이처럼 어뷰징을 방지하기 위해 개발자들이 요구를 해도 제공하지 않는 기능 및 메소드가 몇 가지 있는데 이것들은 보다 나은 광고환경을 제공해 궁극적으로 개발자와 광고주 모두의 이익을 키우게 하기 위한 정책적 결정이므로 개발자들의 너그럽게 이해해야 한다. 
카울리 플랫폼은 진화 중
이상으로 자신이 개발한 앱에 카울리 SDK를 적용해 광고를 노출시키는 방법에 대해 살펴봤다. 몇 가지 주의사항만 유념한다면 큰 어려움 없이 광고를 노출시킬 수 있을 것이다.

현재 카울리는 계속 발전하고 있다. 지난 4월 SDK 0.9.0 버전이 최초 출시된 이래 몇 번의 업데이트를 거치면서 성능과 안정성이 크게 개선됐으며 다양한 기능이 추가됐다. 하지만 아직 갈 길은 멀다. 다양한 플랫폼을 지원하는 SDK가 속속 출시될 예정이며, 아이폰 SDK도 기능과 안정성, 사용자 편의성을 크게 향상시킨 2.0버전이 출시될 예정이다.

모바일 산업은 하루가 다르게 발전하고 있고 수익창출환경도 끊임없이 변화하고 있다. 카울리는 스스로도 변화하는 환경에 능동적으로 대처하고 있는 만큼, 개발자들은 카울리라는 든든한 동반자를 선택한다면 거친 모바일 산업에서 승자가 될 수 있을 것이라 확신한다.

현재 퓨쳐스트림네트웍스에서는 SDK 작업에 어려움을 겪는 개발자를 위해 고객센터(1544-8867 Cauly@futurestream. co.kr)를 운영 중이며, 언제든 관련내용에 대한 친절한 안내를 받을 수 있으니 개발도중 의문사항 있으면 주저없이 연락하자.



기사원문보기

Thursday, 20 October 2011

[DEV] 아이폰 블루투스 프로그래밍 iPhone Bluetooth Programming


이번 호에서는 iOS에서 사용되는 블루투스의 사양과 특징 및 블루투스를 활용한 데이터 통신 방법에 대해 알아보고 실제로 프로그램을 작성해보자.

<화면 1> 블루투스 로고
블루투스는 1994년에 에릭슨이라는 회사에서 최초로 발표한 근거리 무선통신 규약이다. 다른 표준 규약들이 발전하는 방식과 유사하게 블루투스 SIG(Special Interest Group)가 정식으로 발족했으며, 1999년 5월 20일에 공식적으로 배포됐다(IEEE 802.15.1). 블루투스 SIG에는 소니에릭슨, IBM, 노키아, 도시바 등의 전자제품 회사들이 참여하고 있다.
블루투스는 2.45㎓의 대역폭을 사용해 통신을 하고 있으며, 현재 3.0 버전까지 나와 있다. 각 버전이 올라갈 때마다 속도의 향상과 데이터 통신을 할 수 있게 되는 등 기능의 변화가 있었다. 1.0 버전은 각각의 회사별로 호환성에 문제가 있는 경우가 많이 있었으며, 속도를 논의할 단계가 아니었다. 2002년에 정식으로 배포된 1.1 버전부터 723.1kbps에 달하는 속도를 내게 됐고, 버전 2.0부터는 2.1Mbps라는 속도를 낼 수 있어서 음성이나 간단한 command 뿐 아니라 각 장치가 서로 데이터를 주고받을 수 있는 수준이 됐다.
iOS에서 사용되는 블루투스 프로파일
블루투스는 장치에 따라 지원하는 프로파일들이 따로 있다. 이 프로파일들에 따라 지원하는 방식도 달라진다. <표 1>은 iOS4에서 지원되는 블루투스의 프로파일이다.

<표 1> iOS4에서 지원되는 블루투스 프로파일
각각의 프로파일은 다음과 같은 의미를 갖는다.
HFP(Hands-Free Profile)

일반적으로 핸즈프리를 지원하는 기기에서 사용되는 프로파일이다. 오직 음성만을 지원하며, 주로 자동차에 사용되는 블루투스 기기에서 사용된다. 현재 최신 버전은 1.5이며, iOS4에서 지원하고 있다.
PBAP(Phone Book Access Profile)

전화번호부에 접근하기 위한 프로파일이다. 아이폰에서 <홈> 버튼을 계속 누르고 있으면 시작되는 ‘음성명령’ 애플리케이션 등이 PBAP를 지원하는 프로그램이다.

<화면 2> 아이폰의 음성명령 애플리케이션
A2DP(Advanced Audio Distribution Profile)

헤드셋이나 스피커로 음악을 전송할 때 사용하는 프로파일이다. 아이폰3G와 iOS3 버전부터 이 방식이 지원되기 시작했다. 아이폰으로 음악을 들으려면 직접 화면을 보고 조절할 수 있다.
AVRCP(Audio/Video Remote Control Profile)

오디오 뿐만 아니라 비디오까지 컨트롤 할 수 있다. 아이폰3G, iOS4.1 버전부터 지원된다.
PAN(Personal Area Network Profile)

piconet이라고 불리기도 하는데, 최대 8개의 장치와 마스터-슬레이브로 연결될 수 있는 연결방식이다(IEEE 802.15에 정의돼 있다). 일반적으로 지원영역은 10m 정도이며, 기기간에 연결해 최대 100m까지 사용할 수 있다.
데이터 교환을 위해 필수적으로 지원돼야 하며, 초기 아이폰을 제외하고는 모두 지원된다.
HID(Human Interface Device Profile)

각종 키보드, 마우스, 게이밍 디바이스, 태블릿 등을 지원하는 프로파일이다. 아이폰3GS 이상, iOS4 이상부터 지원되기 시작했다. 이 프로파일을 이용하면 블루투스 키보드를 아이폰이나 아이패드와 연결할 수 있다.

<화면 3> 일반적인 HID  연결 방식(출처 : www.blutooth.com)
블루투스에 대해 좀 더 자세히 알고싶다면 ‘http://ko.wiki pedia.org/wiki/블루투스’를 참고하길 바란다.
블루투스 프로그램 만들기
이제 블루투스의 특징을 이용해 Xcode 상에서 블루투스 프로그램을 만드는 방법을 알아보자.
블루투스의 특징을 활용한 아이폰 프로그램 중에 ‘Bump’라는 앱이 있다. 이 앱은 아이폰끼리 서로 부딪힐 때 지정된 정보들을(명함, 연락처, 사진, 캘린더) 진동과 함께 전달한다. 우리도 이렇게 아이폰끼리 서로 부딪혔을 때 정보를 교환할 수 있는 프로그램을 만들어보자.
GameKit에 대해
아이폰으로 블루투스 프로그램을 하려면 여러 가지 프레임워크 중에서 GameKit이라는 것을 사용해야 한다. 이름에 Game Kit라는 단어가 들어가 있어서 게임과 관련된 것이라고 생각할 수 있는데, 사실상 네트워크와 인터넷과 관련된 여러 가지 기능들을 모아둔 프레임워크라고 생각하면 된다.

<화면 4> GameKit
GameKit는 Game Center, Game Voice controller와 Peer-to-peer Connectivity 등을 담당하는 API를 제공해주는데, P2P 연결에 블루투스를 사용하게 된다.
GKSession 클래스가 ad-hoc 블루투스 또는 로컬 무선 네트워크를 관리해준다. 블루투스를 위해 GKPeerPickerController 객체를 사용해 다른 장치와의 연결 등을 담당한다.
세션의 연결
블루투스 장치들간의 연결은 <그림 1>과 같은 형태로 이뤄진다. 장치들은 Peer ID라는 정보를 갖고 있어 상대방과 연결하게 된다. 연결시에는 GKSession이라는 클래스를 사용한다.

<그림 1> 블루투스 장치들간의 연결
다른 블루투스 장치 탐색
장치를 서로 찾을 경우에도 session mode라는 초기화 방법을 이용한다. 만들게 될 프로그램이 서버로 동작할 수도 있고, 클라이언트로 동작할 수도 있다. 서로를 찾게 하는 동작은 동시에 발생시킬 수도 있고 차례대로 발생시킬 수도 있다. 서버 역할을 하게 되는 앱은 세션의 이름을 string이나 sessionID 형태로 다른 장치에게 알릴 수 있다. 이 때 클라이언트로 동작할 장치는 서버의 sessionID를 찾아서 페어링한다.

<그림 2> 다른 장치를 찾을 경우의 동작
GameKit을 사용하면 각각의 장치를 16대까지 지원할 수 있지만 최소한으로 줄이는 것이 탐색시간을 줄이는 방법이다.
내부적으로 장치를 서버로 동작시키려면 GKSessionMode Server나 GKSessionModePeer의 initWithSessionID: displayName:sessionMode:를 사용한다. availabe 속성을 YES/NO로 설정해 사용할 수 있다.
클라이언트가 연결하겠다는 신호를 보내면 session:did ReceiveConnectionRequestFromPeer: 메소드를 사용해 peerID를 받아 들이고 화면에 표시한다.

<화면 5> 장치 #01(좌)과 장치 #02
오류가 발생되면 acceptConnectionFromPeer:error: 메소드가 호출되고 denyConnectionFromPeer:가 호출된다. 성공적으로 호출되면 session:peer:didChangeState:가 호출될 것이다. 그 후에 diaplayNameForPeer:가 호출돼 아이폰 화면에 연결할 장치의 이름이 표시된다. 블루투스에서는 다른 장치로 연결할 때 연결을 허락받는 절차가 있는데, connectToPeer: withTimeout:이라는 메소드를 사용해 대기시간을 갖는다.
데이터의 교환
연결된 블루투스 장치간에는 데이터 교환 등을 할 수 있다. 데이터의 형식은 사용자가 정의한 어떠한 형태로든 가능하다. 이 때 서로 데이터를 교환하는 중에 오류가 발생하면 sendData ToAllPeers:withDataMode:error:라는 방식으로 주변의 모든 장치로 데이터를 보냈을 때의 에러를 검출할 수 있다.
데이터를 전송할 때 1000Byte 미만으로 보내는 것을 권장한다. 전달할 수 있는 가장 큰 용량의 데이터 사이즈는 87KB로 정의돼있다.
일단 전달된 데이터는 receiveData:fromPeer:inSession: context: 메소드를 사용해 주고 받는다.
연결끊기
작성한 앱이 연결을 끓을 준비가 됐다면 disconnectFrom AllPeers 메소드를 호출한다. disconnectTimeout 메소드를 사용해 끊어진다는 신호를 얼마나 기다릴 것인지 설정할 수도 있다. 연결이 완전히 끊어지면 session:peer:didChangeState: 메소드를 호출해 상태를 처리할 수 있다.
실제 프로그래밍 
이제 아이폰 상에서 동작하는 실제 프로그램을 만들어보자. 프로젝트의 이름은 BT로 한다.
1) View-based Application 템플릿으로 프로젝트를 생성한다(File | New Project...). 프로젝트의 이름은 srBluetoot로 한다.
2) Frameworks tree에서 마우스 오른쪽 버튼을 클릭해 Game Kit.framework를 추가한다.

<화면 6> GameKit.framework의 추가
3) 인터페이스 빌더를 사용해 화면을 <화면 7>과 같이 구성한다. 기능으로는 상대방 장치를 연결하도록 하는 <연결하기>, <연결끊기> 버튼과 메시지를 입력하는 TextField 박스, <메시지 전달하기> 버튼을 배치했다.

<화면 7> 인터페이스 빌더 UI  설계
4) 인터페이스 빌더에서 디자인한 버튼들을 코드로 연결한다. srBluetoothViewController.h 파일에 <리스트 1>과 같이 추가한다.
<리스트 1> GKSession과 UI 오브젝트의 선언
#import
#import
@interface srBluetoothViewController : UIViewController {
   GKSession *currentSession;
   IBOutlet UITextField *txtMessage;
   IBOutlet UIButton *sendMessage;
   IBOutlet UIButton *connect;
   IBOutlet UIButton *disconnect;
}
@property (nonatomic, retain) GKSession *currentSession;
@property (nonatomic, retain) UITextField *txtMessage;
@property (nonatomic, retain) UIButton *sendMessage;
@property (nonatomic, retain) UIButton *connect;
@property (nonatomic, retain) UIButton *disconnect;
-(IBAction) btnSend:(id) sender;
-(IBAction) btnConnect:(id) sender;
-(IBAction) btnDisconnect:(id) sender;
@end
먼저 #import 를 사용해 framework 헤더를 포함한다. 또한 GKSession 클래스의 포인터 객체로 currentSession를 생성한다. 그 후 각각의 UI 버튼과 TextField를 만든다. 각각의 오브젝트에는 retain 방식으로 메모리를 관리하도록 하는 @property 코드를 꼭 넣어줘야 한다. 그리고 버튼을 눌렀을 경우 메시지를 보내는 동작을 위해 btnSend: 함수를 만들었고, 연결을 위해 btnConnect:, 함수의 연결을 끊기 위해 btnDisconnect: 함수를 작성한다.
5) 인터페이스 빌더에서 각각의 오브젝트들과 해당 함수 등을 <화면 8>과 같이 연결한다.

<화면 8> 인터페이스 빌더 연결
6) 아이폰의 진동모드는 AudioToolbox라는 프레임워크를 사용한다. 진동을 위해 다음과 같이 AudioToolbox.framework를 추가한다.
#import
이 헤더를 포함시키고 실제로 사용할 때는 다음과 같은 코드를 사용한다.

AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

<화면 9> 진동을 위한 Audion Toolbox.framework 연결
7) 이제 블루투스로 연결된 아이폰을 서로 부딪쳤을 경우 서로 모션 이벤트를 전달하는 코드를 작성해야 한다. <리스트 2>와 같이 srBluetoothViewController.m에 작성한다.
<리스트 2> 모션 이벤트 전달
// 서로 부딪쳤을 경우 최초로 이벤트를 인식하기 위한 부분
- (void)viewDidAppear:(BOOL)animated {
   [super viewDidAppear:animated];
   [self becomeFirstResponder];
}
// 반응을 인지할 것인지의 여부 결정
(BOOL)canBecomeFirstResponder {
   return YES;
}
// 모션이 시작됐을 경우 진동과 함께 textField에 쓰여진 메시지를 블루투스로 연결된 다른 장치로 보내는 역할
(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event{
AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);
   NSData* data;
   NSString *str = [NSString stringWithString:txtMessage.text];
   data = [str dataUsingEncoding: NSASCIIStringEncoding];      
   [self mySendDataToPeers:data];      
}

8) 이번에는 GameKit에 해당하는 Delegate를 추가한다. GKS essionDelegate, GKPeerPickerControllerDelegate srBluetoothAppDelegate.h에 추가한다.
<리스트 3> Delegate 선언 추가
#import
#import
@class srBluetoothViewController;
@interface srBluetoothAppDelegate : NSObject {
   UIWindow *window;
   srBluetoothViewController *viewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet srBluetoothViewController *viewController;
@end
9) 처음으로 앱이 시작될 때 <연결하기>, <연결끊기> 버튼의 상태를 표시하기 위해 <리스트 4>와 같이 입력한다. 각각의 버튼들은 상태에 따라 보이거나 사라진다.
<리스트 4> 로딩시 버튼 상태 설정
(void)viewDidLoad {
  [connect setHidden:NO];
  [disconnect setHidden:YES];
  [super viewDidLoad];
}
10) TextField 메시지 박스와 현재 연결중인 세션의 메모리를 정리하기 위해 <리스트 5>와 같이 작성한다.
<리스트 5> TextField와 연결중인 세션의 메모리 정리
(void)dealloc {
  [txtMessage release];
  [currentSession release];
  [super dealloc];
}
11) 각각의 오브젝트들에 대해 synthesize 코드를 작성한다. @synthesize는 @property로 지정한 각각의 오브젝트와 반드시 쌍으로 작성돼야 한다.
<리스트 6> @property에 대응하는 @synthesize  코드
srBluetoothViewController.h
@synthesize currentSession; //GKSession
@synthesize sendMessage;
@synthesize txtMessage;
@synthesize connect;
@synthesize disconnect;
12) 실제 동작시 사용될 각각의 함수들을 살펴보자. 이번 예제를 위해 다음과 같이 크게 세 가지의 IBAction 함수를 만들었다.
첫 번째로 GKPeerPickerController를 사용해 <연결하기> 버튼을 클릭했을 경우 동작하는 함수가 있다. 여기서 picker. delegate를 자신으로 설정한다. 그리고 연결시 picker의 연결 타입을 결정한다. GKPeerPickerConnectionTypeOnline 또는 GKPeerPickerConnectionTypeNearby로 설정한다. GKPeer...Online 타입은 인터넷 연결이 된 상태의 네트워크 상황에서의 타입을 지정한 것이며, GKPeer...Nearby 타입은 블루투스 타입으로 주변에 있는 장치와 연결하는 방식을 말한다. 또한 이 함수에서 <연결하기>, <연결끊기> 버튼을 보이게 하거나 그렇게 하지 않거나 하는 설정을 한다. 
마지막으로 picker를 보이도록 한다(picker show).
<리스트 7> <연결하기> 버튼 클릭시 동작
(IBAction) btnConnect:(id) sender {
  picker = [[GKPeerPickerController alloc] init];
  picker.delegate = self;
  picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;
  [connect setHidden:YES];
  [disconnect setHidden:NO];  
  [picker show];
}
두 번째로 <연결끊기> 버튼이 있다. 이 버튼을 사용해 블루투스 연결을 끊을 수 있다. 현재 GKSession의 포인터 객체로 연결된 세션의 모든 장치(Peer)들을 끊는다(disconnectFrom AllPeers 사용). 다음으로 현재 연결된 세션의 메모리를 반환한다. 그리고 각각의 버튼들을 보이거나 보이지 않게 설정한다. 이 동작을 완료하면 서로 연결된 블루투스 장치들의 연결이 종료된다.
<리스트 8> <연결끊기> 버튼 클릭시 동작
(IBAction) btnDisconnect:(id) sender {
   [self.currentSession disconnectFromAllPeers];
   [self.currentSession release];
   currentSession = nil;
 
   [connect setHidden:NO];
   [disconnect setHidden:YES];
}
세 번째로 <메시지 전달하기> 버튼을 클릭하거나 두 대의 아이폰을 서로 충돌시켰을 경우에 발생하는 메시지 전달을 위한 동작을 만든다(이번 예제에서는 편의상 한글로 인코딩하지 않고 스트링을 ASCII로 보낸다). 스트링 객체는 data라는 이름으로 만든다. 또한 다른 장치로 메시지를 보내기 위해 mySendData ToPeers라는 함수를 하나 더 만든다.
<리스트 9> <메시지 전달하기> 버튼 클릭시 동작
(IBAction) btnSend:(id) sender
{
   NSData* data;
   NSString *str = [NSString stringWithString:txtMessage.text];
   data = [str dataUsingEncoding: NSASCIIStringEncoding];      
   [self mySendDataToPeers:data];      
}
mySendDataToPeers 함수는 NSData로 정의된 데이터가 현재 세션에 존재한다면 그것을 다른 연결된 블루투스 장치로 보내는 역할을 담당한다. 속성으로는 모든 장치로 데이터를 전달하도록 하는 sendDataToAllPeers라는 것과 데이터를 보낼 때 모드를 지정하는 withDataMode라는 것이 있다. 보내는 값으로 GKSendDataReliable, GKSendDataUnreliable이 있는데, 빠른 속도가 필요한 전달 모드에서는 전자를 사용하고, 좀 느려도 정확한 전달을 원할 때는 후자를 사용한다.
<리스트 10> 다른 장치로 데이터 전송
(void) mySendDataToPeers:(NSData *) data
{
   if (currentSession)
   [self.currentSession sendDataToAllPeers:data
   withDataMode:GKSendDataReliable
   error:nil];  
}
13) 이제 버튼 함수 이외에 사용되는 함수들을 알아보자.
- peerPickerController 함수는 세션 객체를 생성하고 델리게이트를 설정하는 동작들을 담당한다. 또한 데이터를 전송받았을 때 해당 데이터를 핸들링 할 수 있는 데이터 리시브 핸들러를 설정한다. picker 델리게이트도 이 함수에서 지정한다.
<리스트 11> 세션 객체 생성과 델리게이트 생성
(void)peerPickerController:(GKPeerPickerController *)picker
   didConnectPeer:(NSString *)peerID
   toSession:(GKSession *) session {
   self.currentSession = session;
   session.delegate = self;
   [session setDataReceiveHandler:self withContext:nil];
   picker.delegate = nil
   [picker dismiss];
   [picker autorelease];
}

<화면 10> Cancel 이벤트 발생
TextField를 벗어날 경우 OSK(On Screen Keyboard)를 사라지도록 하는 코드
<화면 11>을 보면 OSK가 화면에서 나와 있다. TextField에서 벗어나거나 ‘다음문장’이라는 키보드의 키가 눌렸을 때는 자동으로 OSK가 사라지도록 해야 바람직하다. 다음과 같은 순서로 코드를 넣으면 이를 해결할 수 있다. 
1)  srBluetoothViewController.h 파일에 키보드 액션으로 사용될 함수를 정의한다. TextField를 벗어날 경우와 MainView의 어느 곳이든 선택됐을 경우 가상 키보드가 내려가도록 해야 한다.
- (IBAction)goAwaykeyBoard:(id)sender;
- (IBAction)tabBackgroud:(id)sender;
2) 액션 함수를 다음과 같이 작성한다. 키보드를 첫 번째로 반응하도록 하는 Responder 함수를 호출하도록 설정하며, MainView의 아무 곳이든 눌려지면 역시 resignFirstResponder가 동작하도록 한다.
(IBAction)goAwaykeyBoard:(id)sender
{
 [sender resignFirstResponder];
}
IBAction)tabBackgroud:(id)sender
{
  [txtMessage resignFirstResponder];
}
3)  IB에서 <화면 11>과 같이 TextField에는 ‘Did End On Exit’라는 이벤트를 연결하고 tabBackground 함수는 ‘Control Touch Down’이라는 이벤트를 이어준다. 또한 이를 위해 MainView의 클래스 이름을 UIView에서 UIControl로 변경한다.

<화면 11> 가상 키보드를 위한 함수 연결
- peerPickerControllerDidCancel : 기기간의 연결을 취소했을 경우 동작하는 함수다. picker 델리게이트를 초기화하며, 메모리를 반환(release)한다. 또한 MainView가 있는 버튼의 상태를 설정해준다.
<리스트 12> 기기간의 연결 취소시 동작
(void)peerPickerControllerDidCancel:(GKPeerPickerController *)picker
{
   picker.delegate = nil
   [picker autorelease];
 
   [connect setHidden:NO];
   [disconnect setHidden:YES];
}
<리스트 13> 연결된 장치 사이의 상태 체크
(void)session:(GKSession *)session
   peer:(NSString *)peerID
didChangeState:(GKPeerConnectionState)state {
   switch (state)
   {
      case GKPeerStateConnected:
         NSLog(@"connected");
         break;
      case GKPeerStateDisconnected:
         NSLog(@"disconnected");
         [self.currentSession release];
         currentSession = nil;
         
         [connect setHidden:NO];
         [disconnect setHidden:YES];
         break;
   }
}

<화면 12> 메시지 입력 화면(좌)과 메시지 수신 화면(메시지를 입력하면 메시지가 전달된 후 수신화면을 볼 수 있다)

다음으로 연결된 장치 상호간의 연결 상태를 체크하는 session 함수에 대해 알아보자. session 함수는 GameKit의 GKPublic Protocols.h라는 헤더에 정의돼있다. 장치간에 연결이 끊어지거나 다시 붙거나 하면 이 함수가 호출된다. 인자로 session 이름과 스트링으로 표시될 수 있는 peer, 변경된 상태를 표시해주는 didChangeState를 갖고 있다.
빌드한 후에 <연결하기>로 먼저 블루투스 장치를 연결하고 메시지를 입력한다. 블루투스 장비를 서로 부딪히면 <화면 11>과 같이 메시지가 전달된다.
이번 호에서는 코드를 중심으로 블루투스를 사용하는 각각의 장치가 어떤 방식으로 연결되고 데이터를 교환하는지에 대해 알아봤다. 현재 블루투스는 고속으로 데이터를 전송할 수 있는 프로파일 등이 준비되고 있으며 표준 역시 업그레이드 된 사양으로 발전하고 있다.
참고자료
1. iPadProgrammingGuide.pdf(http://developer.apple.com/library/ios/ documentation/General/Conceptual/iPadProgrammingGuide/iPadProgrammingGuide.pdf)
2. iPad Human Interface Guidelines(http://developer.apple.com/library/ios/ documentation/General/Conceptual/iPadHIG/iPadHIG.pdf)
3. Game Kit Programming Guide(http://developer.apple.com/library/ios/ #documentation/NetworkingInternet/Conceptual/GameKit_Guide/Introduction/Introduction.html)

기사 원문 보기

Wednesday, 19 October 2011

Go 언어 관련 링크 - 마소

참고자료
1. http://golang.org Go 프로그래밍 언어 웹사이트
2. http://en.wikipedia.org/wiki/Ken_Thompson  켄 톰슨
3. http://en.wikipedia.org/wiki/Rob_Pike 롭 파이크
4. http://www.tiobe.com TIOBE
5. http://golang.kr Go프로그래밍언어 문서 한글화 작업 페이지
6. http://en.wikipedia.org/wiki/Go_(programming_language) Wikipedia Go언어
7. http://en.wikipedia.org/wiki/50_Greatest_Players_in_NBA_History NBA 역사상 Top 10 Teams
8. http://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs Plan 9 운영체제
9. http://xkcd.com/ 웹코믹스. ‘컴파일(Compiling)‘ 만화 이외에도 개발자들이 공감할만한 만화가 많다.
10. http://news.cnet.com/8301-30685_3-10393210-264.html CNET Go 출시 기사
11. http://downloadsquad.switched.com/2009/11/11/go-go-google-gopher-go-google-invents-its-own-programming-la/ SWITCHED Go 출시 기사
12. http://en.wikipedia.org/wiki/Newsqueak Newsqueak 프로그래밍 언어

가장 많이 본 글