Android app에서 Twitter 연동하기 (개선-pincode를 받아와서 인증하자)

안녕하세요 지헌입니다.
원래 녹음기가 끝나면 동적 컨트롤 추가를 해보려고 했는데
막간을 이용해 트위터 연동 앱을 한번 더 수정해보도록 하겠습니다.
이번에는 트위터 인증을 할때 웹브라우져 방식이 아니라
pin 코드를 받아와서 인증하는 방식으로 변경해보겠습니다.
이 방식을 사용할 경우 콜백 URL이 필요 없어지고 앱이 더
깔끔해지는것 같습니다.

소스코드는 바로 전에 올린
Android app에서 Twitter 연동하기 (개선-로그인을 한번만 하자) 에서 작성한 코드를
수정해서 사용하겠습니다. (트위터에 앱 등록절차부터 궁금하신 분은 제가 올린
이전의 트위터 연동 글을 참고하시기 바랍니다.)

먼저 트위터사이트에 들어가서 등록한 앱의 설정을 바꿔야 합니다.
다음처럼 어플리케이션 타입을 Client로 바꿔 줍니다.


다음은 TwitterLogin.java 파일을 수정하겠습니다.
다음이 전체 소스입니다. (패키지명은 좀 틀릴 수 있습니다.
각자 프로젝트를 만드시는 분들에 따라 다들 틀려지겠지요
저는 이번 예제를 만들면서 소스는 이전에 제가 만든걸
거의 그대로 가져다 썼지만 프로젝트는 새로 만들어서
패키지명을 com.android.twittercon3 으로 주었습니다.
프로젝트를 새로 만드셨다면 매니페스트에 인터넷 퍼미션
주는것을 잊으시면 안됩니다.)
************************ TwitterLogin.java ***********************
package com.android.twittercon3;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class TwitterLogin extends Activity
{
  // INTENT
  Intent mIntent;
 
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.twitter_login);
    WebView webView = (WebView) findViewById(R.id.webView);
    webView.getSettings().setJavaScriptEnabled(true);
    webView.addJavascriptInterface(new JavaScriptInterface(), "PINCODE");
   
    // 화면 전환시 WebView에서 화면 전환하도록한다.
    // 이렇게하지 않으면 표준 브라우저가 열려 버린다.
    webView.setWebViewClient(new WebViewClient()
    {
      public void onPageFinished(WebView view, String url)
      {
        // page 렌더링이 완료되면 호출됨.
        super.onPageFinished(view, url);
        Log.v(C.LOG_TAG, "On Page Finished URL : " + url.toString());
        view.loadUrl("javas-ript:window.PINCODE.getPinCode(document.getElementById('oauth_pin').innerHTML);"); // 이글루 편집기의 이상으로 오타가 나고 있습니다. javas-ript 가 아니라 자바스크립트(영어로 쓰셔야되요ㅠㅠ) 입니다. 
      }
    });

    mIntent = getIntent();
    String url1 = mIntent.getStringExtra("auth_url");
   
    webView.loadUrl(url1);
  }
 
  class JavaScriptInterface
  {
    public void getPinCode(String pin)
    {
      if (pin.length() > 0)
      {
        mIntent.putExtra("pin_code", pin);
        setResult(RESULT_OK, mIntent);
        finish();
      }
      else
      {
        Log.v(C.LOG_TAG, "get pin failed...");
      }
    }
  }
}
****************************************************************
위의 코드를 보시면 아시겠지만 웹뷰에서 자바스크립트를 사용가능하게
설정하고 있습니다.
webView.getSettings().setJavaScriptEnabled(true);
그리고 인너 클래스로 자바스크립트와 웹뷰를 연결시켜주는 클래스를 
하나 만들어서 웹뷰에 연결시켜주고 있습니다. 
webView.addJavascriptInterface(new JavaScriptInterface(), "PINCODE");

그리고 onPageFinished 메서드에서
view.loadUrl("javas-ript:window.PINCODE.getPinCode(document.getElementById('oauth_pin').innerHTML);");
이렇게 호출하는 것으로 getPinCode 가 호출되게 됩니다.
getPinCode는 웹뷰에서 보이는 핀코드 값을 가지고 오게 되고
그와 동시에 인텐트에 그 값을 넣고 액티비티를 끝내고 있습니다.

____________________________________________________________________
참고로 인너클래스에서 바깥쪽(?)클래스의 멤버변수에 접근하고자 할경우
바깥쪽 클래스의 멤버변수는 접근제한자를 주지 않는것이 좋습니다.
그냥 아무런 접근 제한자를 주지 말고(디폴트값) 선언하게 되면
멤버변수가 패키지 범위로 설정되고 이렇게 되면 내부적으로
클래스파일로 변경되는 시점에 불필요한 합성 메서드가 생성되지
않으므로 속도가 더 빨라집니다.
여기서는
Intent mIntent;
위의 변수 선언에서 그렇게 하고 있습니다.
____________________________________________________________________

그러면 이 로그인 액티비티를 부른 TwitterCon3.java 에서 받아서 처리하면 되겠지요

TwitterCon3.java 소스는 다음과 같습니다.
여기서는 onActivityResult 쪽만 수정되었습니다. (아마 맞을겁니다.
소스를 일일히 비교할 수가 없어서리 ㅠㅠ)
TwitterLogin 액티비티로 부터 pin코드를 받아서
그 핀코드를 이용해서 mAccessToken 을 만들고 있습니다.
어차피 만들어 주는것은 이전 방식으로 하던 핀코드를 이용하건
mAccessToken을 만들어야 하는것은 변함이 없으므로
onActivityResult 만 변경점이 있고 나머지는 그대로 사용하면 되겠습니다.
**************************TwitterCon3.java***************************
package com.android.twittercon3;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import twitter4j.conf.Configuration;
import twitter4j.conf.ConfigurationBuilder;
import twitter4j.auth.AccessToken;
import twitter4j.auth.OAuthAuthorization;
import twitter4j.auth.RequestToken;
import twitter4j.media.ImageUpload;
import twitter4j.media.ImageUploadFactory;
import twitter4j.media.MediaProvider;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class TwitterCon3 extends Activity implements View.OnClickListener
{
  private Twitter mTwitter;
  private RequestToken mRqToken;
  private AccessToken mAccessToken;
  private Button mBtnLogin, mBtnFeed, mBtnLogout;
  private EditText mEtContent;
 
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
   
    mEtContent = (EditText) findViewById(R.id.etContent);
   
    mBtnLogin = (Button) findViewById(R.id.btnLogin);
    mBtnFeed = (Button) findViewById(R.id.btnFeed);
    mBtnLogout = (Button) findViewById(R.id.btnLogout);
   
    mBtnLogin.setOnClickListener(this);
    mBtnFeed.setOnClickListener(this);
    mBtnLogout.setOnClickListener(this);
  }
 
  @Override
  public void onClick(View v)
  {
    switch(v.getId())
    {
      case R.id.btnLogin: // Twitter login
        login();
        break;
      case R.id.btnFeed:  // Twitter 글쓰기
        write();
        break;
      case R.id.btnLogout: // Twitter logout
        logout();
        break;
      default:
        break;
    }
  }
 
  private void login()
  {
    try
    {
      String accessToken = Util.getAppPreferences(this, C.TWITTER_ACCESS_TOKEN);
      String accessTokenSecret = Util.getAppPreferences(this, C.TWITTER_ACCESS_TOKEN_SECRET);

      if (accessToken != null && !"".equals(accessToken) && accessTokenSecret != null && !"".equals(accessTokenSecret))
      {
        mAccessToken = new AccessToken(accessToken, accessTokenSecret);
       
        Log.v(C.LOG_TAG, "accessToken : " + mAccessToken.getToken());
        Log.v(C.LOG_TAG, "accessTokenSecret : " + mAccessToken.getTokenSecret());
      }
      else
      {
        ConfigurationBuilder cb = new ConfigurationBuilder();
        cb.setDebugEnabled(true);
        cb.setOAuthConsumerKey(C.TWITTER_CONSUMER_KEY);
        cb.setOAuthConsumerSecret(C.TWITTER_CONSUMER_SECRET);
        TwitterFactory factory = new TwitterFactory(cb.build());
        mTwitter = factory.getInstance();
        mRqToken = mTwitter.getOAuthRequestToken();
        Log.v(C.LOG_TAG, "AuthorizationURL >>>>>>>>>>>>>>> " + mRqToken.getAuthorizationURL());
       
        Intent intent = new Intent(this, TwitterLogin.class);
        intent.putExtra("auth_url", mRqToken.getAuthorizationURL());
        intent.putExtra("request_token", mRqToken.toString());
        startActivityForResult(intent, C.TWITTER_LOGIN_CODE);
      }
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }
 
  private Configuration getConfiguration(String apiKey)
  {
    return new ConfigurationBuilder().setMediaProviderAPIKey(apiKey).build();
  }
 
  private void write()
  {
    String path = Environment.getExternalStorageDirectory().getAbsolutePath();
    String fileName = "example.jpg";
    InputStream is = null;
   
    try
    {
      if (new File(path + File.separator + fileName).exists())
        is = new FileInputStream(path + File.separator + fileName);
      else
        is = null;

      ConfigurationBuilder cb = new ConfigurationBuilder();
      String oAuthAccessToken = mAccessToken.getToken();
      String oAuthAccessTokenSecret = mAccessToken.getTokenSecret();
      String oAuthConsumerKey = C.TWITTER_CONSUMER_KEY;
      String oAuthConsumerSecret = C.TWITTER_CONSUMER_SECRET;
      cb.setOAuthAccessToken(oAuthAccessToken);
      cb.setOAuthAccessTokenSecret(oAuthAccessTokenSecret);
      cb.setOAuthConsumerKey(oAuthConsumerKey);
      cb.setOAuthConsumerSecret(oAuthConsumerSecret);
      Configuration config = cb.build();
      OAuthAuthorization auth = new OAuthAuthorization(config);
     
      TwitterFactory tFactory = new TwitterFactory(config);
      Twitter twitter = tFactory.getInstance();
      ImageUploadFactory iFactory = new ImageUploadFactory(getConfiguration(C.TWITPIC_API_KEY));
      ImageUpload upload = iFactory.getInstance(MediaProvider.TWITPIC, auth);
     
      if (is != null)
      {
        String strResult = upload.upload("example.jpg", is, mEtContent.getText().toString());
        twitter.updateStatus(mEtContent.getText().toString() + " " + strResult);
      }
      else
        twitter.updateStatus(mEtContent.getText().toString());
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
    finally
    {
      try
      {
        is.close();
      }
      catch (Exception e)
      {}
    }
  }
 
  private void logout()
  {
    Intent intent = new Intent(this, TwitterLogin.class);
    intent.putExtra("auth_url", C.TWITTER_LOGOUT_URL);
    startActivity(intent);
  }
 
  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data)
  {
    super.onActivityResult(requestCode, resultCode, data);
   
    // 액티비티가 정상적으로 종료되었을 경우
    if(resultCode == RESULT_OK)
    {
      if (requestCode == C.TWITTER_LOGIN_CODE)
      {
        try
        {
          Log.v(C.LOG_TAG, "Twitter Pin Code : " + data.getStringExtra("pin_code"));
          mAccessToken = mTwitter.getOAuthAccessToken(mRqToken, data.getStringExtra("pin_code"));
         
          Util.setAppPreferences(this, C.TWITTER_ACCESS_TOKEN, mAccessToken.getToken());
          Util.setAppPreferences(this, C.TWITTER_ACCESS_TOKEN_SECRET, mAccessToken.getTokenSecret());
        }
        catch (Exception e)
        {
          e.printStackTrace();
        }
      }
    }
  }
}
*********************************************************************

이렇게 코딩하고 실행하면 트위터 인증이 다음처럼 바뀝니다.

강좌대로 코딩을 하셨다면 위의 창이 잠깐 보였다가 사라지면서 원래 화면으로 돌아갈
것입니다.
그리고 글을 쓰면 글이 올라가는것을 확인 할 수 있습니다. ^^

참고로 이상까지 마친 프로젝트는 다음처럼 구성되어야 합니다.

이상으로 트위터 연동을 마무리 하겠습니다.
도움 되셨다면 리플 하나씩 남겨주시는 센스!!!! ^^

참고로 Util 클래스와 C.java 클래스 소스와
나머지 레이아웃 xml 파일도 올립니다.
****************************** Util.java *********************************
package com.android.twittercon3;

import android.app.Activity;
import android.content.SharedPreferences;

public class Util
{
  // 전체 어플에 공용으로 적용되는 SharedPreferences에 Key, Value로 값을 저장한다. Value는 String이다.
  public static void setAppPreferences(Activity context, String key, String value)
  {
    SharedPreferences pref = null;
    pref = context.getSharedPreferences(C.LOG_TAG, 0);
    SharedPreferences.Editor prefEditor = pref.edit();
    prefEditor.putString(key, value);
   
    prefEditor.commit();
  }
 
  // 전체 어플에 공용으로 적용되는 SharedPreferences에서 String 값을 가져온다. 
  public static String getAppPreferences(Activity context, String key)
  {
    String returnValue = null;
   
    SharedPreferences pref = null;
    pref = context.getSharedPreferences(C.LOG_TAG, 0);
   
    returnValue = pref.getString(key, "");
   
    return returnValue;
  }
}

************************************************************************

*******************************C.java***********************************
package com.android.twittercon3;

public class C
{
  public static final String LOG_TAG = "TwitterCon";
  public static final String TWITTER_API_KEY = "트위터 API Key";
  public static final String TWITPIC_API_KEY = "트윗픽 API Key";
  public static final String TWITTER_CONSUMER_KEY = "트위터 컨슈머 키";
  public static final String TWITTER_CONSUMER_SECRET = "트위터 컨슈머 시크릿 키;
  public static final String TWITTER_CALLBACK_URL = "http://m.daum.net";
  public static final String MOVE_TWITTER_LOGIN   = "com.android.twittercon.TWITTER_LOGIN";
  public static final int TWITTER_LOGIN_CODE = 10;
  public static final String TWITTER_LOGOUT_URL = "http://api.twitter.com/logout";
  public static final String TWITTER_ACCESS_TOKEN = "twitter_access_token";
  public static final String TWITTER_ACCESS_TOKEN_SECRET = "twitter_access_token_secret";

  public static final boolean D = true;
}
************************************************************************

main.xml 은 다음과 같습니다.
*****************************main.xml**********************************
<?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"
    android:padding="5dp"
    >
 <EditText
  android:id="@+id/etContent"
  android:layout_width="fill_parent"
  android:layout_height="100dp"
  android:padding="5dp"
  android:textSize="16sp"
  android:gravity="top"
  android:typeface="monospace"
  android:scrollbars="vertical"
  android:background="#FFFFFF"/>

 <LinearLayout
     android:orientation="horizontal"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:padding="5dp"
     android:gravity="center_vertical|center_horizontal"
     >
  <Button
    android:id="@+id/btnLogin"
   android:layout_width="70dp"
   android:layout_height="wrap_content"
   android:text="Login"/>
  <Button
    android:id="@+id/btnFeed"
   android:layout_width="70dp"
   android:layout_height="wrap_content"
   android:text="Write"/>
  <Button
    android:id="@+id/btnLogout"
   android:layout_width="70dp"
   android:layout_height="wrap_content"
   android:text="Logout"/>
 </LinearLayout>

</LinearLayout>
************************************************************************

twitter_login.xml 은 다음과 같습니다.
**************************twitter_login.xml*******************************
<?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"
    >
 <WebView
  android:id="@+id/webView"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:layout_weight="1"
 />
</LinearLayout>
************************************************************************

마지막으로 매니페스트 파일입니다.
************************************************************************
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.twittercon3"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".TwitterCon3"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
       
  <!-- ACT : Twitter Login -->
        <activity android:name=".TwitterLogin" android:label="Twitter Login"
         android:screenOrientation="portrait"
         android:windowSoftInputMode="stateHidden"
         android:configChanges="orientation|keyboardHidden"
         android:theme="@android:style/Theme.NoTitleBar">
   <intent-filter>
    <action android:name="com.android.twittercon.TWITTER_LOGIN" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
   </intent-filter>
  </activity>
    </application>
    <uses-sdk android:minSdkVersion="7" />
 <uses-permission android:name="android.permission.INTERNET" />
</manifest>
************************************************************************

by 선지헌 | 2011/04/20 15:16 | Android | 트랙백(1) | 덧글(75)

트랙백 주소 : http://jeehun.egloos.com/tb/4024992
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Tracked from appchemist님의.. at 2011/05/10 13:17

제목 : 안녕하세요, twitter4j 예제 소스 잘 활용하..
Twitter4j를 사용하여 트위터로 글을 쓰는건잘 되는데 그림을 twitpic으로 업로드 할려고 하니 계속 해서 아래와 같은 애러가 뜨네요 Upload.upload 부분에서 애러가 발생합니다.아무리 찾아봐도 모르겠어05-10 13:07:43.589: WARN/System.err(30968): Not trusted server certificateRelev...more

Commented by 민병수 at 2011/04/21 17:30
친절한 설명 감사드립니다.
트위터 않쓰는 어플 개발자인데 ^^; 처음 트위터 연동하라해서 api 보기 싫어 검색하다 여기까지 오게 되었는데 바로끝났네요. 이러면 안되는거 알지만 거저 먹어서 죄송합니다. ^^; 감사해요~~!!

Commented by 선지헌 at 2011/04/22 15:55
넵 도움 되셨다니 기쁩니다. ^^
Commented by 강렬눈썹 at 2011/04/22 11:30
오홋 +_+ 클라이언트도 궁금했는데 고맙습니다. 곧 테스트 해볼게요 ㅋㅋㅋ
Commented by 선지헌 at 2011/04/22 15:55
넵.. 성공하시길 바랍니다. ^^
Commented by arissgo at 2011/04/24 04:00
좋은 자료 감사합니다ㅎ
근데 테스트 해보니까 Login 버튼 클릭시 웹뷰로 잠깐 로그인화면떳다가 바로 웹페이지를 표시할 수 없습니다.라고 뜨더라고요ㅠ
Log를 확인 해보니
On Page Finished URL : javas-ript:window.PINCODE.getPinCode(document.getElementById('oauth_pin').innerHTML);
가 계속 뜹니다ㅜ 뭐가 문제일까요??ㅜ
Commented by arissgo at 2011/04/24 04:03
자문자답이네요ㅎ
위에 TwitterLogin.java 소스 부분에 view.loadUrl 부분에 오타가 잇네요^^;
javas-ript -> javascript로 고치니까 해결됩니다ㅎ
Commented by 선지헌 at 2011/04/25 10:28
그렇네요 오타가 났었네요 근데 이글루 편집기기 이상한지 제대로 써서 올려도 저렇게 변형이 되어 버리네요 ㅠㅠ
Commented by arissgo at 2011/04/24 04:15
logout 시 url이 http://api.twitter.com/logout 인데
폰에서 실행시 mobile주소로 변경되면서 logout이라는 계정에 연결됩니다.
정확한 url이 어떻게 되나요?ㅜ
Commented by 선지헌 at 2011/04/25 10:51
트위터 로그아웃 페이지가 새롭게 리뉴얼 된것 같습니다. 사실 로그아웃 이라는 메서드를 API차원에서 제공하지 않고 있어서 문제가 되는건데요 로그아웃은 조금 더 살펴봐야만 될듯 하네요 ㅠㅠ
Commented by 홍진 at 2011/04/25 16:52
로그아웃 url을 http://api.twitter.com/logout 이거하니깐 모바일주소로변경되더군염

그냥 http://twitter.com/logout로 적어주니간잘돼던데용 ㅋ
Commented by 선지헌 at 2011/04/25 17:12
구래요? 저는 그렇게 했더니 logout 이라는 트위터 계정으로 연결되어 버리던데... ㅠㅠ
Commented at 2011/04/27 05:06
비공개 덧글입니다.
Commented by 선지헌 at 2011/04/27 10:13
앱을 보지 못해서 잘 모르겠네요 ^^;;;
Commented by 홍진 at 2011/04/27 14:48
음 왜 다다르져..??ㅋㅋ지헌님강좌보구만든곤데 ㅠㅠ똑같이ㅜㅋㅋ
아 로그아웃 웹에서하는거말고
다른방법은없을까여 ㅠㅠ찾기가힘드네여ㅓ아ㅓㄴ
Commented by 선지헌 at 2011/04/27 17:18
?? 뭐가 다르다는 말씀이세요? 음음..???
Commented by 해준 at 2011/04/29 17:35
많은 도움 된 강좌입니다.
제가 처리한 logout 메소드 공유해 드릴게요.

private void logout() {
TwitterUtil.setAppPreferences(this,
TwitterConstants.TWITTER_ACCESS_TOKEN, null);
TwitterUtil.setAppPreferences(this,
TwitterConstants.TWITTER_ACCESS_TOKEN_SECRET, null);
//clearApplicationCache(null);
CookieManagercm=CookieManager.getInstance();
cm.removeSessionCookie();

cm.setCookie("twitter.com", "");
String cookie=cm.getCookie("twitter.com");
Log.v("cookie","twitter cookie :"+cookie);

intent.putExtra("account", "");
intent.putExtra("type", "T");
setResult(RESULT_OK, intent);
setFinish();
// Intent intent = new Intent(this, TwitterLogin.class);
// intent.putExtra("auth_url", TwitterConstants.TWITTER_LOGOUT_URL);
// startActivity(intent);
}
Commented by 해준 at 2011/04/29 17:38
글이 잘 안올라가네요..
쿠키메니저 클래스에서 세션 쿠키를 날렸습니다. 근데 로그로 트위터 쿠키 정보를 찍으면 여전히 남아 있는 것으로 보아.. 세션만 날리면 어느정도 만족스럽게 로그아웃이 이루어 지네요.. 쿠키매니저는 스테이틱한 녀석이라 그냥 사용하셔도 됩니다.
Commented by 민병수 at 2011/05/02 14:14
지헌님 하나 물어볼께 있는데요, twitpic API 보니깐 거기선 인증방식 없이 ID/PW만 넣으면 바로 글올리는 API가 있더군요. 그래서 바로 글 올릴땐 그걸 사용해서 ID값 쉽게 화면에 뿌릴수 있는데,, 제가 모르는 부분이 위의 방식에서 key값으로 인증할때사용자 ID를 뿌려주려고 할때 어떻게 접근해야하는지 잘 모르겠는데 혹시 ID및 PW얻어 내는 메소드가 따로 있나요?
못찾아서요^^; 알고 있으면 조언 부탁좀 드릴께요^^; 얻어가기만 해서 미안하네요.
Commented by 선지헌 at 2011/05/02 17:06
twiipic은 xauth를 아직 지원하나 보네요 최근 그렇게 id/pw 만 넣고 접근하는 방식(xauth)는 거의 없어지는 추세인데... 근데 id/pw 를 얻어오고 싶다는거는 트위픽 말고 트위터 로그인할때 말씀이신가요? 트위터는 xauth를 현재 지원하지 않기때문에(지원은 합니다만 이걸 쓰려면 트위터에 메일 보내서 사유를 설명해야 합니다.) xauth 방식으로 인증은 사실상 힘들구요 id/pw를 얻어오는 방법은 저두 아직 잘 모르겠습니다. 근데 api의 결과값으로 pw를 얻어와버리면 그건 좀 위험하지 않을까 생각이 드네요 id는 어떻게 얻어올 수 있으려나... 그부분은 저도 안해봐서 정확히는 모르겠습니다. ^^;;;
Commented by 민병수 at 2011/05/02 18:17
친절한 설명 감사합니다. 고객사에서 원하는데로 해주다 보니, 추세도 뭐고 간에 일단
구현하고보자는 어리석은 프로그래머입니다...ㅠㅠ
트위터 API보지는 않고 지헌님 설명 들어본결과 WebView에서 ID/PW 입력하고 버튼클릭할때 그때 값을 낚아채야겠네요. 그리고 그걸 DB로 저장해놔야 쓸수가 있고요.
하지만 그럴려면 시간이 좀 걸려서 일단
웹에서 토큰 받아오고 나서 mTwitter.getScreenName() 사용하면 ID는얻어 올수는 있네요. 정확히 말하자면 메일주소가 들어간 ID가 아니라 @제외한 ID가 나오네요.
추후에 시간 나면 웹뷰에서 낚아채야 겠네요.
제가 실은 급히 어플 개발하느라 트위터 API는 보지도 않고 지헌님 소스 컨닝해서 연동했습니다.^^; 죄송합니다... 꾸벅.... 나중에 흥미가 있으실만한 주제 있으시다면 소스 공유해드릴께요^^ 이래뵈도 노루페인트,부동산 114,, BindApp등 여러 어플을 개발해서 모듈이 많이 있습니다. 아무튼 하찮은 질문에 답변 달아주셔서 정말 감사드립니다.
Commented by 선지헌 at 2011/05/02 19:16
아닙니다. 죄송하시긴여, 저역시 안드로이드 초보고 도움이 되셨다니 제가 기쁩니다. 나중에 저도 도움 받을 수도 있을테구요 ^^ 여하튼 글 남겨주셔서 감사합니다. ^^
Commented by caprisun at 2011/05/09 15:31
안녕하세요 지허님의 강좌를 보고 따라하고 있는데 글을 잘 올라가는데 이미지 업로드는 왜 안될까요 ㅠㅠ not trusted server certificateRelevant 에러 나네요
Commented by 마니산 at 2011/05/14 17:26
안녕하세요 저도 트윗 연동앱을 만드느라 애먹는데 님의글을 보고 큰 도움을 받고 있습니다 그런데 라이브러리 설정과 소스코드를 똑같이 해놓고 실행하는데도 글이 안올라가는데 정말 이상해요 뭐가 잘못됐을까요?
Commented by 마니산 at 2011/05/14 21:08
화면상으로 웹페이지에서는 pincode를 보여주면서 리다이렉트가 되는데 로그캣을 통해서 보면 pincode값이 안찍히는데 여기서 문제가 있는것 같아요
Commented by 마니산 at 2011/05/15 18:50
죄송합니다 제가 트윗개발자등록때 read-only를 선택하는 바람에 생긴 결과였습니다 read-Write로 바꾸니 바로 되는군요 결국 제가 차분하지못해 생긴 문제입니다 그런데 트윗에서는 굳이 read-only도 선택하게한 이유가 뭔지 모르겠네요
Commented by 선지헌 at 2011/05/16 10:35
그러시군요 ^^ 해결 되셨다니 다행입니다.
Commented by 송지훈 at 2011/05/17 13:59
안녕하세요. 우선 덕분에 좋은강좌보고 좋은공부가 되었습니다
정말 감사드립니다.
질문드리고 싶은게 있는데요.
웹뷰가 뜨고 어플리케이션 승인을 누르면
pin code를 보여주는 웹페이지로 이동합니다.
로그에는 <code>9340839<code> 이런식으로 pin code값이 찍히는것 같은데요.
이게 똑바로 실행이 된건지 잘 모르겠어서 질문드립니다.
그리고 만약 pin code값을 저장하였다면 웹페이지가 자동으로 finish() 되는
구현은 어디서 할 수 있을지 궁금합니다
항상 건강하시고 좋은하루 되시기 바랍니다 :)
Commented by 선지헌 at 2011/05/17 14:02
본 게시물의 TwitterLogin.java 에서 자동 종료하는 코드가 구현되어 있습니다. class JavaScriptInterface 쪽을 참고하시기 바랍니다.
Commented by 송지훈 at 2011/05/17 14:36
답변 감사드립니다^^
지헌님 소스를 보고 따라했는데 이상하게 제가뭔가 잘못건드린건지
웹뷰를 피니시 시키는 부분만 유일하게 잘 안되네요.
조금더 유심히 살펴보고 해결하겠습니다. 정말 감사합니다.
Commented by 송지훈 at 2011/05/17 15:22
if (pin.length() > 0)
{
mIntent.putExtra("pin_code", pin);
setResult(RESULT_OK, mIntent);
finish();
이부분이 웹뷰의 종료여부를 판단해주는곳이었군요.
소스를 복사하지않고 일일히 타이핑하다보니 제가 오타가 있었습니다.
덕분에 정말많이 공부하게되서 감사드립니다. 언제나 좋은하루 되시길 바랄게요 ^^
Commented by 선지헌 at 2011/05/17 18:42
잘 해결 되셨다니 다행입니다. ^^
Commented by leehakjje at 2011/05/17 18:00
너무 너무 감사합니다
정말 3일의 밤생이 이곳에서 5시간으로 해결되어버리다니요!!
감사합니다!!
Commented by 선지헌 at 2011/05/17 18:42
도움되셨다니 제가 다 기쁘네요 ^^
Commented by 바보학생 at 2011/05/25 20:21
아.. 정말 컴퓨터 관련 학과 다니는데에도 코드짜는거에 정말 어려움을 많이 느끼는
허접한 학생인데 이렇게 상세한 자료 올려주셔서 감사드립니다..ㅠ.ㅠ
자주 찾아뵙도록 하겠습니다.
더 염치불구하고 좋은자료 많이많이 올려주시길 부탁드립니다...ㅋ
Commented by 선지헌 at 2011/05/25 20:38
도움 되셨다니 기쁘네요 ^^ 별건 없지만 자주 찾아오시면 저야 고맙지요 ^^
Commented by 바보학생 at 2011/05/25 20:56
헐 실시간 강좌 수강중인데 실시간 댓글이..감사합니다.


오신 김에 조심스레 여쭤봅니다..

현재 마켓에 등록되어있는

트위터 앱을 실행해보면 GPS정보를 넣어서 글을 쓸수있도록 되어있던데요

이 기능을 구현해서 위치정보를 토대로 트윗 검색을 하는것 목표라서..

이 점에 대해서 조언을 구하고 싶습니다

혹은 참고할 만한 자료라던지요...

오늘 처음 찾아와서 너무 건방진건 아닌지...

Commented by 선지헌 at 2011/05/26 01:26
GPS로 현재 좌표 (위도, 경도)를 불러와서 이것으로 주소를 불러와서 트위터에 올린다 라는 건가요? 별루 어려운건 아닌데요 빠른 시일내에 정리해 보도록 하겠습니다. ^^
Commented by andromedaa at 2011/05/28 18:05
이전 트위터 강좌 따라해 보면서 잘 하고 있었는데...

왜 이번 것은 계속 401:Authentication credentials (http://dev.twitter.com/pages/auth) were missing or incorrect. Ensure that you have set valid conumer key/secret, access token/secret, and the system clock in in sync.
이런 에러가 나는건지.. 흑흑

pin.length() > 0 if문 안쪽은 타는데 pin값 로그를 찍어보면 값이 없네요..ㅠㅠ
Commented by 선지헌 at 2011/05/29 02:37
트위터 pincode 값으로 로그인 하는 결과 페이지가 다시 리뉴얼 된 모양입니다.
저도 찍어보니 예전에는 pin 값에 코드값만 들어왔었는데 이번엔 코드가 포함된 스트링(html)이 통으로 들어오더군요 pin코드를 자동으로 가져오는 것은 아무래도 꼼수같은 거였으니까요 이런식으로 트위터의 페이지가 변경되어 버리면 에러가 날 수 밖에 없네요
Commented by 답답 at 2011/05/30 12:45
안녕하세요. 강좌 잘보고 있는데요 궁금한게 하나 있어서요.

TwitterLogin 액티비티에서 pin값을 가져오면

05-30 12:40:49.867: DEBUG/sotong(1161): <p>
05-30 12:40:49.867: DEBUG/sotong(1161): <span id="code-desc">이제 TheSotong_android 앱으로 돌아가 다음의 PIN을 입력하면 승인 절차가 완료됩니다:</span>
05-30 12:40:49.867: DEBUG/sotong(1161): <kbd aria-labelledby="code-desc"><code>2780062</code></kbd>
05-30 12:40:49.867: DEBUG/sotong(1161): </p>

이런식으로 값이 들어오는데 이렇게 들어오는게 맞는건가요?

제생각엔 <code>2780062</code> 또는 2780062만 나와야 정상일 것 같아서요..

이것 때문인지 Login() 함수 안의
String accessToken = Util.getAppPreferences(this,Twit.TWITTER_ACCESS_TOKEN);

구문에서도 토큰 값이 넘어오질 못하고 자꾸 null값만 들어오는게 죽겠습니다ㅠㅠ

확인 부탁드립니다..
Commented by 답답 at 2011/05/30 12:53
아..바로 윗글에 같은 내용이 있었네요...죄송합니다.;;
Commented by 솔로독백 at 2011/05/30 14:57
으헝 ㅠㅠ

계속 pin code 값을 못 받아와서 혹시나 해서 보니깐

html에 oauth_pin 아이디가 없어졌네요 ㅠㅠ
Commented by 선지헌 at 2011/05/30 16:36
현재는 아마 pin 이라는 스트링 변수에 다음처럼 값이 들어올겁니다.
<p>
<span id="code-desc">이제 TheSotong_android 앱으로 돌아가 다음의 PIN을 입력하면 승인 절차가 완료됩니다:</span>
<kbd aria-labelledby="code-desc"><code>2780062</code></kbd>
<p>

원래는 pin 이라는 스트링 변수에 pincode 값만 들어왔었는데 어느순간부터 트위터 핀코드 보여주는 웹 소스가 리뉴얼 되었는지 저렇게 스트링이 통으로 들어오더군요 저두 확인해봤습니다만... 걍 귀찮아서 웹방식 로그인 쓰려구요 ㅠㅠ
Commented by 솔로독백 at 2011/05/30 16:50
아 젠장 -_-;;;

저는 html소스 로그 찍어서 봤는데 oauth_pin이 없는거에요

그래서 아 리뉴얼되서 그렇구나 라고 생각하고 있는데...

계속 삽질을 하고 있는데 제 어플이 browser로 설정되있었음 -_-;;;

분명히 client로 처음에 설정했었는데 ...

pincode는 파싱해서 가져와야겠네요

너무 엉뚱한 곳에서 삽질을 한것 같아요 ㅎㅎ

댓글 감사요
Commented by 도전!만국기 at 2011/06/01 16:54
<p><spanid="code-desc">Next,returntoflagsOfAllNationsandenterthisPINtocompletetheauthorizationprocess:</span><kbdaria-labelledby="code-desc"><code>5745187</code></kbd></p>

핀코드가 이런 형식으로 올라오면서... mAccessToken 널로 떨어지면서..

401:Authentication credentials were missing or incorrect. 에러가 올라들 오실텐데..

혹시나 필요한 분들, 파싱하는 부분 공유 드릴께요 허접하지만 ^^;

int tagFront = pin.indexOf("<code>") + 6 ; // index는 "<code>"를 더해서 잡는다.
StringBuilder sb = new StringBuilder(pin);
sb = sb.delete(0, tagFront);// Tag 앞까지 삭제!

String reminderStr = sb.toString();
int tagBack = reminderStr.indexOf("</code>");// 요놈의 맨앞자리 인덱스 가져와라!

sb = sb.delete(tagBack, reminderStr.length());// 닫는 Tag부터 삭제

Log.w("test", "toss pincode : "+sb.toString());
Commented by 선지헌 at 2011/06/01 23:50
^^ 감사합니다.
Commented by 초보 ㅜ at 2011/06/02 19:29
처음 화면에서 로긴 버튼 누르고
트위터 아이디랑 비번 치는 화면 나올때
아이디 입력하려구 아이디 칸을 터치하면
다시 초기화면으로 돌아가버려요 ㅜㅜ
Commented by 바보학생 at 2011/06/08 03:09
로그아웃 문제로 골머리 앓고 있었는데 @해준 님이 올려주신 참고소스보고
해결했네용!! 감사드립니다.__)//

물론 선지헌님께도 무한한 감사의 마음을..__);;꾸벅

제가 구현하고 있는 어플의 기능은..

증강현실 상에 지오태그가 존재하는 트윗을 뿌려주고(트윗들이 공중에 둥둥 ㅎㅎ;)

이미지링크가 존재한다면 이미지링크를 파싱해서 같이 뿌려주고..(이부분은..당최..ㅠ)
(이부분까지는 트윗4j랑은 상관없긴 하죠 ㅋ)

거기에 추가로

현재 사용자가 있는 위치정보가 담긴 트윗(+이미지)을 작성해서 업로드 하는 기능의

앱을 목표로 하고 있었는데..

증강현실 부분은 LBS AR 엔진을 잘 구해서 쉽게 구현했는데,
(웹 이미지 주소 파싱해서 섬네일로 뿌려주는 부분은 반 포기상태 ㅠㅠ..)

나머지부분 구현(트위터부분)에 난항을 겪다가

선지헌님이 올려주신 강좌보면서 제가 구현하고자 한 형태로

조금씩 수정했더니.. 어느정도 끝이 보여가네요 ㅠㅠ
Commented by 김성중 at 2011/06/13 18:07
진짜 너무 감사해요 자바도 취약하고 안드로이드도 초보인 저로서는
디테일한 설명에 중간중간 노하우까지(참고로 인너클래스에서 .....이하생략)
함께 포스팅해주셔서 너무 잘 배우고 있습니다^^
Commented by 달이랍니다 at 2011/06/20 11:46
잘 구현해서 사용하고 있는데..질문 하나 드립니다ㅠ
안되는 부분이 있어서요ㅠ
애뮬에서는 무리없이 잘 돌아가는데
폰에서 로그인할때 웹뷰가 그냥 꺼져버립니다ㅠ
로그아웃할때도 마찮가지로 그냥 꺼져버리고요..
왜 그러는지 도통 모르겠습니다..ㅠㅠ
Commented by 선지헌 at 2011/06/20 11:50
로그를 좀 봐야겠는데요 저는 갤탭, 모토로이, 갤럭시 에스, 디자이어 에서 다 잘 돌아가는지라... ㅠㅠ
Commented by 달이랍니다 at 2011/06/20 12:03
음..어떤 로그를 보여드리면 될까요?ㅠ
애뮬에서 로그캣으로 찍은거 보여드리면 되나요?ㅠㅠ
Commented by 달이랍니다 at 2011/06/20 13:58
자답입니다..
소스 코드 건들다가..제가 실수로 visibility 부분을 삭제해버렸네요..
아 그리고 혹시 실례가 안되면
bit.ly와 트위터 연동한 소스나 강좌도 있으신가요?ㅠ
Commented by 선지헌 at 2011/06/20 15:22
bit.ly는 해보질 않아서요 ^^;;;;
Commented by 달이랍니다 at 2011/06/20 20:24
역시 구글링이 좋은가보네요~ㅎㅎㅎㅎ
구현했습니다~
트위터와 페이스북은 정말 잘쓰고 있습니다!ㅎㅎ
Commented by 안되면 되게 하라 at 2011/06/21 19:03
twitter관련 api를 이해할려면 어디서부터 접근해야 할까요?
무엇을 봐야하는지 이렇게 지헌님처럼 연동이나 트위터 api를 응용해서 뭔가를 만들어 보고 싶은데, 우선 아주 기초적인 접근부터 알고 싶어요

지헌님, 혹시 지금처럼 "로긴, 쓰기, 로그아웃"이 아니라 해당 아이디의 트위터 화면을 트위터 로고없이 해당 자료들만 리스트에 쫙~ 나오게끔 하는 어플도 있던데, 그런건 어떻게 처리해야 할까요?
Commented by 선지헌 at 2011/06/21 23:55
그것 역시 먼저 트위터에 로그인처리를 해서(OAUTH) 액세스 토큰을 얻은 다음 트위터 API중에 해당 아이디의 글을 가져오는게 있습니다. 그 API를 써서 데이터를 가져온 다음에 리스트로 뿌리면 되겠지요 트위터 API는 트위터 사이트의 개발자 문서를 먼저 참고하시구요 그 다음에는 현재 예제에서 사용하고 있는 Twitter4J 라이브러리의 메서드 설명을 찾아보시는게 나을듯 합니다.
Commented by 박정현 at 2011/06/21 22:36
안녕하세요 정말 좋은 강좌 잘보고 갑니다.
혹시 괜찮으시다면 제 블로그에 글을 좀 올려도 될런지요?
너무 좋은 내용인데 회사에서 egloos가 접속이 안되네요....(보안문제로 막혀있네요....) 혹 허락해주신다면 집에서 글을 좀 옮겨 나를까 합니다.
안된다고 하시면 아쉽지만.... ^^ ㅎㅎ
허락해주신다면 출처는 확실히 밝히도록 하겠습니다.
저같이 회사에서 egloos가 접속안되는 사람들을 위하여 부탁드리겠습니다.
감사합니다. ^^
Commented by 선지헌 at 2011/06/21 23:53
넵 출처만 밝혀주신다면야 저야 괜찮습니다. 도움이 되셨다니 다행이네요 ^^
Commented by 귀염몽키 at 2011/07/07 16:35
좋은 글 정말 잘 보고갑니다.
트위터 연동하는데 감을 못 잡고 있었는데 유용하게 공부하였습니다.
도전!만국기님의 코드로 완성을 할 수 있었네요.
감사합니다^^
Commented by 그루 at 2011/07/27 12:43
제가 먼가 잘못했는지 강좌를 따라서 해봤는데요..
로그인버튼 눌러도 로그인 창이 안뜨네요 ㅠ

아무튼 좋은 강좌 감사합니다~ ㅎ
Commented by 최동선 at 2011/08/03 18:42
많은 도움 얻었습니다. 감사합니다~
Commented by 고추삼겹살 at 2011/08/26 14:17
한가지 질문드립고 싶습니다
자동으로 핀코드를 가져오는 과정에서
핀코드를 읽는 동안 멍하니 있는것 같아서 이미지를 하나 보여주면서 기다리게 하고 싶은대
getpicode 내부에
loading.setVisibility(View.VISIBLE);
이런식으로 뷰를 보여주게 했더니 애러가 나더군요 ㅠㅠ

제가 자바스크립트는 하나도 몰라서

만약 핀코드를 읽는중에 로딩처럼 이미지를 보여주고

다 읽은뒤 이미지를 없어지게 하려면 어찌 해야 하나요 ㅠㅠ
Commented by 선지헌 at 2011/08/26 17:21
한번 해봐야지 답변을 드릴 수 있겠는데요 ^^;;;;
Commented by 고추삼겹살 at 2011/08/27 10:35
ㅠㅠ 어렵군요 안드로이드 ㅠㅠ
Commented by ㅇㅁ at 2011/09/08 14:56
저기...로그인하면 바로 daum으로 들어가지는데...이건 왜 이런가요.?
그리구 어플 타입지정하는데가 어딧죠.ㅠ?없는거 같은데..
Commented by ㅇㅁ at 2011/09/08 15:04
아 그리구 로그아웃이란 토스트가 시작할대 뜨네요..
Commented by EvilStorm at 2011/09/15 11:22
감사합니다. 많은 도움이 되었습니다. (__)
Commented by 감사합니다 at 2011/11/05 16:26
감사합니다. 혹시 시간이되시면 친구목록불러오는거나 메세지관련된것도 해주시면 감사하겠습니다.
Commented by 김성중 at 2011/12/28 10:52
트위터 사이트가 많ㅇ ㅣ리뉴얼 된거 같아요
어플리케이션 Type 을 client와 browser 로 변경할 수 있는 부분이 없는것 같던데...
혹시 누구 아시는분 계신가요?
Commented by 김진모 at 2012/01/07 21:21
그대로 보고 따라하니 무지 쉽네요 ㅎㅎ 같은 개발자로써 감사하게 생각합니다. ㅎㅎ
Commented by 덕덕이 at 2012/02/02 15:24
먼저 좋은 자료 감사합니다~~
위의 글을 보고 수행하던중 로그인은 되는데 "write"버튼을 누르면 글이 올라가지 않습니다.
디버깅을 해보니 write()함수에서 is값이 Null이여서
if (is != null) {
String strResult = upload.upload("example.jpg", is, mEtContent.getText().toString());
twitter.updateStatus(mEtContent.getText().toString() + " " + strResult);
}
이함수를 타지 않는것 같습니다.
혹시 "example.jpg" 이렇게만 놓으면 이파일의 위치는 어떻게 알수 있는거죠??
그리고 지금 이블로그에서 write()부분의 함수내용이 맞는건가요 앞에
트위터연동 4번에 있는 내용이 맞는건가요??
Commented by 선지헌 at 2012/02/03 13:10
is 는 그림파일이 있어야 new File 을 써서 인풋 스트림을 만들수가 있습니다. 트위터 연동하기 4번을 보시면 (http://jeehun.egloos.com/4002329) DDMS를 이용해 에뮬레이터에 먼저 example.jpg 파일을 하나 올려놓으라고 해 놨을겁니다. 패스는 sdcard 바로 밑이 되도록 제가 적어 놨었구요 그럼 위 코드에서 파일 이름과 sdcard 까지의 절대경로를 찾아 올수 있기 때문에 example.jpg를 이용해 인풋 스트림을 만들 수 있게 됩니다. 그러니 먼저 트위터 연동 4 번 글을 보시고 그림파일을 하나 에뮬레이터에 올려 놓으시고 작업을 해보시기 바랍니다.
Commented by lsy at 2012/09/19 10:34
우선 좋은 정보 감사드립니다.

때늦은 질문인데 죄송합니다.
아무리 찾아봐도 저위에 이미지 처럼 client, browser을 선택하는 부분이 안보여서요...ㅠㅠ

지금은 방식이 달라진것인가요...
Commented by 심영재 at 2012/10/18 14:51
저도 그거때문에 지금.. 막막해요..

:         :

:

비공개 덧글

◀ 이전 페이지다음 페이지 ▶