지난 2009년 12월 18일에 프로젝트 코드명 Squiggly(스퀴글리)가 Prerelease판으로 업데이트 되었다.
http://labs.adobe.com/technologies/squiggly/

Squiggly는 Flash Player 10, AIR 1.5이상에서 동작한다. 이 엔진은 ActionScript 3.0 기반이며 영어로 문장에서 사용된 단어를 영어사전의 그것과 비교하여 단어의 철자를 체크한다. 이번 업데이트는 TLF(Adobe Text Layout Framework)를 기반으로 하는 Flex 4 Spark 컴포넌트를 지원하도록 했다. Squiggly는 Flex Builder, Flash Builder, Flash CS4등 다양한 툴에서 사용할 수 있다. 단지 아쉬운 것은 영어단어만 체크한다는 점이다.


다음 페이지는 Squiggly 데모이다.
http://labs.adobe.com/technologies/squiggly/demo/

개발자는 언제든지 예제소스와 ASDoc을 아래 링크에서 받아볼 수 있다.


이것을 쓸지 모르겠지만 아무튼 알아두고 있어 나쁠 것도 없으니....

참고
http://adnaru.com/242

글쓴이 : 지돌스타(http://blog.jidolstar.com/640)

 


Flash, Flex, AIR, ActionScript 프로젝트를 진행하면서 모든 코드를 손수 만들어 사용하는 것은 그다지 추천할 만한 일은 아니다. 왜냐하면 아무리 실력있는 개발자라도 프로젝트에 필요한 코드모음을 전부 만드는 것은 너무 큰 노력이 들뿐만 아니라 코드의 유지보수에도 매우 많은 시간을 허비할 수 있기 때문이다.

Flash 기반 코드 라이브러리는 이미 수년간에 걸쳐 공개되어 있다. 조금만 노력을 기울이면 3D, 트윈, 물리엔진, 수학, 보안, 데이터관리, MVC,   as3corelib, Papervision3d, Away3d, Flex 컴포넌트, 각종 유틸등 ActionScript/Flex/AIR/Flash에 관련된 수십,수백가지 우량(?) 라이브러리들을 쉽게 사용할 수 있다.


위에 링크되어 있는 라이브러리만 해도 정말 현업에 바로 사용할 수 있는 것들이 정말 많다. 또한 단순히 공개차원을 넘어 지속적으로 업데이트가 되며 완성도가 높아지고 있다.

그럼 다시 생각해보자. 내가 3D 게임을 만들기 위해 3D 엔진을 만들어야할 것인가? 내가 트윈(tween)을 구현하기 위해 트윈엔진을 만들어야 할것인가? 각종유틸이 필요해서 그걸 다 내가 만들것인가? 만약 검증되지 않고 아직 별도로 공개되어 있지 않은 것이라면 당연히 만들어야할 것이다. 하지만 기본적으로 큰 노력없이 쉽게 사용할 수 있고 자동으로 업데이트 및 검증까지 해주는 사람들이 만든 훌륭한 라이브러리가 있는데... 왜!!! 그걸 다 만들 필요가 있는가이다.

재미있게도 위에서 소개한 라이브러리들은 대부분 Google 코드(http://code.google.com)에 공개되어 있다. 이는 무엇을 의미하는가? 업데이트할때마다 압축파일을 받아 라이브러리에 복사하는 수고가 필요없이 SVN으로 간단하게 업데이트 할 수 있다는 것을 말한다. 이것을 적극 활용하는 방법을 소개하는 것이 이 글을 쓰는 목적이다.

필자는 Flash 개발자라면 누구라도(?) 잘 알고 있는 Flash 3D 엔진인 Papervision3D과 Away3D를 SVN을 이용해 가져와 프로젝트에서 활용하는 방법을 언급하고자 한다. 개발환경은 Flash Builder 4를 기준으로 하겠다. (거의 모든 기능을 Flex Builder 3에서도 할 수 있다.)


1. Flex/Flash Builder에 SVN 플러그인 설치
이제부터 설명할 공개 라이브러리를 사용하기 위해 Flash builder에 SVN 플러그인을 설치해야한다. 방법은 어렵지 않다. 다음 링크를 참고한다.

Flex Builder 에서 Subversion(SVN) 사용하기


2. Google Code에서 Papervision3D SVN 주소 확인하기
Google 코드 사이트(http://code.google.com)로 들어가 papervision3d로 검색해서 Papervison3D 구글코드 페이지(http://code.google.com/p/papervision3d/)로 들어간다. Papervision3d의 라이센스와 각종 링크들을 보면 다른 정보들도 확인할 수 있다.

물론 화면 우측 Featured downloads에 있는 zip 및 swc 파일을 받아 직접 프로젝트에 복사해 사용할 수 있으나(많은 블로그에 이 방법을 소개하고 있다.) 앞서 말한데로 새로 업데이트되는 최신소스를 바로바로 사용해보려면 이 방법은 너무 불편하다. 게다가 공개 라이브러리를 사용하는게 4~5개 이상 넘어가면 지속적인 업데이트가 힘들다.

어떤 개발자는 너무 최신 버전이면 버그가 있을지도 모르지 않겠느냐? 라고 의심할 수 있을 것이다. 하지만 Papervision3D와 같이 이미 대중적(?)으로 인기를 모으고 있는 라이브러리라면 철저한 검증없이 함부로 최신화(commit) 하지 않는다.


위 Source 탭으로 들어가 Checkout 메뉴를 보면 아래처럼 SVN checkout 주소가 있다. 이 주소는 저장소의 주소라 불리운다. 여러분은 이 주소로 Papervision3D 소스 코드를 받아올 수 있겠다.




3. SVN을 이용해 Papervision3D 라이브러리 프로젝트 만들기
이제 본격적으로 Papervision3d를 SVN으로 받아와 라이브러리 프로젝트를 만들어보자.

Flash Builder를 실행한다. 실행되면 메뉴에서 File > Import 로 들어간다. 아래 처럼 창이 뜨면 SVN > Checkout Projects from SVN 을 선택한다음 Next 버튼을 누른다.



아래 처럼 보이면 새로운 저장소 위치를 만들기 위해 Create a new repository location을 선택후 Next 버튼을 누른다. 이는 새로운 저장소라는 것은 SVN을 접속할 주소를 의미한다고 보면 되겠다. 여기서는 Google 코드에서 봤던 주소 http://papervision3d.googlecode.com/svn/trunk 가 되겠다.

아래처럼 나오면 주소를 입력하고 Next 버튼을 누른다.



아래 화면처럼 나오면 http://papervision3d.googlecode.com/svn/trunk 저장소 내에 있는 Papervision3D 소스 경로를 볼 수 있다. 우리는 ActionScript 3.0 기반에서 제작하기 때문에 as3/trunk를 선택한다. 이때 선택하는 기준은 그 안에 src 폴더의 상위 폴더이어야 한다. 이 방식은 다른 라이브러리를 참조해서 하더라도 저장소내에 구조가 조금씩 다르지만 같은 방법을 사용하므로 기억하자.


위 창에서 Next 버튼을 누르면 다음 창으로 전환된다. 세부적으로 Check out 하는 방법을 설정할 수 있는데 우리는 최신 버전을 사용할 것이기 때문에 바로 Finish 버튼을 누른다.



이제 Papervison3D 라이브러리를 가져올 SVN 주소 설정을 끝냈으므로 이 라이브러리가 담길 프로젝트를 생성해야한다. 위 절차를 모두 끝내면 자동적으로 다음과 같이 New Project 창이 뜬다. 이때 Flex Library Project를 선택하면 되겠다.


다음 그림처럼 Project name을 Papervision3D(이름은 아무거나 써도 상관없다.)으로 설정하고 Flex SDK Version을 선택한 다음 Finish버튼을 누른다.


참고로 Flex SDK Version을 선택시에 라이브러리가 AIR 코드가 포함되어 있는 경우라면 Include Adobe AIR libraries를 선택해야한다.(예: as3corelib) 또한 라이브러리가 구동되기 위한 SDK가 무엇인지도 알아야한다. 가령 Flash Player 10부터 3D API를 사용한 라이브러리라면 그것을 지원하는 SDK를 사용해야한다는 것을 의미한다. SDK는 Adobe Labs에서 최신버전을 받아 사용하면 된다.(방법을 모르시면 댓글을 ^^)

아래처럼 Confirm Overwrite 메시지가 뜨면 그냥 OK 버튼을 누른다.



이제 구글 코드 저장소로부터 아래처럼 Papervision 3D 코드를 받아온다.


Package Explorer에 추가된 Papervion3D 라이브러리 프로젝트를 확인하자. 하지만 만약 에러메시지가 나온다면 다음과 같이 해보자. 해당 프로젝트를 선택하고 오른쪽 마우스 버튼을 눌러 컨텍스트 메뉴에서 Properties로 들어가보자. 아래와 같은 창이 나오면 왼쪽 메뉴에서 Flex Library Build Path를 누르고 우측 상단 탭에 Classes를 선택한다. 그리고 Select classes to include in the library를 선택한 다음 src 앞에 check박스를 체크한다. 그리고 OK 버튼을 누르면 다시 컴파일 되면서 컴파일 에러가 사라질 것이다.



여러분은 이제 최신버전의 Papervision3D를 사용할 수 있게 되었다. 아래처럼 해당 프로젝트를 선택하고 오른쪽 마우스 버튼을 눌러 컨텍스트 메뉴에서 Team > Update to Head를 선택하는 것만으로 최신버전으로 업데이트 할 수 있게 된다. 이러한 방법은 SVN으로 공유한 다른 라이브러리들을 항상 최신으로 유지하는데 쉬운 방법을 제공하게 된다.


한가지 언급하자면 위에서 소개하는 방법은 Papervision3D를 예로 들었기 때문에 다른 라이브러리의 공개 형태에 따라 수행하는 방법의 차이가 있을 수 있다는 점을 강조하고 싶다. 그러한 점은 개발자가 알아서 체크할 수 있어야 한다.


4. 조금만 더 가다듬어 보기 (관심있는 사람만 읽으면 됨)
3번까지 진행하는 것만으로도 개발하는데 전혀 문제없지만 아래 내용을 좀더 알고 가면 더욱 좋을 듯 싶다.

지금까지 구글 코드로부터 SVN 저장소를 통해 받아온 Papervison3d 라이브러리는 설정파일을 제외한 ActionScript 3.0 코드가 대부분이다. 그래서 실질적으로 프로젝트에 필요한 설정구성요소인 .actionScriptProperties나 .flexLibProperties등의 파일들은 Papervision3D 개발자가 처음부터 저장소에 공유하지 않는다. 왜냐하면 .actionScriptProperties, .flexLibProperties들은 Flex Builder나 Flash Builder와 같이 특정 개발툴에서 필요한 파일이기 때문에 다른 IDE에서는 무의미 할 수 있기 때문이다.

아래 처럼 Papervision3D의 프로젝트 이름에 SVN으로 공유되었으나 폴더그림에 * 표시가 되어 있다. 이 표시는 원래 SVN 저장소 내용과 프로젝트 내용이 다를때 나온다. 이 다른 내용이라는 것은 금방 언급했던 .actionScriptProperties, .flexLibProperties 등이다.


Flash Builder에서는 프로젝트내의 .actionScriptProperties, .flexLibProperties 파일을 직접 볼 수 없도록 되어 있다. 이는 Filter 처리가 되어 있기 때문이다. 아래 그림처럼 선택해 Filter 처리된 파일들을 전부 check out하자.



위 그림 처럼 Filter 처리된 파일을 check out하면 아래처럼 프로젝트 내에 .actionScriptProperties, .flexLibProperties 등을 볼 수 있게 된다. 이 파일의 아이콘에 ?로 표시된 것은 저장소에 이 파일이 존재하지 않음을 나타내는 것이다.

* 표시나 ? 표시를 없애기 위해서 이러한 파일들이 SVN 저장소와 공유되지 않도록 무시할 수 있도록 하면 된다. Flash Builder에 설치된 SVN 플러그인은 이러한 기능을 지원해준다. 메뉴에서 window > Preference로 들어가 창이 뜨면 Team > Ignored Resources로 들어가면 아래 처럼 나온다. 여기에 다음 내용을 Add Pattern하자.

.actionScriptProject
.actionScriptProperties
.flexProperties
.flexProject
.project
bin
.settings
참고 : http://labs.adobe.com/wiki/index.php/Flex_Builder:resources:plugins:subversion:filtering




이제 아래 그림처럼 * 표시나 ? 표시가 없어지고 저장소의 원본과 프로젝트의 소스가 일치함을 나타내는 표시로 바뀐다.




5. Away3D를 SVN으로 받아오기

Papervision3D 라이브러리를 이용해서 애플리케이션을 만드는 예제는 굳이 설명안해도 된다고 생각한다. 대신 Away3D를 활용하는 방법을 약간 언급하고자 한다.

Away3D도 Papervision3D처럼 구글코드(http://code.google.com/p/away3d/)를 통해 SVN으로 소스를 공개하고 있다. 하지만 Away3D는 Papervision3D와 다르게 Flash Player 9, Flash Player 10 버전을 함께 제공하면서 Flash Player 10 3D 라이브러리를 이용한 3D 엔진인 Away3DLite도 제공한다. 또한 몇가지 유용한 예제도 함께 제공하고 있다.


Away3D 저장소 주소(http://away3d.googlecode.com/svn/trunk)로 접속하면 아래처럼 나온다. fp9과 fp10은 각각 Flash Player 9, 10 버전을 의미한다. 아무래도 Flash Player 10 버전이 최신이면서 효율적으로 만들어졌으므로 fp10에 있는 공개 라이브러리와 예제소스를 참고할 것이다.

fp10에 보면 Away3D, Away3DLite 소스가 있음을 확인할 수 있다. 또한 그에 대한 예제는 Examples에 들어 있다.


아래는 해당 라이브러리와 예제의 저장소 주소이다.


여러분은 Papervision3D를 SVN으로 프로젝트를 만든 것처럼 Away3D에서도 그래도 하면 된다. 단. Examples의 경우 중간에 프로젝트 생성시 ActionScript 프로젝트를 선택하기 바란다. 물론 Flash Player 10 기준이라는 점도 명심하자.

예제 프로젝트에서는 해당 라이브러리 프로젝트의 경로를 포함시켜줘야한다. Away3D_Example은 Away3D 라이브러리를 Away3DLite_Examples는 Away3dLite 라이브러리를 포함해야한다. 방법은 간단하다. Away3D_Example와 Away3DLite_Examples내에 libs 폴더안에 각각의 라이브러리 프로젝트에서 만들어진 bin디렉토리에 있는 
swc를 복사하면 된다. 하지만 이는 애플리케이션을 전부 만들고 배포하고 난 다음에 백업을 위해 선택할 방법이고 실제로 개발할때는 다음과 같이 한다.

1. Away3D_Example 프로젝트를 선택한다.
2. 메뉴에서 Project > Properties를 선택한다.
3. 창이 뜨면 좌측 ActionScript Build Path(Flex의 경우 Flex Build Path)를 선택한다.
4. 상단 Library path 탭을 선택한다.
5. Add Project를 선택한 다음 Away3D 라이브러리를 선택한다.
6. OK 버튼을 누른다.
7. Away3D_Example의 .actionScriptProperties를 연다.
아래 그림처럼  default package에 있는 소스 들은 전부 애플리케이션들이다. 이 코드들이 진정한 애플리케이션으로서 동작하려면 .actionScriptProperties내에 application으로 등록해야한다. 수작업이긴 해도 전부 등록하자. 또는 해당 as 파일을 선택후 마우스 오른쪽 버튼을 눌러 Set as Default Application 항목을 선택해도 된다. 이는 애플리케이션으로 등록하는 동시에 Default 애플리케이션으로 잡아준다. Default 애플리케이션을 지칭하는 것은 .actionScriptProperties 파일 내에 actionScriptProperties 태그의 mainApplicationPath 속성이 그 역할을 한다.



위 처럼 설정하면 이제 예제 파일들을 아무 문제없이 동작시킬 수 있을 것이다.
8. Away3DLite_Example도 위와 비슷한 방법으로 하면 되겠다.

아래는 Away3DLite_Examples에 있는 Advanced_Mario1000.as 애플리케이션을 실행하는 화면이다.

아마 어떤 애플리케이션은 as3dmod 라이브러리가 필요하다는 에러가 나올것이다. 이것도 비슷한 방법으로 Google Code에서 가져올 수 있다. 단, 몇가지 다른 설정을 해야하는데 여기서 설명하지 않고 각자의 몫으로 돌리겠다.


정리하며

개발자라면 Google Code와 친해져야하지 않을까? 또한 기존 라이브러리가 있는가 검색을 해보는 성의가 있어야하지 않을까? 그리고 그 라이브러리를 잘 활용하는 방법을 스스로 깨달으려고 노력해야하지 않을까?

잘못된 사항이나 더 좋은 정보가 있다면 얼마든지 댓글이나 트랙백 부탁한다.


참고
bs-papervision : http://code.google.com/p/bs-papervision/ 
as3dmod : http://code.google.com/p/as3dmod/
sandy3d : http://www.flashsandy.org 
alternativa3D : http://alternativaplatform.com/en/alternativa3d/

글쓴이 : 지돌스타(http://blog.jidolstar.com/639)





예전에 wonderfl.net에 대해서 소개한바 있다. 여기서 소개하는 Beautifl.netWonderfl.net에서 올라온 엄선된 아름다운(?) ActionScript/Flex 컨텐츠를 목록화 해서 쉽게 볼 수 있도록 해주는 서비스이다.

Beautifl.net은 적절히 분류(3D, Effect, Physics, Game, Sound등)가 되어 있어 관심있는 영역의 Flash 컨텐츠도 감상할 수 있겠다. PV, Pick, New 순으로 정렬도 되기 때문에 이 또한 유용하다. 또한 좋은 컨텐츠가 있다면 누구든지 추천할 수 있으며 RSS feed로도 구독할 수 있다. 

Flash로 이런 것도 만들 수 있구나를 넘어 실제 코드도 볼 수 있기 때문에 Flash 개발자들의 스킬업을 위해 이보다 좋은 것도 없을 것 같다.

Wonderfl.netBeautifl.net을 통해 멋진 Flash 세계를 감상해보자.

참고로 이 둘 사이트는 모두 일본에서 만들어졌다.

글쓴이 : 지돌스타(http://blog.jidolstar.com/634)


Flash 엔터프라이즈 개발 업체를 제외하고는 플래시 개발자가 2~3명인 업체가 대부분입니다. 게다가 Flex/AIR등에 처음 접하는 경우도 다분하죠. 결국 Flash 프로젝트의 실무를 어찌 진행할 것인가 고민이 되는 것이 현실입니다. 그래서 도움이 될만한 글들을 모아봤습니다.

http://opencast.naver.com/FL188/15

이 캐스트는 베스트 No.로 12월 10일에 추천되었습니다. ^^
http://opencast.naver.com/home/bestNo.nhn?exposureDate=20091210 

글쓴이 : 지돌스타(http://blog.jidolstar.com/633)

지난 2009년 11월 어도비(Adobe)에서는 AIR 2.0 Beta를 새롭게 발표하면서 퍼포먼스 향상과 더 많은 OS의 자원을 사용할 수 있는 API 기능을 추가해서 발표했다. Flash Player 10.1 Prerelease와 함께 발표된 Adobe AIR 2.0의 새로운 기능 및 추가/개선 사항에 대해서 정리해보았다.

참고로 이 글은 Elad Elrom의 AIR 2 Enhancements Complete Overview  와 AIR 2 Rerelease Note를 참고해서 정리한 것이다.




  1. 새로운 기능 (이번 페이지에서 다룸)
    - File Promises
    - Screen reader
    - Native Processes
    - New networking support
    - Global Error Handling
    - Packaging an AIR application in a native installer
  2. 기존 API에 대한 추가된 기능 (다음 편에 다룸)
    - Max Size of NativeWindow
    - Idle time-out
    - Mac Vector Printing
    - Database Transaction Savepoints
    - Microphone Access API
    - Open file with Default Application
  3. 플랫폼 인식 관련 API (다음 편에 다룸)
    - Multi-touch functionality
    - Mass Storage Device Detection
  4. 퍼포먼스 향상 (다음 편에 다룸)


출처 : http://tinyurl.com/ydxevnu




Flash Builder 4 beta 2에서 Adobe AIR 2.0로 개발 환경 만들기 

여기에서 보여지는 예제는 모두 Flash Builder 4 beta 2에 기본으로 설치된 Flex 4 SDK를 이용한다. 하지만 AIR 2.0로 테스트해보기 위해서는 AIR 2.0 SDK를 따로 받아 다음과 같은 과정이 필요하다.

Windows 환경이라면 다음과 같이 하면 되겠다.

  • 만약 Flash Builder를 설치 안했다면 다음 링크를 통해 받는다.
    1. AIR 2.0 SDK와 Runtime을 다운로드 받는다.
    2. 다운받은 Runtime을 실행해 설치한다.
    3. Flash builder가 설치된 sdks/4.0.0과 sdks/3.4.1 폴더를 복사해서 sdks 폴더안에 붙인뒤 4.0.0_AIR2.0, 3.4.1_AIR2.0을 만든다. 이렇게 되면 sdks 폴더안에는 3.4.1, 4.0.0, 3.4.1_AIR2.0, 4.0.0_AIR2.0 이름을 가진 4개의 SDK가 만들어진다.
      본인의 경우는 C:/Program Files/Adobe/Adobe Flash Builder Plug-in Beta 2/sdks 내에 있다. 
    4. AIR 2.0 SDK는 압축을 풀고 그안에 있는 내용을 방금 만든 4.0.0_AIR2.0, 3.4.1_AIR2.0 폴더에 복사한다.
    5. Flash Builder를 실행한다.
    6. 메뉴에서 Window > Preference 로 들어간다.
    7. 창이 뜨면 왼쪽 메뉴에서 Flash builder > Installed Flex SDKs를 선택한다.
    8. 우측에 Add버튼을 눌러 위에서 새로 만든 AIR 2.0을 위한 SDKs들을 선택한다.  
      Flex SDK Name은 각각 Flex 3.4 AIR 2.0, Flex 4.0 AIR 2.0 등으로 이름을 바꿔도 된다.
      본인의 경우 아래 경로가 되겠다.
      C:/Program Files/Adobe/Adobe Flash Builder Plug-in Beta 2/sdks/3.4.1_AIR2.0/
      C:/Program Files/Adobe/Adobe Flash Builder Plug-in Beta 2/sdks/4.0.0_AIR2.0/
      아래처럼 Flex 4.0으로 체크되어 있다면 AIR 2.0기반의 Flex 4.0 SDK를 디폴트로 바꾸자.
    9. 이제 모든 개발환경이 완료되었다. 자신의 프로젝트 생성시에 원하는 SDK를 선택하면 되겠다.  물론 아래에서 소개하는 예시를 따르려면 Flex 3든 Flex 4든 AIR 2.0 SDK를 선택해야겠다.


    Mac 환경이라면 다음과 같이 하면 되겠다.

    Mac에서 AIR 2.0 Beta 개발환경 만들기 - Flash Builder 4 Beta 2 기반

    참고로 Flash CS4나 CS3, 드림위버나 기타 다른 IDE에서 개발하시는 분들에게는 본인의 경험이 없어 정보를 줄 수 없다.

  •  
    1. Adobe AIR 2.0 새로운 기능

    1.1 IPv6 지원
    AIR 2.0은 모든 Network API에 대해서 IPv6를 지원하게 되었다. 현재 인터넷에서 주로 사용하고 있는 IP 주소의 버전은 IPv4로서 무려 20년이 넘도록 사용하고 있다. IPv4는 32비트 주소체계를 가지며 4,294,967,296개의 제한된 갯수의 주소를 가진다. IPv6는 이 부족함을 해소하기 위해 만들어진 IP 주소 체계이다. IPv6는 128비트 주소체계를 가진다. IPv6가 일반적으로 사용되고 있는 것은 아니지만  가까운 미래에 IPv6가 범용적으로 도입되어 네트워크 IP 주소체계가 더욱 확장될 수 있으므로 미리 지원될 수 있도록 한 것으로 여겨진다. IPv6에 대한 자세한 내용은 아래 링크를 참고한다.




    1.2  UDP(User Datagram Protocol) 소켓, Server 소켓, TLS/SSL 소켓 지원
    AIR 2.0에서는 더욱 다양한 소켓 통신 관련 클래스들이 추가되었다. 이전버전까지 반쪽짜리 였다면 이제 어느정도 구색을 갖춘듯 하다. 

    AIR 2.0에서 지원하는 네트워크에 관련된 내용은 다음 링크를 참고한다.


    서버 소켓 : ServerSocket 클래스 
    기존 AIR 버전에서는 반쪽 소켓통신만 지원되었다. 즉, 클라이언트는 만들 수 있었지만 서버측을 만들지 못했다. 이번 AIR 2.0에서 서버 소켓이 지원됨에 따라 이를 이용한 다양한 네트워크 애플리케이션을 만들 수 있을 것으로 보인다.

    서버 소켓은 TCP(Transmissin Control Protocal)을 기반으로 한다. TCP는 연결지향 통신 규약으로 인터넷 상의 컴퓨터들 사이에 데이터를 통신하기 위해 IP와 함께 사용된다. TCP는 데이터의 통신 중간에 데이터가 유실되더라도 신뢰도를  체크해서 완벽한 데이터를 통신할 수 있는 신뢰형 기반의 데이터 통신시 사용된다. 일반적인 웹브라우져를 이용한 통신데이터는 모두 TCP를 근간으로 한다.



    AIR 2.0에서 지원하는 서버 Socket는 ServerSocket 클래스에서 관장한다.



    UDP 소켓 : DatagramSocket 클래스
    UDP는 User Datagram Protocal의 약어로 IP를 사용해 네트워크내에서 컴퓨터들간에 데이타 통신하기 위해 제한된 서비스만 제공하는 통신 규칙이다. TCP의 대안이기도 하며 IP와 함께 사용하면 UDP/IP라고 표현하기도 한다. UDP는 정확한 데이터를 전송할 의무가 주어지지 않은 비연결지향성을 가져 데이터의 흐름에 신뢰를 할 수 없는 것이 특징이다. TCP처럼 통신을 하기전 상대방을 확인하는 절차가 없기 때문에 데이터 정확도는 떨어질 수 있지만 빠른 데이타 전송에 유리하다. 그래서 음악 및 비디오 실시간 스트리밍 서비스에 잘 사용하는 프로토콜이다.



    AIR 2.0에서는 UDP 통신을 DatagramSocket 클래스와 DatagramSocketDataEvent 클래스를 지원하고 있다. 더욱 자세한 내용은 아래 링크를 참고한다.



    Secure 클라이언트 소켓 : SecureSocket 클래스 
    소켓서버에 접속하기 위해 SSLv4(Secure Socket Layer version 4) 또는 TLSv1(Transport Layer Security version 1) 기반으로 하는 프로토콜을 이용하여 SecureSocket 클래스로 접속할 수 있다. Secure 소켓을 이용하면 암호화된 데이터 전송으로 서버인증(server authentication), 데이터 무결성(data integrity), 메시지 기밀성(message confidentiality)등의 장점을 가진다. 




    1.3 네트워크 정보 
    AIR 2.0의 API로 네트워크 정보를 얻어낼 수 있는 클래스인 NetworkInfo가 추가되었다. 이 클래스를 이용하면 사용자의 기기의 Mac Address, IP정보 등의 네트워크 정보를 얻어올 수 있다.


    Adobe 문서에서 보여지는 예제에서는 var networkInfo:NetworkInfo = new NetworkInfo() 처럼 생성해서 사용하도록 되어 있는데 잘못된 것이다. var networkInfo:NetworkInfo = NetworkInfo.networkInfo; 처럼 static 속성으로 접근해야한다.
    그리고 NetworkInterface에 networkInterfaceDefault 속성 또한 존재하지 않는다.  
    package { 
    	import flash.display.Sprite; 
    	import flash.net.InterfaceAddress; 
    	import flash.net.NetworkInfo; 
    	import flash.net.NetworkInterface; 
    	
    	public class NetworkInformationExample extends Sprite 
    	{ 
    		public function NetworkInformationExample() 
    		{ 
    			var networkInfo:NetworkInfo.<NetworkInterface> = NetworkInfo.networkInfo;
    			var interfaces:Vector.<NetworkInterface> = networkInfo.findInterfaces(); 
    			
    			if( interfaces != null ) 
    			{ 
    				trace( "Interface count: " + interfaces.length ); 
    				for each ( var interfaceObj:NetworkInterface in interfaces ) 
    				{ 
    					trace( "\nname: "             + interfaceObj.name ); 
    					trace( "display name: "     + interfaceObj.displayName ); 
    					trace( "mtu: "                 + interfaceObj.mtu ); 
    					trace( "active?: "             + interfaceObj.active ); 
    					//trace( "default?: "         + interfaceObj.networkInterfaceDefault ); 
    					trace( "parent interface: " + interfaceObj.parent ); 
    					trace( "hardware address: " + interfaceObj.hardwareAddress ); 
    					if( interfaceObj.subInterfaces != null ) 
    					{ 
    						trace( "# subinterfaces: " + interfaceObj.subInterfaces.length ); 
    					} 
    					trace("# addresses: "     + interfaceObj.addresses.length ); 
    					for each ( var address:InterfaceAddress in interfaceObj.addresses ) 
    					{ 
    						trace( "  type: "           + address.ipVersion ); 
    						trace( "  address: "         + address.address ); 
    						trace( "  broadcast: "         + address.broadcast ); 
    						trace( "  prefix length: "     + address.prefixLength ); 
    					} 
    				}             
    			} 
    		}     
    	} 
    }
    

     
    위 프로그램은 NetworkInfo를 사용하는 아주 간단한 예시이다. Flash Builder 4 에서 이 예시를 테스트해볼때는 AIR 프로젝트 생성시 마지막에 mxml대신 as로 확장자를 두고 생성해서 테스트 하면 되겠다.


    1.4 DNS lookup
    AIR 2.0에서부터 DNSResolver 클래스를 제공하여 DNS(Domain Name System) 정보를 찾을 수 있게 되었다. 정보를 찾게되면 DNSResolverEvent가 발생한다. 

    DNS는 각 도메인 이름(가령 examples.com)을 IP주소로 가리킨다. 일반적으로 사람은 111.123.431.11와 같은 IP주소보다 examples.com처럼 도메인 이름과 같은 단어조합을 더욱 인지하기 쉽다. 이러한 이유로 실제로는 도메인 이름을 사용하면 DNS를 걸쳐 이에 해당하는 IP주소로 연결시켜 관련 서버로 접속하게 한다. AIR 2.0에서 제공하는 DNSResolver 클래스를 이용하면 이러한 관계를 조사해볼 수 있게 된다. 

    IP주소는 IPv4(32비트) 또는 IPv6(128비트)를 사용할 수 있다. 

    DNSResolver 클래스의 lookup() 함수를 통해 host이름과 레코드 형태(record type)을 넘겨주면 DNSResolverEvent.LOOK_UP 이벤트를 발생하여 관련 레코드 타입에 대한 정보를 반환해준다. 
     



     다음은 예제이다.
    package
    {
    	import flash.desktop.NativeApplication;
    	import flash.display.Sprite;
    	import flash.events.DNSResolverEvent;
    	import flash.events.ErrorEvent;
    	import flash.net.dns.AAAARecord;
    	import flash.net.dns.ARecord;
    	import flash.net.dns.DNSResolver;
    	import flash.net.dns.MXRecord;
    	import flash.net.dns.PTRRecord;
    	import flash.net.dns.SRVRecord;
    	import flash.utils.getQualifiedClassName;
    	
    	public class DNSResolverExample extends Sprite
    	{
    		private var lookupCount:int = 0;
    		public function DNSResolverExample()
    		{
    			//Create the resolver object
    			var resolver:DNSResolver = new DNSResolver();
    			resolver.addEventListener( DNSResolverEvent.LOOKUP, lookupComplete );
    			resolver.addEventListener( ErrorEvent.ERROR, lookupError );
    			
    			//Look up records
    			resolver.lookup( "yahoo.com", ARecord );
    			resolver.lookup( "yahoo.com", AAAARecord );
    			resolver.lookup( "yahoo.com", MXRecord );
    			resolver.lookup( "209.191.93.53", PTRRecord );
    			resolver.lookup( "_sip._tcp.yahoo.com.", SRVRecord );
    		}
    		
    		private function lookupComplete( event:DNSResolverEvent ):void
    		{
    			trace("-------------------------------------");
    			trace( "Query string: " + event.host );
    			trace( "Record type: " +  flash.utils.getQualifiedClassName( event.resourceRecords[0] ) + 
    				", count: " + event.resourceRecords.length );
    			for each( var record:* in event.resourceRecords )
    			{
    				if( record is ARecord ) trace( record.name + " : " + record.address );
    				if( record is AAAARecord ) trace( record.name + " : " + record.address );
    				if( record is MXRecord ) trace( record.name + " : " + record.exchange + ", " + record.preference );
    				if( record is PTRRecord ) trace( record.name + " : " + record.ptrdName );
    				if( record is SRVRecord ) trace( record.name + " : " + record.target + ", " + record.port +
    					", " + record.priority + ", " + record.weight );
    			}    
    			if( ++lookupCount == 5 )
    			{
    				NativeApplication.nativeApplication.exit();
    			}
    		}
    		
    		private function lookupError( error:ErrorEvent ):void
    		{
    			trace("-------------------------------------");
    			trace("Error: " + error.text );
    			if( ++lookupCount == 5 )
    			{
    				NativeApplication.nativeApplication.exit();
    			}
    		}
    	}
    }
    



    1.5 스크린 리더 지원(Screen Reader Support)

    AIR 2.0은 스크린 리더를 지원하기 위한 Accessibility 클래스가 추가되었다. 스크린 리더는 시각 장애 사용자들을 위한 보조 기술로서 화면 내용을 오디오 버전으로 제공하는 것이다. 이 클래스는 현재 Windows 환경에서만 제공된다. 이것이 지원되는지 확인하려면 Capabilities.hasAccessibility 정적속성이 true이어야 한다. 버튼, 무비클립, 텍스트필드와 같은 객체에 액세스 가능한 속성을 얻고 설정하기 위해 DisplayObject.accessibilityProperties 속성을 사용하며 이 값이 바뀌었다는 것을 알려주기 위해 Accessibility.updateProperties() 정적메소드를 이용한다.

    이 기능을 사용하기 위해 프로젝트의 컴파일 옵션을 추가해야한다. Flash builder 4에서 해당 프로젝트를 선택후 메뉴의 Project > Properties를 선택한다. 새창이 나오면 Flex Compiler를 선택후 컴파일 옵션에 Generate accessible SWF file을 선택후 OK 버튼을 누른다.


    package {
    	import flash.accessibility.Accessibility;
    	import flash.desktop.NativeApplication;
    	import flash.display.Sprite;
    	import flash.display.StageAlign;
    	import flash.display.StageScaleMode;
    	import flash.utils.setTimeout;
    	
    	public class AccessibilityExample extends Sprite {
    		public static const BUTTON_WIDTH:uint = 90;
    		public static const BUTTON_HEIGHT:uint = 20;
    		
    		private var gutter:uint = 5;
    		private var menuLabels:Array = new Array("PROJECTS", "PORTFOLIO", "CONTACT");
    		private var menuDescriptions:Array = new Array("Learn more about our projects"
    			, "See our portfolio"
    			, "Get in touch with our team");
    		
    		public function AccessibilityExample() {
    			configureAssets();
    			NativeApplication.nativeApplication.autoExit = true;
    			stage.align = StageAlign.TOP_LEFT;
    			stage.scaleMode = StageScaleMode.NO_SCALE;
    			stage.nativeWindow.activate();
    			setTimeout(updateAccessibility, 2000); 
    		}
    		
    		private function updateAccessibility():void {
    			trace("Accessibility.active: " + Accessibility.active);
    			if(Accessibility.active) {
    				Accessibility.updateProperties();
    			}
    		}
    		
    		private function configureAssets():void {
    			var child:CustomAccessibleButton;
    			for(var i:uint; i < menuLabels.length; i++) {
    				child = new CustomAccessibleButton();
    				child.y = (numChildren * (BUTTON_HEIGHT + gutter));
    				child.setLabel(menuLabels[i]);
    				child.setDescription(menuDescriptions[i]);
    				addChild(child);
    			}
    		}
    	}
    }
    
    import flash.accessibility.AccessibilityProperties;
    import flash.display.Shape;
    import flash.display.SimpleButton;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.text.TextFormat;
    import flash.text.TextFormatAlign;
    import flash.text.TextField;
    
    class CustomAccessibleButton extends Sprite {
    	private var button:SimpleButton;
    	private var label:TextField;
    	private var description:String;
    	private var _name:String;
    	
    	public function CustomAccessibleButton(_width:uint = 0, _height:uint = 0) {
    		_width = (_width == 0) ? AccessibilityExample.BUTTON_WIDTH : _width;
    		_height = (_height == 0) ? AccessibilityExample.BUTTON_HEIGHT : _height;
    		
    		button = buildButton(_width, _height);
    		label = buildLabel(_width, _height);
    		
    		addEventListener(Event.ADDED, addedHandler);
    	}
    	
    	private function addedHandler(event:Event):void {
    		trace("addedHandler: " + this._name);
    		var accessProps:AccessibilityProperties = new AccessibilityProperties();
    		accessProps.name = this._name;
    		accessProps.description = description;
    		accessibilityProperties = accessProps;
    		removeEventListener(Event.ADDED, addedHandler);
    	}
    	
    	private function buildButton(_width:uint, _height:uint):SimpleButton {
    		var child:SimpleButton = new CustomSimpleButton(_width, _height);
    		addChild(child);
    		return child;
    	}
    	
    	private function buildLabel(_width:uint, _height:uint):TextField {
    		var format:TextFormat = new TextFormat();
    		format.font = "Verdana";
    		format.size = 11;
    		format.color = 0xFFFFFF;
    		format.align = TextFormatAlign.CENTER;
    		format.bold = true;
    		
    		var child:TextField = new TextField();
    		child.y = 1;
    		child.width = _width;
    		child.height = _height;
    		child.selectable = false;
    		child.defaultTextFormat = format;
    		child.mouseEnabled = false;
    		
    		addChild(child);
    		return child;
    	}
    	
    	public function setLabel(text:String):void {
    		label.text = text;
    		this._name = text;
    	}
    	
    	public function setDescription(text:String):void {
    		description = text;
    	}
    }
    
    class CustomSimpleButton extends SimpleButton {
    	private var upColor:uint = 0xFFCC00;
    	private var overColor:uint = 0xCCFF00;
    	private var downColor:uint = 0x00CCFF;
    	
    	public function CustomSimpleButton(_width:uint, _height:uint) {
    		downState = new ButtonDisplayState(downColor, _width, _height);
    		overState = new ButtonDisplayState(overColor, _width, _height);
    		upState = new ButtonDisplayState(upColor, _width, _height);
    		hitTestState = new ButtonDisplayState(upColor, _width, _height);
    		useHandCursor = true;
    	}        
    }
    
    class ButtonDisplayState extends Shape {
    	private var bgColor:uint;
    	private var _width:uint;
    	private var _height:uint;
    	
    	public function ButtonDisplayState(bgColor:uint, _width:uint, _height:uint) {
    		this.bgColor = bgColor;
    		this._width = _width;
    		this._height = _height;
    		draw();
    	}
    	
    	private function draw():void {
    		graphics.beginFill(bgColor);
    		graphics.drawRect(0, 0, _width, _height);
    		graphics.endFill();
    	}
    }
    


    1.6 네이티브 프로세스의 직접 실행과 상호 작용( Launching and Interacting with Native Processes )
    네이티브 프로세스에 대해서 본인도 처음 접하는 용어라 해석하기 어려웠는데, 이해한바 각 운영체제에 실행될 수 있는 코드라고 생각하면 될 것 같다. 가령, 윈도우에서는 exe, dll, ocx등이겠고 맥이라면 dmg, app 등이 아닐까 생각한다.

    AIR 2.0부터 기존의 애플리케이션을 실행해 AIR 애플리케이션과 표준입출력을 통한 상호작용할 수 있는 기능이 추가되었다. 가령, C언어로 만든 프로그램을 자신의 AIR 애플리케이션과 함께 배포했다고 하자. AIR 애플리케이션이 이 C언어로 만든 프로그램을 실행하고 표준입출력을 이용해 통신이 가능해진다. 또는 이미 설치된 Editplus에 File을 넘겨서 실행하고 종료시점도 알 수 있다.

    자세한 내용은 다음을 참고한다.

    이 기능을 수행하려면 반드시 AIR 디스크립터 파일에 다음 코드를 꼭 넣어야 한다.


    <supportedProfiles>extendedDesktop</supportedProfiles>
    


    아래는 Editplus를 이용해 Text파일을 열고 Editplus가 닫힐 때 감지하는 간단한 Flex 4를 이용한 AIR 2.0 애플리케이션 코드이다. NativeProcess와 NativeProcessStartupInfo 클래스의 용도를 잘 살펴보자.
    <?xml version="1.0" encoding="utf-8"?>
    <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
    					   xmlns:s="library://ns.adobe.com/flex/spark" 
    					   xmlns:mx="library://ns.adobe.com/flex/halo">
    	<fx:Script>
    		<![CDATA[
    			import flash.events.NativeProcessExitEvent;
    			
    			public function executeNativeProcess():void 
    			{
    				var executable:File = new File("C:/Program Files/EditPlus 3/editplus.exe"); //c:/Windows/System32/notepad.exe
    				var workingDirectory:File = new File("c:/");
    				
    				var nativeProcess:NativeProcess = new NativeProcess();
    				
    				if (NativeProcess.isSupported) 
    				{
    					trace("Native Process Supported");
    				}
    				
    				var nativeProcessStartupInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo();
    				nativeProcessStartupInfo.executable = executable;
    				nativeProcessStartupInfo.workingDirectory = workingDirectory;
    				
    				var args:Vector.<String> = new Vector.<String>();   
    				args.push("c:/LAN.log"); // open file that was given with the executable application 
    				nativeProcessStartupInfo.arguments = args;
    				
    				nativeProcess.addEventListener( NativeProcessExitEvent.EXIT, onExitError );
    				
    				try {
    					nativeProcess.start(nativeProcessStartupInfo);
    				} catch (error:IllegalOperationError) {
    					trace("Illegal Operation: "+error.toString());
    				} catch (error:ArgumentError) {
    					trace("Argument Error: "+error.toString());
    				} catch (error:Error) {
    					trace ("Error: "+error.toString());
    				}
    				
    				if (nativeProcess.running) 
    				{
    					trace ("Native Process Support");
    				}       
    			}
    			
    			public function onExitError(event:NativeProcessExitEvent):void 
    			{
    				trace( "Native Process Exit code: "+event.exitCode );
    			}            
    			
    		]]>
    	</fx:Script>
    	
    	<s:Button id="button"
    			  label="Open File foobar.txt with text editor"
    			  click="executeNativeProcess();"
    			  width="250" />
    	
    </s:WindowedApplication>
    

    Mac인 경우 Mac에 설치되어 기본으로 설치되어 있는 텍스트 에디터를 실행할 수도 있다. 이것도 별다른 설정없이 같은 방법으로 실행할 수 있다. new File()에는 "/Applications/TextEdit/TextEdit.app/Contents/MacOS/TextEdit"와 "/" 로 대체하고 args.push()부분은 foobar.txt가 데스크톱에 있을때 "/User/사용자계정/Desktop/foobar.txt"로 대체해서 실행하면 된다. 

    NativeProcess 클래스는 단순히 실행과 종료만 담당하지 않는다. AIR 애플리케이션과 Native 실행 소스간에 통신도 가능하다. 다음 링크는 HTML/Javascript, Flex, Flash 개발자들을 위한 예제이다. AIR코드 뿐 아니라 C코드도 있으니 꼭 다운받아 실행해보길 바란다.

    다음과 같이 Flex 4 코드로 변경해봤다.


    <?xml version="1.0" encoding="utf-8"?>
    <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
    					   xmlns:s="library://ns.adobe.com/flex/spark" 
    					   xmlns:mx="library://ns.adobe.com/flex/halo" 
    					   width="350" height="150"
    					   applicationComplete="windowedapplication1_applicationCompleteHandler(event)">
    	<fx:Script>
    		<![CDATA[
    			import flash.events.ProgressEvent;
    			import flash.system.Capabilities;
    			import flash.utils.IDataInput;
    			
    			import mx.controls.Alert;
    			import mx.events.FlexEvent;
    			
    			private var process:NativeProcess;
    			
    			private function windowedapplication1_applicationCompleteHandler(event:FlexEvent):void {
    				//Native Process가 지원되는지 확인. 
    				//지원되려면 반드시 디스크립터에  <supportedProfiles>extendedDesktop</supportedProfiles>을 추가해야한다.
    				if( NativeProcess.isSupported ) {
    					launchEchoTest();
    				} else {
    					Alert.show("NativeProcess not supported.","Error");
    				}
    			}			
    			private function launchEchoTest():void {
    				//실행할 Native 애플리케이션 선택
    				var file:File = File.applicationDirectory;
    				file = file.resolvePath("NativeApps");
    				if( Capabilities.os.toLocaleLowerCase().indexOf("win") > -1 ) {
    					file = file.resolvePath("Windows/bin/echoTestWin.exe");
    				} else {
    					file = file.resolvePath("Mac/bin/echoTestMac");
    				}
    				
    				//Native Process를 진행하기 위한 정보 설정 
    				var info:NativeProcessStartupInfo = new NativeProcessStartupInfo();
    				info.executable = file;
    				
    				//Native Process생성
    				process = new NativeProcess();
    				
    				//보내고 받을때 발생하는 이벤트에 대한 처리 
    				process.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, function(event:ProgressEvent):void {
    					var date:Date = new Date();
    					var bytes:IDataInput = process.standardOutput;
    					textReceived.text = bytes.readUTFBytes( bytes.bytesAvailable );
    					launchEchoTest();
    					lbDateStamp.text = date.toString();
    				} );
    				process.addEventListener(ProgressEvent.STANDARD_INPUT_PROGRESS, function(event:ProgressEvent):void {
    					process.closeInput();
    				} );
    				//Native Process 시작 
    				process.start( info );
    			}
    			private function writeData():void {
    				process.standardInput.writeUTFBytes( textToSend.text + "\n" );
    			}
    		]]>
    	</fx:Script>
    	<fx:Declarations>
    		<!-- Place non-visual elements (e.g., services, value objects) here -->
    	</fx:Declarations>
    	<s:VGroup paddingLeft="10" paddingRight="10" paddingTop="10" paddingBottom="10">
    		<mx:Form>
    			<mx:FormItem label="Text to send" direction="horizontal">
    				<s:TextInput id="textToSend"/>	
    				<s:Button label="writeData()" click="writeData()"/>
    			</mx:FormItem>
    			<mx:FormItem label="Text received">
    				<s:TextInput id="textReceived" editable="false"/>
    			</mx:FormItem>
    		</mx:Form>
    		<s:Label id="lbDateStamp"/>
    	</s:VGroup>
    </s:WindowedApplication>
    
    


    아래 코드는 AIR 애플리케이션과 통신할 C코드(Mac용)이다.
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    #define BUFFER_SIZE 8192
    
    int main(int argc, char** argv)
    {
    	char buf[BUFFER_SIZE];
    	int  cnt;
    	
    	while ( !feof(stdin) )
    	{
    		cnt = read(STDIN_FILENO, buf, sizeof buf); 
    		if (-1 == cnt) 
    		{
    			perror("read");
    			exit(1);
    		}
    		if (0 == cnt)
    		{
    			// eof reached...
    			exit(0);
    		}
    
    		write(STDOUT_FILENO, buf, cnt ); 
    	}
    	
    	return 0;
    }
    
    




    NativeProcess의 standardInput과 standardOutput 속성은 각각 IDataOutput, IDataInput을 입력과 출력값으로 받고 있다. 그러므로 이 속성을 이용해 표준입출력(standard input/output)을 이용해 서로 통신하게 된다.

    매우 다양한 형태로 응용이 가능할 것이라 판단한다.


    1.7 File Promise 지원

    AIR 2.0부터 FilePromise 클래스가 새로 추가되어 드래그&드롭 형태로 리모트 파일을 AIR 애플리케이션 외부로 다운로드 받을 수 있게 되었다. URLFilePromise 클래스를 이용해 이 작업을 할 수 있다.

    이 기능은 Windows와 Mac에서만 지원되며(Clipboard.supportsFilePromise로 확인) 반드시 AIR 애플리케이션 외부로 드롭하는 경우만 해당한다. 일반적인 클립보드 복사&붙이기 기능으로는 할 수 없다.

    다음 코드는 예시이다.

     

    <?xml version="1.0" encoding="utf-8"?>
    <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
    					   xmlns:s="library://ns.adobe.com/flex/spark" 
    					   xmlns:mx="library://ns.adobe.com/flex/halo"
    					   applicationComplete="windowedapplication1_applicationCompleteHandler(event)">
    	<fx:Script>
    		<![CDATA[
    			import mx.controls.Alert;
    			import mx.events.DragEvent;
    			import mx.events.FlexEvent;
    			
    			private var clipboard:Clipboard;
    			private function windowedapplication1_applicationCompleteHandler(event:FlexEvent):void {
    				clipboard = new Clipboard();
    				if( !clipboard.supportsFilePromise ) {
    					Alert.show( "File Promise를 지원하지 않습니다." );
    				}
    			}
    			private function onDragOut(event:DragEvent):void {
    				trace( event.target, event.type );
    				var items:Array = fileData.selectedItems;
    				var promises:Array = new Array();
    				for each (var item:Object in items) {
    					var filePromise:URLFilePromise = new URLFilePromise();
    					var request:URLRequest = new URLRequest(item.url);
    					filePromise.request = request;
    					filePromise.relativePath = item.name;
    					promises.push(filePromise);
    				}
    				clipboard.setData(ClipboardFormats.FILE_PROMISE_LIST_FORMAT, promises);
    				NativeDragManager.doDrag(fileData, clipboard);     
    			}
    			private function onDragOutComplete(event:NativeDragEvent):void {
    				trace( "Drag out complete");
    				clipboard = new Clipboard();
    			}            
    		]]>
    	</fx:Script>
    	
    	<fx:Declarations>
    		<mx:ArrayCollection id="arrColl">
    			<mx:source>
    				<fx:Array>
    					<fx:Object name="rhall.jpg" url="http://a1.twimg.com/profile_images/57117466/robert_m_hall_bio_photo_big_normal.jpg" />
    					<fx:Object name="bobjim.jpg" url="http://a1.twimg.com/profile_images/51723308/ryancampbell3_normal.jpg"/>
    					<fx:Object name="jenschr.jpg" url="http://a1.twimg.com/profile_images/43222252/jenschr_mugshot3_normal.jpg"/>
    					<fx:Object name="adamflater.jpg" url="http://a1.twimg.com/profile_images/21503622/Photo_8_normal.jpg"/>
    					<fx:Object name="reboog711.jpg" url="http://a1.twimg.com/profile_images/16984682/DSCF0044_normal.jpg"/>
    				</fx:Array>
    			</mx:source>
    		</mx:ArrayCollection>
    	</fx:Declarations>
    	
    	<mx:DataGrid id="fileData" dragEnabled="true"
    				 dataProvider="{arrColl}" 
    				 dragStart="onDragOut(event)"
    				 nativeDragComplete="onDragOutComplete(event)" width="100%">
    		<mx:columns>
    			<mx:DataGridColumn dataField="name" width="100"/>
    			<mx:DataGridColumn dataField="url"/>
    		</mx:columns>
    	</mx:DataGrid>
    	
    </s:WindowedApplication>
    




    1.8 Global Error Handling

    AIR 애플리케이션이 런타임 도중에 에러가 발생할 때 국부적 Error 처리는 이미 가능했다. 하지만 개발자가 애플리케이션의 어느 부분에서 Error가 발생할지 또는 문제가 발생할지 찾기 힘든 것이 현실이다. 국부적으로 일어나는 에러를 처지하지 못하는 경우 애플리케이션이 동작중에 어떤 부분에서 에러가 발생하든지 대처할 수 있도록 Global Error를 처리할 수 있는 기능이 AIR 2.0과 Flash Player 10.1에 추가가 되었다. 다음 글을 참고하자.

    Global Error를 처리하는데 UncaughtErrorEvent 클래스를 이용한다. 이름에서도 볼 수 있듯이 기존의 try..catch문으로 처리하지 못한 Error가 발생할 때 발생함을 알 수 있다.

    발생하는 UncaughtErrorEvent를 처리하기 위해 LoaderInfo 객체의 uncaughtErrorEvents 속성에 이벤트 처리를 위한 함수를 등록하면 된다.

    loaderInfo.uncaughtErrorEvents.addEventListener( UncaughtErrorEvent.UNCAUGHT_ERROR, handler );

    단, 로드된 SWF 객체의 경우에는 Loader의 uncaughtErrorEvents 속성에 이벤트 처리 함수를 등록한다.

    loader.uncaughtErrorEvents.addEventListener( UncaughtErrorEvent.UNCAUGHT_ERROR, handler );


    하나의 SWF가 다른 SWF에 로드되는 경우 UncaughtErrorEvent 이벤트 전파에 대한 처리가 필요하다.  A.swf가 B.swf를 Loader를 이용해 로드했다면 다음과 같은 순서로 LoaderInfo와 Loader 객체에 UncaughtErrorEvent 가 전파된다.

    1. (Capture phase) A.swf의 LoaderInfo
    2. (Capture phase) A.swf내의 Loader 
    3. (Target phase) B.swf의 LoaderInfo
    4. (Bubble phase) A.swf의 Loader
    5. (Bubble phase) A.swf의 LoaderInfo

    Loader객체의 uncaughtErrorEvents 속성은 결코 이벤트 전파시 target phase가 발생하지 않음에 주목하자. 그리고 이렇게 이벤트가 전파되는데는 디스플레이 리스트에 등록되어 있어야만 한다. 즉 addChild()된 객체어야한 한다. 중간에 이벤트 전파를 중단하려면 stopPropagation()이나 stopImmediatePropagation() 메소드를 이용하면 되겠다. 또한 ADL 기반나 디버그용 Flash Player에서 구동 경우 에러표시 다이얼로그가 뜨는 것을 방지하기 위해 UncaughtErrorEvent 이벤트 발생시 preventDefault() 메소드를 사용해 안뜨도록 할 수 있다.

    아래는 AIR 2.0 예제이다.

    package {
    	import flash.desktop.*;
    	import flash.display.*;
    	import flash.events.*;
    	public class UncaughtErrorEventExample extends Sprite {
    		public function UncaughtErrorEventExample()
    		{
    			var options:NativeWindowInitOptions = new NativeWindowInitOptions();
    			options.type = NativeWindowType.UTILITY;
    			
    			var window:NativeWindow = new NativeWindow(options);
    			window.width = 200;
    			window.height = 200;
    			window.title = "UncaughtErrorEventExample";
    			
    			window.stage.scaleMode = StageScaleMode.NO_SCALE;
    			window.stage.align = StageAlign.TOP_LEFT;
    			
    			window.activate();
    			window.addEventListener(Event.CLOSING, function($event:Event):void {
    				NativeApplication.nativeApplication.exit();
    			});			
    
    			var btn:Sprite = new Sprite();
    			btn.useHandCursor = true;
    			btn.buttonMode = true;
    			btn.graphics.clear();
    			btn.graphics.beginFill(0xFFCC00);
    			btn.graphics.drawRect(0, 0, 100, 50);
    			btn.graphics.endFill();
    			btn.addEventListener(MouseEvent.CLICK, clickHandler);			
    			window.stage.addChild(btn);
    			
    			loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, uncaughtErrorHandler);
    		}
    		private function uncaughtErrorHandler(e:UncaughtErrorEvent):void {
    			if (e.error is Error) {
    				var error:Error = e.error as Error;
    				// do something with the error
    				trace(error.errorID, error.name, error.message);
    			} else if (e.error is ErrorEvent) {
    					var errorEvent:ErrorEvent = e.error as ErrorEvent;
    					// do something with the error
    					trace(errorEvent.errorID);
    			} else {
    				// a non-Error, non-ErrorEvent type was thrown and uncaught
    				trace( " a non-Error, non-ErrorEvent type was thrown and uncaught " );
    			}
    			e.preventDefault();
    		}
    		private function clickHandler(event:MouseEvent):void
    		{
    			throw new Error("Gak!");
    		}
    	}
    }
    


    위 예제에서 볼 수 있듯이 AIR 애플리케이션의 노란 부분을 클릭하면 강제로 에러를 발생시킨다. 이때 이 에러를 처리하기 위한 try...catch문이 없으므로 UncaughtErrorEvent가 발생하고 그것을 처리하고 있다. 마지막에 e.preventDefault()를 둬서 에러표시 다이얼로그가 뜨는 것을 방지한다.


    1.9 Packaging an AIR application in a native installer

    AIR 2.0가 생소하게 다가오는 이유중에 하나는 바로 AIR 2.0을 설치할 때 과정이다. 뱃지(Badge)기능을 이용해 웹페이지에서 AIR 런타임 및 해당 AIR 애플리케이션을 다운로드 받을 수 있지만 그 과정이 일반 사용자에게 생소하게 다가올 수 있다. AIR 2.0에서는 이러한 생소함을 덜어주기 위해 각 OS별로 설치패키지를 따로 구성할 수 있도록 지원하고 있다. 가령, Windows는 exe, Mac은 dmg으로 설치 패키지를 구성할 수 있다는 말이다.

    AIR 2.0의 ADT의 옵션설정으로 설치 패키지를 만들 수 있다. 다음 링크를 참고한다.


    연관글






    정리하며 

    이번 글은 Adobe AIR 2.0 Overview 첫번째 글로 AIR 2.0에 추가된 새로운 기능에 대해서만 언급했다.  "기존 API에서 추가된 기능", "플랫폼 인식 관련 API", "퍼포먼스 향상"에 관련된 내용도 조만간 언급하겠다. 이 글을 읽고 AIR 2.0 기반으로 하는 다양한 애플리케이션 예제들이 많이 나왔으면 하는 바램이다.

    글쓴이 : 지돌스타(http://blog.jidolstar.com/629)
    어떤 분이 Flex 3.4환경에서 MenuBar에 색을 입히려하다가 잘 안되서 본인의 블로그에 질문을 해주셨다.


     <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    	<mx:Style>
    		MenuBar { 
    			font-weight:bold; 
    			color:#FFFFFF;
    			fill-colors:#0D0A92, #1B16F4, #37920A, #59EB12;
    			fill-alphas:1.0,1.0;
    		}
    		MenuBarItem {
    			theme-color:#0000FF;
    		}
    		Menu { 
    			alternatingItemColors:#ffffff,#eff4fa;
    			color:#000000;
    			top:4px;
    			bottom:2px;
    			horizontalGap:2px;	
    			roll-over-color:#00ff00;
    		}
    	</mx:Style>
    	<mx:MenuBar id="myMenuBar" labelField="@label" >
    		<mx:XMLList>
    			<menuitem label="MenuItem A">
    				<menuitem label="SubMenuItem A-1" enabled="false"/>
    				<menuitem label="SubMenuItem A-2"/>
    			</menuitem>
    			<menuitem label="MenuItem B"/>
    			<menuitem label="MenuItem C"/>
    			<menuitem label="MenuItem D">
    				<menuitem label="SubMenuItem D-1" 
    						  type="radio" groupName="one"/>
    				<menuitem label="SubMenuItem D-2" 
    						  type="radio" groupName="one"
    						  selected="true"/>
    				<menuitem label="SubMenuItem D-3" 
    						  type="radio" groupName="one"/>
    			</menuitem>
    		</mx:XMLList>
    	</mx:MenuBar>
    </mx:Application>
    



    질문은 MenuBarItem의 themeColor를 #0000FF로 지정했는데 저렇게 나오냐는 것이였다. 참고로 MenuBar는 저 파란색의 바를 말하는 것이고 MenuBarItem은 MenuItem A, MenuItem B...등으로 표시된 것이다. 이들은 모두 UIComponent를 상속했다. 마지막으로 Menu는 서버메뉴로써 List를 확장한 것이다.

    질문처럼 직관적으로 봐도 문제가 있어 보인다. 이렇게 나오는 이유를 알기 위해서는 스킨부분을 찾아봐야 한다.

    (아래내용이 약간 복잡할 수 있으나 천천히 따라오면 그리 복잡한 것도 아니다. 원래 이런걸 말로 설명해야 빠른 건데 글로 설명하려 하니 어렵다. ^^;)


    원인 찾기

    MenuBar의 아이템렌더러는 menuBarItemRenderer속성에 지정된다. 기본적으로 MenuBarItem 클래스가 된다. 쉽게 이야기해 위 그림에서 MenuItem A, MenuItem B... 등은 다 MenuBarItem으로 생성되어 그려진 것이다. 만약 MenuBarItem을 다른 것으로 대체하고 싶다면 IMenuBarItemRenderer 인터페이스를 구현해서 다른 MenuBarItem을 만들면 되겠다. 아래는 MenuBar의 menuBarItemRenderer 속성을 설명하고 있다.

    (문제의 원인을 파악하기 위해 가장 먼저 찾아야 할 것은 API 문서이다.)



    MenuBarItem의 스킨은 무엇일까? 아래 MenuBar에서 Style부분을 보자. MenubarItem의 스킨은 바로 ActivatorSkin 클래스라는 것을 알 수 있다. 결국 스킨도 내 마음대로 바꿀 수 있는 것이다.

    Flex 3.4에서 스킨은 크게 그래픽기반 스킨과 프로그램적 스킨(Programmatic Skin)이 있다. 그래픽기반 스킨은 이미지를 생각하면 된다. 하지만 프로그램적 스킨은 ActionScript 3.0 코드이다. MenuBar의 itemSkin 스타일 속성으로 mx.skins.halo.ActivatorSkin을 썼다는 것은 바로 프로그램적 스킨을 사용한다는 이야기이다.

    (문서를 봐도 해결의 실마리가 안보인다면 SDK를 뜯어보자!)

    그럼 이들이 어떻게 동작하는 것일까? MenuBar부터 시작해 MenuBarItem, ActivatorSkin으로 자연스럽게 찾아보면 된다. Flex 3.4 SDK 소스는 공개되어 있으므로 아래 그림처럼 Flash builder 4에서 쉽게 찾아볼 수 있다. Flex Builder 3를 사용한다면 이 기능은 사용할 수 없다.

    Flex SDK 클래스를 보려면 framework.swc를 펼쳐보면 된다.



    MenuBar 소스에서 mouseOverHandler, mouseUpHandler, mouseDownHandler 메소드들을 보자. 이들 메소드는 마우스 이벤트를 처리하는데 잘 보면 이런 코드들이 있다.

    item.menuBarItemState = "itemDownSkin";
    


    여기서 item은 IMenuBarItemRenderer 인터페이스의 참조이다. 그리고 MenuBarItem 클래스는 이 인터페이스를 구현한 것이다. 결국 MenuBarItem의 menuBarItemState 속성에 itemDownSkin이라고 지정한 것이다.

    그럼 MenuBarItem 소스의 menuBarItemState 부분을 보자.


        public function set menuBarItemState(value:String):void
        {
            _menuBarItemState = value;
            viewSkin(_menuBarItemState);
        }   
    
        private function viewSkin(state:String):void
        {  	
        	var newSkinClass:Class = Class(getStyle(state));
        	var newSkin:IFlexDisplayObject;
        	var stateName:String = "";
        	    	
        	if (!newSkinClass)
        	{
        		// Try the default skin
        		newSkinClass = Class(getStyle(skinName)); 		
        		    	
        		if (state == "itemDownSkin")
        			stateName = "down";
        		else if (state == "itemOverSkin")
        			stateName = "over";
        		else if (state == "itemUpSkin")
        			stateName = "up";
        		
        		// If we are using the default skin, then 
        		if (defaultSkinUsesStates)
        			state = skinName;
        		
         		if (!checkedDefaultSkin && newSkinClass)
        		{
    	    		newSkin = IFlexDisplayObject(new newSkinClass());
    	    		// Check if the skin class is a state client or a programmatic skin
    	    		if (!(newSkin is IProgrammaticSkin) && newSkin is IStateClient)
    	    		{
    	    			defaultSkinUsesStates = true;
    	    			state = skinName;
    	    		}
    	    		
    	    		if (newSkin)
    	    		{
    		    		checkedDefaultSkin = true;
    		    	}
        		}
        	}
        	
          	newSkin = IFlexDisplayObject(getChildByName(state));
    
            if (!newSkin)
            {
                if (newSkinClass)
                {
                    newSkin = new newSkinClass();
    
                    DisplayObject(newSkin).name = state;
    
                    if (newSkin is ISimpleStyleClient)
                        ISimpleStyleClient(newSkin).styleName = this;
    
                    addChildAt(DisplayObject(newSkin), 0);
                }
            }
    
            newSkin.setActualSize(unscaledWidth, unscaledHeight);
    
            if (currentSkin)
                currentSkin.visible = false;
    
            if (newSkin)
                newSkin.visible = true;
    
            currentSkin = newSkin;
            
            // Update the state of the skin if it accepts states and it implements the IStateClient interface.
    		if (defaultSkinUsesStates && currentSkin is IStateClient)
    		{
    			IStateClient(currentSkin).currentState = stateName;
    		}
        }
    

    MenuBarItem의 menuBarItemState에 상태변화 값을 넣어주면 MenuBarItem의 viewSkin() 메소드에서 각 상태값에 따라서 스킨을 만들어준다. viewSkin 메소드에서 newSkin = IFlexDisplayObject(new newSkinClass()); 은 새로운 스킨을 만드는 부분이 newSkinClass가 바로 ActivatorSkin 클래스가 된다. 그리고 newSkin = IFlexDisplayObject(getChildByName(state));  부분은 이전에 만든 스킨이 있는지 확인하는 부분이다. viewSkin() 메소드는 그래픽적 스킨, 프로그램적 스킨등에 모두 대응되며 게으른(lazy) 스킨 생성을 한다. 여기서 게으른 생성이라는 것은 가령, 애플리케이션이 실행 당시에 마우스 Over스킨을 생성하는 것이 아니라 마우스Over시에 스킨은 바로 그때 생성해준다는 것이다. viewSkin() 메소드가 결국 ActivatorSkin 클래스로 하여금 스킨을 만들어주는 것이다.

    ActivatorSkin 클래스의 일부분을 보자.

    	private static function calcDerivedStyles(themeColor:uint,  fillColor0:uint, fillColor1:uint):Object
    	{
    		var key:String = HaloColors.getCacheKey(themeColor,fillColor0, fillColor1);
    				
    		if (!cache[key])
    		{
    			var o:Object = cache[key] = {};
    			
    			// Cross-component styles.
    			HaloColors.addHaloColors(o, themeColor, fillColor0, fillColor1);
    		}
    		
    		return cache[key];
    	}
    
    	/**
    	 *  @private
    	 */
    	override protected function updateDisplayList(w:Number, h:Number):void
    	{
    		super.updateDisplayList(w, h);
    
    		if (!getStyle("translucent"))
    			drawHaloRect(w, h);
    		else
    			drawTranslucentHaloRect(w, h);
    	}
    
    	/**
    	 *  @private
    	 */
    	private function drawHaloRect(w:Number, h:Number):void
    	{
    		var fillAlphas:Array = getStyle("fillAlphas");
    		var fillColors:Array = getStyle("fillColors");
    		var highlightAlphas:Array = getStyle("highlightAlphas");				
    		var themeColor:uint = getStyle("themeColor");
    
    		var themeColorDrk1:Number =
    			ColorUtil.adjustBrightness2(themeColor, -25);
    
    		// Derivative styles.
    		var derStyles:Object = calcDerivedStyles(themeColor, fillColors[0], fillColors[1]);
    												 
    		graphics.clear();
    
    		switch (name)
    		{
    			case "itemUpSkin": // up/disabled
    			{
    				// invisible hit area
    				drawRoundRect(
    					x, y, w, h, 0,
    					0xFFFFFF, 0);
    				break;
    			}
    
    			case "itemDownSkin":
    			{
    				// face
    				drawRoundRect(
    					x + 1, y + 1, w - 2, h - 2, 0,
    					[ derStyles.fillColorPress1, derStyles.fillColorPress2], 1,
    					verticalGradientMatrix(0, 0, w, h )); 
    									
    				// highlight
    				drawRoundRect(
    					x + 1, y + 1, w - 2, h - 2 / 2, 0,
    					[ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
    					verticalGradientMatrix(0, 0, w - 2, h - 2));
    
    				break;
    			}
    
    			case "itemOverSkin":
    			{
    				var overFillColors:Array;
    				if (fillColors.length > 2)
    					overFillColors = [ fillColors[2], fillColors[3] ];
    				else
    					overFillColors = [ fillColors[0], fillColors[1] ];
    
    				var overFillAlphas:Array;
    				if (fillAlphas.length > 2)
    					overFillAlphas = [ fillAlphas[2], fillAlphas[3] ];
      				else
    					overFillAlphas = [ fillAlphas[0], fillAlphas[1] ];
    
    				// face
    				drawRoundRect(
    					x + 1, y + 1, w - 2, h - 2, 0,
    					overFillColors, overFillAlphas,
    					verticalGradientMatrix(0, 0, w, h )); 
    
    				// highlight
    				drawRoundRect(
    					x + 1, y + 1, w - 2, h - 2 / 2, 0,
    					[ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
    					verticalGradientMatrix(0, 0, w - 2, h - 2));
    				
    				break;
    			}
    		}
    
    		filters = [ new BlurFilter(2, 0) ];
    	}
    


    그림을 그릴때 drawHaloRect() 메소드를 호출해서 각 상태값에 따라서 그림을 그려준다. 우리가 처음 themeColor를 지정했음에도 불구하고 다른 색으로 보였던 부분을 알기 위해서는 drawHaloRect()에 switch분기점에서 "itemDownSkin"을 보면 된다. derStyles.fillColorPress1, derStyles.fillColorPress2 색을 사용하는 것을 볼 수 있으며 코드에서 derStyles는 calcDerivedStyles(themeColor, fillColors[0], fillColors[1]);에 의해 만들어진다. calcDerivedStyles() 메소드를 보면 결국 HaloColors.addHaloColors(o, themeColor, fillColor0, fillColor1); 으로 색이 결정됨을 볼 수있다. 여기서 HaloColors 클래스내에서 addHaloColors() 정적 메소드를 보면 다음과 같다.

    public static function addHaloColors(colors:Object,  themeColor:uint,  fillColor0:uint, fillColor1:uint):void
    {
    	var key:String = getCacheKey(themeColor, fillColor0, fillColor1); 
    	var o:Object = cache[key];
    	
    	if (!o)
    	{
    		o = cache[key] = {};
    		
    		// Cross-component styles
    		o.themeColLgt = ColorUtil.adjustBrightness(themeColor, 100);
    		o.themeColDrk1 = ColorUtil.adjustBrightness(themeColor, -75);
    		o.themeColDrk2 = ColorUtil.adjustBrightness(themeColor, -25);
    		o.fillColorBright1 = ColorUtil.adjustBrightness2(fillColor0, 15);
    		o.fillColorBright2 = ColorUtil.adjustBrightness2(fillColor1, 15);
    		o.fillColorPress1 = ColorUtil.adjustBrightness2(themeColor, 85);
    		o.fillColorPress2 = ColorUtil.adjustBrightness2(themeColor, 60);
    		o.bevelHighlight1 = ColorUtil.adjustBrightness2(fillColor0, 40);
    		o.bevelHighlight2 = ColorUtil.adjustBrightness2(fillColor1, 40);
    	}
    	
    	colors.themeColLgt = o.themeColLgt;
    	colors.themeColDrk1 = o.themeColDrk1;
    	colors.themeColDrk2 = o.themeColDrk2;
    	colors.fillColorBright1 = o.fillColorBright1;
    	colors.fillColorBright2 = o.fillColorBright2;
    	colors.fillColorPress1 = o.fillColorPress1;
    	colors.fillColorPress2 = o.fillColorPress2;
    	colors.bevelHighlight1 = o.bevelHighlight1;
    	colors.bevelHighlight2 = o.bevelHighlight2;
    }
    

    위에서 우리가 주목할 점은 o.fillColorPress1와 o.fillColorPress2를 설정할 때 ColorUtil.adjustBrightness2(themeColor, 85);와 같은 방법으로 새로 색을 설정하는 부분이다.

    결국 무엇인가? 지금까지 MenuBar, MenuBarItem, ActivatorSkin 클래스를 쭉 따라가며 themaColor 스타일값이 원하는대로 보여지지 않은 것은 바로 HaloColors 클래스의 addHaloColors() 부분에서 찾을 수 있는 것이다.


    해결하기

    위처럼 themeColor가 원하는대로 적용되지 않은 것 처럼 보인 이유를 분명히 알았다. Flex 3.4가 매우 잘 만들어졌다고 할지라도 이것도 결국 사람이 만든거라 완벽히 원하는대로 기능을 쓸 수 없는 경우가 생긴다. 그러면서 발생하는 문제를 해결하기 위해 단지 피상적으로 문서만 의지해서 해결하려고 하면 절대 답을 못찾을 수 있다. 표면상 문제를 해결할 수 없다면 문제의 부분을 찾기위해 SDK 소스를 위와 같이 찾아보는 스킬을 길러야 한다.
     
    어떤 문제인지 파악했으니 이제 해결해보자. 일단 기본적으로 CSS로 themeColor 와 같은 설정값으로 해결못하는 것을 알았으니 MenuBarItem에 새로운 ActivatorSkin 와 비슷한 MyActivatorSkin 을 만들고 더불어 HaloColors도 동일하게 MyHaloColors를 만들자. 이들은 기존 ActivatorSkin.as와 HaloColors.as 소스를 복사해서 만들면 된다. 물론 package부분 설정 및 include부분 설정으로 인한 에러는 제거해주자.

    MyHaloColors 클래스내에 o.fillColorPress1, o.fillColorPress2에서 ColorUtil.adjustBrightness2(themeColor, 85); 처럼 된 것을 ColorUtil.adjustBrightness2(themeColor, 0);으로 바꾸자.

    그런 다음 메인소스에 CSS에서 MenuBar 셀렉터에 itemSkin을 다음처럼 추가한다.

    MenuBar { 
    	font-weight:bold; 
    	color:#FFFFFF;
    	fill-colors:#0D0A92, #1B16F4, #37920A, #59EB12;
    	fill-alphas:1.0,1.0;
    	itemSkin: ClassReference("skins.MyActivatorSkin");
    }
    


    문제가 해결되었다.


    결론
    나는 개인적으로 Flex 프레임워크가 완벽하다고 보지 않는다. 그래도 전체적으로 잘 구조가 잘 잡혀있는 만큼 구조를 이해하고 잘 따라가보면 표면상으로만 해결하지 못한 부분을 해결할 수 있다. 너무 책과 문서에만 의존하지 말고 개발자라면 Flex 소스도 조금씩 분석해보길 바란다.

    참고로 몇가지 덧붙여 말하면...
    사실 본인은 Flex 3를 손놓은지 꽤 되었다. Flex 4도 지금 입문단계정도이다. 기본적으로 실무에서 Flex 프레임워크로 개발한다기 보다 애플리케이션의 퍼포먼스나 개발적 스타일의 문제로 ActionScript 3.0기반으로 개발한다. Flex 는 너무 유연하게 만들려고 노력해서 그런지 전체적으로 무겁다는 것을 지울 수 없어 간단히 또 빠르고 사용자에게 불편함이 없는 그런 개발이 필요할때는 Flex를 이용하지만 속도,메모리가 중요한 개발은 무조건 ActionScript 3.0으로 개발한다.

    Flex는 ActionScript 3.0으로 만들어진 프레임워크 일종이며 mxml이라는 것은 이 Flex 프레임워크를 손쉽게 쓰기 위해 도입된 xml이다. 이를 파싱해서 ActionScript 3.0으로 해석해 다시 swf로 만드는 컴파일러가 compc, mxmlc인 것이다. Flex에 대해서 이러한 점을 알고 공부하고 개발하신다면 여러가지로 도움이 될 것이다. 


    참고글

    [Flex] 자식 컴포넌트에 CSS를 적용시키는 통상적인 방법 소개
    [Flex] 스킨(Skin)을 이용하여 확장가능한 게이지 컴포넌트 제작


    글쓴이 : 지돌스타(http://blog.jidolstar.com/627)

    Adobe AIR로 만든 아주아주 간단한 웹브라우져이다. Adobe AIR는 Webkit 엔진을 내장한 HTMLLoader라는 클래스가 있다. Webkit엔진은 사파리, 구글 크롬등에 사용하는 엔진이다. Flex 4에서는 이것을 HTML로 한번 랩핑해서 사용하고 있다. Adobe AIR에서 이 엔진을 사용하면 로드되는 페이지의 DOM에 직접 접근이 가능하며 DOM 이벤트 발생시 ActionScript 3.0 함수를 호출하게끔 하는 형태로도 변경이 가능해진다. 생각보다 활용도가 무궁무진하다. 게다가 AIR 2.0부터는 한글입력 문제가 해결되었다 . 또한 HTML5/CSS3를 지원하기 시작했다.

    아래 코드는 AIR 2.0, Flash Builder 4 Beta 2 환경에서 만들었다. 이 환경을 구축하는 방법은 다음과 같이 한다.

  • 만약 Flash Builder를 설치 안했다면 다음 링크를 통해 받는다.
  • AIR 2.0 SDK와 Runtime을 다운로드 받는다.
  • 다운받은 Runtime을 실행해 설치한다.
  • (MS Windows의 경우)SDK는 압축을 풀고 그안에 있는 내용을 Flash builder가 설치된 sdks/4.0.0과 sdks/3.4.1 폴더에 각각 덮어씌운다. 본인의 경우는 C:\Program Files\Adobe\Adobe Flash Builder Plug-in Beta 2\sdks\4.0.0
  • Flash Builder를 실행한다.
  • 메뉴에서 File > New > Flex Project를 선택한다.
  • 프로젝트 이름을 적고 Application Type은 AIR를 선택한다. Finish를 한다.
  • 다음 아래 코드를 메인 코드에 복사해서 덮어씌운다.




  • <?xml version="1.0" encoding="utf-8"?>
    <!--
    	간단한 Adobe AIR 웹브라우져
    	제작 : 지용호 
    -->
    <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
    					   xmlns:s="library://ns.adobe.com/flex/spark" 
    					   xmlns:mx="library://ns.adobe.com/flex/halo"
    					   backgroundFrameRate="0.01"
    					   windowComplete="windowedapplication1_windowCompleteHandler(event)">
    	<fx:Script>
    		<![CDATA[
    			import flash.events.Event;
    			import flash.net.URLRequest;
    			import flash.net.navigateToURL;
    			
    			import mx.events.AIREvent;
    
    			private function windowedapplication1_windowCompleteHandler(event:AIREvent):void {
    				nativeWindow.x = 0;
    				nativeWindow.y = 0;
    				width = 1280;
    				height = 900;
    				//browser.htmlLoader.navigateInSystemBrowser = true;
    			}
    			private function linkClickHandler(o:Object):void {
    				navigateToURL( new URLRequest(o.currentTarget.href), "blank" );
    			}
    			private function browser_locationChangeHandler(event:Event):void {
    				trace( "browser_locationChangeHandler" );
    				tiAddress.text = browser.location;
    				btnBack.enabled = browser.historyPosition==0?false:true;
    				btnNext.enabled= (browser.historyPosition < browser.historyLength-1)?true:false;
    			}
    			private function onGoHandler(event:Event):void {
    				browser.location = tiAddress.text;
    			}
    			private function browser_completeHandler(event:Event):void
    			{
    				trace( "browser_completeHandler" );
    				tiAddress.text = browser.location;
    				var dom:Object = HTML(event.currentTarget).domWindow.document;
    				var links:Object = dom.getElementsByTagName("a");
    				for( var i:Number = 0; i < links.length; i++ ) {
    					if( links[i].target.toLowerCase() == "_blank" || links[i].target.toLowerCase() == "_new" ) {
    						links[i].onclick = linkClickHandler;
    					}
    				}
    			}
    		]]>
    	</fx:Script>
    	<s:VGroup width="100%" height="100%">
    		<s:HGroup verticalAlign="middle" paddingLeft="10" paddingRight="10" paddingTop="5" paddingBottom="5">
    			<s:Button id="btnBack" label="뒤로" click="browser.historyBack()"/>
    			<s:Button id="btnNext" label="앞으로" click="browser.historyForward()"/>
    			<s:Button label="새로고침" click="browser.reload()"/>
    			<s:Label text="주소 : "/>
    			<s:TextInput id="tiAddress" width="400" enter="onGoHandler(event)"/>
    			<s:Button label="가기" click="onGoHandler(event)"/>
    		</s:HGroup>
    		<s:HGroup verticalAlign="middle" paddingLeft="10" paddingRight="10" paddingTop="5" paddingBottom="5">
    			<s:Button label="지돌스타 블로그" click="browser.location='http://blog.jidolstar.com'"/>
    			<s:Button label="위콘 블로그" click="browser.location='http://weconize.com'"/>
    			<s:Button label="천문노트" click="browser.location='http://astronote.org'"/>
    			<s:Button label="Adobe RIA" click="browser.location='http://adoberia.co.kr'"/>
    			<s:Button label="Adobe Labs" click="browser.location='http://labs.adobe.com'"/>
    			<s:Button label="Adobe Development Center" click="browser.location='http://www.adobe.com/devnet/'"/>
    		</s:HGroup>
    		<!-- http://labs.adobe.com/wiki/index.php/Apollo:Articles:Using_HTML_in_Flex-based_Apollo_Applications -->
    		<mx:HTML id="browser" width="100%" height="100%" 
    				 location="http://blog.jidolstar.com"
    				 complete="browser_completeHandler(event)"
    				 locationChange="browser_locationChangeHandler(event)"/>
    	</s:VGroup>
    </s:WindowedApplication>
    
    

    Ajax, ActionScript 3.0, Flex, Flash등을 이용하면 AIR 애플리케이션을 만들 수 있다. Flash를 몰라도 Ajax를 알면 만들 수 있기 때문에 웹개발자들이 데스크탑 영역으로의 개발이 가능해졌다. 실제로 Ajax로 만들어진 애플리케이션도 꽤 된다. Adobe AIR 세계에 많은 개발자가 동참하길 바란다.


    글쓴이 : 지돌스타( http://blog.jidolstar.com/621 )
    어제 Adobe AIR에서 CPU 사용을 줄이는 방법에 대해서 소개했다. 이 글에 Hika님과 찬익님이 그에 대해 댓글을 달아주시며 다른 정보를 공유해주셨다. 정말 감사드린다. 이런 것이 블로그의 매력일 것이다. 블로그를 내 완벽한 지식을 전달하기 위해 쓴다는 것은 다소 어폐가 있다. 완벽한 것은 없다. 블로그는 지식 소통의 도구로 잘 활용하면 좋은 정보 공유를 통한 더욱 완전해지는 지식습득이 가능하게 한다. 난 지난 몇년간 블로그를 하면서 정말 몸소 체험했다. 지금 이글을 보고 있는 분들도 꼭 블로그를 하길 권장한다.

    각설하고. 찬익님이 Flex 4 기반에서 AIR 애플리케이션을 만들때 FrameRate를 조절하는 방법으로 backgroundFrameRate를 소개해주었다. 이것은 Event.ACTIVATE와 Event.DEACTIVATE를 이용해서 이미 Flex 4의
    WindowedApplication 클래스에 적용되어 있다. 아래 코드는 WindowedApplication 클래스의 일부이다.

    /**
    *  Constructor.
    *  
    *  @langversion 3.0
    *  @playerversion AIR 1.5
    *  @productversion Flex 4
    */
    public function WindowedApplication()
    {
    	super();
    
    	addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
    	addEventListener(FlexEvent.PREINITIALIZE, preinitializeHandler);
    	addEventListener(FlexEvent.UPDATE_COMPLETE, updateComplete_handler);
    	addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
    
    	var nativeApplication:NativeApplication = NativeApplication.nativeApplication;
    	nativeApplication.addEventListener(Event.ACTIVATE, nativeApplication_activateHandler);
    	nativeApplication.addEventListener(Event.DEACTIVATE, nativeApplication_deactivateHandler);
    	nativeApplication.addEventListener(Event.NETWORK_CHANGE, dispatchEvent);
    
    	nativeApplication.addEventListener(InvokeEvent.INVOKE, nativeApplication_invokeHandler);
    	initialInvokes = new Array();
    
    	//Force DragManager to instantiate so that it can handle drags from
    	//outside the app.
    	DragManager.isDragging;
    }
    
    /**
    *  @private
    *  Storage for the backgroundFrameRate property.
    */
    private var _backgroundFrameRate:Number = 1;
    
    /**
    *  Specifies the frame rate to use when the application is inactive.
    *  When set to -1, no background frame rate throttling occurs.
    *
    *  @default 1
    *  
    *  @langversion 3.0
    *  @playerversion AIR 1.5
    *  @productversion Flex 4
    */
    public function get backgroundFrameRate():Number
    {
    	return _backgroundFrameRate;
    }
    
    /**
    *  @private
    */ 
    public function set backgroundFrameRate(frameRate:Number):void
    {
    	_backgroundFrameRate = frameRate;
    }
    
    /**
    *  @private
    */
    private function nativeApplication_activateHandler(event:Event):void
    {
    	dispatchEvent(new AIREvent(AIREvent.APPLICATION_ACTIVATE));
    
    	// Restore throttled framerate if appropriate when application is activated.
    	if (prevActiveFrameRate >= 0 && stage)
    	{
    	    stage.frameRate = prevActiveFrameRate;  
    	    prevActiveFrameRate = -1;
    	}
    }
    
    /**
    *  @private
    */
    private function nativeApplication_deactivateHandler(event:Event):void
    {
    	dispatchEvent(new AIREvent(AIREvent.APPLICATION_DEACTIVATE));
    
    	// Throttle framerate if appropriate when application is deactivated.
    	// Ensure we've received an updateComplete on the chance our layout
    	// manager is using phased instantiation (we don't wish to store a
    	// maxed out (1000fps) framerate).
    	if ((_backgroundFrameRate >= 0) && (ucCount > 0) && stage)
    	{
    	    prevActiveFrameRate = stage.frameRate;
    	    stage.frameRate = _backgroundFrameRate; 
    	}
    }
    


    이는 Flex 4를 이용해 AIR 애플리케이션을 만들때 별도의 조치없이 backgroundFrameRate 속성 설정만으로 frameRate를 조절할 수 있다. 이 값은 기본으로 1이다. 더 좋은 값은 0.01이라고 한다. 이는 거의 멈추게 하는 수준이다. 이 속성은 Flex 4에서 AIR를 위해 WindowedApplication 에만 적용되어 있다. Flash기반인 Application 클래스에는 이 속성이 없다.
    참고글
    Adobe AIR에서 CPU 사용을 줄이는 방법

    글쓴이 : 지돌스타(http://blog.jidolstar.com/624)

    오랜만에 네이버 오픈케스트에 케스팅했습니다. 이만저만 하는게 많다보니 여기에 신경을 전혀 못쓰고 있었네요. 요즘에는 AIR분야를 좀 해보려고 하고 있습니다. 항상 눈팅만하다가 본격적으로 결과물을 내어야할 것이 생겨서 이것저것 해보는 중입니다. 이런걸 정리하다 보면 저 자신도 너무 모르는게 많고 항상 부족함을 느낍니다. 아무튼 혼자 아는 것보다 함께 알아서 서로 공유해 서로 커나가는 것이 제 생각입니다. 좋은 정보가 되길 바랍니다.

    http://opencast.naver.com/FL188/14

    글쓴이 : 지돌스타(http://blog.jidolstar.com)
    Adobe AIR는 다양한 OS(Windows, Mac, Linux)에 구동될 수 있는 애플리케이션을 만드는데 사용하는 일종의 Flash Platfom기술이다. Flash ActionScript 3.0이나 Ajax만으로도 AIR 애플리케이션을 만들 수 있기 때문에 기존에 웹개발자들이 다른 언어를 배우지 않고 일반 데스크탑용 애플리케이션을 만드는데 있어서 접근성이 좋다. 앞으로 AIR는 데스크탑뿐 아니라 모바일등과 같은 다양한 기기에도 적용될 예정이다.

    하지만 AIR외에 다른 데스크탑용 애플리케이션과 비교해 그 적용범위가 아직까지 많은 부분 부족하고 복잡한 UI를 다루는데 있어서 성능문제가 걸릴 수 있다. 하지만 AIR 2.0 Beta 버전이 오픈된 것을 볼 수 있었듯이 계속 발전해나갈 것이다. 물론 성능면에서도 마찬가지 일 것이다. 그래도 약간은 부족하다. 기능은 그렇다 쳐도 지금의 성능을  개발자가 조금만 신경을 쓴다면  획기적으로 향상시킬 수 있다.

    일전에 Reducing CPU usage in Adobe AIR라는 글을 보았다. 여기서는 매우 단순하고 쉬운 방법으로 framerate를 줄임으로서 CPU 사용율을 현격히 줄이는 방법을 소개하고 있다.

    이 방법이 퍼포먼스를 올리기 위한 방법의 하나의 예시는 될 수 있지만 그 전부는 아니라는 점은 밝혀둔다.

    (이 글을 완벽히 이해하기 위해서는 ActionScript 3.0과 AIR에 대한 전반적 이해가 요구됩니다.)

    FrameRate를 줄임
    Framerate를 줄임(Framerate throttling)은 애플리케이션의 휴면(idle)이 있을때 자원 사용을 줄여 퍼포먼스를 증가시키는 기술을 의미한다. 이를 구현하기 위해 ActionScript 3.0에서 매우 유용한 속성으로 Stage.frameRate가 있다. 이것을 이용하면 런타임시에 애플리케이션의 framerate를 변경시킬 수 있다. 

    여기서 보여지는 예제는 Reducing CPU usage in Adobe AIR에서 소개한 글에 나온 예제를 조금더 실용적으로 만들었다.(실제로 실행해 볼 수 있도록) Flash Builder 4와 AIR 2.0 SDK를 설치한 사람들이라면 이 예제를 실제로 테스트 해볼 수 있다. 아래 순서대로 개발/테스트 환경을 구축하면 된다.

  • 만약 Flash Builder를 설치 안했다면 다음 링크를 통해 받으세요.
  • SDK와 Runtime을 다운로드 받습니다.
  • 다운받은 Runtime을 실행해 설치합니다.
  • (MS Windows의 경우)SDK는 압축을 풀고 그안에 있는 내용을 Flash builder가 설치된 sdks/4.0.0과 sdks/3.4.1 폴더에 각각 덮어씌웁니다. 제 경우는 C:\Program Files\Adobe\Adobe Flash Builder Plug-in Beta 2\sdks\4.0.0
  • Flash Builder를 실행합니다.
  • 메뉴에서 File > New > Flex Project를 선택합니다.
  • 프로젝트 이름을 적고 Application Type은 AIR를 선택합니다.
  • Next버튼을 두번 클릭후 Main Application file이름이 프로젝트명.mxml로 되어 있다면 Novice.as로 바꾸세요. 그리고 Finish 버튼을 누릅니다.
  • 아래 첫번째 초급 코드를 복사해서 Novice클래스를 열어 붙힙니다.
  • 디버그 모드로 테스트합니다.
  • 두번째, 세번째의 경우 만들어진 프로젝트의 소스폴더에 해당 클래스 이름으로 Class를 만듭니다. File > New > ActionScript Class를 선택한뒤 아래 소스를 복사해 붙여넣으면 되겠죠?
  • Package Explorer에 프로젝트명을 선택후 마우스 우클릭해서 컨텍스트 메뉴에서 Properties를 선택합니다.
  • 창이 뜨면 좌측 Flex Applications를 선택하고 오른쪽에 Add를 눌러 추가한 클래스(Intermediate.as, Expert.as)를 추가한뒤 OK를 합니다. Intermediate-app.xml과 Expert-app.xml이 자동 생성됩니다.
  • 이제 디버그 모드로 실행하면서 동작하는 형태를 학습하세요.
  • 아래 소스는 다음 링크에서 다운로드 받으셔도 됩니다.



  • 초급
    Framerate를 줄일때의 시점을 선택하는데 가장 쉽고 유용한 방법은 NativeApplication에서 Event.ACTIVATE 와 Event.DEACTIVATE 이벤트를 사용하는 것이다. AIR로 만들어진 빈윈도우를 선택해서 사용할때 CPU사용율이 1.8%라면 다른 윈도우를 선택해 그 윈도우의 CPU 사용율이 0.4%까지 떨여졌다고 한다. 또한 framerate를 0.01로 지정하면 0.2%까지 떨어진다고 한다. 이에 대한 예제는 다음과 같다. 예제가 이해하기 쉬우므로 따로 설명하지 않겠다.


    package {
    	import flash.desktop.NativeApplication;
    	import flash.display.NativeWindow;
    	import flash.display.NativeWindowInitOptions;
    	import flash.display.NativeWindowType;
    	import flash.display.Sprite;
    	import flash.display.StageAlign;
    	import flash.display.StageScaleMode;
    	import flash.events.Event;
    	import flash.text.TextField;
    	import flash.text.TextFieldAutoSize;
    	import flash.utils.getTimer;
    	
    	/**
    	 * CPU 사용 줄이기 예제 1 
    	 * @author Yongho, Ji
    	 * @since 2009.12.1
    	 * @see http://blog.jidolstar.com/622
    	 */ 
    	public class Novice extends Sprite {
    		private var __isActive:Boolean = false;
    		private var __window:NativeWindow;
    		private var __textField:TextField;
    		public function Novice() {
    			__init();
    			var options:NativeWindowInitOptions = new NativeWindowInitOptions();
    			options.type = NativeWindowType.UTILITY;
    			
    			__window = new NativeWindow(options);
    			__window.width = 200;
    			__window.height = 200;
    			__window.title = "Novice";
    			
    			__textField = new TextField();
    			__textField.autoSize = TextFieldAutoSize.LEFT;
    			__textField.text = "";
    			
    			__window.stage.scaleMode = StageScaleMode.NO_SCALE;
    			__window.stage.align = StageAlign.TOP_LEFT;
    			
    			__window.stage.addChild(__textField);
    			__window.activate();
    			__window.addEventListener(Event.CLOSING,__onClosing);
    		}
    		private function __init():void {
    			NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, __onActive );
    			NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, __onDeactive );
    			stage.addEventListener(Event.ENTER_FRAME,__onEnterFrame);
    		}
    		private function __onActive($event:Event):void {
    			stage.frameRate = 50;
    			__isActive = true;
    		}
    		private function __onDeactive($event:Event):void {
    			stage.frameRate = 1;
    			__isActive = false;
    		}
    		private function __onEnterFrame($event:Event):void {
    			__textField.text =  "active:" + __isActive + " " + getTimer();
    		}
    		private function __onClosing($event:Event):void {
    			NativeApplication.nativeApplication.exit();
    		}
    	}
    }
    


    중급

    위의 예제보다 조금더 고급적으로 framerate를 조절할 필요가 있다. 가령, 마우스 휠 이벤트에 따라 스크롤이 되는 컨텐츠가 있는 경우가 그것인데 평소에는 작은 framerate를 유지하다가 스크롤시에 빠른 렌더링이 필요하므로 framerate를 올려주는 것이다. 구체적으로 MouseEvent.MOUSE_WHEEL이 발생시 framerate를 올려주고 Event.ENTER_FRAME 이벤트에서 스크롤링후 500ms이 지난 다음 다시 framerate를 줄이는 것이다. 이도 휴면(idle)상태에서 쓸데없이 렌더링되는 것을 방지하고 필요한 동작할 때만 빠른 렌더링을 요구하도록 함으로써 CPU 사용율을 줄여주는 것이다.

    package {
    	import flash.desktop.NativeApplication;
    	import flash.display.NativeWindow;
    	import flash.display.NativeWindowInitOptions;
    	import flash.display.NativeWindowType;
    	import flash.display.Sprite;
    	import flash.display.StageAlign;
    	import flash.display.StageScaleMode;
    	import flash.events.Event;
    	import flash.events.MouseEvent;
    	import flash.text.TextField;
    	import flash.text.TextFieldAutoSize;
    	import flash.utils.getTimer;
    	/**
    	 * CPU 사용 줄이기 예제 2 
    	 * @author Yongho, Ji
    	 * @since 2009.12.1
    	 * @see http://blog.jidolstar.com/622
    	 */ 
    	public class Intermediate extends Sprite {
    		private static const ACTIVE:int = 50;
    		private static const INACTIVE:int = 1;
    		private var __isActive:Boolean = false;
    		private var __isScrolling:Boolean = false;
    		private var __buffer:int;
    
    		private var __window:NativeWindow;
    		public function Intermediate() {
    			__init();
    			var options:NativeWindowInitOptions = new NativeWindowInitOptions();
    			options.type = NativeWindowType.UTILITY;
    			
    			__window = new NativeWindow(options);
    			__window.width = 200;
    			__window.height = 200;
    			__window.title = "Intermediate";
    			
    			var textField:TextField = new TextField();
    			textField.y = 20;
    			textField.width = 195;
    			textField.height = 175;
    			textField.multiline = true;
    			textField.wordWrap = true;
    			textField.border = true;
    			textField.borderColor = 0xff0000;
    			textField.text = "Adobe AIR는 다양한 OS(Windows, Mac, Linux)에 구동될 수 있는 애플리케이션을 만드는데 사용하는 일종의 Flash Platfom기술이다. Flash ActionScript 3.0이나 Ajax만으로도 AIR 애플리케이션을 만들 수 있기 때문에 기존에 웹개발자들이 다른 언어를 배우지 않고 일반 데스크탑용 애플리케이션을 만드는데 있어서 접근성이 좋다. 앞으로 AIR는 데스크탑뿐 아니라 모바일등과 같은 다양한 기기에도 적용될 예정이다.하지만 원천적으로 데스크탑용 애플리케이션과 비교해 그 적용범위가 아직까지 많은 부분 부족하고 복잡한 UI를 다루는데 있어서 성능문제가 걸릴 수 있다. 적용되는 범위는 AIR 2.0 Beta 버전이 오픈된 것을 볼 수 있었듯이 계속 발전해나갈 것이다. 또한 성능면에서도 마찬가지 일 것이다. 그래도 성능면에 있어서 개발자가 조금만 신경을 쓴다면 어떤 부분에 있어서 획기적으로 AIR 애플리케이션의 성능을 향상시킬 수 있다. 일전에 Reducing CPU usage in Adobe AIR라는 글을 보았다. 여기서는 매우 단순하고 쉬운 방법으로 framerate를 줄임으로서 CPU 사용율을 현격히 줄이는 방법을 소개하고 있다. ";
    
    			__window.stage.scaleMode = StageScaleMode.NO_SCALE;
    			__window.stage.align = StageAlign.TOP_LEFT;
    			
    			__window.stage.addChild(textField);
    			__window.activate();
    			__window.addEventListener(Event.CLOSING,__onClosing);
    		}
    		private function __init():void {
    			NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, __onActive );
    			NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, __onDeactive );
    			stage.addEventListener(MouseEvent.MOUSE_WHEEL, __onMouseWheel, true);
    		}
    		private function __onActive($event:Event):void {
    			stage.frameRate = ACTIVE;
    			__isActive = true;
    			trace( "active" );
    		}
    		private function __onDeactive($event:Event):void {
    			stage.frameRate = INACTIVE;
    			__isActive = false;
    			trace( "deactive" );
    		}
    		private function __onMouseWheel($event:MouseEvent):void {
    			if( !__isActive ) {
    				if ( !__isScrolling ) {
    					stage.addEventListener(Event.ENTER_FRAME, __onEnterFrame, true);
    				}
    				stage.frameRate = ACTIVE;
    				__isScrolling = true;
    				__buffer = getTimer()+500;
    			}
    		}
    		private function __onEnterFrame($event:Event):void {
    			if( __buffer < getTimer() ) {
    				stage.frameRate = INACTIVE;
    				__isScrolling = false;
    			}
    		}
    		private function __onClosing($event:Event):void {
    			NativeApplication.nativeApplication.exit();
    		}
    	}
    }
    


    고급

    위에서 소개한 경우보다 약간더 어려운 주제로 넘어가보자. 먼저 창이 보이지 않을때와 보일때에 어떻게 처리할 것인가이다. 보이는 경우라면 일단 최소한의 framerate를 5로 주고 안보인다면 1로 준다. 이 경우는 MS Windows에서는 Tray Icon으로 바뀌며 창이 안보여질 때나 Mac에서 Dock으로만 표시될 필요가 있을때 사용될 수 있을 것이다. 굳이 보여지지 않는데 지나친 framerate를 줄 필요가 없기 때문이다. 평상시 Active한 상태에서는 24 framerate를 유지하지면 때에 따라서 부드럽게 운동하는 모습을 렌더링할 필요가 있을 때가 있다. 상태변화에 따라 Tweener 기능을 사용하는 경우가 그것인데 이때는 평소보다 framerate를 올려줄 필요가 있을 수 있다.

    아래 AIR 애플리케이션 소스코드는 두개의 버튼이 있다. 한개는 창의 visible을 false로 지정했다가 1초후 다시 true로 해주는 것이고 또 하나는 가상의 애니메이션이 있다고 가정하고 1초정도 여분을 둔다. 각 상태가 변할때마다 framerate를 Dubugging 시에 콘솔창에서 상태변화를 확인할 수 있도록 짜여있다.

    package {
    	import flash.desktop.NativeApplication;
    	import flash.display.NativeWindow;
    	import flash.display.NativeWindowInitOptions;
    	import flash.display.NativeWindowType;
    	import flash.display.Shape;
    	import flash.display.SimpleButton;
    	import flash.display.Sprite;
    	import flash.display.StageAlign;
    	import flash.display.StageScaleMode;
    	import flash.events.Event;
    	import flash.events.MouseEvent;
    	import flash.filters.BevelFilter;
    	import flash.text.TextField;
    	import flash.text.TextFormat;
    	import flash.utils.getTimer;
    	import flash.utils.setTimeout;
    	/**
    	 * CPU 사용 줄이기 예제 3 
    	 * @author Yongho, Ji
    	 * @since 2009.12.1
    	 * @see http://blog.jidolstar.com/622
    	 */ 
    	public class Expert extends Sprite {
    		public static const ANIMATING:int = 50;
    		public static const ACTIVE:int = 24;
    		public static const INACTIVE_VISIBLE:int = 5;
    		public static const INACTIVE_INVISIBLE:int = 1;
    		
    		private var __isActive:Boolean = false;
    		private var __isAnimating:Boolean = false;
    		private var __window:NativeWindow;
    		private var __buffer:int;
    		
    		public function Expert() {
    			__init();
    			var options:NativeWindowInitOptions = new NativeWindowInitOptions();
    			options.type = NativeWindowType.UTILITY;
    			
    			__window = new NativeWindow(options);
    			__window.width = 200;
    			__window.height = 200;
    			__window.title = "Expert";
    			
    			__window.stage.scaleMode = StageScaleMode.NO_SCALE;
    			__window.stage.align = StageAlign.TOP_LEFT;
    			
    			//창을 감추기 버튼 
    			var buttonSkin:Sprite = new Sprite;
    			buttonSkin.graphics.beginFill( 0xff0000, 1.0 );
    			buttonSkin.graphics.drawRect(0,0,100,50);
    			buttonSkin.graphics.endFill();
    			buttonSkin.filters = [new BevelFilter()];
    			var textFormat:TextFormat = new TextFormat();
    			textFormat.color = 0xffffff;
    			textFormat.align = "center";
    			var textField:TextField = new TextField();
    			textField.defaultTextFormat = textFormat;
    			textField.text = "창을 감추기(1초후에 나타남)";
    			textField.width = 100;
    			textField.multiline = true;
    			textField.wordWrap = true;
    			textField.y = buttonSkin.height/2 - textField.textHeight/2; 
    			buttonSkin.addChild( textField );
    			var button:SimpleButton = new SimpleButton(buttonSkin,buttonSkin,buttonSkin,buttonSkin);
    			button.addEventListener(MouseEvent.CLICK, __onHide );
    			__window.stage.addChild( button );
    			
    			//Animation 동작 시키기 버튼 
    			buttonSkin = new Sprite;
    			buttonSkin.graphics.beginFill( 0x0000ff, 1.0 );
    			buttonSkin.graphics.drawRect(0,0,100,50);
    			buttonSkin.graphics.endFill();
    			buttonSkin.filters = [new BevelFilter()];
    			textFormat = new TextFormat();
    			textFormat.color = 0xffffff;
    			textFormat.align = "center";
    			textField = new TextField();
    			textField.defaultTextFormat = textFormat;
    			textField.text = "동작시키기(1 second)";
    			textField.width = 100;
    			textField.multiline = true;
    			textField.wordWrap = true;
    			textField.y = buttonSkin.height/2 - textField.textHeight/2; 
    			buttonSkin.addChild( textField );
    			button= new SimpleButton(buttonSkin,buttonSkin,buttonSkin,buttonSkin);
    			button.y = 52;
    			button.addEventListener(MouseEvent.CLICK, __onAnimate );
    			__window.stage.addChild( button );			
    						
    			__window.activate();
    			__window.addEventListener(Event.CLOSING,__onClosing);
    		}
    		private function __init():void {
    			NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, __onActive );
    			NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, __onDeactive );
    		}
    		private function setFrameRate( frameRate:Number ):void {
    			stage.frameRate = frameRate;
    			trace( frameRate );
    		}
    		private function animate($duration:int = 1000):void {
    			trace( "동작시작");
    			setFrameRate( 50 );
    			__buffer = getTimer() + $duration;
    			if(!__isAnimating) {
    				stage.addEventListener(Event.ENTER_FRAME,__onEnterFrame);
    			}
    		}
    		private function active():void {
    			if(!__isAnimating) {
    				setFrameRate( ACTIVE );	
    			} 
    			trace( "active " );
    		}
    		private function deactive():void {
    			if (!__isAnimating) {
    				setFrameRate( (__window.visible) ? INACTIVE_VISIBLE : INACTIVE_INVISIBLE );
    			}
    			trace( "deactive " );
    		}
    		private function show():void {
    			__window.visible = true;
    			active();
    		}
    		private function hide():void {
    			__window.visible = false;	
    			deactive();
    		}
    		private function __onActive($event:Event):void {
    			__isActive = true;
    			active();
    		}
    		private function __onDeactive($event:Event):void {
    			__isActive = false;
    			deactive();
    		}
    		private function __onEnterFrame($event:Event):void {
    			if( __buffer < getTimer() ) {
    				trace( "동작끝");
    				stage.removeEventListener(Event.ENTER_FRAME,__onEnterFrame);
    				__isAnimating = false;
    				if( __isActive ) {
    					active();
    				} else {
    					deactive();
    				}
    			}
    		}
    		private function __onHide($event:MouseEvent):void {
    			hide();
    			setTimeout(show,1000);
    		}
    		private function __onAnimate($event:MouseEvent):void {
    			animate( 1000 );
    		}
    		private function __onClosing($event:Event):void {
    			NativeApplication.nativeApplication.exit();
    		}
    	}
    }
    


    참고글
    Reducing CPU usage in Adobe AIR 
    [머드초보]시스템트레이아이콘(system tray icon) 예제


    글쓴이 : 지돌스타(http://blog.jidolstar.com/622)
    찬익님의 블로그(http://blog.chanik.com/25)로 부터 매우 재미있는 내용을 봤다. 바로 커스텀 메타데이터 태그(custom metadata tag)에 대한 내용인데 커스텀 컴포넌트, 커스텀 이벤트등의 용어는 들어봤어도 커스텀 메타데이터 태그는 생소하다. 말그대로 Flex에서 사용하는 메타데이터 태그인 [Event], [Bindable] 이런 것 들은 사실 예전부터 mxmlc로 컴파일될 때에 ActionScript 3.0으로 변환된다는 것은 알고 있었지만 메타데이터 태그가 이렇게 사용되는지에 대한 내막은 전혀 알지 못했던 것이 사실이다. 아무튼 너무 좋은 정보라 공유하고자 한다.

    사실 Flex 2시절부터 커스텀 메타데이타에 대한 이야기가 있었다고 한다. 하지만 Flex 3서부터 컴파일 옵션에 "-keep-as3-metadata MyTag"와 같은 형태로 사용할 수 있게 되었다. 이는 다음과 같이 ActionScript 3.0 코드에서 사용할 수 있게 된다.
    [Listen(obj="this.closeButton", event="click")]
    public function closeClickHandler(event:MouseEvent) {...}
    

    메타데이타 태그는 위처럼 메소드 뿐 아니라 변수 및 클래스에도 사용할 수 있다.


    커스텀 메타데이타를 사용하는 방법

    커스텀 메타데이타를 사용하는 방법은 3단계로 이뤄진다.

    1. 컴파일러 구성
    Flex 프로젝트 컴파일 옵션으로 "-keep-as3-metadata+=Meta1, Meta2" 를 삽입한다. 만약 라이브러리 프로젝트에서 한다면 거기에 이 옵션을 사용하면 이 라이브러리 프로젝트를 참조하는 다른 프로젝트에 따로 줄필요는 없다.

    2. metadata를 작성

    package
    {
        [Meta2(param1 = "param 1 value")]
        public class TestClass
        {
    
            [Meta1(param1 = "param 1 value", param2 = "param 2 value")]
            public var test1:String;
            
            
            [Meta2(paramA = "param 1 value", paramB = "param 2 value")]
            public function get test2():String
            {
                return null;
            }
            
            public function set test2(val:String):void
            {
            }
    
            [Meta1(param1 = "param 1 value")]
            public function someMethod():void
            {
            };
    
        }
    }
    

    3. 런타임(runtime)시에 작성한 메타데이타를 사용
    describeType(TestClass)를 이용한다. 위처럼 클래스와 메소드에 메타데이타를 작성했다면 다음과 같이 E4X형태의 XML로 접근할 수 있다.

    <type name="TestClass" base="Class" isDynamic="true" isFinal="true" isStatic="true">
      <extendsClass type="Class"/>
      <extendsClass type="Object"/>
      <accessor name="prototype" access="readonly" type="*" declaredBy="Class"/>
      <factory type="TestClass">
    
        <metadata name="Meta2">
          <arg key="param1" value="param 1 value"/>
        </metadata>
    
        <extendsClass type="Object"/>
    
        <method name="someMethod" declaredBy="TestClass" returnType="void">
          <metadata name="Meta1">
            <arg key="param1" value="param 1 value"/>
          </metadata>
        </method>
    
        <variable name="test1" type="String">
          <metadata name="Meta1">
            <arg key="param1" value="param 1 value"/>
            <arg key="param2" value="param 2 value"/>
          </metadata>
        </variable>
    
        <accessor name="test2" access="readwrite" type="String" declaredBy="TestClass">
          <metadata name="Meta2">
            <arg key="paramA" value="param 1 value"/>
            <arg key="paramB" value="param 2 value"/>
          </metadata>
        </accessor>
    
      </factory>
    </type>
    

    만약 Class의 [Meta2]의 param1에 접근한다면 다음과 같처럼 하면 된다.
    var testClass:TestClass = new TestClass();
    var xml:XML = describeType(testClass);
    trace(xml.metadata.(@name==Meta2).arg.(@key==param1).@value);
    

    위에 대한 결과는 'param 1 value'이 된다.


    어떻게 활용할 수 있을까?
    이것을 어떻게 활용할지에 대해서는 찬익님의 언급처럼 FlexUnit 4에서 지원하는 [Test] [BeforeClass]등과 같은 좋은 예시가 있다. 그 외에 것도 예제가 있는지 확인해봤다. 그 결과 재미있는 글을 발견했다.

    Annotating ActionScript Classes with Custom Metadata + Simple ORM Framework for AIR

    이 글에서 말하고 있는 요지는 커스텀 메타데이타를 이용해서 Value Object로 작성한 클래스에 이로 만들어진 객체가 데이타베이스의 어떤 테이블과 어떤 필드에 들어가는지 결정해줄 수 있다는 것이다.


    package
    {
    	[Bindable]
    	[Table(name="contact")]
    	public class Contact
    	{
    		[Id]
    		[Column(name="contact_id")]
    		public var contactId:int;
    
    		[Column(name="first_name")]
    		public var firstName:String;
    
    		[Column(name="last_name")]
    		public var lastName:String;
    		public var address:String;
    		public var city:String;
    		public var state:String;
    		public var zip:String;
    		public var phone:String;
    		public var email:String;
    	}
    }
    
    

    위처럼 작성된 클래스는 contactId 값은 contact 테이블의 contact_id 필드와 매치가 되도록 만든다는 것이다. [Id]메타데이타는 Primay Key와 같은 존재이다. 결국 이것을 해석해서 DB와 연동하는 AIR기반의 EntityManager를 만들어 위 클래스의 객체를 다음과 같이 사용하면 DB연동까지 된다.


    var contact:Contact = new Contact();
    contact.firstName = "Christophe";
    contact.lastName = "Coenraets";
    contact.email = "ccoenrae@adob.com";
    entityManager.save(contact);
    


    이를 수정하려면 다음처럼 쓴다.
    contact.firstName = "Chris";
    entityManager.save(contact);
    


    삭제하려면 다음처럼 쓴다.
    entityManager.remove(contact);
    

    너무 기발하다. 만약 Metadata를 사용하지 않았다면 Value Object와 DB 테이블의 필드명을 맞추기 위해 좀 노가다를 해야할지 모른다. 그런데 Metadata를 이용함으로써 프레임워크 단위로 말끔하게 이 문제를 해결해준다. 

    이에 대한 소스와 테스트 자료는 [여기]에서 다운로드 받는다.
    혹시 링크가 깨졌다면 다음 링크에서 받길 바란다. 
     
    이렇게 활용할 수 있다는 것이 감동이다. 
     

    정리하며
    찬익(http://blog.chanik.com)님 덕분에 아침부터 재미있는 정보를 얻을 수 있었다. 좋은 정보를 공유해주신 찬익님께 감사하며 커스텀 메타데이타에 대한 활용을 담은 글들이 많이 나왔으면 한다.


    참고글
    Custom metadata in three simple steps.
    Annotating ActionScript Classes with Custom Metadata + Simple ORM Framework for AIR
    찬익님의 커스텀 메타데이터 태그


    위 모든 예제는 Flash Builder 4 및 Flex Builder 3에서 테스트 해볼 수 있습니다.


    글쓴이 : 지돌스타(http://blog.jidolstar.com/620)

    안녕하세요. 1개월간 http://flexdocs.kr개인적인 이유로 운영하지 못하다가 좋은 무료웹호스팅을 통해 다시 정상적으로 열었습니다. 무료 웹호스팅 계정은 http://000webhost.com으로 외국 서비스이고 몇몇 한국분들이 잘 사용하신다고 들어서 부랴부랴 다시 복구하게 되었습니다. 약간 단점이 있다면 외국 서비스인 만큼 밤시간대에 느릴 수 있다는 겁니다.

    단, 기존에 SVN으로 Flex 2문서를 수정하는 작업이 진행되었는데 이제 그 시스템을 사용할 수 없게 되었습니다. 사실 이제 더이상 필요성을 못느끼고 있는터라 이제 안정적으로 서비스를 운영하는데만 초점을 맞출 예정입니다. 호스팅서비스 회사에서 강제로 계정을 지우거나 망하지 않는 이상 flexdocs.kr은 살아있을 겁니다.

    이제 flexdocs로 공개적인 모임이나 문서 업데이트는 하지 않을 것이며 Flex한글문서에 목마름을 조금이나마 달래주는 그런 사이트로서의 명맥을 유지할 것이라 생각합니다.

    Flex 4도 나온 마당에 버젓한 Flex 4 한글문서가 나오길 간절히 바라는 마음입니다.

    관심가져주신 분들께 깊은 감사드립니다.

    글쓴이 : 지돌스타(http://blog.jidolstar.com)

    Flash Platform 개발자 분들에게 반가운 소식이 있습니다. AIR 2.0 Beta와 Flash Player 10.1 Prelease 버전이 공개되었습니다. 이제 Adobe Labs(http://labs.adobe.com/)에서 직접 다운로드 받을 수 있습니다.


     

    Adobe AIR 2.0 beta

    AIR 2.0은 다음과 같은 새로운 feature들이 추가되었습니다.(영어 압박? 그럼 : http://blog.chanik.com/entry/AIR-20-Beta-릴리즈 )

    • Support for the detection of mass storage devices.
    • Advanced networking capabilities like secure sockets, UDP support, and the ability to listen on sockets.
    • Support for native code integration.
    • The ability to open a file with its default application.
    • Multi-touch and gesture support.
    • New APIs for access to raw microphone data.
    • Webkit update with HTML5/CSS3 support.
    • Global error handling.
    • Improved cross-platform printing
    • Improved security and support for enterprise and government standards.

    AIR 2.0에 대해서 자세한 설명 다음 글들을 참고하세요. 



    AIR 2.0으로 개발테스트 하시려면 다음과 같이 합니다. 윈도우, Flash Builder 4 beta 2 환경을 가정하고 설명드립니다.

    더 쉽게 환경을 구축하고 테스트 해보시겠다면 다음 링크를 참고하세요.
    http://blog.jidolstar.com/619 

     

    1. 만약 Flash Builder를 설치 안했다면 다음 링크를 통해 받으세요.
    2. SDK와 Runtime을 다운로드 받습니다.
    3. 다운받은 Runtime을 실행해 설치합니다.
    4. SDK는 압축을 풀고 그안에 있는 내용을 Flash builder가 설치된 sdks/4.0.0과 sdks/3.4.1 폴더에 각각 덮어씌웁니다. 제 경우는 C:\Program Files\Adobe\Adobe Flash Builder Plug-in Beta 2\sdks\4.0.0
    5. Flash Builder를 실행합니다.
      Windows>Preferences에 들어가 Flash Builder > Installed Flex SDKs를 확인해보세요.
    6. Learn to Use Adobe AIR 2 Beta에 들어가 관련 내용을 학습합니다.
    7. Adobe AIR 2 Sample Applications에 들어가 Sample을 받아보고 실제 Flash Builder에서 작업해봅시다. (해당작업화면을 이미지 캡쳐하고 이런거 너무 힘들어서요. 그냥 말로 주절주절 써봅니다.)
      저는 일단 수많은 예제들중에 Microphone 예제의 소스를 다운로드 받았습니다.
      Flash Builder에서 Flex Project를 생성합니다. 물론 Application Type은 Desktop으로 설정해야겠죠? 예제를 다운받아 사용하므로 프로젝트 이름은 예제 소스 압축을 풀어보면 메인소스의 이름을 선택해주면 됩니다. 저의 경우 MicrophoneExamples군요. 프로젝트를 생성했으면 그 다음으로 Flash Builder에서 방금 생성한 프로젝트를 선택한 상태에서 마우스 오른쪽 버튼을 눌러 Import로 들어갑니다. 창이 뜨면 General > Archive File을 선택하고 다음 버튼을 누릅니다. Browse...버튼을 눌러 다운받은 소스압축파일을 선택합니다. 그리고 Finish하세요. Overwrite할거냐 물으면 Yes To All 을 선택하시면 됩니다. 초반에 sdk 에러가 뜰겁니다. 원본 소스의 sdk 설정이 달라서 그러는데요. 이것을 해결하기 위해 프로젝트명을 선택한후 마우스오른쪽 버튼을 눌러 Properties로 들어가 Flex Compiler를 선택한 다음 Use a specific SDK를 Flex 3.4로 선택해주시면 됩니다. 4.0이 아닌 이유는 예제 소스가 mx:WindowedApplication으로 만든 것으로보아 Flex 3.4 기반으로 만들어졌기 때문입니다. 다른 예제가 s:WindowedApplication으로 만들어져 있다면 Flex 4.0을 선택하세요. 다 끝났습니다. 이제 실행해보세요.


      앗... 제 데톱에 마이크가 없군요... ㅡㅡ; 아무튼 이렇게 하면 됩니다. Sample에는 Flex뿐 아니라 Ajax, Flash용도 있으니 잘 활용하시면 학습하는데 도움이 될겁니다.

     

    Flash Player 10.1 Prelease

    Flash Player 10.1의 가장 큰 특징은 바로 모바일 지원입니다. 제 블로그에서 앞서 설명했지만 Flash Player 10.1은 오픈소스프로젝트를 통해 탄생된 결과물입니다. 데스크탑 뿐아니라 다양한 기기에서도 Adobe Flash Platform 기술이 적용될 수 있도록 Flash Player 10.1을 만든겁니다. 이는 모바일과 같이 저급(?) 하드웨어 기반에서 항상 이슈가 되어 왔던 메모리, 전력소비, 속도, 하드웨어가속등의 문제를 해결한 Flash Player를 만들었다는 것을 의미합니다. 이외에도 차세대 모바일에 걸맞는 몇가지 기능(멀티터치등)을 구현할 수 있는 API도 추가되었죠. 또한 H.264 비디오도 지원해줍니다.

    Flash Player 10.1에 대해서 더욱 자세히 알고 싶다면 Flash Player 10.1 Beta Release Notes를 참고하시면 될 것 같습니다.

    Flash Player 10.1 기반의 프로그램을 개발하고 싶다면 Flash Player 10.1 플러그인을 자신의 컴퓨터에 먼저 설치한뒤 Player Global SWC를 다운받아 개발하면 됩니다. 일련의 절차를 간단하게 설명드립니다.

    참고로 Flash Player 10.1은 정식 배포버전이 아닙니다. 테스트 목적으로 하시고 실제 배포는 하지 마세요.

    Flash Player 10.1 플러그인을 http://labs.adobe.com/downloads/flashplayer10.html 에서 다운로드 받습니다. 기존에 설치된 Flash Player는 삭제를 하시고 설치하세요. 윈도우의 경우 파이어폭스와 모질라 계열이라면 Download plug-in for Windows (EXE, 2.2 MB)를 받고 IE라면 Download active-x for Windows (EXE, 2.2 MB)를 다운로드 받으세요. 아쉽게도 개발자를 위한 디버그 버전은 아직 없는 것 같습니다.

    Flash Player 10.1 기반 개발을 위해 해당 API로 개발할 수 있도록 지원해주는 SWC를 다운로드를 같은 페이지에서 받을 수 있습니다. 다운받아 압축을 풀면 playerglobal.swc가 있습니다. 이것을 자신의 프로젝트에 포함하여 개발하면 됩니다. 함께 포함된 readme.txt파일을 보면 사용하는 방법이 잘 나와 있는데 여기서도 간단히 설명해 드리죠. (단, Flash Builder 4 beta 2 기준입니다.)

    1. 만약 Flash Builder를 설치 안했다면 다음 링크를 통해 받으세요.
    2. 새로운 애플리케이션 프로젝트를 만듭니다.
    3. playerglobal.swc를 playerglobal10.1.swf로 이름을 바꾸고 만들어진 프로젝트의 libs폴더에 복사합니다. libs폴더에 복사하면 자동으로 Referenced Libraries로 설정됩니다. (여기서 이름을 바꾼 이유는 다음 내용을 설정할 때 playerglobal.swc의 Link Type을 수정못하도록 Flash Builder가 만들어져 있기 때문입니다.)
    4. 프로젝트명을 선택후 마우스 오른쪽 버튼을 눌러 properties를 선택한 뒤 Flex Builder Path를 선택합니다. 그런 다음 Library path 탭을 선택한뒤 libs 폴더를 열어 Link Type을 External로 바꿉니다. 그런 다음 Flex 4.0 를 열어 기존 playerglobal.swc는 삭제합니다. Link type이 External이라는 것은 컴파일시 사용한 클래스를 빼놓는다는 뜻입니다. 어짜피 playerglobal.swc에 정의된 클래스는 이미 Flash player 10.1에서 지원해주기 때문에 굳이 swf안에 포함할 필요가 없기 때문이지요.
    5. Flash Player 10.1을 요구하는 HTML이 되도록 만들어주기 위해 Properties 창에서 Flex Compiler를 선택합니다. Adobe Flash Player options에서 Use a specific version을 10.1.0으로 바꾸거나 Additional compiler arguments에 -target-player=10.1.0 을 추가합니다.

    이로써 Flash Player 10.1 에서 돌아가는 Flash 애플리케이션을 만들때 환경 구축을 모두 완료했습니다.

    아래처럼 Flash Player 10.1 API인 TouchEvent, TransformGestureEvent 등을 사용할 수 있게 되었습니다.



    아래 링크를 통해 Flash Player 10.1에 대한 다양한 정보를 얻을 수 있습니다.


    앞으로 정식버전이 배포되고 Flash CS5도 나오게 되면 아이폰 및 다양한 기기에서 동작하는 재미있는 애플리케이션들을 만들 수 있게 될 것입니다. 

    Flash Platform 개발자들이여.. 향후 10년 밥벌이 벌었습니다. ㅋㅋㅋ


    글쓴이 : 지돌스타(http://blog.jidolstar.com/617)
     



    Flash, Flex, AIR 개발자들이 한권정도는 꼭 가지고 있을 만한 책이다. 이 책은 콜린 무크의 유명한 책인 Essential ActionScript 3.0을 지금도 업계에서 활발히 일하고 계신 유윤선, 송호철님이 번역한 책이다. ActionScript 3.0에 관한한 거의 바이블 수준이다. 시간될 때마다 쭉 훑어보며 느낀 거지만 ActionScript 3.0에 대한 전반적인 개념을 습득하는데 이만한 책이 없다고 생각된다. 

    Flash, Flex, AIR를 개발할 때 가장 기초가 되는 개념은 ActionScript 3.0이다. ActionScript 3.0에 대한 전반적인 개념 및 지식없이 Flex에 접근하다 보면 결국 한계를 느끼게 될 것이다. 왜냐하면 Flex 프레임워크가 모든 기능을 수행해 줄 수 있도록 만들어진 것은 아니기 때문이다. Flex는 프레임워크로서 가치가 있는 것이지 모든 기능을 Flex에서 찾으면 안된다. 또한 Flash로 개발할 때도 마찬가지 인데 타임라인만 의지하다가 뭔가 고급기술을 다뤄야할 필요가 있을때 ActionScript 3.0을 알아야 가능해진다. Flash든 Flex든 AIR든... Flash Platform 개발자가 접근할 수 있는 가장 기초가 되는 것은 결국 ActionScript 3.0이다. (예외적으로 AIR의 경우 Javascript로 만들 수 있는데 이는 컴파일러를 지원하는 차원이지 근간은 ActionScript 이다.)  

    이 책의 한가지 단점이라면 Flash Player 10 API에 해당하는 내용까지 다루지는 않고 있다. 이와 관련된 내용은 여전히 온라인의 ActionScript 3.0 라이브 독을 참고해야한다.

    글쓴이 : 지돌스타(http://blog.jidolstar.com/615

    프로그램상에 폰트를 포함할 때 다음과 같은 문장을 사용할 것이다.

    [Embed(source='C:/WINDOWS/Fonts/ARIAL.TTF', fontName = "MyFont", mimeType = "application/x-font-truetype")]
    private var font:Class;
    

    그런데 Flash Builder 4에서 작업할 때부터 위처럼 Embed한 폰트가 적용이 되지 않았다. 사용한 True Type 폰트는 언제나 테스트할때 문제없이 동작한 것이기 때문에 왜 안되는지 의문이 들었다. Flash Builder 4의 컴파일러인 mxmlc가 버그가 있거나 다른 설정이 추가되었나 싶었지만 그렇지 않았다. 그래서 열심히 구글링해봤더니 폰트를 Embed 처리할때 embedAsCFF 속성이 추가되었다는 것을 발견하고 아래처럼 테스트 코드를 작성해봤다.

    package {
    	import flash.display.Sprite;
    	import flash.text.TextField;
    	import flash.text.TextFormat;
    	import flash.text.TextFieldAutoSize;
    	import flash.text.AntiAliasType;
    	[SWF(width = "500", height = "240", backgroundColor = "#FFFFFF", framerate = "24")]
    	public class FontTest extends Sprite {
    		[Embed(source='C:/WINDOWS/Fonts/ARIAL.TTF', embedAsCFF="false", fontName = "MyFont", mimeType = "application/x-font-truetype")]
    		private var font:Class;
    		public function FontTest() {
    			var format:TextFormat = new TextFormat();
    			format.font = "MyFont";
    			format.size = 30;
    			format.color = 0x000000;
    			var label:TextField = new TextField();
    			label.embedFonts = true;
    			label.autoSize = TextFieldAutoSize.LEFT;
    			label.antiAliasType = AntiAliasType.ADVANCED;
    			label.defaultTextFormat = format;
    			label.text = "blog.jidolstar.com";
    			addChild(label);
    			label.rotation = 5;
    		}
    	}
    }
    


    여기서 embedAsCFF 속성은 도데체 뭔가? 이 전에 CFF(Compact Font Format)가 뭔지 알아야만 했다.

    폰트형태는 여러가지 종류가 있다. OTF(Open Type Font)와 TTF(True Type Font)등이 있다. OpenType은 MS와 Adobe가 TrueType의 후속작으로 Cross Platform을 지원하도록 만들 파일 포멧이라고 한다. 이 OpenType에는 Glyph Outline형식에 대한 정의는 없고 TrueType, CFF, Adobe Type 1(PostScript)를 사용한다고 한다. 이 말은 OTF중에는 TrueType으로 글자모양을 정의한 폰트도 있고 CFF 또는 PostScript Font로 정의한 폰트도 있음을 의미한다.
     
    OpenType과 TrueType에 대한 더욱 자세한 내용은 아래 링크를 참고하자.
    http://en.wikipedia.org/wiki/OpenType
    http://en.wikipedia.org/wiki/TrueType

    CFF는 OpenType의 하나로서 다음 링크에 더 세세하게 설명하고 있다.
    http://en.wikipedia.org/wiki/Compact_Font_Format#Compact_Font_Format

    CFF에 대한 스펙은 다음 파일을 참고한다.


    Flash Player 10과 Adobe AIR 1.5이상부터 TTF뿐 아니라 CFF도 지원하게 되었다. 이는 PDF와 직접적인 관계가 있는 것 같다.  그래서 폰트를 포함할때 TTF인지 CFF인지 명시할 필요에 의해 생긴 것이 embededAsCFF인듯하다. 만약 TTF를 사용한다면 위 예제처럼 embededAsCFF를 false로 지정해야한다.

    필자도 Font Type에 대한 지식은 거의 없어서 난감했다. CFF를 포함하면 글꼴 렌더링시에 텍스트를 보다 쉽게 읽을 수 있으며 작은 크기에서 글꼴의 표시 품질이 향상된다고 Adobe ActionScript 3.0 가이드 문서에는 나와 있을뿐 정확히 TTF와 CFF에 대한 명확한 해석을 찾지는 못했다.

    Adobe ActionScript 3.0 가이드 : 글꼴을 이용한 작업


    갑자기 대두된 Font 포함문제 때문에 매우 당혹스러웠지만 그나마 해결방법이라도 찾아 다행이다. 이에 대해 정확히 기술된 한글문서를 아직 찾지 못했다. 더욱 다양한 글들이 많이 올라왔으면 한다.

    이 실험은 Flash Builder 4 Beta 2에서 테스트 했으며 아래 링크로부터 Flash Builder 4를 다운받을 수 있다.
    http://www.adoberia.co.kr/pds/down.html?src=text&kw=000026



    글쓴이 : 지돌스타(http://blog.jidolstar.com/614)
    Flex 또는 ActionScript 3.0 라이브러리를 만들면서 하나의 네임스페이스를 지정키 위해 manifest설정을 하게 된다. (manifest를 모른다면 일단 Flex Builder에서 나만의 manifest만들기를 먼저 읽어보길 바란다.)

    Flash Builder 4 beta 2를 이용하면서 같은 방법으로 manifest를 설정하는데 아래와 같은 에러가 계속 나는 것이다.


    경험상 소스상에는 문제가 없는 것이기 때문에 다른 부분을 찾다가 beta 2에 있는 새로운 기능을 포착했다. 아래 이미지는 해당 프로젝트에서 Properties > Flex Library Builder Path 에서 Classes 탭을 선택했을때 화면이다. 이전 버전의 Builder에서는 보이고 있는 라디오 버튼이 없었던 것으로 알고 있는데 이번에 새롭게 들어갔나보다.

    저 기능은 라이브러리 컴파일시 컴파일할 대상의 Class를 선택하는 기능인데 이번에 기능이 바뀌면서 자동으로 모든 클래스가 포함되는 것을 선택하도록 하는 기능이 추가된 것이다. 이게 기본값이다. manifest관련 에러가 났던 것인 이 부분이 원인이였다. 다음 처럼 Select classes to Include In the library를 선택해보고 다시 컴파일하면 에러가 사라진다.


    아놔~~ 이 때문에 1시간 허비했다. 아직 beta버전이니깐 넘어가자. 정식버전 나오면 나아지겠지.

    Flash Builder 4는 이전 Flex Builder 3에 비해 너무도 많은 부분이 개선이 되었다. 이제 개발툴로서 제대로 자리매김하는 것으로 보인다. Flash Builder 4 및 다른 제품군을 다운 받기 위해 아래 링크를 참고하길 바란다.

    http://www.adoberia.co.kr/pds/down.html?src=text&kw=000026

    글쓴이 : 지돌스타(http://blog.jidolstar.com/613)
    지난 2009년 10월 5일부터 7일까지 3일간 어도비(Adobe)에서 주최하는 컨퍼런스인 Adobe MAX 2009행사에 참여하기 위해 일주일간의 일정으로 미국 LA에 다녀왔다. ACC(Adobe Community Champion)의 구성원 중에 올해는 필자를 포함한 3명이 발탁되어 이번 행사에 행사참여비를 비롯한 모든 여행경비를 거의 전액 무료로 참여하게 되었다. Adobe MAX는 Adobe의 새로운 기술과 트렌드를 공개하는 큰 행사이다. Adobe Flash Platform에 관련된 기술에 항상 관심을 가지고 지켜본터라 이번 행사의 참여는 개인적으로 매우 즐겁고 흥미로운 경험이였다.

    행사 일정은 3일이였으나 전체 미국에서의 일정은 1주일이였기 때문에 행사 일정을 제외한 나머지 시간은 LA를 둘러보는 시간도 가질 수 있었다. 개인적으로 LA에 동서댁이 살고 있어서 행사끝나고 가족상봉도 이룰 수 있어서 정말 좋은 시간이였다. 

    3일간 열리는 이번 Adobe MAX 2009행사는 노키아 극장에서 열리는 2번의 키노트 행사와 LA 컨벤션 센터에서 주제별 세션이 있었다. 키노트는 한 장소에서 모든 행사 참여자가 경청할 수 있으며 전체 흐름과 주제를 파악하는데 필요한 거의 모든 내용을 다룬다. 키노트 행사에는 수천명의 사람들이 참여한다. 반면 주제별 세션은 많게는 100명 적게는 30~40명 정도 들을 수 있는 방에서 자신이 원하는 세부적인 내용을 들을 수 있는 자리이다. 세션은 제품군, 주제, 난이도 등으로 나눠서 입맛에 맞게 골라 경청하거나 실험해 보는 자리로 꾸며진다.

    Adobe MAX 행사 참여로 누구보다 가장 빠르게 Adobe 신기술을 접할 수 있으며 또한 미국 또는 세계에서 온 각계각층의 다양한 사람들이 이 행사에 참여하기 때문에 안목을 높힐 수 있는 계기를 만들어주었다고 생각한다.

    이 글은 이번 행사를 통해 필자가 알게된 Adobe의 신기술 및 트렌드를 소개하는 것을 목적으로 한다. 

    내용중에 필자의 주관적 진술이 많이 포함되어 있다. 즉 Adobe의 정책이나 방향을 말하고 있지만 그에 대한 전망에 대한 개인적인 의견이지 Adobe의 실질적인 정책은 아님을 미리 말해둔다.


    오픈 스크린 프로젝트 - 디지털 기기간에 장벽제거


    이번 Adobe MAX에서 Flash Platform에 관심이 있는 개발자라면 바로 Flash Player 10.1과 AIR 2.0에 대한 언급이 아니였을까 생각한다. 이들 기술은 더욱 다양하고 강력한 API를 제공할 수 있게 되었다. 그러나 이 기술 자체만 관심가지는 것보다 그 기술에 어째서 만들어졌는가? 더 나아가 Adobe는 왜 이런 기술을 만들어냈는가 관심을 가져야할 것이다.

    Flash Player 10.1과 AIR 2.0은 오픈 스크린 프로젝트(Open Screen Project)의 첫번째 결실이다. 오픈 스크린 프로젝트는 지금까지 데스크탑 컴퓨터 환경을 뛰어 넘어 텔레비전, PC, 모바일 장비, 각종 소비자 가전제품등의 디지털 기기간에 호환성을 보장해주고 다양한 사용자 경험을 선사하기 위한 프로젝트이다. 이 말을 쉽게 이야기 하자면 다양한 기기에 Flash 및 AIR 애플리케이션이 운용될 수 있도록 각종 디지털 기기 업체와 협력하는 프로젝트인 것이다. 애초부터 Adobe Flash Platform 기술은 웹에서 시작해 데스크탑으로 또 각종 운영체제(Windows, Mac, Linux 등)를 지원해왔다. 하나의 애플리케이션이 다양한 환경에서도 동작하게 하기 위한 전략을 세웠던 Adobe가 이를 더 확장하기 위한 정책으로 만든 프로젝트가 바로 오픈 스크린 프로젝트인 것이다.

    오픈 스크린 프로젝트에 참여한 기업은 한국의 삼성, LG를 비롯해 Nvidia, 노키아, 모토로라, 인텔등 다양한 기기 업체들을 포함한다. 또한 각종 컨텐츠 업체들도 참여했는데 대표적으로 구글이 있겠고 BBC, MTV Networks, NBCUniversal 등도 이 프로젝트에 참여했다.

    Adobe는 자사의 기술을 널리 활용될 수 있도록 다음과 같은 적극적인 오픈 정책을 실현해왔다.
    • SWF, FLV/F4V 스팩 사용 제한을 없앰.
    • 어도비 플래시 플레이어용 모바일 단말기 포팅 레이어(APIs)를 퍼블리싱.
    • 어도비 플래시 케스트 프로토콜 및 대용량 데이터 서비스용 AMF 프로토콜을 퍼블리싱.
    • 디바이스용 어도비 플래시 플레이어와 AIR 제품의 차기 버전의 라이센스를 무상 제공.

    오픈 스크린 프로젝트의 첫번째 결실이 Flash Player 10.1과 AIR 2.0 이라고 이미 언급했다. 그럼 어째서 이 기술이 이 프로젝트의 결실물이 되는 것인가? 가장 중요하게 보아야 할 것을 뽑는다면 기능, 메모리, 속도, 전력소비량이 아닌가 생각한다.

    기능적 측면으로 Flash Player 10.1는 멀터터치가 지원되고 AIR 2.0의 경우 다양한 USB 디바이스 지원, 소켓서버, UDP통신 다양한 설치 포멧(dmg, exe등)등을 지원하게 된다. 이러한 기능이 지원된데에는 기존의 부족한 기술을 업그레이드 시키는 것외에도 오픈 스크린 프로젝트와 연관되어 사용자에게 다양한 경험을 주기 위한 것이다. 가령 요즘 모바일에 멀티터치는 기본기능으로 들어간다. 이러한 기능을 Flash 애플리케이션으로 사용할 수 있도록 한것이다. 기능은 단순히 기술을 돋보이게 하는 것이 아니라 철저한 정책 바탕위에 만들어진다.

    다양한 기기에서 Flash 컨텐츠가 문제없이 돌아가야 하므로 메모리, 속도, 전력소비량을 생각하지 않을 수 없을 것이다. 특히나 모바일과 같은 기기에서는 메모리, 속도, 전력소비량을 어떻게 최적화 시키느냐가 관건이 된다. 이는 오픈 스크린 프로젝트를 실현하기 위한 중대한 기술적 이슈로 Adobe의 노력의 결실이 이번 Adobe MAX를 통해 공개된 것이다.

    메모리의 경우 매우 괄목할 만한 성장을 보였다고 할 수 있다. 아래 그림은 키노트 당시 화면으로 각종 애플리케이션에서 기존의 Flash Player 10과 새 Flash Player 10.1 간에 메모리 사용량을 비교하고 있다. 2~3배의 메모리 사용량을 줄였음을 볼 수 있다.

    다음으로 전력소비량이다. 전력소비량도 다음 키노트 영상에서 볼 수 있듯이 모바일 기기에서 운영되는 Flash 컨텐츠가 얼마나 전력을 소비하는가 절대적 수치로 보여주고 있다. 일반적인 동영상의 경우 3.4시간, 애니메이션이 들어간 컨텐츠의 경우 6.5시간, 마지막으로 저전력 모드에서 14.5시간까지 유지할 수 있다고 한다.

    마지막으로 빼놓을 수 없는 것이 속도이다. 다양한 기기들 중에 모바일에서 움직여야하는 컨텐츠의 경우에는 적은 CPU연산으로 속도를 빠르게 하거나 GPU 가속이 필요할 것이다. 오픈 스크린 프로젝트에 참여한 Nvidia가 그것을 실현하는데 결정적인 역할을 하게 되었다. 노트북, 넷북, 스마트폰, 스마트북 등 Nvidia 지포스와 아이온, 테그라 플랫폼 등에 쓰이는 Nvidia GPU의 지원으로 낮은 전력과 CPU점유율을 Flash Player 10.1부터 가능하게 해주었다. 이로써 모바일 기기에서도 HD급 영상을 부드럽게 재생할 수 있게 되었다. 다음 동영상은 이번 키노트를 통해 공개된 속도의 최적화를 단적으로 보여준 동영상이다.



    이처럼 Adobe는 오픈 스크린 프로젝트를 통해 Flash Player 10.1과 AIR 2.0을 탄생되었으며 이들 기술은 기능, 메모리, 전력소비량, 속도등의 개선에 큰 성과를 거두었다.

    세계 전 PC에 99%이상 Flash Player가 설치되었으며 이미 두터운 사용자 층을 다지고 있는 Flash Platform 기술이 이제 Flash 애플리케이션이 모바일, 텔레비전등에도 동작하게 하는 것은 Adobe가 오래전부터 바래왔던 RIA(Rich Internet Application)의 참모습을 보여주기 위한 것이 아닌가 생각된다.

    오픈 스크린 프로젝트의 가장 큰 성과는 바로 엄청난 수의 디자이너와 개발자들이 그들이 가진 자산과 자원을 그대로 사용할 수 있다는 것에 있다. 이로써 Flash Platform 기술을 이용하는 업체들에게 시간과 자본을 매우 줄이는 결정적인 역할을 하게 된 것이다. 이전에 모바일의 Flash 컨텐츠는 Flash Lite로 ActionScript 2.0 기반하에서만 개발할 수 밖에 없는 한계가 있었다. 그러나 이 한계를 기존 Flex, Flash, ActionScript 3.0 기술을 그대로 이용해 데스크탑 뿐 아니라 각종 다양한 기기에도 운영할 수 있는 애플리케이션을 만들 수 있도록 기술적, 정책적 문제를 오픈 스크린 프로젝트를 통해 해결한 것이다. Adobe는 이제 Cross OS, Cross Browser를 넘어 Cross Device를 실현하기 위한 디딤돌을 제대로 만든 셈이다.

    불행히도(?) Apple은 오픈 스크린 프로젝트에 참여하지 않았다. 하지만 Adobe는 Adobe Flash Professinal CS5 베타버전을 선보이며 ActionScript 3.0 기반으로 iPhone용 애플리케이션을 만들어 시연하는 모습을 보여줌으로써 Flash Player가 iPhone에 탑제되어야 한다는 문제를 말끔히 씻었다. Adobe Labs에서는 CS5에 대한 설명 및 이를 이용해 만든 iPhone 애플리케이션을 소개하고 있다.

    http://labs.adobe.com/technologies/flashcs5/



    더 자세한 내용은 오픈 스크린 프로젝트 공식 홈페이지에서 알 수 있으니 참고바란다.

    오픈 스크린 프로젝트 공식 홈페이지 : http://www.openscreenproject.org/


    플래시 플랫폼 서비스 - Adobe의 강력한 유통 채널


    Adobe가 오픈 스크린 프로젝트 프로젝트를 통해 다양한 기기, OS등에 지원하도록 하는 것은 단순히 Flash컨텐츠를 공급하여 자사의 컨텐츠 제작도구를 팔기 위한 것만은 아니라고 생각한다. 물론 지금까지 Adobe는 PhotoShop, CS4, Flex Builder, LCDS등의 다양한 제품을 팔아 이윤을 남겨 회사를 운영했다고 본다. 그런데 몇년전부터 Adobe는 자사의 핵심 기술을 무료로 공개하기 시작했다. 물론 그것이 컨텐츠 제작도구는 아니지만 제품 외에 다양한 기술을 아무 댓가가 없는 것 마냥 공개하기 시작한 것이다. 이미 실시간 메세지 전송 프로토콜인 RTMP과 데이터 통신의 핵심의 일부를 BlazeDS등를 제작해 오픈 소스로 공개하고 있다. 누구든지 오픈소스 홈페이지를 통해 Adobe에서 제작한 소스를 볼 수 있다.

    요즘은 공개가 주요 덕목이라고는 하지만 Adobe가 자사의 기술을 이렇게 공개하는 이유는 무엇일까? 또한 오픈 스크린 프로젝트를 통해 Flash 컨텐츠가 다양한 자원, 기기들을 지원할 수 있도록 한 배경은 무엇일까? 이 이유에 대한 답은 이외로 간단하다. 회사는 영리를 목적으로 한다. Adobe도 건실한 하나의 회사이므로 당연히 영리를 목적으로 한다. 영리를 취하기 위한 방편으로 Adobe가 생각한 것은 바로 유통이다.

    iPhone, iPod을 사용하는 사용자라면 Apple Store에 대해서는 너무도 잘 알것이다. iPhone이라는 매우 훌륭한 기기를 만든 것도 사실이지만 Apple은 더 앞서 이들 기기에 사용할 애플리케이션이 널리 보급되고 공개될 수 있는 유통 채널을 Apple Store를 통해 확보했다. 애플리케이션 개발업체 및 개인 개발자는 Apple Store를 통해 자신의 애플리케이션을 팔 수 있고 그 이윤의 일부를 Apple이 가진다. 얼마 안되는 액수이긴 하지만 이것이 쌓이면 엄청나다. 이런 유통 채널로 무수한 애플리케이션이 만들어졌고 미려한 iPhone의 디자인에 흠뻑 반한데다가 다양한 컨텐츠까지 접할 수 있는 고객입장에서는 iPhone을 선택하지 않을 수 없게 되었다. 어디 그뿐인가? 이것으로 Apple의 매출을 최고조를 이루고 있고 자사의 회사 이미지도 상승하여 다른 제품군들의 매출도 상승하게 되었다. 이 점에서 필자가 생각하는 Apple의 가장 큰 성공요인은 유통이라고 생각한다.

    Adobe는 Apple보다 늦었지만 분명 유통의 강점을 잘 알고 있었을 것이라 생각한다. 유통을 적절하게 해서 성공한 Apple의 사례는 Adobe에게 좋은 간접 경험이 되었으리라 판단한다. 그럼 구체적으로 Adobe는 어떻게 유통을 하겠다는 것인가?

    플래시 플랫폼 서비스(Flash Platform Services)는 Apple Store처럼 유통채널을 만들기 위한 첫단추라고 생각한다. 이번 Adobe MAX 2009 키노트에서는 이에 대해 많은 부분 소개하진 않았다. 하지만 이번에 Flash Platform Service을 공개함으로서 Adobe도 Flash 컨텐츠 유통 시스템을 만들고 있다는 것을 예상할 수 있게 되었다. 

    플래시 플랫폼 서비스는 배포(Distribution), 협업(Collaboration), 소셜(Social)이라는 3가지 키워드로 요약된다.

    배포 서비스는 말그대로 Flash Platform 애플리케이션이 배포될 수 있는 공간을 만들어 준다는 것이다.
    이 서비스는 만들어진 Flash애플리케이션을 마이스페이스나 페이스북과 같은 소셜 서비스와 모바일 기기, 데스크톱등에 배포하기 위한 일련의 복잡한 절차를 해소 시켜주고 각종 프로모션 및 광고를 쉽게 해주고 각종 통계까지 내준다. 배포 서비스에 대해 더욱 자세히 알기 위해 다음 링크와 동영상을 참고한다.

    Flash Platform Distribution Service : http://www.adobe.com/flashplatform/services/distribution/

    협업 서비스는 Adobe가 Adobe자체 기술을 지원해준다는 말이다. 가령, 채팅, 오디오, 비디오 서비스등은 일반 개발자뿐 아니라 회사에게 자체 서버가 있어야하는 기술적, 자금적 부담감이 존재한다. 이런 어려운 부분을 Adobe에서 지원해준다는 이야기이다. 다음 링크로 부터 이 협업 시스템의 형태와 Showcase를 볼 수 있겠다.
     
    Flash Platform Collaboration Service : http://www.adobe.com/flashplatform/services/collaboration/
    Flash Platform Collaboration Service Showcase : http://www.adobe.com/devnet/flashplatform/services/collaboration/showcase/

    소셜 서비스은 페이스 북과 마이 스페이스와 같은 소셜 네트워크와 통합해서 이를 가지고 개발할 수 있도록 하는 서비스이다. 하지만 현재 공개되어 있지 않다. 이미 Open API를 통해 매쉬업 애플리케이션들이 만들어져 있고 그 중요성 또한 높아지고 있다. 이것을 더욱 쉽고 강력하게 할 수 있도록 소셜 서비스를 통해 지원해준 다는 것을 의미한다. 

    위에서 언급한  3가지 키워드를 바탕으로 플래시 플랫폼 서비스로 하여금 유통채널을 만들어 가겠다는 의미로 필자는 받아 들였다. 아직 많은 부분 완성되지 않았지만 앞으로 Flash Player 10.1 및 AIR 2.0 배포되고 이를 지원하는 다양한 디지털 기기들이 판매되며 또한 플래시 플랫폼 서비스의 3가지 키워드가 완성이 된다면 새로운 Flash 컨텐츠 유통채널이 만들어져서 기존 Flash Platform 개발자의 유입이 증대될 것이고 더불어 관련 애플리케이션도 많아져 결국 사용자의 경험을 극대화 시키는 효과와 함께 이것을 수용한 기술 및 제품이 잘 팔리게 되는 효과를 기대할 수 있을 것이라 생각한다. 결국 자사 만족, 개발자만족, 고객만족을 위한 Adobe의 정책이라 할 수 있다.

    이미 두텁케 형성된 Flash 컨텐츠 개발자들은 플래시 플랫폼 서비스를 통해 기존 기술을 맘껏 이용해 개발과 배포를 쉽게 할 수 있다. 그리고 각종 기기 및 기술적 어려운 부분은 오픈 스크린 프로젝트를 통해 그 문제를 해결한다. 이들 모두가 결국 Flash 컨텐츠의 유통을 실현하기 위한 정책의 일환임을 알 수 있다.

    Flash Platform Services 공식 사이트 : http://www.adobe.com/flashplatform/services/
    Flash Platform Services 개발자 센터 : http://www.adobe.com/devnet/flashplatform/services/


    정리하며
    Adobe MAX 2009 행사는 개인적으로 어떤 기술적인 답변을 얻었다것 외에 Adobe가 지향하는 정책에 대한 로드맵을 더욱 이해하는데 도움이 된 자리였다고 생각한다. 어짜피 기술은 계속 발전한다. 기술이 기술자체로 끝나는 것이 아니라 그 방향성이 더 중요하고 결국 사용자에게 감동을 주어야 그 기술이 빛을 발할 것이라 생각한다.

    Adobe가 Flash Platform의 확산을 위해 오픈 스크린 프로젝트(Open Screen Project)와 플래시 플랫폼 서비스(Flash Platform Services)라는 여러가지 대안을 마련하여 이에 기술이 뒷받침 되도록 방향성을 맞추어가고 있다는 것을 염두한다면 Flash Platform 관련 기술 적용에 더욱 도움이 될 것이라 생각한다.

    글쓴이 : 지돌스타(http//blog.jidolstar.com/610)
    Flash Builder 4 Plugin을 설치후 기존 프로젝트로 열었을때 황당한 문제에 봉착했다. 아래 그림처럼 툴바에 Run, Debug 버튼이 없어진 것이다.


    한번도 이런적이 없어서 몇시간 당황했는데, 해결방법은 이외로 간단했다.

    먼저 툴바위에 마우스 오른쪽 버튼을 눌러 Customize Perspective 를 선택한다. 또는 메뉴에서 Window > Customize Perspective 를 선택하면 되겠다. 그럼 다음과 같은 창이 나온다. 여기서 Command 탭을 선택한다.

    위 그림과 같이 왼쪽 Available command groups에 Launch를 체크한뒤 OK버튼을 누른다.



    휴~ 이거 하나 알아낼려고 엄청 힘들었다. 별것도 아닌것이... ㅎㅎㅎ

    Flash Builder 는 언제든지 다운받을 수 있다. 다음 링크를 참고바란다.
    http://www.adoberia.co.kr/pds/down.html?src=text&kw=000026 

    글쓴이 : 지돌스타(http://blog.jidolstar.com/608)

    독립형 FB4(Flash Builder 4)를 사용하지 않고 굳이 Eclipse에 FB4 plugin을 설치하는 이유는 독립형 FB4는 기능의 제약점이 있기 때문이다. 물론 FB4로도 충분히 개발이 가능하지만 Eclipse와 연동하는 것은 이 편이 실무에 더욱 적합하다. 그 이유는 hika님의 글 Flex Builder는 반드시 Plug in 으로 설치 글을 읽어보면 알 수 있다.

    하지만 이러한 설치법은 처음 해보는 사람에게는 단순하지 않다. 한방에 설치하는 독립형 FB4에 비해 이것저것 고려할 것이 많은 것 같은 생각이 들기 때문이다. 이 글을 쓰는 목적은 FB4 plugin을 설치를 하는데 있어서 다소 어려움을 쉽게 극복하기 위한 방법을 소개하기 위함이다.

    설치하는 대략적인 순서는 hika님이 매우 잘 설명해 주었다.
    Flex Builder는 반드시 Plug in 으로 설치

    그러나 더욱 자세한 방법은 Chocodonut님의 글대로 하면 되겠다.
    Flex Builder 3 Professional Eclipse plug-in 설치

    FB4도 위 글과 거의 동일한 방법으로 설치하지만 아래와 같은 몇가지 체크할 사항이 있다. (단, 본인은 Window XP환경에서 테스트 했음을 언급한다. Mac이나 Linux의 경우 아래에서 지적한 문제가 있을지는 테스트해보지 않았다.)

    1. Eclipse는 Ganymede를 설치한다.
    먼저, Eclipse버전은 Ganymede RC2 버전을 이용하기 바란다. 최신 버전인 Galileo는 제대로 설치되지 않는다.
    http://www.eclipse.org/downloads/
    에서 화면 오른쪽에 Older Versions를 선택한 뒤 Eclipse Ganymede SR2 Packages로 들어간다. 여기서 Eclipse IDE for Java EE Developers를 다운로드 받으면 되겠다. 아래 링크로 직접가도 되겠다.
    http://www.eclipse.org/downloads/packages/release/ganymede/sr2

    다운받은뒤 설치를 원하는 곳에 압축을 풀면 설치가 완료이다. 설치완료후 반드시 한번이상 실행해준다.

    만약 Galileo버전을 사용하고 싶다면 굳이 말리지 않는다. ^^
    다음 글을 참고한다.
    http://blog.naver.com/joycestudy/100090900907


    2. Eclipse실행시 JVM terminated. Exit code=-1 에러가 발생하는 경우
    Eclipse 설치폴더에 eclipse.ini를 열어 다음과 같이 수정한다.
    -showsplash
    org.eclipse.platform
    --launcher.XXMaxPermSize
    256M
    -vm
    C:\Program Files\Java\jdk1.6.0_07\bin\javaw.exe
    -Dosgi.requiredJavaVersion=1.5
    -vmargs
    -Xms40m
    -Xmx512m

    원래 eclipse.ini에서 수정된 부분은 -vmargs의 위치가 -Xms40m 바로 위로 이동된 것이며 추가된 부분은 -vm 부분이 들어간 것이다. 이때 javaw.exe 경로는 각자 jdk또는 jre 설치 경로를 따라 설정하면 되겠다. 이렇게 해도 같은 에러가 난다면 검색을 통해 다른 방법을 찾길 바란다.


    3. Flash Builder 4 plug in을 설치시 반드시 Eclipse 설치경로를 지정해줄것!
    FB4 plug in을 설치하면 중간에 Eclipse설치 경로를 지정하는 순서가 있다. 이 부분을 잊지 말고 Eclipse 경로를 지정하기 바란다.


    4. FB4를 실행할때는 Eclise를 실행하거나 FB4에 설치된 Run FB Plug-in with alternate Eclipse를 실행한다.
    FB4 plug-in에서 Run FB plug-in 을 실행하면 eclipse-host-distro의 Eclipse가 실행되므로 이것을 사용하지 말자.

    5. 바로가기를 FB4 아이콘으로 바꾸기
    일반적으로 Eclipse를 실행하기 위해 바탕화면에 바로가기를 만들거나 빠른실행아이콘으로 등록해서 사용할 것이다. 하지만 이 바로가기는 기본 아이콘이 이클립스이다. 그러므로 기존에 사용하는 이클립스 아이콘이 있다면 무엇이 Flash Builder이고 무엇이 Eclipse인지 잘 분간이 안갈터...

    바로가기의 아이콘을 Flash Builder 아이콘으로 바꿔보자.
    1. Flash Builder Plug-in이 설치된 폴더로 가서 eclipse-host-distro 폴더에 가면 Eclipse.ico 파일이 있다. 이것을 복사해서 Eclipse 설치 폴더에 복사한다.
    2. 다음으로 바탕화면 또는 빠른실행아이콘을 선택해 마우스 오른쪽 버튼을 눌러 속성을 선택한다.
    3. 아이콘 변경 버튼을 눌러 Eclipse 설치 폴더에 복사한 Eclipse.ico로 바꿔준다.

    이제 근사하게 Flash Builder 아이콘을 가진 바로가기를 만들 수 있게 되었다.


    6. 이전 워크스페이스를 열때 만약 Run, Debug 버튼이 사라진다면!
    다음 글을 참고한다.
    Flash Builder/Flex Builder의 툴바에서 Run, Debug Launch 버튼이 없어진 경우 해결법


    7. 이전 워크스페이스의 SDK경로는 따로 빼자!
    Flash Builder의 SDK가 아닌 기존에 원래 사용하던 SDK를 참조할 필요가 있는 경우가 있다. 이런 문제를 해결하기 위한 방법은 여러가지가 있겠지만 본인은 C나 D 드라이브로 SDK폴더를 따로 만들어 FB가 이 SDK를 참조하도록 하고 있다.

    다음과 같이 진행한다.

    1. C나 D 드라이브등에 사용할 SDK를 복사한다.(새 FB의 설치경로에 sdks에 있는 파일을 복사할 수 있다.)
    2. FB를 실행한다.
    2. 메뉴에서 Window > Preference를 선택한다.
    3. 창이 뜨면 좌측에 Flash Builder를 열어 Installed Flex SDKs를 선택한다.
    4. 우측에 Flex 3.4, Flex 4.0이 이전 FB버전의 경로를 참고하고 있을 것이다. 이를 C나 D드라이브에 복사한 SDK를 참조하도록 한다.


    8. 기본 플러그인 설치는 기본!
    독립형 FB4에는 설치되지 않는 플러그인이 Eclipse에는 언제든지 설치가 가능하다. 주로 협업이 이뤄지므로 SVN등을 설치해야하고 다양한 배포 경로를 확보하기 위해 ANT관련 설정이 필요할 것이다. C/C++개발을 위한 CDT, PHP개발을 위한 PDT등 플러그인을 제한없이 설치할 수 있으니 Eclipse의 FB4 plugin을 설치하는 편이 훨씬 득이라는 것을 느낄 수 있을 것이다.

    다음글들을 참고하면 좋겠다.
    Flex Builder 에서 Subversion(SVN) 사용하기
    Flex Builder 3에서 ANT 사용하기
    Maven 시작하기


    정리하며
    사실 위에 제시한 사항들은 개인적으로 사용하는 방법이다. 꼭 그렇게 따라할 필요 없으며 필요시 참조하면 무난할 것이라 판단한다.

    실무에 종업하시는 분들은 왠만하면 FB4 플러그인을 사용하고 있다. hika님의 블로그에 실무를 통해 자주 사용하는 설정정보를 정리해두었으니 참고 바란다.

    플래시를 위한 이클립스 기본 설정

    다음 글들은 이외에 개발에 큰 도움이 되는 글이니 참고 바랍니다.
    플래시 어플리케이션 개발하기
    플래시 프로젝트 생성하기


    다운로드
    Flash Builder 및 갖가지 Adobe 제품군을 다운로드 받으려면 다음 링크를 참고하세요.
    http://www.adoberia.co.kr/pds/down.html?src=text&kw=000026

    글쓴이 : 지돌스타(http://blog.jidolstar.com/607)


    다시 오픈했습니다. http://blog.jidolstar.com/618



    사용자 삽입 이미지

    Flex 2 기반으로 근 2년 이상 한글문서를 담당했던 Flexdocs.kr 서비스를 하지 못하게 되었습니다. 그동안 Flexdocs.kr은 제 개인서버에서 서비스 했습니다. 한글작업을 위해 몇몇분들이 관심을 가지고 지속적으로 수정했지만 개인서버라는 제약과 관심부족 그리고 그 서버를 유지하는데 있어서 필요이상의 개인자본을 넣어야한다는 부담이 있었습니다. 그래서 집에서 간단한 서버 구축으로 유지하려고 했으나 인터넷공급업체에서 80번 포트를 막아놓아 더 이상 서비스를 하기에는 불가능하게 되었습니다.(요즘 대부분 인터넷 공급업체는 80번 포트 이용을 막고 있습니다.)

    flexdocs.kr의 문서는 모두 제가 가지고 있습니다. 만약 flexdocs.kr을 계속 유지해야한다고 생각하시고 서버 호스팅을 무료로 해주실 수 있는 분이 있으시다면 연락부탁드리겠습니다. flexdocs.kr은 Apache, php, mysql이 지원되야하며 svn과 mod_rewrite등이 지원되면 되겠습니다.

    이 문서는 누구의 소유가 아닙니다. 상업적 용도로 사용할 수 없습니다.

     


     

    무사히 미국 LA에서의 일정을 보내고 돌아왔습니다. 주요 목적은 Adobe MAX 행사 참석이였습니다.

    ACC(Adobe Community Champion)1년 활동평가를 통해 발탁되어 좋은 기회를 가지게 되었습니다.

    행사기간은 3일이였으며 남는 시간에는 미국의 가족들과 오붓한 시간도 보냈습니다. ^^

     

    참석한 Adobe MAXAdobe의 가장 큰 행사중에 하나로 1년에 한번씩 미국의 주요 도시를 돌면서 열립니다이번 행사 참여로 Adobe 로드맵에 대해서 어느 정도 알 수 있게 되었습니다.

     

    이 로드맵의 첫번째 단추는 Adobe의 기술의 핵심인 Flash Player을 모든 플랫폼에 적용하는 겁니다. 이 플랫폼이라는 것은 모바일이 될 수 있고  각종 다른 기기들이 될 수 있을겁니다. 이것이 가능하게 하기 위해 Adobe는 Open Screen Project(http://www.openscreenproject.org/) 라는 것에 참여하고 있습니다. 이 프로젝트로 각종 기업에서 만들어지는 모바일등의 디바이스에 Flash Player가 설치되고 이미 엄청나게 보급화 되어 있는 Flash 개발인력을 어렵지 않게 흡수 시킬 수 있게 됩니다.

     

    Open Screen Project를 반영하여 탄생된 것이 바로 Flash Player 10.1 입니다. 이 Flash player 10.1은 데스크탑 뿐 아니라 모바일에도 최적화되어 돌아갈 수 있도록 메모리 및 속도 향상에 큰 변화를 가져왔습니다. 그리고 기존에 Flash Lite로만 개발했던 인력을 ActionScript 3.0, Flex 개발자들까지 모바일 프로그램을 할 수 있도록 된거지요. 메모리,속도향상등에 더욱 자세한 내용을 보고 싶다면 제 블로그를 보세요.

    http://blog.jidolstar.com/594

     

    대부분의 개발자의 주요 관심사인 Apple의 경우 Open Screen Project에 참여하지 않고 있습니다. 그래서 AdobeFlash로 개발하고 아에 iPhone용 애플리케이션이 나오도록 해버렸습니다. 이미 어도비 LabsFlash로 만든 iPhone용 애플리케이션이 애플스토어에 올라왔다는 것을 확인할 수 있습니다. 현재 직접 아이튠즈에서 다운로드 받아볼 수 있습니다.

    http://labs.adobe.com/technologies/flashcs5/appsfor_iphone/

     

    Open Screen Project를 통해 대부분의 디바이스 및 각종 플랫폼에 Flash Player가 설치될 수 있도록 하여 Adobe가 얻을 수 있는 것은 Flash 애플리케이션의 유통일겁니다. Adobe가 내놓은 모든 것들이 이제는 모두 이 유통에 집중될 모양입니다. 이에 대한 구체적인 시스템이 바로 Flash Platform Service(http://www.adobe.com/devnet/flashplatform/services/index.html) 입니다. 아래링크는 제 블로그에 올린 Flash Platform Service에 대한 전문입니다.

    http://blog.jidolstar.com/601

     

    정리하자면, AdobeOpen Screen Project를 통해 각종 디바이스에 Flash Player가 돌아갈 수 있도록 하여 시장은 선점하고 여기에 유통시장을 만들어 앱스토어 처럼 수익을 창출하겠다는 겁니다.

     

    이것이 제가 Adobe MAX에 참석해서 파악한 Adobe가 나아가는 방향입니다.

     

    (제가 정확히 파악했는지는 모르겠습니다. 사실 큰 회사의 전체적인 로드맵을 이 짧은 글에 담는 것은 많이 부족하겠지요. 잘못된 내용이나 보강할 내용있다면 댓글 또는 트랙백 걸어주시길 바랍니다.)

     

    글쓴이 : 지돌스타(http://blog.jidolstar.com/603)

    여러분은 지금 Flash로 만든 iPhone, iPod 용 애플리케이션을 애플 스토어에서 다운로드 받을 수 있습니다. Adobe Lab(http://labs.adobe.com)에서 올해 말에 나올 Flash Professional CS5를 홍보하기 위해 떡밥 제대로 내놯습니다. ^^

     

    공식 페이지는 아래 링크를 찾아가세요.

    http://labs.adobe.com/technologies/flashcs5/

    http://labs.adobe.com/technologies/flashcs5/appsfor_iphone/

     

    아래 이미지를 클릭하면 아이튠즈를 통해 받을 수 있습니다. 무료도 있고 유료도 있어요. (아이튠즈가 설치 되어있어야 겠죠?)

     

     

    Chroma Circuit

    chromacircuit

    Trading Stuff

    trading

    Fickleblox

    fickleblox

    Just Letters

    justletters

    South Park

    southpark

    That Roach Game

    roach

    Red Hood

    redhood
     

     

     

    Flash로 아이폰 프로그램을 만든다?!

    Flash/Flex 개발자들 사이에서는 큰 반향일 일으킬게 분명합니다.

    국내에도 곧이어 아이폰이 나온다는데 하고 싶은 개발의 폭이 한층 넓어지겠네요.

     

    단! 기능은 기능일 뿐입니다.

    사업적 가치를 위해서 어떻게 접근할 것인가는 Object-C든 Java든 ActionScript 든 같습니다.

     

    아~ 그리고... 미국애들은 아이팟말고 아이폰만 사용하더군요. 덕분에 MAX 행사 내내 아이팟은 제대로 꺼내보지 못했습니다. ㅋ 그러니까 저 프로그램인 아이폰용으로만 작동될 수도 있다는 거죠. ^^

     

    글쓴이 : 지돌스타(http://blog.jidolstar.com/602)

    Adobe MAX 2009 긴급 뉴스입니다. ^^

    Flex/Flash 개발자들에게 개발하면서 가장 귀찮은 작업이 무엇일가요?

    제 생각에 세세한 조절을 위해 코드를 수정할 때일겁니다. 가령, 100px 움직여야하는 디스플레이 객체를 90,80,70씩 움직여가며 가장 좋은 결과를 보여준다던가 하는 일을 해야할 경우 코딩후 실행, 종료후 코드 수정다음 다시 실행하는 작업을 반복해야할 겁니다.

    Adobe MAX 2009 둘째날 저녁에 열린 MAX Bash@LA Live 행사에서 공개한 Flash Builder는 위의 문제를 해결하기 위해 Edit/Continue 기능을 소개했스니다. 듣기로 이 기능은 이미 일본의 Spark 프로젝트 팀에서 먼저 한걸로 알고 있는데요. Anyway....

    Edit/Continue 기능은 디버깅 중간에 코드를 수정하면 바로 실행중간에 결과가 반영된다는 겁니다! olleh!!!
    Flash Platform 개발자들의 수고를 한층 덜어주는 기능이군요. 제 생각에 이 기능은 Flash Builder 정식버전 및 Flash CS5에서 적용되지 않을까 생각됩니다. 아주아주 기대가 큰 기능입니다.

    이 기능이 가능한 것은 어짜피 컴파일 결과물이 AVM2상 메모리에 올라가고 변경된 코드와 대응하는 메모리상의 위치의 값을 변경하는 일이기 때문입니다.

    우야꼬 블로그에 가면 키노트 상황을 생생히 사진으로 담았다는... ^^
    [at MAX] Sneak peek - Flash Builder Debugging "Edit and Continue"

    물론 당연히 있어야할 기능이 들어간 것일뿐입니다만... ㅎㅎ
    점점더 Flash 개발자들의 편의를 극대화 시켜주는 군요. 정말 반가운 소식입니다. ^^

    Flash Builder는 아래 링크에서 다운로드 받을 수 있어요.

    글쓴이 : 지돌스타(http://blog.jidolstar.com/597)


     

    실무에 바로 쓸 수 있는있는 유용한 Flash/Flex 기반 ActionScript 3.0 라이브러리들입니다. 3번째 라이브러리도 조만간 소개하겠습니다. ^^

     

    http://opencast.naver.com/FL188/12

     

    글쓴이 : 지돌스타(http://blog.jidolstar.com/591)

     

    실무에 바로 쓸 수 있는 유용한 Flash/Flex 기반 ActionScript 3.0 라이브러리들입니다.

    이들을 이용해서 많은 테스트들이 이뤄졌으면 합니다. 물론 관련내용을 블로깅해서 트랙백도 걸어주시면 좋겠어요 ^^

     

    다음주에는 다른 라이브러리를 소개하겠습니다.

     

    http://opencast.naver.com/FL188/11

     

    글쓴이 : 지돌스타(http://blog.jidolstar.com/590)

     

     

     

    구를 표현하는데 있어서 많은 3D 예제들이 그냥 경도, 위도로 나눠서 텍스쳐 입히는 것이 대부분입니다. 사실 그게 가장 쉬운 방법이고 완성된 구를 표현할 것 같으면 그편이 좋습니다.

     

    Geodesic Sphere에 대한 프로그램 코드는 그리 많지 않은 것 같더군요. 대신 건축물은 왜 이렇게 많은지.. ㅎㅎ 이 형태의 구로 만든 건축물이 매우 이쁘고 독특해보이죠. 디즈니랜드의 Epcot Dom이 매우 유명한 Geodesic Sphere의 한종류이죠.

     

     

    응용하면 아래처럼 의자도 만들 수 있네요. 왠지 세련되어 보입니다.

     

    Geodesic이라는 말은 두점간에 최단선(측지선)을 의미합니다. 이 원리를 이용해 만든 구가 바로 Geodesic 구라는 것이지요.

     

    구글 어스(Google Earth)와 같은 3D 프로그램에서 구의 형태를 어떻게 표현했다고 생각하시나요? 정확히는 모르겠지만 Geodesic Sphere 기법을 이용했을 거라 추측합니다. 구글어스에 보이는 지도는 타일 이미지들의 모임입니다. 만약 경도,위도로 그 타일 이미지를 나눠버리면 결국 극쪽(북극, 남극)쪽에 불러와야할 타일 이미지는 엄청 많아지겠죠. 확대할수록 더할 겁니다. 이런 점에 비춰볼때 3D에서 Geodesic Sphere의 선택이 필요할 것 같아집니다.

     

    Geodesic Sphere를 표현하는 방법은 다양합니다. TETRAHEDRON, OCTAHEDRON, ICOSAHEDRON 기반등을 이용해 그려나갈 수 있지요. 아래처럼요.

     

    출처 : http://www.geepers.co.uk/software/geodesicsphere.html

     

    아직 3D 지도에 어떤 방식이 좋을지 명확히 판단하지 못했지만 OCTAHEDRON 또는  ICOSAHEDRON  기반이 아닐까 생각합니다.

     

     

    회전 : 마우스 드래그

    폴리곤수 조절 : 방향키 Up/Down

     

    Flash 3D API의 drawTriangle 메소드 기반으로 그려본겁니다. 일반 경도, 위도만을 가지고 그릴때보다 복잡한 편이라 애를 먹었습니다. 극부분이 이미지가 찌그러져보이는 것은 UV설정이 잘못되었기 때문입니다. 이부분에 대한 보완이 필요합니다. 어쨌든 3D 지도 기반을 만들기 위한 첫단추를 꽨 셈이군요. ^^

     

    소스코드 아래 링크에서 볼 수 있습니다.

    http://wonderfl.net/code/73c32973543fd5d1827ae725ae92f143784b5f97 

     

    글쓴이 : 지돌스타(http://blog.jidolstar.com/589)

     

    Flash에서 이미지 처리는 지금까지 BitmapData 조작이였다. 싱글스레드 기반의 Flash Player는 이미지 조작을 하기에 좋은 퍼포먼스를 가지기 어려웠다. 하지만 Flash Player 10부터 멀티스레드를 기반으로하는 Adobe Pixel Bender를 지원함에 따라 이제 이미지 프로세싱에 Flash의 막강화력을 보여줄 수 있게 되었다. Adobe Pixel Bender에 대한 국내 문서는 그다지 많지 않은 편이지만 앞으로 Flash/Flex/ActionScript 개발자들에게 각광받는 기술이 될 것임에 틀림없겠다.

     

    Opencast 보러 가기 : http://opencast.naver.com/FL188/10

     

    글쓴이 : 지돌스타(http://blog.jidolstar.com/588)

     

    Adobe Flash, Flex, AIR 에 관련된 강좌들을 모아봤습니다.
    공부하는데 큰 도움이 될 것이라 생각합니다.

     

    http://opencast.naver.com/FL188/9

     

    글쓴이 : 지돌스타(http://blog.jidolstar.com/583)

    한글 에러 : ArgumentError: Error #2180: AVM1 내용(AS1 또는 AS2)이 AVM2(AS3) 내용으로 로드된 경우 AVM1 내용을 displayLis의 다른 부분으로 이동할 수 없습니다."

     

    영문 에러 : ArgumentError: Error #2180: It is illegal to move AVM1 content (AS1 or AS2) to a different part of the displayList when it has been loaded into AVM2 (AS3) content.


    위와 같은 에러를 본 적이 있는가?

     

    이것은 Flash Player 9 버전으로 만들어진 애플리케이션에서는 발생하지 않는다. Flash Player 10 버전으로 만들어진 애플리케이션에서 위와 같은 문제가 발생한다.

     

    위 에러가 발생하는 조건은 다음과 같다.

     

    1. AVM2(ActionScript Virtual Machine 2)기반으로 만들어진 Flash 애플리케이션
      AVM2 기반이라는 것은 ActionScript 3.0 기반으로 만들어진 애플리케이션을 의미한다.
    2. Flash Player 10 기반으로 컴파일한다.
      컴파일 옵션에서 Flash Player 버전을 9.0.124 등이 아닌 10.0.0을 기반으로 한다.
    3. 위 두 조건하에서 AVM1기반으로 만들어진 SWF파일을 flash.display.Loader를 이용해 로드한다.
      AVM1 기반이라는 것은 ActionScript 1.0 또는 ActionScript 2.0 기반으로 만든 SWF파일을 의미한다.
    4. Loader.contentLoaderInfo.content를 addChild() 한다.
      Loader는 외부의 이미지, 플래시 파일등을 로드해서 디스플레이 객체로 등록하는 일종의 wrapper역할을 담당한다. 이들을 로드완료하면 Loader.contentLoaderInfo.content에 해당 객체의 참조를 얻을 수 있다. 일반적으로 화면에 출력하기 위해 addChild( Loader ) 식으로 하면 되는데 이렇게 안하고 addChild( Loader.contentLoaderInfo.content ) 를 하는 경우다. 이것이 가능한 이유는 Loader.contentLoaderInfo.content 도 DisplayObject이기 때문이다.

     

    위 조건에 맞춰서 ActionScript 3.0 기반으로 코딩을 아래와 같이 해보겠다.

     

    package
    {
    	import flash.display.DisplayObject;
    	import flash.display.Loader;
    	import flash.display.LoaderInfo;
    	import flash.display.Sprite;
    	import flash.events.Event;
    	import flash.net.URLRequest;
    	
    	public class AVM1LoadTest extends Sprite
    	{
    		private var loader:Loader;
    		
    		public function AVM1LoadTest()
    		{
    			loader = new Loader();
    			loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoadComplete);
    			loader.load( new URLRequest("avm1asset.swf") );	
    		}
    		
    		private function onLoadComplete( event:Event ):void
    		{
    			var loaderInfo:LoaderInfo = event.target as LoaderInfo;
    			trace( loader.numChildren );
    			trace( loaderInfo.content.parent );
    			var avm1asset:DisplayObject = loaderInfo.content;
    			addChild( avm1asset );
    			trace( loader.numChildren );
    			trace( loaderInfo.content.parent );
    		}
    	}
    }
    

     

     

    위 프로그램을 Flash Player 9 버전으로 컴파일하고 실행해보자. (실행되는 Flash Player 버전은 10이어야 한다. 당연히 실험 애플리케이션이 Flash Player 9버전 뿐 아니라 10버전도 만들 것이기 때문이다.)

     

    아래 화면과 같이 AVM1 기반 SWF를 예쁘게 출력해준다.

     

     

    onLoadComplete() 안을 살펴보면 addChild() 앞뒤로 똑같은 trace()문이 있다. 이것은 addChild() 전후로 loader.numChildren과 loaderInfo.content.parent(이것은 loader.content.parent와 같다)의 변화를 살펴보기 위함이다. loader.numChildren은 Loader 객체에 로드된 AVM1객체가 자식으로 등록되어 있는 경우에는 1이 출력되고 그 반대는 0이 된다. loaderInfo.content.parent는 로드된 AVM1객체의 부모가 무엇인지 가리킨다.

     

    결과는 다음과 같다.

     

    1
    [object Loader]
    0
    [object AVM1LoadTest]

     

    무엇을 의미하는가? addChild()를 하기 전에는 AVM1객체는 Loader의 자식이지만 addChild() 후로는 AVM1LoadTest객체의 자식이 된다. AVM1LoadTest는 위 프로그램의 메인 클래스이다. 이것은 당연한 결과로 자식은 두개 이상의 부모를 가질 수 없는 것을 의미한다. Flash Player 9버전으로 만든 경우에는 이러한 코딩이 가능했다.

     

    조건을 바꿔보자. 이제 위 프로그램을 Flash Player 10 버전으로 컴파일하고 실행해보자. 언급했던 에러가 발생한다.

     

    "ArgumentError: Error #2180: AVM1 내용(AS1 또는 AS2)이 AVM2(AS3) 내용으로 로드된 경우 AVM1 내용을 displayLis의 다른 부분으로 이동할 수 없습니다."

     

    무엇을 의미하는가? Flash Player 10 기반으로 만들어진 애플리케이션은 AVM1 객체를 AVM2 기반의 디스플레이 객체로의 이동을 불허한다. 즉 Loader에서 떠나지 못함을 의미한다.

     

    Flash Player 10기반에서 AVM2 SWF를 로드한 경우는 addChild( loader.contentLoaderInfo.content ) 가 가능할까? 이것은 된다!

     

    Flash Player 10에서 AVM1기반의 SWF는 부모로 Loader이어야만 하는 이유는 무엇일까? 사실 여기에 대한 답변을 나는 아직 찾지 못했다. 혹시 아시는 분은 댓글 및 트랙백을 부탁한다.

     

    일본에서는 이미 이 문제로 고민한 사람이 꽤 있었다. 재미있게도 AVM1을 AVM2로 강제로 바이트 단위로 버전을 수정해 버려 로드해버리는 커스텀 Loader까지 만들어 배포하는 사람이 있었다. 좋은 방법인지는 모르겠지만 아무튼 이런 연구가 활발히 진행되는 일본이 부럽당.. ㅡㅡ

     

    Illustrator의 벡터형식 데이터를 읽어들이는 방법(Loader 클래스편)

    Illustrator의 벡터형식 데이터를 읽어들이는 방법(Embed 태그 편)

    BeInteractive - AVM2에서 AVM1의 SWF를 억지로 로드하는 ForcibleLoader 

    BeInteractive - AVM2에서 AVM2의 SWF를 억지로 로드하는 방식 해설

    ForcibleLoader 다운로드

    ForcibleLoader 브라우징하기

     

    흑... 이것도 spark 프로젝트....


    아래 내용도 보면 좋을거다.

    로드한 SWF 내부에 작성된 ActionScript 3.0 클래스 이름 찾기

     

    글쓴이 : 지돌스타(http://blog.jidolstar.com/582)

     

     

    Flex Builder 또는 Flash Builder 에서 유용하게 사용할 수 있는 플러그인을 소개했습니다. 더 많을 것이라 생각하는데 함께 공유했으면 좋겠네요. 댓글, 트랙백 모두 환영합니다.

    http://opencast.naver.com/FL188/8


    참고로 Flash Builder는 아래 링크로 가서 다운받으세요.
    http://www.adoberia.co.kr/pds/down.html?src=text&kw=000026 


    글쓴이 : 지돌스타(http://blog.jidolstar.com/581)

    + Recent posts