갤럭시 노트 잠시 봤는데, 탐나더군요

사용자 삽입 이미지

화면과 해상도가 커졌는데요
5.3인치에 1280 x 800 HD 해상도 입니다.
( 제 맥북 해상도와 같네요…;;; )

단순히 화면이 커진 스마트폰이 아니라 정말 쓰임세가 늘어났더군요.
그동안 스마트폰에서 하지 못했던 Layout 구성도 가능해졌고요. 그야말로 신세경…
( 마치 아이폰과 아이패트 정도의 차이… )

문뜩 의문이 들었습니다.

“1280 x 800 해상도에서 CSS3 Animation 들이 어떻게 보일까?”
(아시다시피 안드로이드에서는 CSS3 하드웨어 가속이 안됩니다. )

그래서 Sencha Touch 의 Kitchen Sink 데모를 돌려 봤습니다.

허걱!! 이게 뭐람?
넥서스원 보다 못한 화면을 보여주고 있는 겁니다.
화면 전환이 일어날때 White 깜빡임도 심하고 에니메이션도 형편 없었습니다.
스크롤도 썩 맘에 들지 않고요.

비단 Sencha Touch 만의 문제는 아니었습니다.
CSS3 효과가 들어간 것들은 영~ 별로였습니다.

1280×800 해상도의 에니메이션을 CPU 가 돌리기에 버거운 것이지요.
그래도 듀얼코어에 1.5GHz 인데 실망감이 크더군요
(해외용 갤럭시 노트는 CPU가 더 좋답니다.)

웹앱 개발 할 때 안드로이드 Device 는 항상 여러가지 사항을 체크해 봐야 합니다.
좀 더 테스트가 이뤄지면 다시 포스팅 해야 겠습니다.

감사합니다.




2012/07/20 21:11 2012/07/20 21:11

일단 퍼미션을 지정합니다.

<!-- Boot Config -->
<receiver android:name=".BootBroadcast" android:enabled="true"
android:exported="false"
android:label="androesServiceManager"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</receiver>

BooBroadcast.java
public class BootBroadcast extends BroadcastReceiver {
static final String TAG = "ANDROES";
private final String BOOT_ACTION = "android.intent.action.BOOT_COMPLETED";

@Override
public void onReceive(Context context, Intent intent) {
//리시버가 발동시 나의 서비스 실행
Logger.d(TAG, "BOOT_ACTION : onReceive");
if (intent.getAction().equals(BOOT_ACTION)) {

// boot 시 shared값을 못불러오네~음
final SharedPreferences prefs = context.getSharedPreferences("androesPrefName", 0);
String status = prefs.getString("status", "");

Logger.d(TAG, "BOOT_ACTION : " + status);
if (status.equals("start")) {
// Logger.d(TAG, "BOOT_ACTION : cylost service ON");
context.startService(new Intent(context, androesService.class));
} else {
// Logger.d(TAG, "BOOT_ACTION : cylost service OFF");
}
}
}
}




2011/12/06 11:35 2011/12/06 11:35

AndroidManifest.xml

<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />

ReadGooleAccount.java
AccountManager mgr = AccountManager.get(this);
Account[] accts = mgr.getAccounts();
final int count = accts.length;
Account acct = null;

for(int i=0;i<count;i++) {
acct = accts[i];
Logger.d("ANDROES", "Account - name="+acct.name+", type="+acct.type);
}

관련사이트)
http://blog.naver.com/cwj3688?Redirect=Log&logNo=20121677208
http://blog.naver.com/cwj3688?Redirect=Log&logNo=20123259451


2011/12/06 11:34 2011/12/06 11:34

AndroidManifest.xml 에 퍼미션 추가

<uses-permission android:name="android.permission.READ_SMS" />
< uses-permission android:name="android.permission.WRITE_SMS" />

SMSList.java
public static final String MESSAGE_TYPE_INBOX = "1";
public static final String MESSAGE_TYPE_SENT = "2";
public static final String MESSAGE_TYPE_CONVERSATIONS = "3";
public static final String MESSAGE_TYPE_NEW = "new";

public void SMSList() {
try {
// Retrieve All SMS
/*
Inbox = "content://sms/inbox"
Failed = "content://sms/failed"
Queued = "content://sms/queued"
Sent = "content://sms/sent"
Draft = "content://sms/draft"
Outbox = "content://sms/outbox"
Undelivered = "content://sms/undelivered"
All = "content://sms/all"
Conversations = "content://sms/conversations"

addressCol= mCurSms.getColumnIndex("address");
personCol= mCurSms.getColumnIndex("person");
dateCol = mCurSms.getColumnIndex("date");
protocolCol= mCurSms.getColumnIndex("protocol");
readCol = mCurSms.getColumnIndex("read");
statusCol = mCurSms.getColumnIndex("status");
typeCol = mCurSms.getColumnIndex("type");
subjectCol = mCurSms.getColumnIndex("subject");
bodyCol = mCurSms.getColumnIndex("body");
*/
Uri allMessage = Uri.parse("content://sms/");
cur = this.getContentResolver().query(allMessage, null, null, null, null);
count = cur.getCount();
Logger.i( TAG , "SMS count = " + count);
String row = "";
String msg = "";
String date = "";
String protocol = "";
while (cur.moveToNext()) {
row = cur.getString(cur.getColumnIndex("address"));
msg = cur.getString(cur.getColumnIndex("body"));
date = cur.getString(cur.getColumnIndex("date"));
protocol = cur.getString(cur.getColumnIndex("protocol"));
// Logger.d( TAG , "SMS PROTOCOL = " + protocol);

String type = "";
if (protocol == MESSAGE_TYPE_SENT) type = "sent";
else if (protocol == MESSAGE_TYPE_INBOX) type = "receive";
else if (protocol == MESSAGE_TYPE_CONVERSATIONS) type = "conversations";
else if (protocol == null) type = "send";

Logger.i( TAG , "SMS Phone: " + row + " / Mesg: " + msg + " / Type: " + type + " / Date: " + date);
}
} catch (IOException e) {
e.printStackTrace();
}
}

public void SMSDelete() {
Uri deleteUri = Uri.parse("content://sms");
int count = 0;
Cursor c = this.getContentResolver().query(deleteUri, null, null,
null, null);
while (c.moveToNext()) {
try {
// Delete the SMS
String pid = c.getString(0);
// Get id;
String uri = "content://sms/" + pid;
// count = this.getContentResolver().delete(Uri.parse(uri),null, null);
} catch (Exception e) {
}
}
}

참고사이트)
http://blog.naver.com/algorithmlab?Redirect=Log&logNo=70098254191
http://mobdev.olin.edu/mobdevwiki/FrontPage/Tutorials/SMS%20Messaging#Catch_the_new_SMS_message
http://stackoverflow.com/questions/2584058/android-querying-the-sms-contentprovider
http://youropensource.com/projects/559-get-All-SMS-messages-in-the-Android
http://stackoverflow.com/questions/2183680/delete-sms-in-android-1-5
 




2011/12/06 11:34 2011/12/06 11:34

SharedPreferences : 화면의 내용이 초기화 되지 않고 유지되는 기능이다.

일반적으로 설정 기능을 구현하고자 할 때 주로 사용되는 것으로 유용하게 쓰일것으로 생각되어 포스팅합니다.

* SampleSharedPreferences.java

package com.androes.exrate;
...
public class SampleSharedPreferences extends Activity {
private SharedPreferences pref = null;
private EditText nameEditText = null;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

// 입력된 정보를 저장하기 위해 Class & Method 호출
pref = getSharedPreferences("com.androes.whitepaper",Activity.MODE_PRIVATE);

nameEditText = (EditText) findViewById(R.id.nameEditText);

// 값 호출
nameEditText.setText(pref.getString("nation", ""));
}
...
@Override
protected void onStop() {
super.onStop();
// 저장을 위해 Edit객체 호출
SharedPreferences.Editor editor = pref.edit();
// 값 변경
editor.putString("nation", nameEditText.getText().toString());
// 변경된 값 저장
editor.commit();
}
}

SharedPreferences 는 임시변수나 작은 크기의 설정 및 환경변수 정보를 저장하기 적합하지만,

다양하고 용량이 큰 데이터 저장시에는 파일 및 sqlite를 사용하는것을 권장합니다.

* 데이터 저장위치(DDMS 나 adb 툴을 이용)
/data/data/패키지명/shared_prefs/패키지명.xml

ex. /data/data/com.androes.exrate/shared_prefs/com.androes.exrate.xml

# cat com.androes.exrate.xml
< ?xml version='1.0' encoding='utf-8' standalone='yes' ?>
< map>
< string name="nation">KOR</string>
< /map>

단, 위 파일은 루팅하셔야만 확인할 수 있다는 점 잊지마세요^^
저도 루팅 안하고 이거 찾느라 바보같이 쌩쇼를 했네요..ㅠㅠ

그럼 님들 저처럼 삽질 마시고 유용하게 잘 사용하시길...^^

p.s) Summary
// WRITE
SharedPreferences prefs = getSharedPreferences("CyLostPrefName", MODE_PRIVATE);
Editor ed = prefs.edit();
ed.putString("gmailID", "snazzy7979");
ed.putString("gmailPWD", "pwd12345");
ed.commit();

// REMOVE
SharedPreferences prefs = getSharedPreferences("androesPrefName", MODE_PRIVATE);
Editor ed = prefs.edit();
ed.remove("gmailID");
ed.remove("gmailPWD");
// ed.clear();
ed.commit();

// READ
SharedPreferences prefs = getSharedPreferences("androesPrefName", MODE_PRIVATE);
String gmailID = prefs.getString("gmailID", "");
String gmailPWD = prefs.getString("gmailPWD", "");




2011/12/06 11:33 2011/12/06 11:33

private void saveView( View view )

{

String path =

Environment.getExternalStorageDirectory().getAbsolutePath();

Bitmap b = Bitmap.createBitmap(

view.getWidth(), view.getHeight(), Bitmap.Config.RGB_565);

if(b!=null){

try {

File f = new File(path+"/notes");

f.mkdir();

File f2 = new File(path + "/notes/"+title+".png");

Canvas c = new Canvas( b );

view.draw( c );

FileOutputStream fos = new FileOutputStream(f2);

if ( fos != null )

{

b.compress(Bitmap.CompressFormat.PNG, 100, fos );

fos.close();

}

//setWallpaper( b );

} catch( Exception e ){

Log.e("testSaveView", "Exception: " + e.toString() );

}

}

}




2011/12/06 11:33 2011/12/06 11:33
안드로이드 Intent에서 앱을 호출하는 방법을 정리 합니다.

연락처 Intent

  • 연락처 조회
intent = new Intent(Intent.ACTION_VIEW, 
Uri.parse("content://contacts/people/" +
String.valueOf(contact.getId())));
startActivity(intent);
  • 연락처 등록
intent = new Intent(Intent.ACTION_INSERT, 
Uri.parse("content://contacts/people"));
startActivity(intent);
  • 연락처 수정
intent = new Intent(Intent.ACTION_EDIT, 
Uri.parse("content://contacts/people/" +
String.valueOf(contact.getId())));
startActivity(intent);
  • 연락처 삭제
intent = new Intent(Intent.ACTION_DELETE, 
Uri.parse("content://contacts/people/" +
String.valueOf(contact.getId())));
startActivity(intent);

전화 Intent

  • 권한 설정 (AndroidManifest.xml)
전화 걸기         : CALL_PHONE = "android.permission.CALL_PHONE"
긴급 통화 : CALL_PRIVILEGED =
"android.permission.CALL_PRIVILEGED"
폰 상태 읽기 : READ_PHONE_STATE =
"android.permission.READ_PHONE_STATE"
폰 상태 수정 : MODIFY_PHONE_STATE =
"android.permission.MODIFY_PHONE_STATE"
브로드케스팅 수신 : PROCESS_OUTGOING_CALLS =
"android.permission.PROCESS_OUTGOING_CALLS"
전화 걸기 이전 : ACTION_NEW_OUTGOING_CALL =
"android.intent.action.NEW_OUTGOING_CALL"
  • 전화걸기 화면
Intent intent = new Intent(Intent.ACTION_DIAL, 
Uri.parse("tel:" + TelNumber));
startActivity(intent);
  • 전화걸기
Intent intent = new Intent(Intent.ACTION_CALL, 
Uri.parse("tel:" + TelNumber));
startActivity(intent);

SMS Intent

  • 권한 설정 (AndroidManifest.xml)
수신 모니터링       : RECEIVE_SMS = "android.permission.RECEIVE_SMS"
읽기 가능 : READ_SMS = "android.permission.READ_SMS"
발송 가능 : SEND_SMS = "android.permission.SEND_SMS"
SMS Provider로 전송 : WRITE_SMS = "android.permission.WRITE_SMS"
: BROADCAST_SMS = "android.permission.BROADCAST_SMS"
  • SMS 발송 화면
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra("sms_body", "The SMS text");
intent.setType("vnd.android-dir/mms-sms");
startActivity(intent);
  • SMS 보내기
Intent intent = new Intent(Intent.ACTION_SENDTO, 
Uri.parse("smsto://" + contact.getHandphone()));
intent.putExtra("sms_body", "The SMS text");
intent.setType("vnd.android-dir/mms-sms");
startActivity(intent);

이메일 Intent

  • 이메일 발송 화면
Intent intent = new Intent(Intent.ACTION_SENDTO, 
Uri.parse("mailto:" + contact.getEmail()));
startActivity(intent);

브라우저 Intent

  • Browser에서 URL 호출하기
new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com/"));
startActivity(intent);
  • 브라우저에서 검색
Intent intent = new Intent(Intent.ACT ION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, "검색어");
startActivity(intent);

지도 Intent

  • 지도 보기
Uri uri = Uri.parse ("geo: 38.00, -35.03");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

안드로이드 마켓 Intent

  • 안드로이드 마켓에서 Apps 검색
Uri uri = Uri.parse("market://search?q=pname:전제_패키지_명");  
//--- 예) market://search?q=pname:com.jopenbusiness.android.smartsearch
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
  • 안드로이드 마켓의 App 상세 화면
Uri uri = Uri.parse("market://details?id=전제_패키지_명");
//--- 예) market://details?id=com.jopenbusiness.android.smartsearch
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

갤럭시S의 Intent

  • 패키지명과 클래스명으로 App 호출
intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName("패키지명", "전체_클래스명"));
startActivity(intent);
  • 전화, SMS
  • 전화번호부 : com.android.contacts, com.sec.android.app.contacts.PhoneBookTopMenuActivity
  • 전화 : com.sec.android.app.dialertab, com.sec.android.app.dialertab.DialerTabActivity
  • 최근기록 : com.sec.android.app.dialertab, com.sec.android.app.dialertab.DialerTabDialerActivity
  • 메시지 : com.sec.mms, com.sec.mms.Mms
  • 이메일 : com.android.email, com.android.email.activity.Welcome
  • 일정 : com.android.calendar, com.android.calendar.LaunchActivity
  • 인터넷 : com.android.browser, com.android.browser.BrowserActivity
  • Google의 Android용 앱
  • 검색 : com.google.android.googlequicksearchbox, com.google.android.googlequicksearchbox.SearchActivity
  • 음성 검색 : com.google.android.voicesearch, com.google.android.voicesearch.RecognitionActivity
  • Gmail : com.google.android.gm, com.google.android.gm.ConversationListActivityGmail
  • 지도 : com.google.android.apps.maps, com.google.android.maps.MapsActivity
  • 위치찾기 : com.google.android.apps.maps, com.google.android.maps.LatitudeActivity
  • YouTube : com.google.android.youtube, com.google.android.youtube.HomeActivity
  • 토크 : com.google.android.talk, com.google.android.talk.SigningInActivity
  • Goggles : com.google.android.apps.unveil, com.google.android.apps.unveil.CaptureActivity
  • Google 번역 : com.google.android.apps.translate, com.google.android.apps.translate.HomeActivity
  • Reader : com.google.android.apps.reader, com.google.android.apps.unveil.CaptureActivity
  • Voice : com.google.android.apps.googlevoice, com.google.android.apps.googlevoice.SplashActivity
  • Google 별지도 : com.google.android.stardroid, com.google.android.stardroid.activities.SplashScreenActivity
  • 카메라 : com.sec.android.app.camera, com.sec.android.app.camera.Camera
  • TV : com.sec.android.app.dmb, com.sec.android.app.dmb.activity.DMBFullScreenView
  • Android 관리
  • 환경 설정 : com.android.settings, com.android.settings.Settings
  • 작업 관리자 : com.sec.android.app.controlpanel, com.sec.android.app.controlpanel.activity.JobManagerActivity
  • 마켓 : com.android.vending, com.android.vending.AssetBrowserActivity



2011/12/06 11:32 2011/12/06 11:32

File apkFile = new File("/sdcard/ApkTest.apk");
Uri apkUri = Uri.fromFile(apkFile);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType( Uri.fromFile(apkFile), "application/vnd.android.package-archive");
startActivity(intent);

this.finish(); // 현재 액티비티 종료




2011/12/06 11:32 2011/12/06 11:32
릴리즈되는 이미지에서는 모든 system file 권한이 read only로 되어있기 때문에 권한 수정이 필요합니다.


/system/app 권한 풀기 방법 1


1. 올릴 apk 파일을 준비한다.

2. emulator를 실행시킬 때, 다음과 같이 파티션 정보를 준다.

> emulator -avd [avd 이름] -partition-size [size]

ex) avd 이름 : avd2

size : 128

====> 요놈을 안 해준상태로 밀어 넣으면 Out of memory 에러가 난다.

참고로, partition이 필요한 이유는 > adb shell df 로 확인할 수 있겠다.

3. remount 시키며 권한을 준다.

> adb remount rw

4. 밀어 넣는다.

> adb push [ .apk] /system/app

/system/app 권한 풀기 방법 2


1. 단말과 연결하신후 adb shell 커맨드에서 다음과 같이 입력하셔서 이미지 리마운트를 합니다.
# mount -w -o remount -t rfs /dev/stl5 /system

2. 그리고 기존에 apk가 깔려있는 폴더와 파일의 권한을 변경합니다.
# chmod 777 /system/app
# chmod 777 /system/app/MusicPlayer.apk (뮤직어플의 경우)




2011/12/06 11:32 2011/12/06 11:32
// 웹페이지 띄우기
Uri uri = Uri.parse("http://www.google.com");
Intent it = new Intent(Intent.ACTION_VIEW,uri);
startActivity
(it);

// 구글맵 띄우기
Uri uri = Uri.parse("geo:38.899533,-77.036476");
Intent it = new Intent(Intent.Action_VIEW,uri);
startActivity
(it);


// 구글 길찾기 띄우기
Uri uri = Uri.parse("http://maps.google.com/maps?f=d&saddr=출발지주소&daddr=도착지주소&hl=ko");
Intent it = new Intent(Intent.ACTION_VIEW,URI);
startActivity
(it);


// 전화 걸기
Uri uri = Uri.parse("tel:xxxxxx");
Intent it = new Intent(Intent.ACTION_DIAL, uri);
startActivity
(it);


Uri uri = Uri.parse("tel.xxxxxx");
Intent it = new Intent(Intent.ACTION_CALL,uri);
// 퍼미션을 잊지 마세요. <uses-permission id="android.permission.CALL_PHONE" />


// SMS/MMS 발송
Intent it = new Intent(Intent.ACTION_VIEW);
it
.putExtra("sms_body", "The SMS text");
it
.setType("vnd.android-dir/mms-sms");
startActivity
(it);


// SMS 발송
Uri uri = Uri.parse("smsto:0800000123");
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
it
.putExtra("sms_body", "The SMS text");
startActivity
(it);


// MMS 발송
Uri uri = Uri.parse("content://media/external/images/media/23");
Intent it = new Intent(Intent.ACTION_SEND);
it
.putExtra("sms_body", "some text");
it
.putExtra(Intent.EXTRA_STREAM, uri);
it
.setType("image/png");
startActivity
(it);


// 이메일 발송
Uri uri = Uri.parse("mailto:xxx@abc.com");
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
startActivity
(it);


Intent it = new Intent(Intent.ACTION_SEND);
it
.putExtra(Intent.EXTRA_EMAIL, "me@abc.com");
it
.putExtra(Intent.EXTRA_TEXT, "The email body text");
it
.setType("text/plain");
startActivity
(Intent.createChooser(it, "Choose Email Client"));


Intent it = new Intent(Intent.ACTION_SEND);
String[] tos = {"me@abc.com"};
String[] ccs = {"you@abc.com"};
it
.putExtra(Intent.EXTRA_EMAIL, tos);
it
.putExtra(Intent.EXTRA_CC, ccs);
it
.putExtra(Intent.EXTRA_TEXT, "The email body text");
it
.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it
.setType("message/rfc822");
startActivity
(Intent.createChooser(it, "Choose Email Client"));


// extra 추가하기
Intent it = new Intent(Intent.ACTION_SEND);
it
.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it
.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/mysong.mp3");
sendIntent
.setType("audio/mp3");
startActivity
(Intent.createChooser(it, "Choose Email Client"));


// 미디어파일 플레이 하기
Intent it = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("file:///sdcard/song.mp3");
it
.setDataAndType(uri, "audio/mp3");
startActivity
(it);


Uri uri = Uri.withAppendedPath(
MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity
(it);


// 설치 어플 제거
Uri uri = Uri.fromParts("package", strPackageName, null);
Intent it = new Intent(Intent.ACTION_DELETE, uri);
startActivity
(it);


// APK파일을 통해 제거하기
Uri uninstallUri = Uri.fromParts("package", "xxx", null);
returnIt
= new Intent(Intent.ACTION_DELETE, uninstallUri);


// APK파일 설치
Uri installUri = Uri.fromParts("package", "xxx", null);
returnIt
= new Intent(Intent.ACTION_PACKAGE_ADDED, installUri);


// 음악 파일 재생
Uri playUri = Uri.parse("file:///sdcard/download/everything.mp3");
returnIt
= new Intent(Intent.ACTION_VIEW, playUri);


// 첨부파일을 추가하여 메일 보내기
Intent it = new Intent(Intent.ACTION_SEND);
it
.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it
.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/eoe.mp3");
sendIntent
.setType("audio/mp3");
startActivity
(Intent.createChooser(it, "Choose Email Client"));


// 마켓에서 어플리케이션 검색
Uri uri = Uri.parse("market://search?q=pname:pkg_name");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity
(it);
// 패키지명은 어플리케이션의 전체 패키지명을 입력해야 합니다.


// 마켓 어플리케이션 상세 화면
Uri uri = Uri.parse("market://details?id=어플리케이션아이디");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity
(it);
// 아이디의 경우 마켓 퍼블리싱사이트의 어플을 선택후에 URL을 확인해보면 알 수 있습니다.


// 구글 검색
Intent intent = new Intent();
intent
.setAction(Intent.ACTION_WEB_SEARCH);
intent
.putExtra(SearchManager.QUERY,"searchString")
startActivity
(intent);




2011/12/06 11:31 2011/12/06 11:31

Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
if (file.getName().endsWith(".pdf")){

intent.setDataAndType(Uri.fromFile(file), "application/pdf");
}else if (file.getName().endsWith(".hwp")){
intent.setDataAndType(Uri.fromFile(file), "application/hwp");
}
try{
startActivity(intent);
}catch(ActivityNotFoundException e){
util.showLongToast("해당파일을 실항할 수 있는 어플리케이션이 없습니다.\n파일을 열 수 없습니다.");
e.printStackTrace();
}



2011/12/06 11:30 2011/12/06 11:30

SAMSUNG, LG, Smart Phone Android Open Source

삼성 안드로이드폰 소스 입니다.
LG 안드로이드 소스 입니다.



2011/12/06 11:30 2011/12/06 11:30
웹뷰를 이용한 간단한 어플을 하나 만들었는데.. 세션이 안되서 삽질을 많이 했습니다.
구글링을 통해 소스는 많이 있지만 자바코드에서 특정 웹페이지를 호출해서 session.getId() 를 찍어본 결과
호출 할 때 마다 다른 값이 나오더군요..뭐 근데.. 방법은 의외로 간단한 거였더군요.. 어쩌면 당연한 거였다는..

일단은 session.getId() 값이 같은 값이 나와야 합니다.. 이 값이 계속 바뀐다면 아무리 삽질을 한들 안되겠지요..
HttpClient httpclient = new DefaultHttpClient(); 이부분을 멤버변수로 바로 선언해 버립니다...
보통 다른 소스들은 호출할 때 마다 계속 재 생성하는데.. 재생성을 안하니 유지가 됩니다..ㅋ 그리고 JSESSIONID를 쿠키로 구우면 OK...

setSyncCookie() 안에 들어 있는 코드는 구글링을 통해 얻은 소스입니다.. 많이들 보셨을듯..하네요.. 바뀐부분은 List<Cookie> cookies = ((DefaultHttpClient)httpclient).getCookieStore().getCookies();
이부분인데.. HttpClient 는 getCookieStroe 메소드가 없어서 위처럼 형변환 해줬습니다..

쿠키로 구을 때 Log 찍어보시면 token값과 JSESSIONID도 같이 구워집니다..
그리고 CookieSyncManager.getInstance().startSync(); 가 되면
웹뷰와 연동 됩니다.. 이렇게 안하면 웹뷰에서 접속하는 것과 HttpClient에서 접속하는 것이 따로 놀더군요...

응용해 보시길 바랍니다.. 더 좋은 방법이 있다면 조언해주시구요^^


public class AndroidTet extends Activity {
public static WebView webview;
public HttpClient httpclient = new DefaultHttpClient(); //멤버변수로 선언
public CookieManager cookieManager;
public String domain = "http://192.168.0.44";
public void onCreate(Bundle savedInstanceState) {
...
CookieSyncManager.createInstance(this);
cookieManager = CookieManager.getInstance();
CookieSyncManager.getInstance().startSync();
...
setSyncCookie();
...
public void onResume() {
super.onResume();
CookieSyncManager.getInstance().startSync();
}

public void onPause() {
super.onPause();

if (CookieSyncManager.getInstance() != null) {
CookieSyncManager.getInstance().stopSync();
}
}
protected void onDestroy() {
super.onDestroy();

if (cookieManager != null) {
cookieManager.removeAllCookie();
}
}
public void setSyncCookie() {
Log.e("surosuro", "token transfer start ---------------------------");
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("token", "TEST");// 넘길 파라메터 값셋팅token=TEST

HttpParams params = new BasicHttpParams();

HttpPost post = new HttpPost(domain+/androidToken.jsp");
post.setParams(params);
HttpResponse response = null;
BasicResponseHandler myHandler = new BasicResponseHandler();
String endResult = null;

try {
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}

try {
response = httpclient.execute(post);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

try {
endResult = myHandler.handleResponse(response);
} catch (HttpResponseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

List<Cookie> cookies = ((DefaultHttpClient)httpclient).getCookieStore().getCookies();

if (!cookies.isEmpty()) {
for (int i = 0; i < cookies.size(); i++) {
// cookie = cookies.get(i);
String cookieString = cookies.get(i).getName() + "="
+ cookies.get(i).getValue();
Log.e("surosuro", cookieString);
cookieManager.setCookie(domain, cookieString);
}
}
Thread.sleep(500);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}



2011/12/06 11:29 2011/12/06 11:29
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "TubeMusic");
나중에 끝날때 wl.release() 호출해주심 됨다.



2011/12/06 11:29 2011/12/06 11:29

1. layout/main.xml의 progress bar의 android:progressDrawable 속성을 설정한다.

<ProgressBar

android:progressDrawable="@drawable/new_drawable"

...

</ProgressBar>

2. res/drawable/new_drawable.xml 파일을 생성한다.

각 스타일을 설정한다.

<?xml version="1.0" encoding="utf-8"?>

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+android:id/background" android:drawable="@drawable/backgroundProgress" />
<item android:id="@+android:id/secondaryProgress" android:drawable="@drawable/secondaryProgress" />
<item android:id="@+android:id/progress" android:drawable="@drawable/progress" />
</layer-list>

3. res/drawable 디렉토리 밑에 다음의 파일을 생성한다.

backgroundProgress.png

secondaryProgress.png

progress.png

png파일을 생성하지 않고 drawable로 작성하려면

2b. res/drawable/new_drawable.xml 파일을 다음과 같이 설정한다.

<?xml version="1.0" encoding="utf-8"?>

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

<item android:id="@android:id/background">
<shape>
<corners android:radius="0dip" />
<gradient
android:startColor="#ff9d9e9d"
android:centerColor="#ff5a5d5a"
android:centerY="0.75"
android:endColor="#ff747674"
android:angle="270"
/>
</shape>
</item>

<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="0dip" />
<gradient
android:startColor="#80ffd300"
android:centerColor="#80ffb600"
android:centerY="0.75"
android:endColor="#a0ffcb00"
android:angle="270"
/>
</shape>
</clip>
</item>

<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="0dip" />
<gradient
android:startColor="#ff0000"
android:centerColor="#00ff00"
android:centerY="0.75"
android:endColor="#0000ff"
android:angle="0"
/>
<stroke android:width="3dp" color="#000000"/>
<padding android:left="10dp" android:top="10dp"
android:right="10dp" android:bottom="10dp" />
</shape>
</clip>
</item>
</layer-list>




2011/12/06 11:29 2011/12/06 11:29
VideoView를 사용하여 assets 디렉토리에 위치한 동영상을 실행하는 코드를 작성하였는데 계속 오류가 발생 했다.
프로젝트의 /assets/a.mp4에 파일을 저장했다.
Url fileuri= Uri.parse("file:///android_asset/a.mp4");
이 렣게 uri를 생성해서 실행했는데 오류가 발생 한다. 이유를 모르겠다. 구글검색으로 자료를 찾아봐도 해결책을 찾을 수 없었다. 그래서 파일의 위치를 res/raw/a.mp4 로 옮기었다.
그리고 다음과 같이 uri를 생성했다.
Uri videofile = Uri.parse("android.resource://"+getPackageName()+"/raw/a");

이렇게 했더니 정상적으로 동영상이 표시되었다.
아래는 전체 소스코드이다. 물론 layout/main.xml에 VideoView객체를 video_view라는 id로 추가했다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<VideoView android:id="@+id/video_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"></VideoView>
</LinearLayout>
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
import android.widget.VideoView;
public class VideoPlayer extends Activity {
VideoView videoview ;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
videoview = (VideoView) findViewById(R.id.video_view);
try {
Uri videofile = Uri.parse("android.resource://"+getPackageName()+"/raw/a");
videoview.setVideoURI(videofile);
//descriptor.
videoview.start();
videoview.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
Log.d(getClass().getName(), "onCompletion()");
}
});
} catch (Exception ex) {
Log.d(getClass().getName(), "Video failed: '" + ex + "'" );
ex.printStackTrace();
}
}
}



2011/12/06 11:28 2011/12/06 11:28

바코드 스캔 라이브러리를 소개하려고 한다.

이름이 zxing이다.

소개를 그대로 인용하면


Multi-format 1D/2D barcode image processing library with clients for Android, Java

다중포멧 1D/ 2D 바코드 이미지 프로세싱 라이브러리, Android, Java 클라이언트 용



Project 사이트는 http://code.google.com/p/zxing/ 이다.

라이센스는 Apache License 2.0 이다.


android 뿐만아니라 iPhone같은 다양한 모바일 기기를 지원한다.


라이브러리를 받아서 빌드한뒤 샘플을 만들어 봤는데 1 시간 밖에 걸리지 않았다.


라이브러리 빌드를 위해서는 ant를 설치해야한다.


1. zxing의 core 디렉토리로 이동한뒤 ant명령어를 입력하여 빌드 한다 결과물로 core.jar가 생성된다.


2. Android 프로젝트를 생성한다.


3. Android 프로젝트의 lib 디렉토리를 생성한뒤 core.jar를 안드로이드 lib에 복사


4. Android 프로젝트의 build path에 /lib/core.jar를 추가해 준다.


5. zxing의 android-integration의 java파일을 Android 프로젝트의 src로 복사한다.


6. 적당한 패키지 경로를 수정해 준다.


7. 버튼을 추가하고 IntentIntegrator.initiateScan 바코드 스캔함수를 호출한다.


public class ZxingTest extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

View scan = findViewById(R.id.scan);

scan.setOnClickListener(new View.OnClickListener() {

  

   @Override

   public void onClick(View v) {

    IntentIntegrator.initiateScan(ZxingTest.this);

   }

  });

}

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

//super.onActivityResult(requestCode, resultCode, data);

IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);

if (scanResult != null) {

// handle scan result

TextView scanResultText = (TextView) findViewById(R.id.scanResult);

String text = "format="+scanResult.getFormatName()+", data:"+scanResult.getContents();

scanResultText.setText(text);

}

}

}



8. onActivityResult에서 결과를 받아서 처리한다


2011/12/06 11:28 2011/12/06 11:28

가끔씩 마주치게 되는 "OutOfMemoryError : bitmap size exceeds VM budget" 에러는 메모리 누수가 주요 원인이다.
이와 관련된 링크를 모아봤다.


* 액티비티가 멈출 때 비트맵을 재활용(즉 GC)되게 하라.
http://stackoverflow.com/questions/1949066/java-lang-outofmemoryerror-bitmap-size-exceeds-vm-budget-android
http://stackoverflow.com/questions/2191407/changing-imageview-content-causes-outofmemoryerror

- bitmap 이미지인 경우 recycle() 호출
- onPause에서 수행하는게 좋음

- ((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle();


* 이미지를 미리 줄여서 읽어들여라
http://chiyo85.tistory.com/entry/Android-Bitmap-Object-Resizing-Tip
http://www.memofy.com/memofy/show/1008ab7f2836ab7f01071c2dbfe138/outofmemory-exception-when-decoding-with-bitmapfactory

- BitmapFactory.Options.inSampleSize 활용


* Activity Context에 대한 참조(reference)를 오랫동안 유지하지 말아라
http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html
(한글 번역 : http://blog.naver.com/huewu/110082062273 )

- Drawable.setCallback(null) 사용
- WeakReference를 가진 static 내부 클래스
- 이미지를 static 변수로 처리하지 말것.


* 외부 클래스의 상태에 의존하지 않는 내부 클래스는 static으로 선언하라
- 내부 클래스는 외부 클래스를 크게 만들며 또한 외부클래스 객체가 필요 이상으로 오래 살아있게 되어 메모리를
더 차지할 수 있다.
- 외부 클래스의 상태 필드에 접근하지 않는(즉, 외부 객체의 상태에 의존하지 않는) 내부 클래스는 static으로 선언.


* Attacking memory problems on Android
http://ttlnews.blogspot.com/2010/01/attacking-memory-problems-on-android.html




2011/12/06 11:27 2011/12/06 11:27

안드로이드 색상코드 형식

AA : 투명도, 00~FF(투명~불투명)
RR : 적색, 00~FF
GG : 녹색, 00~FF
BB : 청색, 00~FF

형식 종류
- #AARRGGBB
- #RRGGBB
- #RGB


이미지 배경을 투명하게하는 값

android:Background = "#00FF0000"




2011/12/06 11:25 2011/12/06 11:25
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// 웹페이지 띄우기
Uri uri = Uri.parse("http://www.google.com");
Intent it  = new Intent(Intent.ACTION_VIEW,uri);
startActivity(it);
// 구글맵 띄우기
Uri uri = Uri.parse("geo:38.899533,-77.036476");
Intent it = new Intent(Intent.Action_VIEW,uri);
startActivity(it);
// 구글 길찾기 띄우기
Uri uri = Uri.parse("http://maps.google.com/maps?f=d&saddr=출발지주소&daddr=도착지주소&hl=ko");
Intent it = new Intent(Intent.ACTION_VIEW,URI);
startActivity(it);
// 전화 걸기
Uri uri = Uri.parse("tel:xxxxxx");
Intent it = new Intent(Intent.ACTION_DIAL, uri); 
startActivity(it); 
Uri uri = Uri.parse("tel.xxxxxx");
Intent it = new Intent(Intent.ACTION_CALL,uri);
// 퍼미션을 잊지 마세요. <uses-permission id="android.permission.CALL_PHONE" />
// SMS/MMS 발송
Intent it = new Intent(Intent.ACTION_VIEW);  
it.putExtra("sms_body", "The SMS text");  
it.setType("vnd.android-dir/mms-sms");  
startActivity(it); 
// SMS 발송
Uri uri = Uri.parse("smsto:0800000123");  
Intent it = new Intent(Intent.ACTION_SENDTO, uri);  
it.putExtra("sms_body", "The SMS text");  
startActivity(it); 
// MMS 발송
Uri uri = Uri.parse("content://media/external/images/media/23");  
Intent it = new Intent(Intent.ACTION_SEND);  
it.putExtra("sms_body", "some text");  
it.putExtra(Intent.EXTRA_STREAM, uri);  
it.setType("image/png");  
startActivity(it);
// 이메일 발송
Uri uri = Uri.parse("mailto:xxx@abc.com");
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
startActivity(it);
Intent it = new Intent(Intent.ACTION_SEND);  
it.putExtra(Intent.EXTRA_EMAIL, "me@abc.com");  
it.putExtra(Intent.EXTRA_TEXT, "The email body text");  
it.setType("text/plain");  
startActivity(Intent.createChooser(it, "Choose Email Client")); 
Intent it = new Intent(Intent.ACTION_SEND);    
String[] tos = {"me@abc.com"};    
String[] ccs = {"you@abc.com"};    
it.putExtra(Intent.EXTRA_EMAIL, tos);    
it.putExtra(Intent.EXTRA_CC, ccs);    
it.putExtra(Intent.EXTRA_TEXT, "The email body text");    
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");    
it.setType("message/rfc822");    
startActivity(Intent.createChooser(it, "Choose Email Client"));  
// extra 추가하기
Intent it = new Intent(Intent.ACTION_SEND);  
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");  
it.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/mysong.mp3");  
sendIntent.setType("audio/mp3");  
startActivity(Intent.createChooser(it, "Choose Email Client"));
// 미디어파일 플레이 하기
Intent it = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("file:///sdcard/song.mp3");
it.setDataAndType(uri, "audio/mp3");
startActivity(it);
Uri uri = Uri.withAppendedPath(
  MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");  
Intent it = new Intent(Intent.ACTION_VIEW, uri);  
startActivity(it); 
// 설치 어플 제거
Uri uri = Uri.fromParts("package", strPackageName, null);  
Intent it = new Intent(Intent.ACTION_DELETE, uri);  
startActivity(it);
// APK파일을 통해 제거하기
Uri uninstallUri = Uri.fromParts("package", "xxx", null);
returnIt = new Intent(Intent.ACTION_DELETE, uninstallUri);
// APK파일 설치
Uri installUri = Uri.fromParts("package", "xxx", null);
returnIt = new Intent(Intent.ACTION_PACKAGE_ADDED, installUri);
// 음악 파일 재생
Uri playUri = Uri.parse("file:///sdcard/download/everything.mp3");
returnIt = new Intent(Intent.ACTION_VIEW, playUri);
// 첨부파일을 추가하여 메일 보내기
Intent it = new Intent(Intent.ACTION_SEND); 
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text"); 
it.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/eoe.mp3"); 
sendIntent.setType("audio/mp3"); 
startActivity(Intent.createChooser(it, "Choose Email Client"));
// 마켓에서 어플리케이션 검색
Uri uri = Uri.parse("market://search?q=pname:pkg_name"); 
Intent it = new Intent(Intent.ACTION_VIEW, uri); 
startActivity(it); 
// 패키지명은 어플리케이션의 전체 패키지명을 입력해야 합니다.
// 마켓 어플리케이션 상세 화면
Uri uri = Uri.parse("market://details?id=어플리케이션아이디"); 
Intent it = new Intent(Intent.ACTION_VIEW, uri); 
startActivity(it);
// 아이디의 경우 마켓 퍼블리싱사이트의 어플을 선택후에 URL을 확인해보면 알 수 있습니다.
// 구글 검색
Intent intent = new Intent();
intent.setAction(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,"searchString")
startActivity(intent);

[출처] Intent 활용 예제|작성자 다빈




2011/12/06 11:25 2011/12/06 11:25

Audio :

*패키지의 assets/audio/oh.mp3 플레이

AssetFileDescriptor atd = getAssets().openFd("audio/oh.mp3");

MediaPlayer audio_play = new MediaPlayer();

audio_play.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());

afd.close();

audio_play.start();

*패키지의 res/raw/oh.mp3 플레이

MediaPlayer audio_play = MediaPlayer.create(context, R.raw.oh);

audio_play.start();

*파일시스템의 /data/oh.mp3 플레이

MediaPlayer audio_play = new MediaPlayer();

audio_play.setDataSource("/data/oh.mp3");

audio_play.start();

Video :

*파일시스템의 /data/oh.mp4 플레이

VideoView video = (VideoView)findViewById(R.id.video);

MediaController nc = new MediaController(this);

nc.setMediaPlayer(video);

video.setVideoPath("/data/oh.mp4");

video.start();

*패키지의 res/raw/oh.mp4 플레이

VideoView video = (VideoView) findViewById(R.id.video);
video.setVideoURI(Uri.parse("android.resource://패키지명/" + R.raw.파일이름));
video.setMediaController(new MediaController(this));
video.requestFocus();
video.start();




2011/12/06 11:24 2011/12/06 11:24
ArrayList<string> phone = new ArrayList<string>();
       
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
while(cursor.moveToNext())
{
    int index = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
    String s = cursor.getString(index);
    phone.add(s);
}
       
Log.e("#####", phone.toString());
//결과 : [01011112222, 01033334444, 01055556666]
public static Map<String, String> getAddressBook(Context context)
{
    Map<String, String> result = new HashMap<String, String>();
    Cursor cursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
    while(cursor.moveToNext())
    {
        int phone_idx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
        int name_idx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
        String phone = cursor.getString(phone_idx);
        String name = cursor.getString(name_idx);
        result.put(name, phone);
    }
   
    return result;
}




2011/12/06 11:24 2011/12/06 11:24

[01] UI 설계(Widget, View, Layout) 개론

View ---+--- View(Widget): 안드로이드가 제공하는 콘트롤, TextView, EditText, Button....
|
+--- Custom View: 기존의 View 를 상속받아 변경하거나 새롭게 생성.
|
+--- ViewGroup --- Layout: View를 배치하고 그룹화 함, LinearLayout, RelativeLayout, TableLayout....

1. UI 설계 방법
- 자바소스상에서 class상에 직접 지정하는 경우와 XML을 이용하는
방법이 있으며 개발과 유지보수의 장점 때문에 XML이 많이 사용된다.
XML을 UI 설계로 이용하는 대표적인 언어는 Flex등이 있다.

2. View
- Widget은 View로 되어있으며 View는 트리구조(상속)를 이루고 있다.
- 모든 안드로이드의 비주얼 콤포넌트는 View 클래스로부터 내려온다.
- View는 Widget, Control이라고 부르기도 한다.
- View --> ViewGroup --> Layout 의 관계를 갖는다.

3. Layout
- ViewGroup class의 확장
- View를 담는 컨테이너 역활을 함.

[02] View
- 화면을 구성하는 UI를 제공한다.
- API: http://developer.android.com/reference/android/view/View.html

1. 공통 XML 속성
- View는 많은 공통 속성과 메소드를 가지고 있는데 TextView의 속성이 대부분의 View에
그대로 적용된다.

android:id : View의 아이디
android:layout_width : 부모뷰를 기준으로 한 폭의 의 크기
android:layout_height : 부모뷰를 높이로한 뷰의 높이
android:padding : 외곽선과 뷰안의 내용과의 간격
android:visibility : 초기화면 표시 여부
android:background : Widget의 배경색을 #RGB, #ARGB, #RRGGBB, #AARRGGBB로 지정
android:clickable : 클릭 가능 여부
android:longClickable : 롱 클릭 가능 여부
android:focusable : 키보드 포커스의 가능 여부

2. 공통 메소드
setEnabled() : Widget의 사용 가능 여부 지정
isEnabled() : Widget이 사용 가능 상태인지 확인
requestFocus(): 해당 Widget으로 입력 포커스 이동
isFocused() : Widget이 현재 포커스를 가지고 있는지 확인
setFocus() : Widget에 focus를 지정
getParent() : 상위 위젯이나 컨테이너 추출
findViewById(): 지정한 id에 대한 위젯 추출
getRootView() : 최상위 컨테이너 추출

3. 레이블
- import android.widget.TextView;
- View --> TextView
- 단순한 문자열의 출력.
- 출력 문자열은 변경할 수 없다.

3. 버튼
- import android.widget.Button;
- 터치 및 클릭 이벤트를 처리한다.
- View --> TextView --> Button
- TextView를 상속받으며 사용자의 tab(터치) 이벤트를 주로 처리한다.

4. 이미지
- import android.widget.ImageView;
- View --> ImageView: 이미지를 넣을 수 있는 View Class
- View --> ImageView --> ImageButton: 이미지를 넣을 수 있는 버튼 클래스

5. 입력 필드
- import android.widget.EditText;
- View --> TextView --> EditText
- 문자를 입력 받을 수 있는 기능 제공

1) XML 속성
android:autoText : 자동 철자 교정
android:capitalize : 첫 글자를 대문자로 변환
android:digits : 특정 숫자만 입력
android:singleLine : 여러줄을 입력받을 것인지 지정
android:numeric : 숫자만 입력 가능
android:password : 패스워드 입력 형태 지정
android:phoneNumber: 전화번호 입력
android:inputMethod: 특정 형식의 입력 지정

6. 체크 박스
- import android.widget.CheckBox;
- View --> TextView --> Button --> CompoundButton
--> RadioButton --> CheckBox
- 취미같은 다중 선택 가능

7. 라디오 버튼
- import android.widget.RadioButton;
- View --> TextView --> Button --> CompoundButton --> RadioButton
- 성별같은 단일 선택만 가능
- RadioGroup에 의해 RadioButton의 그룹화 가능

[03] Layout
- android.view.ViewGroup class 상속 받음.

1. 공통 특성
android:layout_height : 부모 뷰 기준, 자식 뷰에 적용, 뷰의 높이.
android:layout_width : 부모 뷰 기준, 자식 뷰에 적용, 뷰의 너비, 자식뷰의 경우 필수임.
android:layout_margin : 부모 뷰 기준, 뷰의 상하 좌우의 여백 공간.
android:layout_marginTop : 부모 뷰 기준, 뷰의 위쪽 여백 공간.
android:layout_marginBottom: 부모 뷰 기준, 뷰의 아래쪽 여백 공간.
android:layout_marginRight : 부모 뷰 기준, 뷰의 오른쪽 여백 공간 .
android:layout_marginLeft : 부모 뷰 기준, 뷰의 왼쪽 여백 공간.
android:gravity : 자식 뷰 기준, View로 부터의 위치.
android:layout_gravity : 부모 뷰 기준, 현재 View의 위치.

2. AbsoluteLayout: View가 x,y좌표에 의해서 배치, 레이아웃이 깨질 수 있고 화면의
구성요소가 서로 잘 맞아 떨어저야함으로 잘 사용되지 않는다.
안드로이드 SDK 1.5 R1부터 폐기 대상으로 분류되어 더이상 사용되지 않는다.

3. FrameLayout: View를 좌측 상단에 배치, 여러개의 View가 있는 경우 겹쳐서 보임으로
Layout의 효과는 떨어짐, 사용 빈도는 적음.

4. LinearLayout: 직선형의 배치 방식, View를 수평 또는 수직의 라인을 View를 배치,
입력 양식에 많이 사용된다.
android:orientation: 뷰가 출력될 방향을 지정한다.

5. RelativeLayout: 다른 콘트롤에 비례해서 콘트롤의 위치 지정.
- 뷰를 위치를 설정하기위해 여러번 선언 가능.

- 부모뷰를 기준으로
android:layout_marginRight="20px" : 뷰를 부모의 오른쪽에서 일정 간격 떨어짐
android:layout_marginTop="60px" : 뷰를 부모의 위쪽에서 일정 간격 떨어짐
android:layout_alignParentTop="true" : 뷰를 부모에서 상단에 배치
android:layout_centerHorizontal="true" : 뷰를 부모에서 수평 중앙에 배치
android:layout_alignParentRight="true" : 뷰를 부모에서 오른쪽에 배치
android:layout_alignParentLeft="true" : 뷰를 부모에서 왼쪽에 배치
android:layout_centerVertical="true" : 뷰를 부모에서 수직 중앙에 배치
android:layout_centerInParent="true" : 뷰를 수직, 수평의 중앙에 배치
android:layout_alignParentBottom="true": 뷰를 부모에서 하단에 배치

- 주변에 배치된 뷰를 기준으로
android:layout_toRightOf="@id/idname" : 주변 특정 뷰의 오른쪽에 배치
android:layout_toLeftOf="@id/idname" : 주변 특정 뷰의 외쪽에 배치
android:layout_alignBaseline="@id/idname": 주변 특정 뷰와 같은 라인에 배치
android:layout_below="@id/idname" : 주변 특정 뷰의 아래에 배치
android:layout_above="@id/idname" : 주변 특정 뷰의 위에 배치
android:layout_alignRight="@id/idname" : 주변 특정 뷰의 오른쪽에 배치
android:layout_alignLeft="@id/idname" : 주변 특정 뷰의 왼쪽에 배치
android:layout_alignTop="@id/idname" : 주변 특정 뷰의 위쪽에 배치

- 예) [TEL][SMS]의 경우
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnSms"
android:layout_marginLeft="1px"
android:text="SMS"
android:textSize="16px"
android:layout_alignParentRight="true"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnTel"
android:layout_marginLeft="6px"
android:text="TEL"
android:textSize="16px"
android:layout_toLeftOf="@id/btnSms"
/>

6. TableLayout: 행과 열의 격자를 이용해 View의 배치.
- 아래의 레이아웃 특성을 조합하여 사용

android:stretchColumns="1" : 두번째 컴럼의 크기를 남는 공간으로 늘림(확장).
android:stretchColumns=" 늘리려는 column 번호(0~), *"
android:shrinkColumns=" 필요한 공간만 사용하고 줄이고자 하는 column 번호(0~), *"

android:stretchColumns="1" android:shrinkColumns="*": 모든 컬럼의 값을 전부
필요한 만큼만 사용하고 1번째 컬럼을 남은 공간으로 전부 확대

android:collapseColumns=" 숨기고자 하는 column 번호(0~), *"

android:layout_span=" 차지하려는 Column 수", 셀 합치기
android:layout_span="2": 컬럼 2개를 합침.



이름:[ ]의 경우 2번째 입력란을 확대함.
android:layout_marginTop="60px" : 뷰를 부모의 위쪽에서 일정 간격 떨어짐
android:layout_alignParentTop="true" : 뷰를 부모에서 상단에 배치
android:layout_centerHorizontal="true" : 뷰를 부모에서 수평 중앙에 배치
android:layout_alignParentRight="true" : 뷰를 부모에서 오른쪽에 배치
android:layout_alignParentLeft="true" : 뷰를 부모에서 왼쪽에 배치
android:layout_centerVertical="true" : 뷰를 부모에서 수직 중앙에 배치
android:layout_centerInParent="true" : 뷰를 수직, 수평의 중앙에 배치
android:layout_alignParentBottom="true": 뷰를 부모에서 하단에 배치





2011/12/06 11:23 2011/12/06 11:23

1. ViewPage Layout 기술

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="vertical"

>

<android.support.v4.view.ViewPager

android:id="@+android:id/viewpager"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

/>

</LinearLayout>

2. FragmentActivity 기술
/**
*
*/
package com.andy.fragments.viewpager;
import java.util.List;
import java.util.Vector;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import com.andy.R;
import com.andy.fragments.tabs.Tab1Fragment;
import com.andy.fragments.tabs.Tab2Fragment;
import com.andy.fragments.tabs.Tab3Fragment;
/**
* The <code>ViewPagerFragmentActivity</code> class is the fragment activity hosting the ViewPager
* @author mwho
*/
public class ViewPagerFragmentActivity extends FragmentActivity{
/** maintains the pager adapter*/
private PagerAdapter mPagerAdapter;
/* (non-Javadoc)
* @see android.support.v4.app.FragmentActivity#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  super.setContentView(R.layout.viewpager_layout);
  //initialsie the pager
  this.initialisePaging();
}
/**
* Initialise the fragments to be paged
*/
private void initialisePaging() {
  List<Fragment> fragments = new Vector<Fragment>();
  fragments.add(Fragment.instantiate(this, Tab1Fragment.class.getName()));
  fragments.add(Fragment.instantiate(this, Tab2Fragment.class.getName()));
  fragments.add(Fragment.instantiate(this, Tab3Fragment.class.getName()));
  this.mPagerAdapter = new PagerAdapter(super.getSupportFragmentManager(), fragments);
  //
  ViewPager pager = (ViewPager)super.findViewById(R.id.viewpager);
  pager.setAdapter(this.mPagerAdapter);
}
}
3. PageAdapter 기술
/**
*
*/
package com.andy.fragments.viewpager;
import java.util.List;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
/**
* The <code>PagerAdapter</code> serves the fragments when paging.
* @author mwho
*/
public class PagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
/**
* @param fm
* @param fragments
*/
public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
  super(fm);
  this.fragments = fragments;
}
/* (non-Javadoc)
* @see android.support.v4.app.FragmentPagerAdapter#getItem(int)
*/
@Override
public Fragment getItem(int position) {
  return this.fragments.get(position);
}
/* (non-Javadoc)
* @see android.support.v4.view.PagerAdapter#getCount()
*/
@Override
public int getCount() {
  return this.fragments.size();
}
}
4.실행
왼쪽에서 오른쪽은 빨강->녹색->파랑



2011/12/06 11:23 2011/12/06 11:23

사용자 삽입 이미지

이것은 안드로이드 Tab UI 를 구성하는 구성요소 입니다.

안드로이드 Tab UI 는 이와같이 세 개의 다른 클래스들의 집합으로 이루어져 있습니다.

TabHost 는 TabUI 를 구성하는 전체 틀 입니다.

여기에는 특정한 android:id 를 가지는 TabWidget 와 TabSpec 이 포함되어야 합니다.

TabWidget 는 TabUI 에서 선택하는 버튼이 나오는 부분을 말하며 이것의 android:id 는 반드시 “@android:id/tabs” 가 되어야 합니다.

TabSpec 는 하나의 탭을 구성하는 구성요소들의 집합으로서 View 의 하위구성요소가 아니기 때문에 layout xml 파일에 직접 추가될 수 없습니다. 그래서 java 소스코드상으로 추가해 주어야 하며 layout xml 에는 이를 표시하기 위하여“@android:id/tabcontent” 라는 android:id 를 가지는 Layout View 가 추가되어 있어야 합니다.

이렇게 글로만 보면 상당히 어렵게 보이는데 이것을 쉽게 쓰도록 만들어 놓은것이 바로 TabActivity 클래스 입니다.

아래는 TabActivity 를 이용하여 layout xml 파일 없이 TabUI 를 구성하는 예 입니다.

package net.cranix.android.cranixcontact;

import android.app.TabActivity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TabHost;

public class CranixContact extends TabActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

final TabHost tabHost = getTabHost();
tabHost.addTab(
tabHost.newTabSpec("tab1")
.setIndicator("Contacts")
.setContent(new Intent(this,ContactsTabActivity.class))
);
tabHost.addTab(
tabHost.newTabSpec("tab2")
.setIndicator("Calllog")
.setContent(new Intent(this,CalllogTabActivity.class))
);
}
}

위의 소스에는 layout xml 파일이 사용되는 부분이 없지만 TabActivity 내부적으로 기본적인 layout 을 사용하고 있습니다.

그렇다면 TabActivity 에서 사용하는 기본적인 layout 은 무엇일까요?

안드로이드 소스를 직접 다운받아서 xml 파일을 뒤져보면 아래와 같은 레이아웃 파일을 발견할 수 있습니다.

<TabHost xmlns:android="http://schemas.android.com/apk/res/android" 
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TabWidget android:id="@android:id/tabs"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0" />
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"/>
</LinearLayout>
</TabHost>

이것이 바로 TabActivity 클래스가 기본으로 사용하는 layout xml 파일입니다.

위에서 말로 설명한 부분에 나와있는 대로 구성되어있는것을 확인할 수 있습니다.

TabActivity 를 상속받은 Activity 라면 기본적으로 위와같은 layout xml 파일이 contentView 로 자동으로 셋팅됩니다.

이것을 염두해 두고 개발을 해야지 오류를 피할수 있습니다.

그럼 내가만든 layout xml 을 TabActivity 에 띄우는 예제를 만들어 보겠습니다.

먼저 layout 을 구성합니다 파일이름은 main.xml 입니다.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:text="@+id/TextView01"
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button android:text="@+id/Button01"
android:id="@+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>

이것을 TabActivity 에 띄우는 java 코드는 아래와 같습니다.

package net.cranix.android.testtabactivity;

import android.app.TabActivity;
import android.os.Bundle;
import android.widget.TabHost;

public class TestTabActivity extends TabActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
final TabHost tabHost = getTabHost();

getLayoutInflater().inflate(R.layout.main, tabHost.getTabContentView());

tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator("tab1").setContent(R.id.TextView01));
tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator("tab2").setContent(R.id.Button01));
}
}
TabSpec.setContent 에 view 를 지정하려면 반드시 @”android:id/tabcontent” 의 하위 뷰 여야 합니다.
그래서 자신이 만든 layout 을 기존에 있던 tabHost 의 tabContentView 에 inflate 를 활용하여 붙혀주는 것 입니다.

위의 굵은 글씨에 의해 inflat 가 실행된 이후에는 layout 을 아래와 같이 인식합니다.

<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TabWidget android:id="@android:id/tabs"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_weight="0" />
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1">
<TextView android:text="@+id/TextView01"
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button android:text="@+id/Button01"
android:id="@+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
</LinearLayout>
</TabHost>

결국 위와 같이 tabSpec 을 만들때 setContent 에다가 자신이 만든 layout 을 사용할 수 있게 되는것 입니다.

이렇게 TabActivity 가 돌아가는 구조를 알아내면 응용도 가능합니다.

아래 예제는 안드로이드 TabUI 에서 TabWidget 이 아래에 있도록 구성한 Activity 입니다.

먼저 layout 파일은 아래와같이 구성합니다.

<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1">
<TextView android:text="@+id/TextView01"
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button android:text="@+id/Button01"
android:id="@+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
<TabWidget android:id="@android:id/tabs"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_weight="0" />
</LinearLayout>
</TabHost>

그다음 Activity 파일은 아래와 같이 구성합니다.

package net.cranix.android.testtabactivity;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TabHost;

public class TestTabActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TabHost tabHost = (TabHost) findViewById(R.id.tabhost);
tabHost.setup();

tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator("tab1").setContent(R.id.TextView01));
tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator("tab2").setContent(R.id.Button01));
}
}

실행해 보면 아래와 같이 탭이 아래에 있는것을 볼 수 있습니다.

사용자 삽입 이미지

여기서 중요한 것은 TabActivity 가 아니라 그냥 Activity 를 이용하였다는 것과 레이아웃 파일을 안드로이드 TabUI 에 맞게 직접 구성했다는점 입니다.

이렇게 TabActivity 를 통하지 않고 Tab 을 구현할 경우에는 반드시 tabHost.setup() 을 호출해 주어야 합니다.

여기서 TabHost view 하위에 있는 기본 뷰를 탐색해서 셋팅해 주게 됩니다.

즉 이 함수를 거치면 tabHost.getTabWidget() 과 tabHost.getTabContentView() 같은 메소드를 사용할때 null 이 반환되지 않게 됩니다.

결국 안드로이드 TabUI 는 기본적인 안드로이드 UI 구조를 가지고 TabUI 를 구성하기 편하게 상속하여 재작성 한 것입니다.




2011/12/06 11:22 2011/12/06 11:22

* 안드로이드을빨리이해하기위한방법

1. OpenSource활용

- http://code.google.com/hosting/

- http://google.com/codesearch

2. Reverse Engineering 활용하여 학습하기

- 자바 클래스 리버싱

사용자 삽입 이미지

- 안드로이드 실행파일 구조와 리버싱

사용자 삽입 이미지

사용자 삽입 이미지

* APK파일 디컴파일(Decompile)하는 방법

1. 디컴파일을 위한 툴 설치

1.ApkTool

- 다운로드 : http://code.google.com/p/android-apktool/downloads/list

사용자 삽입 이미지

- 압축풀기 : android-sdk가 설치된 platform-tools디렉토리안에 apktool디렉토리를 만들어 압축을 푼다.

apktool1.4.1.tar.bz2

apktool-install-windows-r04-brut1.tar.bz2

사용자 삽입 이미지

2.Dex2Jar

- 다운로드 : http://code.google.com/p/dex2jar/downloads/list

사용자 삽입 이미지


- 압축풀기 : android-sdk가 설치된 platform-tools디렉토리안에 dex2jar디렉토리를 만들어 압축을 푼다.

dex2jar-0.0.7.10-SNAPSHOT.zip

사용자 삽입 이미지

3.Java Decompiler

- 다운로드 : http://java.decompiler.free.fr/?q=jdgui

사용자 삽입 이미지

- 압축풀기 : 실행하기 편한 곳에 압축을 풀어 놓는다.

2. 환경변수 잡기

- adb, apktool, dex2jar 명령어를 사용하기 위한 환경변수를 잡는다.

%ANDROID_SDK%\platform-tools

%ANDROID_SDK%\platform-tools\apktool

%ANDROID_SDK%\platform-tools\dex2jar

 

사용자 삽입 이미지사용자 삽입 이미지

3. apk 파일 추출

- 폰에 설치된 모든 패키리를 리스트로 보인다.

사용자 삽입 이미지

- 리스트 중에 디컴파일 할 APK파일을 정한다.

사용자 삽입 이미지

- APK파일을 추출한다. (adb shell을 종료 후 수행한다.)

사용자 삽입 이미지

4. ApkTool 실행 (java파일 외 xml, image, db등을 추출할 수 있다.)

- apktool 명령어를 사용하여 apk파일에 있는 파일을 디코딩하여 out폴더에 내보낸다.

사용자 삽입 이미지

사용자 삽입 이미지

- xml파일을 열어 내용을 확인한다.

사용자 삽입 이미지

5. Dex2Jar 실행 (Java파일을 추출할 수 있다.)

- apk파일의 확장자를 zip으로 변경한다.

사용자 삽입 이미지

- 추출한 zip파일의 압축을 풀어 classes.dex 파일을 추출한다.

사용자 삽입 이미지

- Dex2Jar를 실행한다.

사용자 삽입 이미지

- Dex2Jar를 실행하면 아래 jar파일이 생긴다.

사용자 삽입 이미지

6. JD-GDI 실행

- JD-GDI실행하여 classes.dex.dex2jar파일을 열어 소스를 분석한다.

사용자 삽입 이미지

7. Enterprise Architect를 이용하여 클래스 다이어그램으로 분석한다.

- 다운로드 : http://www.sparxsystems.com.au/products/ea/trial.html

사용자 삽입 이미지

- 설치

사용자 삽입 이미지

- 실행

사용자 삽입 이미지

- Java Decompiler에서 open할 파일을 추출한다.

사용자 삽입 이미지

- zip파일을 압축을 푼다.

사용자 삽입 이미지

- Enterprise Architect에서 classes.dex.dex2jar.src디렉토리를 import 한다.

사용자 삽입 이미지

- 클래스 다이어그램을 보고 분석한다.

사용자 삽입 이미지

-----------------------------------------------------------------------------------------------------------------------

제 11회 한국자바개발자 컨퍼런스에서 트랙1, 3번째 세션에서 Reverse Engineering, 안드로이드 학습이란 주제로 발표를 진행합니다.

리버싱이 무엇인지, 안드로이드 리버싱을 통해서 어떻게 학습을 할 수 있는지 다양한 도구와 팁들을 소개합니다.

학습을 목적으로 리버스엔지니어링이 허용되지만 기술을 복제 유혹을 받을 수도 있습니다.

법적이나, 윤리적으로 문제가 된다는 것을 명심하고, 공부한 내용을 서로 공유하며 미소 지을 수 있는 개발문화가 되길 바래봅니다. :D

발표자료와 함께 사용된 동영상 공유합니다.

발표자료 : Reverse Engineering, 안드로이드 학습

자바 클래스 리버싱

안드로이드 실행파일 구조와 리버싱

Reverse Engineering 활용한 학습 예제

  1. 분석할 앱선정과 APK 파일 추출
  2. 디컴파일 후 분석
  3. 클래스 다이어그램으로 - Enterprise Architect
  4. 의존성 검사를 통해 쉽게 - xDepend



2011/12/06 11:18 2011/12/06 11:18