Android LintのDetectorを読む Day1: AddJavascriptInterfaceDetector
背景
WebView#addJavascripInterface
によりアプリからオブジェクトを埋め込む関数だが、WebView中のJavaScriptがリフレクション使ってアプリ側のフィールドにアクセス出来る脆弱性があるため。
API17移行では @JavascriptInterface
がついているメソッドしかJavaScriptからアクセスできないが、それ以下だとすべてのメソッドにアクセス可能。
条件
- minSdkVerが17未満
WebView.addJavascriptInterface(objct, string)
TargetApi
RequiresApi
のアノテーションで17以上がついていない
コード読んだ上での気づき
メソッドについて検出の仕方
メソッドに対してLintで検出したい場合、 SourceCodeScanner
を継承し getApplicableMethodNames
visitMethodCall
を実装すること。
class AddJavascriptInterfaceDetector : Detector(), SourceCodeScanner { // ---- implements SourceCodeScanner ---- override fun getApplicableMethodNames(): List<String> = listOf(ADD_JAVASCRIPT_INTERFACE) override fun visitMethodCall( context: JavaContext, node: UCallExpression, method: PsiMethod ) { } } #疑問 minSdkに関係する判定が3度入っていて処理が重複していそうなものだけれどどうなんだろう。 一つ目はわかりやすい。
if (context.project.minSdk >= 17) {
return
}
2つ目について、
if (isSuppressed(context, API_17, node, context.project.minSdkVersions)) {
return
}
でありisSuppressedの冒頭が以下なので、1つ目の判定が同時に行われていそうではある。 処理としては重複しているが、意味合いが異なる (こちらはsuppressされてるかのチェック)のでよさそう。
fun isSuppressed(
context: JavaContext,
api: ApiConstraint,
element: UElement,
minSdk: ApiConstraint
): Boolean {
if (minSdk.isAtLeast(api)) {
return true
}
3つ目について、17未満でレポートするようなコードになっている。 reportについてのコメントでは、 context.projectで取れるのはソースコードのプロジェクト、つまりライブラリだったらライブラリ。 ライブラリのminSdkVerが17未満でも使っているメインのPJで17以上だったら問題ないので、そのための紀伊術。 ちなみにlintの仕組み的に 1. ライブラリのソースファイルからlintチェックを行い、潜在的なエラーを報告する 2. appモジュールなど下流のモジュールでレポートを生成する時、そこでのminSdkVerなどでフィルタリングする となっているので、 判定に `context.main` を使うのは違うようだ。
context.report(incident, minSdkLessThan(17))
マルチモジュール勉強会に出て学んだこと
少し遅くなったが。マルチモジュール勉強会にでたので個人的に参考になったポイント。
詳細設計レビューで新規開発時にルールを徹底させる
普段詳細設計レビューすることがない。というのもそこのレビューのコストを重く見てしまっているのだろうと思う。 レビューしないことによる手戻りも考えられるため、1つ検討しても良いかも知れない。 選択肢として持っておけば、場合に応じて使えるようになる。
クイズ
クイズでこういうケースでモジュールするか?みたいなのがあり、発表者の方はモジュール化導入したほうがよいのでは、と言ったケースでも参加者からは割とどれも導入しないなーとなっていた。 これは発表者・参加者の実際の経験からくるマルチモジュールの評価の違いかな、と感じた。 発表者の方は既にマルチモジュール化しているのでメリットのほうを高く評価していて、参加者からは(おそらく)マルチモジュールしていないのでコストの部分を高く評価しているのかも。
僕もよっぽどじゃないとマルチモジュール化はしないかな・・・(今は進めてるけど)
legacyモジュールの解体作業を進めるよりも新しい機能を別モジュールで作りやすくするという部分に注力
僕も解体作業を進めているところだが、心の底でlegacyモジュールを完全に解体しなきゃいけないんか?という気にはなっていたのでこう言われて心が楽になった。 リファクタリングでやらなきゃいけないものって結構しかかりの物が多く(Kotlin化とかCoroutine化とか) 、同時並行で進んでるものが溜まっていく印象で、なるべく早くやりきりたい気持ちもある。
やりきることにより、古い実装がまるっとコード・アプリ内・頭の中から削除出来る。 ただそこまですることによるメリットをあまり感じられないとあんかなk進められない。
例えば殆ど触っていないようなクラスをKotlin化したからといって、うれしくなるわけではない。
モジュール構成や思想をドキュメントにしておく
ドキュメントを書く時になぜそうなのか?は残すべきところだなーと感じる。コードのコメントに何残すか?と似ている。 結局やったことはそのまま残るから、意図を残しとこうねってやつ。
デモアプリ
良い。その画面に至るまでの色々をすっとばせる。この色々には画面もあるが、ログインまでのフローも含まれるのでそこをすっとばせると非常にありがたい。更にいうとUIテストやるとき。
クックパッド Android アプリのマルチモジュール化とデモアプリの活用 - Speaker Deck デモアプリのStub Injection について、発表時は理解できてなかったけど後から理解した。
BindsOptionalsOfをつけた宣言にはOptional
習慣継続の停滞期
年始以来しばらく順調に続いていた習慣だが、今週に入って途絶えてきている。
フィットボクシング
一番続けていたのがこれだった。が、先週ジムで筋肉痛がひどく、フィットボクシングができない。 「朝着替える」という最小の目標にしていたが割と当たり前過ぎてやる意味もなぁ・・・と考えてしまっていた。 「着替えてFB起動」くらいがいいのかも。
ブログ書く系
実は毎日投稿、と言わず毎日なにがしか書く(下書きでも) やっていたがしばらくあいてしまった。 仕事が少し忙しくなってしまったのがある。 こちらも雌伏の時と考え、「最低のハードルを超える」ことに集中するほうがよさそう。 余裕のできた時にまた増やせばいい。とはいえしばらくは確定申告したりで余裕がなさそうだが・・・
悪い習慣をやめる
年末年始で自分の習慣づくりに取り組んでいたが、良い習慣を続けるより悪い習慣をなくす方がずっと難しい気がする。
以前知り合いになにかやっている習慣はある?と聞いたことがあった。 悪い習慣の答えが多かったので、そちらを直す方が需要がありそうだと感じた。
悪い習慣をやめるためには、良い習慣を続けるためのコツの逆をやればよい。
つまり
- 悪い習慣のきっかけを環境から取り除く
- 悪い習慣を避けることで得られる利益を強調する
- 悪い習慣にたどり着くまでのステップを増やす
- 誰かに行動を見張ってもらう
あたり。
難しいのは、悪い習慣はふいにやってしまうものなので、いくら意識していてもそのタイミングで忘れているor意志が弱いと簡単にやってしまう点。
個人的に具体的に無くしたいのがネットサーフィン。対象にするサイトは結構色々あるが、まぁネットには誘惑が多い。
twitterはパスワードをわからなくする(必要あれば再発行)することでいい感じに離れることができたが、他は難しい。
難しい要因として、
- twitterのようにログインが必要な場合はパスワードをわからなくすればよいが、ログインが必要ない場合はurl叩けば見えてしまうのでダメ。
- さらにurl叩けば見える、だと色々なブラウザから開けてしまう。例えばPCとスマホ、それぞれのユーザーごと。chromeの拡張機能でサイトブロッカーとかもあるけどブラウザのユーザーを使い分けてるとすべてにブロッカー入れないと行けないのでダルい。
基本的に無くしたいが、時々は見てもよいと思うのだが、そうするとブロックの設定を入れたり消したりしなければいけず、更に難しい。
準備をするという習慣
とも関連して。
習慣にするぞ!といっても結構いとも簡単に忘れがちである。 例えば朝起きたら運動する、と決めていても、朝は頭が働かない・バタバタして忘れてしまったりする。
また悪い習慣を断つことを考えるときも、よく引っかかりがちである。 悪い習慣の経ち方には、それをしそうになったときに別の行動をとる、という習慣を立てるのがよいが、しそうになるときは大概突発的なので、反射的に悪い習慣をやってしまうことが多い。
これらに対して、準備するという習慣をいれておく、のがよいなーと思っている。
朝起きたら運動するという習慣のために、夜寝る前に運動着を枕元に置く、という習慣を作っておく。 あるいは仕事初めにブログを書くという習慣のために、仕事終わりにブログのエディタを開いておく、という習慣を作っておく。
タバコを吸いたくなったらガムを噛むという習慣のために、家を出る時にポケットにガムを入れるという習慣を作っておく。
もちろん準備の習慣も忘れると思うが、準備は割といつでもできるので自分の好きに設定しやすいし、習慣の終わりに次の習慣の準備をするようにしておくのでも自動でやることになりやすい。
習慣の手順書作成・自動化
習慣を明確にする
習慣にするとき、やることを明確にするのは非常に大事である。
研究者が「実行意図」と呼ぶもので、いつ、どこで行うか、予め立てておく計画である。
...
多くの研究により、実行意図は目標達成に効果的だとわかっている。
ジェームズ・クリアー式福利で伸びる1つの習慣 第5章
いつどこで何をやるのかを明確に決める。
タスクの分割
ここで習慣から離れて仕事術てきなところになるが、大きいタスクは細かく分割せよ、というものがある。 大きなタスクのままだと何をやればわからず 不安 が発生するので、細かく分割し、1つずつこなしていけばよいというものである。
更にいうと、定期的に実行してルーチン化するようなタスクは、誰でも出来るように手順書を書く・自動化するのが効率化につながる。
習慣の手順書・自動化
これを習慣にも繋げられないだろうか。つまり習慣の際の手順書を作ってみる。
例えば 毎日腕立てを50回する
のであれば
- 運動着に着替える
- 水をコップに入れる
- 腕立てを1回やる
- 腕立てを5回やる
- 腕立てを10回やる
- 腕立てを50回やる
これにより、やることがより明確になり、目の前のステップをこなすことで自然と大きな習慣を達成できる。
またこの手順が自動で実行できるように工夫する。ここでいう自動化とは、機械やコンピュータが勝手にやるようにする、というよりも 自分の体が自動的に動くようにする ということである。
先程の例だと、運動着や水の準備がすぐできるよう、前日の段階でこれらを目につく場所に置いておく等である。 置いてある運動着やコップを見た瞬間、自分自身のスイッチが勝手に入り、習慣を自動的に行う。
習慣のハードルを下げる
手順書を書いたことで、習慣の一番最初に行うことが見えてくる。 これを最低のハードルに設定し、それを1日1回行えば習慣が達成できたことにする。 運動着に着替えるだけならばどんなに時間がなくても毎日続けられるし、また手順書を作っているので、次の手順まではやろう、とモチベーションも上がりやすい。
このあたりがうまく出来るようなアプリ作りたいな〜と考えている。
ハードルを下げる
ハードルを下げる
激短時間でできることを習慣とする。5分でできることとか1分でできること、とかも耳にするが、個人的には 10秒 で良いと思う。
その日の習慣を達成するまでなにか続けなければいけないではなく、本当にやれば終わるもの。
毎日したいことを頭に浮かべて、実際にやることを洗い出してみる。そして一番最初にやることを習慣としてやることにする。
- 運動をする、という習慣であれば運動着に着替える
- 勉強する、であればペンを持つ
- ブログを書く、のであればエディタを開く
- 部屋の片付け、であれば物を1つ移動する・捨てる
どれくらい効果あるの?
根底にあるのはとにかく やる
のを 続ける
ということ。
やる気・モチベーションは実際に行動していると自然に出てくるものなので、やる気が出てきた時にしか出来ないようなものは習慣にすべきではない。
やる気が出てこなくても出来るものを習慣にして、それにより弾みがついてやる気が出て、最終的に多くのことができるようになる。
やる
のを 続ける
ためにも、ハードルを激低に設定するべし。