解せぬ日記

雑な話をする

画像ビューアを作ってみている話

macOS用の見開き画像ビューアがほしいなぁと思い、車輪の再発明をすべく画像ビューアを作り始めた。最初Electronで作っていて、最小の機能の付いたそれっぽいものを作った段階でいかんともしがたい問題にぶつかり、一旦、他の技術も見てみようと、QtのGoバインディングで作り直してみてる。

成果

何はともあれ成果です。

vimeo.com

vimeo.com

Electronの問題

Electronで一通り作り終えた時に、サムネイル画像のキャッシュなどを作らずにオリジナルで表示してたので、メモリの使用量がどんなものになるのか気になって調べた。いろいろ調べているうちに、macOSで画像を切り替えまくると爆速でメモリが1.5GBぐらいまで増加していくことが分かった。画像自体は全体で110MBほどなのでいくら何でもひどい。待っていても開放される気配は一切なく、Chromeのプロファイラを見た限りではJS Heapなどはたいしてメモリを食っていなかったのとGCは走ってるように見えたので、DOMリークなのかなと思っている。とにかく何をしても解消しなかった。Chromiumの複数バージョンを試して、それっぽいバグは再現できたけど、既にバグ報告はしてあり最新版では再現しない。加えてWindowsLinuxでは特に問題なくてメモリも開放されてるので、内部のChromiumのバージョンが上がったら直りそう。ちなみに次のバージョンでは直ってなかった。

QtのGoバインディング

github.com

上記のやつを使っている。ただデバッグがやりにくくて萎えそう。独特の文法みたいなものが必要にはなるものの、サンプルも結構用意してあるので、それを読めば割とイケる。

https://github.com/therecipe/qt/tree/master/internal/examples

Qt自体はQMLというインターフェースのためのマークアップ言語を用意していて、Javascriptが利用可能でJavascriptにロジックを追いやったりできるので、そこはとっつきやすい。ちなみにQtの最新版である1.9.1を使っていたら、QMLのImageでメモリリークが起こっていて、笑うしかなかった。バージョンを下げて対応した。

今後

QtのGoバインディングのデバックについて、もうちょっといいやり方がないか調べたりして、知見ためたい。もう少し試してみて、ElectronかQtのGoバインディングにするか決めようと思っている。

雰囲気でマイクロサービス入門をやってみた

ごんげお兄さんのエントリーを見て、興味あったのでやってみた。

gong023.hatenablog.com

TL;DR

  • お兄さんのエントリー通りやると、雰囲気が分かるので超お勧め
  • 動かしてからドキュメント眺めたらいいと思う
  • GCP初めての人は$300のクレジットが貰えるぞ!

ありがたいなぁ。

補足

僕の環境はArch Linuxでかつ、GCPを触るのが初めてだったこともあって、いくつか追加の作業が必要だったのでそれだけ書いておく。最初にGCPのアカウントを開設して$300のクレジットを貰っておくように。

コマンドラインツールのインストール

AURにある。

$ yaourt -S google-cloud-sdk
$ gcloud auth login

# /opt以下に入るのでsudoで実行
$ sudo gcloud components install kubectl

初めてのコマンド前に認証が必要。ターミナルのコマンドからブラウザが起動してターミナルに処理が戻るの初めて見たかも知れない。

結構頑張ってついて行ってるのに、out-of-dateフラグ立てられてるのがかわいそう。僕もheroku-cliパッケージでたまに立てられるので気持ちは分かる。

コマンドラインツールの設定

リージョンやらプロジェクトやら色々設定しておいたほうが毎回オプションを渡さなくて済む。configの設定については https://cloud.google.com/sdk/gcloud/reference/config/set を眺める。

$ gcloud config set project micro-sample-XXXXX

Container Registry 有効化

dockerのimageをpushする際、Container Registryというサービスにpushするのだけど、これは有効化されてないとpushできない。ブラウザのコンソールから有効化するとよい。

環境変数の設定

対象のコードではBACKEND_SERVICE_NAMEという環境変数を使ってるので、その設定がいる。暗号化の仕組みも用意されてそうだった。バックエンドのIPを見たら設定しておく。たぶんドキュメントとかにコマンドラインとかから渡す方法が書いてあるんじゃないのって思ってるんだけど、どうなんすかね?

2017/10/06 追記

お兄さんにDNSあるよって教えてもらったので、そっちを使うほうが良さそう。IP変わるのでおっしゃる通りすぎる。コメントを参照のこと。ハマりどころがあって勉強になったぞ!!!!!!!1

ドキュメントによればKubernetes 1.3からDNSがビルトインされたようで、Serviceの名前がfooでKubernetesのネームスペースがbarの場合、foo.barで対象のServiceのクラスタIPが解決できる模様。ネームスペースやDNSの様子は以下のコマンドで眺められた。

$ kubectl get namespaces                                                                                         
NAME          STATUS    AGE                                                                                    
default       Active    19m                                                                                      
kube-public   Active    19m                                                                                      
kube-system   Active    19m 

$ kubectl get svc --namespace=kube-system                                                                        
NAME                   CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE                       
default-http-backend   10.31.249.157   <nodes>       80:31925/TCP    21m
heapster               10.31.247.113   <none>        80/TCP          21m
kube-dns               10.31.240.10    <none>        53/UDP,53/TCP   21m
kubernetes-dashboard   10.31.245.255   <none>        80/TCP          21m

$ kubectl get svc --namespace=default                                                                            
NAME                            CLUSTER-IP     EXTERNAL-IP    PORT(S)        AGE                                 
kubernetes                      10.31.240.1    <none>         443/TCP        22m                                 
micro-sample-service-backend    10.31.244.62   <none>         8000/TCP       17m                                 
micro-sample-service-frontend   10.31.249.64   XX.XX.XX.XXX   80:32186/TCP   21m

ということで、バックエンドはmicro-sample-service-backend.defaultで引けることになる。 ちなみにPodの中にはresolv.confが用意してあって、ドキュメントに書いてあるように以下のような定義になっている。

$ kubectl get pods
NAME                                               READY     STATUS    RESTARTS   AGE
micro-sample-backend-deployment-3300239719-22qdm   1/1       Running   0          38m
micro-sample-backend-deployment-3300239719-mpjh9   1/1       Running   0          38m
micro-sample-frontend-deployment-836517767-3vgzv   1/1       Running   0          10m
micro-sample-frontend-deployment-836517767-vbbrp   1/1       Running   0          10m

$ kubectl exec -ti micro-sample-frontend-deployment-836517767-3vgzv -- cat /etc/resolv.conf
nameserver 10.31.240.10
search default.svc.cluster.local svc.cluster.local cluster.local c.micro-sample-XXXXX.internal google.internal
options ndots:5

なのでネームスペースがdefaultの場合は、micro-sample-service-backendだけでも引けるわけだけど、ネームスペースがいつもdefaultとは限らないので、ネームスペースと組み合わせた名前で指定しておくのがいいと思う。

追記終わり。

...
     containers:
      - name: micro-sample-frontend
        image: gcr.io/micro-sample-XXXXX/micro-sample-frontend:v0.1
        env:
          - name: BACKEND_SERVICE_NAME
            #value: 10.31.XXX.XXX
            value: micro-sample-service-backend.default
        ports:
...

Podの削除

せっかくなので、Podを消してみると不死鳥のように蘇る様子を見ることが出来る。

$ kubectl get pods
NAME                                               READY     STATUS    RESTARTS   AGE                            
micro-sample-backend-deployment-3300239719-ghw8q   1/1       Running   0          5m                             
micro-sample-backend-deployment-3300239719-h8nwp   1/1       Running   0          5m                             
micro-sample-frontend-deployment-602895698-qrwfk   1/1       Running   0          4m                             
micro-sample-frontend-deployment-602895698-ts2kr   1/1       Running   0          4m

$ kubectl delete pod micro-sample-backend-deployment-3300239719-ghw8q 
pod "micro-sample-backend-deployment-3300239719-ghw8q" deleted

$ kubectl get pods
NAME                                               READY     STATUS    RESTARTS   AGE                            
micro-sample-backend-deployment-3300239719-h8nwp   1/1       Running   0          6m                             
micro-sample-backend-deployment-3300239719-ppzf9   1/1       Running   0          9s                             
micro-sample-frontend-deployment-602895698-qrwfk   1/1       Running   0          5m                             
micro-sample-frontend-deployment-602895698-ts2kr   1/1       Running   0          5m

ありがたいなぁ。

電源が入ってないiPhoneやAndroid端末を見つける技術

本日、Android端末を落とした。多分タクシーに乗っているときだと思うけど、ちょうど領収書をもらってなくて、タクシー会社名も分からなければ車両番号も分からないという状態で困っていた。幸いにも世の中は便利になっていて、iPhoneAndroid端末の位置を調べたりできるのだけど、僕の場合は気づいた時間の1時間前ぐらいから場所が拾えなくなっていた。つまり電波が入ってないか、電源が切られている状況で、普通に端末を探す方法は使えなかった。なので、ロックしてメッセージを出したり、着信音を強制的に鳴らしたり、リモートでデータを消したりとかそんなことはできない。そんな時にどうして見つけ出したかという話を書いておく。

TL;DR

  • タクシーの領収書は必ずもらいましょう。
  • Google Mapのタイムラインを使いましょう。

f:id:terut:20170913203009p:plain

探し出した流れ

Google端末を探すで表示される位置は結構ラグがあるみたいで、1時間前にある場所はよく分からないマンションの前を指し示していた。あーこれは後の乗客にパクられたかなと思っていたのだけど、タイムラインから表示してるような旨のメッセージが出ていたので、Google Mapのタイムラインから今日の移動経路を見てみると隣町の警察署で止まってる感じだった。え、位置情報違うじゃんって思いながらも、3時間ぐらい警察署の位置で止まってるような表記だったので、警察署に電話して落とし物係に繋いでもらい、この時間帯にこういう端末が届けられてないかという確認をしたら、それっぽいものがあるとのことだった。どうも照会するのにSIMの製品番号が必要だったので、携帯ショップに行って事情を説明すると、電話番号の入力で警察署にあることが分かり、拾得物番号、受理番号、SIMの製品番号などをメモしてもらって、警察署に電話を折り返して照会したら端末があるとのことだった。あとは受け取りに向かい、身分証明とメモを渡して、サインを書けばOKだった。イースタンモータース東京とかいうタクシー会社の運転手さんが届けてくれたとのことで、有り難しだった。まあなんでタイムラインで表示されている位置が変な場所なら、諦めて紛失届を警察に出して枕を濡らしながら待つとよい。

追記

疑問

そういえば電源はどの時点で切られたのか?警察署?タクシーの運転手さん??警察署に行った段階で必ず電源切られるとなるとなかなか厳しいのかもしれない。

近況報告

f:id:terut:20170908152513p:plain

僕の知り合いへ向けての報告です。7月中旬に海外から住所不定無職として日本に帰ってきました。7月中は実家に帰省していて、8月に関東へ戻ってきて日本の住所を得た結果、現在のステータスは無事に住所一定無職です。正確には7月末日付の退職でした。

元々自分の好きなことでもやりながらしばらくはフラフラするかーと思っていたんですが、8月はプライベートな問題で色々ゴタゴタしていたこともあり、あっという間に9月になった感じでした。自分が使う用の画像ビューアが欲しくて、絶賛車輪の再発明中ということで、暇があればコードを書いたりしてましたが、太陽フレアの影響もあり、そろそろ職探しでもするかーという気持ちになってきたので、職探しします。ずっと新規サービスばっかり開発してきたのですが、今後は開発者やデザイナーを後押しするようなツールやサービスを開発してご飯を食べていきたいなと何となく思っています。

恥ずかしながら転職するのは初めてなのだけど、職歴って前にLinkedInにまとめたやつがあって、こんなんでいいのかな?

https://www.linkedin.com/in/terunori-togo-03ab4511b/

とりあえず無職になって思ったことは健康保険の任意継続の便利さは異常

相談

ところで画像ビューアをElectronで作ってんですが、img.src切り替えるとメモリ積まれていってて、色んなリークを疑って最小構成にしても起こったんですが、Chrominumが抱えてるバグが直ってないだけなんですかね?そんなこんなでQtのgolangのbindingを見つけたんで、そちらで作り直してる感じですが、最新版の5.9.1でもImageのソースを切り替えるとメモリリークするバグにぶち当たり最高なので、Qtやりましょう。

例のヤツ

http://amzn.asia/1X52w1M

Arch LinuxのHeroku CLIパッケージのメンテナになるまでにやったこと

メンテナになったと言えば聞こえは非常にいいのだけど、つまるところArch Linux用のHeroku CLIパッケージがなかったので作って公開して使えるようになったということだったりする。まあサイトにはメンテナとして名前が載ってるし、メンテナなんだろうと思う。何らかのOS用のパッケージ配布自体は初めてで、作る上で色々と人々に教えを乞うたら、Arch Wikiには書いてなかった気がすることも教えてもらえたのでまとめておくことにした。

f:id:terut:20170611171250p:plain

成果

何はともあれ、成果になります。

aur.archlinux.org

モチベーション

パッケージを作っていた時点のGo/NodeベースのHeroku CLIのドキュメントには、Apt以外で管理する場合、スタンドアロンバージョンを使うように書いてあり、自分でファイル管理をしないといけなかった。とにかくパッケージとしてシュッとインストールしたり、アンインストールしたかった。作っていた時点と言ってるのは今はドキュメントが変わっているからで、それについてはあとの方で触れようと思う。

パッケージの作り方

Arch LinuxではPKGBUILDというファイルを使ってパッケージのビルドの手順をシェルスクリプトで書いていく感じになるのだけど、まず最初はArch Wikiをよく読むとよい。パッケージに関してもArch Packaging Standardsとして基本的な作成方針がまとめられている。他にも基本的な作り方であれば、ググれば見つかるのでそういう類の情報は書かない。勢い良くブラウザバックして別のページを探すとよいと思う。

Arch packaging standards - ArchWiki

最初作ろうとしたもの

僕が作り始めた当初はGolang/Nodeで書かれたHeroku CLI v5がGithubのmasterで開発されていた。プラグイン機構がNodeで実現されてるからだと思う。Nodeベースのv6系もリリースはされてはいたが、v6ブランチ上で開発されていたのとGolangのコードがまだあったため、masterで開発されているGolang/NodeのHeroku CLIをパッケージ化しようと試みた。ただHeroku CLIはそれ自身に自動アップデートの機構をもっているため、バージョン指定でバイナリを取得できず、ステーブルという形でのダウンロードになってしまって、どのバージョンなのか分からない状態だった。VCSなどから直接コードを持ってきてビルドするタイプのパッケージは、gitコマンドなどからバージョンを取得してパッケージのバージョンを動的に決めていたので、それを真似してダウンロードしてきたバイナリの実行結果からバージョン情報を解析してバージョンをつける方式をとった。

最初のレビュー

基本的なことは既に述べたようにPackaging Standardsを読めば分かるわけだけど、不安がある人はBBSとかでレビューしてもらいましょうと書いてあったので、作ったPKGBUILDのレビューをお願いしてみた。そうするとWikiに書いてなかったようなアドバイスを色々ともらえた。

  • ダウンロードしたものの検証にはsha512を使ったほうが良いこと
  • 検証をSKIPする指定は、VCSなどからのソースビルドをするようなパッケージに使うこと
  • pkgver()はVCSを使うパッケージ用なので使うのはやめたほうがよいこと
  • バージョンを固定できないため、VCSで使うような方法をワークアラウンドとして採用してるみたいだけどセキュリティホールになるので、バージョンが固定されたアーカイブを探したほうが良いこと
  • ライセンスファイルのコピーの正しい方法
  • installコマンドを使ったほうが良いこと
  • メッセージを出すためにはprintじゃなくてechoやcatとヒアドキュメントを使うこと
  • ~/.local/shareなどのHOMEをいじるようなメッセージは出さないこと
  • HOMEをいじるような場合はスクリプトを用意し、かつ"${XDG_DATA_HOME:-~/.local/share}“のようにXDG_DATA_HOMEを使うこと
  • ソースとバイナリはライセンスが違う場合があること

それでバージョンを固定するには自分でビルドするしかないなと思ったのだけど、Golang/Nodeで書かれているため、普通のgo buildとかではなく、Makefileと格闘するハメになった。

Herokuへの問い合わせ

Makefileでやるのはビルドできなすぎて辛すぎたので、Heroku Supportで問い合わせしてバージョン固定でバイナリをダウンロードできないのか聞いてみた。そうするとNodeバージョンを使うと良いよというアドバイスと共に、Heroku CLIのドキュメントを見てと言われたので眺めてたら、全体的にアップデートされ、ArchやBSDは自動アップデートなしのNodeバージョンを使ってくれという感じになっていた。GithubのmasterもNodeベースに切り替わっていてGolangの実装は全てなくなっていた。CLIのコア部分はcli-engineというFrameworkに依存してたので、Golangの実装はv6で使ってなかったのかも知れないし、以前から切り替える計画があったのかもしれないけど、問い合わせてから2-3日でやるのはさすがに強い。これが世界のやっていきですかという気持ちになった。結果としてNodeのライブラリとしてバージョンを指定してインストールするパッケージを書けば良くなった。

2回目のレビュー

1回目のレビューの時と違い、Nodeのライブラリをパッケージとして提供してるものは既にあったので、探してマネをした。ただAURで公開されてるライブラリは正しいやり方をしてないものも多いし、PKGBUILDのオートジェネレータがおかしなビルド方法を提供していたりるので、気をつけたほうが良さそうだった。既にコミュニティパッケージになっているものを参照してリリースにこぎつけた。正直Nodeとnpmがあれば普通にインストールできるのだけど、Node使う環境にいない人にとっては、依存を解決して全部入れてくれるし多少は便利かなと思ってリリースすることにした。レビューのスレッドを一応貼っておく。

[SOLVED] PKGBUILD review request: heroku / Creating & Modifying Packages / Arch Linux Forums

最終的なPKGBULDの様子。

github.com

今の悩み

めちゃめちゃHeroku CLIのリリーススピードが早くて、一日に2回リリースされたりとかザラだったりする。そんな感じなので最新バージョンに違いが出やすくて、マイナーバージョンの違いでもOut-of-dateフラグ、つまり古いぞフラグをパッケージにつけるマンがいる気配を感じている。僕はどうしたらいいんだろうか。

まとめ

とにかくHeroku強い。世界のやっていきを見た。

英語をやっていくためのDuo3.0デスクトップアプリを作った話

以前、英語をやっていくためのDuo3.0アプリを作り直した話 - 解せぬ日記で書いたとおりReactNativeで作ったモバイルアプリを使ってDuo3.0をやってきたわけだけど、それをやっていると今度はデスクトップアプリが欲しくなってきた。やっぱりタイピングはそっちのほうが早く時間も節約できる。僕は普段、ArchLinuxを使ってて、仕事ではMacOSXを使っているので、気がついたらElectronを使って作ってた。Duo3.0アプリ芸人みたいな様相を呈してきたけど、僕はボキャビルがしたいだけなんだ。

成果

以下、成果になります。

vimeo.com

ソースコードも置いとく。小さいのでElectronやってみたい人が雰囲気を眺めるには良いかも知れない。

github.com

TL;DR

Electronに関してはサンプル程度だが前に書いたこともあり、中身はJavascriptとHTMLで書くということで、React入れて、ロジックとJSX書いて、トランスパイルして、JS読み込むという感じなのでシュッとアプリを書くには非常によい。

実装に関して

難易度

今回はデスクトップアプリとはいえ、メニューバーに常駐したりするわけでもなく、アプリ自体のメニューとかも別にどうでも良かったので、Electronで実装されてるAPIにはあまり触れてない。MenuItemとかTrayとかそういう類のやつ。たぶんこの辺を触り始めると、これぞElectronという特有の知識が必要になって、難易度も上がるんだろうと思う。そこを触らないのであれば、APIを眺めることもあまりないと思う。

アプリサイズ

これはよく言われてることで、そのままビルドすると異常なサイズになる。普通にやってしまうとnode_modulesとかも一緒にいれてしまうのが原因で、いちいちnode_modulesやら必要ないものは外す必要がある。最初、何も考えずにビルドしたら400MBぐらいあってウケた。色々含めないようにして100MBぐらいになった。音声ファイルが40-50MBぐらいあるので、まあそんなもんかなという感じ。

音声の再生

これはもうHTML5使えるからめちゃめちゃ楽でaudioタグを使って終わり、何も難しいことはない。FlutterやReactNativeでは大変だったので有り難し。

Diff

モバイルアプリを使ってて見にくいなーと思ったのが、一瞬でどこ間違ったか分からないことだった。間違った箇所を確認するのに時間を取られてしまい、効率的ではない。ということで、diffを導入して、差分で間違ったところだけを赤くするようにした。diffライブラリを使っていて、addedのステータスの単語を赤く表示している。ただこれ回答側に余分な単語、例えば冠詞がないのに冠詞をつけていた場合は、何も表示されないのでなんとかしたいが、いいUIが思いつかない。とりあえずaddedだけでも必要十分な気がしたので、これでやっていってる。

まとめ

全体としてシュッと出来たなという感じ。フロントエンドマンならもっと早くできるんだろう。2ヶ月前ぐらいに作って、これ使ってやりまくってたら、45セクションを2日で終わらすみたいなこともできるようになってきて、めでたい。何気にセンテンスのjsonを別の例文に変えても使えるので、新しく覚えたい例文とか足していってもいいかもしれないですね。

やっていき。

英語をやっていくためのDuo3.0アプリを作り直した話

先日、Flutterで英語をやってくためのDuo3.0アプリを作ってみた話 - 解せぬ日記というのを書いたわけだけど、そのアプリに音読用の機能が欲しいなということで追加を検討した結果、Flutterで作ったものをReact Nativeで作り直した。

成果

以下、成果になります。

vimeo.com

ソースコードも置いとく。スタイルやらちょっと整理したい。

github.com

TL;DR

React NativeはJavascriptとReactという慣れた言語で書けることや割とライブラリとかもあって良い反面、iOSAndroidAPIを分けたりしてる部分があったりして、そこがすごく気になった。コードを無理に共通化しようとすると分岐が出てきて、なんとなくそのうちやっぱSwiftやJavaで作り直したほうがいいねとなるかもしれない。Dartという言語で新しいFrameworkを学ぶ必要があり、対応してるAPIはまだ少ないものの僕個人としてはFlutterが実現しようとしてることのほうが好きだし、コードも楽しく書けた気がする。シンプルなものはFlutterでiOSAndroidを動かし、それなりの表現がしたいものはSwiftやJavaで個別に作るみたいな流れが好ましい。FlutterはGoogleが作ってる新しいOSのFuchsiaのUIレイヤーに採用されるみたいで、コミットも活発だし期待したい。

作り直した背景

音読機能を追加するにあたり、音声を流すための調査をした。その結果、Flutterには現在のところ音声ファイルを扱えるAPIが存在しないということが分かった。正確にはメンテする人がいないということでオープンなリポジトリからはAPIを削除したとのこと。Privateリポジトリに移したから使いたい人やメンテしたい人はgoogleグループに連絡くれとのことだったのだけど、前に公開されてたコード読んだ感じ、結構難しかったのでReact Nativeで作り直すことにした。

React Nativeを選んだ背景には、音声ファイルを扱えるライブラリがあったこと、AndroidiOSのアプリをビルドできたこと、そしてReactとJavascriptをもう少し触っとこうと思ったことがある。個別に作りたいアプリじゃないし、iPhoneを使ってる妻も使えるようにということで、FlutterだったりReact Nativieを選んでる。

実装で詰まった部分

ReactとJavascriptで書けるので、まあなんとか書けたものの設定やらなんやらで割とハマった。thisを束縛したりとかはReactでお馴染みだったので、React書ける人ならビルド周辺以外はハマることは少ないような気はする。ライブラリも結構色々あって探せばなんかありそう。

Buildの設定

React NativeのCLIから作られるアプリの中にはAndroidiOSディレクトリがあり、それぞれBuildに使うための設定ファイル群が生成される。僕はAndroidをサンプル程度のものしか作ったことがなくて、あまり知識がないのだけど、React Nativeは結構Androidのビルドの仕組みなどの知識を要求してくる感じだった。iOSはまだBuildしてないが、Info.plistなどが生成されてるし、まあ多分同じなんだろうと予想している。

build.gradleにはAndroidSDKやBuildツールのバージョンが書かれていて、Android Studioをインストールした時に入るSDKのバージョンによってはSDKやBuildツールの対象バージョンをインストールするか、設定ファイル自体を対応するバージョンに書き直す必要がある。React NativeのCLIファイルが作るファイルは全てSDKが23でBuildツールが23.0.1だったので、もしかしたら書き直すことの方が多いかもしれない。多分基本的なことなので、トラブルシューティングにも書いてない。

けどよくよく考えれば、公開するために署名やProfileなどの話は避けて通れないし、どちらにしろBuildに関しては抑えておく必要はありそう。

音声ファイルの置き場所

これも考えれば当たり前なのだけど、AndroidをBuildするときに全部がbundleされるわけじゃなさそうで、音声ファイルが参照できなかった。そこでres/rawに入れたのだけど、ここってディレクトリ管理できないっぽくて、そのまま直下に置いた。assetsとして管理すればディレクトリ管理もできそうなので、Androidマン頼む教えてくれ。自分でドキュメント読めという話かもしれない。

APIの分岐

これはハマったというより悩んだという感じだったのだけど、iOS用のコンポーネントが用意されてたり、Android用のAPIが存在してたりして、一つのソースでやろうと思うとまあそうだよねって思うものの、非常に考えさせられた。当然、個別に用意されてるものを使ったほうが実装が楽だったりで便利そうな感じはすごくしたのだけど、そうすると再利用できる部分はどんどん減っていく。それで行き着く先は、個別に作ったほうがいいんじゃね?ってなりそうだなと思ったんだけど、そんなことないよって実際作ってる人がいれば話を聞いてみたい。

まとめ

無事に音読用の機能を追加できた。とりあえずこれでオフラインでも英語の勉強には困らなそう。人の目を盗んでは一人でブツブツ言うということもできそうだ。どっかの綾瀬はるか似がDuo 3.0やってるって言ってたし、Javascript界隈に詳しいっぽいので、色々ReactとかJavascriptの書き方教えてくれると嬉しい。多分Flutterが音声ファイルを流すためのAPIに再度対応したらFlutterの方に機能追加して、そっちをメインにすると思う。FlutterはGoogleが作ってる新しいOSのFuchsiaのUIレイヤーに採用されるみたいで、コミットも活発だし多分追加してくるだろうと予想してる。

やっていき。