Twitterブログ: #日本語ハッシュタグ
こちらの対応。
以前はハッシュタグの対応に正規表現を利用していたかと思いますが、最近はstatusからハッシュタグ情報がとれます。
GET statuses/show/:id | Twitter Developers
include_entities=trueでhashtagsがとれてその中にハッシュタグ情報が。
APIのバグかと思われますが、「ー」で終了しているタグがhashtagsにはいってきません。
api.twitter.com/1/statuses/show/90961863306772481.xml?include_entities=true
バグレポートすればそのうち直るのかな。
searchAPIにはそもそもハッシュタグ情報が含まれないので現状では解決策なし。
GET search | Twitter Developers
他のIntentから遷移し、URL表示しないブラウザを立ち上げ認証したらhogehoge。
public class OAuthActivity extends Activity {
final private String CONSUMER_KEY = "xxxxxx";
final private String CONSUMER_SECRET = "xxxxxx";
private String CALLBACK_URL = "myapp://oauth";
private OAuthAuthorization oauth;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView webview = new WebView(this);
setContentView(webview);
Configuration config = new ConfigurationBuilder().build();
oauth = new OAuthAuthorization(config);
oauth.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
oauth.setOAuthAccessToken(null);
try {
String url = oauth.getOAuthRequestToken(CALLBACK_URL).getAuthorizeURL();
webview.loadUrl(url);
} catch (TwitterException e) {
Toast.makeText(this, R.string.twitter_failed, Toast.LENGTH_LONG).show();
finish();
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Uri uri = intent.getData();
if (uri != null && uri.toString().startsWith(CALLBACK_URL)) {
String verifier = uri.getQueryParameter("oauth_verifier");
try {
AccessToken at = oauth.getOAuthAccessToken(verifier);
Log.d(getLocalClassName(), "screen_name = " + at.getScreenName());
Log.d(getLocalClassName(), "access_token = " + at.getToken());
Log.d(getLocalClassName(), "access_token_secret = " + at.getTokenSecret());
// hogehoge
Toast.makeText(this, R.string.twitter_login_success, Toast.LENGTH_LONG).show();
finish();
} catch (Exception e) {
Log.w(getLocalClassName(), e.getMessage());
Toast.makeText(this, R.string.twitter_login_failed, Toast.LENGTH_LONG).show();
finish();
}
}
}
}
AndroidManifest.xml該当箇所。
lunchModeで多重起動させない。
あとヒストリー残さない。
ブラウザから「myapp://oauth」でIntentが起動するように。
<activity
android:name=".OAuthActivity"
android:launchMode="singleTask"
android:noHistory="true"
>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="oauth" />
</intent-filter>
</activity>
Mac OS XにPEARのインストール – ぱんぴーまっしぐら
うまく行かなくなってたので。
$ curl -O http://pear.php.net/go-pear.phar
$ php go-pear.phar
パイプでつなぐとreadlineがうまくいかないので別で実行。
ユーザー環境にインストールしようとするのでそのままEnter
~/pear/bin/pear help
layoutはボタン置いてあるだけなので省略。
ボタンクリック>ギャラリーから画像選択>クロップ>なんかするhogehoge。
クロップ後のサイズ(outputX、outputY)が大きすぎるとエラーでて利用できない。
壁紙サイズは無理。
package com.example.crop;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener {
final private int REQUEST_CODE_GALLERY = 10;
final private int REQUEST_CODE_CROP = 11;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button_background = (Button)findViewById(R.id.button_background);
button_background.setOnClickListener(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case REQUEST_CODE_GALLERY:
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setData(data.getData());
intent.putExtra("outputX", 48);
intent.putExtra("outputY", 48);
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("scale", true);
intent.putExtra("return-data", true);
startActivityForResult(intent, REQUEST_CODE_CROP);
break;
case REQUEST_CODE_CROP:
Bundle ext = data.getExtras();
if (ext != null) {
Bitmap bitmap = ext.getParcelable("data");
// hogehoge
}
break;
}
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_background:
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, REQUEST_CODE_GALLERY);
break;
}
}
}
m2eclipseを利用する。
MacOSX(snow leopard)のMaven 3.0.2、Windows環境で昔インストールしたMaven 2.2.1の環境で動作した。
jreはJDKのものを指定しないとエラーでる。
Android 2.1 update 1 ~ Android 2.3.2
AsyncTaskのcancel(true)を外部から呼んだ場合と、doInBackgroundで呼んだ場合挙動が異なる。
あと、cancelしてもdoInBackgroundは最後まで実行される。
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new AsyncTask<Void, Integer, Void>() {
@Override
protected Void doInBackground(Void... params) {
for (int i = 0, cnt = 10; i < cnt; i++) {
publishProgress(i);
SystemClock.sleep(1000);
if (i == 5) {
cancel(true);
}
}
return null;
}
@Override
public void onProgressUpdate(Integer... values) {
Log.d(getLocalClassName(), "count "+values[0]);
}
@Override
protected void onCancelled() {
Log.d(getLocalClassName(), "onCancelled");
}
@Override
protected void onPostExecute(Void result) {
Log.d(getLocalClassName(), "onPostExecute");
}
}.execute();
}
}
結果
count 0
count 1
count 2
count 3
count 4
count 5
onPostExecute
count 6
count 7
count 8
count 9
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
AsyncTask<Void, Integer, Void> task = new AsyncTask<Void, Integer, Void>() {
@Override
protected Void doInBackground(Void... params) {
for (int i = 0, cnt = 10; i < cnt; i++) {
publishProgress(i);
SystemClock.sleep(1000);
}
return null;
}
@Override
public void onProgressUpdate(Integer... values) {
Log.d(getLocalClassName(), "count "+values[0]);
}
@Override
protected void onCancelled() {
Log.d(getLocalClassName(), "onCancelled");
}
@Override
protected void onPostExecute(Void result) {
Log.d(getLocalClassName(), "onPostExecute");
}
};
task.execute();
SystemClock.sleep(5000);
task.cancel(true);
}
}
結果
count 0
count 1
count 2
count 3
count 4
onCancelled
count 5
count 6
count 7
count 8
count 9
Apacheのリバースプロキシを利用して、SERVER_NAMEがリバースプロキシサーバのIPになっちゃう場合は、リバースプロキシ側のApacheに以下の設定を追加。
ProxyPreserveHost On
PHPプログラムでSERVER_NAMEの値を超利用しまくりな場合は、問題ないようならぶち込んじゃってもいいかも。
$_SERVER['SERVER_NAME'] = isset($_SERVER['X_FORWARDED_HOST']) ? $_SERVER['X_FORWARDED_HOST'] : $_SERVER['SERVER_NAME'];
システム環境設定>共有>Web共有をチェック
httpd.confの設定
$ sudo vim /etc/apache2/httpd.conf
設定を上書きできないと困るので180行目のAllowOverrideを変更
AllowOverride All
PHPを利用可能にするため116行目のコメントアウトを外す
LoadModule php5_module libexec/apache2/libphp5.so
ヴァーチャルホストの設定ファイルvhosts以下に配置し読み込めるように最後の行に追加
デフォルトだと469行目でヴァーチャルホストの設定を読み込んでいるようだが、最終行のIncludeでPHPの設定が行われているので、それ以降に設定を書かないとPHPを利用できないため
Include /private/etc/apache2/vhosts/*.conf
ヴァーチャルホストの設定ファイルを作成
ファイル名はお好みで
$ sudo vim /etc/apache2/vhosts/httpd-vhosts-hoge.example.com.conf
ファイルはhogeユーザのSite以下にドメインディレクトリを作成し、そこをドキュメントルートにしています
localhostから接続できるようにAllow fromを追加
<VirtualHost *:80>
ServerName hoge.example.com
DocumentRoot /Users/hoge/Sites/hoge.example.com
<Directory /Users/hoge/Sites/hoge.example.com>
Allow from ::1
Allow from 127.0.0.1
</Directory>
ErrorLog /var/log/apache2/hoge.example.com-error_log
CustomLog /var/log/apache2/hoge.example.com-access_log combined
</VirtualHost>
Apache設定ファイルにミスがないかチェック
sudo apache2ctl configtest
大丈夫なようなら再起動
sudo apache2ctl -k restart
hostsファイルに名前解決できるように追加
sudo vim /etc/hosts
::1 hoge.example.com
127.0.0.1 hoge.example.com
DDMSのファイル・エクスプローラだとGUIで簡単に転送できますが、テスト用に大量に転送する必要があったのでadbコマンドを利用します。
Windowsでのお話。
転送コマンド自体は以下。
adb push ファイル名 /sdcard/転送先
SDカードは「/sdcard」としてマウントされています。
実機のSDカードをGドライブにマウントし、downloadフォルダ内のgifファイルをエミュレータのSDカード内のdownloadフォルダに転送します。
実機も認識しているため、adbのオプションで実行先をエミュレータとする「-e」オプションを指定。
for %A in (G:\download\*.gif) do adb -e push %~fA /sdcard/download
転送後、エミュレータのアプリケーション一覧から「Dev Tools > Media Scanner」でSDカードを再認識させる必要がある。
UTF-8の範囲、BMP外はダメっぽい。
文字数はUTF-8で23文字までっぽい。
日本語
http://twitter.com/cockok/%E6%97%A5%E6%9C%AC%E8%AA%9E
日本語-18
http://twitter.com/cockok/%E6%97%A5%E6%9C%AC%E8%AA%9E-18
☃
http://twitter.com/cockok/%E2%98%83
http://twitter.com/cockok/%EE%98%BE