20210228のAndroidに関する記事は7件です。

【Android】【初心者向け】RoomのAutoIncrement(PrimaryKeyのautogenerate = true)の値は、0で良い

【Android】【初心者向け】 RoomのAutoIncrement(PrimaryKeyのautogenerate = true)の値は、0で良い

概要

タイトル通りですが、AndroidのRoomのAutoincrement(PrimaryKeyのautogenerate = true)の値は、0で良いという話です。

今まで、業務でRoomを使う経験がなく、 ドキュメントやサンプルコードを見ていて、
AutoIncrementのときに、何を渡せば良いのかわからず、どこかで見たサンプルと同じように0を渡しすようにしていました。
ただふとこれで正しいのかと気になり、調べてみて良かったということに気づいたという話です。

参考にしたもの

developers: Primarykey

以下は、引用です。

autoGenerate

public boolean autoGenerate ()
Set to true to let SQLite generate the unique id.

When set to true, the SQLite type affinity for the field should be INTEGER.

If the field type is long or int (or its TypeConverter converts it to a long or int), Insert methods treat 0 as not-set while inserting the item.

If the field's type is Integer or Long (or its TypeConverter converts it to an Integer or a Long), Insert methods treat null as not-set while inserting the item.

つまり、以下のような内容かと思います。

  • autoGenerateをtrueにすると、SQLiteがユニークなIDを生成するよ
  • 型が longintのときは、insertのメソッドは、0を未設定として扱うよ
  • 型が、LongIntegerのときは、insertのメソッドは、nullを未設定として扱うよ

そして、基本的にはkotlinのintを使うかと思いますので、0を設定してあげるのが良いということになるかと思います。

コード的なイメージ

仮にUserというEntityを使う場合ですが、以下のようになるのかと思います。

UserEntity.kt
@Entity(tableName = "users")
data class User(
  // デフォルト引数に0を設定
  @PrimaryKey(autoGenerate = true) val id: Int = 0,
  @ColumnInfo(name ="name") val name: String
)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Android/Kotlin] Android Studioで JSON Kotlin Class 簡単に作ってみた。

JSONデータをKotlin classに変更するため
json to kotlin classというプラグインをインストールする。

Android Studioのpluginsで
json to kotlin class を打つと下記のようにプラグインが出ます。

スクリーンショット 2021-02-28 17.13.43.png

インストールるしてIDEを再実行する。

スクリーンショット 2021-02-28 17.19.13.png

new -> Kotlin data class File from JSON 又は

JSON データをコピーして Command + N を打つと

スクリーンショット 2021-02-28 17.20.25.png

上記のように出ます。

Kotlin data classes from JSONを押下した場合は

スクリーンショット 2021-02-28 17.38.39.png

JSON形式を書ける画面とグラス名を書ける画面がです。

入力して Generateを押下すると入力したJSON値を用いて下記のようにデータクラスを生成してくれる。

スクリーンショット 2021-02-28 17.39.32.png
スクリーンショット 2021-02-28 17.39.36.png

API通信などで Jsonをクラスを簡単に作って活用してみましょう!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

エミュレータをIDE内に表示する

概要

Android 4.1 より、Android Studio の IDE 内にエミュレータを表示できるようになりました。
IDEの上にエミュレーターが重なって手動で移動させたり、アクティブにしたりなどの手間もなくなるので、ディスプレイのサイズが広い場合は、こちらが使いやすいかもしれません。

また、デフォルトでは無効となっているので、設定を調整する必要があります。

スクリーンショット 2021-02-28 14.00.57.png

必要環境

  • Android Studio 4.1 以降
  • Android Emulator の バージョン 30.0.10 以降

やり方

以下OS毎のメニュー箇所を参照に [Launch in a tool window] にチェックを入れてください。
次回エミュレーター起動時からIDE内に表示されるようになります。

mac

[Android Studio] > [Preferences] > [Tools] > [Emulator]
の項目を開いて、 [Launch in a tool window] にチェック

スクリーンショット 2021-02-28 13.58.39.png
スクリーンショット 2021-02-28 13.59.36.png

Windows

[File] > [Settings] > [Tools] > [Emulator]
の項目を開いて、 [Launch in a tool window] にチェック

エミュレーターのタブが自動的に表示されない場合

[View] > [Tool Windows] > [Emulator] で表示できます。
スクリーンショット 2021-02-28 14.09.45.png

公式情報

こちらの情報は公式ページよりご参照しました。
詳しくはこちらを参照ください。

■ Android Studio で Android Emulator を直接実行する

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android StudioでエミュレータをIDE内に表示する

概要

Android 4.1 より、Android Studio の IDE 内にエミュレータを表示できるようになりました。
IDEの上にエミュレーターが重なって手動で移動させたり、アクティブにしたりなどの手間もなくなるので、ディスプレイのサイズが広い場合は、こちらが使いやすいかもしれません。

また、デフォルトでは無効となっているので、設定を調整する必要があります。

スクリーンショット 2021-02-28 14.00.57.png

必要環境

  • Android Studio 4.1 以降
  • Android Emulator の バージョン 30.0.10 以降

やり方

以下OS毎のメニュー箇所を参照に [Launch in a tool window] にチェックを入れてください。
次回エミュレーター起動時からIDE内に表示されるようになります。

mac

[Android Studio] > [Preferences] > [Tools] > [Emulator]
の項目を開いて、 [Launch in a tool window] にチェック

スクリーンショット 2021-02-28 13.58.39.png
スクリーンショット 2021-02-28 13.59.36.png

Windows

[File] > [Settings] > [Tools] > [Emulator]
の項目を開いて、 [Launch in a tool window] にチェック

エミュレーターのタブが自動的に表示されない場合

[View] > [Tool Windows] > [Emulator] で表示できます。
スクリーンショット 2021-02-28 14.09.45.png

公式情報

こちらの情報は公式ページより参照しました。
詳しくはこちらをご覧ください。

■ Android Studio で Android Emulator を直接実行する

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Jetpack Compose の依存関係を alpha → beta にあげた時の setContent の Deprecated を解消する

はじめに

最近 Jetpack Compose が beta 版になったということで早速 Hello World してみたのですが、 元々 alpha 版で作っていたプロジェクトを beta 版にした途端、 setContent が参照できなくなってしまったのでその備忘録です。

結論

結論から書いてしまいます。
以下を追加すると setContent が参照できるようになります。

build.gradle
implementation 'androidx.activity:activity-compose:1.3.0-alpha03'

androidx.compose.ui.platform.setContent から androidx.activity.compose.setContent に変更されていたために参照できなかったようです。

最後に

Android Developers は日本語にすると情報が古かったりするので、English でまずは読む癖をつけたいですねぇ。。

参考

Announcing Jetpack Compose Beta!

Add Jetpack Compose toolkit dependencies

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SharedPreferencesを自前で難読化するのはもう古い?これからはEncryptedSharedPrefenrecesを使おう

EncryptedSharedPreferencesとは

Android Developersのサイトにある通り、「SharedPreferencesのKeyとValueを暗号化する実装」を提供するものです。

Android Developers公式サイトより引用)

An implementation of SharedPreferences that encrypts keys and values.

今までのgetSharedPreferences()などで使用していたAPIの使い勝手はそのままに、暗号化する機能を提供してくれるので、手軽にセキュリティを高めることができます。

動作条件

・プロジェクトのminSdkVersionが23以上であること

これはandroidx.securityのライブラリのminSdkVersionが「23」に指定されているためです。
(APIレベル23未満では、EncryptedSharedPreferencesを使用するためのマスターキー情報がないので使用できない)

ライブラリの組み込み

build.gradleに以下のコードを追加します。
ライブラリのバージョンはその時の状況に応じて、適宜変更してください。

dependencies {
    implementation "androidx.security:security-crypto:1.1.0-alpha03"
 }

EncryptedSharedPreferencesを使ってみる

MainActivity.kt
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey

class MainActivity : AppCompatActivity() {
    companion object {
        const val PREF_NAME = "encrypted_prefs"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val mainKey = MasterKey.Builder(applicationContext)
                .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
                .build()

        val prefs = EncryptedSharedPreferences.create(
                applicationContext,
                PREF_NAME,
                mainKey,
                EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
                EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        )

        with (prefs.edit()) {
            putString("foo", "bar")
            apply()
        }

        val savedValue = prefs.getString("foo", "Nothing")
        Toast.makeText(this, """the saved value of the key "foo" is $savedValue""", Toast.LENGTH_LONG).show()
    }
}

上記のコードでアプリをビルドすると、EncryptedSharedPreferencesを使用して保存したデータ("bar"という文字列)がToastで表示されるはずです。
非常にお手軽に使えますね!

以下、上記のコードについて軽く触れておきます。

MasterKey

MasterKeyはandroidx.securityライブラリで使われるマスターキーをラップするクラスです。
このキー情報を使用して、EncryptedSharedPreferencesのKey/Valueの値を暗号化します。
また、このキーはAndroid KeyStoreに格納されるため安全に使用することができます。
以下のコードで、デフォルト設定のマスターキーを取得します。

 val mainKey = MasterKey.Builder(applicationContext)
                //master keyに使用するKeySchemeを指定. 本記事執筆時、AES256_GCMのみ定義されている
                .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
                .build()

※開発者自身で、鍵生成のパラメータを指定することができますが、上記の(デフォルト)設定の使用が推奨されているようです。

EncryptedSharedPreferences.create

以下のコードで、EncryptedSharedPreferencesインスタンスを生成することができます。

 val prefs = EncryptedSharedPreferences.create(
                applicationContext, 
                PREF_NAME, 
                mainKey, 
                EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
                EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        )

それぞれの引数について。

  • 第1引数 … Contextインスタンス。SharedPreferencesインスタンス生成のために使用
  • 第2引数 … 保存先のファイル名
  • 第3引数 … MasterKeyインスタンス
  • 第4引数 … keyを暗号化するために参照されるPrefKeyEncryptionScheme情報。本記事執筆時、AES256_SIVのみが定義されている
  • 第5引数 … valueを暗号化するために参照されるPrefValueEncryptionScheme情報。本記事執筆時、AES256_GCMのみが定義されている

保存されたデータを見てみよう

今回は保存するファイル名を「encrypted_prefs」としました。
/data/data/${アプリのパッケージ名}/shared_prefs/encrypted_prefs.xmlの中身を見てみましょう。
筆者の環境では以下のようになっていました。暗号化された文字列の値は環境により異なります。

encrypted_prefs.xml(EncryptedSharedPreferencesを使用した場合)
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="__androidx_security_crypto_encrypted_prefs_key_keyset__">12a9010d7073b7e3c32bd1ce2184835ef4b9582676b80a4a8158f4cff8f8f3f852cd3191216e3cbb97aaa6ade6e49f8f8e58570dcec6dda3144ec2abfbdca143553576c2e60f13f6398f496540421768693f3ea9f1be169983e03c37dec39f1302364b0f710dbdeaea5c495efb15f26e8aab33a0fb882a8ae0f500238206a78776479a08b78f45a766b3fe06c2047c0479c70715bb7e99989a4feef0d74223552b6e5c292a5c06532efd3a661a4408f3bfa1a006123c0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696e6b2e4165735369764b6579100118f3bfa1a0062001</string>
    <string name="__androidx_security_crypto_encrypted_prefs_value_keyset__">128601101a6c6904bfc93b66d78e2f65ad240a53a2d203536980b93d5f85b74e695b94ca27333264d4d42f3c69b4549a773a876c44c7afe99345402ab376dd896501b297f2e84c00fb1c9842e094dc77ac9012fb4e543a4180d991c80b01077e8483cc8e1097b35ec8f1a2e92e9557ccc4f1c60891a1549b0ae42a1bb4f1601346b377dda1087dc56f1a4208e580f910123b0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696e6b2e41657347636d4b6579100118e580f9102001</string>
    <string name="AWQIX/Ot9q4upiyy+U2fP4RhilkKf/vT">AQIeQGVdBmATM9ubBcCayGfwulNZzpZbQJdADMe97l6cNJJ1XrPjoHa4vP0=</string>
</map>

"foo"というKeyが"AWQIX/Ot9q4upiyy+U2fP4RhilkKf/vT"という文字列に、
"bar"というValueが"AQIeQGVdBmATM9ubBcCayGfwulNZzpZbQJdADMe97l6cNJJ1XrPjoHa4vP0="という文字列に暗号化されています。
ユーザーにとって意味不明な文字列になっていますね。アプリの秘匿情報を使うのが楽になりました!

"__androidx_security_crypto_encrypted_prefs_key_keyset__"と"__androidx_security_crypto_encrypted_prefs_value_keyset__"は、それぞれKeyとValueの暗号化に使用するkeyset情報で、自動的に保存される情報のようです。

※ちなみに、EncryptedSharedPreferencesではなく、getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)を使ってデータを保存した場合は、以下のようになります。

encrypted_prefs.xml(getSharedPreferencesを使用した場合)
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="foo">bar</string>
</map>

補足

プロジェクトのminSdkVersionが23未満の場合

プロジェクトのminSdkVersionが23未満の時は、以下の修正を加えればビルド自体はできます。
 ・AndroidManifest.xmlにoverrideLibraryの設定を追加

AndroidManifes.xml
<!--以下のコードを追加-->
 <uses-sdk tools:overrideLibrary="androidx.security"/>

 ・端末のOSバージョンによって処理を分岐

if (Build.VERSION.SDK_INT >= 23) {
  APIレベルが23以上の時のみ、処理を実施
}

※ただし、後述のように、このような実装を行うメリットはあまりないでしょう。

最後に

  • EncryptedSharedPreferencesは、今までのgetSharedPreferences()による共有設定の編集と同じようなAPIで、KeyValuePairデータを端末に安全に保存できる

  • プロジェクトのminSdkVersionが23以上の新規開発では、getSharedPreferences()ではなく、EncryptedSharedPreferencesの使用を積極的に検討しよう

  • プロジェクトのminSdkVersionを23以上にあげられない場合、素直に既存のSharedPreferencesを使い回す(必要に応じて、KeyやValueを自前で暗号化)なり、他の暗号化ライブラリの使用を検討した方が良いでしょう。
    => SharedPreferencesを使って保存される情報の暗号化有無がOSバージョンによって変わるのは好ましくない。暗号化するなら、全ての端末を対象とするのが基本。また、OSバージョンにより暗号化の実装を変えるのは無駄に複雑。

  • すでにリリースされているアプリで、EncryptedSharedPreferences以外によるデータ保存処理を行なっている場合、EncryptedSharedPreferencesに移行すべきかどうかは、アプリの特性やプロジェクトの状況に応じて様々なので、それぞれで考えよう

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NFCタグ×MacroDroid×Switch Botで機器を制御

はじめに

日頃よくSwitch Botを使用して快適に機器の制御をしています。
Switch BotはHubを使用することで、音声インターフェースなどと組み合わせて使用することも多いと思いますが、私はあまり好きではないのでアプリから制御をしています。
ただ、その方法だとまずアプリを毎回開く必要があります。加えて、一定期間でアプリとサーバとのセッションが切れるため、ログインをし直す必要があります。TV、エアコン、照明のON/OFFなどの頻繁に行う制御だと少々使いにくいところがありました。
そこでNFCタグで制御する方法があることを知ったので、試してみることにしました。

使用したもの

  • Switch Bot機器,Hub
  • IFTTT
  • NFC Tools
  • MacroDroid
  • Android スマホ端末
  • NFCタグ

試したこと

まずiPhoneユーザの方であればショートカットがあるのでそちらでレシピを作成すればすぐにできるらしいのですが、Androidではそれができず、別の手段で設定しなければなりません。。
そんなのIFTTTでいいじゃないかと思われた方もいらっしゃると思います。実際、YouTubeにIFTTTを使用して、Android端末でNFCタグからSwitch Botを制御している動画がありそれを参考に試してみました。

試した手順は以下です
1. IFTTのif thisの部分にwebhooksでリクエストのevent nameを設定する
2. then thatの部分でSwitch Botを選択し、turn on(off)application with Hub IR remoteというを選択
3. Hubに登録している機器名がプルダウンメニューに表示されるので、対象機器を選択する
4. finishで作成終了
5. Exploreからwebhooksを選択し、documentationを選択
6. request urlの設定画面に遷移するので、urlの{event}のところをタップし、先ほど作成したevent nameを入力する
7. 画面下にcurlが表示されるのでそのurl部分をコピー
8. NFC Toolsを開き、「書く」→「レコードを追加」→「カスタム URL/URI」を選択
9. URL入力画面に遷移するので、コピーしたURLを張り付ける
10. 「書く」→「書く」を選択すると、NFCタグにアクセスするので、NFCタグに登録する

上記の方法で実際に登録し、試してみました。
試してみて感じたことは、正直使いにくいなということでした。
webhookを使用して制御するという方法で試したのですが、
NFCにかざしたときにブラウザが起動してしまいます。制御するたびにいちいち新しいタブでブラウザが起動されては、制御する気が失せてしまいかねません。
また、無料版だとレシピが3つまでしか作成できないので、そこも個人的にネックでした。
私自身あまりIFTTTを使い慣れていないので他にやり方があったかもしれませんが、もうシェルスクリプトとかでSwitch BotのAPIをたたいて直接制御したらいいんじゃね?と思ったのでその方法で試してみることにしました。
いろいろ模索したところ、MacroDroidというアプリがあるということを知りました。
簡単に説明すると、内容としてはIFTTTのようなもので、トリガーとアクション(と条件)を設定してマクロを作成して、トリガー発生時にアクションを実行してくれるというものです。

MacroDroidについて

個人的には、IFTTTは用意されている別のアプリなどの設定がしやすいイメージがあります。実際Switch Botもif this,then thatの設定にデフォルトで用意されているため、そういったアプリと紐づけたりする際に、あまり慣れていない人でも操作しやすいのが特徴なのかなというイメージがあります。(正直全然使っていないのでイメージです。。)
MacroDroidはIFTTTみたいに連携するアプリが設定しやすいように用意されているということはなく、自分でロジックを組むことになります。Android端末の細かいトリガーやアクションが設定できるため、自由度が高く、自分で細かいことまで設定したいという方には向いているのかなという気がしました。
テンプレートといって、他の方が作成したマクロが、新着、高評価、最新順などになってみることができるので、気になった方はそういうのも参考にして使ってみてもいいと思います。ちなみにIFTTTは無料版だと3つまでしか作成できないと述べましたが、MacroDroidも無料版だと5つまでという制限があります。
ついハマってしまい課金をしてしまったので、さっきのIFTTTは無料版だと~というのが説得力がなくなってしまいますが、無料版でも十分価値はあると思います。また、課金する場合は500円一回きり払えば作成できるマクロが無制限になります。

設定方法

機器制御の流れ
機器制御の流れ

まず、Switch BotのAPIから仕様を確認する必要があります。
https://github.com/OpenWonderLabs/SwitchBotAPI

APIを使用するにはSwitch Botのアプリからオープントークンを取得する必要があります。
オープントークンの取得方法は「プロフィール」→「設定」を開き、「アプリバージョン」を10回タップすると、「開発者向けオプション」が画面に表示され、その画面でオープントークンを取得できます。
私はSwitch Botのアプリでシーンを作成して、そのシーンをPOSTするという方法で制御しました。その際は、アクション条件を手動実行にして登録します。
また、シーンを使用して制御する方法ではシーンIDがリクエストに必要になるので、シーンIDを取得します。

シーンIDを取得

まず、コマンドプロンプトでシーン一覧を取得します。
取得したオープントークンはリクエストヘッダーに挿入します。

curl -H "Authorization:{token}" -X GET https://api.switch-bot.com/v1.0/scenes
出力結果
{
"statusCode":100,
"body":[
    {"sceneId":"T01-202102211837-11256265","sceneName":"air conditioner on"}, 
    {"sceneId":"T01-202102211838-38812579","sceneName":"air conditioner off"}, 
    {"sceneId":"T01-202102211839-30390367","sceneName":"tv on off"}...
]

マクロの設定

シーンIDを取得したら、MacroDroidにシーンを制御するマクロを作成していきます。1
まず、「マクロを追加」からマクロを作成します。
トップ画面

作成画面からマクロ名の設定とトリガー、アクション、条件を設定します。
マクロ作成画面

まずトリガーの設定をしていきます。
「トリガー」→「機器のイベント」→「NFCタグ」→[NFCタグを新規作成]を選択し、OKを選択
NFCタグをかざすと登録が完了します。
トリガー作成画面

次にアクションの設定をします。
「アクションを追加画面」で「アプリ」から「シェルスクリプト」を選択
アクション作成画面

スクリプトの入力フォームにスクリプトを入力し(貼り付け)ます。
シェルスクリプト例

OKを押して、マクロを登録すれば完了です。「アクションを試す」を選択すると、シェルスクリプトが実行されるので、テストをすることもできます。

ちなみに、端末はルート化しなくても使用はできるので、非ルート化を選択します。基本端末のルート化はされてないと思うので、これだけの使用であれば、わざわざする必要もないと思います。
ただ、他のアクションでルート化のみ実行できるものもあるので、それらをされる場合はルート化が必要になります。
あと、URLの[v=token]や[v=scenes_ctl]についてですが、MacroDroidでは変数を設定できるため、複数回使いまわす値は変数にしています。トップ画面で設定できる変数とマクロの作成画面で設定できるローカル変数があります。私の場合は通常の変数にオープントークンとシーン制御の共通部分のURLを設定したため、画像のようなスクリプトになっています。ローカル変数の場合は[v=hoge]のところが[lv=hoge]になるらしいです。

おわりに

MacroDroidを使用して、NFCタグからSwitch Bot機器を制御する方法をご紹介しました。
IFTTTでの実行に比べると、自分で設定しなければならないことが多いため、若干の面倒くささは否めませんが、やっていること自体は複雑ではないのですぐにできると思います。
ちなみに、私はトリガーにNFC以外にウィジェットも設定しています。このように、MacroDroidは他にも端末を自由にカスタマイズできるので、Switch Botとの連携以外でも楽しめると思うので、今後もいろいろ試してみようと思います。


  1. 作成時のMacroDroidはv5.8.15です。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む