1. Native Extension 구조의 이해


우선 개발에 앞서서 Native Extension에 대한 이해가 필요합니다.


Native Extension은 ActionScript Library와 iOS 또는 Android Library와 함께 컴파일되서 *.ane 파일이라는 결과물로 나옵니다.


우리가 개발할 앱에서는 이 *.ane 파일만 있으면 됩니다.


이 *.ane 파일에는 Flash 코드와 Native 코드가 모두 들어있어서 Flash Builder 4.6 이상부터는 자동완성도 가능하고 개발하는데 전혀 지장없습니다.


이 ane 파일에 대해서 간략하게 설명하자면


Flash와 JavaScript가 통신하는 것과 비슷합니다.


서로 약속된 메소드와 프로토콜을 기반으로 Flash 코드와 Native 코드를 하나의 *.ane파일로 만들어주는 것입니다.


즉 Flash쪽에서 


extension.call( "showMessage" );


라고 호출하기로 했다면


iOS에서는 showMessage라는 호출에 대응할 메소드를 제공해줘야합니다.


FREObject showMessage( FREContext context, void* data, uint32_t argc, FREObject param[] )
{
    // do something
} 

void ContextInitializer( void* data, const uint8_t* type, FREContext context, uint32_t *functionNumber, const FRENamedFunction** functions )
{
    ....생략....

    function[ 0 ].name = (const uint8_t*) "showMessage";
    function[ 0 ].functionData = NULL;
    function[ 0 ].function = &showMessage;

    ....생략....
}


이처럼 서로 약속된 프로토콜 전제하에 개발되어야 정확하게 동작합니다.


이렇게 서로 약속된 프로토콜에 따라 만들어진 ActionScript Library에서 만들어진 swc파일과 iOS에서 만들어진 *.a 파일을 가지고 *.ane 파일을 만들게 됩니다.




제 강좌에서는 Flash쪽에서 메세지를 보내면 디바이스의 기본 팝업으로 띄우는 간단한 앱을 만들어 볼 겁니다.


기대되요? ㅋㅋ





2. Project 생성



먼저 Xcode > File > New > Project 에서 


Framework & Library의 Cocoa Touch Static Library로 프로젝트를 생성합니다.



Product Name과 Company Identifier가 합쳐져서 App ID가 되므로


잘 네이밍을 해줍니다.


(프로비져닝 파일을 "*"로 해줬다면 어떤걸로 지어줘도 무방합니다.)


Next를 누르면 저장할 위치를 선택해주고나면 다음과 같이 프로젝트가 생성됩니다.



아무것도 손대지 말고 (복잡하니까) 바로 다음단계로 넘어갑니다.


Adobe Flash Builder의 SDK가 설치된 폴더에 가면


include폴더 밑에 FlashRuntimeExtensions.h 파일이 보일겁니다.



제 경우에는 


/Applications/Adobe Flash Builder 4.6/sdks/AIR 3.4/include/


위치에 있네요.


SDK는 가능하면 최신을 권장합니다.


이 FlashRuntimeExtensions.h 파일을 파인더에서 Xcode의 소스 있는데로 드래그해줍니다.



그럼 이렇게 묻는게 나오는데 맨 위에 체크박스를 해석해보자면


Destination ㅁ Copy items into destination group's folder (if needed)


파일 위치 ㅁ 필요하다면 프로젝트 폴더로 파일을 복사하기


라는 뜻입니다.


뭔 말인고 하니 체크를 하면 실제 파일을 복사해서 Xcode 프로젝트의 소스 폴더로 복사해온다는 뜻이고


체크 안하면 그냥 원본 파일의 경로로 참조만 한다는 뜻입니다.


저는 그냥 불안해서 항상 체크해서 복사해서 가져다 씁니다.


(지울지도 모르자나요 ㅋ)



복사해서 오면 위 그림과 같이 놓여져있을 겁니다.


셋팅은 끝났고 이제 코딩에 들어갑시다.




3. Extension 개발


AlertExtensions.m 파일을 선택하고 


import 구문에 다음과 같이 FlashRuntimeExtensions.h 헤더 파일을 임포트해줍니다.


#import "FlashRuntimeExtensions.h"
#import "AlertExtension.h" 


그리고 아래와 같이 메소드를 추가해줍니다.



다음과 같이 5개의 메소드를 순서대로 만들어줍니다. 


(언어가 C++ 이기 때문에 메소드 선언 순서도 중요합니다. 제가 모르고 해매서 그런거 아니에요.)


// 이 메소드를 플래시에서 호출할 것이다.
FREObject alert( FREContext context, void* data, uint32_t argc, FREObject param[] )
{
    return NULL;
}

void ContextInitializer( void* data, const uint8_t* type, FREContext context, uint32_t *functionNumber, const FRENamedFunction** functions )
{
    
}

void ContextFinalizer( FREContext context )
{
    
}

// 초기화 생성자로 사용할 메소드
// ANE를 생성할 때 메소드명을 정확하게 지정해줘야 하므로 기록해두자.
void AlertExtensionInitializer( void** data, FREContextInitializer* initializer, FREContextFinalizer* finalizer )
{
    
}

// 소멸자로 사용할 메소드
// 이 역시도 ANE를 생성할 때 메소드명을 정확하게 지정해줘야 하므로 기록해두자.
void AlertExtensionFinalizer( void* data )
{

}    

각 메소드의 역할은 다음과 같습니다.


void ContextInitializer( void* data, const uint8_t* type, FREContext context, uint32_t *functionNumber, const FRENamedFunction** functions )


런타임에 의해서 호출되는 메소드입니다.


Flash 쪽에서 createExtensionContext()로 Native Extension 객체를 생성하면 자동으로 호출되는 메소드입니다.


void ContextFinalizer( FREContext context ) 


마찬가지로 Flash 쪽에서 객체가 메모리에서 제거될 때 호출되는 메소드입니다.


void AlertExtensionInitializer( void** data, FREContextInitializer* initializer, FREContextFinalizer* finalizer ) 
void AlertExtensionFinalizer( void* data )


위 두 개의 메소드 ContextInitializer, ContextFinalizer는 Native Extension에서 자동으로 호출되는 메소드인 반면에


이 두 메소드 AlertExtensionInitializer, AlertExtensionFinalizer는 우리가 원하는 초기화 과정을 실행할 수 있도록 사용되는 메소드입니다.


그렇기 때문에 이 두 메소드는 *.ane 파일을 만들때 어떤 메소드들을 초기화, 소멸화 메소드를 사용할 것인지 선언해줘야합니다.


FREObject alert( FREContext context, void* data, uint32_t argc, FREObject param[] ) 


이 메소드는 Flash와 약속된 메소드입니다. 


Flash와 약속된 메소드는 반드시 위와 같은 메소드로 이뤄져야합니다.


이 메소드 안에서 우리가 구현하고 싶은 코드를 구현하면 됩니다.


이렇게 5가지 메소드가 Native Extension의 기본 골격입니다.


이제 하나하나 메소드를 구현해보겠습니다.




먼저 Native Extension이 앱에서 실행될 때 맨 처음 실행되는 초기화 생성자인 AlertExtensionInitializer를 작성해보겠습니다.


void AlertExtensionInitializer( void** data, FREContextInitializer* initializer, FREContextFinalizer* finalizer )
{
    *data = NULL;
    *initializer = &ContextInitializer;
    *finalizer = &ContextFinalizer;
}


이 Native Extension에게 초기화 메소드와 소멸자 메소드를 알려주는 부분입니다.


다음으로 Native Extension의 자체 초기화 메소드인 ContextInitializer를 구현해보겠습니다.


void ContextInitializer( void* data, const uint8_t* type, FREContext context, uint32_t *functionNumber, const FRENamedFunction** functions )
{
    *functionNumber = 1;
    
    FRENamedFunction* function = (FRENamedFunction*) malloc( sizeof(functionNumber) );
    function[ 0 ].name = (const uint8_t *) "alert";
    function[ 0 ].functionData = NULL;
    function[ 0 ].function = &alert;
    
    *functions = function;
}

저도 외워서 쓰는거라 잘 몰라요.


근데 가만 보면 어디어디를 고쳐야될지 보이죠?


function[ 0 ].name 에 Flash쪽에서 호출할 메소드명을 적어주고


function[ 0 ].function 에 실제 호출될 메소드의 레퍼런스를 넘겨줍니다.


그리고 ContextFinalizer나 AlertExtensionFinalizer 두 소멸자는 지금은 별 의미 없어서 공백으로 비워둡니다 ㅋ




이 단계에서 Command + B 를 눌러서


빌드가 잘 되는지 확인해야합니다.


빌드가 잘 됐다면 이제 실제로 팝업 부분을 구현해볼 차례입니다. 


alert 메소드죠.




4. Native 구현


팝업을 구현하기 위해서는 UIKit 프레임웍이 필요합니다.


AlertExtension.m 파일의 상단에 


UIKit을 임포트합니다.


#import "FlashRuntimeExtensions.h"
#import "AlertExtension.h"
#import <UIKit/UIKit.h>


이렇게 하면 알럿 팝업을 띄울 수 있게 됩니다.


이제 alert 메소드를 구현합니다.


FREObject alert( FREContext context, void* data, uint32_t argc, FREObject param[] )
{
    NSLog( @"ALERT~~~" );
    
    NSString* title = nil;
    NSString* message = nil;
    
    uint32_t titleLen;
    const uint8_t* titleString;
    
    if( FRE_OK == FREGetObjectAsUTF8( param[ 0 ], &titleLen, &titleString ) )
        title = [NSString stringWithUTF8String:(char*) titleString];
    
    uint32_t messageLen;
    const uint8_t* messageString;
    
    if( FRE_OK == FREGetObjectAsUTF8( param[ 1 ], &messageLen, &messageString ) )
        message = [NSString stringWithUTF8String:(char*) messageString];
    
    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:title message:message
                                                   delegate:[UIApplication sharedApplication] cancelButtonTitle:@"OK" otherButtonTitles:nil ];
    
    [alert show];
    
    return NULL;
}


파라미터를 가져오는 방법을 잘 익혀두시기 바랍니다.


    uint32_t titleLen;
    const uint8_t* titleString;
    NSString* title = nil;
    
    if( FRE_OK == FREGetObjectAsUTF8( param[ 0 ], &titleLen, &titleString ) )
        title = [NSString stringWithUTF8String:(char*) titleString];


이제 다 됐습니다.


기왕이면 테스트하는 것까지 하려고 했는데


그럴려면 또 일이 너무 커져버려서 코드가 그리 복잡하지 않기 때문에 그냥 넘어가겠습니다.




5. Binary 파일


여기까지 다 됐으면


왼쪽에 Products 폴더를 열어보면


libAlertExtension.a 라는 파일이 생성되어 있는 것을 볼 수 있습니다.



이 파일이 ane를 만들때 필요한 파일입니다.


이 파일을 선택하면 Xcode오른쪽에 이 파일에 대한 위치와 파인더에서 볼 수 있는 버튼이 나옵니다.



ane 파일을 만들기 위한 바이너리 파일이므로 잘 봐둬야합니다.


이제 다음 강좌에서는 ane의 나머지 한 부분인 Flash 라이브러리를 만들어 보겠습니다.




소스 코드 다운로드 : 


AlertExtension.zip




저작자 표시 비영리 동일 조건 변경 허락
신고
  1. PJH 2015.12.11 18:30 신고

    ContextInitializer 에서 malloc 하는 부분 FRENamedFunction에 함수 갯수를 곱해서 해주셔야해요. 함수 2개 이상되면 오작동하더라고요 ㅠㅠ

+ Recent posts

티스토리 툴바