- 投稿日:2020-01-01T22:44:27+09:00
Dagger/MissingBindingエラー
以下のようなエラーが出た
エラー: [Dagger/MissingBinding] [dagger.android.AndroidInjector.inject(T)] jp.co.xxxxx.yyyy.data.repository.ZzzRepository cannot be provided without an @Provides-annotated method. public abstract interface AppComponent extends dagger.android.AndroidInjector<jp.co.xxxxx.yyyy.App> ・ ・ ・結論
対象repositryのBindsができていなかった。。。
@Module(includes = [DataSourceModule::class]) interface RepositoryModule { @Binds fun bindZzzRepository(repository: ZzzDataRepository): ZzzRepository }新たな画面を追加する際にrepositoryの追加も行う場合に、moduleに対しても色々と設定追加してやらないといけないのが漏れていた。Daggerの概念をちゃんと理解しつつ設定周りをちゃんと確認しないとですね。。
- 投稿日:2020-01-01T22:26:32+09:00
Androidアプリのインストール数をGCPに自動収集させる
はじめに
Androidアプリのインストール数をGCPのBigQueryに自動収集するようにしました。
これまで、Androidアプリのインストール数を確認するときは、Google Play Consoleを開き、アプリを選択し、レポートをcsv形式でダウンロードし、、、といった作業が必要でそれが面倒でした。
この面倒な作業をなくすために、Google Play から取得できるアプリのインストール数をGCPのBigQueryに毎日自動転送するよう設定した流れが以下の通りです。
GCPのBigQueryにデータを格納する
転送を選択して、+転送を作成ボタンを選択する
ソースタイプを選ぶところがあるので、「Google Play」 を選択します。
設定画面が表示されるので、項目を埋めていく
- 「転送項目名」と「スケジュールオプション」は、任意でokです。今回は、毎日繰り返すように設定しました。
- 「転送データの宛先」は、転送したいデータセットのIDを選択します。新しいデータセットに転送したい場合は、GCPのBigQueryのトップ画面に戻って、データセットの作成ボタンをタップして、作成してください。
- 「Cloud Storage bucket」 は、IDに基づく Google Cloud Storage のバケットパスを入れる必要があります。 このIDは、Google Play Console に接続して、「レポートをダウンロード」から対象アプリを選択するとレポートの最下部に "gs://pubsite_prod_rev_[ID]/reviews/" の記載があるのでこれを利用します。
以上で指定したデータセットにレポートのデータが格納されます!簡単だー!
格納されたデータを確認する
BigQueyの転送を選択した画面をみると、先ほど作成した転送項目名が表示されています。
転送項目名を選択すると、転送の詳細画面に遷移して、転送がスケジュール通りに実行されていることを確認できます。
BigQueryのトップ画面に戻り、先ほど選択した転送データの宛先を選択します。
すると、Installs_app_versionやInstalls_carrierなどたくさんデータが取得できていることが見てわかると思います。実は、今回転送設定したGoogle Play のレポートには、インストール数だけでなく、アンインストール数、クラッシュ、ANR、レビュー、などなど色々なデータも含まれているんです。今回のやり方で一緒に取得できているものは、こちらにまとまっています。
Google Play report transformation
それでは、クエリエディタで、今日のキャリアとアクティブデバイスインストールの数字を取得する以下のようなクエリを試しにたたいてみます。
SELECT Carrier, Active_Device_Installs, DATE ('2019-12-16') AS _LATEST_DATE, DATE (_PARTITIONTIME) AS _DATA_DATE FROM `449658023734.firebase_download.p_Installs_carrier_MT`そうすると、クエリ結果欄で以下のように結果が出ました。
無事にデータがBigQueryに転送されていることが確認できました
(SoftBankユーザー多いな~。とかわかりますね)
設定はたったこれだけで完了です。
これで、アプリのバージョンやOSによるインストール数、クラッシュ数など非常に色々な数字を毎日BigQueryに取得できるようになりました!おわりに
以上で、Androidアプリのインストール数の収集を、GCPのBigQueryに自動収集できるようになりました。
収集したデータの中から必要なインストール数とアンインストール数のみをスプレッドシートに出力したり、視覚的にもわかりやすいデータポータルにグラフとして出力したりすれば、常に自動更新された形いつでも見ることができるようになります。
スプレッドシートに出力するのも、データポータルに出力するのもとても簡単だったので、ぜひ試してみてください。
読んでいただきありがとうございました
参考
- 投稿日:2020-01-01T21:23:29+09:00
10年ぶりのAndroidアプリ開発 (1)開発環境準備編
はじめに
およそ10年ぶりにAndroidアプリを作ってみることにしたので、準備から(たどり着ければ)公開までを記事にしていきたいと思います。
私はAndroidのバージョンがまだ2の頃、少しだけアプリを作って遊んだことはありますが、その後はまったく触っていません。なので大まかなアプリの仕組みや開発の流れは分かっているつもりですが、Android Studioも触ったことがないし、Kotlinもまったく知りません。その他にも10年前と変わっていることはたくさんあると思いますので、そういった変化で戸惑ったところなど、紹介していければと思っています。環境
- ホストPC: Ubuntu 18.04.3 LTS
- Android Studio: 3.5.3 for Linux 64-bit
- デバッグに使うデバイス: 主にSHARP SH-M08 (Android 9)
Android Studioのインストール
Android Studioのインストールに従ってインストールします。ちゃんとLinux用の手順も書いてくれているのでありがたいです。Android Studioのバージョンは3.5.3でした。
まずはダウンロードページからダウンロードし、解凍した android-studio フォルダを /usr/local/ に置きます。
以下のコマンドで32bit用のライブラリをインストールします
$ sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386android-sudio/bin/ フォルダで
./studio.sh
を実行します。
ここで私の環境では下記のエラーが出ました。$ ./studio.sh # # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x00007f301898f3e6, pid=8378, tid=0x00007f2ffc2cc700 # # JRE version: OpenJDK Runtime Environment (8.0_202) (build 1.8.0_202-release-1483-b49-5587405) # Java VM: OpenJDK 64-Bit Server VM (25.202-b49-5587405 mixed mode linux-amd64 compressed oops) # Problematic frame: # V [libjvm.so+0x4b13e6] MarkFromRootsClosure::scanOopsInOop(HeapWord*)+0x1c6 # # Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again # # An error report file with more information is saved as: # /home/atsushi/java_error_in_STUDIO_8378.log # # If you would like to submit a bug report, please visit: # http://bugreport.java.com/bugreport/crash.jsp # Aborted (core dumped)とりあえず
apt upgrade
とapt update
して再チャレンジしたらインストールできました。ただ、一度失敗した影響か、ウィザードのステップが随分と省略されてしまっているような気がしました。たぶん、必要なら後からでも設定変更できると思うのでそのまま続行することにします。[Welcome to Android Studio] の画面右下の [Configure] の中の [Create Desktop Entry] を選択することにより、Ubuntuのアプリケーション一覧の中にAndroid Studioが表示されるようになります。
これでAndroid Studioのインストールは完了したっぽいです。
Hello World
Android Studioを起動し、[Start a new Android Studio project] を選択します。
最初なので、[Empty Activity] を選んでみます。
[Name] を "Hello" として、[Language] が "Kotlin" になっていることを確認して [Finish] します。
今回はHello World程度なのでどうでもよいですが、API levelのHelpを開くと、API LevelとAndroid versionとユーザー比率が表示されるの、よいですね。古いAndroid versionを切り捨てるかどうかの判断がやりやすそうです。
さて、Hello Worldアプリなので、適当にラベルを配置して"Hello World"とでも表示しようと思ってactivity_main.xmlを開いたらなんと!!すでにHello World!と書かれたラベルが配置されている!!!考えが読まれている(笑)。コーディング0行でアプリができてしまいました。
エミュレータで実行
せっかくなのでこのまま進めましょう。エミュレータで実行してみます。ツールバーの[No devices]をクリックし、Open AVD Managerを開きます。
"Q"の横の"Download"をクリックし、System Imageを入手します。ライセンスを読んで同意しましょう。ダウンロードとインストールにしばらくかかります。インストールが完了したら、改めて"Q"を選択して"Next"をクリックします。
あとからAVDを複数作ったときに見分けがつきやすいように、AVD Nameを適切につけておきます。もともと"Pixel 3a API 29"と入力されていたので、Android versionとの関係がわかりやすいように"(Q)"と付け加えました。
"Finish"をクリックすると"Android Virtual Device Manager"の画面に戻るので、先程追加したデバイスの三角ボタン(Launch)を押すと・・
"KVM is required to run this AVD"と怒られました。そういえばさっきからずっと、"/dev/kvm is not found"ってメッセージが出てましたね。
KVMの準備
KVMって何?って感じですが、Kernel-based Virtual Machine、つまりLinux Kernel自身が仮想OSを管理するハイパーバイザとして動作するものらしいです。詳しく調べていくとこれだけで記事がいくつも書けそうですが、今回はとりあえず動かすことを優先します。こことここが参考になりました。試行錯誤しながらやったので、不要な手順も含んでしまっているかもしれません。
まず、必要なパッケージをインストールし、ユーザーグループに追加します。
$ sudo apt install -y qemu-kvm libvirt0 libvirt-bin virt-manager libguestfs-tools $ sudo gpasswd libvirt -a [username] $ sudo reboot再起動のついでにBIOSに入り、Intel(R) Virtualization TechnologyとIntel(R) VT-d FeatureをEnableにします。
これで改めてAVDを起動してみると・・・
KVMに対してもユーザーの追加が必要なようです。ということで以下を実行。
$ sudo adduser [username] kvm $ sudo reboot三度目の正直!今度こそエミュレータが起動しました。10年前はエミュレータは遅すぎて実用にならなかったですけど、今は十分使えそうです。
エミュレータ起動したので、意気揚々とRunボタンをクリック! Hello Worldアプリが起動しました!
実機で実行
続いて実機でも動作を確認します。
Androidデバイス側で 設定 > システム > 端末情報 > ビルド番号 を連打すると、開発者向けオプションが有効になるので、設定 > システム > 開発者向けオプション > USBデバッグ をONします。このあたりは昔から変わりませんね。
USBケーブルでデバイスとPCを接続したところ、Android Studioのデバイス欄に "Unknown Device" と出ました。機種名が表示されないのが気になりますが、とりあえずRunしてみます。
案の定、怒られました。
01/01 19:23:46: Launching 'app' on Unknown Device. Installation did not succeed. The application could not be installed. Installation failed due to: 'insufficient permissions for device: user in plugdev group; are your udev rules wrong? See [http://developer.android.com/tools/device.html] for more information'メッセージに従い、http://developer.android.com/tools/device.html を確認すると、adbを入れろとのこと。そりゃそうか。
$ sudo apt install adb下記で、自分がplugdevグループに所属しているかどうかを確認。私の環境ではすでにグループに参加しているようでした。
$ groups [ユーザー名]デバイス側で「USBデバッグを許可しますか?」のメッセージが表示されるので、OKを押します。
すると、Android Studioのデバイス欄に "SHARP SH-M08" が表示されました。
まとめ
KVMを導入するところで若干苦労しましたが、それ以外は比較的スムーズに進めることができました。公式のドキュメントもしっかりしているので、この先の開発もやりやすそうな予感です。
2020年の元旦から引き籠もってしまいましたが、今年はたくさんソースコード書いてたくさんアプリ作って楽しめるといいなあと思います。
- 投稿日:2020-01-01T19:11:45+09:00
Realmのデータを確認するツール・ライブラリまとめ
Androidアプリの開発中、Realmに書き込んだデータを確認しようとしたのですが、
色々あってどれを使うかめちゃくちゃ迷ったので、調べたことをまとめておきます。
(間違いなどあればご指摘お願いします)Realm Studio
概要
- Realmが公式に提供している開発者ツール
- 公式サイト: https://realm.io/products/realm-studio/
Realm Database
とRealm Platform
を簡単に操作することができる- 2017年10月頃にリリースされた
- Mac, Windows, Linuxに対応している
使い方
adbコマンドを使って
.realm
ファイルを取り出し、アプリケーション上で開いてデータを確認する。所感
Realmが2017年以降力を入れて開発しているサービスっぽい。
できることの幅も広く、Realm Browserの昇華版と言えそう。Realm Browser
概要
- Realmが公式に提供している開発者ツール
- Mac App Store: https://apps.apple.com/app/realm-browser/id1007457278
.realm
データベースを閲覧、編集することができる- Mac専用
使い方
adbコマンドを使って
.realm
ファイルを取り出し、アプリケーション上で開いてデータを確認する。所感
2017年でアップデートが終わっているので、今後もうメンテされることはなさそう?
今から使うのならRealm Studioを選びたい気がする。stetho-realm
概要
- Stethoは、Chrome Developer Toolsを利用して、Chromeからデバッグを行うことができるAndroidのデバッグブリッジ
- Stethoの公式サイト: http://facebook.github.io/stetho/
- Facebookが作っている
- stetho-realmは、StethoをRealmに対応したライブラリ
- GitHub: https://github.com/uPhyca/stetho-realm
- 2017年を最後に更新されていないが、その後もコミュニティによって対応がされているらしい
- 個人が作っている
使い方
build.gradleに依存関係を追加し、Application内で初期化、
アプリを起動後、Chrome上でデータを確認する。所感
個人的には一番簡単で、使いやすいと感じた(新たにアプリケーションをインストールしたり、adbコマンドを叩いたりする必要がないため)。
一点注意点としては、Realm3.7.1以上のバージョンはサポートされておらず、Realmの最新版を使ったりするとアプリがクラッシュするので、下記記事を参考にコミュニティが対応しているリポジトリを使う必要がある。
https://blog.local-c.com/archives/2496
https://stackoverflow.com/a/51381971/11934352realm-browser
概要
- Androidデバイス上でデータベースを閲覧するライブラリ
- GitHub: https://github.com/dmytrodanylyk/realm-browser
- 2015年で正式にサポートが打ち切られている
- 個人が作っている
使い方
build.gradleに依存関係を追加し、初期化、
閲覧用のActivityを呼び出して、デバイス上でデータを確認する。所感
デバイス上で見れるのは楽そうでいいなと思うが、参考になる記事も少ないので、ハマったときにつらそう。
結論
- さくっと確認するなら stetho-realm が一番使いやすいと感じた(→結果これを使った)
- これからRealm公式ツールを使うなら、Realmが推している Realm Studio を使いたい
- 投稿日:2020-01-01T18:04:20+09:00
【ぶっちゃけAndroidアプリ開発】SQLiteデータベースにアクセスして画面に表示するサンプル
sqliteで作成したテーブルにアクセスして、Activityに表示する簡単なサンプルを作成しました。
動くサンプルコードが欲しい人のために、簡単な解説とともに載せておきます。Android StudioでEmpty Activityで新規プロジェクト作成し、コピペすれば動くはずです。
<前提>
作成日:2020年1月1日
AndroidStudio 3.5.3
targetSdkVersion 26
CompileSdkVersion 29・Empty Activityの雛形を元に作成。
1.データベースファイルの作成
test.csv1,東京都庁,東京都新宿区西新宿2-8-1,03-5321-1111,metro.tokyo.jp 2,神奈川県庁,神奈川県横浜市中区日本大通1,045-210-1111,pref.kanagawa.jp 3,埼玉県庁,埼玉県さいたま市浦和区高砂3-15-1,048-824-2111,pref.saitama.lg.jp 4,千葉県庁,千葉県千葉市中央市場町1-1,043-223-2110,pref.chiba.lg.jp 5,静岡県庁,静岡県静岡市葵区追手町9-6,054-221-2455,pref.shizuoka.jp・住所録ちっくなcsvファイルをインポートし、sqliteを使用してデータベースファイル「test.db」を作成する。
・テーブル名は「addressbook」、項目は seq(integer),name(text),address(text),phone(text),mail(text) の5つ。
・データベースファイルの作成方法は、「【ぶっちゃけAndroidアプリ開発】sqliteでデータベースを作成する」を参照。2.データベースファイルをプロジェクトに追加する
(1)Assetsフォルダの作成
・ツールウィンドウのモジュールを右クリックして、Assetsフォルダを追加する。
(2)データベースファイルの追加
・作成した「test.db」ファイルをAssetsフォルダにコピペする。
3.SQLiteOpenHelperクラスの実装
・SQLiteOpenHelperを継承したクラスを実装する。
・実装例は「Y.A.M.さんのページ」を参照させていただきました。DatabaseHelper.javapublic class DatabaseHelper extends SQLiteOpenHelper { private static String DB_NAME = "test"; private static String DB_NAME_ASSET = "test.db"; private static final int DATABASE_VERSION = 1; private final Context mContext; private final File mDatabasePath; public DatabaseHelper(Context context) { super(context, DB_NAME, null, DATABASE_VERSION); mContext = context; mDatabasePath = mContext.getDatabasePath(DB_NAME); } /** * asset に格納したデータベースをコピーするための空のデータベースを作成する */ public void createDatabase() throws IOException { boolean dbExist = checkDatabaseExists(); if (dbExist) { // すでにデータベースは作成されている } else { // このメソッドを呼ぶことで、空のデータベースがアプリのデフォルトシステムパスに作られる SQLiteDatabase db = getReadableDatabase(); db.close(); try { // asset に格納したデータベースをコピーする copyDatabaseFromAsset(); String dbPath = mDatabasePath.getAbsolutePath(); SQLiteDatabase checkDb = null; try { checkDb = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE); } catch (SQLiteException e) { } if (checkDb != null) { checkDb.setVersion(DATABASE_VERSION); checkDb.close(); } } catch (IOException e) { throw new Error("Error copying database"); } } } /** * 再コピーを防止するために、すでにデータベースがあるかどうか判定する * * @return 存在している場合 {@code true} */ private boolean checkDatabaseExists() { String dbPath = mDatabasePath.getAbsolutePath(); SQLiteDatabase checkDb = null; try { checkDb = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READONLY); } catch (SQLiteException e) { // データベースはまだ存在していない } if (checkDb == null) { // データベースはまだ存在していない return false; } int oldVersion = checkDb.getVersion(); int newVersion = DATABASE_VERSION; if (oldVersion == newVersion) { // データベースは存在していて最新 checkDb.close(); return true; } // データベースが存在していて最新ではないので削除 File f = new File(dbPath); f.delete(); return false; } /** * asset に格納したデーだベースをデフォルトのデータベースパスに作成したからのデータベースにコピーする */ private void copyDatabaseFromAsset() throws IOException{ // asset 内のデータベースファイルにアクセス InputStream mInput = mContext.getAssets().open(DB_NAME_ASSET); // デフォルトのデータベースパスに作成した空のDB OutputStream mOutput = new FileOutputStream(mDatabasePath); // コピー byte[] buffer = new byte[1024]; int size; while ((size = mInput.read(buffer)) > 0) { mOutput.write(buffer, 0, size); } // Close the streams mOutput.flush(); mOutput.close(); mInput.close(); } @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }・createDatabaseメソッドでデータベースをプログラムで使用できるようにする。AssetsフォルダのデータベースをAndroid端末内にコピーする。(そうしないと使えないらしい)
4.MainActivityからデータベースアクセス
MainActivity.javapublic class MainActivity extends AppCompatActivity { private DatabaseHelper helper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView = findViewById(R.id.textview); helper = new DatabaseHelper(this); try { helper.createDatabase(); } catch (IOException e) { throw new Error("Unable to create database"); } StringBuilder builder = new StringBuilder(); SQLiteDatabase db = helper.getReadableDatabase(); String sql = "select seq, name, address, phone, mail from addressbook"; try { Cursor cursor = db.rawQuery(sql, null); while(cursor.moveToNext()) { builder.append(cursor.getInt(0) + " "); builder.append(cursor.getString(1) + " "); builder.append(cursor.getString(2) + " "); builder.append(cursor.getString(3) + " "); builder.append(cursor.getString(4) + "\n"); } } finally { db.close(); } textView.setText(builder.toString()); } }・helperオブジェクトを作成する。
・createDatabaseメソッドでデータベースを使用できる状態にする。
・getReadableDatabaseメソッドで読み取り専用データベースをオープンする。
・sqlで全レコードをselectし、TextViewに表示する。
・このサンプルは読み取り専用だが、getWritableDatabaseで読み書きできるデータベースとしてオープンできる。5.レイアウト
activity_main.xml<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>・TextViewのidに「textview」を指定してください。
6.実行結果