umeda_apk #4 メモ
2018/06/07 にCAさんの大阪支社で開催された umeda.apk #4 - Report from Google I/O 2018 に関するメモです
What's new in Android @hi6484 / 株式会社メルカリ
Google I/O 2018 で発表された内容の全体像
Android App Bundles
- Legacy APK
- リソースはすべて入れる
- Dynamic Delivery
- 必要なリソースだけ入れる
Android Jetpack
Battery
Adaptive Battery
- 消費電力をアプリの使用状況に合わせて調整する
App Standby Buckets
- 4つの状態がある
- Active
- Working set
- Frequent
- Rare
- 制限されるのは
- Job
- Alarms
- High Priority Firebase Cloud Message
- Network
- 4つの状態がある
Background Input & Privacy
- マイク、カメラ、センサー情報
- バックグラウンドで使わない!
Location
- Wi-Fi Round-Trip-Time(RTT) APIで屋内でMAPが使える
- ACCESS_FINE_LOCATIONパーミッションが必要
- Google Wi-Fiが IEEE 802.11mc WiFiプロトコルをサポートする
Security
- Fingerprint ManagerがDeprecated
↓↓↓
Enterpise
企業向けの機能 (回転寿司にある注文用のタブレットアプリとかああいう向けのやつ)
- android.content.pm.CrossProfile
- Profileをスイッチ
- DevicePolicyManager.setLockTaskPackage()
- デバイスの画面をロックする
- DevicePolicyManager.createAndManagerUser(MAKE_USER_EPHEMERAL)
- ユーザを作成する
Notification
ユーザがメッセージを受信したときに新しいAPIを追加
- Inline images/stickers
- Participant images
- Smart reply UI
- RemoteInput.setChoices()
Deprecated Policy
App Compatibility
privateと@hideのAPIを使わない!
g.co/dev/appcompat
へリクエストして、APIに対して3タイプのリストを持っている
- Blacklist
- Dark Greylist
- Light Greylist
Camera
- タイムスタンプ
- Stabilization (手ブレ補正)
- Display Flash
- USBカメラ
- マルチカメラ
ImageDecoder
- Animated Image Drawable (GIFファイルをロードできる)
- BitmapFactoryは使わずImageDecoderつかってね
Media
Chrome OS
Preview Android Studio on Chomebooks
- ChromeOSでAndroid Studioが動く
- USBデバッグはサポートされていない
- 今後に期待
Android Jetpack @satorufujiwara / 株式会社サイバーエージェント
- 良いアプリを早く簡単につくるための、ライブラリやツールや設計指針
- Foundation(基本), Archtecture(アプリ設計), Behavior(動作), UI の4つに分類されている
- Support LibraryやArchtecture Commponentも含まれる
What's new in Android Jetpack
今回更新があったもの
WorkManager
- バックグラウンド処理を行うためのライブラリ
- 画像のアップロードのような、アプリを終了しても継続したい処理につかう
- アプリを終了した場合に中断したい処理にはThreadPoolもしくはRxJavaを使う
- 内部的にはJobScheduler or FirebaseJobDispatcher or AlarmManagerが使われる
WorkManagerの実行例
class UploadPhotoWorker : Worker() { override fun doWork() { // do in background uploadPhoto() return WorkerResult.SUCCESS } } val request = OneTimeWorkerRequestBuilder<UploadPhotoWorker>().build() WorkManager.getInstance().enqueue(request)
Navigation
- 単一Activity内のFragmentの画面遷移(Fragment Transaction)を行うフレームワーク
- 変数(bundle)の受け渡しUp/Backの制御やDeep Linksも定義することができる
- Android Studio 3.2 から導入されたNavigation Editorを使い編集する
- Navigation Editor の編集結果はXMLで保存される
- コードからはNavigationControlleなどを用いて遷移を呼び出す
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { findViewById<Button>(R.id.next_button).setOnClickListener( Navigation.createNavigationOnClickListener(R.id.next) ) findViewById<Button>(R.id.settings_button).setOnClickListener { v -> val navController = v.findNavController() navController.navigate(R.id.settings) } }
Paging
- Archtecture ComponentsのPagingのStableバージョンがでた
- Recycler Viewに表示しているデータの「続きを読み込む」ライブラリ
- 読み込み先はネットワーク、データベース、またはその両方
Slices
- Google検索(今後はGoogleアシスタントなどにも)にアプリのコンテンツを表示するためのUIテンプレート
- Android 4.4 (API 19) 以降で使える
- 自身のアプリのエンゲージメントを高めるのにつかう
Andoird KTX
- AndoirdのAPIをKotlinから扱いやすくするためのKotlinの拡張関数群
- 既にバージョン0.3.0が公開されていたが、1.0.0-alphaが公開された
- Android Framework以外のライブラリに対応した拡張関数が多く追加されている
Android KTXの例
// Before adapterView.setPaging(10, avatarView.paddingTop, 10, adapterView.paddingBottom) // After (名前付き引数を使い実現している) adapterView.updatePadding(left = 10, right = 10)
BTW: Kotlinについて
- Kotlinを使ったPlaySotre上のアプリは昨年比で6倍
- ディベロッパーの35%がKotlinを使っており、毎月増加している
- Android DevelopersのドキュメントもKotlin対応版が提供されるようになった
googlesamples/android-sunflower
Android Jetpackをふんだんに使ったサンプル(ベストプラクティス?)
AndroidX
サポートライブラリの名前が分かりづらかった問題(v4とかv7とか...) → AndroidXという名前でリファクタリング
- 新しいAndroidのバージョンではありません
- Support Libraryなどのパッケージをリファクタリングしたもの
- OSにバンドルされないAndroidの拡張ライブラリ
- JetpackにはAndroidXに含まれるものもあるし、含まれないものもある
AndroidXのリファクタリング
- パッケージをリファクタリング
com.android.support.**
→androidx.**
android.databinding.**
→androidx.databinding.**
android.arch.**
→androidx.arch.core.**
- v4やv7などの表記が消える
- バージョンが28.0.0から1.0.0にリセットされる
- 管理も厳密に (メジャーバージョンが同じなら互換性あり)
AndroidXへの移行
- Android Studioにリファクタリングツールが提供される
- 上部メニュー > Refactor > Refactor to AndroidX...
- 使っているライブラリのJAR/AARを変換するJetifierというツールも提供される
One more thing
一番盛り上がってたやつ
MotionLayout
- ConstraintLayout 2.2から導入されるConstraintLayoutのサブクラス
- Viewの状態(ConstraintSet)間をアニメーションを使って動かすことができる
- What's new with ConstraintLayout and Android Studio design tools
- Motion Editorでアニメーションを編集することができる
Dynamic Feature @punchdrunker / 株式会社ミクシィ
Android App Bundleの目玉機能の一つである、Dynamic Feature Modulesについてのお話。
Android App Bundle概要
アプリをいままでよりスマートに配信する事が出来る機能群の総称
- Multi APKの代替 (何らかの理由で端末別にapkを用意できる仕組み)
- APKサイズの最適化 (aab)
- 必要になった時に追加でモジュールをインストールできる
- Dynamic Feature Moduleとしてベータ公開中
- アプリをインストールしていなくてもモジュール単位で利用可能になる
- instant enableとして近日公開予定
(Android Studio 3.2 RC14以降でしか使えない)
Dynamic Feature Module?
アプリのインストール後に、必要になった時に機能やリソースを事後的にインストール(Dynamic Delivery)することができる仕組みのこと。
一部の端末やユーザ向けのものはアプリインストール後に必要になったときにインストールすることで、その機能が必要の無いユーザに対してはストレージ容量を抑えられる。
また回線速度に依存するが、モジュールのインストールには数秒以上かかると思ったほうがよい。
必要なくなったらuninstallすることもできる。
Dynamic Feature Moduleの使い道
- 有料コンテンツやプレミアム機能
- 有料登録時にインストールできればよい
- ゲームのステージ情報
- ステージが進んだ時にインストールすればよい
- とにかく大きな画像などのリソースをたまに使う
- 必要だとわかったらインストールすればよい
- 利用者が少なく、ある程度分離された機能
- 他サービスとの連携する機能など
(あくまで妄想)
どんな対応が必要か
- play coreライブラリを使用
com.google.android.play.core.splitinstall.*
- SplitInstallManagerを使って、利用可能なモジュールの確認やインストールを行う
- 確認:
SplitInstallManager.getInstalledModules()
- 追加:
SplitInstallManager.startInstall(module)
- 削除:
SplitInstallManager.defferedUnsintall(modules)
- 確認:
- インストール完了したら(SplitInstallStateUpdatedListener)を使うだけ
- パッケージ名を指定して、startActivity()やcreatePackageContext()するだけ
デモ
- 設定アプリでhochoアプリのストレージ使用量を確認
- hochoアプリを起動
- メニューからDynamic Feature Moduleを選択
- 写真一覧が表示されるまで待機
- 写真一覧が表示されたら再度設定アプリでhochoのストレージ使用量を確認
サンプルアプリ: インストールURL → hocho - Google Play
ハマりどころ(1)
- Modules 'base' and 'gallery' contain entry 'res/layout/activity_main.xml' with different content.
- 別モジュールでも同じリソース名は不可
- オンデマンドモジュールのタイトルはリソースIDには、ベースモジュールで定義された文字列を指定する必要があります。無効なモジュールは「gallery」です
- ベースとなるアプリ側でリソースIDを定義しておく必要がある(feature_names.xml)
- implementationで利用するライブラリを定義すると、dynamic feature module側から使えない
- apiでロードするようにしたら使えた
ハマりどころ(2)
- ベータ機能なので、申請フォームに記入が必要
- 半日くらい待つと使えるようになっていた
- aabリリースしたらminSdkVersion21なのに、hdpi端末でベクターがぼやけた(伝聞)
- VectorDrawableCompatのissueが上がっているので、そのうち直りそう
Work Manager @takahirom / 株式会社AbemaTV
Workmanagerとは
Android Jetpack - Architectureの中の1つ Google I/O 2018 で発表
Deferrable guaranteed execution (延期保証実行)
- ツイートの送信
- ログ送信
- データ同期
- メディアファイルのサーバへのアップロード
Deferrable guaranteed execution の何が問題か
- タイミングが後になってもよく、動作が保証したい場合たくさんの解決方法がある
- JobScheduler, FirebaseJobDespatcher, AlarmManager + BroadCastReceivers
- たくさんのことを考慮しながら、たくさんのAPIの呼び出しを書く必要がある
- APILevel?, FirebaseJobDespatcher? ...
- これにWorkManagerが対応する
どんなタスクにWorkManagerを使うべきか?
- システムがアプリを終了したとしても、動作保証したいタスクのために使う
アプリのプロセスが終了しても、安全に終了できるタスクのためには利用しない
- それは、ThreadPoolかRxJavaかCoroutineを使うべき
例えばどんなタスク
- ○: ツイート
- ○: メディアファイルのサーバへのアップロード
○: データのパースとデータベースへの保存
×: パレットカラーを抽出してImageViewをアップデート (※1)
- ×: データをパースしてViewをアップデート (※1)
- ×: 課金のトランザクションを実行 (※2)
(※1): ThreadPool, RxJava, Kotlin Coroutine を使う (※2): Foreground Service を使う
WorkManagerの使い方
// 必須 implementation "android.arch.work:work-runtime:1.0.0-alpha02" // Firebase JobDispatcherを使う場合必要 implementation "android.arch.work:work-firebase:1.0.0-alpha02" // Kotlinを使う場合、あったほうが簡潔に書ける implementation "android.arch.work:work-runtime-ktx:1.0.0-alpha02" // テストを書ける androidTestImplementation "android.arch.work:work-testing:1.0.0-alpha02"
WorkManagerの中心となるクラス
- Work: 作業をするクラス。実際にやりたいことを継承して記述する
- WorkRequest: Workのリクエストクラス
- OneTimeWorkRequest: 一度きりのWorkを実行する場合のRequest
- PeriodicWorkRequest: 繰り返しWorkを実行する場合のRequest
Workerを使ってみる
コードなので省略
WorkManagerの機能紹介
- Workの依存グラフが作れる
- then()でWorkを繋げられる
- RxJavaのzipみたいなことができる
- InputMergerを使う
- Workに条件をつけられる
- LiveDataで今の状態が見られる
- Workにタグをつけて絞り込みなどができる
- チェイン開始時にユニークな名前をつけて絞り込みや、同じ名前が流れたときの制御ができる
then()でWorkを繋げられる
- 写真にフィルターをかけた後アップロードしたいときなどに利用する
- 今回は World -> Hello, World -> HELLO, WORLD をやってみた
WorkManager.getInstance() .beginWith(OneTimeWorkRequestBuilder<AddHelloWorker>() .setInputData(mapOf(KEY to "World").toWorkData()) .buiild() ) // ここ .then(OneTimeWorkRequestBuilder<UpperCaseWorker>().build()) .enqueue()
Workに条件をつけられる
- ネットワークに繋がっている時のみ、充電時のみ実行などの条件がつけられる
- setConstraintsで設定してあげる
val workRequest = OneTimeWorkRequestBuilder<AddHelloWorker>() .setInputData(mapOf(KEY to "World").toWorkData()) // 充電がはじまると、実行される .setConstranits(Constraints.Builder().setRequiresCharging(true).build()) .build()
Workにタグをつけて絞り込みなどができる
- 好きにネームスペースが作れる
- addTag()でタグ追加
- getStateusesByTag()で絞り込み
- 他にもタグ単位でキャンセルしたりできる
val taggedRequest = OneTimeWorkerRequestBuilder<AddHelloWorker>() .setInputData(mapOf(KEY to "WorkManager").toWorkData()) // タグ追加 .addTag("tag") .build() WorkManager.getInstance().enqueue(taggedRequest) WorkManager.getInstance() // getStatusesByTag()で絞り込み .getStatusesByTag("tag") .observe(this, Observer<List<WorkStatus>> { workStatuses -> val workStatus = workStatuses?.getOrNull(0) ?: return@observer when (workStatus.state) { State.SUCCEEDED -> { ... } } })
チェイン開始時にユニークな名前をつけて絞り込みや、制御ができる
- beginUniqueWorkを使う
- ExistingWorkPolicy は同じ名前でWorkを始めたときのポリシー
- KEEP: 先に始めたWorkだけ実行
- REPLACE: 先に初めたWorkをキャンセルして削除、新しいWorkを開始
- APPEND: 先に始めたWorkの後に、両方行う
val workRequest = OneTimeWorkRequestBuilder<AddHelloWorker>() .setInputData(mapOf(KEY to "World").toWorkData()) .build() WorkManager.getInstance() .beginUniqueWork("Hello", ExistingWorkPolicy.KEEP, workRequest) .enqueue()
Inside WorkManager
WorkManagerの内部実装の基本
DBに情報を入れてから、①まずExecutorで実行する。その間にプロセスが止まっても良いように②JobSchedulerなどからExecutorを実行する
- ① Executor
- ② API 23+?
- YES: JobScheduler
- Executor
- NO: App include Firebase JobDispatcher?
- YES: Firebase JobDispatcher
- Executor
- NO: AlarmManager + Broadcast Receivers
- Executor
- YES: Firebase JobDispatcher
- YES: JobScheduler
WorkManagerの依存関係
- Roomに依存している
- DBの中をStethoで確認できる
- androidx.work.workdbにWorkerが登録されている
- DBの中をStethoで確認できる
WorkManagerのテスト
TestDriver()
を使って同期的に動かしてテストできる
@Test func test() { val testDriver = WorkManagerTestInitHelper.getTestDriver() val workRequest = OneTimeWorkRequestBuilder<AddHelloWorker>() .setInputData(mapOf(KEY to "World").toWorkData()) .build() WorkManager.getInstance().enqueue() testDriver.setAllConstraintsMet(workRequest.id) val outputData = WorkManager.getInstance() .synchronous() .getStatusByIdSync(workRequest.id) .outputData assertThat(outputData.getString(KEY, "none"), equalTo("Hello World")) }
WorkManagerのサンプル実装
- WorkManagerSample - googlesamples/android-architecture-components
- Navigationなどもここにあるので見てみるとよいです
- 画像が表示してあってボタンを押すと、WorkManagerでエフェクトをかけたり出力したりする
Android Sunflower (alpha) 内にあるWorkManager
Android Sunflower (alpha) は、Android JetpackでAndroid開発のベストプラクティスを示すガーデニングアプリ。
- Workerも組み込まれている
- Android SunflowerのWorkerの起動タイミング
- RoomのDBのonCreateで行っている (1度しか呼ばれない)
- Android SunflowerのWorkerの処理
- ローカルにあるJSONをパースして、Roomに入れている
Workerの中でのDIは?
- Redditに質問が上がっていた
- 乞うご期待
ベストプラクティス
- システムがアプリが終了したとしても、動作保証したタスクのために使う
- DataクラスはデータストアではないのでちゃんとRoomなどを使う
実行できる機会をうかがうようにConstraintで条件を書こう
例えば画像の書こうとアップロードをするときに、アップロードのWorkにネットワークが必要だとしておけば、飛行機に乗っている間に画像の加工までは終わって、繋がったらアップロードしてくれるなどができる
まとめ
- システムがアプリが終了したとしても、動作保証したいタスクのために使う
- OSの依存、使うべき仕組みの切り替えなど、とても楽になる。ボイラープレートがなくなる
- Workに制約をつけれる、繋げられる、タグがつけられる、名前がつけられる、状態をLiveDataで取得できる
- 使いみちは多いので、使ってみると良さそう