SQLの窓

2013年10月13日


Java : バッチでテストする Twiiter API の『検索処理』

更新履歴
2013-10-09 : 初回投稿
2013-10-13 : rfc3986 対応と、検索結果を一覧で表示

SkyDrive へ移動


BASE64 のエンコードには、外部ライブラリが必要です。( Android ならば Android SDK 内に存在します )

URLエンコードに、URLEncoder.encode を使っていますが、正確には結果の文字列に少し加工が必要です
実装しました

JSON の処理には、google-gson を使用しています 

※ API に対して件数の引数は渡していません
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
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 org.apache.commons.codec.binary.Base64;
import com.google.gson.Gson;

public class HttpAndGet {

	public static void main(String[] args) {

		// コマンドを入力する為の 128 バイトのバッファ
		byte[] line = new byte[128];
		// コマンド部分を抽出する文字列
		String command = "";
		int i_len = 0;
		// 終了コマンド
		while( !(command.toUpperCase().equals("Q")) ) {
			
			try {
				// プロンプト出力
				System.out.print("java>");
				// 入力( 改行付きで入力 )
				i_len = System.in.read(line);
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				// 入力内容を文字列に変換して、入力文を取り出す
				command = (new String(line, "SJIS")).substring(0, i_len);
				// コマンドのみに変換
				command = command.trim();
				
			} catch (UnsupportedEncodingException e) {
				// TODO 自動生成された catch ブロック
				e.printStackTrace();
			}
			
			// コマンド処理( 大文字小文字を区別しない )
			// "get 検索文字列" で検索( 省略時は "get sworc" とみなす )
			if ( (command.toUpperCase()+"   ").subSequence(0, 3).equals("GET") ) {
				String search_string = null;
				String[] data = command.split(" ");
				if ( data.length == 1 ) {
					search_string = "sworc";
				}
				else {
					search_string = data[1];
				}
				Twitter_Search(search_string);				
			}
			// MS932 で判断
			if ( command.equals("強制終了") ) {
				System.out.print("強制終了します");
				System.exit(0);
			}
			
		}
		
		System.out.print("プログラムを終了しました");
		
	}
	
	private static String _api_url = "https://api.twitter.com/1.1/search/tweets.json";
	private static String _consumer_key = "";
	private static String _consumer_secret = "";
	private static String _token = "";
	private static String _secret = "";

	// ******************************************************************
	// Twitter API の検索
	// ******************************************************************
	public static void Twitter_Search(String search_string) {
		
		System.out.println("Twitter_Search を実行中です");
		
		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("q=" + rfc3986(URLEncoder.encode(search_string, "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 = "GET" + "&";
			// API のエントリポイント
			work2 += rfc3986(URLEncoder.encode(_api_url,"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(_api_url + "?q=" + rfc3986(URLEncoder.encode(search_string, "utf-8")));

			// 接続準備
			HttpURLConnection http = (HttpURLConnection)url.openConnection();
			http.setConnectTimeout(30000);
			http.setReadTimeout(30000);
			http.setRequestMethod("GET");					
			// ヘッダ
			http.setRequestProperty("Authorization", "OAuth " + data);
			
			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\"}"; 
		}
		
		// Gson を作成
		Gson gson = new Gson();
		
		System.out.println(result_string);
		
		JSON_ENTRY je = gson.fromJson(result_string,JSON_ENTRY.class);
		
		for(TWITTER item : je.statuses) {
			System.out.println( item.text );
			System.out.println( item.user.name );
			System.out.println( item.user.profile_image_url );
			System.out.println( "-----------------------" );
		}
		
	}
	
	private static String rfc3986( String param ) {
		param = param.replace("+", "%20");
		param = param.replace("*", "%2A");
		param = param.replace("%7E","~");
		return param;
	}
	
	private static String dD(String param){
		return "\""+param+"\"";
	}

	private static String getNonce(){
		Random random = new Random(); 
		return String.valueOf(random.nextInt(1000000000));
	}
	
	private static String getTimeStamp(){
		return String.valueOf(System.currentTimeMillis() / 1000L);
	}		
	
	private static 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());
			// http://commons.apache.org/proper/commons-codec/
			signature = new String (Base64.encodeBase64(rawHmac));
			
		} catch(NoSuchAlgorithmException e){
		}
		
		return signature;
	}
	

	// ******************************************************************
	// BufferedReader から テキストを取得
	// ******************************************************************
	static class TextReader {
		public String getText(BufferedReader br) throws IOException {

			String result_string = "";
			String line_buffer = null;   
			// BufferedReader は、readLine が null を返すと読み込み終了   
			while ( null != (line_buffer = br.readLine() ) ) {   
				result_string += line_buffer;
			}
			
			return result_string;
		
		}
	}
	
	static class JSON_ENTRY {
		TWITTER[] statuses;
	}
	
	static class TWITTER {
		String text;
		USER user;
	}

	static class USER {
		String name;
		String profile_image_url;
	}
}

関連する記事Java : Eclipse 実行の System.in.read(buff) でコンソール入力RFC 3986 に基づいた URL エンコード の簡単な理解Android : ListView Twitter 検索テンプレート


posted by lightbox at 2013-10-13 21:19 | java : 通信関連 | このブログの読者になる | 更新情報をチェックする

Android : ListView Twitter 検索テンプレート



OneDrive へ移動




ListView で表示されている画像は、『private Drawable[] image_icon = new Drawable[100];』を定義しておいて、検索結果分を保存しておくようにしています。アダプタ内の getView で行うと、Android の仕様により、画像の表示がスクロールに追いつかない状態になります。

TwitterSearch.java
package com.example.listviewobjectjson;

import java.io.BufferedReader;
import java.io.InputStreamReader;
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;

public class TwitterSearch {

	// 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/search/tweets.json";
	
	// **************************************************************
	// コンストラクタ
	// **************************************************************
	public TwitterSearch(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 Searched {
		public void onSearchResult(String result);
   	}
	
	// **************************************************************
	// Twitter 投稿
	// **************************************************************
	public void Search(String query, int count, final Searched OnSearchResult) {
		
		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("count=" + params[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("q=" + 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 = "GET" + "&";
					// 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 + "?q="
						+ rfc3986(URLEncoder.encode(params[0], "utf-8"))
						+ "&count=" + params[1]
					);

					// 接続準備
					HttpURLConnection http = (HttpURLConnection)url.openConnection();
					http.setConnectTimeout(30000);
					http.setReadTimeout(30000);
					http.setRequestMethod("GET");					
					// ヘッダ
					http.setRequestProperty("Authorization", "OAuth " + data);
					
					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 メソッドの引数のインターフェイス内のメソッドを呼び出す
				OnSearchResult.onSearchResult(result);
			}
			
		}.execute(query,String.valueOf(count));
	
	}
	
	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;
	}
	
}

※ リストビューの処理(MyListview.java)
ソース全体


posted by lightbox at 2013-10-13 20:19 | Android | このブログの読者になる | 更新情報をチェックする

2013年10月12日


トラブル : AndroidManifest.xml に XML 宣言があるとエラーになる???

ちょっと前に作ったプロジェクトが動かなくなったので、現在動作中のプロジェクトと比べてみると、動いているほうには XML 宣言がありません・・・・。

Android ドキュメントの The AndroidManifest.xml File には、XML 宣言あるんですけれど・・・
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.posttest"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.posttest.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="NextPage">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </activity>
	</application>

</manifest>
1行目を削除すると動いてくれます。

ですが、わけが解らないのでいろいろ更新をかけていくうちに・・・・Eclipse の Android 部分が動かなくなりました。

なもんで、Google より最新版をダウンロードして日本語化して Window Builder をインストールしました。

Android は、4.3 になったので、AndroidManifest.xml の android:targetSdkVersion="17" を android:targetSdkVersion="18" に変えて動作確認しました。

※ 以下はプロジェクトのプロパティの変更です。


※ ようこそがちょっと違う???


関連する記事ADT( Android Development Tools ) Eclipse の導入(日本語化手順はこの中)
■ ADT( Android Development Tools ) Eclipse に Window Builder をインストールして Swing アプリケーションを作成する(1)ADT( Android Development Tools ) Eclipse に Window Builder をインストールして Swing アプリケーションを作成する(2)

結局今は、どちらの AndroidManifest.xml でも動作しています(なにがなんだか)。



最新の ADT の Eclipse は、特に変わらず Juno でした。
『.eclipseproduct』
name=Eclipse Platform
id=org.eclipse.platform
version=4.2.0


posted by lightbox at 2013-10-12 20:19 | Android | このブログの読者になる | 更新情報をチェックする

Twitter API の自分のアプリのトークンを使って投稿するだけの class Android_Twitter

更新履歴
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 キーの利用



タグ:twitter API
posted by lightbox at 2013-10-12 17:39 | Android | このブログの読者になる | 更新情報をチェックする

VS2010(C#)WPF : ListView Twitter 検索テンプレート

SkyDrive へ移動





Twitter_Search.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Diagnostics;
using System.Security.Cryptography;

namespace VS2010_Twitter
{
	class Twitter_Search
	{
		private string _consumer_key;
		private string _consumer_secret;
		private string _token;
		private string _secret;

		private string _tweet_api = "https://api.twitter.com/1.1/search/tweets.json";

		public Twitter_Search(
			string consumer_key,
			string consumer_secret,
			string token,
			string secret
			)
		{
			_consumer_key = consumer_key;
			_consumer_secret = consumer_secret;
			_token = token;
			_secret = secret;
		}

		public void Tweet(string text, int count, DownloadStringCompletedEventHandler newEvent = null)
		{

			WebClient wc = new WebClient();

			if (newEvent != null) {
				wc.DownloadStringCompleted += newEvent;
			}

			// ソートされるリスト
			SortedList<string, string> sl = new SortedList<string, string>();
			sl.Add("count", count.ToString());
			sl.Add("oauth_consumer_key", _consumer_key);
			sl.Add("oauth_nonce", Nonce());
			sl.Add("oauth_signature_method", "HMAC-SHA1");
			sl.Add("oauth_timestamp", TimeStamp());
			sl.Add("oauth_token", _token);
			sl.Add("oauth_version", "1.0");
			sl.Add("q", rfc3986(Uri.EscapeDataString(text)));

			// http ヘッダ用シグネチャ作成
			string work = "";
			foreach (KeyValuePair<string, string> kvp in sl) {
				if (work != "") {
					work += "&";
				}
				work += kvp.Key + "=" + kvp.Value;
			}

			string work2 = "";
			// メソッド
			work2 += "GET" + "&";
			// API URL
			work2 += rfc3986(Uri.EscapeDataString(_tweet_api)) + "&";
			// Oauth + データ
			work2 += rfc3986(Uri.EscapeDataString(work));

			// OAuth tool チェック用
			Debug.WriteLine(work2);

			string oauth_signature = Signature(work2);

			// ヘッダ情報を作成
			work = "";
			foreach (KeyValuePair<string, string> kvp in sl) {
				// oauth_* のみを使用する
				if (work != "") {
					if ((kvp.Key + "      ").Substring(0, 6) == "oauth_") {
						work += ", ";
					}
				}
				if ((kvp.Key + "      ").Substring(0, 6) == "oauth_") {
					work += kvp.Key + "=" + Dd(kvp.Value);
				}
			}
			// シグネチャを追加( ヘッダーはソートの必要は無い )
			work += ", oauth_signature=" + Dd(rfc3986(Uri.EscapeDataString(oauth_signature)));

			// OAuth tool チェック用
			Debug.WriteLine(work);

			// フォーマットは、 OAuth tool で確認。
			wc.Headers["Authorization"] = "OAuth " + work;

			// 投稿
			wc.DownloadStringAsync(new Uri(
				_tweet_api +
				"?" +
				"q=" + sl["q"] +
				"&count=" + sl["count"]
			));

		}

		private string rfc3986(string base_string)
		{
			string result = base_string.Replace("!", "%21");
			result = result.Replace("'", "%27");
			result = result.Replace("(", "%28");
			result = result.Replace(")", "%29");
			result = result.Replace("*", "%2A");
			return result;
		}

		// ダブルクォートで挟む
		private string Dd(string base_string)
		{
			return "\"" + base_string + "\"";
		}

		private string Nonce()
		{
			Random rand = new Random();
			int nonce = rand.Next(1000000000);
			return nonce.ToString();
		}

		// タイムスタンプ
		private string TimeStamp()
		{
			TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
			return Convert.ToInt64(ts.TotalSeconds).ToString();
		}

		// シグネチャ
		private string Signature(string target)
		{
			string work = _consumer_secret + "&" + _secret;
			byte[] bin = Encoding.UTF8.GetBytes(target);

			HMACSHA1 hmacsha1 = new HMACSHA1();
			hmacsha1.Key = Encoding.UTF8.GetBytes(work);
			byte[] hash = hmacsha1.ComputeHash(bin);

			return Convert.ToBase64String(hash);
		}
	}
}




posted by lightbox at 2013-10-12 00:20 | VS(C#) | このブログの読者になる | 更新情報をチェックする

2013年10月11日


VirtualStore を起因とするアプリからレジストリへの書き込みトラブルの回避



上の画像は、ANHTTPD のプロパティです。実行時に右クリックから『管理者として実行』してもいいと思いますが、不特定のユーザが利用する環境ならばプロパティがいいでしょう。

参考ページ

ファイル仮想化(VirtualStore)のトラブル対応


タグ:トラブル
posted by lightbox at 2013-10-11 21:58 | Windows | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します
container 終わり



フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

CSS ドロップシャドウの参考デモ
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり