본문 바로가기

파이어몽키

파이어몽키에서 안드로이드 외부 라이브러리(jar 파일) 이용(Import jar)

 안녕하세요. 험프리 김현수 입니다. 그간 많은 분들이 질문주셨던 내용인데요. 이제야 정리되어 소개해 드립니다.


 안드로이드에서 외부라이브러리 사용하려면 so, jar 파일을이용하는 2가지 방법이 있습니다. 이번에 소개할 내용은 jar 파일을 이용해 외부 라이브러리를 활용하는 내용입니다.

 간단하게 소개를 먼저하면, 필요한 jar 파일을 포함한 classes.dex 파일을 생성 후 배포 시 앞에서 생성한 classes.dex 파일을 배포하여 소스상에서 jar파일에 포함된 자바클래스를 활용하는 방식입니다.


아래의 순서대로 진행되어야 하며 순서에 맞춰 설명하겠습니다.


  1. 사용자 classes.dex 파일 생성
    • APK 구조와 jar 파일의 위치
    • java 소스파일 또는 jar 파일 준비
    • 빌드
      • (옵션) java 소스파일 컴파일
      • jar 파일 생성
      • jar 파일을 dex 파일로 변환
      • dex 파일 병합
  2. 배포파일 관리
  3. Java Interface 파일 생성
  4. 구현 및 확인

프로젝트 구성

  • JarBridge
    • [Java]
      • [output] - 빌드 시 자동생성
        • [dex] classes.dex - 빌드 후 생성
      • [src] kr\co\devgear\test\Foo.java
      • build.bat
    • JarBridgeDemo.dpr 등 - 프로젝트 및 폼 파일
    • JavaFoo.pas -Java Interface 정의 유닛

사용자 classes.dex 파일 생성

▶ APK 구조와 jar파일의 위치

apk 파일을 압축유틸리티로 열면 위와 같은 구조로 되어 있습니다. 그 중 jar 파일을 포함할 파일은 classes.dex 파일입니다. 여러분의 jar 파일은 아래의 빌드단계를 거처 classes.dex 파일로 변환됩니다.


dex 파일이란?

▶ Java 소스파일(또는 jar 파일) 준비

 저는 인터페이스 테스트를 위해 아래의 자바코드를 간단하게 작성했습니다. (워낙 간단하니 따로 설명드리지 않겠습니다.)

 해당 자바코드는 아래의 빌드 단계에서 jar파일을 생성합니다. 만약, 다른 jar 파일을 이용할 경우 아래의 코드는 작성하지 않아도 됩니다.

package kr.co.devgear.test;

import android.app.Activity;
import android.widget.Toast;

public class Foo
{
    public void printMsg(final Activity activity)
    {
         activity.runOnUiThread(new Runnable()
         {
               @Override
                public void run()
                {
                    Toast.makeText(activity.getApplicationContext(), "Hello world from a Java .jar library", Toast.LENGTH_SHORT).show();
                }
         });
    }

    public int getInteger(){
        return 99;
    }

    public String getString(){
        return "Foo string";
    }
}


▶ 빌드

 준비된 자바 소스파일을 jar로 만들어 새로운 classes.dex에 포함하는 작업을 위해 아래의 배치파일을 사용합니다. (빌드파일은 Brian long(http://blog.blong.com)이 공개한 빌드파일을 참고해서 수정 되었습니다. 많은 도움이 되었습니다.)


빌드파일은 아래의 내용을 진행합니다.

  1. Compiling the Java source file - 자바소스를 컴파일
  2. Creating jar containing the new classes - jar 파일을 만들고
  3. Converting from jar to dex - jar 파일을 dex 파일로 변환 후
  4. Merging dex files - 3에서 생성된 dex 파일을 Embarcadero의 dex파일과 병합
만약, 보유한 jar파일을 이용하는 경우 3, 4 단계만 진행하도록 배치파일을 수정 후 사용바랍니다.

@echo off

setlocal

if x%ANDROID% == x set ANDROID="C:\Users\Public\Documents\RAD Studio\12.0\PlatformSDKs\adt-bundle-windows-x86-20130522\sdk"

set SRC_PATH=src\kr\co\devgear\test\Foo.java
set LAST_DOMAIN=kr
set ANDROID_PLATFORM=%ANDROID%\platforms\android-17
set DX_PATH=%ANDROID%\build-tools\android-4.2.2
set DX_LIB=%DX_PATH%\lib
set EMBO_DEX="C:\Program Files (x86)\Embarcadero\RAD Studio\12.0\lib\android\debug\classes.dex"
set PROJ_DIR=%CD%
set VERBOSE=0

echo.
echo Compiling the Java source file
echo.
mkdir output\classes 2> nul
if x%VERBOSE% == x1 SET VERBOSE_FLAG=-verbose
javac %VERBOSE_FLAG% -Xlint:all -classpath %ANDROID_PLATFORM%\android.jar -d output\classes -source 1.6 -target 1.6 %SRC_PATH%


echo.
echo Creating jar containing the new classes
echo.
mkdir output\jar 2> nul
if x%VERBOSE% == x1 SET VERBOSE_FLAG=v
jar c%VERBOSE_FLAG%f output\jar\test_classes.jar -C output\classes %LAST_DOMAIN%


echo.
echo Converting from jar to dex...
echo.
mkdir output\dex 2> nul
if x%VERBOSE% == x1 SET VERBOSE_FLAG=--verbose
call %DX_PATH%\dx --dex %VERBOSE_FLAG% --output=%PROJ_DIR%\output\dex\test_classes.dex --positions=lines %PROJ_DIR%\output\jar\test_classes.jar

echo.
echo Merging dex files
echo.
java -cp %DX_LIB%\dx.jar com.android.dx.merge.DexMerger  %PROJ_DIR%\output\dex\classes.dex %PROJ_DIR%\output\dex\test_classes.dex %EMBO_DEX%

echo Tidying up
echo.
del output\dex\test_classes.dex
del output\jar\test_classes.jar
rmdir output\jar

echo.
echo Now we have the end result, which is output\dex\classes.dex

:Exit

pause

endlocal

배치파일의 경로는 RAD Studio XE5를 기준으로 설정되어 있어, 기본 경로로 설치하셨을 경우 아래의 2가지 변수외에는 그대로 사용하실 수 있습니다.

  • SRC_PATH : java 소스파일의 상대경로로 수정
  • LAST_DOMAIN : 도멘인의 마지막을 입력(e.g. kr, com, net 등)


위의 배치파일을 실행하면 output\dex\classes.dex 파일이 생성됩니다. 아래의 배포파일 관리에서 해당 파일이 사용됩니다.

배포파일 관리

안드로이드 모바일 프로젝트를 생성하면 배포파일 목록에 엠바카데로에서 제공하는 classes.dex이 등록되는데, 우리는 jar파일이 포함된 classes.dex를 배포해야 합니다.



위의 그림과 같이 기본 지정된 classes.dex파일을 선택해제 하시고, Add files 버튼을 이용해 위에서 만든 classes.dex 파일을 추가하고 아래와 같이 속성을 변경합니다.

classes.dex

  • Platform : Android
  • Remote Path : classes\

Java Interface 파일생성

위의 자바파일(Foo.java)을 참고해 아래의 JavaFoo 유닛을 만들었습니다.

자바파일 구조

  • package kr.co.devgear.test;
  • public class Foo
    • public void printMsg(final Activity activity)
    • public int getInteger()
    • public String getString()


unit JavaFoo;

interface

uses
  Androidapi.JNIBridge,
  Androidapi.JNI.JavaTypes,
  Androidapi.JNI.APP;

type
  JFoo = interface;

  JFooClass = interface(JObjectClass)
   ['{94F03A5A-B62B-401E-BE8D-2A96B77FA542}']
   function init: JFoo;
  end;

  [JavaSignature('kr/co/devgear/test/Foo')]
  JFoo = interface(JObject)
    ['{66CA87AA-1A6B-4039-A4E0-EB771BC2F4A5}']
    procedure printMsg(const AActivyty: JActivity);
    function getInteger: Integer; cdecl;
    function getString: JString; cdecl;
  end;

  TJFoo = class(TJavaGenericImport<JFooClass, JFoo>) end;

implementation

end.

위의 과정이 어렵다면 Android2DelphiImport tool(유료: 0.25 bitcoin)을 이용할 수 있습니다.

위의 링크의 설명은 어떤 jar파일도 pas파일로 변환해준다는 내용이 있습니다.
(비트코인으로 결재를 하네요^^)


파이어몽키 - 안드로이드 SDK 전체 랩핑(Wrapping) 파일

  • http://blog.hjf.pe.kr/185

구현 및 확인

아래와 같이 JavaFoo 파일을 uses에 넣고 버튼을 누르면 JFoo 생성 후 자바 메소드를 호출하면 응답을 받을 수 있습니다.

uses
  JavaFoo,
  Androidapi.JNI.JavaTypes,
  FMX.Helpers.Android;

{$R *.fmx}

procedure TForm1.Button2Click(Sender: TObject);
var
  Foo: JFoo;
begin
  Foo := TJFoo.JavaClass.init;

  Edit1.Text := IntToStr(Foo.getInteger);
  Edit2.Text := JStringToString(Foo.getString);

  Foo.printMsg(SharedActivity);
end;

아래는 넥서스 7에서 실행한 화면입니다.


참고



관련 글