DroidKaigi2020 Lite

本記事では、2020年8月にオンライン開催された、DroidKaigi2020 Liteの以下セッションについて学んだことを記載します。
一部、動画の画面キャプチャを使用させて頂いております。

1.アプリのアップデート浸透率を上げろ！〜in-app updatesを実践投入して見えてきたもの〜
2.自動生成でさくさく実装するユニットテスト
3.Jetpack時代のFragment再入門
4.Androidで音声合成（TTS）をフル活用するための知識と実践事例
5.Scadeを使って「Swift」で始めるAndroidアプリ開発

# 1.アプリのアップデート浸透率を上げろ！〜in-app updatesを実践投入して見えてきたもの〜

### アプリの更新方法に以下がある。

(1)Google Play ストアで自動更新されるように設定する。
　※「アプリのダウンロード設定」のデフォルト設定は「Wi-Fi経由のみ」
　　自動更新をきらい、設定しない人もいる。

(2)アプリ内からの更新
　※バージョンをチェックして、Google Play Storeに飛ばす方法もある。

### アプリ内からの更新方法はin-app updatesという
機能を利用して実装する。

2つの実装の仕方がある。
　- Flexible
　- Immediate

### Flexible（英訳：融通のきく、適応性のある）
![flexible.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355942/a510477b-ecfd-5424-8a20-5ad9107a8ba8.png)

①ダイアログ表示。更新する・しないを選択
②バックグラウンドで動作するので、更新データをダウンロードしながら
　アプリをプレイできる。ダウンロードが完了すると、画面下部に通知される
③画面を占有してインストール

### Immediate（英訳：即座の、即時の）
![immediate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355942/1ef466fe-3cd7-18c9-7f1e-936a72060e41.png)

①画面を占有して表示。更新する一択。
　※右上の×ボタンや戻るキーで戻れるがそれだとFlexibleと同じになるので。。
　　実装で対策する（できる）
②更新データをフォアグラウンドでダウンロード、インストールまで一気に行う。
　この間はアプリをプレイできない。

### 課題
アプリの起動時にチェックが走り、onCreateごと≒アプリ起動ごと、に
アップデートの確認ダイアログがでてしまう。
→対策としては、内部ストレージにチェックした時間を記憶しておき、
　1週間経過したら、再びだすなど。

### 使い分け
おためし機能をリリースするといったような、緊急性がないものはFlexible、緊急度の高いアップデートはImmediateを利用する。
さきほど、アップデートチェックは、ある一定期間後と言ったが、
Immediateの場合は、チェックした時間にかかわらず、毎回出す方が良い。

### アプリ内にアップデートを検知する仕組みを実装することで実際、どのぐらいアップデート率があがるのか？

Before
・in-app updatesを導入していないアプリ
・従来どおりのアップデート

After
・in-app updatesを導入したアプリ
・Flexibleを有効化した状態でのアップデート

※検証対象はグロービス社のアプリ

### 結果
Before
2週間経過時点で
・最新バージョンが90%前後

After
2週間経過時点で
・最新バージョンは95%前後

→最新版の割合が2週間時点で5%アップ

### 考察
・そもそも自動アップデートの人の割合が相当高い（全体の90%くらい）
→残りの1割に対して効いてくる

・in-app updates導入前の過去バージョンはどうしても残りがち
→時間があったら、アプリバージョンの早いうちに入れておいた方がよい



# 2.自動生成でさくさく実装するユニットテスト
このセッションの方針
・IntelliJ IDEAの力を借りる
・さくさくコード実装のサポートを目指す
・テストパラメータやテストケースの自動生成は目指さない
　→実装の分岐からテストケースを複数自動生成する、ということではない

※IntelliJ IDEAとは、Android StudioのベースとなっているIDE（統合開発環境）
ライブコーディングでは、Android Studioでコーディングを行っている

### 今回登場するもの
(1)Live Template
(2)File Template
(3)Postfix Completion
(4)Parameterizedテスト生成Plugin
いずれもIntelliJ IDEAで完結するもの

(1)〜(3)はAndroidStudioからもカスタマイズ可能
ファイルの受け渡しもできる

(4)は実装を変更することでカスタマイズ可能

### (1)LiveTemplate
・スニペット
　ループ、条件、さまざまな宣言、出力ステートメントなどの一般的な構成をコードに挿入しする
・キーワードをタイプしてテンプレートのコードを生成する

![スクリーンショット 2021-02-14 12.45.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355942/f01d609e-1cbf-3395-d320-8bd04f6077e2.png)

![スクリーンショット 2021-02-14 12.45.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355942/13bd7cca-bc5e-e0dc-c81b-fd86dc1d69c9.png)

### (2)File Template
・ファイル作成時のテンプレート
・File > Newをしたときに選択できる

![スクリーンショット 2021-02-14 12.48.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355942/714101ad-0aad-3f54-f4bb-06718d04998e.png)

↑RoomTestは自分で作成したテンプレート

![スクリーンショット 2021-02-14 12.48.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355942/24beecaf-5e3b-9d60-22fa-6d9994138688.png)

今回の例では、よくあるJUnitの@Before・@Afterを含んだテストクラスの記載を、テンプレートを基に生成している
テンプレート生成時に、ファイル名とDB名を指定している

### (3)Postfix Completion
・式の後に 「.キーワード」をタイプして
　テンプレートの形式にコードを置き換える

![スクリーンショット 2021-02-14 12.51.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355942/ca8cc10f-4134-f4b1-ea67-caa3fc9b1607.png)

![スクリーンショット 2021-02-14 12.51.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355942/8597d560-0eab-f720-fe55-023dff323425.png)


### (4)Parameterizedテスト生成Plugin（DynamicTest生成Plugin）
##### Parameterizedテストとは
・テストをパラメータ化することで入力値や期待値を動的に受け取れるようにする
・組み合わせテストや境界値テスト等、
　1つのテスト対象を複数のパターンでテストしたいときに便利

##### Parameterizedテスト生成Plugin（DynamicTest生成Plugin）
・テスト対象FuntionのシグネチャからParameterizedテストの雛形を自動生成
→Go言語のテストライブラリに影響を受けて発表者の方が作成された、Android Kotlin用のライブラリ

参考リンク: [Parameterizedテスト生成Plugin](gitHub.com/tkmnzm/test-gen "")

以下のソースコードの9行目と10行目のテストケースとなる部分以外が自動で生成されるので
テストケースとなる部分は自分で埋める

~~~
 1: @TestFactory
 2: fun length(): Collection<DynamicTest> {
 3:   data class TestCase(
 4:     val test: String,
 5:     val expect: Int
 6:   )
 7: 
 8:   return listOf<TestCase> {
 9:     TestCase("test", 4),
10:     TestCase("cat", 3)
11:   }.map { case ->
12:     dynamicTest(case.toString()) {
13:       assertThat(case.text.length, equalTo(case.expect))
14:     }
15:   }
16: }
~~~

解説
DynamicTestクラスはJunit5のクラス
・1〜2行目は、DynamicTestを使うための記述
　戻り値にDynamicTestクラスのCollectionを受け取る
・3〜6行目は、スコープがFunction内の
　テストパラメータを保持するdata class
・８〜10行目は、そのテストパラメータ（テストケース）を保持するdata classのリスト
・11〜14行目は、DynamicTest型にmap
・12〜14行目、1DynamicTestが1テストケースとして実行される
・12行目、data classのtoStringをテストケース名に指定

![スクリーンショット 2021-01-30 16.30.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355942/a4444d9f-0452-86b2-4cb9-1197afbf5079.png)



# 3.Jetpack時代のFragment再入門
### シングルActivity
・画面ごとにActivityを作るのではなくて、全体で1つだけのActivityを定義してアプリを組み立てる
・画面の遷移はコンポーネントをActivityに貼り付けて作る
・ActivityはAndroidのバージョンごとに動作がことなる。シングルActivityであればそれにとらわれない。コンポーネントの切り替えだけでUXが良い。
・シングルActivityを実現するためにはFragmentを使う。

### Fragmentの良くないところ
(1)テストを書きづらいこと。準備が面倒
(2)FragmentTransactionを使わないといけないところ
　 FragmentTransactionのメソッドを使わないとFragmentの画面遷移などの制御ができない
　 参考リンク: [Fragmentを使った画面遷移メモ](http://nein37.hatenablog.com/entry/2018/05/06/204943 "")
(3)ライフサイクル
　 Fragmentのライフサイクルは、Activityのライフサイクルに比べて複雑なため
　 少し間違えると不具合の原因となる

・(1)〜(3)に関しては、最近のアップデートで随分と改善されている＝Fragmentは使い易い→UX改善に繋がる

・Jetpackの最近のアップデートで、Fragmentの面倒な部分を回収してくれている

・そもそもJetpackとは
Androidのライブラリで、Androidの複数バージョンとデバイスにわたって一貫して機能するコードを作成できるので、導入することにより、コードの重要な部分に集中することができる

フラグメントは複雑なシステムというイメージがあったが、複雑ゆえにいまいちなところはJetpackによって改善されてきた。昔とはだいぶ違う。
その他、JetpackではFragment以外にも様々なコンポーネントが改善されている。これらを利用していくことでAndroidのコードを良くできる。

### 複数Activityがないと厳しいケースは何か
・自分のアプリの中で画面を分割したい時
・Android8からの機能であるピクチャー・イン・ピクチャー（ホーム画面などで小窓でYouTubeアプリなどを再生する）を使いたい時
・Android11からの機能であるBubbles（アラートを小さな丸型で通知する）を使いたい時

### シングルActivityを採用する際の懸念点
学習コストが高い。FragmentとNavigationを使ってSingleActivity化するやり方を覚える。FragmentもNavigationも巨大なライブラリ



# 4.Androidで音声合成（TTS）をフル活用するための知識と実践事例
### 最近の音声合成の事情
・「棒読み感」が改善してきている
・自然なイントネーション
・平仮名、アルファベット、漢字に柔軟に対応

音声合成の分野は急速に発達している

### 音声合成の周辺知識
歴史
1779: 母音を発声できる機械の登場
1930: ボコーダー（通信用の音声分析・音声合成器）の登場
1950: コンピュータを用いた音声合成器の登場（デイジーベルの歌唱）
1999: 隠れマルコフモデル（HMM）を用いた音声合成の登場
2013: ニューラルネットワークを用いた音声合成の登場
2016: WaveNetの登場

##### WaveNet
ディープラーニングを活用した音声合成手法
音声波形を生成するためのニューラルネットワーク
DeepMind社が開発（2014年にGoogleが買収）
音声合成の最高精度を更新
→自然な音声を作り出す

従来はHMMが主流であったが、WaveNetが登場してからは
ディープラーニングを活用した音声合成が主流になった

WaveNetはニューラルネットワークを用いた音声合成では一番注目を集めている

##### 音声合成を活用したサービス
・音声アシスタント
・スマートスピーカー（GoogleHomeやAmazonEcho）
・カーナビ
・ブックリーダー
・ニュースリーダー
・自動翻訳

※音声認識の精度向上も相まり、音声技術関連サービスが増加

##### Voice UI
Voice User Interface
声で入力・出力を行いやりとりをする
スマートスピーカーやアシスタントサービスの台頭で注目を集める
Voice UIプロダクトの開発には音声合成が不可欠

##### Androidの音声合成
・標準で質の高い音声合成APIが利用可能
・Android1.6（2009年リリース）から搭載されており、歴史は古い
・日本語対応は2014年頃から

##### Androidで音声合成を利用する機会
・アプリの性質に「音声合成」が適した場合
　本やニュースの読み上げ
　ガイド
　ナビゲーション
　対話（アシスタントなど）

・アプリのアクセシビリティを向上させたい場合
　Androidには「Talkback」が標準搭載

　Talkback・・・Google製スクリーンリーダー
　　　　　　　　　画面の音声フィードバックが出力され、
　　　　　　　　　画面を見ずにデバイスを利用できる機能
・ディスプレイを持たないデバイスの開発をする場合
　AndroidOSは「デバイス」開発でも多く利用される
　デバイスはディスプレイがあるとは限らない
　音声合成が出力としてのインターフェースとなることは多い

### Androidで利用可能な音声合成
音声合成を利用する方法は大きく3つある
(1)Android標準の音声合成APIを利用する
(2)サードパーティ製（Android標準API以外）の音声合成を利用する
(3)自前で音声合成を構築する

### (1)Android標準の音声合成APIを利用する
TextToSpeech（TTS）API （Android 1.6〜）
手軽な実装で音声合成の導入が可能

##### 標準音声合成を利用するメリット
・実装工数をさほどかけずに安定した音声合成を導入できる
　→これが最大のメリット
・カスタマイズ可能な項目も充実
　声のスピード
　声のピッチ
　定位
　ボリューム
　声の変更
　エンジンの変更

##### 標準音声合成を利用するデメリット
・提供される音声データ以外利用できない
・開発したいサービスと声がマッチしない場合などに対応できない
・カスタマイズ可能な範囲が限られる
・端末によって利用可能な音声データに差異がある

### (2)サードパーティ製（Android標準API以外）の音声合成を利用する
・様々なサードバーティ製の音声合成サービスが利用できる
・WebAPIや組み込みSDKなど形態は様々

##### サードパーティ製の音声合成
・Google Cloud Text To Speech
・Amazon Polly
・AlTalk

##### サードパーティ製を利用するメリット
・ユニークでハイクオリティな音声合成が利用できる
・マッチしたサービスがあればプロダクトの理想にあった音声を選択できる
・端末のエンジンやスペックに影響を受けづらい
　　
##### サードパーティ製を利用するデメリット
・利用したいサービスによって導入コストが異なる
・外部サービスへ依存してしまうことのリスク

##### Web APIで提供されるTTSサービスの利用
Web APIで提供される音声合成サービスが増えている
例）
・Google Cloud Test-to-Speech（GCTS）
　Google Cloud Platformが提供する音声合成サービス
　安価に自然な発話ができる音声合成を利用可能
　WaveNetを利用した高品質な音声合成を含む

##### 利用方法
①APIにテキストデータを渡して、音声データ生成をリクエストする
②音声データを受け取り再生可能な形に変換する
③再生する
　GCTSではSSMLが利用可能
　SSMLは音声合成用のマークアップ言語
　抑揚など発言をマークアップ言語で制御できる

 TTSエンジンへの文字数はどれぐらい渡せるか
 →4000文字

##### WebAPI利用の注意点
・コスト面
　リクエスト量（従量課金）
　通信量
・パフォーマンス面
　HTTP通信を必要とすることによる再生遅延
　→リクエストする文章量（バイト容量）によって、遅延度が変わる
　オフラインでの利用ができない

対策として
・コスト面
　CDNやCloud Storage等でキャッシュすることによって
　重複した音声合成を防止する
　標準の音声合成と併用する
　※声の差異が気にならない場合に限る

・パフォーマンス面
　オフラインキャッシュの利用

※サービスの性質によっては上記の対策が難しい場合もある

##### 組み込み系の音声合成を利用する
音声合成エンジンをアプリ内に設置し利用する方法も存在する
AI社のAITalk

組み込み用のSDKが提供されていて、それをアプリ内で利用する

##### 組み込み系の音声合成利用のメリット
・読み上げまでの遅延を最小限で抑えられる
・オフラインでの読み上げに対応できる

##### 組み込み系の音声合成利用の注意点
・エンジンや音声データのサイズが大きい
　・アプリの初回起動時の音声データ設定処理が必要になる
　・アプリ自体のサイズも大きくなる

・メンテナンスが難しい

・導入するサービスの利用可能端末が制限される可能性がある
→対応しているCPUが違うとか

### (3)自前で音声合成を構築する
独自の音声合成を利用する
・音響モデルやテキストから音声に変換する音声合成エンジンの開発が必要

##### メリット
・開発したいプロダクトにあった音声合成を利用できる
・外部の事情に左右されない

##### デメリット
・工数大
・専門的な知識が必要
・コスト大
　声優調達
　録音設備・機材
　インフラ構築
　メンテナンス



# 5.Scadeを使って「Swift」で始めるAndroidアプリ開発
マルチプラットフォームとして有名なのが
最近だとFlutter、KotlinNative
古くからあるものとしてReactNative

マイナーなものとして
VueNativeやXamarinなどがある

そんな中でScadeとは
・EclipseベースのIDE
主な機能
・Swiftを用いたマルチプラットフォーム開発
・Swiftを用いた共通ライブラリ開発
・Swift+Kituraを用いたサーバーサイド開発
　※Kituraはサポートが終了している

基本無料だが、一部有料でないと利用できない機能がある

### iOSからAndroidへの開発はScadeが初めてではなく以前から存在していた
・Objective-C+apportable 2011
apportableでJavaのコードに変換してビルドできる

・Fire+Silver 2015
SwiftコードをJavaのコードに変換してビルドできる

いずれも、開発が終わってしまったりして、現在は後発のScadeが細々と残っている

### ScadeのSwiftサポート
Swiftの3、4、5と小まめにサポートしている

### なぜAndroidでSwiftが動くのか
以下、コンパイラの話

##### Androidのapkは以下の手順でパッケージ化される
①ソースコード（IDE: AndroidStudio、言語: Kotlin）
↓ javac、kotlinc
②中間コード
↓ ProGuard/D8、R8（D8）
③ネイティブコード
↓ apk
④パッケージ

##### iOSのipaは以下の手順でパッケージ化される
①ソースコード（IDE: Xcode、言語: Swift）
↓ Clang
②中間コード
↓ LLVM
③ネイティブコード
↓ ipa
④パッケージ

以下、マルチプラットフォーム開発では
##### KotlinNative
1.Android
①ソースコード（IDE: AndroidStudio、言語: Kotlin）
↓ kotlinc
②中間コード
↓ ProGuard/D8、R8（D8）
③ネイティブコード
↓ apk
④パッケージ

2.iOS
①ソースコード（IDE: AndroidStudio、言語: Kotlin）
↓ kotlinc
②中間コード
↓ LLVM
③ネイティブコード
↓ ipa
④パッケージ

##### Flutter
1.Android
①ソースコード（IDE: AndroidStudio、言語: Dart）
↓ NDK（Clang）
②中間コード
↓ NDK（LLVM）
③ネイティブコード
↓ apk
④パッケージ

2.iOS
①ソースコード（IDE: AndroidStudio、言語: Dart）
↓ NDK（Clang）
②中間コード
↓ LLVM
③ネイティブコード
↓ ipa
④パッケージ

##### Scade
Scadeのサイトに明確な記載はないが
発表者の方が調査された結果、
コンパイルの流れは大体Flutterと同じと推測される

1.Android
①ソースコード（IDE: Scade、言語: Swift）
↓ NDK（Clang）
②中間コード
↓ NDK（LLVM）
③ネイティブコード
↓ apk
④パッケージ

2.iOS
①ソースコード（IDE: Scade、言語: Swift）
↓ NDK（Clang）
②中間コード
↓ LLVM
③ネイティブコード
↓ ipa
④パッケージ

Scadeの画面作成は、AndroidやXcodeと同じようにGUIで作成することができる

### Scadeでできる主なこと
・カメラ制御
・地図制御
・Deeplink遷移
・WebView表示
・カスタムフォント表示
・SVGアニメーション
・フォアグラウンド・バックグラウンドのハンドリング
・タップ・スワイプのジェスチャーハンドリング
・JSONからAPIのコード生成ジェネレータ
決められたJSONの書式で記載すると、リクエストとレスポンスとネットワーククラスを作ってくれる

### Scadeでできない主なこと
・動画表示
・Push通知制御
・Bluetooth制御
・遷移アニメーションのカスタマイズ
・細かいライフサイクルのハンドリング
・テストコードの実行
・タブレット対応（固有のViewを出せない）
・Java / Kotlinの呼び出し
・ライブラリ管理ツールがSPMしかない（結構制約がある）

### Scadeの不安要素（Android向け）
・一部ビルドできないAndroid端末がある
・可変デザインだとAndroidで表示が崩れることがある
・Androidでメインスレッドで動作するべきところが、Scadeのビルドだとそうはならずにクラッシュする
・大量の画像はAndroidでクラッシュすることがある
　→内部的にViewを使い回す構造になっていないようで、メモリを大量に使用する
・一部のネイティブAPIに非対応
・eclipseベースなのでエディタが重い
・アニメーション周りのサポートがまだまだ弱い
・内部エラーのクラッシュは何も対処できない（※Scadeに限らず、マルチプラットフォームの問題）
・GUIで設定できるものが少ない
→アプリ開発がここ数年で成熟してきている。
　よく使われるものはGUIで設定ができる

・Scadeのシミュレータは実機とは微妙に結果が違うことがある
→シミュレータで動いても、実機では動かないものがある
　シミュレータでは見た目の確認など、素早くできるものを主に行う

・差分ビルドの仕組みがまだない