家族ToDo(仮)開発日誌スマートフォン用の表示で見る家族ToDo(仮)開発日誌やりたいことや行きたい場所を家族で共有するためのAndoridアプリの開発日誌(兼Android開発学習メモ)です。この広告は、90日以上更新していないブログに表示しています。前回の日誌で示したシーケンスのフィジビリティをとるために、最低限必要なWeb側の機能をやっつけ実装する。↓の図の1〜7までは前回までで終わっているので、8〜10が対象となる。独自認証キーの発行いわゆるセッションキーであるので、それなりに気をつけたい。気をつけるべきポイントは下記の通り。Webセキュリティの小部屋1、2についてはアクセストークンをSeedにして乱数生成すればいいだろう。3はCookie使わないのでアレだが、通信はHTTPSで行うのは必須。4-1、4-2はいずれかを対応すれば良いので、今回は4-1を採用する。Android端末から認証のために認証キーが送られてきて認証が成功する度に、新規の認証キーを生成して払い出すようにすれば良い。アクセストークンとメールアドレス、認証キーをDBに保存googleから得られたJSONをjson_decode関数を使ってデコードし、結果をPDOでDBにINSERTする。認証時も同様にPDOでメールアドレスを条件にSELECTし、見つかったら認証キーとともにユーザ情報をJSONにエンコードしてカスタムスキーマのURLへリダイレクトする。以下、30分くらいはまったのでメモ。PDOでエラー時に例外を生成するようにするPDOの属性PDO::ATTR_ERRMODEにPDO::ERRMODE_EXCEPTIONを指定すれば良い。デフォルトでは何もエラーはかないので大変困る。エラー内容を確認できなかったのでPDO::prepareメソッドでPDOStatementクラスがうまく生成されない原因に気づくのに時間が掛かった。ちなみに原因はINSERT文中の列名の誤り。prepareメソッドでそんなところまでチェックするんだね。json_decode関数はstdClassを返すそもそもstdClassって何?と最新のPHP事情について行けていない自分がいるが、身も蓋もない言い方をすれば、連想配列のキーをpublicフィールドとして持つ単純クラス、ということでしょうか。JavaなんかのObjectクラスに相当するとか聞いたけど、メソッドとかもっているかまでは調べてない。指定するとイメージ(?)通り連想配列を返してくれる。カスタムスキーマを使い、認証キーを返却カスタムスキーマなURLにリダイレクトしてResponseとしてJSON吐けばいいだけじゃん、とか思ってたら、うまくリダイレクトできなくて悲しい。いうのも、Androidの実行環境としてGenymotionを使っているので、localhost:8888/ほげほげとかににリダイレクトしようとすると、当然ながらAndroid端末内のlocalhostへリダイレクトしてしまうのだった。URLにIPアドレスを指定できないじゃあ母艦のIPアドレスを直接指定すればいいじゃんと192.168.ほげほげとかを指定すると、今度はGoogleのOAuthリダイレクトURLのチェックではじかれるのだった。kazokutodo.example.comなどドメインの形式であればOKのようなので、Google側はそれで登録した。Genymotion上のAndroid端末のrootを取得する問題はAndroidから上記URLを使ってリダイレクトさせる方法だが、hosts書き換えれば一発OKであるものの、Android上のhostsを書き換える方法に苦戦。Configurationアプリを使用することで簡単に取得できるのだが、hostsをAndroid端末上で修正する方法がわからないのであった。エディタとか無いしね。Playアプリが必要とのことで、下記サイトを参考にインストールを敢行。4.1.1の端末にはうまくインストールできなかったので、4.2.2の端末を作り直してそちらでやり直すとうまくいった。hello-world.jp.net晴れてAndroidから母艦のWebサーバへリダイレクトできるようになった。日誌の整理が必要かもしかし開発日誌と銘打ってはいるものの殴り書きのメモに近い状態になってきたので、ここらで一休みして記事の整理をしていく必要がある気がした。コード片の記載もスクリーンショットも少ないので、単なる妄想日記に見えないこともないし。5hWebアプリ(PHP)経由でOAuth前回、Androidアプリから直接GoogleにOAuth2.0で認証しようとしたが、下記が課題だった。urlをhttp://localhost固定にしたのか、その理由は探し出せなかったが、前できていたのをわざわざ変更したのだから、おそらくセキュリティ的な理由*1があるからと思う。ちなみに、もう一つのリダイレクトURLにurn:ietf:wg:oauth:2.0:oobというのがあるが、これはブラウザに表示されたPINをアプリにコピペするという方式で、これまためんどくさい。やったことあるならわかると思うが、スマホ上での文字列のコピペは大変苦労する。Developersとまあそんなわけで結局Androidアプリから直接OAuthするのはあきらめ、自前のWebアプリを作りそいつ側にOAuthをやらせ、Androidアプリは必要なユーザ情報だけを受け取るような感じにしようと思う。これでセキュリティと利便性を両立しようという目論見だ。ユーザ登録後の認証時。ポイントは下記の通り。(Webアプリに脆弱性が無い限りアクセストークンが漏洩しない)Androidアプリ側にはWebアプリ側で発行した専用の認証キーだけを持たせるので、端末に保存されている情報を抜かれたとしても、OAuthに関する情報は何一つ漏洩しない。(開発工数増加)ユーザにとって良くわからんサイト(自前Webアプリ)を経由するので、怪しい許可する対象がAndroidアプリではなく、自前のWebアプリとなっており、怪しい。自前のWebアプリが死んてたらGoogleが生きていても認証不可。2と3はリダイレクト前にガイダンス画面(こちらは家族ToDoアプリの認証ページです。下のボタン押してGoogleのサイトに飛んだことを確認し認証を許可して下さい。)を表示することで緩和するとか。1と4は仕方が無いね。2と3のデメリットを受け入れるなら、素直にWebViewを使ってAndroid端末側だけで頑張った方がいいのかね。「使ってたAndroidアプリと違うWebアプリに対して認証許可」するのがいいか、「アプリ内ブラウザでGoogleアカウントのID・パスが抜かれているかもしれない懸念を抱きながら認証許可」するのがいいか。・・セキュリティ的には前者の方がましか。調べれば調べるほどOAuth使うとセキュリティ的に考慮しなきゃいけないところが多くて不安だな。なんか普通にユーザ登録させる機能だけにした方がよほど安全な気がしてきた。技術調査がてら実装してみた。時間ないので使った開発環境や技術だけ。細かいことは後日書く。URLをうまく扱ってくれない件について調査。URLはなんか古かった。2.0に対応したよさげなForkを選択。全ソースを取得、Netbeansにインポートしたらボタン一つでビルドできた。Studioにインポート。いままでServiceBuilder.providerメソッドに与えていたGoogleApiクラスをGoogleApi20クラスに変更。これでうまくいくかと思いきやUnsupportedOperationExceptionが発生。scribeでは1.0と2.0でお作法が異なる模様。Overflow下記サンプルを見ると、getRequestTokenは使わず、いきなりgetAuthorizationUrlを呼んでいたりする。サンプルを参考に処理を書き換え。GitHubこれでいけると思いきや、secretKeyが空文字であることが災いして、scribeのチェック処理で死ぬ。scribeはsecretKeyが必須の前提で作られている模様。仕方が無いのでNetbeansで当該チェック処理をコメントアウトして再ビルド、うまく通るようになった。Filterの設定もしているのに、うまくアプリに戻ってくれない。2.0では非標準なスキーマは使えなくなったようだ。iOS向けでは下記のようにすることもできるようだが・・。https://plus.google.com/+NaveenAgarwal/posts/AztHNnQh7w6残念ながら、Androidでうまくいかない。URLであるhttp://localhostを使用する以外に無いようだ。httpはブラウザに割り当てられているのでアプリ選択ダイアログが出てしまう。StackOverflowの下記トピックでは、結論としてWebViewを使うことにしたとのこと。アプリ組み込みのフォームではユーザに安心感を与えられないので標準ブラウザを使う方法を探したという経緯があったのだが・・。http://stackoverflow.com/questions/6966965/best-way-to-use-google-apis-using-oauth-2-0-on-androidもう少し追跡調査をしてみるつもりだが、現状これは致し方がないのかもしれない。AndroidだけならAccountManagerをつかえという話なのかも。IDの登録結果画面にclient_secretも表示されるようなのだが、どう探してもない。IDの場合、client_secretは発行されないように変更された模様。Overflow最新の認証方法は下記URL記載のこと。Developers何が困るって、第5回でうまくいったライブラリを使う方法が使えなくなるのではないかと言うこと。いうわけで次回に続く。第5回でOAuthする際、デフォルトのWebブラウザのActivityを呼び出してGoogleの認証画面を表示しているわけだが、これはAndroidのIntent解決機能を利用している。(アクション名)をとるコンストラクタで第2引数にURLを渡し生成したIntentを使うと、指定したアクション名とURLに対応する規定のアプリが起動するという仕掛け。Filterを定義することで表明できる。2.0)何かサービスを作る度にユーザ管理・認証のしかけを再発明しているのにうんざりしていたが、最近OAuthが一般的になってきておりこれらを外部サービスに丸投げできるのがうれしい。Connectという規格がはやり始めている模様。Connectに修正する方向で進める。OAuthで目的の認証情報を得るにはSPの提供する認証画面をたたいてコールバックを受けなければならない。そのため多少複雑な実装*1が必要となる。面倒なのは嫌いなので簡単にできるライブラリがないか探したところ、scribe-javaというのがある模様。下記サイトにはこれを用いたGoogleに対するOAuthの実装例まであるのでとりあえずこれを丸パクりして動作確認をしてみる。(サンプルでは単にoauth://callback/としているが、他アプリとかち合わないように名前空間でも入れておいた方が良い)サンプルコードに載っていないsecretTokenの保存・復元処理だけ書き足して実行すると、見事に動作。ユーザ情報の入ったJSONを取得できた。あとはこのJSONを解釈してUserクラスのインスタンスを作って、Intentを使用してメイン画面へ運べばよい。↓メイン画面で表示してみた(モザイクだらけで分けわからんな)。使ってみたいのでこの辺はToDoとして次回へ。2.5h端末ローカルへのデータ保存(JSON形式)ネットワーク接続が不安定な状況を考えると、アプリのデータは端末ローカルとサーバ側の両方に保存するようにしたい。基本としては端末側にデータ保存を行い、定期的にサーバ側と同期をとるわけだ。APIで同期を行うことを考えるとやはりテキストデータであることが望ましい。テキストデータと言えばCSV、XMLあたりが一般的と思うが、データとの親和性と取り扱いの容易さを考えると最近はもうJSONでいいだろう。いうわけでAndroidで使えるJSONライブラリを探してみた。下記サイトによれば、JSONICが一番シンプルで使いやすそうである。標準でもJSONObjectなるクラスが用意されているようだが、プリミティブすぎて取り扱いが面倒そうであった。Streamが取得できる模様。Booster保存時と読み込み時のコードは下記のような感じ。はじめJSONからArrayListに復元できるかと思ったがうまくいかなかったのでToDoの配列を経由している。}}これで端末側でデータを保存・復元できるようになった。APIに渡す際は、このJSON文字列をそのまま投げつければ良い。daggerでInjectするオブジェクトの生成時に引数を渡す上記クラスはファイルIOのためにContextクラスが必要なため、コンストラクタで受け取るようにしている。このクラスはdaggerによってインスタンス化を行っているため、下記サイトを参考に、まずModuleクラスのコンストラクタでContextをわたし、provideメソッドにて目的クラスのインスタンスを生成する際にそのContextを渡すようにしている。ほげほげ(仮)文章で書くと全くわからんな。要は下記のようになっている。アプリのデータをJSONで保存するTweet広告を非表示にするもっと読むコメントを書く次のページプロフィールid:ymknやりたいことや行きたい場所を家族で共有するためのアプリの開発日誌(兼Android開発学習)です。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。