- 投稿日:2019-07-11T21:37:04+09:00
KotlinのDelegated Propertyを使って、Android DatabindingのBaseObservableを実装する
はじめに
こんにちは。普段はAndroidアプリの開発をしているのですが、最近KotlinのDelegated Propertyを使って実装することが増えてきました。
また、Android Databindingというデータバインディング用の公式のライブラリがありますが、バインディングの実装方法としてBaseObservableというクラスを継承して実装する方法があります。
そこで今回は、こちらのBaseObservableとKotlinのDelegated Propertyを組み合わせた実装方法が可読性的に良いなと感じたのでその方法について紹介していこうと思います。
間違っている部分あれば指摘していただけますと幸いです。こちらを参考にしております。
https://stackoverflow.com/questions/46029570/android-data-binding-with-kotlin-baseobservable-and-a-custom-delegate検証済みの動作環境
以下の環境で正常に動作することを確認しています。
- Android Studio 3.4.1, 3.5 beta
- Kotlin 1.3.11
KotlinのDelegated Property
Kotlinの言語機能としてDelegated Propertyというものがあります。日本語に訳すと「委譲プロパティ」となります。
こちらはKotlinのプロパティのset,getする際のロジックを別のクラスとして切り出し、そちらに処理を委譲させることができるものになります。
Delegated Propertyを使った実装の例はこちらになります。by
キーワードを使って、クラスを記述します。こちらのクラスには、varであればgetValue()とsetValue()を、valであればgetValue()をそれぞれoperator funtionとして定義しておくことが必要になります。class Example { var p: String by ReadWriteDelegate() val q: String by ReadOnlyDelegate() } // var用のDelegate用のクラス class ReadWriteDelegate { // pのプロパティの値を取得時にこちらの処理を経由する operator fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, thank you for delegating '${property.name}' to me!" } // pのプロパティの値をセット時にこちらの処理を経由する operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("$value has been assigned to '${property.name} in $thisRef.'") } } // val用のDelegate用のクラス class ReadOnlyDelegate { // qのプロパティの値をセット時にこちらの処理を経由する operator fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, thank you for delegating '${property.name}' to me!" } }また、このDelegateに使うインターフェースも用意されています。val用の
ReadOnlyProperty
、var用のReadWriteProperty
の2つが用意されているので、プロパティごとに使い分けることになると思います。// ReadWritePropertyインターフェースを継承する class ReadWriteDelegate : ReadWriteProperty<Any?, String> { override fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, thank you for delegating '${property.name}' to me!" } override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("$value has been assigned to '${property.name} in $thisRef.'") } } // ReadOnlyPropertyインターフェースを継承する class ReadOnlyDelegate : ReadOnlyProperty<Any?, String> { override fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, thank you for delegating '${property.name}' to me!" } }これらのコードを以下のように実行するとこうなります。参照するときにはgetValueに記述していた処理が、更新するときはsetValueに記述していた処理が実行されていることがわかると思います。
fun main() { val example = Example() println(example.p) println(example.q) example.p = "updated p" }↓出力結果
Example@37f8bb67, thank you for delegating 'p' to me! Example@37f8bb67, thank you for delegating 'q' to me! updated p has been assigned to 'p in Example@37f8bb67.' Process finished with exit code 0Andriod Databindingについて
次はDatabindingについて軽く説明します。Android DatabindingはAndroidにおいてデータバインディングを実現するための公式のライブラリになります。bindするオブジェクトをxmlに定義しておくと、アノテーションプロセッシングによって、Bindingクラスが生成され、xml内で
@{}
のキーワードの中でbindされたオブジェクトを参照することができるというものです。詳しくは、こちらを御覧ください。
https://developer.android.com/topic/libraries/data-binding?hl=jaBaseOvservableによる実装
Android Databindingでは、バインディングする方法として2種類の方法があります。
- ObservableFieldを使う
- BaseObservableを使う
今回ObservableFieldでの方法については割愛し、BaseObservableを使った方法を紹介します。BaseObservableを使う方法では、Viewにバインディングさせる対象のプロパティは、以下のようにBaseObservableというクラス内で定義しておき、
@Bindable
(※Kotlinでは@get:Bindable
)アノテーションを付与する必要があります。また、API通信などによって取得したデータによって、バインディングしているプロパティを更新する場合、notifyPropertyChangedメソッドを使って、プロパティが更新されたことを明示的に通知する必要があります。class UserModel : BaseObservable() { @get:Bindable var firstName: String = "" set(value) { field = value notifyPropertyChanged(BR.firstName) } @get:Bindable var lastName: String = "" set(value) { field = value notifyPropertyChanged(BR.lastName) } }また、アプリの規模が大きくなってきたりすると、UserModelのデータを別のdataクラスとして持たせてそちらを経由させてデータを取得したい場合もあると思います。その場合は、以下のようになり、getterまで記述する必要が出てきました。
class UserModel(val userData: UserData) : BaseObservable() { @get:Bindable var firstName: String = "" get() = userData.firstName set(value) { userData.firstName = value notifyPropertyChanged(BR.firstName) } @get:Bindable var lastName: String = "" get() = userData.lastName set(value) { userData.lastName = value notifyPropertyChanged(BR.lastName) } } data class UserData(val firstName: String, val lastName: String)上記のように定義されたクラスは、xml内では
@{user.firstName}
のように記述することで、モデルクラスのプロパティをlayoutにbindすることができます。<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="user" type="youmeee.co.jp.app.UserModel" /> </data> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/firstName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}"/> <TextView android:id="@+id/lastName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.lastName}"/> </androidx.constraintlayout.widget.ConstraintLayout> </layout>DelegateクラスでBaseObservableを実装する
本題に入ります。上記のようにBaseObservableを使ったクラスはただプロパティをbindするだけであればそこまで冗長になりませんが、参照する際に少しロジックが入ってくると、見通しが悪くなる可能性があります。
また、データの取得時に別のdataクラスを経由したり、bindする前になんらかのロジックが必要な場合があります。その際、getterとsetterを両方記述する必要があり、プロパティが多くあるViewModelをbindする場合などにおいては、毎回それぞれを書かなくてはならず、少し手間がかかりますし、ボイラープレートな記述も増えていきます。
これを解決する方法として、KotlinのDelegated Propertyが使えます。以下のようにDelegateクラスを定義してみます。
class UserPropertyDelegate(data: String, id: Int) : ReadWriteProperty<Any?, String> { override fun getValue(thisRef: Any?, property: KProperty<*>): String { return data } override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { data = value notifyPropertyChanged(id) } }こちらを使うと、以下のように、バインディングするプロパティを記述することができます。
setterとgetterをそれぞれ定義する必要がなくなりましたし、notifyPropertyChangedを各プロパティごとに呼ぶ必要もなくなりました。なんて便利!!class UserModel(val userData: UserData) : BaseObservable() { @get:Bindable var firstName: String by UserPropertyDelegate(userData.firstName, BR.firstName) @get:Bindable var lastName: String by UserPropertyDelegate(userData.lastName, BR.lastName) /* Before @get:Bindable var firstName: String = "" set(value) { field = value notifyPropertyChanged(BR.firstName) } @get:Bindable var lastName: String = "" set(value) { field = value notifyPropertyChanged(BR.lastName) } */ }また、上記のプロパティでは、Stringのプロパティにしか対応していないので、ジェネリクスを使って汎用的なDelegateクラスにすることも可能です。
// ジェネリクスTを使って、汎用的にDelegateクラスを利用する class UserPropertyDelegate<T> (data: T, id: Int) : ReadWriteProperty<Any?, T> { override fun getValue(thisRef: Any?, property: KProperty<*>): T { return data } override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { data = value notifyPropertyChanged(id) } }Delegates.observableも使える
↑こちらでも紹介されていますが、
Delegates.observable()
というメソッドを使ってDelegated Propertyを実装する方法もあります。
Delegates.observable()
は、以下のような仕様になります。
第一引数: プロパティの初期値
第二引数: プロパティが変更されたときの通知を受け取るラムダ。パラメータとして「割り当てられているプロパティ」「古い値」「新しい値」があります。。例えば、データバインディング用のプロパティを定義し、setしたあとnotifyPropertyChanged()を呼びたいときは、以下のように記述することができます。プロパティが変更されるたびに、ラムダにてイベントを受け取れるので、ここで
notifyPropertyChanged()
を呼ぶことができます。class UserModel : BaseObservable() { @get:Bindable var firstName: String by Delegates.observable("") { prop, old, new -> notifyPropertyChanged(BR.firstName) } }まとめ
KotlinのDelegated Propertyの機能を使えばDatabindingのプロパティをシンプルに定義することができました。
これからもKotlinを愛でていきたいです。参考資料
- 投稿日:2019-07-11T21:37:04+09:00
【Android DataBinding】BaseObservableを継承しているクラスのプロパティをKotlinのDelegated Propertyで実装する
はじめに
こんにちは。普段はAndroidアプリの開発をしているのですが、最近KotlinのDelegated Propertyを使って実装することが増えてきました。
また、Android Databindingというデータバインディング用の公式のライブラリがありますが、バインディングの実装方法としてBaseObservableというクラスを継承して実装する方法があります。
そこで今回は、こちらのBaseObservableとKotlinのDelegated Propertyを組み合わせた実装方法が可読性的に良いなと感じたのでその方法について紹介していこうと思います。
間違っている部分あれば指摘していただけますと幸いです。こちらを参考にしております。
https://stackoverflow.com/questions/46029570/android-data-binding-with-kotlin-baseobservable-and-a-custom-delegate検証済みの動作環境
以下の環境で正常に動作することを確認しています。
- Android Studio 3.4.1, 3.5 beta
- Kotlin 1.3.11
KotlinのDelegated Property
Kotlinの言語機能としてDelegated Propertyというものがあります。日本語に訳すと「委譲プロパティ」となります。
こちらはKotlinのプロパティのset,getする際のロジックを別のクラスとして切り出し、そちらに処理を委譲させることができるものになります。
Delegated Propertyを使った実装の例はこちらになります。by
キーワードを使って、クラスを記述します。こちらのクラスには、varであればgetValue()とsetValue()を、valであればgetValue()をそれぞれoperator funtionとして定義しておくことが必要になります。class Example { var p: String by ReadWriteDelegate() val q: String by ReadOnlyDelegate() } // var用のDelegate用のクラス class ReadWriteDelegate { // pのプロパティの値を取得時にこちらの処理を経由する operator fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, thank you for delegating '${property.name}' to me!" } // pのプロパティの値をセット時にこちらの処理を経由する operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("$value has been assigned to '${property.name} in $thisRef.'") } } // val用のDelegate用のクラス class ReadOnlyDelegate { // qのプロパティの値をセット時にこちらの処理を経由する operator fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, thank you for delegating '${property.name}' to me!" } }また、このDelegateに使うインターフェースも用意されています。val用の
ReadOnlyProperty
、var用のReadWriteProperty
の2つが用意されているので、プロパティごとに使い分けることになると思います。// ReadWritePropertyインターフェースを継承する class ReadWriteDelegate : ReadWriteProperty<Any?, String> { override fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, thank you for delegating '${property.name}' to me!" } override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("$value has been assigned to '${property.name} in $thisRef.'") } } // ReadOnlyPropertyインターフェースを継承する class ReadOnlyDelegate : ReadOnlyProperty<Any?, String> { override fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, thank you for delegating '${property.name}' to me!" } }これらのコードを以下のように実行するとこうなります。参照するときにはgetValueに記述していた処理が、更新するときはsetValueに記述していた処理が実行されていることがわかると思います。
fun main() { val example = Example() println(example.p) println(example.q) example.p = "updated p" }↓出力結果
Example@37f8bb67, thank you for delegating 'p' to me! Example@37f8bb67, thank you for delegating 'q' to me! updated p has been assigned to 'p in Example@37f8bb67.' Process finished with exit code 0Andriod Databindingについて
次はDatabindingについて軽く説明します。Android DatabindingはAndroidにおいてデータバインディングを実現するための公式のライブラリになります。bindするオブジェクトをxmlに定義しておくと、アノテーションプロセッシングによって、Bindingクラスが生成され、xml内で
@{}
のキーワードの中でbindされたオブジェクトを参照することができるというものです。詳しくは、こちらを御覧ください。
https://developer.android.com/topic/libraries/data-binding?hl=jaBaseOvservableによる実装
Android Databindingでは、バインディングする方法として2種類の方法があります。
- ObservableFieldを使う
- BaseObservableを使う
今回ObservableFieldでの方法については割愛し、BaseObservableを使った方法を紹介します。BaseObservableを使う方法では、Viewにバインディングさせる対象のプロパティは、以下のようにBaseObservableというクラス内で定義しておき、
@Bindable
(※Kotlinでは@get:Bindable
)アノテーションを付与する必要があります。また、API通信などによって取得したデータによって、バインディングしているプロパティを更新する場合、notifyPropertyChangedメソッドを使って、プロパティが更新されたことを明示的に通知する必要があります。class UserModel : BaseObservable() { @get:Bindable var firstName: String = "" set(value) { field = value notifyPropertyChanged(BR.firstName) } @get:Bindable var lastName: String = "" set(value) { field = value notifyPropertyChanged(BR.lastName) } }また、アプリの規模が大きくなってきたりすると、UserModelのデータを別のdataクラスとして持たせてそちらを経由させてデータを取得したい場合もあると思います。その場合は、以下のようになり、getterまで記述する必要が出てきました。
class UserModel(val userData: UserData) : BaseObservable() { @get:Bindable var firstName: String = "" get() = userData.firstName set(value) { userData.firstName = value notifyPropertyChanged(BR.firstName) } @get:Bindable var lastName: String = "" get() = userData.lastName set(value) { userData.lastName = value notifyPropertyChanged(BR.lastName) } } data class UserData(val firstName: String, val lastName: String)上記のように定義されたクラスは、xml内では
@{user.firstName}
のように記述することで、モデルクラスのプロパティをlayoutにbindすることができます。<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="user" type="youmeee.co.jp.app.UserModel" /> </data> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/firstName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}"/> <TextView android:id="@+id/lastName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.lastName}"/> </androidx.constraintlayout.widget.ConstraintLayout> </layout>DelegateクラスでBaseObservableを実装する
本題に入ります。上記のようにBaseObservableを使ったクラスはただプロパティをbindするだけであればそこまで冗長になりませんが、参照する際に少しロジックが入ってくると、見通しが悪くなる可能性があります。
また、データの取得時に別のdataクラスを経由したり、bindする前になんらかのロジックが必要な場合があります。その際、getterとsetterを両方記述する必要があり、プロパティが多くあるViewModelをbindする場合などにおいては、毎回それぞれを書かなくてはならず、少し手間がかかりますし、ボイラープレートな記述も増えていきます。
これを解決する方法として、KotlinのDelegated Propertyが使えます。以下のようにDelegateクラスを定義してみます。
class UserPropertyDelegate(data: String, id: Int) : ReadWriteProperty<Any?, String> { override fun getValue(thisRef: Any?, property: KProperty<*>): String { return data } override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { data = value notifyPropertyChanged(id) } }こちらを使うと、以下のように、バインディングするプロパティを記述することができます。
setterとgetterをそれぞれ定義する必要がなくなりましたし、notifyPropertyChangedを各プロパティごとに呼ぶ必要もなくなりました。なんて便利!!class UserModel(val userData: UserData) : BaseObservable() { @get:Bindable var firstName: String by UserPropertyDelegate(userData.firstName, BR.firstName) @get:Bindable var lastName: String by UserPropertyDelegate(userData.lastName, BR.lastName) /* Before @get:Bindable var firstName: String = "" set(value) { field = value notifyPropertyChanged(BR.firstName) } @get:Bindable var lastName: String = "" set(value) { field = value notifyPropertyChanged(BR.lastName) } */ }また、上記のプロパティでは、Stringのプロパティにしか対応していないので、ジェネリクスを使って汎用的なDelegateクラスにすることも可能です。
// ジェネリクスTを使って、汎用的にDelegateクラスを利用する class UserPropertyDelegate<T> (data: T, id: Int) : ReadWriteProperty<Any?, T> { override fun getValue(thisRef: Any?, property: KProperty<*>): T { return data } override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { data = value notifyPropertyChanged(id) } }Delegates.observableも使える
↑こちらでも紹介されていますが、
Delegates.observable()
というメソッドを使ってDelegated Propertyを実装する方法もあります。
Delegates.observable()
は、以下のような仕様になります。
第一引数: プロパティの初期値
第二引数: プロパティが変更されたときの通知を受け取るラムダ。パラメータとして「割り当てられているプロパティ」「古い値」「新しい値」がある。例えば、データバインディング用のプロパティを定義し、setするときはnotifyPropertyChanged()を呼びたいときは、以下のように記述することができます。プロパティが変更されるたびに、ラムダにてイベントを受け取れるので、ここで
notifyPropertyChanged()
を呼ぶことができます。class UserModel : BaseObservable() { @get:Bindable var firstName: String by Delegates.observable("") { prop, old, new -> notifyPropertyChanged(BR.firstName) } }まとめ
KotlinのDelegated Propertyの機能を使えばDatabindingのプロパティをシンプルに定義することができました。
これからもKotlinを愛でていきたいです。参考資料
- 投稿日:2019-07-11T19:12:04+09:00
Android Keystoreの概要
昨今、システム開発においてセキュリティの重要性は増しています。
Androidのセキュリティ機構としては、Android Keystoreシステムなどが挙げられますね。
このAndroid KeystoreはAndroid developersのサイトに説明があるのですが、日本語だとちょっと読みづらい所があったので、自分なりに概要をまとめてみました。Android Keystoreシステムとは
ざっくりまとめると、「Androidデバイス内の安全な領域に暗号化キーを保管するための仕組み」と言えそうです。
暗号化キーをアプリ内にそのまま保持したりすると、ルート化された端末だと丸見えになります。
「セキュアなデータを端末内に保持する必要がある」などのセキュリティが重視される要件ではAndroid Keystoreの使用も検討しましょう。Android Keystoreの特徴
- 暗号化キーはデバイスから抽出が困難なコンテナ内に保管される
- 特定の暗号化モードでしか暗号化キーを使用できないように設定することができる
- 暗号化キーを使用する際にユーザー認証を求めることができる
Android Keystoreはどうやって暗号化キーのキーマテリアル抽出を困難にしているのか
- キーマテリアル(注1)の使用を「暗号化操作を実行するシステムプロセス」にしか許可しない
- 「アプリプロセス」にキーマテリアルの使用を許可しない
- Androidデバイスの安全なハードウェア(Trusted Execution Environment(TEE)、セキュア エレメント(SE)など)にキーマテリアルをバインドできるようにしている
注1… 解釈が曖昧ですが、ここでは「暗号化キー生成の元となるデータ」を指していると思われます。
暗号化キーの作成方法
以下のソースコードは、AndroidKeystoreプロバイダを利用して暗号化キーを作成する手順の一例です。
ここではRSAアルゴリズムの鍵ペアを作成しています。
共通鍵等のその他の鍵の生成方法や、暗号モードの指定方法の詳細はAndroid developersなどを参考にしましょう。
(例外処理は省略)Android Keystoreインスタンスの取得
AndroidKeyStoreインスタンスの取得/* Keystore.getInstanceの引数に"AndroidKeyStore"を指定し、Android KeyStoreのインスタンスを取得する。 このインスタンスはフィールドにAndroidKeyStoreSpiのインスタンスを保持する。 */ val keyStore: KeyStore = KeyStore.getInstance("AndroidKeyStore") //Android KeyStoreをロードする。内部のAndroidKeystoreSpiがこのメソッドにより初期化されるため、この処理が必要 keyStore.load(null)鍵ペアの生成
鍵ペアの生成/* 鍵ペアを作成するためのKeyPairGeneratorのインスタンスを取得する 引数のproviderに"AndroidKeyStore"を指定することで、 Android Keystoreに鍵ペアを作成するKeyPairGeneratorSpiインスタンスを取得する */ val kpg: KeyPairGenerator = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore" ) // 作成する鍵ペアのスペックを指定するためのKeyGenParameterSpecインスタンスを生成 val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder( "hoge", //エイリアスを"hoge"に設定。Android KeyStoreからエントリーを取得する際はこのエイリアスを使用する。 KeyProperties.PURPOSE_SIGN//鍵の使用目的を指定する。ここでは署名のみを目的とした鍵を生成。指定した目的以外で鍵を使用するとInvalidKeyExceptionが発生する ).run { //使用するダイジェストのアルゴリズムをSHA-256に限定する。これ以外のダイジェストアルゴリズムの使用は拒否される。 setDigests(KeyProperties.DIGEST_SHA256) //使用するパディングモードの指定。RSA鍵ペアを生成する場合は指定必須。指定したパディングモード以外は拒否される。 setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1) build() } //指定したKeyGenParameterSpecでKeyPairGeneratorを初期化 kpg.initialize(parameterSpec) //KeyPairGeneratorで鍵ペアを生成 val kp = kpg.generateKeyPair()データへの署名処理
データへの署名//署名対象のデータ val str = "sign" val data = str.toByteArray(StandardCharsets.UTF_8) // Android KeyStoreのインスタンスを取得 val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) } //Android KeyStoreからエイリアスを指定してKeystoreエントリを取得する val entry = keyStore.getEntry("hoge", null) //署名を作成/検証するためのSignatureインスタンスを取得。引数は適宜変更必要。 val s = Signature.getInstance("SHA256withRSA") //秘密鍵を指定してSignatureインスタンスを初期化する。ここでは変数entryはprivate keyであること前提 s.initSign((entry as KeyStore.PrivateKeyEntry).privateKey) //Signatureインスタンスによる署名対象データの更新を実行 s.update(data) //署名対象データに署名する val signature = s.sign() //署名したデータをBase64エンコード val result = Base64.encodeToString(signature, Base64.DEFAULT)Android KeyStoreを利用した暗号化キー生成を実装してみましたが、触ってみると非常に奥が深いですね。TEEやSEなどの詳細も気になるところですが、今回はここまでです。
- 投稿日:2019-07-11T18:59:09+09:00
FireTVのリモート停止
Vimに関してだけ使おうと思ってたんですけど、手持ちのRaspberry Piのイメージが吹っ飛んで消失する度にひどい目にあうので、この際備忘録的に残しておくやつです。簡単に…Raspbianのcronにこれを引っ掛けておくと、寝落ちしても勝手に動画再生が止まります。
TL;DR
backfire.sh#!/bin/sh adb connect my.fireTV > /dev/null 2>&1 sleep 3s adb shell input keyevent 223 adb kill-server備忘録としての解説
adb connect
のあと少し待ってあげないと、$ADB_VENDOR_KEYS
がカラのままなのでadb shell
が失敗してひどく混乱します。あとはキーイベント223 (KEYCODE_SLEEP
)を送って終わりです。多くのシェルからのFireTV遠隔操作の解説で使われる
adb shell input keievent 3
(キーイベント3はKEYEVENT_HOME
) は、ホームに戻る際にCECコマンドを出力する設定の場合は勝手にテレビがfireTVに切り替わり、我が家では不満アリです。電源も切りたいのであれば、"cec-utils"をインストールして 、定番のecho "standby 0" | cec-client -s
を足しておくのがスジかなと思います。
- 投稿日:2019-07-11T13:38:10+09:00
Bitrise で並列ビルド (iOS/Android)
概要
- React Native のビルドとデプロイに Bitrise を利用している
- iOS のビルド時間が長いせいで、 Android が完了する前に45分超えてしまう
- そのため、 iOS/Android でビルドするワークフローを並列実行したい
- 使っている技術が別物だから、並列実行しても問題ないのではないか
結論
並列実行は GUI ではサポートされていないが、 Bitrise CLI を使うと、超単純に並列ビルドが可能。
- ローカルに下記のような
bitrise.yml
を入れてGitリポジトリに入れるbitrise.yml--- format_version: '6' default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git project_type: react-native workflows: common: steps: - yarn@0.0.8: inputs: - command: install ios: steps: - certificate-and-profile-installer@1.10.1: {} - # 色々 android: steps: - install-missing-android-tools@2.3.5: {} - # 色々
- Bitrise にて、ワークフローエディタを開き、下記を入力
#!/bin/bash set -ex bitrise run common --config bitrise.yml bitrise run ios --config bitrise.yml & bitrise run android --config bitrise.yml & wait全体としてはこんな感じ。
これで、ビルド時間が3分の2くらいになった。
- 投稿日:2019-07-11T12:47:32+09:00
Activity transitions+shared elementsで画面遷移にアニメーションつけてきた+詰まったところ
今携わっているマッチングアプリで、ActivityTransactionで画面遷移をやってみました。
※こちらはデモなので私が撮影した我が家のかわいいネコチャンが表示されています。実際のアプリではかわいい女性が表示されます。要件
- カード選択画面(左右スワイプで選ぶ)→プロフィール詳細への移動のとき、同じ写真はスムーズなアニメーションで地続きになるようにする
- プロフィール詳細には複数写真があるので、プロフィール詳細で選んだ写真がそのままカード選択画面でも表示されるようにする
参考サイト
Android公式サイト
https://developer.android.com/training/transitions/start-activity
Googleデベロッパーブログ
https://developers-jp.googleblog.com/2018/04/continuous-shared-element-transitions.htmlその他transition animationやらいろいろ検索ででてきたサイト
実装方法
カードからプロフィールへの遷移
SharedElementsを有効にする
style.xmlで定義してあるアプリのrootThemeに
<item name="android:windowActivityTransitions">true</item> <item name="android:windowSharedElementsUseOverlay">true</item>を足す。
共有させたいObjectに同じtrasitionNameを指定
カード内のImageViewとプロフィール上部のImageViewのlayoutのxmlにtrasitionNameで同じ名前を指定します。
<ImageView android:id="@+id/profile_photo" android:layout_width="match_parent" android:layout_height="wrap_content" android:transitionName="share_profile_photo_img"/>これはプロフィール側の指定ですが、遷移元のカード側も同様に
android:transitionName="share_profile_photo_img"
を足します。
直接書くよりも、strings.xmlに引数切った方が共有しやすいと思います。startActivityにActivityOptionsを足す
遷移タイミングのstartActivityのBundleにoptionsとしてActivityOptionsを足す。
public void startActivity (Intent intent, Bundle options)実際のコードでは、
ActivityOptions.makeSceneTransitionAnimation(requireActivity(),android.util.Pair.create(view.photo, "share_profile_photo_img"))をstartActivityの第二引数に渡しています。
遷移先のActivityでImageのローディングをする
↑のstartActivityのタイミングで表示するurlを渡しておきます。(実際の実装だと諸事情によりUrlのlistと選択しているurlを渡しています)
で、onCreateでsetContentView(view)
後に、対象のImageViewにローディングをします。
このとき、ただロードするとロードよりも遷移が先にきてしまい、画像が用意されていないので背景の白色が一瞬うつってしまいます。
なので、ロード前に遷移を止めるActivity#postponeEnterTransition()
を呼び出し、画像ロード後にActivity#startPostponedEnterTransition()
を呼び出すと、白のチラツキなしに遷移ができるようになります。
https://developer.android.com/reference/android/app/Activity.html?hl=ja#postponeEnterTransition()
https://developer.android.com/reference/android/app/Activity.html?hl=ja#startPostponedEnterTransition()
多分よくある失敗がロードが失敗したタイミングで呼び出し忘れて永遠に遷移しない、だと思うのでわすれずに呼び出しましょう。引っかかったポイント
画像がなめらかに移動せず、拡大してからちょうどいいサイズになるように見える
最初実装したときはこんな感じでした。一回画像が拡大してから移行しているように見え、スムーズじゃないですね。
原因としては、画像の拡大率。どちらのImageViewもandroid:scaleType="fitCenter"
を設定していましたが、カード側が縦長、プロフィール側が横長でした。
なので、プロフィール側の画像サイズを必ず縦長にするようにして、回避しました。プロフィールで画像を切り替えたときにカード側に伝える方法
これはActivityTransitionに直接関係ないのですが、Transitionで遷移→戻るのタイミングで、遷移を止める
Activity#postponeEnterTransition()
のようなものが見当たりませんでした(あったら教えてほしい)
で、onActivityResultをつかってみたのですが、アニメーション遷移で遷移するタイミングで間に合わず、直前に表示されていた画像がチラついていました。
対応としては、EventBus的な機構を使って、カード側のFragmentをonCreate→onDestroyまでイベントを待機して、切り替えるたびに親画面に伝え、画像のIndexを切り替え、再表示タイミングでそのurlで画像を呼び出すとだいたいキャッシュされているのですぐに表示されるため、それでしのいでいます。
正直あんまりいいやり方ではないので、他にいいやり方があれば知りたいです。簡単でしょ?
簡単じゃなかっ……
前述のデベロッパーブログに乗っているソースコードを読みつつ、適宜いろんなブログを見つつしてなんとかわかった感じです。
でも、これを入れるだけでなんかちょっと今どきのアプリ感は出るかなーと思うので、ぜひやってみてください!
- 投稿日:2019-07-11T11:40:40+09:00
スマホのシェア率を見れるサイトのまとめ
スマホのシェア率なんてググればすぐ出てくるだろーって思ったら意外と時間かかったのでまとめました。
特にandroidの機種ごとのシェア率は全然見つからないですね…
サイト名 OS カテゴリ 集計期間 対象 集計方法 apple iOS バージョン 1日? 世界 App Store(アクセス解析?) スマタブinfo iOS/android バージョン 直近3ヶ月? 日本 独自調査 DeviceAtlas iPhone+android 機種 四半期 国別 提携サイトのアクセス解析 statista 記事により異なる android android バージョン 1週間 世界 Google Play ストアのアクセス解析 statcounter iOS/android バージョン/メーカー 最小で日単位 世界/国別 提携サイトのアクセス解析 webrage iPhone+android 機種 1ヶ月? 日本 アクセス解析 BCN+R android メーカー 半期 日本 販売台数 BCN+R iPhone+android 機種 1ヶ月 日本 販売台数 apple
https://developer.apple.com/support/app-store/
シンプルな円グラフでわかりやすいです。スマタブinfo
http://smatabinfo.jp/os/android/index.html
iOSはバージョンごと、androidはAPKレベルごとに見れます。
また実測値は見れませんが、androidの機種ごとのシェアが5段階のランクで見れるのがいいですね。DeviceAtlas
https://deviceatlas.com/blog/most-popular-smartphones#japan
OS関係なく全機種のシェア率の上位12機種が見れます。
日本はiphoneのシェア率が高いので実質ihponeの機種ごとのランキングになってます。statista
https://www.statista.com/search/?q=share&category=418&subCategory=481
ほとんどの記事が有料会員専用なのであまり使えないかもしれません…
集計方法は記事によって異なります。android
https://developer.android.com/about/dashboards/index.html
集計期間が2018/10/20~2018/10/26とちょっと古いです。
他に画面サイズと密度ごとのシェア率も見れます。statcounter
http://gs.statcounter.com/
一番情報量が多く使い勝手がいいサイトでした。
OSごと、バージョンごと、などなどたくさんの統計を2009年1月から最小は日単位で見ることができます。
元となるデータも200万サイト月間100億PVと申し分ないです。webrage
https://webrage.jp/techblog/sp_share/
日本でのシェア率ランキングです。
iPhoneはiphoneで一括りにされてます。BCN+R
https://www.bcnretail.com/market/contents_type=49
androidのシェア率を全国の主要家電量販店・ネットショップのPOSデータから集計しています。
アクセス解析ではなく販売台数なので注意。
目当ての記事探すのがちょっと大変かも。
- 投稿日:2019-07-11T11:16:41+09:00
Kotlin のプロジェクトでもライブラリが Java8 に依存していれば compileOptions の指定が必要
結論
Kotlin だけで書いてる Android のプロジェクトで Java8 が使われているライブラリを使用する場合でも、compileOptions が必要
(Kotlin だけ使ってるプロジェクトだと意識しないから忘れがち)compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 }今回の現象との遭遇
material-components 1.1.0-alpha08 が出たので Kotlin だけで書いてるプロジェクトで使おうとしたら、以下の現象に遭遇しました。
- 実機デバッグの時にビルドは通るが layout の inflate でクラッシュしている
- assembleDebug をするとエラーが出る
Execution failed for task ':app:mergeExtDexDebug'. > Could not resolve all files for configuration ':app:debugRuntimeClasspath'. > Failed to transform artifact 'material.aar (com.google.android.material:material:1.1.0-alpha08)' to match attributes {artifactType=android-dex, dexing-enable-desugaring=false, dexing-is-debuggable=true, dexing-min-sdk=21}.よく見たら Java8 に依存してるて書いてるからもしかしてと思ったらそうだった
- 投稿日:2019-07-11T08:15:27+09:00
Windows Subsytem on Linux で OpenSTF (Smartphone Test Farm) を動かす
はじめに
OpenSTF (Smartphone Test Farm) とは
https://openstf.io/
スマートフォンやタブレットを集中管理し、ブラウザから遠隔操作できるようにするオープンソースソフトウェア。
エミュレータとは違い、物理端末のスクリーンキャプチャを転送する仕組みなので動作を正確に確認できるのが特長です。
スマホアプリやモバイル向けWebページを制作する人の味方。
動かすのに結構苦労したので、誰かの助けになればと思い記事にしていきます。試した環境
- Windows 10 Home 1903
- Linux には Ubuntu 18.04.2 LTS (Bionic Beaver) を使用
Windows Subsystem on Linux (Ubuntu) の インストール
特にこだわりはなかったので STF の記事が多かった Ubuntu を選択しました。
Windows の機能「Windows Subsystem for Linux」の有効化をして
Microsoft Store から Ubuntu を探してインストールすればOK。
(バージョンの記載が無いものを選んだら 18.04 が入りました)
バージョンの確認は
cat /etc/os-release
でできるみたいです。コピーした状態から右クリックでペーストできます。
RethinkDB のインストール
STF ではデータベースとして RethinkDB を使用するので、先に RethinkDB を入れます。
Linux 上にインストールする方法もあるのですが Linux がわからなすぎてハマりました。
RethinkDB は Windows 上でも動くので、Linux に不慣れな方は Windows 上にインストールするのをお勧めします。
https://www.rethinkdb.com/docs/install/windows/
からダウンロードしてきて
任意のフォルダに展開し、rethinkdb.exe を起動するだけです。
(exeファイルをダブルクリックでも、コマンドプロンプトから実行でもOKです)
このように表示されれば起動中です。
http://localhost:8080 にアクセスすれば RethinkDBが動いているのを確認できると思います。
Tables や Indexes が 0 でないのは STF をインストール後にスクリーンキャプチャしたためです。
手順通り進めた場合、この段階では 0 で大丈夫です。
rethinkdb がエラーになる/ページがエラーになる場合は?
RethinkDB はポート 8080 を使用します。
他で使用していないか確認し、ある場合は他の設定を解除してから試してみてください
(色々入れてる環境で起きがち…)STF に必要な他のアプリと、STF 本体のインストールする
RethinkDB 以外にもいくつかアプリが必要です。
これらは Linux 上にインストールしていきましょう。こちらのお二方の記事を参考に進めました。
http://yakisaba.hatenablog.jp/entry/2018/07/26/103620
https://qiita.com/tanaka512/items/4792931fe08b08441dc7以下全部コピーして貼り付ければOK
Ubuntusudo apt-get update sudo apt-get install git sudo apt-get install npm sudo apt-get install android-tools-adb sudo apt-get install python sudo apt-get install autoconf sudo apt-get install automake sudo apt-get install libtool sudo apt-get install build-essential sudo apt-get install ninja-build sudo apt-get install libzmq3-dev sudo apt-get install libprotobuf-dev sudo apt-get install graphicsmagick sudo apt-get install yasm sudo apt-get install stow #nodejs curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - sudo apt-get install -y nodejs sudo npm install -g bower karma gulp mkdir ~/Downloads #ZeroMQ cd ~/Downloads wget http://download.zeromq.org/zeromq-4.1.2.tar.gz tar -zxvf zeromq-4.1.2.tar.gz cd zeromq-4.1.2 ./configure --without-libsodium --prefix=/usr/local/stow/zeromq-4.1.2 make sudo make install cd /usr/local/stow sudo stow -vv zeromq-4.1.2 #Google protobuf cd ~/Downloads git clone https://github.com/google/protobuf.git cd protobuf ./autogen.sh ./configure --prefix=/usr/local/stow/protobuf-`git rev-parse --short HEAD` make sudo make install cd /usr/local/stow sudo stow -vv protobuf-* sudo ldconfig #OpenSTF cd mkdir openstf cd openstf/ git clone https://github.com/openstf/stf.git cd stf sudo npm install -g stf --unsafe-permSTF の実行
さきほど書いた手順で RethinkDB を起動しておきます。
そのうえで Ubuntu上 でstf local
を実行します。(どの階層で実行してもOK)
下のような実行結果になるはず。http://localhost:7100
にアクセスして次のページが表示されれば STF の起動は成功です。STF 上で端末を操作する
端末が認識されない場合
基本的なところの確認はこちらのページがとても詳しくてわかりやすいです。
[Android] デバッグモードで接続した端末がadb devicesで認識されない場合の対処法Windows Subsystem in Linux 特有の確認ポイント
Windows と Ubuntu で同じバージョンの adb を起動する必要があります。
Ubuntu 上の adb のバージョンはadb --version
で確認できます。上の画面だと、1.0.39 です。
このバージョンと同じ adb を探します。
一覧のページが全く見つけられなかったのですが URL でバージョンを直接指定する方法で乗り切れます。例えば
http://dl.google.com/android/repository/platform-tools_r23.0.1-windows.zip
→ 1.0.41
http://dl.google.com/android/repository/platform-tools_r21.0.1-windows.zip
→ 1.0.39ダウンロードできたら解凍してインストールしてください。
インストールできたら、PowerShell でadb start-server
します。うまくいかないときは、
kill-server
をしてからstart-server
を試してみてください。
また、この操作をすると Linux 上で STF が終了するので、再度stf local
を実行して起動しなおしてください。うまくいけば、STF 上に端末が表示されるはずです。
以上です。おつかれさまでした!
- 投稿日:2019-07-11T08:15:27+09:00
Windows Subsystem on Linux で OpenSTF (Smartphone Test Farm) を動かす
はじめに
OpenSTF (Smartphone Test Farm) とは
https://openstf.io/
スマートフォンやタブレットを集中管理し、ブラウザから遠隔操作できるようにするオープンソースソフトウェア。
エミュレータとは違い、物理端末のスクリーンキャプチャを転送する仕組みなので動作を正確に確認できるのが特長です。
スマホアプリやモバイル向けWebページを制作する人の味方。
動かすのに結構苦労したので、誰かの助けになればと思い記事にしていきます。試した環境
- Windows 10 Home 1903
- Linux には Ubuntu 18.04.2 LTS (Bionic Beaver) を使用
Windows Subsystem on Linux (Ubuntu) の インストール
特にこだわりはなかったので STF の記事が多かった Ubuntu を選択しました。
Windows の機能「Windows Subsystem for Linux」の有効化をして
Microsoft Store から Ubuntu を探してインストールすればOK。
(バージョンの記載が無いものを選んだら 18.04 が入りました)
バージョンの確認は
cat /etc/os-release
でできるみたいです。コピーした状態から右クリックでペーストできます。
RethinkDB のインストール
STF ではデータベースとして RethinkDB を使用するので、先に RethinkDB を入れます。
Linux 上にインストールする方法もあるのですが Linux がわからなすぎてハマりました。
RethinkDB は Windows 上でも動くので、Linux に不慣れな方は Windows 上にインストールするのをお勧めします。
https://www.rethinkdb.com/docs/install/windows/
からダウンロードしてきて
任意のフォルダに展開し、rethinkdb.exe を起動するだけです。
(exeファイルをダブルクリックでも、コマンドプロンプトから実行でもOKです)
このように表示されれば起動中です。
http://localhost:8080 にアクセスすれば RethinkDBが動いているのを確認できると思います。
Tables や Indexes が 0 でないのは STF をインストール後にスクリーンキャプチャしたためです。
手順通り進めた場合、この段階では 0 で大丈夫です。
rethinkdb がエラーになる/ページがエラーになる場合は?
RethinkDB はポート 8080 を使用します。
他で使用していないか確認し、ある場合は他の設定を解除してから試してみてください
(色々入れてる環境で起きがち…)STF に必要な他のアプリと、STF 本体のインストールする
RethinkDB 以外にもいくつかアプリが必要です。
これらは Linux 上にインストールしていきましょう。こちらのお二方の記事を参考に進めました。
http://yakisaba.hatenablog.jp/entry/2018/07/26/103620
https://qiita.com/tanaka512/items/4792931fe08b08441dc7以下全部コピーして貼り付ければOK
Ubuntusudo apt-get update sudo apt-get install git sudo apt-get install npm sudo apt-get install android-tools-adb sudo apt-get install python sudo apt-get install autoconf sudo apt-get install automake sudo apt-get install libtool sudo apt-get install build-essential sudo apt-get install ninja-build sudo apt-get install libzmq3-dev sudo apt-get install libprotobuf-dev sudo apt-get install graphicsmagick sudo apt-get install yasm sudo apt-get install stow #nodejs curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - sudo apt-get install -y nodejs sudo npm install -g bower karma gulp mkdir ~/Downloads #ZeroMQ cd ~/Downloads wget http://download.zeromq.org/zeromq-4.1.2.tar.gz tar -zxvf zeromq-4.1.2.tar.gz cd zeromq-4.1.2 ./configure --without-libsodium --prefix=/usr/local/stow/zeromq-4.1.2 make sudo make install cd /usr/local/stow sudo stow -vv zeromq-4.1.2 #Google protobuf cd ~/Downloads git clone https://github.com/google/protobuf.git cd protobuf ./autogen.sh ./configure --prefix=/usr/local/stow/protobuf-`git rev-parse --short HEAD` make sudo make install cd /usr/local/stow sudo stow -vv protobuf-* sudo ldconfig #OpenSTF cd mkdir openstf cd openstf/ git clone https://github.com/openstf/stf.git cd stf sudo npm install -g stf --unsafe-permSTF の実行
さきほど書いた手順で RethinkDB を起動しておきます。
そのうえで Ubuntu上 でstf local
を実行します。(どの階層で実行してもOK)
下のような実行結果になるはず。http://localhost:7100
にアクセスして次のページが表示されれば STF の起動は成功です。STF 上で端末を操作する
端末が認識されない場合
基本的なところの確認はこちらのページがとても詳しくてわかりやすいです。
[Android] デバッグモードで接続した端末がadb devicesで認識されない場合の対処法Windows Subsystem in Linux 特有の確認ポイント
Windows と Ubuntu で同じバージョンの adb を起動する必要があります。
Ubuntu 上の adb のバージョンはadb --version
で確認できます。上の画面だと、1.0.39 です。
このバージョンと同じ adb を探します。
一覧のページが全く見つけられなかったのですが URL でバージョンを直接指定する方法で乗り切れます。例えば
http://dl.google.com/android/repository/platform-tools_r23.0.1-windows.zip
→ 1.0.41
http://dl.google.com/android/repository/platform-tools_r21.0.1-windows.zip
→ 1.0.39ダウンロードできたら解凍してインストールしてください。
インストールできたら、PowerShell でadb start-server
します。うまくいかないときは、
kill-server
をしてからstart-server
を試してみてください。
また、この操作をすると Linux 上で STF が終了するので、再度stf local
を実行して起動しなおしてください。うまくいけば、STF 上に端末が表示されるはずです。
以上です。おつかれさまでした!
- 投稿日:2019-07-11T08:15:27+09:00
Windows Subsystem for Linux で OpenSTF (Smartphone Test Farm) を動かす
はじめに
OpenSTF (Smartphone Test Farm) とは
https://openstf.io/
スマートフォンやタブレットを集中管理し、ブラウザから遠隔操作できるようにするオープンソースソフトウェア。
エミュレータとは違い、物理端末のスクリーンキャプチャを転送する仕組みなので動作を正確に確認できるのが特長です。
スマホアプリやモバイル向けWebページを制作する人の味方。
動かすのに結構苦労したので、誰かの助けになればと思い記事にしていきます。試した環境
- Windows 10 Home 1903
- Linux には Ubuntu 18.04.2 LTS (Bionic Beaver) を使用
Windows Subsystem for Linux (Ubuntu) の インストール
特にこだわりはなかったので STF の記事が多かった Ubuntu を選択しました。
Windows の機能「Windows Subsystem for Linux」の有効化をして
Microsoft Store から Ubuntu を探してインストールすればOK。
(バージョンの記載が無いものを選んだら 18.04 が入りました)
バージョンの確認は
cat /etc/os-release
でできます。
Ubuntu への貼り付けは右クリックでできます。
RethinkDB のインストール
STF ではデータベースとして RethinkDB を使用するので、先に RethinkDB を入れます。
Linux 上にインストールする方法もあるのですが Linux がわからなすぎてハマりました。
RethinkDB は Windows 上でも動くので、Linux に不慣れな方は Windows 上にインストールするのをお勧めします。
https://www.rethinkdb.com/docs/install/windows/
からダウンロードしてきて
任意のフォルダに展開し、rethinkdb.exe を起動するだけです。
(exeファイルをダブルクリックでも、コマンドプロンプトから実行でもOKです)
このように表示されれば起動中です。
http://localhost:8080 にアクセスすれば RethinkDBが動いているのを確認できると思います。
Tables や Indexes が 0 でないのは STF をインストール後にスクリーンキャプチャしたためです。
手順通り進めた場合、この段階では 0 で大丈夫です。
rethinkdb がエラーになる/ページがエラーになる場合は?
RethinkDB はポート 8080 を使用します。
他で使用していないか確認し、ある場合は他の設定を解除してから試してみてください
(色々入れてる環境で起きがち…)STF に必要な他のアプリと、STF 本体のインストールする
RethinkDB 以外にもいくつかアプリが必要です。
これらは Linux 上にインストールしていきましょう。こちらのお二方の記事を参考にて進めました。
http://yakisaba.hatenablog.jp/entry/2018/07/26/103620
https://qiita.com/tanaka512/items/4792931fe08b08441dc7以下全部 Linux にコピーして貼り付けて実行、を繰り返せばOK
sudo apt-get updatesudo apt-get -y install npmsudo apt-get -y install git android-tools-adb python autoconf automake libtool build-essential ninja-build libzmq3-dev libprotobuf-dev graphicsmagick yasm stow#警告が出るが気にしない sudo npm install -y -g bower karma gulp#ZeroMQ mkdir ~/Downloads cd ~/Downloads wget http://download.zeromq.org/zeromq-4.1.2.tar.gz tar -zxvf zeromq-4.1.2.tar.gz cd zeromq-4.1.2 ./configure --without-libsodium --prefix=/usr/local/stow/zeromq-4.1.2 make sudo make install cd /usr/local/stow sudo stow -vv zeromq-4.1.2#Google protobuf 10分程度かかる cd ~/Downloads git clone https://github.com/google/protobuf.git cd protobuf ./autogen.sh ./configure --prefix=/usr/local/stow/protobuf-`git rev-parse --short HEAD` make sudo make install cd /usr/local/stow sudo stow -vv protobuf-* sudo ldconfig#OpenSTF cd mkdir openstf cd openstf/ git clone https://github.com/openstf/stf.git cd stf sudo npm install -g stf --unsafe-permSTF の実行
さきほど書いた手順で RethinkDB を起動しておきます。
そのうえで Ubuntu上 でstf local
を実行します。(どの階層で実行してもOK)
下のような実行結果になるはず。http://localhost:7100
にアクセスして次のページが表示されれば STF の起動は成功です。※最初に表示されるログイン画面はただのモックなので何をいれても進めます。
STF 上で端末を操作する
端末が認識されない場合
基本的なところの確認はこちらのページがとても詳しくてわかりやすいです。
[Android] デバッグモードで接続した端末がadb devicesで認識されない場合の対処法Windows Subsystem in Linux 特有の確認ポイント
Windows と Ubuntu で同じバージョンの adb を起動する必要があります。
Ubuntu 上の adb のバージョンはadb --version
で確認できます。上の画面だと、1.0.39 です。
このバージョンと同じ adb を探します。
一覧のページが全く見つけられなかったのですが URL でバージョンを直接指定する方法で乗り切れます。例えば
http://dl.google.com/android/repository/platform-tools_r23.0.1-windows.zip
→ 1.0.41
http://dl.google.com/android/repository/platform-tools_r21.0.1-windows.zip
→ 1.0.39ダウンロードできたら解凍してインストールしてください。
インストールできたら、PowerShell でadb start-server
します。うまくいかないときは、
kill-server
をしてからstart-server
を試してみてください。
また、この操作をすると Linux 上で STF が終了するので、再度stf local
を実行して起動しなおしてください。うまくいけば、STF 上に端末が表示されるはずです。
以上です。おつかれさまでした!
- 投稿日:2019-07-11T01:05:28+09:00
スライム絵文字をTextViewに設定したい!
こんばんは。
突然ですが、スライム絵文字って知ってますか?
海をわたるとBlob Emojiとか呼ばれてるやつです。Android 7まで採用されてた黄色のかわいい絵文字のことです。
丸いやつじゃないです。実装方法とか
- NotoColorEmoji.ttf(Blobmoji.ttf)をTextViewに設定する。
- 今回はこの方法を使う。
- https://github.com/C1710/blobmoji/releases から
- C1710/FilemojiCompat つかう
- EmojiCompatに対応したttfファイルを読み込める。簡単?
- TypeFaceを設定していても使える?←つおい
NotoColorEmojiをただ設定すればいいわけじゃない。
まずサンプルコードです。
予めダウンロードしといてね→https://github.com/C1710/blobmoji/releases
MainActivity.ktはカットで。
やってることはTextViewをおいてfontFamilyにスライム絵文字のフォントファイルを指定しているだけです。<TextView android:layout_width="wrap_content" android:textSize="30sp" android:layout_height="wrap_content" android:padding="10dp" android:text="123456789\nあいうえお\n??????"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="123456789\nあいうえお\n??????" android:textSize="30sp" android:padding="10dp" android:fontFamily="@font/no_number_blobmoji" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" android:id="@+id/textview"/>どこにフォントファイル置くのかって話ですが、
res
の中にfont
を作って中に入れればいいです。
大文字は使えませんので気をつけて。
何が起きたか
なぜか数字まで絵文字で表示されてしまったので、(数字の絵文字が白色なので背景と同化して)見えなくなりました。
数字までが絵文字になっているのです。絵文字だけでいいのに。直す
fonttools/fonttoolsを使います。
Pythonのセットアップは省きます。Pythonなんて触ったこと無いのでインストールする
pip install fonttools
数字だけ消す?
Issueありました。
https://github.com/googlefonts/noto-emoji/issues/218この手順をたどってスライム絵文字を使えるようにしましょう。
手順
1.適当にディレクトリ(フォルダ)作成。今回はfontsってフォルダをデスクトップに置くことにします。
2.そこにBlobmoji.ttfを入れます。名前を変えて最初の文字を小文字に変えときましょう。
3.さらにテキストファイルを作ってください。名前は
codes-no-numbers.txt
で行きましょう。4.そのテキストファイルに以下のサイトの内容を入れてください。
U+00000からU+FE837まで
https://gist.github.com/MKuranowski/bdbdfb96cf87f6302cd43860aa3471635.PowerShell(じゃなくてもいいけど)を開いて以下の通りに入力してください。
fonttoolsがちゃんと入ってれば完了するはずです。pyftsubset blobmoji.ttf --output-file=no_number_blobmoji.ttf --unicodes-file=codes-no-numbers.txt
6.完成です
これをfontディレクトリに入れてfontFamilyに指定してあげればいいはずです。
完成
←かわいいいいいいいいいいいいいいい
私はAndroid 7時代のが使えて満足です。
便利な使い方とか
GalaxyとかHTCとかASUSとかのAndroid端末は標準でフォント差し替え機能があります。
直接ttfファイルを入れるのではなく、FlipFont Manager
を使うことで利用できます。
AOSPで実装してほしい。Root化は流石に、、お疲れ様です
ありがとうございました。端折りすぎてよくわからんなこれ。
本当は好きなフォントと結合して使いたかったんですが、流石にできないっぽいかな。
お金かかるのでなしです(2回目参考ページ
https://github.com/fonttools/fonttools
https://github.com/C1710/blobmoji/releases
https://github.com/googlefonts/noto-emoji/issues/218
https://gist.github.com/MKuranowski/bdbdfb96cf87f6302cd43860aa347163おまけ
Android 10 ってIMEI取れない?
https://developer.android.com/preview/privacy/data-identifiers?hl=ja