2013년 4월 25일 목요일

[Android] APK Decompile (APK 추출)

안드로이드 앱을 보다보면 어떻게 만들었는지 궁금 할 때가 있을 겁니다. 이럴때 Apk Decompile을 통해서 전체적인 코드를 확인 하실 수가 있습니다. Apk Decompile이 가능하다고 악용하시지 마시고요 자기발전을 통한 재능기부로 이여졌으면 합니다. 참고로 Apk Decompile은 Mac, Window, Linux 에 따라 JD-GUI만 OS별로 설치하시면 나머지는 똑같습니다.

Apk Decompile을 하긴 위한 전체적인 프로세스
Apk Decompile을 하기 위해서는 우선 Apk 파일이 필요하겠습니다. Apk 파일을 추출 하는 방법은 여러 방법이 있으나 저는 Es File Explorer 앱을 이용하여 Apk 파일을 추출하는 방법을 소개시켜 드리겠습니다.(Astro, ApkManager,ApkTool 등등.. Apk  파일을 추출하는 방법은 많이 있습니다.) Apk 파일 추출 후 Apk 파일를 압축파일로 변환하고 압축을 풀어 dex2jar를 이용하여 classes.dex 파일을 jar로 만들어면 JD-GUI를 통해 보실 수가 있습니다. XML은 바이너리 코드로 보여지므로 AXMLPrinter2.jar를 통한 XML  코드 변환까지 포스팅 하겠습니다.

간단히 순서를 요약해 보면..
  1. APK 파일 추출
  2. APK 파일을 zip으로 변환 후 압축풀기
  3. dex2jar를 이용해 classes.dex를 jar로 변환(dex2jar 다운받기)
  4. JD-GUI 툴을 통해 java 소스보기(JD-GUI 다운받기기)
  5. AXMLPrinter2.jar를 통해 XML 보기 (AMLPrinter2.jar 다운받기)
APK 추출

Google Play에서 Es File Explorer를 다운로드 받습니다. Astro에서도 가능 합니다만 제가 Es File Explorer를 사용하고 있는 관계로 Es File Explorer로 설명 드리겠습니다. 사실 Apk 파일을 추출하는 용도로 사용 할 것이기 때문에 다른 방법으로 Apk 파일을 추출하실 수 있는 분이시나 이미 Apk 파일이 있으신 분들은 굳이 다운로드 받지 않아도 상관없습니다. Es File Explorer의 Backup기능을 이용 하여 Apk 파일을 추출 해야 되나 최근에  Es File Explorer의 업데이트로 인해 UI 변경이 있어으니 Backup 기능을 사용 하실 줄 모르시면 아래 글을 참조하면 됩니다.


Es File Explorer 앱을 실행 시킨 후 메뉴를 클릭하시면 Facebook 메뉴처럼 이동하면서 그림과 같은 화면이 나타납니다. 메뉴 화면에서 Tools을 클릭하시고 App Manager를 클릭하시면 디바이스에 설치되어있는 앱들이 나타나게 됩니다. 그중 Decompile을 하고 싶은 앱을 Long Click을 하시면 앱이 선택되면서 하단 메뉴도 바뀝니다. 그중에 Backup 메뉴를 클릭하시면 Apk 파일이 자동으로 저장됩니다. 저장된 Apk 파일은 backups 폴더에 자동으로 저장되어 집니다. 이제 저장된 폴더를 작업하시고자 하시는 컴퓨터로 가지고 오시면 됩니다.
  1. Es File Explorer 다운
  2. Fast Access 버튼 클릭 (실행하자마자 왼쪽 상단버튼, 그림으로는 녹색화면 화면)
  3. Tools  클릭
  4. App Manager 클릭
  5. Apk 파일을 추출하고 하는 App Long Click
  6. 하단 Backup 버튼 클릭
Apk 파일을 컴퓨터로 가지고 오셨으면 이제 Apk 파일을 zip으로 변경해 주셔야됩니다. 변경방법은 확장자를 .zip으로 바꿔주시면 됩니다. app.apk 을 app.zip으로 바꿔주시면 zip파일로 변환 되며 바로 압축을 풀어 줍니다.

dex2jar사용하기

다운받은 dex2jar의 압축을 풉니다. 이번 단계에서 풀어놓았던 Apk 파일의 압축파일을 푼 폴더를 보면  src 폴더가 보이지가 않습니다. XML 파일은 다 바이너리 코드로 보일 거구요. 이제부터 하나하나 Decompile를 해보도록 하겠습니다.
터미널을 여시고 다운 받은 dex2jar 폴더로 이동하셔서 아래의 명령어를 입력합니다. 참고로 저는 Mac에서 Decompile 를 하고 있어서 경로를 Mac 경로를 입력하였습니다. Window에서는 Window 경로를 입력해 주시면 됩니다.아래 경로는 classes.dex의 경로 이니 OS에 맞게 경로를 입력해 주시면 됩니다. 아래 명령어를 실행시키면 그림 처럼 해당 폴더에 classes_dex2jar.jar파일이 생성된걸 볼 수 있습니다. 이제 JD-GUI를 이용하여 .java파일을 보시기만 하면 됩니다.

sh [dex2jar.sh 경로] [classes.dex파일 경로]

sh dex2jar.sh /Users/Downloads/appFolder/classes.dex


JD-GUI 사용하기

위의 주소로 들어가면 그림과 같은 화면이 나옵니다.

여기서 해당 OS에 맞는 JD-GUI를 다운로드 받으시면 됩니다. 저는 이것도 모르고 Mac에서는 다른 특별한 방법이 있는 줄 알고 한참 구글링 했었습니다. 하지만 별거 없었습니다. 그냥  JD-GUI 툴만 OS별로 다운 로드 받아서 보시면 됩니다. 그러니 Mac이나 Linux를 사용하시는 분들도 JD-GUI만 작업하시는 OS버전으로 다운 받아서 보면 됩니다. 저는 Mac을 사용하니 Mac 버전을 다운 받았습니다.
JD-GUI을 실행 시키고 classes_dex2jar.jar를 open 하시면 앱의 package부터 .java 파일 까지 전부 확인 하 실 수 있습니다. 이제 마지막으로 xml을 복구해 보도록 하겠습니다.


AXMLPrinter2.jar 사용하기

위의 주소에서 AXMLPrinter2.jar를 다운받은 후 터미널에서 AXMLPrinter2.jar가 있는 경로로 들어가 줍니다. 그후 아래와 같이 입력하시면 xml이 보여집니다.

java -jar [AXMLPrinter2.jar] [xml 파일 위치] > [변환 될 파일 위치]

java -jar AXMLPrinter2.jar /Users/aaaaa/Downloads/call_in.xml > /Users/aaaaa/Downloads/asdfg/call_in.xml

변환 될 파일위치로 가셔서 확인해 보시면 바이너리 코드로 있어던 xml 파일이 변환되어 보입니다. 완벽하게 변환 되는것은 아니면 값들은 코드값으로 보여지게 됩니다.

2013년 4월 24일 수요일

[Android] Action Bar Usage (Action Bar 사용방법 예제)

ActionBar 사용방법에 대한 예제가 Open Source에 있어서 포스팅 하려고 합니다. 소스에 특별한 내용은 없으나 우리가 Action Bar를 사용 할 때 생각해야 될 부분 중에 하나인 작은 화면에서의 Action Bar의 item을 효율에 관한 소스라고 생각 되어 포스팅 합니다. Action Bar내용이 아닌 소스 내용은 주석을 참고 해서 보시면 됩니다.  Open Source 클래스 중 ActionBarUsage클래스 내용입니다.

<menu xmlns:android=”http://schemas.android.com/apk/res/android”>
    <item android:id=”@+id/action_search”
          android:icon=”@android:drawable/ic_menu_search”
          android:title=”@string/action_bar_search”
          android:showAsAction=”ifRoom”
          android:actionViewClass=”android.widget.SearchView” />
    <item android:id=”@+id/action_add”
          android:icon=”@android:drawable/ic_menu_add”
          android:title=”@string/action_bar_add” 
          android:showAsAction=”collapseActionView”/>
    <item android:id=”@+id/action_edit”
          android:icon=”@android:drawable/ic_menu_edit”
          android:showAsAction=”always”
          android:title=”@string/action_bar_edit” />
    <item android:id=”@+id/action_share”
          android:icon=”@android:drawable/ic_menu_share”
          android:title=”@string/action_bar_share”
          android:showAsAction=”ifRoom” />
    <item android:id=”@+id/action_sort”
          android:icon=”@android:drawable/ic_menu_sort_by_size”
          android:title=”@string/action_bar_sort”
          android:showAsAction=”ifRoom”>
        <menu>
            <item android:id=”@+id/action_sort_size”
                  android:icon=”@android:drawable/ic_menu_sort_by_size”
                  android:title=”@string/action_bar_sort_size”
                  android:onClick=”onSort” />
            <item android:id=”@+id/action_sort_alpha”
                  android:icon=”@android:drawable/ic_menu_sort_alphabetically”
                  android:title=”@string/action_bar_sort_alpha”
                  android:onClick=”onSort” />
        </menu>
    </item>
</menu>
SearchView를 사용 하기 위해서 android:actionViewClass를 사용 하여 Android에서 제공하고 있는 android.widget.SearchView 경로를 사용한 것을 확인 할 수 있습니다. SearchViw는 ShareActionProvider와 마찬가지로 Android에서 제공하고 있는 클래스를 가져다가 사용만 하면 됩니다. android:showAsAction의 값이 "ifRoom"으로 설정하면 item들이 순차적으로 Action Bar에 보이다가 공간이 부족하면 Menu 버튼을 클릭해야지 보이는걸 확인 할 수 있습니다.
id가 action_sort인 item은 서브 메뉴 아이템을 가지고 있는것을 보실 수 있습니다.

public class ActionBarUsage extends Activity implements OnQueryTextListener {
 private static final String TAG = "ActionBar_Api_Usage";
 
 private TextView mSearchText;
 private int mSortMode = -1;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  mSearchText = new TextView(this);
  setContentView(mSearchText);
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // TODO Auto-generated method stub
  MenuInflater inflater = getMenuInflater();
  inflater.inflate(R.menu.actions, menu);
  
//  Action Bar에서 SearchView를 보여주고 싶을때 사용하는 클래스입니다.
  SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
  searchView.setOnQueryTextListener(this);
  return true; 
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  // TODO Auto-generated method stub
   Toast.makeText(this, "Selected Item: " + item.getTitle(), 
     Toast.LENGTH_SHORT).show();
  return true;
 }
 
// Menu의 sort item에서 android:onClick="onSort" 기능으로 호출한다.
    public void onSort(MenuItem item) {
        mSortMode = item.getItemId();
        // onPrepareOptionMenu를 호출 할 수 있어서 sort icon을 바꿀 수 있다.
        invalidateOptionsMenu();
    }
 
//  invalidateOptionsMenu()메서드를 실행하면 호출된다.
 @Override
 public boolean onPrepareOptionsMenu(Menu menu) {
  // TODO Auto-generated method stub
  if (mSortMode != -1) {
   Drawable icon = menu.findItem(mSortMode).getIcon();
   menu.findItem(R.id.action_sort).setIcon(icon);
  }
  return super.onPrepareOptionsMenu(menu);
 }

// SearchView에 텍스트를 입력하면 TextView에 바로 적용된다.
 @Override
 public boolean onQueryTextChange(String newText) {
  // TODO Auto-generated method stub
  newText = newText.isEmpty() ? "" : "Query so far : " + newText;
  mSearchText.setText(newText);
  return false;
 }

// Submit을 누르면 onQueryTextSubmit 메소드가 호출된다.
 @Override
 public boolean onQueryTextSubmit(String query) {
  // TODO Auto-generated method stub
  Toast.makeText(this, "Searching for: " + query + "...", 
    Toast.LENGTH_SHORT).show();
  return true;
 }
}


참조

[Android] Action Bar ShareActionProvider( 공유 )

ShareActionProvider 

ShareActionProvider는 공유를 위한 Provider입니다. 데이터를 공유할수 있고, 만약 overflow 메뉴에 배치된다면 서브 메뉴에서 공유 activity들을 보여 줍니다.
ShareActionProvider는 ActionProvider를 상속 받고 있는 클래스 이며, Action Bar에서 공유하는 기능을 담당하고, 간단하게 공유를 사용 할 수 있게 해줍니다.

이번 포스팅에서는 Open Source 중 ActionBarShareActionProviderActivity에 대해 살펴 볼려고 합니다.
<menu xmlns:android=”http://schemas.android.com/apk/res/android”>
    <item android:id=”@+id/menu_item_share_action_provider_action_bar”
        android:showAsAction=”always”
        android:title=”@string/btn_api_provider_share”
        android:actionProviderClass=”android.widget.ShareActionProvider” />

    <item android:id=”@+id/menu_item_share_action_provider_overflow”
        android:showAsAction=”never”
        android:title=”@string/btn_api_provider_share”
        android:actionProviderClass=”android.widget.ShareActionProvider” />
</menu>

이전 포스팅한 Action Bar ActionProvider와 같은 구조로 되어 있습니다. 다만 한가지 차이점은 ActionProvider를 사용하기 위해 설정해 줘야 했던 android:actionProviderClass의 경로가 안드로이드에서 기본으로 제공하고 있는 android.widget.ShareActionProvider로 설정해야 됩니다. 당연한 말이지만 android.widget.ShareActionProvider는 ShareActionProvider의 경로 입니다. Action Bar ActionProvider포스팅에서는 직접 ActionProvider를 상속받아 구현한 클래스가 있었으므로 ActionProvider를 상속받은 클래스의 경로를 사용 했었습니다. 상단 item 의 android:showAsAction 값은 "always"이며 하단 item의 android:showAsAction 값은 "never"입니다. "always"는 항상 ActionBar에 보여진다는 뜻이며 "never" Action Bar에 보여지지 않는다는 뜻입니다.
public class ActionBarShareActionProviderActivity extends Activity {
 private static final String TAG = "ActionBar_Api_Provider_Share";
 private static final String SHARED_FILE_NAME = "shared.png";

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  copyPrivateRawResuorceToPubliclyAccessibleFile();
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // TODO Auto-generated method stub
  getMenuInflater().inflate(R.menu.action_bar_share_action_provider, menu);
  
  MenuItem actionitem = menu.findItem(R.id.menu_item_share_action_provider_action_bar);
  ShareActionProvider actionProvider = (ShareActionProvider) actionitem.getActionProvider();
  actionProvider.setShareHistoryFileName(ShareActionProvider.DEFAULT_SHARE_HISTORY_FILE_NAME);
  actionProvider.setShareIntent(createShareIntent());
  
  MenuItem overflowItem = menu.findItem(R.id.menu_item_share_action_provider_overflow);
  ShareActionProvider overflowprovider = (ShareActionProvider) overflowItem.getActionProvider();
  overflowprovider.setShareHistoryFileName(ShareActionProvider.DEFAULT_SHARE_HISTORY_FILE_NAME);
  overflowprovider.setShareIntent(createShareIntent());
  return true;
 }

 private Intent createShareIntent() {
  Intent shareIntent = new Intent(Intent.ACTION_SEND);
  shareIntent.setType("image/*");
  Uri uri = Uri.fromFile(getFileStreamPath("shared.png"));
  shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
  return shareIntent;
 }

 private void copyPrivateRawResuorceToPubliclyAccessibleFile() {
  InputStream is = null;
  OutputStream os = null;
  try {
   is = getResources().openRawResource(R.raw.robot);
   os = openFileOutput(SHARED_FILE_NAME, Context.MODE_APPEND);
   byte[] buffer = new byte[1024];
   int length = 0;
   while ((length = is.read(buffer)) > 0) {
    os.write(buffer, 0, length);
   }
  } catch (Exception e) {
   // TODO: handle exception
   Log.e(TAG, "Exception : " + e);
  } finally {
   try {
    is.close();
    os.close();
   } catch (Exception e2) {
    // TODO: handle exception
    Log.e(TAG, "Exception : " + e2);
   }
  }
 }
}
copyPrivateRawResuorceToPubliclyAccessibleFile() 메서드는 raw 폴더안의 robot.png 파일을 device안에 저장하는 간단한 소스 입니다.
ShareActionProvider를 사용 할때는 onCreateOptionsMenu(Menu menu)에서 이미 ActionProvider를 상속받고 있는 ShareActionProvider 클래스를 사용하면 됩니다.
MenuItem으로 가져온 Menu의 item을 ShareActionProvider로 가져온 후 setShareHistoryFileName(ShareActionProvider.DEFAULT_SHARE_HISTORY_FILE_NAME);를 통해 공유 기록을 저장할 파일 이름을 설정하고 setShareIntent로 공유 할 앱들을 설정한 후 호출하면 된다.(DEFAULT_SHARE_HISTORY_FILE_NAME가 기본)


참조

2013년 4월 23일 화요일

[Android] Action Bar ActionProvider

ActionProvider

ActionProvider는 하나의 component 안에서 다양한 메뉴의 상호작용을 의미한다. ActionProvider는 Action Bar에서 사용 할 수 있는 Action View를 생성하며, MenuItem에 서브메뉴를 동적으로 채운다. 그리고 기본 메뉴의 아이템을 처리합니다. ActionProvider는 MenuItem만을 위한 옵션을 설정할 수도 있으며, 간단한 버튼을 표시할때는 Action View를 만들어 표시 할 것이다.

ActionProvider는 추상 메서드로서 필요한 메서드를 Override해서 사용 할 수 있습니다. API Level 16부터 onCreateActionView()는 deprecated 되었으며 onCreateActionView(MenuItem forItem)이 추가 되었습니다. onCreateActionView() 메서드를 사용 하려면 android:targetSdkVersion을 16미만으로 적용 하시면 됩니다. onCreateActionView(MenuItem forItem)에서 MenuItem이 매개변수로 추가된 이유는 MenuItem을 재정의 할 수 있게 할려고 한게 아닌가 싶습니다. onCreateOptionsMenu(Menu menu)에서 정의된 Menu를 사용 할 수도 있겠지만 MenuItem만을 위한 재정의를 할 수 있게 추가 된게 아닐까 생각합니다. targetSdkVersion만 맞춰준다면 현재로서는 어떤 메서드를 사용하든지 상관 없으나 이왕이면 deprecated된 메서드 보다는 새로 추가 된 메서드를 사용 하시는걸 추천 합니다.

이번 포스팅에서는 Open Source 중 ActionBarSettingsActionProviderActivity에 대해 살펴 볼려고 합니다.
<?xml version=”1.0” encoding=”utf-8”?>
<menu xmlns:android=”http://schemas.android.com/apk/res/android”>

    <item android:id=”@+id/menu_item_action_provider_action_bar”
        android:showAsAction=”ifRoom”
        android:title=”@string/btn_api_provider_setting”
        android:actionProviderClass=”com.example.wawoops_test_actionbar.ActionBar_Api_Provider_Setting$SettingActionProvider”/>

    <item android:id=”@+id/menu_item_action_provider_overflow”
        android:showAsAction=”never”
        android:title=”@string/btn_api_provider_setting”
        android:actionProviderClass=”com.example.wawoops_test_actionbar.ActionBar_Api_Provider_Setting$SettingActionProvider”/>
</menu>
Menu를 보면 item이 2개인 것을 보실 수 있습니다. 여기서 주의깊에 봐야 할 부분은 android:showAsAciton부분입니다. 첫번째 item은 "ifRoom"으로 되어있고 두번째 item은 "never"로 되어있습니다. 첫번째 item은 만약 ActionBar에 공간이 있다면 표시하라는 뜻이며 두번째  item의 "never"는 overflow 영역으로 무조건 빼라는 뜻입니다. 즉 화면서 바로 보지 않겠다는 뜻입니다.
android:actionProviderClass를 설정하면 ActionProvider를 사용 할 수 있습니다. ActionProvider를 extends 하고 있는 클래스 경로명을 적어주면 되며, setActionProvider(ActionProvider)를 사용하여 자바코드에서도 설정해 줄 수 있습니다. 만약 공간이 부족해서 Overflow부분으로 빠진다면 텍스트가 보여져야 되므로 이왕이면 Title은 각 item마다 설정해 주는게 좋습니다.

public class ActionBarSettingsActionProviderActivity extends Activity {

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // TODO Auto-generated method stub
  getMenuInflater().inflate(R.menu.action_bar_settings_action_provider, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  // TODO Auto-generated method stub
  Toast.makeText(this, "선택된 버튼의 타이틀 : " + item.getTitle(), Toast.LENGTH_SHORT).show();
  return true;
 }
 
 public static class SettingActionProvider extends ActionProvider{
  private static final String TAG = "SettingActionProvider";
  private final Context mContext;
  private final Intent sSettingsIntent = new Intent(Settings.ACTION_SETTINGS);
  public SettingActionProvider(Context context) {
   super(context);
   // TODO Auto-generated constructor stub
   mContext = context;
  }

  @Override
  public View onCreateActionView(MenuItem forItem) {
   // TODO Auto-generated method stub
//   actionBar 영역에 들어가는 itme을 재정의 해 줄 수 있다. 
//   메뉴 버튼과 actionBar의 버튼을 서로 다르게 정의 할 수 있다.
//   forItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
   LayoutInflater layoutInflater = LayoutInflater.from(mContext);
   View view = layoutInflater.inflate(R.layout.action_bar_settings_action_provider, null);
   ImageButton button = (ImageButton) view.findViewById(R.id.button);
   button.setOnClickListener(new View.OnClickListener() {
    
    @Override
    public void onClick(View v) {
     // TODO Auto-generated method stub
     mContext.startActivity(sSettingsIntent);
    }
   });
   return view;
  }

  @Override
  @Deprecated
  public View onCreateActionView() {
   // TODO Auto-generated method stub
   return null;
  }

  @Override
  public boolean onPerformDefaultAction() {
   // TODO Auto-generated method stub
   Log.e(TAG, "onPerformDefaultAction()");
   mContext.startActivity(sSettingsIntent);
   return true;
  }
 }
}
onCreateOptionsMenu(Menu menu)에서  Menu를 inflate 해주면 Menu 버튼과 Action Bar 두곳 모두에서 사용 할 수가 있습니다. 이전 포스팅한 글에서 Menu는 Menu 버튼을 클릭하면 나타나는 것이고 MenuItem은 Action Bar에서 나타난다고 말했습니다. ActionProvider가 onCreateOptionsMenu(Menu menu)에서 inflate되는 Menu를 MenuItem에 추가 하는 기능을 합니다. 만약 onOptionsItemSelected(MenuItem item)가 호출 되지 않았다면 ActionProvider의 onPerformDefaultAction()이 호출 되었을 겁니다.  onPerformDefaultAction()은 Overflow 영역에 있을때 호출되며 이 메서드가 호출되면 onOptionsItemSelected(MenuItem item)은 호출 되지 않습니다.

소스에서는 onCreateActionView(MenuItem forItem)에서 inflate해준 view에 클릭 이벤트를  줬습니다. 이 결과 onPerformDefaultAction()와  onOptionsItemSelected(MenuItem item)가 호출 되지 않았으며 바로 onClick(View v)메서드가 호출되는 것을 확인 하였습니다. 간단하게 onCreateActionView(MenuItem forItem)메서드에서 만들어 놓은 레이아웃을 inflate 해주고 바로 이벤트를 걸어 사용 하면 되지 않을까 생각됩니다. onCreateActionView(MenuItem forItem)에서 버튼 하나를 만들어서 붙여 본 결과  onCreateOptionsMenu(Menu menu)에서 추가된 item 개수만큼 버튼이 생기는걸 확인 할 수 있었습니다.(물론 Action Bar에서 보여 질수 있는 item에 한해서 말하는 것입니다.)


참조

2013년 4월 21일 일요일

[Android] Action Bar Mechanics

Android에서는 고맙게도 Open Source를 제공해 주고 있습니다.
Android의 어떤 기능을 배우고 싶을때 Open Source를 보고 분석하는 것 보다 더 좋은 방법은 없다고 생각합니다.
Action Bar 역시 Open Source를 분석하면서 습득하는게 가장 확실한 방법이 아닐까 생각합니다. Open Source에서 ActionBar의 예제는 총 6가지 입니다. 각각의 클래스 이름은ActionBarDisplayOptions, ActionBarMechanics, ActionBarSettingsActionProviderActivity, ActionBarShareActionProviderActivity, ActionBarTab, ActionBarUsage 입니다. 이 중 블로그 제목처럼 ActionBarMechanics에 대해 작성해 보겠습니다. ActionBarMechanics  클래스는 이름처럼 ActionBar를 구현하기 위한 기본 구조를 설명하는 클래스입니다.

public class ActionBar_Api_Mechanics extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // TODO Auto-generated method stub
//  Menu 버튼
  menu.add("Normal item");
  
//  Action Bar  버튼
  MenuItem actionItem = menu.add("Action Button");
  actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
  actionItem.setShowAsAction(android.R.drawable.ic_menu_share);
  return true;
 
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  // TODO Auto-generated method stub
  Toast.makeText(this, "Selected Item : " + item.getTitle(), Toast.LENGTH_SHORT).show();
  return true;
 }
}

Action Bar를 설정하기 위해서는 Content View를 Setting하기전에 getWindow().requestFeature(Window.FEATURE_ACTION_BAR)를 설정해 줘야 됩니다. 그러나 보통 Activity의 테마가 기본으로 적용하고 있어서 위와 같이 getWindow().requestFeature(Window.FEATURE_ACTION_BAR)를 적용하지 않고도 Action Bar를 사용 할 수 있습니다. 물론 Theme.NoTitleBar를 적용하여 Action Bar영역을 사라지게 할 수 도 있습니다.

Action Bar에 기능을 추가 하는 방법은 Menu버튼을 사용 할 때와 크게 다르지 않습니다.
onCreateOptionMenu(Menu menu)에서 Menu를 추가해주고 onOptionsItemSelected(MenuItem item)에서 추가해준 Component의 이벤트를 받아서 처리해 주면 됩니다. 한가지 차이점은 ActionBar에 추가되는 Component는 MenuItem 클래스 추가해 줘야 된다는 점입니다. 위의 Source를 실행해 보면 Menu 버튼을 클릭하면 "Normal item"이 출력이 되며, Action Bar에 있는 Share 버튼을 클릭하면 "Action Bar"가 Toast에 출력 됩니다. 만약 Theme.NoTitleBar를 적용해 주면 Menu 버튼을 클릭했을때 "Normal item" 과 "Action Bar"가 Menu 버튼에 표시 되게 됩니다.
Action Bar에 많은 Item를 추가해 주면 Overflow 영역으로 빠지게 됩니다. setShowAsAction() method를 이용하여 Action Bar에서 item의 보여지는 방법을 설정 할 수 있습니다. 위의 Source 에서 설정한 SHOW_AS_ATION_IF_ROOM은 ActionBar의 공간이 있으면 item의 icon만으로 Action Bar에 나타나도록 합니다.

Constants
intSHOW_AS_ACTION_ALWAYSAlways show this item as a button in an Action Bar.
intSHOW_AS_ACTION_COLLAPSE_ACTION_VIEWThis item's action view collapses to a normal menu item.
intSHOW_AS_ACTION_IF_ROOMShow this item as a button in an Action Bar if the system decides there is room for it.
intSHOW_AS_ACTION_NEVERNever show this item as a button in an Action Bar.
intSHOW_AS_ACTION_WITH_TEXTWhen this item is in the action bar, always show it with a text label even if it also has an icon specified.


참조

2013년 4월 18일 목요일

[Android] 이제 Action Bar 사용은 선택이 아닌 필수.


ActionBar는 Android 3.0(API Level 11)부터 추가되었으며 사용 할 때는 Manifest에서 targetSdkVersion 이나 minSdkVersion을 11로 맞춰줘야 되며, Theme.Holo 테마를 사용하여야 됩니다.(Theme.Holo가 Default  테마입니다.)

Android 3.0 이전에는 Title Bar에서 단순 Application의 이름정도만 보여주는게 전부 였으나 Android 3.0 부터는 Action Bar라는 놈이 추가되어서 Application의 이름 뿐만 아니라, 사용자가 보고 있는 화면의 위치, Navigation Button, Tab, Share 등을 빠르게 사용 할 수 있게 되었습니다.
사실 Android 3.0 이전부터 우리는 Action Bar의 기능을 전부 사용하고 있었습니다.
초창기 아이폰 App들의 UI를 벤치마킹 하여 디자인했기 때문에 안드로이드에는 back버튼이 있음에도 불구하고 상단에 back 버튼은 안드로이드 App에서도 흔히 볼 수 있었습니다.(물론 ActionBar의 Navigation Button과 back Button은 기능적으로 차이가 있습니다.) Back Button 뿐만 아니라 App에서 Home으로 바로 이동 할 수 있는 Button역시 관련 Activity에서 Inflate를 사용하던지 해당 View에 바로 적용하던지 하는 방법으로 사용 했었습니다. 뿐만 아니라 아이폰의 Tab이 아래에 있다는 이유만으로 안드로이드에서도 Tab을 하단에 적용해야 했던 적도 있었습니다.(안드로이드는 아이폰과 달리 하단에 Menu, Home, Back Button 이 있어서 Tab을 잘못 눌러 하단의 기본 Button들을 클릭 하는걸 방지하고자 Tab이 위에 있었던 겁니다.) 우리는 Share Button 역시 만들어서 사용 했었습니다. 그러나!! 이제는 Action Bar를 사용하여 위에 열거했던 모든 기능들을 간편하게 사용 할 수 있게 되었습니다.

안드로이드 개발자 사이트에 있는 Action Bar 이미지입니다. 여기서는 기능별로 4가지로 분류했습니다.


1. App Icon

Action Bar의 좌측에 App의 Icon을 넣을 수 있습니다. Icon을 터치하면 App의 Home으로 보낼 수도 있으며, Back Button과 마찬가지로 Task의 상위단계로 이동하게 만들 수도 있습니다.
ActionBar에서 Home로 이동하게 만들경우는 setHomeButtonEnabled(true);를 사용하여 나타낼수 있으며 Intent.FLAG_ACTIVITY_CLEAR_TOP를 추가해 주는것이 좋습니다. 그렇지 않으면 Back Button을 누를때 엄청난 양의 Task를 목격 하실 수도 있으실 겁니다.
ActionBar에서 Task의 상위 단계로 이동하게 만든다면setDisplayHomeAsUpEnabled(true); 사용하여 나타낼 수 있습니다. 상위단계로 이동하게 만들때의 주의점은 Back 버튼과 동일한 프로세스로 만드는게 아니라 상위 카테고리로 보내게끔 만드는게 더 나을 수도 있다는 점입니다. 예를 들자면 Home -> A -> B -> a -> b 와 같이 화면전환이 이루어 졌다면 (A와 B는 같은 레벨이며 a, b는 A, B의 하위 레벨 입니다.)  b 에서 Back Button을 누르면 a로 이동되나 ActionBar의 Navigation Button은 B로 이동되어져야 된다는 것입니다. Back Button이 있는 안드로이드에서 굳이 똑같은 기능을 하는 버튼을 하나 더 만들어야 되는지 생각해 볼 필요가 있습니다.


Home과 Task의 상위 단계로 보낼때의 Icon 모양은 아래와 같이 차이가 있습니다.강제성이 있는것은 아니나 이런 약속들은 지키는게 좋습니다. 이미지에 나타난 데로 Home으로 가는 버튼에는 " < " 기호가 없으며  상위 Task로 이동하는 버튼에는 " < "기호가 있음을 알 수 있습니다.


2. View control

다른 화면으로 이동 하고 싶을때 위의 이미지 처럼 drop-down 형태로 나타낼 수도 있으면 Tab방식으로 나타낼 수도 있습니다. 만약 화면 전환 메뉴가 필요없으면 해당 위치에 사용자의 위치를 표시 해 줄 수도 있으며, App의 Title를 표시해 놓을 수도 있습니다. 물론 사용자의 위치 와 Tab을 동시에 표시할 수도 있습니다. 

Tab을 사용 할때는 device화면의 크기에 따라 그림과 같이 Tablet 처럼 큰 화면에서의 배치와 작은 화면에서의 배치가 다르게 표현 된다는 걸 알 수 있습니다.



3. Action Button

Action Bar에 버튼을 추가하는 영역입니다. 보통 화면에서 가장 중요한 기능을 한 두가지 넣어주거나 Search 기능이나 Share기능을 추가 할 수도 있습니다. Action Bar에서 사용 할 Icon은 안드로이드 UX팀에 의해 디자인된 Action Icon을 사용하는것을 추천합니다. 만약 Custom 하려고 한다면 Android에서 제안하는 기준에 맞게 디자인 하기를 추천합니다. Action Bar안의 ActionView영역은 사라졌다가 확장되었다가 할 수 있기 때문에 device 화면의 크기에 따라 유동적으로 바뀌게끔 설정해 주면 됩니다. 이런 기능은 device화면이 작을 때 공간 효율을 더욱 좋게 해줍니다. 사용자가 Back Button이나 Navigation Button을 터치하면 확장되었던 화면은 다시 사라지게 되며 MenuItem의 expandActionView()와 colapseActionView()를 이용하여 ActionView를 사용자가 컨트롤 할수 있게 만들 수도 있습니다.

4. Action overflow

ActionBar에 메뉴 버튼이라고 생각하면 됩니다. 자주 사용하지 않은 기능들이나 화면에
넘치는 기능 또는 메뉴버튼으로 사용 되어지고 싶은 기능을 추가하는 영역입니다. Android 3.0이전에는 물리적인 메뉴버튼을 이용하였지만 Android 3.0이후에는 물리적인 메뉴 버튼 대신 Action Bar의 overflow 영역이 생겼습니다. Android 3.0이전의 모든 device에는 메뉴 버튼이 있었으나 Android 3.0 이후 부터는 물리적인 메뉴 버튼이 없는 device도 있습니다.  Android 3.0이전에 옵션메뉴로 개발되어진 App은 targetSdkVersion 이나 minSdkVersion를 11또는 그 이상으로 설정한다면 이전에 설정했던 옵션 기능들은 API 레벨에 근거하여 Action overflow에 추가하지 않습니다. 
보통 메뉴버튼은 해당 Activity의 옵션기능을 설정하였습니다. overflow영역 역시 마찬가지로 해당 Activity나 Fragment의 옵션 기능을 설정하는 영역입니다.



참조


2013년 4월 2일 화요일

[UML] ClassDiagram (클래스 다이어그램)

ClassDiagram을 구체적으로 설명 한다기 보다는 실무에서 쓰는 정도와 개념에 대해 설명 하겠습니다.

ClassDiagram이란?
: 소스코드에 나타나는 클래스 사이의 의존 관계를 표기한 Diagram이다.


Class (클래스)
◆ 일반 클래스

public class Dialer{

}



public class Dialer{
     private Vector digits;
     private int nDigits;
     public void digit(int n);
     protected boolean recordDigit(int n):
}


둘 중 어떤 방식을 사용 해도 상관 없으나 단순 클래스의 연관을 표현 할려고 하면 Class명만 사용하여 연관 관계를 표시하는게 더 직관적이며 눈에 잘 들어 옵니다.

◆ 추상 클래스

public abstract class shape{
     private Point itsAnchorPoint;
     public abstract void draw();
}









추상 클래스는 Class명을 이텔릭체로 쓰거나 {abstract}라고 명시해 주면 됩니다.

  • ClassDiagram 기호 및 구조
    • 기호
      • Class 안의 기호 중에 -, +, # 을 볼 수 있습니다..
        • 대시 (-): private
        • 더하기 (+) : public
        • 해시 (#) : protected
    • 구조
      • 제일 상단은 클래스 이름.
      • 두번째는 변수타입 및 변수명.
      • 세번째는 메소드 타입 및 메소드 명.
◆ 내부 클래스

public class A{
     private class B{
     }
}




◆ 익명 내부 클래스

public Class A{
     public void c(){
          new B().start();
     }
}



◆연관


public class phone{
     private Button itspnos;
}





Phone Class에 Button을 가지고 있다는 표현입니다..
여기서 *는 버튼이 여러개일 수 있다는 의미 이며 * 대신 10, 20 등과 같이 숫자로 표현 할 수 도 있습니다.

◆상속


public class Employee{
   . . .
}





public class SalariedEmployee extends Employee{
   . . .
}
SalariedEmpoloyee Class는 Employee Class를 상속하는 모습입니다.
연관과 상속의 차이점은 화살표 모양입니다. 또한 일반적으로 상속은 위 아래로 표현하며 연관은 좌우로 표현합니다.

interface 표시는 아래 그림 중 하나를 선택해서 표시하면 됩니다.


Class Diagram에는 더 많은 기능과 기호들이 있습니다. UML 전문가가 되려면 이 외에 많은 기능들을 알아야되나 실무에서 사용하는 정도로는 이정도만 알고 있으면 되지 않을까 싶습니다. 사실 이 이상 사용할 일은 거의 없다고 생각됩니다.