2011年5月3日

AndroidでURLを開く度に自作のアプリを起動する (1) インテントを受け取る



最近、ようやく少しずつAndroidのプログラムを作り始めている。

とりあえず必要に迫られて試して見たのが、

「ブラウザで開く」というインテントを受け取ってURLの履歴を保存し、再度そのURLをブラウザで開く

というアプリ。
単純なアプリだが、実際に作って見るとインテントの面白さを実感出来る。



動作の概要


例えば「はてなブックマーク」のアプリからリストの項目をタップすると「ブラウザで開く」インテントが発行される。(もちろんアプリはURLからブラウザを開く事が出来るものであれば何でも良い。)

インテントに対応出来るアプリが複数ある場合は選択ダイアログが表示される。

自作アプリ「intent01」を選択すると、標準ブラウザーが開く。

「戻る」ボタンでブラウザを閉じると自作アプリに戻る。開いたURLの履歴が表示されている。



インテントを受け取る


Androidのインテントには、起動するコンポーネントを指定して発行される明示的インテントと、特に指定しない暗黙的インテントがある。面白いのは暗黙的インテントの場合だ。

暗黙的インテントが発行された場合は、システムがそれを処理出来るアプリを自動的に見つけて起動してくれる。候補となるアプリが複数見つかった場合は、選択する為のダイアログが表示され、ユーザーがどれを起動するか選択出来る仕組みになっている。

つまり自作のアプリを「"ブラウザでURLを開く"インテントの処理が可能です」と宣言しておけば、システムがそれを認識して該当の暗黙的インテントが発行された時に選択ダイアログに表示してくれる訳だ。

この宣言をするには、AndroidManifest.xmlファイルのactivityタグの下に次の記述を追加するだけで良い。

<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="http" />
    <data android:scheme="https" />
</intent-filter>

アプリ内では、getIntent()でインテントを取得出来る。単にホーム画面のランチャーから起動されたのか、別のアプリで「URLをブラウザで開く」操作をされて暗黙的インテント経由で起動されたのかは、取得したIntentのgetAction()で判断可能だ。


if (Intent.ACTION_VIEW.equals(intent.getAction()) ){
    //暗黙的インテント経由で起動された時の処理
} else {
    //ランチャーから起動された時の処理
}



ListViewに表示する


インテントに詰め込まれたURLは、
String url = intent.getDataString();

で取得出来る。

ここまで来れば、後はListViewにURLの文字列を追加する部分さえ作れば履歴の表示が出来る。

注意が必要だったのは、ListViewに表示するArrayAdapterをstaticで宣言する事。でないと起動される度に毎回newされてしまい、リストには最後の1件しか表示されなくなってしまう。



標準ブラウザでURLを開く


ListViewに追加した後、標準ブラウザでこのURLを開く為には、明示的にブラウザを指定して同じインテントを発行し直せば良い。
intent.setClassName("com.android.browser", "com.android.browser.BrowserActivity");
startActivity(intent);

setClassNameの1つ目の引数はパッケージ名、2つ目はクラス名なので、これらを変えればもちろんFireFoxなど他のブラウザを呼び出す事も可能だ。(オプションで設定可能にしたら便利かも知れない。)

ブラウザからハードウェアのバックボタンで自作アプリの画面に戻るとちゃんとListViewにURLが追加されている。素晴らしい。(笑)

もちろんこのままだとリストの内容はstatic変数で保持しているだけなので、アプリのプロセスが終了した時点できれいさっぱり失われてしまう。本来ならローカルデータベースに保存するなどの処理を追加する必要がある。(それは次回以降のネタとして取って置きたい。)



結局何がしたかったのか


で、実は何がしたかったかと言うと、この履歴一覧の内容をPCに送りたいのだった。

最近寝る前に携帯で気になるニュースやブログ記事をピックアップしておいて、翌日の空き時間にPCでじっくり読むというスタイルが定着して来たので、出来るだけ簡単にURLの一覧をPCに送信する方法はないかと考えていて思いついた方法がこれだ。

もちろん「Read It Later」やその類のアプリもちょっと試しては見たけれども、いちいちユーザーアカウントを作るのも面倒だし、そもそも送信元のアプリから「共有」もしくは「送る」という操作をしないといけないのが面倒に感じていたのだ。例えば、「Google Reader」からだと一覧の記事を長押ししてもそこには「送る」メニューは無く、記事の詳細を開いた上でメニューボタンを押して、「その他」から「Send」を選んで、それからようやく送り先のアプリを選べる事になる。

記事のタイトルだけチェックしてさくさくとPCに送りたいと思うと、いちいち「送る」メニューを選ぶのはどうも使い辛い。

今回の自作アプリだと、一度デフォルトブラウザとして選択しておけば、後はリンクをタップして行くだけで裏で履歴を取ってくれるのでかなり時間が短縮出来そうな気がする。

という事で、次回からメール送信やローカルデータベースへの保存の部分を作ってみたい。

ちなみにここまでのプロジェクト全体のソースはこちらからダウンロード可能になっている。(初めてGitHubに上げて見た。^^)
https://github.com/mikehibm/android-browser-intent01

設定ファイルを除いた本体のソース(Intent01Activity.java)は68行しかないので興味がある方はぜひどうぞ。






追記: 標準ブラウザが格納している履歴を取得する方法

こちらに標準ブラウザが保存している履歴をコンテントプロバイダー経由で取得する例を見つけた。機会があればこの方法も試して見たい。
furafura times: 標準ブラウザのコンテントプロバイダから履歴を取得
WebView逆引き - でこちく備忘録



AndroidでURLを開く度に自作のアプリを起動する









.

2011年4月22日

XOOMよりすごいかも! ASUS Eee Pad Transfomerが米国などで発売へ

「ASUS Eee Pad Transfomer」が4月26日から米国などで発売されるとの事。




タブレットとしてのスペック的にはMotorola XOOMとほとんど変わらない感じだが、キーボードと合体出来るという点が面白そうだ。合体するとバッテリーで16時間駆動というのも素晴らしい。

しかもUSBポートに普通のPC用のキーボードやマウスをつないで操作出来るらしい。さらに標準でPCをリモート操作するアプリ(MyCloud=Splashtop Remote)が入っているのも良い。

画面解像度も1280x800あるので、いよいよ開発マシンにリモート接続して仕事がバリバリ出来そうな端末の登場かも知れない。

価格面でも、キーボード付きで比較してもXOOMより安くなりそうだ。

となるとこれはひとまず買ってみるしかなさそうだ。^^



ASUS、「Eee Pad Transformer」を北米で4月26日に発売、価格は$399~ | juggly.cn

Eee Pad Transformer(EPTF)新着動画5 « 恐ろしき寒さののちも桜花

Asus Eee Pad Transformer 発表、キーボード合体で16時間駆動
10.1型1280 x 800 IPS液晶、静電容量式マルチタッチ、1080p動画再生にも対応するデュアルコアのNVIDIA Tegra 2 プロセッサ、512MB / 1GB RAMと16GB / 32GB Flashストレージ、デュアルカメラ、microSDポートにミニHDMIといった基本仕様はスライダーとほぼ同一。OSもおなじAndroid 3.0を採用します。

ASUS「Eee Pad Transformer」のスペック・特徴まとめ(着脱式キーボード付) - NAVER まとめ

ASUS Eee Pad TransformerにSplashtop Remote Desktopが標準搭載~アンドロイド端末からWindowsを操作可能に~(ドリームニュース) - livedoor ニュース
「Splashtop Remoteが搭載された‘Tranformer’は、アンドロイド画面をタップするだけで、WindowsやMacにアクセスでき、一つの端末で複数を楽しむことができる、まさに‘Transformer’です。」とスプラッシュトップ社のCEOである Mark Leeは述べています。
Splashtop Remoteは、アンドロイドマーケットにおいて$4.99で入手できますが、Eee Pad Transformerには標準搭載されており、無料です。



2011/6/24 追記:
より詳しいレビュー記事。
XOOM/Optimus Padとの比較も:タブレットとノートの“いいとこ取り”か?――「Eee Pad Transformer TF101」発売直前レビュー (1/5) - ITmedia +D PC USER
AndroidタブレットはiPadへの対抗意識から、結果として見た目も中身も画一的な仕様になりがちだが、そうした中でEee Pad Transformer TF101は、Android 3.0+Tegra 2による高速な起動やレスポンスと、ノートPCならではの使い勝手のよさがうまくブレンドされ、ほかのタブレットにはない魅力を獲得できた貴重な存在といえる。

日本でも発売されて、さらに詳しい情報が増えて来そうだ。
ASUS Eee Pad Transformer 開封の儀 - Kazzzの日記
「デフォルトではオフになっているがキーボードから一発でスクリーンショットを撮ることが出来る。」 < これはいいな〜。
キーボードつきでノートPCライクに使えるAndroidタブレット「Transformer TF101」ファーストインプレッション - カイ士伝









.

2011年4月16日

Android版Skypeの内部データベースを確認して見た

SkypeのAndroid版にセキュリティ上の問題がある事がニュースになっている。
【注意】Android版skypeで個人情報ダダ漏れ。アンインストールしましょう。 - Hacking My Way ~ itogのhack日記

元々の発見者のブログ記事はこれの様だ。
[Updated] Exclusive: Vulnerability In Skype For Android Is Exposing Your Name, Phone Number, Chat Logs, And A Lot More | Android Police

興味があったので早速自分の携帯でチェックして見た。

とりあえずAstro File Managerで /data ディレクトリを開いて見たが、何も見れなかった。

次に、Android SDKの adb コマンドを試す。
> adb shell
で adb のシェルに入る。
$ ls -l /data
ls -l /data
opendir failed, Permission denied
$
やはり /data ディレクトリの中味は見れない。ただ、/data/data だと一覧が表示された。
$ls -l /data/data
drwxr-x--x app_135 app_135 2011-04-13 16:10 org.openintents.filemanager
drwxr-x--x app_132 app_132 2011-04-13 16:11 com.android.keepass
drwxr-x--x app_130 app_130 2011-04-10 00:41 com.thedeck.android.app
drwxr-x--x app_1 app_1 2010-08-03 20:03 com.htc.weather.agent
drwxr-xr-x app_1 app_1 2010-08-03 19:33 com.htc.CustomizationSetup
drwxr-x--x app_71 app_71 2010-10-05 01:34 com.skype.raider
...
「com.skype.raider」というのが問題のディレクトリらしい。
$ ls -l /data/data/com.skype.raider
ls -l /data/data/com.skype.raider
opendir failed, Permission denied
$
/data/data/com.skype.raider ディレクトリの一覧表示は出来なかった。もちろんこれはRoot化していないAndroid端末では当然の事(のはず)。

次に、/data/data/com.skype.raider/files/shared.xml の存在を確認してみる。
$ ls -l /data/data/com.skype.raider/files/shared.xml
ls -l /data/data/com.skype.raider/files/shared.xml
-rw-rw-rw- app_71 app_71 51210 2011-03-08 15:24 shared.xml
$
おぉ~、確かにあるある! しかもパーミションは「全ユーザーが読み書きOK」になっている。

ではいよいよファイルの中味を表示して見よう。
$ cat /data/data/com.skype.raider/files/shared.xml
cat /data/data/com.skype.raider/files/shared.xml
<?xml version="1.0"?>
<config version="1.0" serial="168" timestamp="1299633891.14">
<lib>
<account>
<default>(Skype ID)</Default>
</Account>
<audio>
<sidipckeyprefix>/tmp/</SidIpcKeyPrefix>
確かに自分のSkype IDが表示された!

さて、さらに内部データベースが格納されているディレクトリを一覧表示。
$ls -l /data/data/com.skype.raider/files/(Skype ID)/

-rw-rw-rw- app_71 app_71 0 2010-10-05 01:35 config.lck
-rw-rw-rw- app_71 app_71 12824 2010-10-05 01:35 keyval.db-journal
drwxrwxrwx app_71 app_71 2010-10-05 01:38 chatsync
-rw-rw-rw- app_71 app_71 40960 2010-10-05 01:35 keyval.db
-rw-rw-rw- app_71 app_71 5776 2011-03-08 15:24 config.xml
-rw-rw-rw- app_71 app_71 12824 2010-10-05 01:35 griffin.db-journal
-rw-rw-rw- app_71 app_71 28672 2010-10-05 01:35 griffin.db
drwxrwxrwx app_71 app_71 2010-10-05 01:35 voicemail
-rw-rw-rw- app_71 app_71 164672 2011-03-08 15:25 main.db-journal
-rw-rw-rw- app_71 app_71 33344 2011-03-08 15:25 bistats.db-journal
-rw-rw-rw- app_71 app_71 487424 2011-03-08 15:25 main.db
-rw-rw-rw- app_71 app_71 69632 2011-03-08 15:25 bistats.db
確かに全部のファイルがパーミッション全開だ。

ではいよいよ main.db というファイルをPC側にダウンロードする。

adbのシェルから抜けてPC側で、
> adb pull /data/data/com.skype.raider/files/(Skype Id)/main.db \work\main.db
を実行すると、一瞬でPC側にmain.dbがコピーされた。

さてこの内容をどうやって確認しようかと思ったが、「SQLite Manager」というFireFoxのアドオンがあったのでこれをインストールして開いてみた。

「SQLite Manager 0.7.0」FireFox Add On
https://addons.mozilla.org/en-US/firefox/addon/sqlite-manager/


左側にテーブルの一覧が表示されている。


Accountsテーブルのフィールド一覧はこんな感じ。

(画像をクリックして拡大可能)



EmailアドレスやSkypeクレジットの残高、Call Forward用の電話番号などがあるのが分かる。

公開する為にプロフィールに登録している情報だけでなく、残高やCall Forward用の電話番号など公開するべきでない情報までが平文のままで保存されているのは困る。

Account情報の他に、通話記録、チャット履歴、友人の一覧などのテーブルがある。

これはマズイ。とりあえず今すぐSkypeはアンインストールした方が良さそうだ。
(2011/4/27 追記: この問題は既に修正済みなので最新版が入っていれば今は心配はない)

そうしないと、悪意を持った他のアプリケーションがこれらの情報を自由に利用したりどこかに送信したりする事があり得る。

「悪意を持ったアプリケーションなんてインストールしてないよ」と思い込むのは危険だ。既にインストールされている普通のアプリでも、開発者がその気になればアップデートでSkypeの情報を読み取って送信する機能を付け加える事が可能だ。つまり新規インストールでなく既存アプリのアップデートでもこの脆弱性を利用して情報を盗まれる危険性があるという事だ。



それにしても、どうしてこんな基本的なミスが起こってしまったのだろうか。通常のやり方でDBを作成すれば、自動的に自分のアプリからしか参照出来ない様なパーミッションが付加されるはずだ。
throw Life - AndroidのFile入出力サンプル

ただ、下の方法を使うと他のアプリからでも読み書き可能になるらしい。
OutputStream output = openFileOutput(dst,
Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);

もしこれに似たようなミスが原因だとすると、Android版を開発したプログラマは今頃、職を失っているのではないだろうか。。。いや、テスト担当者の責任になるんだろうか。いずれにせよ、開発者としては身につまされる思いがする。





2011/4/20 追記:
早速Skypeアプリが更新された。更新後、下の通りパーミッションが適切に修正されているのが確認出来た。
$ ls -l /data/data/com.skype.raider/files/shared.xml
ls -l /data/data/com.skype.raider/files/shared.xml
-rw------- app_139 app_139 54794 2011-04-20 12:54 shared.xml
$ cat /data/data/com.skype.raider/files/shared.xml
cat /data/data/com.skype.raider/files/shared.xml
/data/data/com.skype.raider/files/shared.xml: Permission denied
$



2012/4/4 追記:
CodeZineにこんな記事があったのでメモ。
AndroidアプリにおけるDBファイルの正しい使い方:CodeZine
SQLiteDatabase#openOrCreateDatabase を使うとパーミションが644になる。
Context#openOrCreateDatabaseでかつMODE_PRIVATEを指定して使うと660になる。
との事。








.