暫く使っている Cocoa Emacs を更新していなかったので、24.3 に上げてみた。
当てるパッチは inline patch とポップアップフリーズ対応パッチくらい。
24.3 には既にフルスクリーン実装が入っているので、よく使われているフルスクリーンパッチは外した。
普通に安定してる。。。良い事。
但し、フルスクリーン時に、ツールバー表示をトグルすると上下に変な隙間が出て、変だ。
どうしたもんだかなぁ
ちょっとめもっぽいもの
暫く使っている Cocoa Emacs を更新していなかったので、24.3 に上げてみた。
当てるパッチは inline patch とポップアップフリーズ対応パッチくらい。
24.3 には既にフルスクリーン実装が入っているので、よく使われているフルスクリーンパッチは外した。
普通に安定してる。。。良い事。
但し、フルスクリーン時に、ツールバー表示をトグルすると上下に変な隙間が出て、変だ。
どうしたもんだかなぁ
Eclipse を使って Android アプリのプロジェクトを作成すると build.xml が作られずに、 コマンドラインからの構築ができない。 ただ、ちょっと前の ADT の話なので定かでない。。。
Eclipse を使うと署名済みの apk パッケージまで作れるが、 GUIを使って一連の操作を毎回するのは面倒なので、 ant を使ったリリース方法を調べてみた。
ant 化対応は非常に簡単で、プロジェクトのトップディレクトリで次のコマンドを実行すれば良い。
% ${ANDROID_SDK}/tools/android update project --path .
この時点で「ant debug」を実行すると bin/${project名}-debug.apk にデバック用のアプリが作成できる。
ただ、SDK Tools r14 から若干ファイルの構成が変更されているので注意が必要である。
プロパティ値として key.store/key.alias/key.store.password/key.alias.password を設定しておけば、あとは万事取り計らってくれるようである。ただ、パスワード情報を記載するので、VCSへの登録される可能性が高いant.properties への記述は避けるべきで、VCS には登録しない secure.properties を作成して、コイツを読み込むように build.xml を変更するべきかなぁ。。。
build.xml
...
<property file="ant.properties" />
<property file="secure.properties" /> <!-- ここ追加 -->
...
secure.properties
key.store=path-of-keystore
key.alias=alias
key.alias.password=password
key.store.password=password
これで、 「ant release」の実行で bin/${project名}-release.apk に署名済みのapkパッケージが作成される。
ここまで来ると、リリース apk パッケージのファイル名に自動的に構築日時とversionCodeを埋め込みたいのが、エンジニアの心情だと思う。
build.xml をよく読むと、一番最後の import 要素の上に、任意のターゲットを追加すると良さ気である。なので、 次の deploy ターゲットを追加してみた。
build.xml
...
<target name="deploy" depends="release" description="deploy">
<xpath input="AndroidManifest.xml"
expression="/manifest/@android:versionCode"
output="config.versionCode"
default="release"
/>
<tstamp>
<format property="config.versionDate" pattern="yyyyMMdd" />
</tstamp>
<property name="out.deploy.file"
value="${out.absolute.dir}/${ant.project.name}-${config.versionDate}-${config.versionCode}.apk"
/>
<copy file="${out.final.file}"
tofile="${out.deploy.file}"
overwrite="true"
/>
<echo>Deploy Package: ${out.deploy.file}</echo>
</target>
...
これで、 「ant deploy」の実行で bin/${project名}-YYYYYMMDD-V.apk に署名済みのapkパッケージが作成される。
ターゲット名はあまり良く無いかも。。。
makeファイルでのスクリプト片をantのタスク等で作成しないといけないのでいまいち使い勝手がよくわからない。 が、スゲー便利なんだろうなぁ。。。ant
定期的にCocoa Emacs 23 を構築して使っていた。今日も定期作業とおもって、構築したらビルドが失敗してしまった。。。
どうしたもんだかなぁ
ググってみると、、、MLの「Re: Emacs with Cocoa/GNUstep」の内容の通りで、lisp.h の修正の影響で nsmenu.m のビルドが失敗したみたいで修正したよ。それで emacs-23 ブランチには lisp.h の修正のみしかマージされていないみたいで、、、、うまく行かなかったということらしい。
masterブランチで作ってれば問題無しなのか、、、まぁそのうち emacs-23 ブランチに修正が降ってくるのかなぁ。
それまでは、以下のように対処してみた。(ヘタレ git 使いだから bzr の人用の手順は分からん、、、)
% git clone git://repo.or.cz/emacs.git % cd emacs % git checkout emacs-23 % git cherry-pick -n 207421c0af4edf88943e270ad4bc83934cabcc04 ... # src/nsmenu.m の2箇所のコンフリクトを修正 # 1箇所目は、memcpy を使ってる奴を残す # 2箇所目は、どっちでもいい # ... % patch -p 0 < favorite-patch-file ... # で構築 % eval "$(PATH= /usr/libexec/path_helper -s)" # PATHをクリーンにする % ./configure --with-ns % make bootstrap % make install % open nextstep/Emacs.app
なかなか、いい感じだぁ
自分の携帯を Androidの開発端末として使うのは、日常生活でメールや連絡が来たりするときに結構困る場合がある。なので、3〜4インチ程度の安いAndroid 端末が無いかなと物色したら、Zen Touch 2 がよさげ。
、、、
静電式のものに慣れているので、感圧式タッチパネルが違和感ありまくり操作がし辛いこと。
実物を見ないで、購入したので自業自得だが、、、ついでに、Android Market 非対応のも、、、 余り Android 端末としてはお薦めできないなぁ。。。まぁ音楽プレーヤーですね。
今まで扱った Android 端末は、何もせずに MacOSX の Android 開発用の SDK で認識されたので、気に留めるなかったが、こいつは認識しない。。。
はて、どうしたもんだかなぁ
熟考の結果、下記の投稿記事と同じ対応をすれば、adb で認識して、開発に使えるようである。
サクっと、認識させてみた。
# Creative Zen Touch 2 のベンダーIDを追加
% echo "0x041e" >> ~/.android/adb_usb.ini
# adb を再起動
% ${ANDROID_SDK_DIR}/platform-tools/adb kill-server
% ${ANDROID_SDK_DIR}/platform-tools/adb start-server
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
# adb でデバイスのリストを確認
% ${ANDROID_SDK_DIR}/platform-tools/adb devices
List of devices attached
16XXXXXXXXXXXX 0 device
これは adb が自前でAndroid のベンダーIDのリストを持っていることなのかぁ。。。
開発機としては、スペックも低いし解像度も高くなく無いので、下手な実装を洗い出せるので良いのかも。
ふむ、静電式でマーケット対応の一番安い奴でも探すかなぁ。。。
だれかに何故 0x041e なのか答えないといけない気がしたので。。。
単純に dmesg の直近で出てくるログ行で判断するのが正解かなぁ。。。
% sudo dmesg
...
USBMSC Identifier (non-unique): XXXXXXXXXXX 0 0x41e 0x4166 0x225
...
あとは USBストレージモードにして、システムプロファイルを参照するのも正解かぁ。。。
iOS の VIewController のライフサイクル図を書き起こしてみた。
開発ドキュメントから読み取ったのだが、理解不足なためか不正確な部分も無きにしもあらず。精進せねば。
まぁ、いらないと思うがPDF版 @ Google Docsもアップ。
Android の基本の Activity のライフサイクルの図が開発サイトに乗ってる。
これでも前後の文章で補完すれば分かるんだが、2〜3ヶ月後の自分はまた忘れてる可能性大なので、 ちょこっと弄ってみた。
まぁ、いらないと思うがPDF版 @ google docs もアップ。
Google のサービスと連携するには Google Data API を使う。Googleが公式にサポートしているので、とても安心して使える。RSS リーダーとしてよく使われている Google Reader 用のAPI も。。。は、まだ公式には無い。
まぁ、色々な人が解析しており、GoogleReaderAPIのページが、詳細にまとまっている。
なので、Google 提供の python ライブラリで、Google Reader API を叩いてみた
ただ、サンプルを書いたあとで、pyrfeed内にGoogleReader 用のライブラリが含まれていたのに気付いたので、そっちを使うのがいいのかも。
MacPorts を使っているので、さくっとインストール。
% sudo port install py27-gdata
そうでないならば、gdata-python-clientから最新版をインストールする。
gdata-python-client には、Reader サービスの固有の API は無いので、ベースのモノを適当に設定する必要がある。
import gdata.service
config = { 'Email': 'foobar@gmail.com', 'Passwd': 'password' }
# Google Reader サービス設定
service = gdata.service.GDataService(account_type='GOOGLE',
service='reader',
server='www.google.com',
source='MyReaderHoge')
# Google アカウント設定とログイン
service.ClientLogin(config['Email'],config['Passwd'])
# 認証トークン(SIDの値)
print service.GetClientLoginToken()
# 書き込み用のトークンの取得
token = service.Get('/reader/api/0/token',converter=lambda x:x)
print "token:", token
'api/0'以下のレスポンスが AtomPub 形式では無く、小細工が必要である。gdata-python-clientには、ちょうど隙間が開いてるようである。。。
'api/0/unread-count'を JSON 形式で取得する
query = gdata.service.Query(feed='/reader/api/0/unread-count',
params={'all':'true', 'output':'json'})
feed = json.loads(service.Get(query.ToUri(), converter=lambda x:x))
unreadcounts = feed['unreadcounts']
# 全体の未読数を一番前に移動しとく
for i, item in enumerate(unreadcounts):
if re.match(r'^user/\d+/state/com.google/reading-list$',item['id']):
unreadcounts.pop(i)
unreadcounts.insert(0,item)
break
# 全体の未読数
print int(unreadcounts[0]['count'] if len(unreadcounts) > 0 else 0)
#=> 1
# 未読があるラベルとその未読数
for item in unreadcounts:
if not re.match(r'^user/\d+/label',item['id']): continue
print "count:%(count)s id: %(id)s" % item
#=> count:1 id: user/16814486509924941024/label/android
query = gdata.service.Query(feed='/reader/api/0/tag/list',
params={'all':'true', 'output':'json'})
feed = json.loads(service.Get(query.ToUri(), converter=lambda x:x))
tags = feed['tags']
for item in tags:
tag = re.sub(r'^user/\d+/',r'',item['id'])
print "tag: %s" % tag
#=> tag: state/com.google/starred
#=> tag: state/com.google/broadcast
#=> tag: label/android
#=> tag: label/misc
#=> tag: label/neta
#=> tag: state/com.blogger/blogger-following
android 関連の記事を 5 件見てみるかいな。。。
query = gdata.service.Query(feed='/reader/atom/user/-/label/android',
params={'n': str(5)})
feed = service.Get(query.ToUri())
for entry in feed.entry:
print "===="
dom = xml.dom.minidom.parseString(entry.ToString())
print dom.toprettyxml(indent=" ")
print "===="
print "href: %s" % entry.GetHtmlLink().href
print "title: %s" % entry.title.text
# print "%s" % entry.summary.text
先の記事は、読んだから既読にする。
# token, feed は、上に記載の書き込み用トークンと直前で取得した記事リスト
for entry in feed.entry:
i = entry.id.text
s = entry.source.extension_attributes['{http://www.google.com/schemas/reader/atom/}stream-id']
ret = service.Post(urllib.urlencode({'i':i,
'a':'user/-/state/com.google/read',
's':s,
'T':token,
}),
'/reader/api/0/edit-tag',
converter=lambda x:x,
extra_headers={'Content-Type': 'application/x-www-form-urlencoded'})
print i,ret
何でも無いが、この部分には半日悩んでしまった。
何気ない POST パラメータを送信する POST 処理なのだが、gdata.service.Post は aplication/atom+xml形式のデータ送信を想定するため、明示的に Content-Typeを指定する必要がある!気づくまで、「400 Bad Request」+「X-Reader-Google-Bad-Token: true」に悩まされてしまった。
sub = r'feed/http://headlines.yahoo.co.jp/rss/rps_dom.xml'
ret = service.Post(urllib.urlencode({'s':sub,
'ac': 'subscribe',
'T':token,
}),
'/reader/api/0/subscription/edit',
converter=lambda x:x,
extra_headers={'Content-Type': 'application/x-www-form-urlencoded'})
print sub,'subscribe',ret
sub = r'feed/http://headlines.yahoo.co.jp/rss/rps_dom.xml'
ret = service.Post(urllib.urlencode({'s':sub,
'ac': 'unsubscribe',
'T':token,
}),
'/reader/api/0/subscription/edit',
converter=lambda x:x,
extra_headers={'Content-Type': 'application/x-www-form-urlencoded'})
print sub,'unsubscribe',ret