- 投稿日:2019-08-20T20:53:15+09:00
Androidアプリにも審査がされるようになった件
先日Androidアプリをリリースしようといつもどおりの作業を行ったのですが、5時間たっても公開されない状況が続いていたため、なにかあったのかと思いコンソールを見てみると、初めて見るメッセージが表示されていました。
「Androidアプリに審査…?公開後に機械的にやってるんじゃないの…?」
と思ったのですが、Twitterなどで調べてみると、Androidアプリの審査があってアプリが公開できていないという話をされてる方がちらほらいました。とりあえずこちらでは制御できないので、一旦審査が終わるのを待ちました。
翌朝確認してみるとストアにアプリが公開されており、「アップデート公開したよ!」というメールが深夜3時頃に来ていました。
リリース作業を行ったのが14時頃だったので、リリースまでに13時間ほどかかったことになります。とりあえずリリースは無事終わったのですが、改めて審査についてGoogleに問い合わせしてみました。
Q. 審査って何時間ぐらいかかりますか?
A. 目安としては、最大48時間です。Q. 審査って土日もやっているのですか?
A. 審査は営業日に行うので、土日を挟むと審査が遅れる可能性があります。Q. 審査を先に通過させておくなど、デベロッパー側でリリースタイミングを制御する方法はありますか?
A. 時間指定公開を使えばデベロッパー側で制御できます。しかし、時間指定公開は、すでに公開されているアプリのアップデートをリリースする場合のみ有効で、新規に公開するアプリは使用できません。8/22 追記
新規アプリの時間指定公開についてですが、@kafumi さんからコメントで、新規に公開するアプリを時間指定公開する方法があるとのご指摘をいただいたので訂正します。クローズドトラックに一度公開し、そちらから製品版にプロモートする形であれば時間指定公開を利用できるとのことで、新規アプリでもこの方法を使えばリリースタイミングが制御できるようです。
Q. 審査でリジェクトされる可能性ありますか?ある場合、リジェクトの基準などありますか?
A. 社内ポリシーのためお答えできません。参考にこちらをご確認ください。とのことでした。
今後のリリースについて
審査が入ること自体はGoogle Play Storeが無法地帯にならないので良いことだと思うのですが、審査を土日にやってくれないのはなかなかタイミングが難しいですね…
深夜3時にアップデートが公開されたことから、審査はカリフォルニアで行っているようです。
なので、日本時間の金曜日に提出した場合、その日のうちに審査が通る可能性もあると思われます。
同時に、アメリカの祝日についても考慮しなければいけないですが…今後は、Androidアプリのリリースも審査があることを考慮してリリーススケジュールを組む必要がありそうです。
リリースのタイミングをデベロッパー側でなるべく制御したい場合は、時間指定公開を有効にし、先に審査を通過させておく必要があります。時間指定公開のやり方は、以下のページに記載があります。
https://support.google.com/googleplay/android-developer/answer/6334282?hl=ja
- 投稿日:2019-08-20T17:54:41+09:00
Androidで色の透過率を指定する
Color.argbで指定する方法
example.ktimport android.graphics.Color Color.argb(128, 51, 51, 51)引数として以下の4つの値を10進数(0〜255)のintで渡す。
- alpha 透過率
- red 赤
- green 緑
- blue 青
↑の例の場合、以下のような値を渡している。
- alpha = 128
- red = 51
- green = 51
- blue = 51
colors.xmlで定義する方法
app_name/app/src/main/res/values/colors.xml<color name="example">#80333333</color>2桁ごとに以下の4つの値を16進数(0〜FF)で指定する。
- alpha 透過率
- red 赤
- green 緑
- blue 青
↑の例の場合、以下のような値を定義している。
- alpha = 80
- red = 33
- green = 33
- blue = 33
- 投稿日:2019-08-20T17:52:24+09:00
Androidで色の透過率を指定する
Color.argbで指定する方法
example.ktimport android.graphics.Color Color.argb(128, 51, 51, 51)引数として以下の4つの値を10進数(0〜255)のintで渡す。
- alpha 透過率
- red 赤
- green 緑
- blue 青
colors.xmlで定義する方法
app_name/app/src/main/res/values/colors.xml<color name="example">#80333333</color>2桁ごとに以下の4つの値を16進数(0〜FF)で指定する。
↑の例の場合、
alpha = 80
red = 33
green = 33
blue = 33
- 投稿日:2019-08-20T09:01:40+09:00
Roomで多対多のEntityを取得する方法
はじめに
みなさんRoom使っていますか?
SQLiteの面倒な部分をいい感じにやってくれるいいヤツです。多対多な関係にあるEntityの取得方法に苦戦にしていたところ
最高の解決方法があったのでシェアします。多対多(Many-to-Many)の関係
多対多の関係とはなんぞや?知っている方はスキップで大丈夫です。
簡単に言えば、音楽のプレイリストと楽曲の関係と同じです。
例えば、「新海誠」というプレイリストに
- 「前前前世/RADWIMPS」
- 「愛にできることはまだあるかい/RADWIMPS」
- 「One more time, One more chance/山崎まさよし」
- 「Rain/秦基博」
という複数の楽曲が登録されているとします。
一方で、「RADWIMPSマイベスト」というプレイリストには
- 「前前前世/RADWIMPS」
- 「愛にできることはまだあるかい/RADWIMPS」
- 「おしゃかしゃま/RADWIMPS」
という複数の楽曲が登録されているとします。
「新海誠」と「RADWIMPSマイベスト」には共通して
- 「前前前世/RADWIMPS」
- 「愛にできることはまだあるかい/RADWIMPS」
という楽曲があることが分かります。
このように、一つのプレイリストに対して複数の楽曲が紐付いていて、一つの楽曲に対しても複数のプレイリストに紐付いているような関係を多対多と呼びます。
本題
Roomを使ってこの関係を表現しようとすると、
@Entity data class PlayList( @PrimaryKey val id: Long, val name: String ) @Entity data class Song( @PrimaryKey val id: Long, val name: String ) @Entity( primaryKeys = ["play_list_id", "song_id"], foreignKeys = [ ForeignKey( entity = PlayList::class, parentColumns = arrayOf("id"), childColumns = arrayOf("play_list_id") ), ForeignKey( entity = Song::class, parentColumns = arrayOf("id"), childColumns = arrayOf("song_id") ) ] ) data class PlayListAndSongXRef( @ColumnInfo(name = "play_list_id") val playListId: Long, @ColumnInfo(name = "song_id") val SongId: Long, )のようにプレイリストと楽曲の関係を表す中間テーブルを用意して実現すると思います。
(Songクラスには簡単のためにアーティスト名は省略)では、特定のプレイリストとそのプレイリストに紐づく楽曲一覧を取得したいとしましょう。
以下のようなEntityとして返ってくることを期待していますdata class PlayListAndSongs( val playList: PlayList, val songs: List<Song> )これをDao経由で一発で取得する方法が分からず、頭を悩ませていましたが
Room2.2-alpha01から@Junction
というアノテーションが追加され、https://developer.android.com/jetpack/androidx/releases/room#2.2.0-alpha01
試しに使ってみたらいともたやすく解決できてしまいました。
@Junction
アノテーションは、今回のような中間テーブル経由で紐づく複数のデータを取得する際に利用することができます。使い方は簡単です。
class PlayListAndSongs { @Embedded lateinit var playList: PlayList // ① @Relation( entity = Song::class, // ② parentColumn = "id", // ③ entityColumn = "id", // ④ associateBy = Junction( value = PlayListAndSongXRef::class, // ⑤ parentColumn = "play_list_id", // ⑥ entityColumn = "song_id" // ⑦ ) ) lateinit var songs: List<Song> }①:
@Embedded
アノテーションを取得する親になるフィールドに付与します。
②:@Relation
アノテーションを複数の子になるフィールドに付与して、entity
に子のクラスを指定します。
③parentColumn
:@Embedded
を付与したクラス(PlayList
)と中間テーブル(PlayListAndSongXRef
)を紐付けるためのPlayList
側のキー
④entityColumn
:Song
と中間テーブルを紐付けるためのSong
側のキー※③、④のカラム名が同じでややこしくなってしまった・・・。
⑤:
associateBy
にはvalue
に中間テーブルのクラス、
⑥parentColumn
:@Embedded
を付与したクラス(PlayList
)と中間テーブル(PlayListAndSongXRef
)を紐付けるための中間テーブル側のキー
⑦entityColumn
:Song
と中間テーブルを紐付けるための中間テーブル側のキーを指定します。
あとはDaoを
@Dao interface PlayListAndSongsDao { @Query(""" SELECT * FROM PlayList WHERE name = :name LIMIT 1 """) fun getPlayListAndSongsByName(name: String): PlayListAndSongs }のように定義して、
val playListAndSongs = dao.getPlayListAndSongsByName("新海誠")とすれば「新海誠」のプレイリストとそれに紐づく複数の楽曲データがリストで取得できます。
@Junction
すげー!2019/8/20段階ではalphaな機能なのでプロダクションで使うには検討が必要ですが、他対他のデータ取得がとても簡単になるので、
ぜひ導入していきたいですね。
自分は個人開発アプリでガシガシ使っていこうと思います。
- 投稿日:2019-08-20T00:00:08+09:00
androguardを使ってapkを解体する
androguardというツールを使ってapkを解体してみる。
どのへんがガードなんだ逆じゃないか、と言いたくなるのは置いておくとして。TL;DR
pip3 install -U androguard[magic,GUI] androguard analyze TestActivity.apk In [2]: dx.classes : In [3]: for meth in dx.classes['Ltests/androguard/TestActivity;'].get_methods(): print("inside method {}".format(meth.name)) for _, call, _ in meth.get_xref_to(): print(" calling -> {} -- {}".format(call.class_name, call.name)) androguard axml TestActivity.apk androguard arsc TestActivity.apk --list-types androguard arsc TestActivity.apk --type string --locale ja androguard axml TestActivity.apk -r res/layout/main.xml環境
- MacOS Mojave 10.14.6(18G87)
- Python 3.7.4
- Androguard version 3.3.5
androguard
の導入以下を実行。
pip3 install -U androguard[magic,GUI]apkの中身を見る
以下を実行。
androguard analyze TestActivity.apkすると
In [1]:
のような表示が出るので、そこでdx.classes
してみる。
するとすべてのクラスの一覧が表示される。次に
a.get_activities()
してみる。
するとapkに含まれるすべてのアクティビティのクラスが列挙される。その他、以下のようなコマンドが実行できる。
In [4]: a.get_package() Out[4]: 'com.greenaddress.abcore' In [5]: a.get_app_name() Out[5]: u'ABCore' In [6]: a.get_app_icon() Out[6]: u'res/mipmap-xxxhdpi-v4/ic_launcher.png' In [7]: a.get_androidversion_code() Out[7]: '2162' In [8]: a.get_androidversion_name() Out[8]: '0.62' In [9]: a.get_min_sdk_version() Out[9]: '21' In [10]: a.get_max_sdk_version() In [11]: a.get_target_sdk_version() Out[11]: '27' In [12]: a.get_effective_target_sdk_version() Out[12]: 27コマンドラインは通常通り、
Ctrl+D
で抜ける事ができる。
AndroidManifest.xml
を読む以下コマンドを実行するだけ。
androguard axml TestActivity.apkres(リソース)を一覧する
# 種類を一覧する androguard arsc TestActivity.apk --list-types # 色を一覧する androguard arsc TestActivity.apk --type color # 日本語リソースの文字列を一覧する androguard arsc TestActivity.apk --type string --locale jalayoutを読む
下記のようなコマンドで解体できる。
androguard axml TestActivity.apk -r res/layout/main.xml
リソースは探すのが手間なので、拡張子を
apk
からzip
に変更して解凍し、バイナリXMLにしてからandroguardしたほうが楽。ただし、これで出てくるのはリソースのIDの状態なので、例えば
android:id="@7F0802F9"
という値があるとして、R.java
から0x7f0802f9
になっている値を探して、それがhoge_id
だと判明する。色や文字列の場合は、そこから更に--type color
などで追いかける必要があって結構難儀。備考
androlyze.py
はどうやら動かない。
プログラムを解体したいだけなら、 jad や dex2jar を組み合わせたほうが楽。参考