본문 바로가기

android/Twitter

Android app에서 Twitter 연동하기 (개선-Twitter4J 2.2.1로 업그레이드)


http://jeehun.egloos.com/4019071
상단에 원본 링크 입니다. 아래 포스트는 제가 작성한 것이 아니고 egloos.com에 접속되지 않는 분들은 위한 글임을 미리 밝혀 둡니다.
너무 잘 작성된 예제라서 가져옴을 다시 알려드립니다.

안녕하세요 지헌입니다.
강렬눈썹님의 제보로 트윗4J 가 2.2.1로 업데이트 되었음을 알게 되었습니다.
그래서 기존의 2.1 버전을 걷어 내고 2.2.1로 라이브러리를 변경해서 기존의
TwitterCon을 수정해보았습니다.

먼저 twitter4j 2.2.1을 다운받습니다.
아래 파일을 받으시면 됩니다.
twitter4j-android-2.2.1.zip

그리고 이제 프로젝트를 만듭니다. 다음처럼 만드시면 됩니다.

프로젝트를 만드신 다음에는 프로젝트의 프로퍼티 창을 열어 리소스를 선택하시고
Text file encoding을 UTF-8로 맞춰주시기 바랍니다.

그리고 프로젝트의 src 폴더와 같은 레벨에 lib 폴더를 만듭니다.
그리고 위의 twitter4j 압축 파일을 twitter4j-android-2.2.1 이라는 디렉토리에 풉니다.
그런 다음에 디렉토리째로 TwitterCon2 프로젝트의 lib 폴더에 붙여 넣습니다.
그럼 다음처럼 프로젝트가 구성됩니다.
다음은 이 라이브러리를 프로젝트에 등록해주어야 합니다.
프로젝트에서 오른쪽 마우스버튼 클릭하여 프로퍼티를 선택하여 프로퍼티 창을 엽니다.
그래서 라이브러리 탭으로 가셔서 Add JARs.. 를 선택하여 다음의 두개의 jar 파일을
선택합니다.
프로젝트의 lib 폴더에 있는 twitter4j-android-2.2.1 폴더의 lib 펄더에서 core와 media jar 파일을 각각
추가하여 줍니다.

다음으로는 C.java 파일을 만들겠습니다. 상수를 저장해 놓는 클래스입니다.
이것은 기존의 TwitterCon 에 있는것을 그대로 쓰겠습니다.
소스는 다음과 같습니다.
************************ C.java ****************************
package com.android.twittercon;

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 boolean D = true;
}
***********************************************************

다음은 트위터 로그인을 위한 TwitterLogin.java를 만듭니다.
이것도 기존의 프로젝트에 있는것과 같은 파일을 씁니다.
소스는 다음과 같습니다.
*********************** TwitterLogin.java ***********************
package com.android.twittercon;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
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에서 화면 전환하도록한다.
// 이렇게하지 않으면 표준 브라우저가 열려 버린다.
webView.setWebViewClient(new WebViewClient()
{
public void onPageFinished(WebView view, String url)
{
// page 렌더링이 완료되면 호출됨.
super.onPageFinished(view, url);

// 로그아웃을 처리한후에는 바로 Activity를 종료시킨다.
if (url != null && url.equals("http://mobile.twitter.com/"))
{
finish();
}
else if (url != null && url.startsWith(C.TWITTER_CALLBACK_URL))
{
String[] urlParameters = url.split("\\?")[1].split("&");
String oauthToken = "";
String oauthVerifier = "";

try
{
if (urlParameters[0].startsWith("oauth_token"))
{
oauthToken = urlParameters[0].split("=")[1];
}
else if (urlParameters[1].startsWith("oauth_token"))
{
oauthToken = urlParameters[1].split("=")[1];
}

if (urlParameters[0].startsWith("oauth_verifier"))
{
oauthVerifier = urlParameters[0].split("=")[1];
}
else if (urlParameters[1].startsWith("oauth_verifier"))
{
oauthVerifier = urlParameters[1].split("=")[1];
}

mIntent.putExtra("oauth_token", oauthToken);
mIntent.putExtra("oauth_verifier", oauthVerifier);

setResult(RESULT_OK, mIntent);
finish();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
});

mIntent = getIntent();
String url1 = mIntent.getStringExtra("auth_url");
webView.loadUrl(url1);
}
}
***************************************************************

다음은 레이아웃 xml 파일입니다.
main.xml과 twitter_login.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 *************************
<?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>
***************************************************************

다음은 매니페스트 파일을 수정합니다.
인터넷 퍼미션을 주고 TwitterLogin 액티비티를 등록합니다.
********************** 매니페스트파일 *************************
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.twittercon"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".TwitterCon2"
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>
****************************************************************

여기까지 하면 프로젝트는 다음과 같은 모양이 됩니다.


다음은 가장 중요한 TwitterCon2.java 파일을 수정하겠습니다.

소스코드는 다음과 같습니다.
기본적으로 구조는 기존의 TwitterCon.java 와 변경점은 없습니다.
다만 Twitter4j를 사용하는 방법이 좀 바뀌었네요
일단 소스를 보시면 ..
************************ TwitterCon2.java *************************
package com.android.twittercon;

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 TwitterCon2 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
{
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(C.TWITTER_CALLBACK_URL);
Log.v(C.LOG_TAG, "AuthorizationURL >>>>>>>>>>>>>>> " + mRqToken.getAuthorizationURL());

Intent intent = new Intent(this, TwitterLogin.class);
intent.putExtra("auth_url", mRqToken.getAuthorizationURL());
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(C.MOVE_TWITTER_LOGIN);
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
{
mAccessToken = mTwitter.getOAuthAccessToken(mRqToken, data.getStringExtra("oauth_verifier"));

Log.v(C.LOG_TAG, "Twitter Access Token : " + mAccessToken.getToken());
Log.v(C.LOG_TAG, "Twitter Access Token Secret : " + mAccessToken.getTokenSecret());
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
}
******************************************************************
위에서 파란색으로 표시 했듯이 login()과 write() 만 변경되었습니다.
로그인을 보시면
먼저 ConfigurationBuilder 객체를 만들어서 거기에 setOAuthConsumerKey 메서드와
setOAuthConsumerSecret 메서드를 이용해 컨슈머 키와 컨슈머 시크릿 키를 할당합니다.
그리고 트위터 팩토리를 만들때 이 ConfigurationBuilder 객체의 build() 메서드를 호출해
인자로 넣어 줍니다. cb.build() 는 리턴값이 트위터4J에서 제공하는 Configuration 객체를
리턴합니다.

따라서 로그인 메서드의
TwitterFactory factory = new TwitterFactory(cb.build());
이 부분은

이렇게 바뀌어도 상관은 없습니다.
Configuration config = cb.build();
TwitterFactory factory = new TwitterFactory(config);

왜 이것을 언급하냐면 cb.build()는 한번 호출되면 다시 호출될 수 없습니다.
그래서 이 config 를 여러곳에서 사용하고자 할때는 (그림을 올리고 트위터에 글을
올리는 경우) 두번째 방법처럼 해줘야만 합니다.

아무튼 이렇게 로그인 메서드를 수정하고
다음은 write() 메서드를 수정합니다.
예제로 올리고자 하는 그림파일은 DDMS를 통해 에뮬레이터의 sdcard에 example.jgp 라는
이름으로 올려 놓았습니다.
http://jeehun.egloos.com/4002329 게시물 참조

sdcard에 올려놓은 파일을 인풋스트림으로 받아서 is라는 인풋 스트림 변수에 담구요
역시
ConfigurationBuilder cb = new ConfigurationBuilder(); 를 이용해서
액세스 토큰, 토큰 시크릿 (로그인하면서 받아왔습니다.)
그리고 컨슈머 키, 컨슈머 시크릿 키(상수 클래스에 정의되어 있습니다.)를 cb에
할당합니다.
이렇게 할당하고 cb.build() 메서드를 호출해 config 객체를 만듭니다.
Configuration config = cb.build();
이렇게요

이 config를 이용해 트윗픽에 그림을 올릴때 필요한 OAuthAuthorization 객체를 만듭니다.
다음처럼요
OAuthAuthorization auth = new OAuthAuthorization(config);

이것을 이용해 트윗픽에 그림을 올리고 그 리턴값(url)을 받아서
트위터에 글을 올리면 됩니다.
별로 어려운것은 없습니다만

새로 올라온 Twitter4j 2.2.1의 예제를 찾는게 좀 힘들었네요
트윗4J 라이브러리 압축파일 내에 example 폴더가 있는데 거기를 참고해서
만들었습니다.

이렇게 하고 컴파일 > 실행하고
로그인 버튼 눌러서 로그인 하고 글 쓰고 write버튼 눌러주시면
트위터에 그림과 글이 올라가게 됩니다.

나머지 로그아웃은 기존 TwitterCon 강좌와 동일하기때문에 따로 언급하지 않겠습니다.

그럼 이상으로 twitter4j 2.2.1 버전을 적용해보았습니다.
도움 되셨다면 리플 하나씩... ^^