coolsharp의 놀이터

'개발'에 해당되는 글 81건

  1. 2012.03.19 안드로이드 각종 마켓 링크
  2. 2012.02.24 안드로이드 proguard 적용 후 에러 발생할때…
  3. 2012.01.05 ubuntu 11.10에서 jdk 설치
  4. 2011.12.21 이클립스 디버그 퍼스팩티브 전환 설정
  5. 2011.12.05 이클립스 설치 후 설치해야 할 플로그인 목록
  6. 2011.11.24 구글 앱 엔진 파이썬 런쳐가 실행 오류
  7. 2011.11.23 안드로이드 트위터 연동 번외편(이미지 업로드) 2
  8. 2011.11.21 android OpenCV 빌드 중 cannot find - lcxcore 에러 해결 방법
  9. 2011.11.17 이클립스에서 코드 정렬
  10. 2011.11.15 이클립스에서 Column 선택 지원 및 Code Align을 지원하는 플로그인
  11. 2011.11.04 자바에서 콜백 처리를 위한 리스너
  12. 2011.11.03 Android 게임 강좌 - Cocos2d로 슈팅 게임 만들기 서문
  13. 2011.11.03 C2DM 서비스 플로우 확장
  14. 2011.11.02 C2DM 소스(안드로이드에서 푸시 서버를 사용하자.)
  15. 2011.11.02 페이스북에게 사과를 받다.
  16. 2011.11.02 C2DM 간략 시퀀스
  17. 2011.11.01 참 뭐 같은 페이스북
  18. 2011.10.31 안드로이드 구글 맵 연동 4
  19. 2011.10.31 ADT 14 이후 Google APIs 항목이 설치되지 않는 문제 해결 8
  20. 2011.10.31 구글 맵 인증서 키 md5로 얻기
  21. 2011.10.28 안드로이드 트위터 정리
  22. 2011.10.28 안드로이드 트위터 추가사항
  23. 2011.10.28 안드로이드 트위터 연동 최종
  24. 2011.10.27 안드로이드 트위터 연동 #2
  25. 2011.10.27 OAuth 용어 정리
  26. 2011.10.27 안드로이드 트위터 연동 #1
  27. 2011.10.27 Android Facebook 연동
  28. 2011.10.19 cocos2d for android - 서서히 빨라졌다 느려졌다 다시 빨라졌다 이동
  29. 2011.10.19 cocos2d for android - 점점 빠르게, 점점 느리게 레이어를 이동
  30. 2011.10.19 cocos2d for android - 클린업
안드로이드마켓
https://market.android.com/details?id=[PackageName]
티스토어
tstore://PRODUCT_VIEW/[PID]/0
오즈스토어
ozstore://STORE/PID=[PID]
올레마켓
cstore://detail?CONTENT_TYPE=APPLICATION&P_TYPE=c&P_ID=[CONTENT_ID]&N_ID=[APP_ID]
Posted by coolsharp

image

 

이런 에러가 발생하면

[Android SDK Installation Directory]\tools\proguard\bin\proguard.bat

수정

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

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

Posted by coolsharp

터미널을 열고 다음과 같이 입력

sudo apt-get install openjdk-7-jdk

 

아니면 다음과 같이 설치 할 수 있음

sudo add-apt-repository ppa:ferramroberto/java
sudo apt-get update
sudo apt-get install sun-java6-jdk sun-java6-plugin

Posted by coolsharp

이클립스에서 디버깅시 자동으로 퍼스팩티브 전환이 되는 짜증을 극복하기 위한 설정

Windows -> Preferences -> Run/Debug –> Perspactives

에서 디버그를 None로 하면 자동으로 퍼스팩티브 전환이 안됨

Posted by coolsharp
Posted by coolsharp

image

 

회사에서는 제대로 되던 넘이 집에와서 안되서 찾아본 결과 저따구 에러창을 내뱉으면

 

C:\Users\사용자 계정\Google 폴더의 모든 ini 파일을 지우면 해결 됨

Posted by coolsharp

지난번 최종 소스를 올렸지만 정작 중요한 이미지 업로드 기능이 빠져 있으므로 이번에 추가하였습니다.

 

트윗픽을 연동하여 올리는 것이 아닌 순수 트위터만의 API를 이용하여 전송하는 예제 입니다.

 

 

   1: package com.coolsharp.test;
   2:  
   3: import java.io.File;
   4: import java.util.List;
   5:  
   6: import twitter4j.Paging;
   7: import twitter4j.Status;
   8: import twitter4j.Twitter;
   9: import twitter4j.TwitterException;
  10: import twitter4j.TwitterFactory;
  11: import twitter4j.auth.AccessToken;
  12: import twitter4j.auth.RequestToken;
  13: import twitter4j.conf.Configuration;
  14: import twitter4j.conf.ConfigurationBuilder;
  15: import twitter4j.media.ImageUpload;
  16: import twitter4j.media.ImageUploadFactory;
  17: import android.app.Activity;
  18: import android.content.Intent;
  19: import android.net.Uri;
  20: import android.os.Bundle;
  21: import android.util.Log;
  22: import android.view.View;
  23: import android.widget.Button;
  24:  
  25: /**
  26:  * @author coolsharp
  27:  *
  28:  */
  29: public class TwitterApp extends Activity {
  30:  
  31:     /**
  32:      * Twitter instance object
  33:      */
  34:     private Twitter twitter;
  35:     private AccessToken acToken  = null;
  36:     private RequestToken rqToken = null;
  37:     private Status status        = null;
  38:     String access_token          = "";
  39:     String access_token_secret   = "";
  40:  
  41:     private static final String CONSUMER_KEY        = "";
  42:     private static final String CONSUMER_SECRET     = "";
  43:     private static final String ACCESS_TOKEN        = "ACCESS_TOKEN";
  44:     private static final String ACCESS_TOKEN_SECRET = "ACCESS_TOKEN_SECRET";
  45:     public static Uri CALLBACK_URL = Uri.parse("wefu://twitter");
  46:  
  47:     /** 생성. */
  48:     @Override
  49:     public void onCreate(Bundle savedInstanceState) {
  50:         super.onCreate(savedInstanceState);
  51:         setContentView(R.layout.main);
  52:  
  53:         // 트위터 인스턴스 얻기
  54:         twitter = new TwitterFactory().getInstance();
  55:         // 컨슈머 키 대입
  56:         twitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
  57:         
  58:         // 버튼 리스너 등록
  59:         Button btn = (Button) findViewById(R.id.btnAuthorize);
  60:         btn.setOnClickListener(new Button.OnClickListener() {
  61:             public void onClick(View v) {
  62:                 try {
  63:                     File file = new File("/sdcard/test.jpg");
  64:                     if (file.exists())
  65:                         writePicTwitter("test", file);
  66: //                    if (null != acToken) getList();
  67:                 } catch (TwitterException e) {
  68:                     // TODO Auto-generated catch block
  69:                     e.printStackTrace();
  70:                 } // 토큰 발행
  71:             }
  72:         });
  73:     }
  74:     
  75:     /**
  76:      * 트위터 글 쓰기
  77:      * @return
  78:      * @throws TwitterException 
  79:      */
  80:     private boolean writeTwitter(String content) throws TwitterException {
  81:         boolean res = false;
  82:         
  83:         getToken(); // 토큰 읽기
  84:  
  85:         if (null != acToken) {
  86:             // 트위터 글쓰기
  87: //            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  88: //            dateFormat.format(new Date(System.currentTimeMillis())).toString();
  89:             status = twitter.updateStatus(content);
  90:         }
  91:         
  92:         return res;
  93:     }
  94:     
  95:     /**
  96:      * 트위터 글 쓰기
  97:      * @return
  98:      * @throws TwitterException 
  99:      */
 100:     private boolean writePicTwitter(String content, File file) throws TwitterException {
 101:         boolean res = false;
 102:         
 103:         getToken(); // 토큰 읽기
 104:  
 105:         if (null != acToken) {
 106:             ConfigurationBuilder builder = new ConfigurationBuilder();
 107:             builder.setOAuthConsumerKey(CONSUMER_KEY);
 108:             builder.setOAuthConsumerSecret(CONSUMER_SECRET);
 109:             builder.setOAuthAccessToken(access_token);
 110:             builder.setOAuthAccessTokenSecret(access_token_secret);
 111:             builder.setMediaProvider("TWITTER");
 112:  
 113:             Configuration conf = builder.build();
 114:  
 115:             ImageUpload imageUpload = new ImageUploadFactory(conf)
 116:                     .getInstance();
 117:  
 118:             try {
 119:                 imageUpload.upload(file, content);
 120:             } catch (TwitterException e) {
 121:                 e.printStackTrace();
 122:             }
 123:         }
 124:         
 125:         return res;
 126:     }
 127:     
 128:     /**
 129:      * 토큰 얻기
 130:      * @return
 131:      * @throws TwitterException 
 132:      */
 133:     private void getToken() throws TwitterException {
 134:         // 토큰이 발행 되지 않았으면
 135:         if (null == acToken) {
 136:             // 최근 사용한 토큰 읽기
 137:             access_token           = Util.getSharedPreferencesValue(this, "coolsharp", MODE_PRIVATE, ACCESS_TOKEN);
 138:             access_token_secret = Util.getSharedPreferencesValue(this, "coolsharp", MODE_PRIVATE, ACCESS_TOKEN_SECRET);
 139:             
 140:             // 토큰 값이 모두 있으면
 141:             if ((!access_token.equals("")) && (!access_token_secret.equals(""))) {
 142:                 // 기존 토큰 값으로 토큰 발행
 143:                 acToken = new AccessToken(access_token, access_token_secret);
 144:                 twitter.setOAuthAccessToken(acToken);
 145:             }
 146:             else {
 147:                 // 인증 시작
 148:                 startAuth();
 149:             }
 150:         } else {
 151:         }
 152:     }
 153:     
 154:     /**
 155:      * 인증 시작
 156:      * @throws TwitterException 
 157:      */
 158:     private void startAuth() throws TwitterException {
 159:         rqToken = twitter.getOAuthRequestToken(CALLBACK_URL.toString());
 160:         startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(rqToken.getAuthorizationURL())));
 161:     }
 162:     
 163:     /**
 164:      * @throws TwitterException
 165:      */
 166:     private void getList() throws TwitterException {
 167:         List<Status> statuses;
 168:         Paging page = new Paging();
 169:         page.count(20);
 170:         page.setPage(1);
 171:         statuses = twitter.getHomeTimeline(page);
 172:         for (Status status : statuses) {
 173:             Log.i("coolsharp", status.getText());
 174:         }
 175:     }
 176:  
 177:     /* (non-Javadoc)
 178:      * 인텐트 생성
 179:      * @see android.app.Activity#onNewIntent(android.content.Intent)
 180:      */
 181:     protected void onNewIntent(Intent intent) {
 182:         super.onNewIntent(intent);
 183:         Uri uri = intent.getData();
 184:         if (uri != null && CALLBACK_URL.getScheme().equals(uri.getScheme())) {
 185:             String oauth_verifier = uri.getQueryParameter("oauth_verifier");
 186:             try {
 187:                 acToken = twitter.getOAuthAccessToken(rqToken, oauth_verifier);
 188:                 access_token           = acToken.getToken();
 189:                 access_token_secret = acToken.getTokenSecret();
 190:                 Util.setSharedPreferencesValue(this, "coolsharp", MODE_PRIVATE, ACCESS_TOKEN, access_token);
 191:                 Util.setSharedPreferencesValue(this, "coolsharp", MODE_PRIVATE, ACCESS_TOKEN_SECRET, access_token_secret);
 192:             } catch (TwitterException e) {
 193:                 Log.e("coolsharp", e.getMessage());
 194:             }
 195:         }
 196:     }
 197: }
Posted by coolsharp

android에서 OpenCV 빌드 중 cannot find – lcxcore 에러가 나온다면 다음과 같이 해결 할 수 있다.

android.mk 파일을 수정한다.

LOCAL_LDLIBS := -L $(SYSROOT)/usr/lib -l dl -l log \
        -L "D:\OpenCV-Android\obj\local\armeabi" \
        -l cxcore -l cv -l cvaux -l cvml -l cvhighgui
TARGET-OUT을 수정한다.
이상이다.
Posted by coolsharp

 

소스 코드를 작성 하다 보면 정렬이 안된 코드는 가독성이 떨어져 향 후 유지보수에 불편함을 줍니다.

 

물론 개의치 않는 개발자분들도 많으시겠지만 가급적이면 소스 코드는 들여쓰기, 내어쓰기, 정렬이 잘 되어 있는 코드가 깔끔하고 보기에도 좋겠지요.

 

다음과 같은 경우 유용하게 사용될 수 있습니다.

 

정렬이 안된 소스 코드

   1: public static final String ERR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE";
   2: public static final String ERR_ACCOUNT_MISSING = "ACCOUNT_MISSING";
   3: public static final String ERR_AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED";
   4: public static final String ERR_TOO_MANY_REGISTRATIONS = "TOO_MANY_REGISTRATIONS";
   5: public static final String ERR_INVALID_PARAMETERS = "INVALID_PARAMETERS";
   6: public static final String ERR_INVALID_SENDER = "INVALID_SENDER";
   7: public static final String ERR_PHONE_REGISTRATION_ERROR = "PHONE_REGISTRATION_ERROR";

 

정렬이 된 소스 코드

   1: public static final String ERR_SERVICE_NOT_AVAILABLE    = "SERVICE_NOT_AVAILABLE";
   2: public static final String ERR_ACCOUNT_MISSING          = "ACCOUNT_MISSING";
   3: public static final String ERR_AUTHENTICATION_FAILED    = "AUTHENTICATION_FAILED";
   4: public static final String ERR_TOO_MANY_REGISTRATIONS   = "TOO_MANY_REGISTRATIONS";
   5: public static final String ERR_INVALID_PARAMETERS       = "INVALID_PARAMETERS";
   6: public static final String ERR_INVALID_SENDER           = "INVALID_SENDER";
   7: public static final String ERR_PHONE_REGISTRATION_ERROR = "PHONE_REGISTRATION_ERROR";

 

대부분의 개발툴이 코드 정렬 기능을 근본적을 지원해 주시 않고 있습니다.

 

때문에 각 개발툴은 플러그인을 통해 위와 같은 기능을 사용할 수 있습니다.

 

비주얼 스튜디오는

 

Visual Studio Code Align

 

편을 보시면 플러그인을 통한 코드 정렬을 쉽게 할 수 있습니다.

 

오늘의 주제는 이클립스이므로 이클립스에서 코드 정렬의 기능을 설명 드리도록 하겠습니다.

 

이클립스에서 코드 정렬을 하려면 플러그인을 설치해야 합니다.

 

플러그인 설치

이클립스 플러그인을 설치합니다.

 

기본적으로 이클립스 사용법을 아시는 분들을 상대로 한 강좌이기 때문에

 

설치 방법을 따로 설명 드리지는 않겠습니다.

 

플러그인 주소 : http://columns4eclipse.sourceforge.net/updates/

 

사용법

설치가 끝나면 재 시작을 한 후 프로젝트를 오픈합니다.

 

정렬을 원하는 코드를 블록 지정 합니다.

 

단축키 Shift + alt + K, A를 누릅니다.

 

 

정렬을 원하는 구분자를 입력 후 OK를 누르면 코드 정렬이 자동으로 진행 됩니다.

Posted by coolsharp

검색을 하다 찾게된 플러그인

 

Column 선택 지원 및 Code를 특정 Delimeter를 기준으로 정렬 해주는 기능이 있음

 

http://columns4eclipse.sourceforge.net/updates/

Posted by coolsharp

 

자바에서 콜백 처리를 하기 위해서는 인터페이스를 사용해야 한다.

 

인터페이스는 아래처럼 정의 할 수 있다.

   1: interface onTapCallback {
   2:     void onTap(GeoPoint p, MapView mapView);
   3: }

 

호출할 함수 원형을 인터페이스에서 정의 하였으면 인터페이스 변수를 선언해야 한다.

   1: private onTapCallback cbOnTap = null;

 

인터페이스 변수를 선언하였다면 인터페이스 변수를 외부에서 할당 할 수 있게 set 함수를 만들어 준다.

 

   1: public void setOnTapCallback(onTapCallback cb) {
   2:     cbOnTap = cb;
   3: }

 

실제 콜백을 호출해야 할 함수에서 다음과 같이 할당이 되었는지 확인 후 호출 한다.

 

   1: if (null != cbOnTap) cbOnTap.onTap(p, mapView);

 

간단한 콜백 사용 예제는 다음과 같다.

 

   1: onTapCallback cb = new onTapCallback() {
   2:     
   3:     @Override
   4:     public void onTap(GeoPoint p, MapView mapView) {
   5:         CenterLocation(p);
   6:     }
   7: };
   8:  
   9: il.setOnTapCallback(cb);
Posted by coolsharp

오늘부터 Cocos2d로 슈팅 게임 만들기 강좌에 들어간다.

 

실제가 필자가 Cocos2d로 기본 슈팅 게임을 만드는데 걸린 시간은 5일이 걸리지 않았다.

 

그만큼 Cocos2d는 잘 구성된 라이브러리이며 기능 또한 막강하여 단시일 내 퀄리티 있는 게임 개발이 가능하다.

 

Cocos2d 간결하고 편리한 라이브러리의 재미에 흠뻑 취해보자.

 

현재 다른 프로젝트 중이므로 틈틈히 시간을 내여 기 개발된 게임 소스를 가지고 포스팅을 이어가겠다.

 

Posted by coolsharp

C2DB로 카카오톡 같은 서비스를 개발하기 위한 플로우 이다.

Posted by coolsharp

C2DM이란 안드로이드 2.2 프로요 버전 부터 푸시 서버를 제공해 주는 기능이다.

 

이하 소스는 http://www.androidside.com/bbs/board.php?bo_table=B46&wr_id=14705

 

에서 소스를 받아 수정 하였다.

 

푸시서버를 사용하기 위해서는 다음과 같은 절차가 필요하다.

 

  1. 구글에 해당 서버 사용 인증 요청
    http://code.google.com/intl/ko-KR/android/c2dm/signup.html에서 등록 요청
  2. 메일로 승인 확인
  3. 소스 코딩

 

C2dm_BroadcastReceiver.java

package com.coolsharp.push;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;

public class C2dm_BroadcastReceiver extends BroadcastReceiver {

    static String registration_id = null;
    static String c2dm_msg = "";

    /* 메시지 도착
     * (non-Javadoc)
     * @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {

            handleRegistration(context, intent);

        } else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {

            c2dm_msg = intent.getExtras().getString("msg");

            System.out.println("c2dm_msg======>" + c2dm_msg);
            Toast toast = Toast.makeText(context, "메시지 도착!\n" + c2dm_msg, Toast.LENGTH_SHORT);
            toast.setGravity(Gravity.TOP | Gravity.CENTER, 0, 150);
            toast.show();

        }
    }

    /**
     * @param context
     * @param intent
     */
    private void handleRegistration(Context context, Intent intent) {

        registration_id = intent.getStringExtra("registration_id");

        System.out.println("registration_id====>" + registration_id);

        if (intent.getStringExtra("error") != null) {

            Log.v("C2DM_REGISTRATION", ">>>>>" + "Registration failed, should try again later." + "<<<<<");

        } else if (intent.getStringExtra("unregistered") != null) {

            Log.v("C2DM_REGISTRATION", ">>>>>" + "unregistration done, new messages from the authorized sender will be rejected" + "<<<<<");

        } else if (registration_id != null) {

            System.out.println("registration_id complete!!");
        }
    }

}

 

Coolsharp_pushActivity.java

package com.coolsharp.push;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class Coolsharp_pushActivity extends Activity {

    // 아래 문자는 수정하면 안됨.
    // 구글에서 필요한 변수명.
    private static final String S_APP = "app";
    private static final String S_SENDER = "sender";
    private static final String S_REGISTRATION_ID_KEY = "S_AUTH_TOKEN";
    private static final String S_AUTH_TOKEN_KEY = "S_REGISTRATION_ID";
    private static String S_REGISTRATION_ID = "";
    private static String S_AUTH_TOKEN = "";
    EditText msg_text;
    Button msg_send;

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

        // 마지막 저장된 인증
        S_AUTH_TOKEN = Util.getSharedPreferencesValue(getApplicationContext(), "coolsharp", MODE_PRIVATE, S_AUTH_TOKEN_KEY);
        // 마지막 저장된 레지스트레이션 아이디
        S_REGISTRATION_ID = Util.getSharedPreferencesValue(getApplicationContext(), "coolsharp", MODE_PRIVATE, S_REGISTRATION_ID_KEY);
        if (S_REGISTRATION_ID.equals("")) {
            // C2DM 등록ID 발급
            Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
            registrationIntent.putExtra(S_APP, PendingIntent.getBroadcast(this, 0, new Intent(), 0)); // 어플리케이션ID
            registrationIntent.putExtra(S_SENDER, "xxxx@gmail.com"); // 개발자ID
            startService(registrationIntent); // 서비스 시작(등록ID발급받기)
        }

        msg_text = (EditText) findViewById(R.id.msg_text);
        msg_send = (Button) findViewById(R.id.msg_send);

        msg_send.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                try {
                    // 메시지를 보낼때 sender(발급받은 ID, 토큰인증값, 메시지)
                    // 한번 발급 받은 인증을 다시 발급 받지 않게 하기 위함
                    // 인증을 따로 문자열로 저장하는 것도 좋을 듯 함
                    if (S_AUTH_TOKEN.equals("")) {
                        S_AUTH_TOKEN = getAuthToken();
                        Util.setSharedPreferencesValue(getApplicationContext(), "coolsharp", MODE_PRIVATE, S_AUTH_TOKEN_KEY, S_AUTH_TOKEN);
                    }
                    // 한번 발급 받은 REGISTRATION_ID를 다시 발급 받지 않게 하기 위함
                    if (S_REGISTRATION_ID.equals("")) {
                        S_REGISTRATION_ID = C2dm_BroadcastReceiver.registration_id;
                        Util.setSharedPreferencesValue(getApplicationContext(), "coolsharp", MODE_PRIVATE, S_REGISTRATION_ID_KEY, S_REGISTRATION_ID);
                    }
                    sender(S_REGISTRATION_ID, S_AUTH_TOKEN, msg_text.getText().toString());
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * 메시지 전송
     * @param regId
     * @param authToken
     * @param msg
     * @throws Exception
     */
    public void sender(String regId, String authToken, String msg) throws Exception {
        StringBuffer postDataBuilder = new StringBuffer();

        postDataBuilder.append("registration_id=" + regId); // 등록ID
        postDataBuilder.append("&collapse_key=1");
        postDataBuilder.append("&delay_while_idle=1");
        postDataBuilder.append("&data.msg=" + URLEncoder.encode(msg, "UTF-8")); // 태울
                                                                                // 메시지

        byte[] postData = postDataBuilder.toString().getBytes("UTF8");

        URL url = new URL("https://android.apis.google.com/c2dm/send");

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", Integer.toString(postData.length));
        conn.setRequestProperty("Authorization", "GoogleLogin auth=" + authToken);

        OutputStream out = conn.getOutputStream();
        out.write(postData);
        out.close();

        conn.getInputStream();

    }

    /**
     * 인증 토큰 얻어오기
     * @return
     * @throws Exception
     */
    public String getAuthToken() throws Exception {
        String authtoken = "";

        StringBuffer postDataBuilder = new StringBuffer();
        postDataBuilder.append("accountType=HOSTED_OR_GOOGLE"); // 똑같이 써주셔야 합니다.
        postDataBuilder.append("&Email=xxxx@gmail.com"); // 개발자 구글 id
        postDataBuilder.append("&Passwd=xxxx"); // 개발자 구글 비빌번호
        postDataBuilder.append("&service=ac2dm");
        postDataBuilder.append("&source=test-1.0");

        byte[] postData = postDataBuilder.toString().getBytes("UTF8");

        URL url = new URL("https://www.google.com/accounts/ClientLogin");

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", Integer.toString(postData.length));

        OutputStream out = conn.getOutputStream();
        out.write(postData);
        out.close();

        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

        String sidLine = br.readLine();
        String lsidLine = br.readLine();
        String authLine = br.readLine();

        System.out.println("sidLine----------->>>" + sidLine);
        System.out.println("lsidLine----------->>>" + lsidLine);
        System.out.println("authLine----------->>>" + authLine);
        System.out.println("AuthKey----------->>>" + authLine.substring(5, authLine.length()));

        authtoken = authLine.substring(5, authLine.length());

        return authtoken;
    }

}

Util.java

package com.coolsharp.push;

import android.content.Context;
import android.content.SharedPreferences;

public class Util {
    public static String getSharedPreferencesValue(Context context, String name, int mode, String key) {
        SharedPreferences prefs = context.getSharedPreferences(name, mode);
        return prefs.getString(key, "");
    }

    public static boolean setSharedPreferencesValue(Context context, String name, int mode, String key, String value) {
        SharedPreferences prefs = context.getSharedPreferences(name, mode);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString(key, value);
        return editor.commit();
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.coolsharp.push"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="8" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="@string/app_name"
            android:name=".Coolsharp_pushActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver
            android:name=".C2dm_BroadcastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter >
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />

                <category android:name="com.coolsharp.push" />
            </intent-filter>
            <intent-filter >
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

                <category android:name="com.coolsharp.push" />
            </intent-filter>
        </receiver>
    </application>

    <permission
        android:name="com.coolsharp.push.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />

    <uses-permission android:name="com.coolsharp.push.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.INTERNET" />

</manifest>

Posted by coolsharp

image

 

너무 불편했다.

 

지금이라도 처리해줘서 고맙다.

Posted by coolsharp

C2DM 간략 시퀀스

2011. 11. 2. 13:44 : 개발

C2DM의 동작을 보고 간략하게 시퀀스를 그려봤다.

 

내부 알고리즘은 잘 모르지만 동작 자체는 단순하다.

 

image

Posted by coolsharp

참 뭐 같은 페이스북

2011. 11. 1. 01:59 : 개발

모처럼 페이스북 연동 앱을 개발하기 위해 앱 생성에 들어갔다.

 

앱 생성이 되지 않아 이상하게 여겨 페이스북에 문의 메일을 보냈다.

 

그에 대한 답변은 다음과 같다.

 

image

 

난 실명을 사용하고 있고 타인을 사칭한 적도 없다.

 

어떤 알고리즘으로 내가 타인을 사칭하거나 가명을 썼다고 감지했는가?

 

페이스북의 감시 시스템의 알고리즘이 궁금하다.

 

여하튼 잘못 돌아가고 있는 시스템임을 나에게 확인 시켜 주었다.

 

웬만하면 안쓰고 말겠지만 신분증을 발송했다.

 

차라리 한국처럼 주민등록 번호 받아라.

Posted by coolsharp

안드로이드에서는 구글 맵을 쉽게 연동 할 수 있다.

 

다음과 같이 프로젝트를 생성한다.

image

image

image

 

AndroidManifest.xml을 다음과 같이 생성한다.

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.coolsharp"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="8" />

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="@string/app_name"
            android:name=".Coolsharp_googleMAPActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <uses-library android:name="com.google.android.maps" android:required="true" />
    </application>

</manifest>

퍼미션과 라이브러리를 추가한다.

 

package com.coolsharp;

import android.os.Bundle;

import com.google.android.maps.MapActivity;

public class Coolsharp_googleMAPActivity extends MapActivity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected boolean isRouteDisplayed() {
        // TODO Auto-generated method stub
        return false;
    }
}

MapActivity에서 상속 받게 수정한다.

 

<?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" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />
   
        <com.google.android.maps.MapView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:apiKey="발급받은 키" />

</LinearLayout>

 

구글 사이트에서 발급받은 키를 추가한다.

 

빌드하고 설치하면 다음과 같은 화면이 나온다.

image

Posted by coolsharp

ADT 14 이후 자동으로 설치되었던 Google APIs가 항목에 보이지 않는 문제가 발생하였습니다.

image

1시간 넘게 삽질 중 원인을 찾았습니다.

 

Tools>Manage Add-on Sites…

image

 

image

New

 

http://dl-ssl.google.com/android/repository/addon.xml 입력

 

image

 

 

image

Posted by coolsharp

JDK 1.7 부터 keysotore Fingerprint가 기본 SHA1으로 발급 됨

 

해당 문제를 해결하기 위해 다음과 같이 명령어를 쓰면 MD5 정보도 볼 수 있음

 

keytool -list -v -keystore debug.keystore

 

http://code.google.com/intl/ko-KR/android/maps-api-signup.html

 

사이트에서 생성된 MD5를 이용하여 API 키를 발급 받으면 된다.

Posted by coolsharp

안드로이드 트위터 연동에 대해 다음과 같이 정리를 해 보았다.

 

참고 사이트

http://easymicro.egloos.com/5480058 http://blog.outsider.ne.kr/434

 

 

  • 트위터 모듈 추가
    http://twitter4j.org/en/index.html#download 사이트에서 안드로이드 모듈을 다운로드 받음

    해당 모듈을 압축을 풀고 프로젝트에 복사
  • 트위터 인스턴스 생성 
    twitter = new TwitterFactory().getInstance();
  • 트위터 컨슈머 키 대입 
    twitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
  • 리퀘스트 토큰 생성 후 인텐스 생성하며 엑티비티 호출 
    rqToken = twitter.getOAuthRequestToken(CALLBACK_URL.toString());

    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(rqToken.getAuthorizationURL())));
  • 엑세스 토큰 얻어옴 
    rqToken = twitter.getOAuthRequestToken(CALLBACK_URL.toString()); protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Uri uri = intent.getData();
        if (uri != null && CALLBACK_URL.getScheme().equals(uri.getScheme())) {
            String oauth_verifier = uri.getQueryParameter("oauth_verifier");
            try {
                acToken = twitter.getOAuthAccessToken(rqToken, oauth_verifier);
                saveData(S_CONSUMER_KEY, acToken.getToken());
                saveData(S_CONSUMER_SECRET, acToken.getTokenSecret());
            } catch (TwitterException e) {
                Log.e("coolsharp", e.getMessage());
            }
        }
    }
Posted by coolsharp

PIN 코드를 입력하지 않기 위해서 콜백 URL을 트위터 설정에서 꼭 해야 한다.

URL은 어떤 것이든 관계 없다.

트위터를 연동하기 위해서 http://twitter4j.org/en/index.html 라이브러리를 써야 한다.

twitter4j-android-2.2.6-SNAPSHOT.zip(slimmed version for Android platform)

Posted by coolsharp

package com.coolsharp.test;

import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.List;

import twitter4j.Paging;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

/**
* @author coolsharp
*
*/
public class TwitterApp extends Activity {

    /**
     * Twitter instance object
     */
    private Twitter twitter;
    private AccessToken acToken = null;
    private RequestToken rqToken = null;
    private Status status = null;

    private static final String CONSUMER_KEY = "트위터에서 받아온 컨슈머 키";
    private static final String CONSUMER_SECRET = "트위터에서 받아온 컨슈머 비밀 키";
    private static final String S_CONSUMER_KEY = "CONSUMER_KEY";
    private static final String S_CONSUMER_SECRET = "CONSUMER_SECRET";
    public static Uri CALLBACK_URL = Uri.parse("wefu://twitter");

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

        // 트위터 인스턴스 얻기
        twitter = new TwitterFactory().getInstance();
        // 컨슈머 키 대입
        twitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
        // 버튼 리스너 등록
        Button btn = (Button) findViewById(R.id.btnAuthorize);
        btn.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                try {
                    getToken();
                    if (null != acToken) getList();
                } catch (TwitterException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } // 토큰 발행
            }
        });
    }
    /**
     * 토큰 얻기
     * @return
     * @throws TwitterException
     */
    private boolean getToken() throws TwitterException {
        boolean res = false;
        // 토큰이 발행 되지 않았으면
        if (null == acToken) {
            // 최근 사용한 토큰 읽기
            String key = loadData(S_CONSUMER_KEY);
            String value = loadData(S_CONSUMER_SECRET);
            // 토큰 값이 모두 있으면
            if ((!key.equals("")) && (!value.equals(""))) {
                // 기존 토큰 값으로 토큰 발행
                acToken = new AccessToken(key, value);
                twitter.setOAuthAccessToken(acToken);
                res = true;
            }
            else {
                // 인증 시작
                startAuth();
            }
        } else {
        }
        if (null != acToken) {
            // 트위터 글쓰기
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            status = twitter.updateStatus("" + dateFormat.format(new Date(System.currentTimeMillis())).toString());
        }
        return res;
    }
    /**
     * 인증 시작
     * @throws TwitterException
     */
    private void startAuth() throws TwitterException {
        rqToken = twitter.getOAuthRequestToken(CALLBACK_URL.toString());
        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(rqToken.getAuthorizationURL())));
    }
    /**
     * @throws TwitterException
     */
    private void getList() throws TwitterException {
        List<Status> statuses;
        Paging page = new Paging();
        page.count(20);
        page.setPage(1);
        statuses = twitter.getHomeTimeline(page);
        for (Status status : statuses) {
            Log.i("coolsharp", status.getText());
        }
    }
    /**
     * 스트링 데이터 저장하기
     * @param Key
     * @param Data
     * @return
     */
    private boolean saveData(String Key, String Data) {
        SharedPreferences prefs = getSharedPreferences("coolsharp", MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString(Key, Data);
        return editor.commit();
    }
    /**
     * 스트링 데이터 불러오기
     * @param Key
     * @return
     */
    private String loadData(String Key) {
        SharedPreferences prefs = getSharedPreferences("coolsharp", MODE_PRIVATE);
        return prefs.getString(Key, "");
    }

    /* (non-Javadoc)
     * 인텐트 생성
     * @see android.app.Activity#onNewIntent(android.content.Intent)
     */
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Uri uri = intent.getData();
        if (uri != null && CALLBACK_URL.getScheme().equals(uri.getScheme())) {
            String oauth_verifier = uri.getQueryParameter("oauth_verifier");
            try {
                acToken = twitter.getOAuthAccessToken(rqToken, oauth_verifier);
                saveData(S_CONSUMER_KEY, acToken.getToken());
                saveData(S_CONSUMER_SECRET, acToken.getTokenSecret());
            } catch (TwitterException e) {
                Log.e("coolsharp", e.getMessage());
            }
        }
    }
}


Posted by coolsharp

 

 

위와 같이 키가 생성 된다.

 

위의 키를 가지고 연동 작업을 진행 할 수 있다.

 


Posted by coolsharp

OAuth 용어 정리

2011. 10. 27. 16:18 : 개발

트위터는 OAuth를 사용하므로 해당 알고리즘에 대한 용어 정리부터 시작함

An open protocol to allow secure API authorization in a simple and standard method from desktop and web applications. (데스크탑과 웹어플리케이션에서 간단하고 표준적인 방법으로 안전한 API 인증을 하도록 하는 공개 프로토콜입니다.)

OAuth Logo

  • 서비스 프로바이더(Service Provider) – API를 제공하는 서비스 주체(페이스북, 트위터)
  • 컨수머(Consumer) – 서비스 프로바이더로 부터 제공된 API를 사용하여 개발된 애플리케이션(내가 만들 어플)
  • 사용자(users) – 일반 유저(내가 만든 어플을 사용하는 사람들)
  • 보호된 자원(Protected Resources): 서비스 프로바이터의 데이터들(페이스북 대화 내용)
  • 컨수머 키(Consumer Key) : 서비스 프로바이더에 접근할 컨수머의 인증키
  • 컨수머 시크릿(Consumer Secret) : 컨수머 키의 암호키
  • 요청 토큰(Request Token) : 사용자로부터 위임 권한(Authorization)을 얻기 위해 Consumer가 사용하는 토큰, Access Token으로 교환된다.

  • 접근 토근(Access Token) : 사용자의 보호된 자원에 접근하기 위해 Consumer가 사용하는 값

 

대충 정리하자면 다음과 같음

A 서비스의 특정 기능을 B 서비스가 쓰고 싶은데 B 서비스에서 A 서비스를 접근하기 위한 인증

A 서비스는 B 서비스에게 A 서비스 계정 정보를 주지 않고 토큰이라는 것을 발행하여 접근 할 수 있게 함

 

다음 플로우를 보면 이해가 쉬움

출처 : http://developer.yahoo.com/oauth/guide/oauth-auth-flow.html

Posted by coolsharp

페이스북부터 연동하려 하였으나 페이스북 계정이 생성 후 별로 사용치 않은 관계로 앱 등록이 불가능했다.

 

때문에 우선 트위터로 안드로이드 연동부터 공부 후 페이스북은 추후 연동하도록 하겠다.

 

트위터 개발자 등록 사이트는 다음과 같다.

 

https://dev.twitter.com/

 

 

Create an app을 클릭한다.

 

Name, Descriptoion, Web Site를 입력 후 생성한다.

Posted by coolsharp

Android Facebook 연동

2011. 10. 27. 14:50 : 개발

오늘부터 안드로이드에 facebook을 연동하는 방법을 모색한다.

 

그 과정에 대한 일종의 기록을 다음과 같이 기록한다.

 

다음 사이트에 안드로이드 튜토리얼이 있다.

 

http://developers.facebook.com/docs/mobile/android/build/

 

다음 페이지에 가서 새로운 앱을 등록하자.

 

create a new app on Facebook

 

허용여부를 묻는 화면에서 허용을 버튼을 클릭하자.

 

다음과 같은 화면이 나온다.

 

새 앱 만들기를 클릭하자.

 

 

App Display Name은 사용자에게 보여질 어플리케이션 이름이다.

 

App Namespace는 Open Graphic과 Canvas Page를 위한 개발 어플을 위한 네임스페이스이다.

 

계속하기를 클릭하면

 

 

자동 가입을 막기 위한 문자 입력 단계가 있다.

 

글을 입력하고 확인을 클릭한다.

 


가짜 아이디로 오해 받는 듯…

 

이렇게 좌절… 쩝

 

우선 테스트 계정으로 라도 연동해 봐야겠다.

 

http://developers.facebook.com/docs/test_users/

Posted by coolsharp
    static class SpriteEaseInOut extends SpriteDemo {
        public void onEnter()
        {
            super.onEnter();
       
            // 윈도우 크기 지정
            CGSize s = CCDirector.sharedDirector().winSize();
            // 5초동안 화면 크기 만큼 이동
            CCIntervalAction move = CCMoveBy.action(5, CGPoint.make(s.width,0));
       
            // 서서히 빨라졌다 다시 서서히 느려지는 액션 값을 2.0f로 셋팅
            CCIntervalAction move_ease_inout1 = CCEaseInOut.action(move.copy(), 2.0f);
            CCIntervalAction move_ease_inout_back1 = move_ease_inout1.reverse();
       
            // 서서히 빨라졌다 다시 서서히 느려지는 액션 값을 3.0f로 셋팅
            CCIntervalAction move_ease_inout2 = CCEaseInOut.action(move.copy(), 3.0f);
            CCIntervalAction move_ease_inout_back2 = move_ease_inout2.reverse();
       
            // 서서히 빨라졌다 다시 서서히 느려지는 액션 값을 4.0f로 셋팅
            CCIntervalAction move_ease_inout3 = CCEaseInOut.action(move.copy(), 4.0f);
            CCIntervalAction move_ease_inout_back3 = move_ease_inout3.reverse();
       
            // 0.25f 딜레이
            CCIntervalAction delay = CCDelayTime.action(0.25f);
       
            // 액션 대입
            CCIntervalAction seq1 = CCSequence.actions(move_ease_inout1, delay, move_ease_inout_back1, delay.copy());
            CCIntervalAction seq2 = CCSequence.actions(move_ease_inout2, delay.copy(), move_ease_inout_back2, delay.copy());
            CCIntervalAction seq3 = CCSequence.actions(move_ease_inout3, delay.copy(), move_ease_inout_back3, delay.copy());
       
            // 액션 시작
            tamara.runAction(CCRepeatForever.action(seq1));
            kathia.runAction(CCRepeatForever.action(seq2));
            grossini.runAction(CCRepeatForever.action(seq3));
        }
       
        public String title() {
            return "EaseInOut and rates";
        }
    }

Posted by coolsharp
    static class SpriteEase extends SpriteDemo {
        public void onEnter() {
            super.onEnter();
       
            CGSize s = CCDirector.sharedDirector().winSize();
            CCIntervalAction move = CCMoveBy.action(3, CGPoint.make(s.width-130,0));
            CCIntervalAction move_back = move.reverse();
   
            // 점점 느리게
            CCIntervalAction move_ease_in = CCEaseIn.action(move.copy(), 3.0f);
            CCIntervalAction move_ease_in_back = move_ease_in.reverse();
       
            // 점점 빠르게
            CCIntervalAction move_ease_out = CCEaseOut.action(move.copy(), 3.0f);
            CCIntervalAction move_ease_out_back = move_ease_out.reverse();
       
            CCIntervalAction delay = CCDelayTime.action(0.25f);
       
            CCIntervalAction seq1 = CCSequence.actions(move, delay, move_back, delay.copy());
            CCIntervalAction seq2 = CCSequence.actions(move_ease_in, delay.copy(), move_ease_in_back, delay.copy());
            CCIntervalAction seq3 = CCSequence.actions(move_ease_out, delay.copy(), move_ease_out_back, delay.copy());
       
       
            CCAction a2 = grossini.runAction(CCRepeatForever.action(seq1));
            a2.setTag(1);
       
            CCAction a1 = tamara.runAction(CCRepeatForever.action(seq2));
            a1.setTag(1);
       
            CCAction a = kathia.runAction(CCRepeatForever.action(seq3));
            a.setTag(1);
           
            schedule("testStopAction", 6.25f);
        }
       
        public void testStopAction(float dt) {
            unschedule("testStopAction");
            tamara.stopAction(1);
            kathia.stopAction(1);
            grossini.stopAction(1);
        }
       
        public String title() {
            return "EaseIn - EaseOut - Stop";
        }
    }

Posted by coolsharp

cocos2d for android - 클린업

2011. 10. 19. 14:13 : 개발
    static class Test5 extends TestDemo {

        public Test5() {
            super();

            // 스프라이트 생성
            CCSprite sp1 = CCSprite.sprite("grossinis_sister1.png");
            CCSprite sp2 = CCSprite.sprite("grossinis_sister2.png");

            // 위치 지정
            sp1.setPosition(CGPoint.make(100, 160));
            sp2.setPosition(CGPoint.make(380, 160));

            // 액션 설정
            CCIntervalAction rot = CCRotateBy.action(2, 360);
            CCIntervalAction rot_back = rot.reverse();
            CCAction forever = CCRepeatForever.action(
                    CCSequence.actions(rot, rot_back));
            CCAction forever2 = forever.copy();

            forever.setTag(101);
            forever2.setTag(102);

            addChild(sp1, 0, kTagSprite1);
            addChild(sp2, 0, kTagSprite2);

            sp1.runAction(forever);
            sp2.runAction(forever2);

            schedule("addAndRemove", 2.0f);
        }

        public void addAndRemove(float dt) {
            CCNode sp1 = getChildByTag(kTagSprite1);
            CCNode sp2 = getChildByTag(kTagSprite2);

            // 지우면서 클린업하지 않음
            removeChild(sp1, false);
            // 지우면서 클린업
            removeChild(sp2, true);

            // 다시 추가하면 액션이 진행됨
            addChild(sp1, 0, kTagSprite1);
            // 다시 추가하면 액션이 멈춤
            addChild(sp2, 0, kTagSprite2);
        }

        public String title() {
            return "remove and cleanup";
        }
   

Posted by coolsharp