更新履歴 2013-07-11 : 初回投稿 2013-08-24 : Twitter がエラーを返す場合は、getErrorStream を使う必要があったので修正 2013-10-12 : rfc3986 内部メソッドを追加( やはりきっちりしないとエラーになりました )Twitter がエラーを返す場合( 例えば投稿データか空の場合 )は、getInputStream では無く getErrorStream を使わないと、エラー内容が取得できなかったので修正しましたAndroid なので、非同期処理は AsyncTask です。クラスのメソッド内で匿名のインナー型を使用して実装しています。終了時のイベントは、専用のインターフェイスを作成して、onPostExecute から呼び出しています。 Android_Twitter.java
package com.example.posttest;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import android.os.AsyncTask;
import android.util.Base64;
import android.widget.EditText;
public class Android_Twitter {
// AsyncTask のインラインで参照する為の final
private final String _consumer_key;
private final String _consumer_secret;
private final String _token;
private final String _secret;
// API
private final String _tweet_api = "https://api.twitter.com/1.1/statuses/update.json";
// **************************************************************
// コンストラクタ
// **************************************************************
public Android_Twitter(String _consumer_key, String _consumer_secret,
String _token, String _secret) {
this._consumer_key = _consumer_key;
this._consumer_secret = _consumer_secret;
this._token = _token;
this._secret = _secret;
}
// **************************************************************
// AsyncTask の onPostExecute から外部イベントとして呼び出す為のインターフェイス
// **************************************************************
public interface Tweeted {
public void onTweetResult(String result);
}
// **************************************************************
// Twitter 投稿
// **************************************************************
public void Tweet(String text, final Tweeted OnTweetResult) {
new AsyncTask<String, Void, String>() {
// **************************************************************
// 非同期処理
// **************************************************************
@Override
protected String doInBackground(String... params) {
ArrayList<String> lst = new ArrayList<String>();
String nonce = getNonce();
String timeStamp = getTimeStamp();
String result_string = "";
try {
// *********************************
// 投稿に必要なデータ (1)
// *********************************
lst.add("oauth_consumer_key=" + _consumer_key);
lst.add("oauth_nonce=" + nonce);
lst.add("oauth_signature_method=" + "HMAC-SHA1");
lst.add("oauth_timestamp=" + timeStamp);
lst.add("oauth_token=" + _token);
lst.add("oauth_version=1.0");
lst.add("status=" + rfc3986(URLEncoder.encode(params[0], "utf-8")));
Collections.sort(lst);
String work = "";
for(int i = 0; i < lst.size() ; i++ ){
if ( i != 0 ) {
work += "&";
}
work += lst.get(i);
}
// *********************************
// 投稿に必要なデータ (2)
// *********************************
String work2 = "POST" + "&";
// API のエントリポイント
work2 += rfc3986(URLEncoder.encode(_tweet_api,"utf-8")) + "&";
// 投稿に必要なデータ (1)
work2 += rfc3986(URLEncoder.encode(work,"utf-8"));
// *********************************
// 投稿に必要なデータ (3)
// *********************************
String oauth_signature = getSignature(work2);
// *********************************
// 投稿に必要なデータ (4) / ヘッダ
// *********************************
String data = "oauth_consumer_key=" + dD(_consumer_key) +
",oauth_nonce=" + dD(nonce) +
",oauth_signature=" + dD(rfc3986(URLEncoder.encode(oauth_signature, "utf-8"))) +
",oauth_signature_method=" + dD("HMAC-SHA1") +
",oauth_timestamp=" + dD(timeStamp) +
",oauth_token=" + dD(_token) +
",oauth_version=" + dD("1.0");
// 投稿先
URL url = new URL(_tweet_api);
// 接続準備
HttpURLConnection http = (HttpURLConnection)url.openConnection();
http.setConnectTimeout(30000);
http.setReadTimeout(30000);
http.setDoInput(true);
// ヘッダ
http.setRequestProperty("Authorization", "OAuth " + data);
http.setRequestMethod("POST");
// 送信用ストリーム
OutputStreamWriter osw = new OutputStreamWriter(http.getOutputStream());
BufferedWriter bw = new BufferedWriter(osw);
// 送信データの書き込み
bw.write("status=" + rfc3986(URLEncoder.encode(params[0], "utf-8")));
bw.close();
osw.close();
InputStreamReader isr = null;
try {
// 受信用ストリーム
isr = new InputStreamReader(http.getInputStream(), "UTF-8");
}
catch( Exception e ) {
isr = new InputStreamReader(http.getErrorStream(), "UTF-8");
}
// 受信
BufferedReader br = new BufferedReader(isr);
String line_buffer;
while ( null != (line_buffer = br.readLine() ) ) {
// コマンドプロンプトに表示
result_string += line_buffer;
}
// 終了処理
br.close();
isr.close();
http.disconnect();
}
catch( Exception e ) {
result_string = "{\"errors\":\"unknown\"}";
}
return result_string;
}
// **************************************************************
// 非同期処理終了後の処理( 画面へのアクセスが可能 )
// **************************************************************
@Override
protected void onPostExecute(String result) {
// Tweet メソッドの引数のインターフェイス内のメソッドを呼び出す
OnTweetResult.onTweetResult(result);
}
}.execute(text);
}
private String rfc3986( String param ) {
param = param.replace("+", "%20");
param = param.replace("*", "%2A");
param = param.replace("%7E","~");
return param;
}
private String dD(String param){
return "\""+param+"\"";
}
private String getNonce(){
Random random = new Random();
return String.valueOf(random.nextInt(1000000000));
}
private String getTimeStamp(){
return String.valueOf(System.currentTimeMillis() / 1000L);
}
private String getSignature(String baseString){
String work = "";
work += _consumer_secret;
work += "&";
work += _secret;
String signature = "";
SecretKeySpec key = new SecretKeySpec(work.getBytes(), "HmacSHA1");
try {
Mac mac = Mac.getInstance(key.getAlgorithm());
try{
mac.init(key);
} catch(InvalidKeyException ike){
}
byte[] rawHmac = mac.doFinal(baseString.getBytes());
signature = new String (Base64.encodeToString(rawHmac, Base64.NO_WRAP));
} catch(NoSuchAlgorithmException e){
}
return signature;
}
}
処理が完了すると、onTweetResult が実行されます。 MainActivity.java
package com.example.posttest;
import com.example.posttest.Android_Twitter.Tweeted;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.EditText;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void postAction(View view) {
EditText et = (EditText)this.findViewById(R.id.editText1);
new Android_Twitter(
"Consumer key",
"Consumer secret",
"Access token",
"Access token secret").Tweet(et.getText().toString(), new Tweeted() {
@Override
public void onTweetResult(String result) {
System.out.println(result);
}
});
}
}
関連する記事 Twitter API の自分のアプリのトークンを使って投稿するだけの class VS2010_Twitter Twitter API の自分のアプリのトークンを使って投稿するだけの class VS2012_Twitter WSH : VBScript と JavaScript で Twitter に投稿する PHP : Twitter 投稿関数( twitter_update ) / cURL 関数 Twitter アプリの登録方法と、API キーの利用
|
|
【Androidの最新記事】
- デバイスを探す / Find My Device - Google / Android Find
- JavaScript から Android へアクセス
- Monaca と 本当の 『Onsen UI最小限のテンプレート』
- Android 5.1 リリース済み。SDK( android-sdk_r24.0.2-windows.zip ) でまずエミュレータ作って、あとから Eclipse と Android Studio..
- クラウドでアプリを作成してスマホで動作させる『Monaca』を Android エミュレータの 5.1 で動作確認しました
- Android で Post と Get
- 別の ADT(Android) で作成されたワークスペースを最新の ADT で開く場合の操作方法
- Android : ListView Twitter 検索テンプレート
- トラブル : AndroidManifest.xml に XML 宣言があるとエラーになる???
- Android 単純リストビューを google-gson で最速構築
- Android をテストするのにほんの少し楽になるかもしれないクラス
- Android : Google Spreadsheets API version 3.0でGoogleスプレッドシートを参照
- Android 4.2.2(ADT) : class MyDatePicker extends DatePickerDialog
- Android : 日付ダイアログをインナーで使う( 完了ボタンをクリックした場合としない場合の対応 )
- Android(4.2.2) ADT から Post や Get をできるかぎり簡単にするサンプル
- Android ADT : 単純画面遷移
- HashMap の Key と Value をそれぞれソートして、最終的には 配列に変換して テンプレートを使って for ループを簡単に記述する
- ADT Eclipse : sysout テンプレートの変更
- Android(ADT Eclipse) 用 ボタンイベントテンプレート
- Android から Post 投稿 / HttpPostAndXml extends AsyncTask<Map, Void, Document>






