Scratch3.0とスマホを連携させるために、色々作った(作ってる)


2018年アドベントカレンダー個人開発部門18日目でございます。
初投稿ですが、よろしくお願いします！

# 作ったもの
<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">１月頭にリリースされるであろうScratch3を改造して、スマホと連携させてみた。動画は明るさセンサーを使って遊んでみた例。やり方はこちら。<a href="https://t.co/1qgtK8Qlev">https://t.co/1qgtK8Qlev</a><a href="https://twitter.com/hashtag/Scratch?src=hash&amp;ref_src=twsrc%5Etfw">#Scratch</a> <a href="https://twitter.com/hashtag/Scratch3?src=hash&amp;ref_src=twsrc%5Etfw">#Scratch3</a> <a href="https://t.co/WaJvGfvWeM">pic.twitter.com/WaJvGfvWeM</a></p>&mdash; aknow2 (@aknow21) <a href="https://twitter.com/aknow21/status/1073431351297110016?ref_src=twsrc%5Etfw">December 14, 2018</a></blockquote>

ちなみに、Scratch3.0は2019年1月2日にリリースが正式に決まりましたー🎉 
Scratch3.0でReact.jsとGoogle blocksをベースとしたウェブアプリに生まれ変わります！  


## 仕組み(概要)
![presentation.jpg](https://qiita-image-store.s3.amazonaws.com/0/319213/2dcd4c69-d063-721f-b814-c8c4c6ecd6c5.jpeg)

Scratch3.0の外部拡張ブロックを取込む機能を使って、今回自作した拡張ブロックを読み込みます。それから、拡張ブロックがAPIサーバー化したスマホにアクセスして、センサー値等を取り込んだり更新したりします。
<b>※Scratch3の拡張ブロックの取込機能について</b>
拡張ブロック自体はJavascriptで作れます。実装した拡張ブロックはjsファイルとしてHTTPでアクセス出来るようにします。例えば、http://localhost:8080/ext.js で公開したすると、このURLをScratch3の拡張機能でImportすると自作したブロックが使える様になります。

そして、この仕組みを実現させるために作ったものは3点！
・Myriad スマホの機能(主にセンサー)をAPIサーバー化するアプリ(React Native)
・Scratchの拡張ブロック (Javascript)
・Scratch3.0 外部拡張ブロックのImport機能対応版 (Scratch-GUI, Scratch-VM)

作ったAndroidのアプリはベータ版で公開しています。
[<img src="https://qiita-image-store.s3.amazonaws.com/0/319213/cdf6807e-9696-0681-328b-837adef9ca38.png" width="200px">
](https://play.google.com/store/apps/details?id=com.myriad&hl=ja)


## そもそも、なぜ作ったか
1．Scratch3.0がReact.jsで出来ていて興味を持って、ソースコードを眺めてたら拡張機能が簡単に作れそうだったから。
2. Scratch3の標準で使える拡張機能にmicro:bitであったり、レゴのマインドストーム等が並んでいます。確かに色んな工作が出来そうで楽しそうだけど、買うのはちょっと引ける(
お金が無い
)。
じゃあ、手持ちの何かでScratchと連携させたら楽しそうな物がないか考えて、すぐ思いついたのがスマホ。スマホには色んなセンサーや機能があるし、Scratchと連携出来たら楽しそうだと考えました。また、過去はどうなんだろうと調べるとScratch1.4やScratchXでもスマホと連携するアプリがったので、じゃあこれらのScratch3版を作ろうとなりました(自分の中で)。

また、どうせアプリを作るならScratch3.0専用設計ではなく、単純なREST APIでスマホの機能を呼び出せる設計しておけば、スマホを工作で使う部品と見立て使える事が出来き夢が広がるよねーと考え、Scratchには依存しない独立して動作するアプリとして作る事にしました。

## 作ったもの詳解
### Myriad スマホの機能をWeb API化アプリ(android)
<img src="https://qiita-image-store.s3.amazonaws.com/0/319213/cd17391b-d8fd-4854-d32c-86a824b0dbe4.png" width="200">
[<img src="https://qiita-image-store.s3.amazonaws.com/0/319213/cdf6807e-9696-0681-328b-837adef9ca38.png" width="200px">
](https://play.google.com/store/apps/details?id=com.myriad&hl=ja)
#### 技術スタック
・言語:　Typescript(以下、TS)
・アプリフレームワーク:　React Native(以下RN)
・Webフレームワーク: Express
・サーバー実行環境: [Node.js for mobile Apps](https://code.janeasystems.com/nodejs-mobile)
・ユニットテスト: Jest
・APIドキュメント：Swagger + Redoc
#### 選定した流れ
最初はAndroidをサーバー化するなら純粋にJavaで行こうかなーと思ったけど、
Node.jsをiOS, Androidで動かせる[Node.js for mobile Apps](https://code.janeasystems.com/nodejs-mobile)をみつけて、iOSも出来るならiOS版も見越してNode.jsで行こう。じゃあ、アプリ側もTS(JS)で書けた方がいいよねー！となりReact Nativeで書くことにした。  

#### 実装内容
###### State管理
思う事がありState管理にReduxやMobXを使わず、自作のState管理ライブラリを作りながら実装してみた。これについて語ると長くなるので違う機会に語りたい。

###### UI: React Native Elements vs Native Base
UI kitは[React Native Elements](https://github.com/react-native-training/react-native-elements)と[Native Base](https://nativebase.io/)の両方を使ってみて比較した結果、React Native Elementsの方を選びました。理由としては、カスタマイズ性の違い。Native BaseはUIのカスタマイズする時にNativeBase独自の仕組みに乗っかかる必要があります。対してReact Native Elementsの方は公式のUI kitの薄いラッパーというイメージで単純にStyleを書けばカスタマイズ出来たためです。使いこなせばNativeBaseのカスタマイズ機能でスタイルの一元管理が出来そうなので良さそうではあるけど、その仕組みを学ぶのがダルイといった感じ。

###### Node.js for mobile Apps
今回はExpressを実行するために利用している。Androidではv8ベース、iOSではchakracoreで動いているらしい。アプリ側とNodejs側で簡単にメッセージング出来る仕組みもある。ただ、v8のinspectorに対応しておらずデバッグはlogcatでのprintデバッグ。しかも、エラーが起きると何も言わずにアプリがスッと落ちる。なので、凡ミスでもエラー箇所を探すのが結構大変。
対策として以下の2点を実施して乗り切りました。
・原理主義的にTDDを実践していく（おかげでNodejs側のカバレッジ率は96.7%）
・アプリ側に実装の重きを置いて、サーバー側はなるべくシンプルにする。
・TypeScriptを導入する。
で、どうにかしました。当初、モバイル上で初めてNode.jsを動かすのでJavascritptで書いていましたが、原因が型変換によるエラーをデバッグするのに数時間かかってしまったのでTypescriptに変えました。あと、趣味レベルだとTDDとか面倒となりがちですが、やっぱりした方がいいですね。小まめにテストしながら作った箇所は、アプリ側と結合した時に一発で動いたので気持ちがよかった。

###### PWYW 
アプリは無料で使えます。広告も出ません！アプリ内課金がありますが、これはアプリにお金を払う価値があると思った人だけに払ってもらう方式にしました。

###### APIドキュメント
APIのドキュメントは王道でSwaggerを使用。サーバーを建てるのは面倒なので、直接yamlファイルを取り込んでいい感じに表示してくれる[Redoc](https://github.com/Rebilly/ReDoc)を使いました。公開先は何も考えずにgithub pages。
成果物：https://myriadapi.github.io/ja/api/

###### とりあえず、リリース。
主要なセンサーにアクセス出来るようになり、このアドベントカレンダーもあるので、とりあえず公開しました。
今、利用可能なAPIの一覧です。
・ジャイロスコープ
・加速度センサー
・磁気センサー
・明るさセンサー
・近接センサー
・フラッシュライト
・バイブレーション機能
カメラやGPSにも対応出来てないし、ファイルの読書きとかも出来たら楽しそうだなーとは考えています。まだまだ、作りたりない！

一応、このアプリのロードマップ的な物をTrelloに公開しています。
https://trello.com/b/TTKSHxbx/myriad

### Scratchの拡張ブロック
[https://myriadapi.github.io/myriad_scratch3_blocks/ja/](https://myriadapi.github.io/myriad_scratch3_blocks/ja/)
#### 技術スタック
・Typesciript
・webpack
・github page
#### 実装内容
Scratch3の拡張機能の仕様は[ここ](https://github.com/LLK/scratch-vm/wiki/Scratch-3.0-Extensions-Specification)に書いてある。
最終的に1つのjsファイルにして公開する必要があります。ただ、実装時から1ファイルで実装するのは何かと辛いのでwebpackで一つにまとめる様にしました。ハマったのが、外部から読み込んだ拡張機能はWeb worker上で動作するので、Web workerが対応していないAPI、DOMの操作やAlertが出せず最初？？？となりました。
これまた、公開先は何も考えずにgithub pagesへ公開しました。  

### 外部拡張機能に対応したScratch3.0
https://aknow2.com/scratch/
http://aknow2.com/scratch/
#### 技術スタック
・Scratch-GUI(React.js)
・Scratch-vm(Javascript)
#### 実装内容
Scratch3.0のアーキテクチャですが、GUIとVMと2層に分かれています。GUIの方はReactjsで作られており主にブロック等を表示させるためのView層で、VMの方はスプライトの追加、ブロックの生成、プロジェクトの保存読込等のロジック層となっています。
残念な事に現在、β版で公開されているScratch3.0は外部の拡張機能が読み込める機能が公開さおらず、読み込める拡張機能が限定されています。ですが、コメントアウト的に使えなくなっているだけなので、使えるようにするのは簡単で、GUIの方だけをちょっと改造すればすぐに出来ます。ただ、プロジェクトを保存した読込んだりするには、中途半端に実装された外部拡張の読込機能を直す必要があり、コードを追って行けば出来るのですがちょっと面倒でした。はやく正式に対応してほしい。。。

実は最初、これを作るつもりはあんまり無かったです。というのも、SheepTesterさんが外部拡張機能を有効にしたScratch3.0をリリースしているから。が、いざアプリとブロックを作ってSheepTesterさんのScratch3に読み込ませようとするが動かない！ログを見ると、、、
`mixed Content: The page at '<URL>' was loaded over HTTPS, but requested an insecure resource '<URL>'. This request has been blocked; the content must be served over HTTPS.
`
Github PageはHttpsで、API化アプリはHTTPでサーバーが起動している。そのため、HttpsからHttpを呼び出すなというMixed contentのエラーが出て、APIが呼び出せていなかった。
この対策で、アプリで証明書を設定出来るようにしてHttpsに対応するか、Scratch3を改造してhttp版で公開するか迷いました。そして、選んだのはScratch3を改造する方。理由は手軽さ。ユーザーにアプリを証明書を作って、Https化してから使ってねは辛そう。自分も辛い。あとSheepTesterさんの改造したScratch3が大分、古いリビジョンだったので新しいリビジョンで作った方が良いなー、ついでにScratchの中身もハックするかという気持ちもあり改造していまいました。腕試しにSheepTesterさんの実装を見ずに独力でやってみましたが、最初に書いた通り、意外に簡単に出来ました。（こんな事をしてるから主要な機能の実装が遅れる。。。まあ、これも個人開発の醍醐味ではある。）

## コンクルージョン
という事で書き散らして来ましたがまとめます。

まず、出来てないけど感想、やっぱり興味のある技術と作りたい物をゴリゴリ作るのは精神衛生上とても良いものですね。あと、Redux使わないとか、人の実装を参考にしないとか、色んな制約をかけて、寄り道をしながらモクモクと作っていくのは楽しい！

また、このアドベントカレンダーのおかげで尻尾に火が付きがんばれた気がします。締め切り駆動開発は有効に一票です。

今後ですが、アプリの方に注力して機能を開発したいなーと思ってます。せっかく作ったので当初の目論見通りScratch3で遊ぶだけじゃなく他の遊び方も模索していきたいです。何かいいアイデアあったら教えてください。


最後まで読んでくださり、ありがとうございましたー。