2015년 4월 27일 월요일

Eclipse 에서 Project 공유하기(git/share project)


* Git 대박 메뉴얼 : 




* Eclipse 에서 Project 공유하기(git)


#Step 1. 로컬 저장소 셋팅

Eclipse > Team > Share Project > Git > Configure Git Repository (저장소 설정)
1. Use or create repository in parent folder of project 체크
(* Eclipse에서 프로젝트  저장위치와 Git Repository 를 다른  path에 지정하라고하나 그렇게 하면 오류가 난다. )
2. 화면 하단 "Create Repository" 클릭
3. finish
----------------------< Repository설정완료



#Step 2. 원격 저장소 셋팅

1. bitbucket.org : 원격 저정소 생성 
- Create Repository
- 해당 Repository > Overview > Command line  > I have an existsing project  에서 

2. Remote Repository Sync(push)
Eclipse > Team > Add Index > Commit > Push Message  입력 후  > Commit & Push  클릭 

> Destination Git Repository > Location >   위에서 복사한  https:// yourday .... 붙여 넣기  >  finish

Android: onNewIntent

안드로이드는 일반적으로 액티비티에서 액티비티를 호출 할 경우,

onCreate() ->  onStart() -> onResume() 의 순서로 호출이 된다.

그런데 만약 어떤 액티비티에서 자기 자신을 호출하며, 약간의 값만 수정할 경우가 있을 수 있다.

이런 경우 일반 호출 방식으로 하게 되면, 액티비티 스택에는

동일한 액티비티가 중복되어 쌓일 것이다.

자기 자신을 호출하며, 갱신만 할 방법은 없을까?

onNewIntent란 놈이 있다.

이놈은 항상 실행되는 것이 아니고 일정 조건을 갖추었을 때, 자동 호출이 된다.

onNewIntent가 호출되는 조건은 두가지가 있다.



첫째로, 인텐트에 Activity Flag값을 주는것이다.

예)
Intent intent = new Intent(Activity.this,Activity.class);

intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);


두번째 라인에 intent.addFlags(intent.FLAG_ACTIVITY_SINGLE_TOP)를 보자.

인텐트에 flag값을 주는 부분이다.  FLAG_ACTIVITY_SINGLE_TOP 속성은

foreground 상태의 액티비티에서 자신을 호출 할 경우 자기 자신을 재활용 하는 속성값이다.


두번째로, Androidmanifest.xml 에서 속성을 주는 방법이다.

 예)
<activity android:name=".TestActivity" android:launchMode="singleTop">
</activity>



위 코드와 같이 매니페스트 파일에서 액티비티에 launchMode 의 속성을 singleTop으로

준다. singleTop 은 위에서 설명한 FLAG_ACTIVITY_SINGLE_TOP과 같은 속성이다.


2015년 4월 26일 일요일

Design: 5 Best Websites to Download Free Design Source (Free Design Source)


 5 Best Websites to Download Free Icons

:  5 Best Websites to Download Free Design Source



5. http://iconfinder.com



* 무료로 앱디자인이나 웹디자인 소스를 제공하는 사이트는 많으나, 위에 사이트가 괜춘하다. 
특히  freepick.com이 거의 무료 디자인 소스 사이트의 포털인듯하다. 



2015년 4월 24일 금요일

Android : 이클립스 단축키 추가하기 (Eclipse add shourtcut)

이클립스 단축키 추가
(* Eclipse add shortcut)


1. Window > Preference 메뉴를 클릭한다.
2. General > Keys 로 이동한다.


3. Command에서 단축키를 수정할 또는 추가할 명령어를 선택한다. 



4. 화면 하단부 Binding에 원하는 단축키를 누른다.
 [Apply] 버튼 또는 [OK] 버튼을 클릭한다.

(* 단축키를 누를때 오른쪽 Conflicts 란에 기존에 단축키들과 충돌이 일어나는지 확인후 OK버튼을 누른다)

Android Error: Conversion to Dalvik format failed with error 1

Android Project Export Error : Conversion to Dalvik format failed with error 1 



* 해결책 01 : 


Confirmed the problem is caused by ProGuard command line in the file
[Android SDK Installation Directory]\tools\proguard\bin\proguard.bat

Edit the following line will solve the problem:

Edit the following line will solve the problem:

call %java_exe% -jar "%PROGUARD_HOME%"\lib\proguard.jar %*

to

call %java_exe% -jar "%PROGUARD_HOME%"\lib\proguard.jar %1 %2 %3 %4 %5 %6 %7 %8 %9


* 해결책 02 : 


You can solve this issue easily (with Eclipse Android Developer Tools, Build: v22.0.1-685705)
by turn off 
Eclipse > Menu > "Project" > "Build Automatically" 
while exporting (un)signed Android application. After that, don't forget to turn it on again.

Android : enum 열거형 데이터 타입(Handler 활용)

* enum Type은 구조체 대신 사용(Java 구조체가 없다. )


//enum 선언
public enum NetworkState {
     NETWORK_ON, NETWORK_OFF, AUTH_ON, AUTH_OFF
};

private NetworkState[] networkStates = NetworkState.values(); // 배열로 가지고온다.


//핸들러 생성
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
  try {
switch (networkStates[msg.what]) {
case AUTH_ON:

     break;
case AUTH_OFF:

     break;
default:
     break;
}
} catch (Exception e) {

}

       } //end method__

}; //end handler

//sendMessage
Message msg = mHandler.obtainMessage(NetworkState.AUTH_ON.ordinal(), 0, 0);
mHandler.sendMessage(msg);



* enum Data Type 설명 : 

enum은 데이터 타입 정의 해서 필요한 값만 사용 할 수 있게 사용하기 딱 좋은 데이터 형이다.
예를 든다면 통신사 타입을 사용 하는 변수가 필요하다 하자.

보통은 문자열 또는 정수형으로 "SKT", "KT"... 또는 "1" - SKT, "2" - KT 등으로 상호간 약속을 하고 이 테이더 를 사용하게 된다.
이 약속을 잘 지킬 경우 문제가 없어지지만 그렇지 않을 경우 에러가 발생 할 수 있다.

바로 함수에서 파라미터로 이 값을 전달 받을 케이스다.

void setTelecomType( int type);

이런 정수형으로 타입을 받을 때 서로 약속 한 정수 값이 아닌 다른 값이 왔을 경우 함수 안에서 일일히 if 문으로 데이터 유효성 검사를 해야만 하는 것이다. 저런거 많이 봤다... 하지만 이 경우 enum을 사용할 경우 위와 같은 걱정은 사라진다. enum으로 정의한 값만 올 수 있기 때문에 별도 다른 값이 올 수 없다. 특히 java는 enum이 byte 형태의 데이터가 아닌 별도 object 이므로 데이터가 혼용될 가능성은 낮다.

위에서 예를 든 통신사를 실제 enum으로 구현해 보자.


/**
 * 통신사  enum 값 정의
 */
public enum ETelecom {
    /** None */
    None, 
    /** SKT */
    SKT,
    /** KT */
    KT,
    /** LGT */
    LGT,
    /** MVNO */
    Other;
}
 

간단히 enum을 정의 해 사용 가능 하다.

PHP : JSON (Multi-Row/JSONArray) Sample Code

PHP :  JSON (Multi-Row/JSONArray) Sample Code

<?
$_zb_url = "http://$_SERVER[HTTP_HOST]/admin/";
$_zb_path =$_SERVER["DOCUMENT_ROOT"]."/admin/";
REQUIRE_ONCE $_zb_path."incs/lib.php";

header("Content-Type:application/json");

if(!$connect) $connect = dbconn();

$stmt = db_query("select * from list where app_no = $app_no");
$resultArray = array();

while($data=mysql_fetch_object($stmt)) { // $data->phoneNumber
$resultArray[] = $data;
}

//Android 측 Code에서는 JSONArray 객체로 받아야 한다.
$json = json_encode($resultArray); //array > json 변환
echo $json;

?>



#결과값 : 

[{"no":"12","app_no":"4","number":"0609002218","regdate":""},{"no":"13","app_no":"4","number":"0609002219","regdate":""},{"no":"14","app_no":"4","number":"0609002246","regdate":""},{"no":"15","app_no":"4","number":"0609002247","regdate":""},{"no":"16","app_no":"4","number":"0609002248","regdate":""},{"no":"17","app_no":"4","number":"0609002249","regdate":""},{"no":"18","app_no":"4","number":"0609050113","regdate":""},{"no":"19","app_no":"4","number":"0609050116","regdate":""},{"no":"20","app_no":"4","number":"0609050117","regdate":""},{"no":"21","app_no":"4","number":"0609057099","regdate":""},{"no":"22","app_no":"4","number":"0609057100","regdate":""},{"no":"23","app_no":"4","number":"0609057575","regdate":""},{"no":"24","app_no":"4","number":"0609058877","regdate":""},{"no":"25","app_no":"4","number":"0609059009","regdate":""}]

Android : ContentProvider URI Structure

URI의 구조
http://developer.android.com/guide/topics/providers/content-providers.html#urisum



1. Prefix
   - 컨텐트 프로바이더를 사용한다는 고정적인 스키마이다.

2. Authority
   - 컨텐트 프로바이더를 구분하기 위한 고유 이름이다.
     사용하기 위해서 <provider> 엘리멘트에 authority 속성을 정의해야 한다.

3. Path
   - 프로바이더가 제공할 데이터의 타입을 정한다.
     만약 프로바이더가 제공하는 데이터 타입이 하나라면 데이터 유형을 비워도 된다.
     또 "/" 기호를 사용하여 여러개를 연결하여 사용할 수 있다.

4. ID
   - 요청한 레코드의 아이디.
     만약 아이디가 없다면 요청한 레코드 전체 데이터를 의미한다. 

Android : BroadcastReceiver Sample

1. StandAlone Type
: 별도의 클래스에 Custom BroadcastReceiver Class생성
: Manifest파일에 Receiver등록 및 IntentFilter > Action 정의


+ Manifest : 

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.networkreceiver"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="8"/>
    <application android:label="@string/app_name" android:icon="@drawable/icon">
        <receiver android:name="NetworkReceiver">
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
            </intent-filter>
        </receiver>
    </application></manifest>


+ Java Code : (Custom Receiver Class)

import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.net.ConnectivityManager;import android.net.NetworkInfo;import android.util.Log;

public class NetworkReceiver extends BroadcastReceiver {
    private static final String LOGTAG = "NetworkReceiver";

    @Override
    public void onReceive(Context ctx, Intent intent) {
        Log.i(LOGTAG, "Action: " + intent.getAction());
        if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
            NetworkInfo info = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
            String typeName = info.getTypeName();
            String subtypeName = info.getSubtypeName();
            boolean available = info.isAvailable();
            Log.i(LOGTAG, "Network Type: " + typeName 
                        + ", subtype: " + subtypeName
                        + ", available: " + available);
        }
    }}






2. Inside Activity Type
: Activity내부에서 BroadcastReceiver와 IntentFilter 생성 및 등록


    private IntentFilter mNetworkStateChangedFilter;
    private BroadcastReceiver mNetworkStateIntentReceiver;
    private String mTypeName = "Unknown";
    private String mSubtypeName = "Unknown";
    private boolean mAvailable = false;

    private TextView statusField;

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

        mNetworkStateChangedFilter = new IntentFilter();
        mNetworkStateChangedFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);

        mNetworkStateIntentReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                    NetworkInfo info = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
                    mTypeName = info.getTypeName();
                    mSubtypeName = info.getSubtypeName();
                    mAvailable = info.isAvailable();
                    Log.i(LOGTAG, "Network Type: " + mTypeName 
                                + ", subtype: " + mSubtypeName
                                + ", available: " + mAvailable);
                    updateScreen();
                }
            }
        };

        setContentView(R.layout.main);
    }

    private void updateScreen() {
        statusField = (TextView) findViewById(R.id.networkStatus);
        statusField.setText("Network Type: " + mTypeName + "\n"
                          + "Network subtype: " + mSubtypeName + "\n"
                          + "Available: " + mAvailable);
    }

    @Override
    protected void onResume() {
        Log.d(LOGTAG, "onResume");
        super.onResume();
        registerReceiver(mNetworkStateIntentReceiver, mNetworkStateChangedFilter);
        unregisterReceiver(mNetworkStateIntentReceiver);
        registerReceiver(mNetworkStateIntentReceiver, mNetworkStateChangedFilter);
    }

    @Override
    protected void onPause() {
        Log.d(LOGTAG, "onPause");
        super.onPause();
        unregisterReceiver(mNetworkStateIntentReceiver);
    }

Android : Date Object Sample (Calendar, SimpleDateFormat )

     /**
     *  Unix TimeStamp > Date String 변환
     * @param dbTimeStamp
     * @return
     */
     public static String timeStampToSimepleDateString(String dbTimeStamp){
         
          SimpleDateFormat dateFormat = new SimpleDateFormat ("yy/MM/dd");
          SimpleDateFormat timeFormat = new SimpleDateFormat ("HH:mm분");
         
          //Yesterday
          Calendar today = Calendar.getInstance ( );
          today.add ( Calendar.DATE, -1 );
          Date yesterday = today.getTime ( );
          String yesDate = dateFormat.format(yesterday);
         
          //Current date
          Date now = new Date();
          String curDate = dateFormat.format(now);
         
          //MySQL DB TimStamp > JAVA Date
          Date unixDate = new Date(1000l*Long.parseLong(dbTimeStamp)) ;
          String dbDate = dateFormat.format(unixDate);
         
         
          if(curDate.equals(dbDate)){ // Current
               return timeFormat.format(unixDate);
          } else if(yesDate.equals(dbDate)){ //Yesterday
               return "어제";
          } else { // Another 
               return dbDate; //yyyy MM dd
          }
    

Android : OAuth

OAuth


OAuth는 계정정보(ID/PW)를 이용한 인증 방식의 경우, API사용 시 계정 노출의 위험을 방지하기 위해 대안으로 나온 방식입니다.
(이전의 여러가지 인증 방식들이 존재하였으나 표준화되지 않고 각각의 회사마다 다른 방식의 인증을 제공하였습니다.
하지만 컨슈머(써드파티앱)의 입장에선 여러 플랫폼으로부터 서비스를 제공받으려면 
여러가지 인증 수단을 학습해야했던 불편함을 OAuth라는 표준 프로토콜을 이용함으로써 편리해졌습니다.)

Facebook, 포스퀘어, Google, Microsoft, LinkedIn의 경우엔 OAuth 2.0방식을 이용하며,
Naver, Twitter, Vimeo등의 경우엔 OAuth 1.0a 방식을 이용합니다.

OAuth 1.0a의 경우 HMAC_SHA1 알고리즘과 base64 암호화를 이용해 서명을 생성합니다.(굉장히 복잡하단 것이 단점..)
검증 작업시 서비스 제공자의 성능 이슈들이 있으며, 사용 중 생기는 여러가지 요구 사항들을 처리하기 위해 확장을 시도하지만, 한계에 부딪힙니다.
ex) Auto Refresh Token, Long-Live Token 등의 구현 제약

그 후 OAuth 2.0은 1.0a의 복잡함 및 확장 한계등의 단점을 보완하여 나왔습니다. (아직 드래프트 단계로써, 최종안이 나오지 않음)
ex) Auto Refresh Token, Long-Live Token 구현 가능!
인증 아키텍쳐 및 접근법등은 그대로이지만 하지만 새로운 프로토콜로 나오게 되면서 이전버전과의 하위호환을 제공하지 않습니다.
Client에서 HMAC_SHA1등의 암호화 서명을 걷어내고, HTTPS 프로토콜을 이용하게 됩니다.
(이 과정에서 HTTPS의 보안 취약점이 이슈로 거론 됩니다)

OAuth 1.0a는 다음과 같은 방식으로 서비스됩니다.
1) 컨슈머가 서비스제공자에게 Request Token 확인 요청.
2) 서비스제공자는 컨슈머의 Request Token을 받아 등록 된 컨슈머인지 확인.
3) 서비스제공자는 컨슈머에게 Access Token을 발급해주어도 되는지 유저에게 확인(로그인 및 권한 부여)
4) 이후 컨슈머는 이 Access Token을 이용해 서비스제공자에게 API 요청.

Request Token을 발급받기 위해선 다음과 같은 파라미터들이 필요합니다.
oauth_callback (서비스제공자가 인증 완료 후 리다이렉트할 컨슈머의 URL. 웹이 아닌 환경은 Out Of Band를 통해 리다이렉트 하지 않을 수 있습니다)
oauth_consumer_key (컨슈머 고유 키값. 서비스제공자로부터 발급받아 사용할 수 있습니다)
oauth_nonce (컨슈머에서 임의로 생성한 값. 악의적 목적의 요청 방지를 위함이며 중복이 불가능합니다)
oauth_timestamp (요청 생성 시점의 시간을 나타냅니다. 현재시간 - 1970.01.01/00:00:00을 초로 환산하여 넣어줍니다.
oauth_version (버젼을 의미합니다. 1.0a / 2.0 등등)
oauth_signature_method (signature 암호화 방법을 명시해줍니다. ex: HMAC-SHA1)
oauth_signature (signature을 제외한 모든 파라미터와 HTTP method, URL을 조합하여 암호화 한 값이 됩니다)


이하 1.0a 사용 방법은 naver open api를 기준으로 작성합니다.

Request Token 요청 시 URL입니다. (http://helloworld.naver.com/helloworld/24942 참조)
GET http://nid.naver.com/naver.oauth?mode=req_req_token&
oauth_callback=http://example.com/OAuthRequestToken.do&
oauth_consumer_key=WEhGuJZWUasHg&
oauth_nonce=zSs4RFI7lakpADpSsv&
oauth_signature=wz9+ZO5OLUnTors7HlyaKat1Mo0=&
oauth_signature_method=HMAC-SHA1&
oauth_timestamp=1330442419&
oauth_version=1.0 HTTP/1.1

Response parameter는 다음과 같습니다.
http://myapp.example.com/callback/callback.nhn?oauth_token=REQUEST_TOKEN&oauth_verifier=VERIFIER_CODE

Access Token을 발급받기 위해선 다음과 같은 파라미터들이 필요합니다.

파라미터 이름설명비고
mode네이버의 OAuth 인증 단계의 구분은 mode의 파라미터 값으로 구분합니다.
Request Token 발급 : req_req_token
사용자 인증 : auth_req_token
Access Token 발급 : req_acc_token
auth_req_token고정
oauth_consumer_key네이버 개발자 센터에서 발급 받은 Consumer Key 값입니다.Consumer Key 값
oauth_token2.3 단계에서 발급받은 “인증 받은 Request Token” 입니다.
oauth_signature_method서명문을 생성하기 위해 사용하는 메소드입니다.HMAC-SHA1 고정
oauth_timestamp요청을 하는 시점의 타임 스탬프로, 1970년 1월 1일부터 시작한 초 단위의 숫자입니다.
타임 스탬프의 값은 항상 이전에 사용한 타임 스탬프의 값보다 커야 합니다.
oauth_nonce컨슈머에서 생성하는 임의적인 문자열로 동일한 타임 스탬프에서는 유일한
값이어야 합니다.
oauth_versionOAuth의 버전 정보입니다.1.0 고정
oauth_verifierCallback URL에 대해 입증한 값
oauth_signature위의 OAuth 인증 정보를 HMAC-SHA1 서명 후, Base64 인코딩을 통해
생성한 서명 값이며, Signature Base String 작성 규칙에 의해 만듭니다.


Access Token 요청 시 URL입니다.
GET http://nid.naver.com/naver.oauth?mode=auth_req_token&
oauth_consumer_key=WEhGuJZWUasHg&
oauth_nonce=zSs4RFI7lakpADpSsv&
oauth_signature=wz9+ZO5OLUnTors7HlyaKat1Mo0=&
oauth_signature_method=HMAC-SHA1&
oauth_timestamp=1330442419&
oauth_version=1.0 HTTP/1.1&
oauth_verifier=zSs4RFI7lakpADpSsv&
oauth_token=zSs4RFI7lakpADpSsv


Response Parameter는 다음과 같습니다
oauth_token=OAUTH_TOKEN&oauth_token_secret=OAUTH_TOKEN_SECRET&id=enc(naverID)

이후 획득한 Access Token을 사용하여 API를 요청할 수 있습니다.

HTTP 헤더엔 GET/POST와 같은 메소드가 아닌 HEAD방식으로 Authorization 필드를 주어야 합니다.
카페의 메뉴리스트를 가져오는 예제 URL입니다.
POST /cafe/getMenuList.xml HTTP/1.1
Authorization: OAuth oauth_consumer_key="dpf43f3p2l4k3l03",oauth_token="nSDFh734d00sl2jdk"
,oauth_signature_method="HMACSHA1",oauth_timestamp="1379123202",oauth_nonce="chapoH",oauth_signature="MdpQcU8iPSUjWoN%2FUDMsK2sui9I%3D"
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: http://openapi.naver.com