画竜点睛を衝く@mapyo

日々やった事をつらつらと書くブログです

時間のかかるコマンドの実行が終了した時にディスプレイに通知する

10秒とか20秒とか1分とか時間のかかるコマンドを実行する事はしばしばある。 この間ずっとiterm2を目視しているわけにもいかず、何か別の事をする。しかし別の事をしていると、コマンドが終わった時に気が付けない。10秒くらいで終わるコマンドを実行しているのに、気がついたら5分くらい別の事をしてた。なんてあるあるだ。

なのでコマンドの実行が終わったら通知して欲しい。

探したらいいのを見つけた。

qiita.com

そして、参考サイトのコピペするだけで動いた!

function notify_precmd {
    prev_command_status=$?

    if [[ "$TTYIDLE" -gt 1 ]]; then
        notify_title=$([ "$prev_command_status" -eq 0 ] && echo "Command succeeded \U1F646" || echo "Command failed \U1F645")
        osascript -e "display notification \"$prev_command\" with title \"$notify_title\""
    fi
}

function store_command {
  prev_command=$2
}

autoload -Uz add-zsh-hook
add-zsh-hook preexec store_command
add-zsh-hook precmd notify_precmd

さらに、これのいいところは、1秒より長いコマンドを実行した時には自動的に実行してくれるので、短いコマンドで無駄に通知されることもない。 これでちょっと便利になったー。

[追記] 実際にしばらく使ってみてはいるが、たまに通知してくれない時もあるようだ。。。

戦略とか戦術とか

あれ、どっちがどっちだっけ?と迷った時に、よくこのブログを思い出して検索する

d.hatena.ne.jp

不意に読もうという気持ちになってさくっと購入して読んでみた。

booth.pm

さくっと読めるのでオススメ。この中に戦略的設計と戦術的設計が出てきたのでブログを検索して読み直してみたのだった。 そんな今日この頃。

VysorからOpenSTFに乗り換えた

今まではVysorを使っていた

Vysor

Androidの実機をPCから操作したい時に主に使っていた。 ディスプレイにうつして他の人にデモしたり、テキストを入力する時に便利。

しかしながら、無料版だといくつかの欠点があった

  • 画質が悪い
  • たまに広告が勝手に起動する

特に音が出るアプリを開発している時は、スマホのボリュームをある程度上げている。その状態で音声つきの広告が再生されるとびっくりする事があった。 いろいろと考えてみると、OpenSTFを普通にMacにインストールして、自分専用にして使えばいいんじゃないか。。?と思ったので試してみた。

導入はMacであれば、基本的に

github.com

これを見ながらやればOK

よかったこと

  • 画質が荒くなく、普通にいい
  • PCでコピーしたURLをスマホのブラウザで開く時に便利(好きなブラウザで開くための機能がある。Vysorでもコピペして入れればOKだったが、機種によってはちゃんとコピペが出来ない時もあって不便だった)

わるかったこと

  • PCと接続すると、STFService is runningの通知がずっと出っぱなしになって結構気になる
  • ↑がアンインストールするまで消えない。
  • 何故かマナーモードにしていても、PCと接続すると勝手に解除されて音がちょっと出るようになる
  • 悪くはないけど、Vysorではスクロールで画面が移動していたのだがOpenSTFは出来なかった。。

こんな感じ。わるかったことに関しては今後、対応出来るものであれば対応していきたいけど、ざっと調べた時は出来なさそうな感触ではあった。。。 そんな今日この頃。

RxJavaでPublishSubjectをsubscribeした時にonErrorが呼ばれるとそれ以降動かなくなる

サンプルコード

        subject.subscribe ({ number ->
            println(number.toString())

            if (number == 3) throw RuntimeException()
        }, {
            println("onError")
        }, {
            println("onComplete")
        })

        subject.onNext(1)
        subject.onNext(2)
        subject.onNext(3)
        subject.onNext(4)
        subject.onNext(5)

実行結果

1
2
3
onError

4と5が表示されない

所感

onErrorに入った時にちゃんと気がつけないと、何故かいきなり動かなくなってる。。。! という辛みがあるので注意。

fastlaneを使ってGoogle Playのベータ版にアップする

http://mapyo.hatenablog.com/entry/2017/07/23/032630

この辺で日々のビルドをするためにfastlaneを使ったので、次はGoogle Playにアップするところで使ってみる。

いきなり本番は流石に辛いのでベータ版にアップする部分を自動化して、手元で確認してから、Developer Console上で操作して本番に公開という流れをとりたい。

fastlane的なbetaとFabricのBetaとデベロッパーコンソールのBetaといろいろ混同しそうなので注意。

基本的な導入周りはこの辺でいい感じに出来てる

http://qiita.com/gupuru/items/9ddeff0906b02d779ed9

公式ドキュメントも参照

https://docs.fastlane.tools/getting-started/android/setup/

認証情報の設定

https://docs.fastlane.tools/getting-started/android/setup/#collect-your-google-credentials

この辺を見ればOK。内容的には同じだけど、僕のメモを書いとく

  1. Google Play Consoleにアクセス https://play.google.com/apps/publish/
  2. 左上のハンバーガーメニューをクリック
  3. 設定→APIアクセス
  4. サービスアカウントを作成をクリック
  5. ダイアログが表示されて、説明に書いてある通りにGoogle Api コンソールに移動
  6. サービスアカウントを作成
  7. サービスアカウント名を入れる。役割はプロジェクト→サービスアカウントアクターを選択
  8. 新しい秘密鍵の提供にチェックを入れる。キーのタイプはJSON(デフォルトでそうなってた気がする)
  9. 作成をクリック
  10. 秘密鍵が作成されてダウンロードされるので、大事に保存しときましょう
  11. Google Play Consoleに戻って、出てたダイアログの完了をクリック
  12. 新しいサービスアカウントが出来てる事を確認
  13. 新しく出来たやつの、アクセスを許可をタップ
  14. 権限で、「アルファ版とベータ版の APK の管理」以外の権限すべてをOFFにする。これで安心。
  15. ↑と思ったら、「表示設定」の権限は最低限必要だった。アプリ個別に設定するか、全体に設定するかが必要そう。
  16. 終わったらユーザを追加をクリック(しかし、何で権限の変更をしたつもりがユーザの追加になるんだ?権限の設定が終わって初めてユーザを追加するという意味なのかな。)

という感じでもろもろ設定が終わり。権限を絞っているので、何か起きたとしてもアルファ版かベータ版がどうにかなるだけなので、ある意味安心出来る(笑)

ダウンロードしたjsonを好きな場所に置いて、

fastlane/Appfile

ここに追記すればOK

fastlane側の設定

https://docs.fastlane.tools/getting-started/android/beta-deployment/#supported-beta-testing-services

この辺を見て設定する

今回追加したlaneはこちら

  lane :googleplay_beta do
    gradle(task: "clean assembleRelease")
    supply(track: 'beta')
  end

ハマったところは、ここの設定じゃないんだけど、サンプル用にGoogle Play上にアプリを作ったんだけど、公開するために必要なものを一通り設定して、1回でも公開(ベータ版でも可)しないとapiでアップする事が出来なかった。。。

mapping.txtとかどうするの?

BITRISEを使っていると、 deploy-to-bitrise-ioというstepをとりあえず実行しとけば apkとかも含めてそのビルドに保存してくれるので楽。

所感

これでgoogle playのベータにアップするところが自動化出来て最高。という感じ

アプリで日々のビルドを配布する作業を自動化する時に考えた事

現在開発中のdevelopブランチの最新を日々自動的に配布したい。 日々配布してQA担当の方にテストしていただいたり、今のアプリの動きどうなってるんだろ?と思った時にさくっと確認出来て便利。

developブランチにMergeしたタイミングでapk作るのはちょっと細かすぎるかな?という気持ちがあって、1日に1回。 でも、何もdevelopにMergeされてない時にもapkが作られるのでそれはそれで微妙かもしれない。

やりたい事

ざっくり書くと以下のような感じ。

  • 日々の最新のdevelopを使ってFabricのBetaで配布したい
  • バージョン番号もしくは、ビルド番号をカウントアップしてどのビルドなのかをわかるようにしたい

スケジューリング

bitriseを使う。workflowを簡単に設定できて非常に便利。しかしお金はかかりますよと。 毎日指定した時間に発動させる。

バージョン番号もしくは、ビルド番号のカウントアップ

versionCodeとversionNameのどちらかを更新する

日々ビルドしてアップするので、一体どのビルドなんだろう。。。?? というのをわかるようにしないと混乱してしまう。

versionCodeとversionNameのどちらをカウントアップするのがいいのだろうか?

versionCode 1
versionName "1.0.0-alpha.1” // こちらをカウントアップするのがいいと考えた

軽く考えたところで、versionNameの方を変更する事にした。 気分的な問題だけど、versionCodeを日々カウントアップすると実際にアプリをリリースする時に無駄に増えた状態でリリースされてしまいそうと考えたからだ。

日々のビルドは、versionNameの最後に-alpha.1とつけて配布する事にしてみる。

どうやってversionNameの更新するか?

やろうと思えば、いろいろと方法があると思う。

gradleでやるには

https://stackoverflow.com/a/21951328/2172277

この辺を参考にすれば書けるかもしれない。

また、ちょっと話はそれるのだが、将来的にGoogle Playへのデプロイも自動化したいので、その辺も考慮に入れると、

Gradleのgradle-play-publisher vs fastlane

という感じになってくる

どっちがいいんだろうか。。。?と調べてみたところ、1年以上前だけど、いい比較記事を見つけた!

http://qiita.com/shiraji/items/518cb1a20671a6388dd7

fastlaneの方が確かに開発が活発そうな感じなのと、

https://docs.fastlane.tools/getting-started/android/setup/

この辺のドキュメントみたりして比較記事から1年以上たって、いろいろと機能が追加されてそうなので、fastlaneを使ってみる。GroovyよりもRubyの方が僕にとってはコードが読めそう。

fastlaneを使ってversionNameを更新する

fastlaneの準備とかもろもろはちょっとめんどくさくなったので省略する。 versionNameを更新するactionを以下のような感じで作ってみた。

https://gist.github.com/mapyo/e0387f94bf94f6bcb119be7b40ea23ac

fastlane使ったの初めてだし、action作ったのも初めてなのでそんな感じ。 後は、versionNameなどはこの表示形式にする。という決め打ち前提なので、あまり使い勝手は良くないかもしれない。

ビルドと配布

fastlaneのlaneの中で以下のような感じでやる

gradle(task: "clean assembleDebug crashlyticsUploadDistributionDebug")

crashlytics用のactionも用意されているっぽい感じだったけど、既にgradleで配布出来てたし、別に使わなくてもええやん。という気持ちで雑にgradleを使うようにした。

所感

fastlane、今まで全然使った事なかったけど、Android開発者にとっても、便利そうだ!! そして、bitriseが結構便利です!!

今度はアプリをgoogle playに配布するとこら辺を自動化してみたい気持ち。

KotlinでSealed Classを継承したクラスをGsonでシリアライズする時の話

こんな感じのseald classを作る

sealed class SampleEvent(open val name: String)

class SampleEventA(
        override val name: String
): SampleEvent(name)

こんな感じでJson作る

Gson().toJson(SampleEventA("aaaaa"))

気持ちとしては以下のようなjsonが出て欲しい

{"name":"aaaa"}

でもエラーが出る

SampleEventA declares multiple JSON fields named name

ほほう

Android Studioの、

Tools > Kotlin > Show Kotlin Bytecode

でBytecodeからのJavaにDecompileしてどんな感じか見る。

public final class SampleEventA extends SampleEvent {
   @NotNull
   private final String name;

   @NotNull
   public String getName() {
      return this.name;
   }

   public SampleEventA(@NotNull String name) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      super(name, (DefaultConstructorMarker)null);
      this.name = name;
   }
}

public abstract class SampleEvent {
   @NotNull
   private final String name;

   @NotNull
   public String getName() {
      return this.name;
   }

   private SampleEvent(String name) {
      this.name = name;
   }

   // $FF: synthetic method
   public SampleEvent(@NotNull String name, DefaultConstructorMarker $constructor_marker) {
      this(name);
   }
}

abstract classと継承したclassの両方でnameが作られていてそれが原因でエラーが出てるようだ。

javaでabstractを使った時にちゃんと動かすならこんな感じで書けばよさそうだった

abstract class JavaSampleEvent {
    protected final String name;

    public JavaSampleEvent(String name) {
        this.name = name;
    }
}

class JavaSampleA extends JavaSampleEvent {

    public JavaSampleA(String name) {
        super(name);
    }
}
String json = new Gson().toJson(new JavaSampleA("aaaa"));

最後に

結局、Seald Classを使わずにInterfaceを使って対応したのだけど、こういう場合はどうやってやるのがよかったのだろうか。。。??

追記

Twitterでいい感じに出来る方法を教えて頂きました!!

sealed class SampleEvent {
    abstract val name: String
}

class SampleEventA(
        override val name: String
) : SampleEvent()

abstractでプロパティを宣言すれば大丈夫だった。 sealed class使う時にいつもopen使ってやってたけど、こっちの方がよさそうだなー