ページ

2014/01/12

[書評]Effective Java 第2版

Effective Java 第2版 (The Java Series)
著者 : Joshua Bloch
ピアソンエデュケーション
発売日 : 2008-11-27
ブクログでレビューを見る»
Java中級者以上なら読むことがマナーであると言われるJavaの必読書。
内容が難しいのか訳がわかりにくいのか理解度が低いのかわからないけども、
内容が理解できない部分もあったが必ず役に立つと感じさせられた。
期間をあけて何度か読んで理解度を上げて実践していきたい。
Java は Android アプリ開発のために独学でろくに入門書も読まずに勉強したので
ベストプラクティスとか正しいやり方・マナー的な部分を全然知らずに開発していました。
基本的に Android アプリは一人で開発していてコードレビュー的なこととか全くしたことがなかったので
果たしてちゃんと Java を書けているのだろうかという疑問がありました。
そんな時に Effective Java は Java を書くなら読んでおくべきだよねーという意見を聞いたので
読まなくてはと思いました。(思っただけで実際に読むまでは時間が空きましたが。)

結局、読まなくてもなんとなく書けるので中々読もう!というところまで行かないんですね。
転機が訪れたのは Effective Java の出版元であるピアソンエデュケーション(ピアソン桐原)が
ピアソングループを離脱したことによって技術系の書籍が入手困難になったことでした。
ピアソンの技術書は書店在庫限りとの見通し。ピアソン桐原社がピアソングループ離脱で(追記あり) - Publickey
そういうわけで入手できなくなる前に Amazon で入手して読むに至りました。

良かったことに、丸善出版さんが Effective Java 第2版だけでなく他の書籍も再出版してくれるそうです。
[丸善出版] 旧・ピアソン桐原より翻訳刊行されていた書籍を、一部再出版することになりました。
ピアソンエデュケーション:Effective Java 第2版
丸善出版:EFFECTIVE JAVA 第2版
もうすでに Amazon で予約することができます。

ところで内容ですが、enum と並列性の部分はあまり馴染みのない部分だったので役に立ちました。
アノテーションと Serializable は使ったことがないのでまだ良くわかりませんでした。
他の部分はなんとなく知っていただけどちゃんとした知識として入ってはいなかったので良かったです。
ちゃんと理解できるとソースコードの見え方が違って見えるので読んでよかったなと思います。
それこそ TimeUnit クラスの実装を見て、あ!これ Effective Java でやったやつだ!ってなりました。
Java を書くならオススメだと思います。

2014/01/11

[Android]TwitterのOAuth認証を行う

Android で Twitter の OAuth って前は WebView で行うのが一般的だった気がします。

でもアプリ内の WebView で実装した場合は、
ユーザー側にはそれが本物なのかフィッシングなのか区別できません。

OAuthの認証にWebViewを使うのはやめよう - Shogo's Blog
アプリ内でWebViewを使うとURLが表示されません. つまり 本当にツイッターにアクセスしているかわからない のです. もし,表示されるのが偽の認証画面だったら,アプリから簡単にパスワードがわかってしまいます.

じゃあ,URL を表示させればいいかというとそういうわけでもありません. 画面上のURL表示なんて簡単に偽装できてしまいます. どんな工夫をしても アプリがパスワードの要求をしていることには変わりありません . アプリはパスワードを簡単に取得できます.

アプリのユーザはTwitterに限らずSNSへのログイン時にブラウザを開かないアプリは信用しないようにしましょう. どこかでパスワードの抜かれている可能性があります. (ただし,公式アプリは除く.公式アプリが信用できないならそもそもサービスを利用できないもんね.)

じゃあ外部のブラウザアプリを開いて、
カスタム URL スキームを Intent Filter で拾うよ。

外部のブラウザアプリなら普段ユーザーが使っているし、アプリ側から偽装はできないよね?
本物かどうか区別できるから安全だよね?ってコードがこちらです。
public class TwitterAuthActivity extends FragmentActivity {

    private AsyncTwitter mTwitter;
    private static final String CONSUMER_KEY = "Your CONSUMER_KEY";
    private static final String CONSUMER_SECRET = "your CONSUMER_SECRET";
    private static final String CALLBACK_URL = "yourapp://twitter_callback/";
    private RequestToken mRequestToken;

    private TwitterListener mTwitterListener = new TwitterAdapter(){
        @Override
        public void gotOAuthRequestToken(RequestToken token){
            mRequestToken = token;
            final Intent intent = IntentUtils.createOpenBrowserIntent(mRequestToken.getAuthorizationURL());
            startActivity(intent);
        }

        @Override
        public void gotOAuthAccessToken(AccessToken token){
            // save access token
            finish();
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        mTwitter = new AsyncTwitterFactory().getInstance();
        mTwitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
        mTwitter.addListener(mTwitterListener);
        mTwitter.getOAuthRequestTokenAsync(CALLBACK_URL);
    }

    @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");
            if(verifier != null){
                LogUtils.d(verifier);
                mTwitter.getOAuthAccessTokenAsync(mRequestToken, verifier);
            }else{
                // User canceled!
                finish();
            }
        }else{
            // other
            finish();
        }
    }

}
<activity
    android:name=".TwitterAuthActivity"
    android:launchMode="singleTask" >
    <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:host="twitter_callback"
            android:scheme="yourapp" />
    </intent-filter>
</activity>
OAuthの認証にWebViewを使うのはやめよう - Shogo's Blog
ポイントは以下の点です。
  • Twitter へのアプリケーション登録時に Callback URL にテキトーなURLを入れておく
  • 独自スキーマを定義して,受け取れるようにしておく
  • getOAuthRequestToken 呼び出し時に,Callback URL を明示的に渡す
  • アクティビティの多重起動を防止しておく
確認すべきはカスタム URL スキーマが被った(被せられた)場合に
AccessToken を奪われる可能性があるけど大丈夫?という点。
特定条件下におけるOAuth 2.0の認可応答を奪取されるリスクとその対策について - r-weblife
今回は、「ネイティブアプリケーションからOAuth 2.0を使うとき、特定の条件下において、正規のClientではない悪意のある第3者に認可応答を持って行かれて、その結果Access Tokenを取得できちゃうリスクがあるよね。どうしようか。」っていう話です。

条件っていうのは、

OAuth 2.0のClientはネイティブアプリケーションであり、Client Credential(client_id/client_secret)を安全に管理できない
Clientは外部のブラウザを立ち上げ、ユーザーは認可要求のURLにアクセスする。この時にいわゆるImplicit GrantやAuthorization Code Grantを使う
ユーザーがリソースアクセスを許可した後、認可応答はカスタムURIスキームでClientに渡る
というところです。

なんでこれで認可応答を持って行かれるかというと、カスタムURIスキームの扱いです。

認可要求を送ったClientに認可応答が戻ってくれればよいのですが、カスタムURIスキームを被せてきた(たまたま一緒だっただけかもしれない)別のアプリケーションに認可応答が渡る可能性があると。

で、このあたりのルールが”アプリを選択させる”、“先にインストールした方が優先”、“後にインストールした方が優先”、とかOSに依存するので悩ましい。
Android アプリである限り ConsumerKey/ConsumerSecret は漏れる。
たぶんリバースエンジニアリングとかで。詳しい手法は知らない。
同様にして AndroidManifest.xml の Intent Filter で受け取るカスタム URL スキーマもわかるんじゃないかな?
ということで カスタム URL スキームを Intent Filter で拾う手法は
狙われたらアウト、狙われなければセーフ的なギリギリのラインで危険で安全な手法。非推奨
上のコードで実装して何かあっても責任取れませんってやつです。

カスタム URL スキームが被る(被せられる)から問題なんだよね?
じゃあ動的に生成すれば被せられることはないんじゃない?

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);

    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_VIEW);
    filter.addCategory(Intent.CATEGORY_BROWSABLE);
    filter.addCategory(Intent.CATEGORY_DEFAULT);
    filter.addDataScheme("http"); // http じゃないとブラウザからレシーブできない
    filter.addDataAuthority(RandomStringUtils.randomAlphanumeric(20), null);
    registerReceiver(mIntentReceiver, filter);
}

private BroadcastReceiver mIntentReceiver = new BroadcastReceiver(){
    @Override
    public void onReceive(Context context, Intent intent){
        Uri uri = intent.getData(); // ドメイン部分しか取れない
    }
};
コメントに書いてある通り無理だった…。
<activity
    android:name=".TwitterAuthActivity"
    android:launchMode="singleTask" >
    <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:host="twitter_callback"
            android:pathPattern=".*"
            android:scheme="yourapp" />
    </intent-filter>
</activity>
    private static final String CALLBACK_URL = "yourapp://twitter_callback/" + RandomStringUtils.randomAlphanumeric(20);
より複雑にしてみたらどうだろうと思ったけどシンプルな方でも拾えるので意味がなかった。

ということでカスタム URL スキームを Intent Filter で受け取る手法を安全にするのは難しそうです。

ではどうすればいい?

OAuthの認証にWebViewを使うのはやめよう - Shogo's Blog
PIN コードを利用

一つ目の方法はPC版クライアントでよく使われる方法. 認証後にPINコードと呼ばれる数字が表示されるので,それをアプリに入力します. twiccaなんかでも使われてますね. Twitter へのアプリケーション登録のときにコールバックURLを入力しないとこの認証方式になります.
ユーザーが自分でアプリに戻ってきて PIN を入力してくれれば
他のアプリに認証情報を取られるということがないという原始的な安全性の担保方法です。
原始的だからこそ付け込む隙がなくて安全なわけですね。

PIN コードさえ利用すれば安全?

いまさらブログ: Androidの脆弱性(まとめ版)
WebViewの addJavascriptInterface()の危険性(参考)が、Android 3.x/4.0/4.1 ではWebViewそのものに存在する。
このためWebViewをそのまま使っているアプリや、WebViewのラッパにすぎない標準ブラウザに同様の脆弱性がある。(Android版ChromeはWebViewを使っていないので問題ないです)

(中略)

Android 標準ブラウザや WebView クラスを利用しているアプリで、細工されたウェブページを閲覧した際に、ユーザの意図に反して Android OS の機能を起動されたり、任意のコードを実行されたりする可能性があります。
Android 4.2 未満の標準ブラウザや WebView では、
入力してアプリに保存した ID とパスワードを読み取られる可能性があります。
PIN コードを利用しようが、カスタム URL スキームを Intent Filter で受け取ろうが
Android 4.2 未満の標準ブラウザや WebView を利用した時点で安全とは言い切れなくなります。
しかも自分のアプリで気をつけていても他のアプリに問題があれば
自分のアプリの保存した ID とパスワードを読み取られる可能性があるようです。
参考
Androidアプリセキュリティ〜WebViewの注意点(1)〜 | Android | Developers AppKitBox
Androidアプリセキュリティ〜WebViewの注意点(2)〜 | Android | Developers AppKitBox

どんなに頑張っても危険があってツラい…

iOS みたいに端末に設定したアカウントを使えるとか何か良い方法ないんですかね?

参考にしたサイトまとめ

OAuthの認証にWebViewを使うのはやめよう - Shogo's Blog
TwitterのOAuthの問題まとめ
TwitterのOAuthの問題の補足とか
特定条件下におけるOAuth 2.0の認可応答を奪取されるリスクとその対策について - r-weblife
いまさらブログ: Androidの脆弱性(まとめ版)
Androidアプリセキュリティ〜WebViewの注意点(1)〜 | Android | Developers AppKitBox
Androidアプリセキュリティ〜WebViewの注意点(2)〜 | Android | Developers AppKitBox

2014/01/10

[書評]OpenGL ES 2.0 Androidグラフィックスプログラミング

OpenGL ES 2.0 Androidグラフィックスプログラミング
著者 : 松田晃一
カットシステム
発売日 : 2012-08
ブクログでレビューを見る»
Android で OpenGL ES 2.0 を使いたい人が入門書として読むのにオススメな本です。
ゼロから OpenGL ES 2.0 について、Android で使う方法について
解説されているので大変わかりやすいです。
CUTT System:OpenGL ES 2.0 Androidグラフィックスプログラミング

目 次

第1章 OpenGL ES 2.0って何?

1.1 Android上のOpenGL ES 2.0は何がよいのか?
1.2 OpenGL ES 2.0はOpenGLを簡単にしたもの
1.3 OpenGL、OpenGL ES 1.1/2.0、WebGL
1.4 OpenGL ES 2.0のソフトウェア構造
1.5 開発環境とスマートフォン
1.6 サンプルプログラム
1.7 参考文献の表記に関して
1.8 まとめ

第2章 環境を整える

2.1 Android SDKの導入
2.2 Eclipseの導入
2.3 Androidアプリケーションの実行
2.4 プログラムの表示のさせ方
2.5 メッセージを表示させる
2.6 まとめ

第3章 はじめの一歩

3.1 世界一短いOpenGL ES 2.0:描画領域をクリアする(HelloGLES20)
3.2 点を描画する(1)
3.3 点を描画する(2)
3.4 タッチされた場所に点を描画する
3.5 点の色を変更する
3.6 縦横比を保持する
3.7 精度修飾子に関してもう少しだけ
3.8 まとめ

第4章 三角形の描画とアニメーション

4.1 複数の点を描画する(1)
4.2 複数の点を描画する(2)
4.3 三角形さん、こんにちは
4.4 移動、回転、拡大縮小
4.5 移動し、回転する
4.6 アニメーションさせる
4.7 まとめ

第5章 色と画像を使う

5.1 頂点に関する複数種類のデータをシェーダに渡す
5.2 三角形に色を付ける(ColoredTriangle.java)
5.3 四角形に画像を貼る
5.4 複数のテクスチャを貼る
5.5 まとめ

第6章 小休止:OpenGL ESシェーダ記述言語(GLSL ES)

6.1 GLSL ESとは
6.2 Hello Shader!
6.3 扱えるデータ(数値、論理値)
6.4 変数
6.5 型に厳しい言語
6.6 基本の型
6.7 ベクトル型と行列型
6.8 構造体
6.9 配列

6.10 サンプラ

6.11 演算子の優先順位
6.12 条件分岐と繰り返し
6.13 関数
6.14 組み込み関数
6.15 グローバル変数とローカル変数
6.16 型修飾子
6.17 精度修飾子
6.18 プリプロセッサ指示子
6.19 まとめ

第7章 3次元の世界へ

7.1 どこからどこを見ているかを指定する
7.2 タッチで視点の位置を変える
7.3 どこからどこまでが見えるかを指定する(直方体型)
7.4 どこからどこまでが見えるかを指定する(四角錐型)
7.5 前にある物が後ろにある物を隠す
7.6 立方体さん、こんにちは
7.7 ワールド座標系とローカル座標系
7.8 まとめ

第8章 光溢れる世界へ

8.1 物体に光を当てる
8.2 回転し、平行移動した物体に光を当てる
8.3 物体に点光源を当てる
8.4 複数の物体から構成される物体の描画と操作
8.5 シェーダとプログラムオブジェクト——initShaders( )は何をやっているのか?
8.6 環境に優しいプログラム
8.7 まとめ

第9章 さまざまなテクニック

9.1 物体を指で回転する
9.2 物体を選択する
9.3 物体を指で拡大縮小する
9.4 フォグ(大気効果)
9.5 四角い点を丸くする
9.6 アルファブレンディング
9.7 シェーダを切り替える
9.8 描画した内容をテクスチャ画像として使用する
9.9 影を表示する
9.10 モデルを読み込み表示する
9.11 センサを利用する
9.12 まとめ

付録

付録A Androidプロジェクトの作成
付録B GLSL ES 1.0の組み込み関数
付録C 行列一覧
付録D OpenGL ES 2.0/OpenGLは左手系?
付録E 逆転置行列!
付録F シェーダをファイルから読み込む
OpenGL の概要も全然知らないけど画像加工フィルターが作りたくて良さそうな本はないかと買いました。
概要から 2D、そして 3D へという流れで解説しています。
画像加工フィルターが作りたかっただけなので 3D の 第7~9章は読んでいません。
まだ画像加工フィルターを作ってないのでちゃんと理解できているかどうかは微妙ですが、
わかりやすい図解などもあり、少なくともわかったつもりにはなれると思います。
次の DevCamera のアップデートで実装してちゃんと理解したいです。

2014/01/09

[書評]Smashing Android UI レスポンシブUIとデザインパターン

Smashing Android UI レスポンシブUIとデザインパターン
著者 : Juhani Lehtimaki
インプレスジャパン
発売日 : 2013-08-26
ブクログでレビューを見る»
Android アプリを開発する際に iOS の流儀を持ち込む人に読んでもらいたい本です。
Android を使ったことのない人に
Android とはこういうものだと知ってもらうのにちょうどいいと思います。
また、Android アプリ開発者も良いデザインパターンとアンチパターンを知り、
良い UX を提供できるようになれると思います。
書籍についてのページ: Android UI Patterns: Smashing Android UI
サンプルアプリ: Smashing Android UI Companion - Google Play の Android アプリ

本書は Android アプリ開発に関わるデザイナー、ディレクターにぜひ読んで欲しいと思います。
大きく分けて4部で構成されています。

第1部 Android デザイン

第1部は Android プラットフォームの全容とユーザー中心設計の開発手法を紹介しています。
開発者とデザイナーで最低限の共通認識を構築するために読んでおく必要があると思います。

第2部 Android プラットフォームの機能と UI コンポーネント

第2部は Android の流儀を解説しているので普段 Android を使わない関係者に読んで欲しい内容です。
Android の開発が初めてなプログラマがどんな UI パーツがあるのか等を知るのにもちょうどいいと思います。

第3部 スケーラブルな Android デザイン

第3部は Android の様々な機種のフラグメンテーションをカバーする強力な仕組みを解説しています。
この部分を理解しているかどうかで Android アプリ開発に関する印象は大きく変わるかと思います。

第4部 Android UI デザインパターン

第4部は Android における UI のデザインパターンとアンチパターンを紹介しています。
iOS と同じデザインで、同じ UI で、という要望があっても
Android には Android デザインパターンがあるのだ!と跳ねのけて
最適な Android のためのデザインをして欲しいと思います。
そのためには良いデザインパターンを知らなければならないので本書で学びましょう。

関連
SMASHING Android UIはAndroid開発に関わるなら必読書かも - なるようになるといいね
iOS な人が Android アプリを開発するときに気をつけたいこと | SmartNews開発者ブログ

Android アプリ開発に幸あれ!

2014/01/08

2013年の反省と2014年の目標

あけましておめでとうございます。
2012/01/08に始まったこのブログも
2周年を迎えました。
2012年の208記事とまでは行きませんが
2013年も117もの記事を書けたので
このブログのアクセスも増えていきました。
昔からの人も最近からの人も
2013年、お世話になりました!
2013年のエンジニア人生を振り返って
2014年の目標を立ててみようと思います。

2013年

Android アプリを何本か作った

まず、プライベートではDevCameraというカメラアプリを作りました。
これは会社でカメラアプリを作った際に無音連写が実装できずに悔しい思いをしたためと、
会社のカメラアプリがヒットしたのでその引合でカメラアプリ開発の依頼が来るだろうという予測のもと、
個人で技術調査的に開発したアプリです。
実際にカメラアプリの仕事を依頼を受けて開発しましたし、
カメラアプリ開発以外の仕事にも広がったので大変良い結果になったと思います。
本当は DevCamera 経由で仕事の依頼が来て、技術で仕事取ってきたどー!ってしたいので
もしカメラアプリの開発の仕事がありましたらこちらにメールいただけると嬉しいです。

カメラ機能は爆速で開発できるようになったのでこれ↓を作れば良かった。仕事してる場合じゃねぇ!
「きすしよ!」ヤフー!があの「天才1」が考案したアプリを爆速で本当に開発www | あんどろいどスマート

生産性の向上

2013年の目標であった「生産性の向上」はある程度達成することができたと思う。
Sublime Text 2 のカスタマイズはある程度使いやすくなったので完全に放置しているけど
Android のユーティリティ的なライブラリを充実させていったので開発速度は結構上がってるはず。

巳年なのでPythonを学ぶ?

Sublime Text 2 のプラグインを作るために学ぶかなと思ったけどやらなかったね。
必要は発明の母だから必要になっていない場合はモチベーション低くてやらないね。たぶん今年も。

新しい言語を学ぶ

新しいプログラミング言語を学ぶとかそんなことはなかった。
まぁ Android の Fragment とか Loader などの Android 3.0 以上の API を学んで使っていたのでアリ?
去年と比べたらグッと Android (Java) の技術力が上がったと思う。

UnitTestを学ぶ

Android の一部アプリで少しやったくらい。いかんせんカメラアプリとかだとやりにくい。

CI(継続的インテグレーション)を学ぶ

UnitTest と合わせて CI を回すと考えていたけど UnitTest をやっていないので CI も、という状況。

個人でのプロダクトを出す

Android アプリ「DevCamera」を出しましたね。
月一でアップデートするようにしています。じわっと 1000 DL 超えました。
まだまだやりたいことは多いのでアップデートしていきます。

収入を増やす

OpenGL を学んで DevCamera でフィルターの販売とかしたい。アプリ内課金の練習にもなるし一石二鳥。
応用情報技術者を取っていない。春に取ろう。
Amazon アフィリエイトは料率下がってるし、書評を書いてないしで減収。悲しい。
Google AdSense はブログのアクセスが増えて少し増えたけど飲み会にも行けないレベル。もっと増やしたい。
そして、今年もヘッドハンティング的なメールを頂いた。年末はそういう時期なのかな?
今年は去年と違ってヘッドハンティング会社ではなく、
開発会社から直接興味があったらお話でもというメールだった。
ブログの目的の一つがセルフブランディングなので技術者としての価値を認めてもらえたというのは
ブログがしっかり役割を果たしていて凄く嬉しい。
しかもカメラアプリを作っているようで、DevCamera が目に止まったのかなぁとか思ったりして
まったく DevCamera は大成功だな!

2014年

Androider としての技術力を更に高める

実装能力だけじゃなくて細部のクオリティの高さとか使った時の気持ちよさなんかを上げていきたい。

新しい言語を学ぶ

アプリのバックエンドとかを Ruby とかで作ってみたい気はするけど
Mobile Backend Starterとかあるしどうかな?
Ruby on Rails を動かすのに Heroku とかお金かかっちゃうからその辺をまかなえる副収入とか欲しい。

OpenGL を学ぶ

DevCamera にフィルター機能を追加してアプリ内課金で販売とかしたい。
画像加工系はカメラアプリ作ってるとそこそこ需要あるからできるようになっておきたい所。

UnitTest / CI を学ぶ

継続的なサービスとかじゃないと UnitTest や CI は意味が無いので
まずは継続的なサービスを作る所から?先は長い。

個人でのプロダクトを出す

今のところは DevCamera で一通りの実装をするかなぁ。更にもう一個作るかどうかは微妙。
DevCamera のクオリティアップだけでやることいっぱいなので今年は育てるフェーズになると思う。

収入を増やす

応用情報技術者を取る。アプリで収益を出す。ネット上で技術書代くらいは稼ぐ。
仕事も頑張って昇給/賞与の増額を狙う。頑張れば正当な評価も良い機会も与えられるので頑張ろう。
現状は特に不満もないし、やればやっただけ成長できるし、
生活基盤も構築されてきて遠くには移りづらいので転職は考えていないかな。
稼がねば。

2014年もよろしくお願いします!

さらなる飛躍の年にするべく頑張ります!