Java 코드를 DEX(Dalvik EXecutable)로 변환하고 이것을 안드로이드 디바이스에서 실행하는 방법에 대해서 알아봅니다.
정확하게 말하면, 다음 순서로 파일을 변환해야 디바이스에서 실행할 수 있습니다.
- Java 코드를 class 파일로 컴파일
- class 파일을 JAR 파일로 변환
- dx 툴을 이용하여 JAR 파일을 Dex로 변환
- classes.dex를 ZIP으로 압축
- ZIP 파일을 디바이스에서 실행
JVM vs DVM(or ART)
Java를 Dex로 변환하기 전에, JVM과 DVM의 차이에 대해서 알아보겠습니다.
JVM(Java Virtual Machine)은 .class
파일을 읽고 실행할 수 있습니다.
Java 코드를 컴파일하면 bytecode로 변환되며, .class
파일에 저장이 됩니다.
즉, .class
파일은 bytecode들로 이루어져 있습니다. bytecode는 JVM(Java Virtual Machine)이 실행할 수 있는 명령어들입니다.
반면에 안드로이드는 JVM이 없고 DVM(Dalvik Virtual Machine)이 있습니다.
DVM은 .class
파일을 읽지 못하고 .dex
파일을 읽고 실행할 수 있습니다.
안드로이드 스튜디오로 Java 코드를 컴파일하면 Dalvik bytecode로 변환되며 .dex
파일에 저장이 됩니다.
즉, .dex
는 Dalvik bytecode로 이루어져 있습니다. Dalvik bytecode는 DVM이 실행할 수 있는 명령어들입니다.
Java 코드를 class 파일로 컴파일
다음과 같이 간단한 자바 프로그램을 작성합니다. 파일 이름은 HelloWorld.java
로 만드시면 됩니다.
public class HelloWorld {
public static void main(String[] args){
System.out.println("This is my first program in java");
}
}
먼저 다음과 같이 PC에서 javac로 컴파일할 수 있습니다. HelloWorld.class
파일이 생성되는 것을 볼 수 있습니다.
$ javac HelloWorld.java
$ ls
HelloWorld.class HelloWorld.java
그리고 다음과 같이 실행할 수 있습니다.
$ java HelloWorld
This is my first program in java
class 파일을 JAR 파일로 변환
Android SDK에서 제공하는 dx라는 툴을 이용하면 JAR(Java ARchive) 파일을 dex파일로 변환할 수 있습니다.
그래서 먼저 .class
로 컴파일된 파일들을 .jar
형태로 변환해야 합니다.
다음과 같이 jar cvf [output file name] [class file name]
명령어를 사용하면 .class
파일을 .jar
파일로 변환할 수 있습니다.
*.class
는 현재 디렉토리에 있는 모든 .class
파일을 선택하기 위한 명령어입니다.
$ jar cvf HelloWorld.jar *.class
added manifest
adding: HelloWorld.class(in = 446) (out= 307)(deflated 31%)
$ ls
HelloWorld.class HelloWorld.jar HelloWorld.java
HelloWorld.jar
파일이 생성된 것을 확인할 수 있습니다.
dx 툴을 이용하여 JAR 파일을 Dex로 변환
이제 dx 툴을 이용하여 .jar
파일을 .dex
로 변환해야 합니다.
dx는 Android SDK의 build-tools 아래에 있습니다. 저는 SDK 경로를 PATH에 추가했기 때문에 리눅스에서 which 명령어로 확인해보면 다음과 같은 디렉토리에 존재하는 것을 확인할 수 있습니다.
$ which dx
~/Android/Sdk/build-tools/29.0.0-rc3/dx
다음과 같은 명령어를 입력하면 .jar
파일이 classes.dex
파일로 변환이 됩니다. .dex
파일의 이름은 classes.dex
로 설정하시는 것이 좋습니다.
$ dx --dex --output=classes.dex HelloWorld.jar
$ ls
classes.dex HelloWorld.class HelloWorld.jar HelloWorld.java
classes.dex를 ZIP으로 압축
안드로이드에서 classes.dex
를 실행하려면 ZIP으로 압축해줘야 합니다.
다음과 같은 명령어를 사용하면 classes.dex
를 ZIP으로 압축하여 HelloWorld.zip
파일로 만들어 줍니다.
$ zip HelloWorld.zip classes.dex
adding: classes.dex (deflated 43%)
$ ls
HelloWorld.class HelloWorld.jar HelloWorld.java HelloWorld.zip
ZIP 파일에서 classes.dex
는 가장 최상위 디렉토리에 위치하면 됩니다.
다음과 같이 압축을 풀어서 상위에 위치하는지 확인할 수 있습니다.
$ unzip HelloWorld.zip -d out
$ tree out/
out/
└── classes.dex
ZIP 파일을 디바이스에서 실행
위에서 만든 HelloWorld.zip
을 실행하려면 먼저 디바이스에 저장해야 합니다.
다음과 같이 adb 명령어로 /sdcard
에 복사합니다.
$ adb push HelloWorld.zip /sdcard
그리고 다음과 같이 shell에서 dalvikvm
을 이용하여 프로그램을 실행시킬 수 있습니다.
아래 명령어는 HelloWorld.zip
에 있는 classes.dex
에서 HelloWorld
라는 클래스를 찾아서 실행시키라는 의미입니다.
$ adb shell dalvikvm -cp /sdcard/HelloWorld.zip HelloWorld
This is my first program in java
이 글에서는 dex파일을 HelloWorld.zip 라는 이름으로 압축했습니다. 사실 확장자는 중요하지 않습니다.
.apk
로 변경해도 됩니다.
또는 shell에서 app_process
를 이용하여 프로그램을 실행시킬 수도 있습니다.
먼저 export로 클래스 패스를 설정하고 app_process
으로 HelloWorld
클래스를 실행시킬 수 있습니다.
$ adb shell
generic_x86_arm:/ $ export CLASSPATH=/sdcard/HelloWorld.zip
generic_x86_arm:/ $ app_process / HelloWorld
This is my first program in java
정리
순수한 Java 코드를 .dex
로 변환하여 Android에서 DVM으로 실행하는 방법을 알아보았습니다.
이런 작업은 Android Studio가 알아서 해주기 때문에 알 필요는 없습니다.
하지만 Android에서 Java 코드가 어떻게 컴파일되서 실행되는지 원리를 이해하는데 도움이 될 수 있습니다.
참고
Related Posts
- Android 14 - 사진/동영상 파일, 일부 접근 권한 소개
- Android - adb push, pull로 파일 복사, 다운로드
- Android 14 - 암시적 인텐트 변경사항 및 문제 해결
- Jetpack Compose - Row와 Column
- Android 13, AOSP 오픈소스 다운로드 및 빌드
- Android 13 - 세분화된 미디어 파일 권한
- Android 13에서 Notification 권한 요청, 알림 띄우기
- Android 13에서 'Access blocked: ComponentInfo' 에러 해결
- 에러 해결: android gradle plugin requires java 11 to run. you are currently using java 1.8.
- 안드로이드 - 코루틴과 Retrofit으로 비동기 통신 예제
- 안드로이드 - 코루틴으로 URL 이미지 불러오기
- Android - 진동, Vibrator, VibrationEffect 예제
- Some problems were found with the configuration of task 에러 수정
- Query method parameters should either be a type that can be converted into a database column or a List
- 우분투에서 Android 12 오픈소스 다운로드 및 빌드
- Android - ViewModel을 생성하는 방법
- Android - Transformations.map(), switchMap() 차이점
- Android - Transformations.distinctUntilChanged() 소개
- Android - TabLayout 구현 방법 (+ ViewPager2)
- Android - 휴대폰 전화번호 가져오는 방법
- Android 12 - Splash Screens 알아보기
- Android 12 - Incremental Install (Play as you Download) 소개
- Android - adb 명령어로 bugreport 로그 파일 추출
- Android - adb 명령어로 App 데이터 삭제
- Android - adb 명령어로 앱 비활성화, 활성화
- Android - adb 명령어로 특정 패키지의 PID 찾기
- Android - adb 명령어로 퍼미션 Grant 또는 Revoke
- Android - adb 명령어로 apk 설치, 삭제
- Android - adb 명령어로 특정 패키지의 프로세스 종료
- Android - adb 명령어로 screen capture 저장
- Android - adb 명령어로 System 앱 삭제, 설치
- Android - adb 명령어로 settings value 확인, 변경
- Android 12 - IntentFilter의 exported 명시적 선언
- Android - adb 명령어로 공장초기화(Factory reset)
- Android - adb logcat 명령어로 로그 출력