言いたいことはそれだけか

KotlinとかAndroidとかが好きです。調べたことをメモします。٩( 'ω' )و

南の島で読んだ本たち

先日ふらっと南の島(タイのサムイ島)に行ってきた。日常から頭を切り離すことが目的でとにかくぼんやりしてみたくなったのだ。 ぼんやりするにも時間は潰したいので本を持って行くことにしたのだか、日常を想起させる技術書・ビジネス書はNGという縛りで何冊かピックアップ+Twitterでオススメしてもらった本を持って行った。その備忘ログ。

f:id:muumuumuumuu:20180228234012j:plain

1冊目:走ることについて語るときに僕の語ること(村上春樹

走ることについて語るときに僕の語ること (文春文庫)

走ることについて語るときに僕の語ること (文春文庫)

村上春樹によるエッセイ。村上春樹の書籍は「村上さんのところ」くらいしか読んだことがなかったが、私もサボりがちながらも走ったりするので以前から興味があり購入。走ることだけじゃなくて、著者の考え方だったり作家という職業だったり、ほんの少し知らない世界が覗き見れた気がして楽しかった。

2冊目:美味礼讃(ブリア=サヴァラン)

美味礼讃

美味礼讃

19世紀のフランスでベストセラーになった書籍の玉村豊男の新訳の方。新訳じゃなかったら絶対に途中で心折れてただろうなってくらい訳が秀逸。訳だけじゃなくて、2,3ページに毎くらいに解説(ツッコミ?)が入っているのが楽しくてどんどん読める。食(美味学)というのが本書のテーマだが、食だけじゃなくて恋愛とそれに関わる一連の行動について謎の圧で語られていて笑える。

3冊目:サイコパス(中野 信子)

サイコパス (文春新書)

サイコパス (文春新書)

新宿紀伊国屋の精神医学や犯罪心理学の棚で見つけた一冊。これはかなり当たりだった!!本書はサイコパス脳科学の観点から解き明かして行く。目次をみただけでもサイコパスと恋愛はできるか」サイコパスかもしれないあなたへ」サイコパス向けの仕事を探そう」という具合にパワーワードが並ぶ。身の回りの誰かの顔を思い浮かべながら読むと楽しい。

ここまでの3冊は自分で選んで買ったもの。以降はTwitterでオススメしてもらったものたち。

4冊目:世界の終わりとハードボイルド・ワンダーランド村上春樹

世界の終りとハードボイルド・ワンダーランド

世界の終りとハードボイルド・ワンダーランド

またまた村上春樹。こちらはshiroyamaさんのオススメの一冊。

村上春樹の小説初めて読んだけど、ミステリー調で想像していたものより100倍読みやすかった!食べ物とお酒とファッションと音楽と女の子が魅力的に語られるシャレオツ小説でした。世界の終わりの影が好きでした。ハードボイルド・ワンダーランドの方だと博士と図書館の女性が好き。あと、よく「やれやれ」っていうと村上春樹っぽいってインターネッツでネタにされてるのがようやく理解できた。本当にたくさん「やれやれ」って言ってた。

5冊目:EAT&RUN(スコット・ジュレク)

EAT&RUN 100マイルを走る僕の旅

EAT&RUN 100マイルを走る僕の旅

こちらはimaiさんのオススメ。ヴィーガンウルトラマラソン走っちゃうとんでもない人の自伝。

「とにかくいいからやるんだ」期と「どうやったら勝てるか?」を考える期、どちらが適切か受け入れる姿勢は取り入れていきたい。そんな難しいことを考えながら読んで勉強になったけど、最後にはシンプルに「あぁ、走りたいなぁ」と思えるいい本だった。

6冊目:仁義なきキリスト教史(架神恭介

こちら、オススメしていただいた時の元tweetが消されているため、本当はオススメじゃなかった説あるけど気になったので読んだ。色々ぶっ飛んでて楽しかった!セリフが全部広島弁の極道。多少なりともキリスト教の知識があったほうが笑えると思う。これ読んで日本帰ったらポプテピピック8話が同じく広島弁極道ネタだったのでまた笑えた。

以下、持っていけなかったけどオススメしてもらったのでいつか読みたい本たち。

おまけ1:野火(大岡昇平

野火 (新潮文庫)

野火 (新潮文庫)

こちらはkurokawaさんオススメ。あらすじ読んで怖くなったのでいつかメンタルが強くなったら読みたい。

おまけ2:孤島の冒険(N. ヴヌーコフ)

孤島の冒険 (フォア文庫)

孤島の冒険 (フォア文庫)

こちらはmitsuyoshiのオススメ。児童書なのかな?絶版っぽいので今度会った時に貸してもらう。

おまけ3:蜜蜂と遠雷恩田陸

こちらは鍵付きアカウントからのオススメ。恩田陸は高校生の頃めちゃめちゃ読んでたなぁ。

おまけ4:グラゼニ(原作 森高夕次 漫画 アダチケイジ)

こちらはnakagawaさんのオススメ。Webコミックなのかな?

www.moae.jp

野球のことは全くわからないけどせっかくオススメされたので読んでみたい。




こうやってみると仕事以外だと食べることと走ることに興味があるんだなー。

DroidKaigi公式アプリにRTL周りのPull Request出した時にやったことまとめ

DroidKaigiお疲れ様でした!公式アプリでRTL周りのPull Requestを出したので何をしたのか備忘録のメモを残しておきます。

Issue

github.com

Pull Request

github.com

やったこと

Left / Right をgrepして適切なものに置き換え

ConstraintLayout周りとかLintで指摘してくれないものがあるのでleft / rightgrepした方がいいと思います。 grepした結果を機械的に置き換えれば良いというわけではなく、例えば情報としてはひとまとまりなんだけどviewとしては別れているみたいなケースがあります。

例えば、下記の画像の場合、

f:id:muumuumuumuu:20180214101601p:plain

What is " が一つのTextView, DroidKaigiが一つのImageVIew, " ? が一つのTextViewで構成されています。 RTL表示の場合でも英字はLTRの方向で表示するため、単純にleft / right をstart / end に置き換えてしまうと表示がおかしくなってしまいます。

上記のように色々試行錯誤した結果たどり着いたのがこちら。

具体的に書くと、DroidKaigi のImageViewの(画像自体に)左右に余白を取って、そこを起点に左右のViewに制約をつける方法で回避しました。

今気がついたんだけど、なぜか" ?の方だけRTL設定の時に? "になっちゃってますね。 What is "の方は大丈夫なんだけど。
" ?の方のTextViewにandroid:textDirection="ltr"を指定してLocaleに関係なく文字方向を固定することで回避できます。

Localeに関わらずTextViewにRTLを強制する場合は android:textAlignment を設定

例えばこのような条件の場合、

  1. アラビア語のリソースをvalues-ar配下に定義
  2. widthがmatch_parentなTextViewのtextに1のリソースを設定
  3. 端末の言語設定をアラビア語に設定

2で設定したリソースは右から表示されます。

今回のDroidKaigiの公式アプリはアラビア語リソースは用意されていないので、「開発者向けオプション」> 「RTLレウアウト方向を使用」にチェックを入れて表示確認をして行きます。この場合だと英語リソースのままレイアウト方向はRTLになりますが、逆にいうとレイアウト方向しかRTLにならないのでmatch_parentなTextViewのtextは左から表示されます。

こんな感じ。

そこでandroid:textAlignment="viewStart"を設定することでレイアウト方向とテキスト方向が連動するようになります。

directional symbolは反転させる

directional symbolって日本語でなんていうのがポピュラーなのかわかっていませんが、矢印のように方向性を持ったシンボル(そのまんまや…)のことです。Droidkaigi公式アプリではほとんどvector drawableでアイコンが作られていたので<vector>tagのなかにandroid:autoMirrored="true"を指定してやればRTL表示時に反転します。

stringsのplaceholderは(必要があれば)RTL用のものを作る

そのまんま。必要があればこんな感じでRTL用のplaceholderを作ります。

     <string name="room_format" translatable="false">%1$s%2$s</string>
     <string name="room_format_rtl" translatable="false">%2$s%1$s</string>

アラビア語のリソースを用意するのであれば不要かもしれません。ケースバイケース。
上で書いたように今回は同じ言語リソース(英語と日本語)でRTLの場合とそうでない場合に対応するのでコードで、動的にどちらを読むか判断しています。 どちらを読むかについては下記の拡張関数を作ってレイアウト方向をチェックして判断するようにしました。

fun View.isLayoutDirectionRtl() =
        resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL

コードからPadding設定するとき用に拡張関数作る

View#setPadding() メソッドは引数を4つ持ちますが、そのうち第1引数は(startではなく)left固定、第3引数も同様にright固定となります。そのため、RTL表示の場合はleftとrightを入れ替える拡張関数を作りました。

fun View.setPaddingWithLayoutDirction(start: Int, top: Int, end: Int, bottom: Int) =
        if (isLayoutDirectionRtl()) {
            setPadding(end, top, start, bottom)
        } else {
            setPadding(start, top, end, bottom)
        }

おまけ

全く気がつかなかったのですが自分のPull Requestにtypoがあって気がついた方に直してもらいました…

圧倒的申し訳なさ…!

AndroidのMVIについて勉強した時のメモ

AndroidのMVIについて勉強した時のメモです。自分用のメモなので雑です。

MVIとは

MVCを元にして、jsのreduxやreactの思想を取り入れた何か」のようなもの。リアクティブで関数型プログラミングを採用している。

MVCだとViewを操作するのがControllerかもしれないし、Modelかもしれないが、MVIはreduxのようにデータの流れが単一方向。また、Reduxのようにいろんな部分を純粋関数で記述するのでテストも書きやすい。

詳しくは

この辺のリンクに目を通したらだいたいわかった気になれる。

hannesdorfmann.com

yuyakaido.hatenablog.com

github.com

雑感

Reduxと違うところ

すでにReduxが何か理解している人向けに書くと、Reduxと比べてこの辺が良さそう。

  • 非同期処理というかデータの取得と整形をProcessorでやると定まっている
    • Reduxだとこの辺がふわふわしている印象
      • ほとんどの人はCreatorProducerがやるんだろうけど
    • 初めての人でも迷わなさそう
  • ActionとIntentが別れているのが良い
    • ReduxだとViewがCreatorProducer経由でAction発行するの、わかるんだけど、User観点で何をしたいのか?と実際にデータをどうするか?を分けて記述できるのがわかりやすい
  • ActionとResultが別れているのが良い
    • ReduxだとActionに変更したいstateのデータを詰める感じだと思うけど、それをResultという別のものとして扱うのが直感的
  • ユーザの入力によって何をするべきかというのがコードで表現される
    • あまり仕様を書かない文化のチームだと助かる場面があるかも

一方、Reduxと比べてこの辺つらみありそうというところもあって、

  • SingleなStoreの概念がないので、一箇所で集中管理する感じではない
  • ViewModel層がいかつい
    • 細かく切ってる分ボイラープレート増える
      • IntentとAction増えてくるとここまでする必要あるのかな〜って気分になってきそう
  • まだそんなに流行ってないので知見がweb上で見つかりにくい

で、どうなの

自分の中では結局「どういうプロダクトかによる」という普通かよ〜〜〜みたいな結論になった。ユーザの入力というかIntentの種類がたくさんあって、かつ結びつけるActionがバラバラだったりすると、ActionをIntentを分ける恩恵はありそう。今Reduxを採用しているAndroidアプリの中からMVIに移行するケースがあれば話を聞いてみたい。でもStoreがないのでAndroidで採用するほどのモチベーションがありそうなケース、そんなになさそうかも?

今年のDroidKaigiでMVIのセッションがあるので今から楽しみにしている。

droidkaigi.jp

完全に余談になるが、AndroidでIntentというとおそらく大多数の人がandroid.content.Intentだと思うし、Processorio.reactivex.processorsを連想する人が多いと思う。名前の衝突が発生して、今どちらについて話しているのか?の認識合わせをしながらコミュニケーションとって行く必要があるので地味にストレス溜まるかもしれないなーと思った。チーム開発で取り入れてみないと何も言えないけれど。

おまけ:本家Circle.js

Twitterで釘宮さんに圧倒的知見をいただいた。感謝!

本家Cycle.jsだとかなりシンプルな構成で、DOM source(入力)とDOM sink (出力)を繋ぐのは、intentとmodelとviewだけ。面白いのはintentとか含めだいたいstreamとして扱われるところ。reactだからかな。

こんなにスッキリかけるのは羨ましい。

function main(sources) {
  return {DOM: view(model(intent(sources.DOM)))};
}

cycle.js.org

また、Eggheadのvideoコースもわかりやすいので、jsと英語にアレルギーがなかったらみてみると良いと思う。

egghead.io

[海外対応] AndroidのLocale周りまとめ [多言語対応]

はじめに

複数の国や地域、あるいは言語に対応する場合に避けられないMulti Locale対応ですが、Android Frameworkのバージョンによってできること・しなくてはならないことが変わって来ます。 各APIでの大きな変化を時系列でまとめてご紹介します。 また、実際にMulti Localeに対応して来た中で遭遇したハマり所とその対策方法・tipsなども共有していきます。

ってDroidKaigi2018のCfPに応募したけどRejectされたのでブログにまとめます😇 「急にグローバル対応しなきゃいけなくなったけど何していいかわかんない!」みたいな人にざっと見ていただきたいような内容です。

それでは各APIで何が対応されたのかまとめます。ハマり所とその対策方法とかは別のエントリで書けたらいいな。

Locale周りの変遷

API Level 1 : Localeの基礎

LocaleクラスはAPI Level 1の時代から存在している。というかAndroidで独自に定義したものではなく、java.util.Localeを使っている。そもそもLocaleってなに?という話をすると、ドキュメントには

A Locale object represents a specific geographical, political, or cultural region.

と定義されている。単に国というわけではなく、地理的・政治的・文化的な特定の地域をさすものである。例を挙げると、日本だとja-JPになる。これはlanguageとcountry(region)を合わせたものだ。この頃はlanguage codeについてはISO 639-1、region codeについてはISO 3166-1で定義されているものが使える。後述するが、API Level 24以降ではIETF BCP 47をサポートする。

「地理的・政治的・文化的」という部分について補足すると、languageにおいて同じ中国語でも簡体字繁体字が別のものとして扱われていたり、regionの方も中国(本土)と香港と台湾が別のコードが割り当てられている例がわかりやすいかもしれない。

さて、話をAndroidに戻そう。LocaleオブジェクトはContextからgetResources()getConfiguration()と経由して、Configurationのpublicなメンバであるlocaleにアクセスすることができる。アプリやActivity独自でLocaleの設定を持ちたい場合は、ApplicationやActivityのContextのlocaleを書き換えることで言語切り替えを行うことができる。具体的にはいい感じにLocaleを書き換えたConfigurationオブジェクトを使って Resources#updateConfiguration()を呼んでやるとできる。(端末の言語設定に従う場合は端末で設定したLocaleがここに入ってくるので特に個別のアプリで対応する必要はない。)端末の言語設定で何が選択されているか知りたい時にはLocale#getDefault()が使える。

では各Localeごとのリソースをどう定義するか。ドキュメントはこの辺りを参照してほしいが、ざっくりいうとres/配下のディレクトリにconfig_qualifierを付与することでLocaleごとのリソースを定義することができる。ディレクトリ名のルールはこのようにハイフンつなぎ。

<resources_name>-<config_qualifier>

例を挙げると、 アメリカ・英語用の言語リソースは下記のように定義できる。valuesresources_nameenrUSconfig_qualifierだ。

values-en-rUS/strings.xml

上記の例のように、qualifierはハイフンで複数繋げることができる。Localeクラス同様languageは ISO 639-1、regionは ISO 3166-1で定義されたものが使える。ただし、regionの方は頭にrをつけなければならない。なぜかというとcase sensitiveではないので、ハイフンでqualifierを繋げた場合にregionを明示的に示すために必要なのだ。また、regionを指定する場合は必ずlanguageとセットで指定しなければならない。(region単体では使えない。)

例ではvalues/を示したが、values以外にももちろん使える。例えばdrawable/でも文字埋め込み画像の出し分けをするのに必要だし、xml/menu/でLocaleによって機能の出し分けをするのに使うことができる。

API Level 17 : RTL対応

ここからConfigurationクラスにsetLocale()メソッドが追加された。とは言え、このクラスのメンバであるlocaleはpublicのままだ。では直接localeの値を書き換えるのとsetLocale()メソッドでやっていることは何が違うかコード見てみよう。

     /**
      * Set the locale. This is the preferred way for setting up the locale (instead of using the
      * direct accessor). This will also set the userLocale and layout direction according to
      * the locale.
      *
      * @param loc The locale. Can be null.
      */
     public void setLocale(Locale loc) {
         locale = loc;
         userSetLocale = true;
         setLayoutDirection(locale);
     }

まずはlocaleの更新を行なっている。これは予想通りだろう。次にuserSetLocaleフラグをtrueにしている。このフラグはpublicだがhideアノテーションが付いている。これはActivityManagerServiceがsystem propertyにlocale情報を書き込む時に使われる。 そして最後のsetLayoutDirection()メソッド。これもAPI Level 17から追加されたAPIだ。何をしているかと言うと、どちらからどちらの方向にレイアウトするをLocaleから判断している。

「どちらからどちらにレイアウトするか」と聞いてピンと来ない人がいるかもしれない。我々が普段目にする文字は(横書きの)日本語であれば左から右方向に流れる。よく目にする英語もそうだ。しかしアラビア語ヘブライ語など一部の言語では横書きでも右から左に文字を記述する。右から左、なのでRight to Left, 頭文字をとってRTL言語と言われる。文字だけでなく、ボタンの位置などもRTL方向に配置する必要があるが、言語によってレイアウトを複数分けて用意する必要はない。例えばRelative Layoutの子要素として、TextViewとその右にButtonを置きたいと思ったらandroid:layout_toRightOf ではなくandroid:layout_toEndOfを使おう。これもAPI Level 17から追加されたattributeだ。このattributeを使っているとsetLocale()を使ってLocaleを更新した際に画面の再描画が走って適切なLayout Directionで表示されるようになる。

API Level 24 : Multi Locale

このAPIバージョンから java.util.Locale が変わってIETF BCP 47をサポートするようになった。これによりサポートされる言語が大幅に増えた。 また、Multi LocaleをサポートするようになったのもAPI Level 24からだ。

Multi Localeについては以前ブログにまとめた。

muumuutech.hatenablog.com

詳細は上記を読んでもらうとして、ざっくり概要を書くと「これまではユーザは言語を一つしか設定できなかったが、このバージョンからは複数の言語とその優先順位を設定でき、かつシステム側もいくつかLocaleを準備しておくことによってより良いマッチングを行うことができる」ものである。

いくつかの言語をユーザが設定できるという部分だが、これに伴いConfigurationクラスのAPIにいくつか変更が入った。具体的には単一のLocaleを引数に取る setLocale() 、またpublicメンバのlocale がdeperecatedになった。代わりに使用が推奨されるのがLocaleListクラスを引数に取るsetLocales()だ。

    public void setLocales(@Nullable LocaleList locales) {
         mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales;
         locale = mLocaleList.get(0);
         setLayoutDirection(locale);
     }

3行のシンプルなメソッドだ。Localeのリストを更新して、その優先順位トップのものを現在のLocaleとして設定、最後に現在のLocaleに応じたLayout Directionを設定する。

ちなみにLocaleListクラスがマッチングをやってくれる。ロジックはこの辺。以前blogにもちょっと書いた。

muumuutech.hatenablog.com

API Level 25 : Configurationの設定方法が変わった

Resources#updateConfiguration() がdeprecatedになった。代わりに何を使うのが推奨されているかというと、Context#createConfigurationContext()だ。(このAPIが追加されたのはAPI Level 17。)ただし、これは引数で指定したConfigurationが設定された新しいContextオブジェクトを返してくれるだけだ。ここで生成したContextをActivity#attachBaseContext()に渡してやると新しいConfiguration(と、これが持っているLocale)が設定される。

Twitterで教えてもらいました。感謝!)

API Level 26: Configurationの共有範囲が変わった

API Level 25でdeprecatedになったResources#updateConfiguration()だが、25までは一度コールするとその設定がapplication内で共有されていたが、API Level 26からは各activity/applicationで別の設定になった。

このあたりの記事が参考になった。

proandroiddev.com

最後に

以上でざっとLocale周りの変遷を書いた。最後の方とかLocaleともはや直接関係ないんじゃ…という気がしなくもないが、多言語、海外対応する際に必要になるケースも多いのではないかと思うので消さずに残しておく。

それにしてもAPI Level が上がれば上がるほどアプリ内で独自の言語設定させていかないぞ♡というGoogle先生のお気持ちが強まっているのかなと思わずにはいられない😇 😇 😇

Kotlin 1.1以降をAndroidで安全に使いたかった話

はじめに

この記事は「Kotlin 1.1以降をAndroidで安全に使いたかった話」です。本当は会社のAdvent Calendar向けに書くはずだったのですが、色々あってお蔵入りになったのでこちらで供養。 ちなみにこれはボツネタ第2弾で、第1弾はこちら。 muumuutech.hatenablog.com

Kotlin 1.1 とJava 8

Kotlin 1.1がリリースされて久しいが、1.1.系からJava 8 に依存したAPIがいくつか追加された。AndroidAPI Level 24からJava 8 に対応しているので、23以下の端末でうっかり該当APIが実行されるとCrashしてしまう

Java 8 に依存したAPI@PlatformDependentアノテーションが付与されている。今の所このアノテーションが付与されているのは、MapインターフェイスgetOrDefault()MutableMapインターフェイスremove()の二つ。

これらのAPIを安全に扱うためにCustom Lintの導入を試みた。1

Custom Lintを作ろう

Android LintもしくはJava Lintに使えそうなものがないか確認したところ2なさそうなので作っていく。gradleの設定をして、Detector, Issue, Registryの順に作っていく。

最初にGradleでビルドするプロジェクトを作る。言語は今回Kotlinにした。

Gradle

プロジェクトができたらGradleを書いて行く。 lint-apilint-checksを追加する。(kotlinを使う場合はkotlin用の依存も追加)

dependencies {
    def lintVersion = "25.3.0"
    compile "com.android.tools.lint:lint-api:$lintVersion"
    compile "com.android.tools.lint:lint-checks:$lintVersion"

}

そしてここがポイントなのだが、Lint-Registry-v2 でRegistoryを定義する。色々ググったらLint-Registryで定義している情報が出てくるが、2017年末時点ではLint-Registry-v2で定義しないとLintがうまく動かなかった。(これに気がつかず何時間も無駄にしてしまった…)

jar {
    manifest {
        attributes("Lint-Registry-v2": "com.your.package.CustomLintRegistry")
    }
}

Detector

今回やりたいことは「特定のアノテーション(@PlatformDependent)が付与されたAPIを使用した際にwarningをだす」である。本来であればJavaPsiScannerを使ってASTに解析されたノードを探索して行って…みたいなことをするべきなんだろうけど、Advent Calendar向けにはヘビィだったので妥協案でいくことにする。

該当APIが付与されたAPIはたったの2個なので、「それらが使われた時にwarningをだす」でとりあえずお茶を濁すことにする。特定のコードが記述されているか検知したいので(まずはよく使うgetOrDefault()でlintチェックが出るか試す)、 ClassScanner インターフェイスを使い、必要なメソッドをoverrideしていく。

getApplicableCallNames()

detectorが検知したいメソッド名のリストを返すメソッド。今回は特定のメソッドがコールされたことを検知したいので、そのメソッド名をstringのmutable listにして返してやる。

    override fun getApplicableCallNames(): MutableList<String> = mutableListOf("getOrDefault")

checkCall()

detectorが上記getApplicableCallNames()で定義したメソッドを検知すると呼ばれるメソッド。本当はpackageのチェックとかやらなきゃいけないがとりあえずノーチェックで通す。

    override fun checkCall(context: ClassContext?, classNode: ClassNode?, method: MethodNode?, call: MethodInsnNode?) {
            context?.report(ISSUE, method, call, context.getLocation(call),
                    "Don't use Java 8 dependency API")
    }

Issue

DetectorクラスのstaticなオブジェクトとしてIssue.create() メソッドを使って作成する。 適当に各パラメータを設定しよう。Implementation の第1引数には上記で作成したDetectorのクラスオブジェクトを渡す。

class CustomLintDetector : Detector(), Detector.ClassScanner {

    companion object {
        val ISSUE: Issue = Issue.create(
                "Java8Api",
                "Java 8 API is used",
                "Java 8 API is used. This causes crash with Android OS level under 23.",
                Category.CORRECTNESS, 6, Severity.WARNING,
                Implementation(CustomLintDetector::class.java, Scope.CLASS_FILE_SCOPE))
    }

Custom Lintを実行する

ここまでで作ったプロジェクトをbuildして作成されたjarファイルを.android/lint/配下に格納し、./gradlew lint コマンドを叩けばlintが動く。

ここからが本当にわけがわからないのだが、fat jarにしないとうまく動いたり動かなかったりする。(自分で書いていて「そんなことある?」って今思ってます…)

jarファイルを作る環境のJavaのバージョンだったり、gradleのバージョンだったりをいくつか試してみたが、どういう時に動いてどういう時に動かなかったか全然切り分けができなかった。Gradleのcacheを疑ったがこれもダメ。

そう行ったわけでQiitaで書いているAdvent Calendarに載せるわけには行かなかったのでこちらで供養。なんだかモヤモヤしたままだが、とりあえずfat jarにしておけばこんな感じでCustom Lintを作ることはできた。f:id:muumuumuumuu:20180106162609p:plain

感想

Custom ListをよりによってKotlinで作ろうとして一番大変だったのは、とにかくドキュメントがないこと。公式もそうだが、全体的に情報が少ない。ヒットしても数年前のものだったりして現状で動かなくなったりして困った。無駄にCustom Listの中のコードを読んでちょっと詳しくなってしまった気がする… もしもどこかに体系化された素晴らしいドキュメントがあれば教えてください(´;ω;`)

Links

実装にあたりこれらの記事を参考にした。


qiita.com


tools.android.com


Help developers with custom Lint rules · Jeremie Martinez


www.slideshare.net


www.bignerdranch.com


qiita.com


  1. Jet Brains 公式ドキュメントではkotlin-stdlib-jre7kotlin-stdlib-jre8を使えと書いている。kotlin-stdlib-jre7だけを指定するとJava 8 に依存した機能を使った時にコンパイルエラー出してくれるかな?と期待したが、残念ながらエラーは出なかった。kotlin-stdlib-jre8を指定しようと思ったらAndroidではJack and Jillへ依存を持っているようでgradleのsyncすらできなかった。(Jack and Jillはdeprecatedになりましたね…)

  2. むしろデフォルトでチェックがついているJava 8 migration aidsの Replace with single Map methodでMap.getOrDefault()を使うように推奨してきます😇

2017年を振り返る

はじめに

2017年に自分が何をしていたか後から振り返られるようにメモを残しておく。 shirajiさんのエゴサで振り返るというアイディアがとても素敵だったので彼に倣ってtweetをペタペタしていこう。

shiraji.hatenablog.com

1月

自分が業務でやっているサービスのAndroid Appが初の海外対応をリリースして浮かれていた。この時に割と多言語・他地域対応の知見が溜まったのでよかった。

ここでちょっと業務が落ち着いたので以降はDroidKaigiの準備に追われていたように思う。

2月

今まで怖くて入れなかったandroid-jpのslack channelに入ってみた。最近は #generalより #english の方が活発な不思議なコミュニティだった。

そうか、けもふれは今年の2月か…

この頃からランニングを再開していたようだ

3月

DroidKaigiにスピーカーとして参加した。最高に楽しかったけど、今年はrejectされたので聞く側で楽しんできます :p この頃はずっとねこ、えさ、ねこ、って言ってたきがする

muumuutech.hatenablog.com

決める――すべてを一瞬で判断できるシンプルな技法

決める――すべてを一瞬で判断できるシンプルな技法

この時期に読んだこの本はよかった。タスクを分類して意識的にどちらかを減らしてどちらかを増やすということはこれからも意識していきたい。

4月

この頃からPodcastを大量に聴き始める。そういう意味で今年はインプットの方法が大きく変わった。通勤中とかもうほとんど音楽聞かずにPodcastばかり聴いている。

Androidを支える技術〈I〉──60fpsを達成するモダンなGUIシステム (WEB+DB PRESS plus)

Androidを支える技術〈I〉──60fpsを達成するモダンなGUIシステム (WEB+DB PRESS plus)

Androidを支える技術、今年はAndroidエンジニアの中で流行ったなー。いい本だ。

5月

KotlinがAndroid公式サポートされた。便乗して会社のTech Blogを書いていた。

自宅の引越しを行ったのもこの時期。都民デビュー。

6月

今度は自宅ではなくオフィスも引越した。

引越し直前にオフィス近くの人気店とだかを貸し切って美味しい食事をしていた。

SHIROBAKOに手を出し始めたのもこの頃。

7月

Swiftに手を出し始めたようだ。

アラサーにして初めてまともにドラクエをみた。夫がPS4ドラクエ11をやってるのをところどころチラ見していたけど衝撃のストーリー展開にびっくりしすぎて自分でもやり始めた。セーニャちゃんと結婚したかった…

8月

Lisp本を読み切った。なんだかんだネタ枠と言いつつ意外とよかった…

会社でやっているもくもく会が20回を突破。 もくもく会については最近ポエムも書いた。

muumuutech.hatenablog.com

Swift入門枠で登壇もやった。

Fearless Change アジャイルに効く アイデアを組織に広めるための48のパターン

Fearless Change アジャイルに効く アイデアを組織に広めるための48のパターン

omoiyari.fm でおなじみのFearless change、すごくいいことが書いてた。でもやっぱり実践するのは難しいなーと思い知った年でもあった。

9月

muumuutech.hatenablog.com

KotlinとReduxの話を自社イベントでしてきた。

Android エンジニアTシャツ、この日以降まだ出番はない。

10月

この頃からTwitterをはじめ色々なwebサービスで設定しているアイコンを自分の顔写真にした。

11月

DroidKaigi 2018のCfPが不採択でショックを受けるなか、その日は外部の勉強会でKotlinとサービスについて話してきた。

ハーフマラソンを走った。20km以上走るのは7年前のフルマラソン以来だったので不安だったが無事完走。

ずっとファンだったPodcastにゲストとして呼んでもらった。感動した。

12月

社内のエンジニア向けに「Androidではじめの方に知っておきたかったこと講習会」みたいなことをやり始めた。これは機会があれば資料を綺麗に作り直してどこかに出したい。

仲間内でクローズドなPodcastごっこを始めた。

来年

DroidKaigi 2018のセッションの解説をする。プレミアムフライデーって本当に実在するのか…。解説陣がgfxさんshirajiさんと(私はともかく)豪華なので楽しいと思うのでぜひご参加ください。 connpass.com

おまけ

夫が可愛いシリーズ

KotlinJSでReact Nativeを書いてみたかった話

はじめに

この記事は「KotlinJSでReact Nativeを書いてみたかった話」です。つまりできなかった話 であることをあらかじめご了承ください。


では本題。

年末になり会社のAdvent Calendarのネタ探しをしている最中に電波が降りて来た。

当時Kotlinが好きすぎてちょっとおかしくなっていたのか、「SwiftではなくKotlinでiOSかけたら最高では?😇 」「でもKotlin/Native で書くのはちょっとまだ早すぎるよな〜〜😓」「あれ?KotlinJSでReactNativeいける!?!?」

ネタとしてもちょっとおもしろいかなと思いやってみることに。

ちなみにKotlin/Nativeまだ実務ではつらいよねって話は同僚がまとめてくれた記事が良いので興味ある人はぜひ読んでほしい。せめて補完が効くようになったら起こしてください( ˘ω˘ ) スヤァ…

qiita.com

React NativeとKotlinについて

React NativeはJavascriptで記述する。その名の通りReactベースなのだが、コンポーネント部分をそれぞれのプラットフォームのブリッジでごにょごにょしてくれるのでnativeとして動く。つまり、AndroidであればJava1iOSであればSwiftのコードになる。2

一方Kotlinは1.1よりJavascriptへのコンパイルをサポートした。どういうことかというと、Kotlinで書いたコードがJavascriptにconvertされるということ。

これらを組み合わせて、

  1. React NativeでJavascript部分をまずはKotlinで書いて、
  2. それをJavascriptに変換し、
  3. さらにブリッジを経由してJavascriptが対応するSwiftもしくはJavaのコードとして動作

これにより実質KotlinでReactNativeでは?というのがやりたいことになる。

やってみた

まずはReact Nativeのプロジェクトを用意する

このへんをみて適当にプロジェクトを作る。まずはデフォルトで生成されるJavascriptがちゃんとアプリで表示されることを確認。デフォルトの画面が表示されえたのでOK。

JSのコードをKotlinに置き換えたかった

Kotlin JS がサポートしているビルド方法は下記4種類。

それぞれCompile後にjsファイルが吐き出される。

React NativeはReactで動いているので、まずはReactをimportする。 Kotlinを開発しているJetBrains社がWrapperを用意してくれているのでこいつをinstallする。

npm i @jetbrains/kotlin-react

次にReactNativeのコンポーネント部分をimportしよう、と思ったところでそんなものは世の中に存在しないことに気がついてしまった。

自分で書くにはJS力足りないし、何よりもはやAdvent Calendarのネタとしては重すぎるよな〜〜というわけでお蔵入りになりました :p


というわけでボツネタ供養でした :pray:



  1. 独自コンポーネントをKotlinでかけばKotlinに変換されるという理解

  2. React Nativeは軽く技術検証したくらいしか触ってない。業務でがっつり使ったわけではないので間違ったこと書いてたらすみません…