펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

요점은 ACTION_DOWN 이벤트 발생 시, 해당 좌표값 저장, 이후 MOVE 발생 시

다른 변수에 해당 값 저장. 둘의 값 비교 == 이동량

이미지를 기존 이미지 위치 - 이동량 하여 새로그려줌

그리고 처음 DOWN때 위치를 저장한 변수에 두번째 값을 넘겨주고

다시 MOVE 이벤트 발생시 값 갱신 하는식으로

MOVE시마다 이전값과 이후값의 차가 이동한 거리이므로 계속 새려그려주면 손가락을 따라 움직이는것처럼 표현된다.


float saveX, saveY;

float moveX, moveY;

float diffX, diffY;

@Override

public boolean onTouchEvent(MotionEvent event) {

if (event.getAction() == MotionEvent.ACTION_DOWN) {

saveX = event.getX();

saveY = event.getY();

}

if (event.getAction() == MotionEvent.ACTION_MOVE) {

moveX = event.getX();

moveY = event.getY();

diffX = saveX - moveX;

diffY = saveY - moveY;

// SurfaceViewView에 따라 그리는 방식은 달라짐. SurfaceView같은경우

canvas.canvas = mHolder.lockCanvas();

canvas.drawBitmap(img, 기존이미지X - diffX, 기존이미지Y - diffY, p);

holder.unlockCanvasAndPost(canvas);

//뷰같은경우 locakCanvas(); 대신 invalidate();로 재호출.

saveX = moveX;

saveY = moveY;

}

}


그리기 부분은 따로 설명하지 않았다. 새로운 포스트로 소개할듯 싶지만,

그 전에 궁금한부분이 있으면 댓글주기바람



펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

기본적인 셋팅은 이전에 방위센서에서 다뤘으므로 주석없이 술술 나가겠음


float[] gravity_data = new float[3];

float[] accel_data = new float[3];

float[] m_acc_data = new float[3];

 final float alpha = (float)0.8;


SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);

Sensor mSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);


protected void onResume(){

super.onResume();

sm.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_UI);

}


public void onDestroy(){

super.onDestroy();

sm.unregisterListener(this);

}


@Override

public void onSensorChanged(SensorEvent event) {

if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

gravity_data[0] = alpha * gravity_data[0] + (1 - alpha) * event.values[0]; //먼저 중력데이터를 계산함

gravity_data[1] = alpha * gravity_data[1] + (1 - alpha) * event.values[1];

gravity_data[2] = alpha * gravity_data[2] + (1 - alpha) * event.values[2];

accel_data[0] = event.values[0] - gravity_data[0]; // 순수 가속도센서값에 중력값을 빼줌

accel_data[1] = event.values[1] - gravity_data[1]; // 아니면 약 9.81 어쩌고 하는값이 더해짐

accel_data[2] = event.values[2] - gravity_data[2];

tv1.setText("x축 : " + accel_data[0]);

tv2.setText("y축 : " + accel_data[1]);

tv3.setText("z축 : " + accel_data[2]);

}

}


빼먹은게 있을수도 있지만, 알맹이는 다 들어있습니다. 문의는 댓글로

'Android > 센서' 카테고리의 다른 글

기본적인 센서(Sensor) 사용법  (1) 2014.01.07
TYPE_MAGNETIC_FIELD 센서로 방위각 구하기  (2) 2013.11.28
Android/센서 | Posted by 덩치 2013. 11. 28. 16:33

TYPE_MAGNETIC_FIELD 센서로 방위각 구하기

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

가장 기본적이면서 중요한 메커니즘은 SensorEventListener 참조, onResume에서 딜레이 설정이다.


//먼저 액티비티에 SensorEventListener을 implements 해 준다.

public class MainActivity extends Activity implements SensorEventListener{

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);


float[] rotation = new float[9];  

float[] result_data = new float[3];

float[] mag_data = new float[3]; //센서데이터를 저장할 배열 생성 

float[] acc_data new float[3]; //가속도데이터값이 들어갈 배열. 각도를 뽑으려면 가속도와 지자계의 값이 있어야함.

크기가 3인 이유는 센서값 values의 index가 3이기때문(x.y.z)


SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE); //센서매니저 생성

mag_sensor = sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); //마그네틱 필드 센서 생성

}

//센서 읽어들이는 간격 설정(NORMAL < UI < GAME 순 속도)

protected void onResume(){

super.onResume();

sm.registerListener(this, mag_sensor, SensorManager.SENSOR_DELAY_UI);

}



@Override

public void onSensorChanged(SensorEvent event) {  //센서값 변경을 읽는 리스너

if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)   //센서가 읽어들인 값이 마그네틱필드일때

mag_data = event.values.clone();    //데이터를 모두 mag_data 배열에 저장

if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) // 가속도센서값일때

acc_data = event.values.clone();  //마찬가지

if (mag_data != null && acc_data != null) { //널체크    

       SensorManager.getRotationMatrix(rotation, null, acc_data, mag_data); //회전메트릭스 연산

             SensorManager.getOrientation(rotation, result_data); //연산값으로 방향값 산출

result_data[0] = (float)Math.toDegrees(result_data[0]); // 방향값을 각도로 변환

if(result_data[0] < 0) m_result_data[0] += 360; //0보다 작을경우 360을더해줌

}

}



//종료시에는 반드시 센서의 리스너를 해제해줘야함

public void onDestroy(){

super.onDestroy();

sm.unregisterListener(this);

}


}


빠진부분이나 의문사항 댓글로 남겨주면 답변드립니다.


Android/History | Posted by 덩치 2013. 10. 28. 13:25

안드로이드는 ?

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

안드로이드(Android)는휴대 전화를 비롯한 휴대용 장치를 위한 운영 체제와 미들웨어, 사용자 인터페이스 그리고 표준 응용 프로그램(웹 브라우저, 이메일 클라이언트, 단문 메시지 서비스(SMS), 멀티미디어 메시지 서비스(MMS)등)을 포함하고 있는 소프트웨어 스택이자 모바일 운영 체제이다. 안드로이드는 개발자들이 자바 언어로 응용 프로그램을 작성할 수 있게 하였으며, 컴파일된 바이트코드를 구동할 수 있는 런타임 라이브러리를 제공한다. 또한 안드로이드 소프트웨어 개발 키트(SDK)를 통해 응용 프로그램을 개발하기 위해 필요한 각종 도구들과 API를 제공한다.


안드로이드는 리눅스 커널 위에서 동작하며, 다양한 안드로이드 시스템 구성 요소에서 사용되는 C/C++ 라이브러리들을 포함하고 있다. 안드로이드는 기존의 자바 가상 머신과는 다른 가상 머신인 달빅 가상 머신을 통해 자바로 작성된 응용 프로그램을 별도의 프로세스에서 실행하는 구조로 되어 있다.


2005년에 안드로이드 사를 구글에서 인수한 후 2007년 11월에 안드로이드 플랫폼을 휴대용 장치 운영 체제로서 무료 공개한다고 발표한 후 48개의 하드웨어, 소프트웨어, 통신 회사가 모여 만든 오픈 핸드셋 얼라이언스(Open Handset Aliance, OHA)에서 공개 표준을 위해 개발하고 있다. 구글은 안드로이드의 모든 소스 코드를 오픈 소스 라이선스인 아파치 v2 라이선스로 배포하고 있어 기업이나 사용자는 각자 안드로이드 프로그램을 독자적으로 개발을 해서 탑재할 수 있다. 또한 응용 프로그램을 사고 팔 수 있는 구글 플레이를 제공하고 있으며, 이와 동시에 각 제조사 혹은 통신사별 응용 프로그램 마켓이 함께 운영되고 있다. 마켓에서는 유료 및 무료 응용 프로그램이 제공되고 있다.


안드로이드의 역사 

- 2005년 7월 구글이 미국 캘리포니아 주의 팔로알토에 위치한 작은 '안드로이드'사를 인수


- 2007년 11월 5일 텍사스 인스트루먼트, 브로드컴 코퍼레이션, 구글, HTC, 인텔, LG전자, 마벨 테크놀로지 그룹, 모토로라, 엔비디아, 퀄컴, 삼성전자, 스프린트 넥스텔, T-모바일의 몇몇 회사로 구성된 컨소시엄인 오픈 핸드셋 얼라이언스(OHA)가 모바일 기기의 공개 표준을 개발하는 것을 목표로 결성되었다. 또한 OHA는 리눅스 커널 2.6에서 빌드된 그들의 첫 번째 모바일 기기 플랫폼 결과물인 안드로이드를 발표.


- 2008년 10월 21일 안드로이드의 오픈소스 선언, 구글은 네트워크와 텔레폰 스택을 포함하는 완전한 소스 코드를 아파치 라이선스로 공개하였다.


- 2008년 12월 9일 ARM 홀딩스, 아세로스(Atheros Communications), 아수스, 가르민, 소프트뱅크, 소니 에릭슨, 도시바, 보다폰으로 구성된 새로운 14개의 멤버가 안드로이드 프로젝트에 참여하였다.


- 2010년 12월 15일 중국산 보급형 태블릿 단말 뿐만 아니라 갤럭시탭, 노션 잉크의 아담 등 하이엔드 유저를 겨냥한 태블릿 단말들이 출시되어 있는 상태로 안드로이드는 휴대전화 뿐 아니라 3G 또는 와이파이 전용 태블릿 단말에도 탑재되어 출시되고 있다.


구조 -


안드로이드의 구조는 위쪽 그림과 같은 구성 요소로 구성되며 이 구성 요소에는 응용 프로그램, 응용프로그램 프레임워크, 라이브러리, 안드로이드 런타임, 리눅스 커널의 총 5개의 계층으로 분류되어 있다.


버전 -

안드로이드는 6개월~12개월에 한번씩 업데이트를 진행한다. 업데이트의 내용은 주로 오류 수정이나 새로운 기능 추가로 구성된다. 하지만 이전 버전을 사용하는 기기들은 바로 업데이트를 제공받을 수 없으며, 기기 제조사에서 구글의 소스를 받아 직접 작업후 배포해야 한다. 이때문에 아직도 구버전 사용자가 많은 것이다. 참고로, 안드로이드의 각 버전들은 알파벳 첫 글자를 오름차순에 맞춘 음식 이름(디저트)을 코드명으로 삼고 있다. 버전은 1.0,2.0...으로 올라가며, 앞자리의 숫자가 올라가면 대규모 업데이트(메이저 업데이트), 소수점 아래 숫자가 올라가면 소규모 업데이트(마이너 업데이트)로 판명한다.


안드로이드는 6개월~12개월에 한번씩 업데이트를 진행한다. 업데이트의 내용은 주로 오류 수정이나 새로운 기능 추가로 구성된다. 하지만 이전 버전을 사용하는 기기들은 바로 업데이트를 제공받을 수 없으며, 기기 제조사에서 구글의 소스를 받아 직접 작업후 배포해야 한다. 이때문에 아직도 구버전 사용자가 많은 것이다. 참고로, 안드로이드의 각 버전들은 알파벳 첫 글자를 오름차순에 맞춘 음식 이름(디저트)을 코드명으로 삼고 있다. 버전은 1.0,2.0...으로 올라가며, 앞자리의 숫자가 올라가면 대규모 업데이트(메이저 업데이트), 소수점 아래 숫자가 올라가면 소규모 업데이트(마이너 업데이트)로 판명한다.


구성 및 특징 -

커널 : 리눅스

그래픽 엔진 : 오픈 GL의 휴대기기용 버전인 오픈GL ES를 채택

폰트 : 프리타입

웹 렌더링 : 웹키트 엔진

보안 모듈 : SSL

개발환경 : 이클립스와 이클립스에 통합된 플러그인 ADT(안드로이드 개발 도구) 사용을 권장하고 있음.



안드로이드 버전별 점유율(13년 8월 1일 기준) -




출처 - 위키백과 ( http://ko.wikipedia.org )

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

public static byte[] shortToByte(short a) {

byte[] shortToByte = new byte[2];

shortToByte[0] |= (byte)((a & 0xFF00) >>> 8);

shortToByte[1] |= (byte)(a & 0xFF & 0xff);

return shortToByte;

}  

   public static byte[] intToByte(int a) {  

     byte[] intToByte = new byte[4];     

     intToByte[0] |= (byte)((a&0xFF000000)>>24);     

     intToByte[1] |= (byte)((a&0xFF0000)>>16);     

     intToByte[2] |= (byte)((a&0xFF00)>>8);     

     intToByte[3] |= (byte)(a&0xFF);   

     return intToByte;  

   }  


-끝-

Android/WI-FI | Posted by 덩치 2013. 10. 23. 16:18

Wifi를 검색하여 자동으로 연결하기

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

wifi를 검색하는 방법에 대해서는 이전 글에서 알아보았다.


wifi에 연결하기 위해서는 보안방식과 비밀번호, ssid가 필요한데

보안방식과 ssid는 이전글의 ScanResult에서 뽑아낼 수가 있다.


비밀번호를 모르면 당연히 보안이 걸려있는 wifi에는 연결이 불가능.


일단 소스를 살펴보자


open일때

wfc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);

wfc.allowedProtocols.set(WifiConfiguration.Protocol.RSN);

wfc.allowedProtocols.set(WifiConfiguration.Protocol.WPA);

wfc.allowedAuthAlgorithms.clear();

wfc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);

 

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);

wep일때

wfc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);

wfc.allowedProtocols.set(WifiConfiguration.Protocol.RSN);

wfc.allowedProtocols.set(WifiConfiguration.Protocol.WPA);

wfc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);

wfc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);

wfc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);

 

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);

wfc.wepKeys[0] = "123456abcd";   <<--이부분중요. \"부분 빼고 그냥 비밀번호만 넣는다

wfc.wepTxKeyIndex = 0;

wpa나 wpa2일때

wfc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);

wfc.allowedProtocols.set(WifiConfiguration.Protocol.RSN);

wfc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);

wfc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);

wfc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);

wfc.preSharedKey = "\"".concat("123456abcd").concat("\"");


이렇게 보안방식별로 설정 방법이 다르다.

wpa와 wpa2는 설정이 같다고 하는데 필자의경우 wpa방식은 연결이 안되더라.

실제 테스트해본건 wpa2와 wep, open밖에 없다.

참고로 ScanResult.capabilites에서 뱉어주는 보안방식이 실제 open, web, wpa로 나오는건 아니고

[WPA-PSK-TKIP+CCMP][ESS]

[WPA2-PSK-CCMP][WPS][ESS]  이런식이며, 같은 방식도 length가 다른경우가 있다.

이부분은 알아서 잘 처리해주리라 믿고,



먼저 공통설정을

WifiConfiguration wfc = new WifiConfiguration(); (WifiConfiguration는 전역변수,지역변수 알아서 상황에 맞게 조절한다)

wfc = new WifiConfiguration();

wfc.SSID = "\"".concat(ssid 입력).concat("\"");

wfc.status = WifiConfiguration.Status.DISABLED;

wfc.priority = 40;

이렇게 해준다.


그리고 위의 보안방식에 따른 설정을 해 주고,


int networkId = wm.addNetwork(wfc);

if (networkId != -1) {

wm.enableNetwork(networkId, true);

}


이렇게 해주면 해당하는 wifi에 연결이 완료된다.

open형의 경우에는 level(신호세기)에 따라 정렬을 해 주고, 위의 소스를 적용시키면 가장 신호가 센놈으로

자동으로 연결될듯하다.



-끝-


Android/WI-FI | Posted by 덩치 2013. 10. 23. 16:08

Wifi 목록 검색하는법

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO


전역변수로 

ScanResult scanResult;

WifiManager wm;

List apList;


WifiManager 초기화

wm = (WifiManager) getSystemService(WIFI_SERVICE);


검색

wm.startScan(); 때려주고


IntentFilter filter = new IntentFilter();

filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);

registerReceiver(wifiReceiver, filter);

이렇게 브로드캐스트리시버를 사용해줘야한다.

이유는 스캔이 끝났을 때를 체크하기 위해서이다


브로드캐스트리시버 선언

private BroadcastReceiver wifiReceiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {

searchWifi();

}

}

};

스캔이끝났다는 방송이 전달되면 searchWifi() 호출


searchWifi를 보면

public void searchWifi() {

apList = wm.getScanResults();

if (wm.getScanResults() != null) {

int size = apList.size();

for (int i = 0; i < size; i++) {

scanResult = (ScanResult) apList.get(i);

}

}

}


이렇게 하면 scanResult에 Wifi에 대한 정보들이 입력된다. 호출은 반복문 안에서나 원하는 위치에서

scanResult.SSID 등으로 이용할 수 있다.

Wifi가 on인지 off인지 모를때는 필터액션에 와이파이 스테이트 체인지액션까지 넣어주면 더욱좋다


-끝-

Android/Adb | Posted by 덩치 2013. 10. 22. 13:58

자주 사용하는 ADB 명령어

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

Adb의 개념에 대해서는 이 전 글에서 알아봤으니, 이번에는 명령어에 대해 알아보자


다음 명령어들은 Path설정이 돼 있다면(이전 글 참조) 다른 준비작업 없이

커맨드라인에 그냥 입력하면 된다.


adb devices

현재 컴퓨터에서 인식하고 있는 Device 또는 Emulator 목록을 출력한다.

다른 작업을 하기 전 우선 단말이나 에뮬이 제대로 인식되었는지 확인차 사용한다.


adb install filename

filename은 apk파일의 이름이다. Device나 Emulator에 filename에 해당하는 어플을 설치하라는 

명령이다. 추가옵션으로 -r과 -l을 설정해 줄 수 있다.

-l은 어플이 다른 장치로 복사되는것을 막는 옵션, -r은 이미 존재하는 어플을 삭제하지 않고 설치


adb uninstall 패키지경로

ex ) com.android.test  (.apk를 제외한 패키지 전체경로 입력)

해당하는 어플이 삭제된다


adb push local_파일명 remote_파일명

개발자 컴퓨터의 파일을 타겟에 복사한다.


adb pull remote_파일명 local_파일명

타겟의 파일을 개발자 컴퓨터로 복사한다.


adb shell

Device에 직접 접속하는 명령어. 이 명령어를 통해 android console에 직접 접속할 수 있다.

디바이스를 루팅하지 않으면 리눅스에서는 먹히는 명령이 먹히지않는경우가 많다.


adb kill-server

adb에 문제가 있을 경우, adb를 종료시킨다. (단말기와 노트북의 케이블을 뺏다꽂아도된다)


adb start-server

종료된 adb를 실행시킨다.


adb reboot

Device를 재시작한다. (리부팅)


이정도가 자주사용되는 명령어들이고,


그 외 명령어들이 궁금하다면 그냥 adb 만 입력하면 도움말이 나온다.


디벨로퍼 사이트에서 좀 더 자세한 사항을 알아보고싶다면

http://developer.android.com/tools/help/adb.html 로 이동하면 된다.


-끝-




'Android > Adb' 카테고리의 다른 글

Adb에 대해 알아보자  (1) 2013.10.22
Android/Adb | Posted by 덩치 2013. 10. 22. 11:27

Adb에 대해 알아보자

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

이 글에서는 Adb의 개념과 사용을 위한 환경구축에 대해 다뤄보겠다.

명령어나 사용법은 다음 글에서 다룬다.



ADB(Android Debug Bridge)란 ?

안드로이드 SDK에 포함되어 있는 기능으로, 안드로이드 디버그에 관련된 툴

따라서 SDK의 설치가 필수적 (http://developer.android.com/sdk/index.html)이며, 기능으로는

어플리케이션 설치, 디바이스 접속 및 관리, 파일 업/다운로드, 시스템 로그출력, shell 접속 등이 가능하다.

특히 shell 접속 후 커맨드라인을 통하여 다양한 작업이 가능하다.

android는 리눅스 기반 운영체제이기때문에, shell에 접속하여 리눅스의 명령어를 사용 할 수 있다.

(모든 명령어를 지원하지는 않지만...)


ADB를 사용하기 위해서 -

adb명령을 사용할 때 마다 경로를 입력하기 번거로우니 환경변수를 등록 해 준다.



컴퓨터 마우스 우클릭 > 속성 > 고급 시스템 설정 > 환경변수 선택




Path 선택 > 편집 클릭



맨 뒤 ; 다음 sdk의 platform-tools경로 입력

(필자는 C:\Program Files\adt-bundle-windows-x86_64-20130522\sdk\platform-tools) > 확인


이러면 환경변수는 등록이 끝났다.


잘 등록되었는지 확인을 해 보자





명령프롬프트창 (윈도우키+R)을 띄운 뒤 adb 엔터 했을때 이렇게 글이 막 나온다면 성공, 사용 준비 끝


명령어나 사용하는 방법은 다음 글을 참고하기바란다


-끝-


'Android > Adb' 카테고리의 다른 글

자주 사용하는 ADB 명령어  (0) 2013.10.22
Android/Compile | Posted by 덩치 2013. 10. 21. 17:17

apk파일 디컴파일하기

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

apk파일을 디컴파일하게되면 원본 소스코드를 100%는 아니더라도 확인이 가능하다.

다만, 소스코드 난독화(proguard등)가 적용되어 있다면 코드의 해석은 상당히 힘들게된다.

그럼에도 불구하고 필요한 소스코드가 있다면 디컴파일하여 쓸만한 건덕지를 찾아봐야하니 디컴파일은 중요하다고

할 수 있다. (개발자의 경우 상당히 기분나쁜부분, 우리는 참고용으로만 사용하자)

디컴파일 전에 몇가지 준비사항이 필요하다.


1. https://code.google.com/p/dex2jar/downloads/list 

여기서 dex2jar 다운로드 > 

C:\Program Files\adt-bundle-windows-x86_64-20130522\sdk\platform-tools\dex2jar-0.0.9.15 경로에 압축해제 

(위 경로는 본인의 경우이고, sdk가 있는 경로상에 집어넣어주면 된다.)

dex2jar.bat 파일 우클릭 후 편집 > echo off 를 echo on 으로 수정



2. http://varaneckas.com/jad/

여기서 최신버전 Jad (자바 디컴파일러) 다운로드 > 압축해제


이제 디컴파일 준비는 끝났다.


시작




- 우선 디컴파일할 apk파일의 확장자를 apk 에서 zip로 바꾸면 zip파일이 된다.

- 압축해제하면 classes.dex 파일이 나온다. 이것만 있으면 된다






그렇게 나온 classes.dex 파일을

아까 받은 dex2jar 폴더로 이동시킨다





그리고 현재 위치의 경로를 복사 한 뒤

시작 > 실행 > cmd > cd적은다음 한칸띄고 마우스 우클릭 > 붙여넣기 > 엔터 하면

위의 경로로 이동





이제 d2j-dex2jar.bat classes.dex를 적고 엔터를 누르면 사진과같이 이상한글이 쫘르륵 나오고

경로에 classes-dex2jar.jar 파일이 생성된다.

버전에 따라 d2j-dex2jar.bat가 아니라 dex2jar.bat 인경우도 있는듯 하니 파일명을 잘보고 알아서 입력한다


그리고 생성된 파일을 압축해제하면 클래스파일들이 나오게 된다.




필자는 proguard를 적용한 apk를 사용했기때문에 보는바와같이 클래스명이 저렇게 지맘대로다.

이제 MainActivity.class를 java파일로 변환해줘야 소스코드를 확인할 수 있다.


MainActivity.class파일을 복사하여 2번에서 설치한 Jad가 설치된 경로에 붙여넣어준다





그리고





다시 시작 > 실행 > cmd > jad 경로로 이동 후


jad -o -sjava MainActivity.class  엔터




그러면 이렇게 MainActivity.java 파일이 생긴다 ! 실행해보자




다시말하지만 필자는 코드난독화(proguard)를 적용했기에 변수명이 이렇게 알아먹기 힘들게 표시된다.

(적용하지 않으면 대부분의 소스코드를 볼 수 있다)

오랜시간 해석한다면 불가능하진 않지만 상당한 곤욕을 치루는것은 어쩔 수 없다.


proguard에 관한 포스팅은 이전글을 참고하길 바라며


-끝-