연재순서
작업환경
Android용 네이티브 라이브러리를 만들기 위해서는 ADT 즉 Android Development Toolkit이 필요합니다. 최신 이클립스를 설치하시고 플러그인으로 ADT를 설치하시면 됩니다. 자세한 설치방법은 다음의 링크를 참고하세요. ADT 설치하기, 안드로이드 SDK 설치하기, AVD 추가하기
- Mac OS 10.7.4
- Flex SDK 4.6.0 for AIR3.3
- Eclipse 4.2.0
- Android Development Toolkit 20.0.0
소스 다운로드
[button url=’https://github.com/sewonist/ScreenWakeUp’ target=’_blank’ size=’large’]Sources in GitHub[/button]시작점 만들기
이클립스에 정상적으로 안드로이드 SDK 설치 되었다면 위의 이미지와 같이 신규 프로젝트에 Android 가 추가된 것을 확인 할 수 있습니다. Android Application Project를 선택합니다. 어플리케이션 이름을 지정해 줍니다. Build SDK는 설치된 SDK 이고 Minimum Required SDK는 최소 필요 SDK입니다. 이 최소SDK 에 따라 사용 할 수 있는 기능에 차이가 있을 수 있습니다. Create Activity 는 일반 안드로이드앱을 만들 때를 위한 기본 템플릿 입니다. ANE를 위한 라이브러리에서는 필요 없는 기능이므로 체크를 해제 하고 프로젝트 생성을 완료 합니다. 플래시와 네이티브 라이브러리를 연결하기 위해 사용 할 각종 함수와 정의가 있는 FlashRuntimeExtenshion.jar 파일을 복사합니다. 이 파일은 일반적으로 {Flash Builder 설치 경로}/sdks/{SDK 버전}/lib/android 폴더 안에 위치 합니다. FlashRuntimeExtenshion.jar 을 좀전에 만든 프로젝트 폴더의 libs폴더에 복사 합니다. Android 의 경우에는 libs 폴더안의 jar 파일은 자동으로 참조하니 따로 프로젝트에 등록 할 필요는 없습니다.코드작성
Android 용 네이티브 라이브러리는 작성은 iOS용과 약간의 차이가 있습니다. iOS용이 C 의 구조체를 이용한 방식이라면 Android는 Java의 클래스를 이용하고 있습니다. 이는 단순히 언어의 문법적 차이일뿐 실제 작동 방식은 거의 유사합니다.
package it.ane.screenwakeup; import android.util.Log; import com.adobe.fre.FREContext; import com.adobe.fre.FREExtension; public class ScreenWakeUpExtension implements FREExtension { @Override public FREContext createContext(String arg0) { Log.e("ScreenWakeUp", "call createContext"); return new ScreenWakeUpContext(); } @Override public void dispose() { } @Override public void initialize() { } }
ScreenWakeUpExtension 클래스는 FREExtension 인터페이스를 정의하고 있습니다. 저는 처음 Android용 ANE를 라이브러리를 만들 때 당연히 전부 클래스를 상속하려니 extends 를 했던 아픈 기억이 있습니다. 클래스 확장인 아닌 인터페이스 정의에 주의 하시기 바랍니다.
이 ScreenWakeUpExtension 은 extension.xml 에 정의 되어 있습니다. 그래서 AIR런타임 실행시 extension.xml을 참조하여 ScreenWakeUpExtension 의 createContext을 실행하여 context를 반환 받습니다. 인자 arg0은 ExtensionContext.createExtensionContext([extensionId], [contextTyoe]); 실행시 전달되는 contextType 입니다.
package it.ane.screenwakeup; import java.util.HashMap; import java.util.Map; import com.adobe.fre.FREContext; import com.adobe.fre.FREFunction; public class ScreenWakeUpContext extends FREContext { @Override public void dispose() { // TODO Auto-generated method stub } @Override public Map<String, FREFunction> getFunctions() { Map<String, FREFunction> map = new HashMap<String, FREFunction>(); map.put("isSupported", new IsSupportedFunction()); map.put("lock", new LockFunction()); return map; } }
FREContext 를 확장하는 ScreenWakeUpContext 를 만듭니다. getFunctions() 함수를 통해 함수목록이 있는 map을 반환 합니다. map에 AIR에서 함수 호출시 사용할 이름과 함수의 인스턴스를 넣어 줍니다. C의 경우 함수에 대한 포인터 참조이나 Java의 경우 객체라는 점이 다릅니다. Java문법과 유사한 ActionScript에 익숙한 플래시 개발자들에게 좀더 익숙한 문법이 아닌 가 싶습니다.
package it.ane.screenwakeup; import android.app.Activity; import android.content.Context; import android.os.PowerManager; import android.util.Log; import com.adobe.fre.FREContext; import com.adobe.fre.FREFunction; import com.adobe.fre.FREInvalidObjectException; import com.adobe.fre.FREObject; import com.adobe.fre.FRETypeMismatchException; import com.adobe.fre.FREWrongThreadException; public class LockFunction implements FREFunction { protected PowerManager.WakeLock mWakeLock; private Boolean isLock; @Override public FREObject call(FREContext ctx, FREObject[] args) { if(mWakeLock==null){ Activity activity = ctx.getActivity(); final PowerManager pm = (PowerManager) activity.getSystemService(Context.POWER_SERVICE); this.mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "ScreenWakeUp"); isLock = false; } try { Boolean flag = args[0].getAsBool(); if(flag==true && isLock==false){ this.mWakeLock.acquire(); } else if (flag==false && isLock == true) { this.mWakeLock.release(); } isLock = flag; } catch (IllegalStateException e) { e.printStackTrace(); } catch (FRETypeMismatchException e) { e.printStackTrace(); } catch (FREInvalidObjectException e) { e.printStackTrace(); } catch (FREWrongThreadException e) { e.printStackTrace(); } return null; } }
실제 기능을 할 함수클래스를 작성합니다. LockFunction은 FREFunction 인터페이스를 정의하고 있는 것에 주의 하시기 바랍니다. 함수 인자를 살펴보면 ctx 는 context, args는 플래시에서 함수 호출신 전달되는 인자입니다. Android도 iOS와 마찬가지로 인자를 바로 사용하는 것이 아니라 getAsBool() 등의 함수를 통해 네이티브 변수로 변환 해야 합니다. 사용 할 수 있는 인자 타입은 아래와 같습니다.
- getAsInt()
- getAsDouble()
- getAsBool()
- getAsString()
위의 리스트는 FREObject의 경우이며 추가적으로 FREObject의 자식인 FREArray, FREBitmapData, FREByteArray 클래스도 사용할 수 있습니다.
Activity activity = ctx.getActivity(); final PowerManager pm = (PowerManager) activity.getSystemService(Context.POWER_SERVICE); this.mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "ScreenWakeUp"); ... this.mWakeLock.acquire(); ... this.mWakeLock.release();
실제로 화면잠금 구현부입니다. 여기서 재미난게 있습니다. PowerManager를 사용하기 위해서는 Activity 가 있어햐 하는데 우리는 이 Activity를 만든 적이 없습니다. 하지만 이미 AIR에 의해서 기본적으로 Activity가 만들어져 있기 때문에 ctx.getActivity(); 를 통해 바로 사용 할 수 있습니다.
참고로 Android 에서 이 기능을 사용하기 위해서는 아래의 퍼미션이 필요하므로 제작한 AIR앱의 -App.xml 에 아래의 퍼미션을 추가해야 합니다.
<uses-permission android:name="android.permission.WAKE_LOCK" />
빌드
Package Explorer 에서 프로젝트의 src 폴더를 우클릭해서 Export 합니다. 물론 다른 방법으로도 Export 할 수 있지만 이렇게 하는게 가장 깔끔하게 Export 됩니다. Export 는 Java 의 JAR file 을 선택 합니다. Export generated class files and resources 가 체크 활성화 되어 있는지 확인합니다. JAR 파일이 저장될 곳을 선택하고 완료합니다.정리
Android 용 네이티브 라이브러리 만드는 법을 살펴 보았습니다. iOS와는 문법적으로 조금 다르나 기본적으로 context를 생성하고 함수 목록을 반환하야 사용하는 구조는 유사하다는 걸 알 수 있었습니다. 즉, extension.xml 에 의해 ScreenWakeUpExtension 이 실행되고 이어 각 기능 함수가 포함되어 있는 ScreenWakeUpContext가 반환되는 것 입니다. 함수들은 FREFunction 인터페이스만 정의 하고 있으면 내부적으로는 어떻게 작성되어도 무방합니다. 또한 예제에서는 편의를 위해 모든 파일을 따로 만들었지만 한파일에 모두 정의 되어 작성되어도 잘 작동하니 참고 하시기 바랍니다.
이제 다음 시간에는 앞서 만든 각 네이티브 라이브러리를 실제 플래시와 연결해 줄 연결 SWC 를 만들어 보도록 하겠습니다.
잘 봤습니다 ^^
잘 봤습니다^^ 정말 고맙습니다.