[筆記]讓Android上的browser用你寫的app開啟連結
真是落落長的標題,不過因為沒有要仔細討論 intent filter 還是不要用什麼『極祕!Android的 intent filter萬萬強』這類聳動的 title 比較好,免得點進來一看大失所望。
當網站上有 market://xxx.ooo 這樣的連結出現,用 Android 瀏覽器點下去,就會自動打開 market下載應用程式,相當便利。如果連結是 tel:012345678 就會叫出撥號畫面,而且號碼已經帶好了,Google Map 則是 Geo:經緯度 這種形式。
我們自己開發的 Android 程式,要怎麼支援這種功能?比如說我的網站上提供這樣的連結
tarutaru://dance
希望點下去就會帶出我們的app,出現塔魯跳舞動畫..
方法:
1. 請打開 AndroidManifest.xml
2. 找到塔魯跳舞的Activity
3. 請參考下面的寫法
這樣不管你是 tarutaru:dance 還是 tarutaru://dance 還是 tarutaru:///dance 都會叫出目標activity
如果 data 這行寫成:
這樣就只有 tarutaru://mysite/xxx 才會對應到你的跳舞Activity. 也可以利用這樣來把連結導到不同Activity。
比方說 tarutaru://dance/xxx, tarutaru://panic/ooo 就可以分別對應到不同兩個Activities。
其他更多細節就請自行參考官方文件啦age ヽ( ̄∀ ̄)ノ
Messenger for mac 全名單Block
前陣子出國玩了幾天,回來後不記得是不是因為做了Mac OS 更新,總之 msn for mac 登入後就跳出某某人想加你為好友之類的,接著發現整個名單都是Block的狀態,非常的嚇人。不管接受與否(我真的有一度一個一個耐心按完接受),依然是全員被自己Block的狀態。Google了一下並不能說是很輕鬆就找到答案,但到底還是找到了,看起來是userlist檔案權限出了問題。解決方法是刪除以下檔案:
/Users/{your_username}/library/Preferences/Microsoft/Microsoft Messenger User Cache.plist
真是嚇死我,還以為出個國回來就要沒朋友了…
【歌詞】手紙 〜拝啓 十五の君へ〜
看到某Sエルフ的FB想到這首歌詞還沒收,順便附上中日對照Youtube影片
アンジェラ・アキが大好きだよ (´∀`)
手紙 〜拝啓 十五の君へ〜
アンジェラ・アキ
拝啓 この手紙読んでいるあなたは どこで何をしているのだろう
十五の僕には誰にも話せない 悩みの種があるのです
未来の自分に宛てて書く手紙なら
きっと素直に打ち明けられるだろう
今 負けそうで 泣きそうで 消えてしまいそうな僕は
誰の言葉を信じ歩けばいいの?
ひとつしかないこの胸が何度もばらばらに割れて
苦しい中で今を生きている
今を生きている
拝啓 ありがとう 十五のあなたに伝えたい事があるのです
自分とは何でどこへ向かうべきか 問い続ければ見えてくる
荒れた青春の海は厳しいけれど
明日の岸辺へと 夢の舟よ進め
今 負けないで 泣かないで 消えてしまいそうな時は
自分の声を信じ歩けばいいの
大人の僕も傷ついて眠れない夜はあるけど
苦くて甘い今を生きている
人生の全てに意味があるから 恐れずにあなたの夢を育てて
Keep on believing
負けそうで 泣きそうで 消えてしまいそうな僕は
誰の言葉を信じ歩けばいいの?
ああ 負けないで 泣かないで 消えてしまいそうな時は
自分の声を信じ歩けばいいの
いつの時代も悲しみを避けては通れないけれど
笑顔を見せて 今を生きていこう
今を生きていこう
拝啓 この手紙読んでいるあなたが
幸せな事を願います
[筆記]讓Android emulator連intranet
先說明,這算是某種特殊情況,一般Android開發者不見得會遇到同樣情形。總之在公司內部使用Android emu時,打開browser可以使用內部IP連上內部網站,但如果是使用domain name就會失敗,說是無法解析DN。試過使用官方說明的emulator下 -dns-server參數,但直接就在開模擬器時收到無法解析的錯誤了,當然browser一樣不認得內部網站的名稱。強者小Y同事建議改 hosts 檔看看,不過會得到 "failed to copy 'hosts' to '/system/etc/hosts': Read-only file system" 這樣的訊息。找到一篇blog文章提供的解法:Configure hosts File in Android。一開始嘗試是失敗的,後來小Y大人又給了些建議之後成功了。事實上,直接參考該文的做法對 Android 1.5, 1.6 的模擬器都是有效的,但偏偏我剛好正在用來測的是2.1。直接把作法寫在下面:
[通用部分]
如果開了一個以上的模擬器的話請自行加adb參數
0a. 先adb pull /system/etc/hosts hosts抓回local來修改。
0b. 在原本的 127.0.0.1 localhost 加上新的行,寫入你需要的對應如 192.168.1.15 mytestsite,存檔。
1. adb remount (才不會發生Read-only file system錯誤)
2. adb push hosts /system/etc/hosts
[2.0.1, 2.1 only]
這兩個版本會在這邊丟出錯誤訊息,分別為
failed to copy 'hosts' to '/system/etc/hosts': No space left on device
failed to copy 'hosts' to '/system/etc/hosts': Out of memory
解決方法是,開啟模擬器時不要直接從 AVD Manager介面開,請下指令:
$ emulator -avd youravdname -partition-size 128
接著再對這個模擬器使用上面的 hosts修改大法就不會出現錯誤了。
partition size的單位是MB,預設似乎是64。從adb shell 用 df 指令觀察的結果,/system 和 /data 都會被這個設定成這邊指定的值。而1.5, 1.6 的 image 因為剛好沒超過 64MB,還剩下一點空間,所以 hosts 還寫得進去,而 2.x 的 image 有 七萬多K,mount之後 /system 這個 partition 看起來就是全滿,剩下空間 0K。因此 hosts變肥後無法寫入,真的是因為partition爆了。事實上正常的手機確實也不需要留空間給user hack…模擬器還讓我們調參數已經很偷笑了,可惜AVD Manager 的 Start 沒地方可以設定 partition size。若有此需求的話只好麻煩一點手動下指定開emulator囉。
FFXI 垢魔道士を誘っちゃったPT
雖然是很老的flash,再看一次還是笑到肚子痛,配樂也配的好讚。尤其那隻黑塔魯跟我長一樣… 害我想起小時候也遇過好幾次睡好的怪被打醒然後塔魯就屁屁朝天了。 (*/ω\*)
【歌詞】ラブレターのかわりにこの詩を
信蜂 テガミバチ OP2。非常清新的曲風,但其實是相當感傷的歌詞。
ラブレターのかわりにこの詩を
歌:星羅
詞:星羅、中山豪次郎
曲:中山豪次郎
紙に書いたらわかるのかな
言葉にすれば見えるのかな
何も無くなってしまった
だけど身体重く感じた
足りなかった言葉 やっと気付いた
今なら全て包めるのにな
何度名前を呼んでも
決して届かないけど今
思い出す 振り向く笑顔が
まぶしくて きゅっと目を伏せた
もう二度と誰かのこと
すきにならないと思ってたのに
君だったから ほどけたんだ
なのにもう 君が居ないんだ
今は何処を歩いてるんだろう
灯り見失ってしまった
欠けちゃった心 補うために
誰かを想えたら楽なのかな
何度名前を叫んでも
決して届かない夜空に
浮かべてる 柔らかい笑顔
まぶしくて きゅっと目を伏せた
もう一度と誰かの事
すきになろうと思ってみたのに
君の声が 離れないんだ
だから今 君を呼ぶんだ
そっと胸に抱いた 言葉を手紙にたくした
一言でいい 届いてほしい。 涙 ひとしずく 落ちた
何度名前を呼んでも
決して届かないけど今
思い出す 振り向く笑顔が
まぶしくて きゅっと目を伏せた
もう二度と誰かのこと
すきにならないと思ってたのに
君だったから ほどけたんだ
ありがとう今も思うんだ
君だったからほどけたんだ
だから今 君を想うんだ
[筆記]Android emulator常用指令與技巧
1. 切換 Layout為 Landscape or Protrait: Ctrl + F11 or Ctrl + F12
2. 模擬網路 ON/OFF: F8
3. 模擬有電話打進來的情形: 開兩個模擬器即可互打,電話號碼就是模擬器上的 5554, 5556 etc。
4. 把檔案放到 emu 的 sdcard 或系統目錄
adb push my_song.mp3 /sdcard/my_song.mp3
5. 從 emu 把檔案 copy出來
adb pull /data/data/com.example.android.notepad/databases/note_pad.db note_pad.db
6. 安裝 apk 到 emu 上
adb install c:/android-apk/myapp.apk
7. 進入 emu 的 shell ,可執行 ls, rm 等動作,有root權
adb shell
8. 進入sqlite3 shell,先進入 shell之後
# sqlite3 /data/data/com.example.android.notepad/databases/note_pad.db
以上指令如果在開啟了超過一個模擬器的狀態下,必須指定要針對哪個模擬器
adb -s emulator-5554 shell
列出所有模擬器代號:
adb devices
附註: SQLite資料檔可以使用 push pull 拉到 emu外來使用輔助工具 SQLite Database Browser 來瀏覽或管理,對開發很有幫助。
[筆記] Android 使用httpclient對self-signed certificate網站進行SSL連線
Android SDK 在進行 https 連線時,對於自簽署的憑證是會拒絕連線的,會得到 Not trusted server certificate 的例外。如果使用 HttpsURLConnection 來連線,網路上可以找到一些破解方法,在此不多談。使用 apache httpclient 其實執行效率比較差一點,但是他最大的好處就是有內建的機制儲存cookie,並且也可以跟隨 server 作自動轉址。網路上資料比較多的是 httpclient 3.x版,Android 使用 httpclient 4 (而且還有些實作被拿掉) 唯一找到比較可信的來源是 apache httpclient 官方的 example。節錄重點段落如下:
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream instream = new FileInputStream(new File("my.keystore"));
try {
trustStore.load(instream, "nopassword".toCharArray());
} finally {
instream.close();
}
SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore);
Scheme sch = new Scheme("https", socketFactory, 443);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);
直接把這段拿去用當然只有一個死字。本來看討論以為是要製造一個假的空憑證騙過 httpclient,從 Android 檔案系統有點微妙開始改來改去,一連串不同的例外或直接crash就不多談了。解決了檔案路徑,到底有沒有建立等等方面的問題之後才終於發現,假憑證是不行的…
1. 所以首先,開啟你PC或Mac上的瀏覽器連上目標網站,從憑證管理的地方把該網站的憑證匯出。每個瀏覽器做法都不同,請各位發揮正常工程師的水準做完這件事。以Firefox為例,找到site名後選匯出,多半是會得到一個檔名為 your_site_name.crt 的 X509(PEM) 憑證檔。為了之後使用方便,先把這檔案複製一份並把檔名改為 your_site_name.pem。
2. 將這個憑證格式從 PEM 轉為 BKS 格式。 這是關鍵性的一步啊。
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
這行中的 getDefaultType 到底會 get到什麼 type 呢?答案:在 Android 中是 BKS。有 J2ME 經驗的人會想說,我看多半是跟 J2ME 一樣的 Sun JKS 格式吧,而且,我不要用 getDefaultType 就好了,我可以自己指定為 PEM, JKS格式啊。是的,你可以。只是你會得到錯誤訊息說 KeyStore JKS implementation not found。測了半天,看起來 Android 的 httpclient 只吃 BKS 就對了,其他都沒實作。
3. 那格式要怎麼轉?根據網路上找到的資料,可以使用 KeyTool IUI 這個Java工具。打開後從介面選 create → KeyStore,格式選 BKS,自己命名一下,要不要設密碼都可。接著選 import → Keystore’s entry → Trusted certificate → Regular certificate。 Source 的部分選 PEM 並選到剛剛瀏覽器得到的那個檔,Target 當然選 BKS 和剛 create 出來的檔。按OK之後會跳出Entries視窗,下方提示你enter new alias,隨便取個名字後ok連打,順利的話你應該就會有一個 your_keystore.bks 之類的檔案了。
4. 要把憑證檔放在 Android app 能讀到的地方,做法有兩種,放在 SD card 中,或直接放在 resources 中。
[方案一] 放在 SD card 的情形:首先模擬器要掛上SD card,這在 Eclipse 用 AVD 工具產生 avd 時就可以順便指定SD了。如果習慣用指令的話,也可以用如下指令產生 image 並 mount 上:
$ mksdcard 512M my_sdcard.so $ emulator -sdcard ./my_sdcard.so
再來要把憑證檔 copy 到 SD card 中,目前只知道指令的做法:
$ adb push file_path/your_keystore.bks /sdcard
如果有顯示類似 ftp 傳輸速度之類的訊息應該就是成功了。
接著把 android 程式碼中檔案部分改一改
FileInputStream instream = new FileInputStream(new File("/sdcard/your_keystore.bks"));
...
trustStore.load(instream, null);
如果沒設密碼,可以把 keystore load 的第二個密碼參數改成 null,有設的話當然就把 “nopassword” 改成你的密碼。
基本上這樣應該就大功告成了。
[方案二] 再講講憑證放在 resources 的方法。首先把檔案複製到專案下的 res/raw/your_keystore.bks 。Eclipse 沒有錯誤的話就 ok,否則多半是你檔名不合規格,稍微改改。接著取用方法是把 android 程式碼改成:
InputStream instream = getResources().openRawResource(R.raw.your_keystore);
其它同SD card。
5. 還有一個地方要注意,就是 SSL port。
Scheme sch = new Scheme("https", socketFactory, 443);
如果你要連的網站不是用 port 443,這邊請記得改掉。
6. 另外如果要使用檔案放在 resources 的做法,getResources() 應該只能在 Activity class 中執行,如果另外包裝連線類別的話請不要直接服用上面的程式碼,要自行從 context 抓到資源再傳過去。
看起來不太複雜的事情我其實還鬼打牆了滿久才解決,希望對各位有點幫助。
[筆記]Android 的 Activity Lifecycle
Activity Lifecycle實驗:1 = Root Activity, 2 = Sub Activity started by 1
Scenario A
- 先測單一Activity時,程式啟動,進入主畫面
onCreate 1
onStart 1
onResume 1 - 按 BACK,螢幕跑回桌面
onPause 1
onStop 1
onDestroy 1 - 選程式icon再進入主畫面
onCreate 1
onStart 1
onResume 1
結論:在 Root 按 BACK 等於結束程式。
Scenario B
- 程式啟動進入主畫面
onCreate 1
onStart 1
onResume 1 - 按 HOME,螢幕跑回桌面
onSaveInstanceState 1
onPause 1
onStop 1 - 選程式icon再進入主畫面
onRestart 1
onStart 1
onResume 1
結論:在 Root 按 HOME 只是把程式放到背景,重新進入後不會執行 onCreate。
Scenario C
- 程式啟動進入主畫面
onCreate 1
onStart 1
onResume 1 - 按下按鈕,進入畫面2
onSaveInstanceState 1
onPause 1
onCreate 2
onStart 2
onResume 2
onStop 1 - 按BACK 返回主畫面
onPause 2
onRestart 1
onStart 1
onResume 1
onStop 2
onDestroy 2
結論:在 Sub 按 BACK,Sub活動會消滅,另外看起來Android滿仔細的,停掉2重開1的流程是有巧妙的安排。
Scenario D
- 程式啟動進入主畫面
onCreate 1
onStart 1
onResume 1 - 按下按鈕,進入畫面2
onSaveInstanceState 1
onPause 1
onCreate 2
onStart 2
onResume 2
onStop 1 - 在畫面2,按HOME 返回桌面
onSaveInstanceState 2
onPause 2
onStop 2 - 選程式icon,會直接進入畫面2
onRestart 2
onStart 2
onResume 2
結論:在 Sub活動按 HOME 會暫停Sub (Root早就暫停了),再回到程式是直接 Reactivate Sub畫面
Scenario E
- 補充:在 textbox 打字到一半,按POWER鎖住螢幕
onSaveInstanceState x
onPause x - 解除鎖定,會直接回app畫面,並且之前的輸入到一半的文字不會消失
onResume x
Scenario F
- 補充:打字到一半,有電話進來
onSaveInstanceState x
onPause x
onStop x - 掛斷電話,畫面及游標回到原來的 textbox,輸入的文字還在
onRestart x
onStart x
onResume x
這裡面有個更讓我在意的事情,就是我在兩個Activity都有overwrite onRestoreInstanceState,並加入message,但是從來都沒有被呼叫過。官方手冊在提到 onSaveInstance 的時候,也是說明這儲存的bundle是讓你在下次onCreate時使用,並沒有提到 onRestoreInstanceState。不論如何,這兩個method並不是在 Lifecycle 中必定會呼叫的程序,不要依賴它們來儲存使用者輸入到一半的資料,照設計目的看來比較像是記住上一次是看到第二頁之類的功能。之後如果有讀到相關說明再補充上來。
上面的實驗雖然 onPause 和 onStop 總是在一起,但根據手冊,Pause 狀態跟 Stop狀態確實是不同。Pause狀態下,使用者不能與這個活動互動,但是仍然看的見它。也就是說如果你產生了一個透明的或不占到全螢幕的子活動,則主活動有可能只會 Pause,而不會 Stop。而Pause狀態對系統來說仍然是alive,只有系統資源真的太低時才會kill它,而Stop的活動相對來說很有機會被殺掉。(不知道 Alert Dialog 與 Parent是不是這種關係)
關於保存狀態或傳遞資料方面,官方SDK手冊強調,如果需要回傳結果給主活動,不要在 onDestroy 加入 setResult function! ,之前被 google 到的某論壇文章騙了,說可以在 onDestroy setResult,怒。根據手冊說,想要做保存資料,例如 user 輸入之類的事情應該放在 onPause,onDestroy 應該只做釋放資源之類的動作,因為 oPause是唯一一個保證會在系統 kill process 之前呼叫並且等待其return的function。實際上測試的結果,確實在 onDestroy 試圖 setResult 是沒有用的,intent 應該是會隨著此sub Activity 被消滅,onActivityResult 的地方會得到 null intent。一般來說返回鍵表示要放棄現在的動作返回,不保留狀態還算合理,但看了一下Android的通訊錄app,按下返回鍵時,其實還是當作 submit 立刻儲存了打到一半的資料,這可能是為了防止編輯到一半電話進來,資料全被清空的滿腔怒火。另外已經在背景的Activity是有機會被kill process的。萬一發生了這事情,在kill process之前會先 onSaveInstanceState(Bundle),下次再 onCreate(Budle) 時就可以使用這 bundle 的動態暫存資料。
總之,儲存永久性資料的動作可以在 onPause做,onDestroy只能做資源回收,比如 connection close,之後有其他心得會再補充資料。