RoadMovie

write down memos or something I found about tech things

AndroidアプリのonResumeとonPause

かなりラフな記事になるけど、Androidでアプリがforeground(起動中)の時とbackgroundにある時とでの挙動に手を加えたかったり、そうなるタイミングで何か処理を行いたいということがあると思う。

Lifecycleを調べると、onResumeonPuase がそれぞれforegroundとbackgroundに対応しているように思われるが、これは必ずしも100%保証された動作ではない。

これらの検知をどう正確に実現するのかは下記のStackOverflowが役に立つのでそちらに譲ることにする。

How to detect when an Android app goes to the background and come back to the foreground - Stack Overflow


私が手こずらされた原因になったのは下記。知っていればなんてことないが、あまりAndroidアプリの経験がないと困る可能性がある。

android - OnPause is called right after OnResume - Stack Overflow

Note: When the system calls your activity's onPause() method, the system may be signaling that the activity will be paused for a moment and the user may return focus to your activity, or that the app is running in multi-window mode. However, this method call may also be the first indication that the user is leaving your activity.

ここにあるように、ユーザーがactivityを離れるときにもonPauseは呼ばれる。要はあなたのアプリでactivityを複数使っている場合(多くはそうだと思われるが)、そのactivity間の遷移でもonPauseは呼ばれる。

Keep in mind that onResume is not the best indicator that your activity is visible to the user; a system window such as the keyguard may be in front. Use onWindowFocusChanged(boolean) to know for certain that your activity is visible to the user

また、上記もある特定のユースケース(私が関わっているアプリはそうだった)では面倒な事になるので、正確に onResumeonPause の挙動を理解する必要がある人は頭に入れておきたい内容。

Kotlinで知ってると便利なTips

もともとはRubyをメインで書いていたのですが、最近Kotlinを使うようになって便利だと思ったTipsをいくつか紹介します。

data class

Ref: https://kotlinlang.org/docs/reference/data-classes.html

何もしないけどデータだけ持たせたい時に使えるクラスです。equals, toStringなどいくつかの簡単なメソッドは使えるようにしてくれています。

sealed class

Ref: https://kotlinlang.org/docs/reference/sealed-classes.html

簡単に言うとenumの拡張型です。継承に制限があって、同じファイル内でしか継承できません。

例えばこんなふうに使っています。

sealed class Result { 
    data class Success(val a: A, val b: B): Result() 
    data class Failure(val a: A, val b: B): Result() 
} 

enumだとこのようにdataクラスを持つことができないので、便利に使えます。

custom getter(setter)

Ref: https://kotlinlang.org/docs/reference/properties.html#getters-and-setters

ちょっと上の2つとは毛色が違いますが、getter, setterのoverrideをこんな風にかけます。知ってると意外と便利です。

var stringRepresentation: String 
    get() = this.toString() 
    set(value) { 

        setDataFromString(value) // parses the string and assigns values to other properties 

    } 

また何かおもしろいTipsを見つけたら追記していきます。

Kotlinで新たに使えるようになったCoroutineで非同期処理

Coroutines Overview - Kotlin Programming Language

2019/01/16現在、まだexperimentalなのですが、使い勝手が良いので私が手伝っている会社でも取り入れ始めている、というより全面的にcoroutineで書き直しています。 基本的に launch の使い方と async, await の使い方を理解できれば良いだけなのでとっつきやすいと思います。

launch — This builder simply launches a new coroutine and returns a reference to it as a Job object which does not have a result. If you intend to block the current thread, instead of launch you may use runBlockingbuilder instead.

訳: 新しいcoroutineを作ってJob objectとしてそのcoroutineへのリファレンスを返してくれる。現在動かしているスレッドをブロックしたければrunBlockingbuilderを使うことで可能になる。

これだけで非同期処理ができるのでラクですよね。

async — This builder launches new coroutine and returns a reference to it as a Deferred type object which may have a result. It is usually used along with await which is a suspending function which can wait for a result without blocking the current thread.

訳: 新しいcoroutineを作ってDeferred typeとしてリファレンスを返す。awaitと併用されるのが通常。併用すると現在のスレッドをブロックせずに結果を待つことができる。


要はasyncを呼んでDeferredを受け取っておくと自分の好きなタイミングで後でawaitを呼ぶことで実行して結果を受け取れる、という感じです。この2つを使いこなすだけでいわゆるコールバック地獄に陥らずにすむので便利ですね!

redashでデータドリブンなチームを構築

こんにちは。

あなたの会社では分析ツールやダッシュボードなどを使っていますか?もしまだ使ってない、あるいは現状のツールに満足していないのであれば、redashが代案になるかもしれません。redashはとてもシンプルで簡単ですし、分析に必要十分なツールだといえるでしょう。この記事ではAWS EC2を使ったビルド方法を紹介します。



https://redash.io/

Make Your Company Data Driven Connect to any data source, easily visualize and share your data

お金を払えば一切何もしないでredashを利用することもできますが、あなたがエンジニアであれば(あるいはエンジニアに手伝ってもらえば)すべての機能を無料で使うことができます。

documentは下記になります。

https://redash.io/help-onpremise/setup/setting-up-redash-instance.html


Steps

1. EC2をredash AMIを使って起動

2. データソースに接続

3. SESを使ってEmailシステムを構築

First Step: EC2をredash AMIを使って起動

redashはビルド方法として2つ用意しています。ひとつはDockerを用いた方法で、もうひとつがAWSのAMIを使った方法です。 ここではAMIを使った方法を紹介します。

EC2のダッシュボードで、"Launch Instance"をクリックします。そして、左側の"Community AMIs"をクリック。次に、検索窓から先程のdocumentにあったAMIの名前を探します。インスタンスサイズはsmallで十分なようです。起動が完了するとpublic DNSでアクセス可能になります。もちろん独自ドメインの設定も可能です。


Second Step: データソースに接続

最初のステップはとても簡単でした。次のステップは少し難しくなるかもです。PostgreSQLをデータソースに選んだ場合の方法を示します。

難しいポイントはポート指定です。autosshを使うと比較的簡単に設定が可能になります。もしAWS RDSを使っていれば簡単に接続できますが、そうでない場合はこの手段を用いるのが良いでしょう。

ubuntuにautosshをインストールします。

$ sudo apt-get install autossh

コネクションの設定例です。

$ autossh -M 0 -f -N -L 127.0.0.1:15432:127.0.0.1:5432 ubuntu@example.com -p 5082

上記のケースでは,

1. ubuntu userとしてsshexample.comにport 5082で接続

2. example.comのport 127.0.0.1:5432をhost(autosshを使っている)のport 127.0.0.1:15432に接続

autosshのプロセスを確認しておきましょう。

ubuntu@redash-production:~$ ps ax | grep autossh
 5746 pts/0    S+     0:00 grep --color=auto autossh
14346 ?        Ss     0:00 /usr/lib/autossh/autossh -M 0    -N -L 127.0.0.1:15432:127.0.0.1:5432 ubuntu@example.com -p 5082

ところで、実際はredashユーザーを作成して、read-onlyの権限を与えて運用するのが良いでしょう。

Third Step: SESを使ってEmailシステムを構築

もしredashにログイン可能なユーザーを追加したければ、Email送信機能を構築する必要があります。これは、redashでユーザーを追加した際、登録したメールアドレスに確認URLが書かれたメールが届くからです。ここではAWSを使っているのでSESを利用するのが簡単で良いでしょう。

先程のEC2内の /opt/redash にredashの設定があります。ここに.envという隠しファイルがあるので、SESの設定をここに書いていきましょう。

下記は設定例です。

# .env

export REDASH_LOG_LEVEL="INFO"
export REDASH_REDIS_URL=redis://localhost:6379/0
export REDASH_DATABASE_URL="postgresql:///redash"
export REDASH_COOKIE_SECRET=SECRET_KEY // set by default

export REDASH_MAIL_SERVER="email-smtp.eu-west-1.amazonaws.com" # default: localhost
export REDASH_MAIL_PORT="587" # default: 25
export REDASH_MAIL_USE_TLS="true" # default: false
export REDASH_MAIL_USE_SSL="false" # default: false
export REDASH_MAIL_USERNAME="USERNAME_OF_SES" # default: None
export REDASH_MAIL_PASSWORD="PASSWORD_OF_SES" # default: None
export REDASH_MAIL_DEFAULT_SENDER="email@email.com" # Email address to send from

export REDASH_HOST="https://redashhost.com" # base address of your Redash instance, for example: "https://demo.redash.io"

SESのusernameとpasswordがわからなければ下記のdocumentをチェックしてみてください。 https://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-credentials.html


これで完了になります。クエリを作成してダッシュボードを作ってみましょう。

Happy life with redash! :D


ReactNativeでプッシュ通知を実装する方法

この記事ではReactNativeでのプッシュ通知の実装方法を紹介したいと思います。


まず最初に全体の設計はこんな感じです。

Application

  • identifierをAPIサーバ(Backend)に送ります
  • AWS SNSから通知を受け取ります

Backend(ここでは例としてRailsを想定しています)

  • identifierをアプリから受け取ります
  • DBにidentifierを保存します ( endpoint_arn を保存しましょう)
  • endpoint_arn を登録して、トピックをサブスクライブします
  • いつ通知を送るのかをAWS SNSに教えます(cronなどでトリガーを用意するという意味です)

AWS SNS

  • endpoint_arn を保存します
  • トピックを作ります(ユーザーグループのようなものです)
  • 通知を送ります
    • 例えばAndroidアプリではFMC(firebase message cloud)を利用します

ライブラリ群

in ReactNative

アプリからidentifierを送る必要があります。ReactNativeではindex.android.jsindex.ios.jsに実装コードを書くのがよいのではないでしょうか。OS毎に設定が多少違うので、ここだとその差異を吸収しやすいと思います。

例としてスクリプトを載せておきます。

in Rails(Backend)

まず、aws-sdk-rails用にinitializerを用意するのが良いでしょう。


Controller内でidentifierを受け取るためのアクションを定義しておきましょう。もしそれが新規identifierであればAWS SNSに登録します。AWS SNSにリクエストを送るとendpoint_arnを受け取ることができます。DBに保存しておきましょう。


上記の Aws::Sns::DeviceTokenRegisterer.register(device_token) はサービス層に用意しています。endpoint_arn を登録するために呼んでいます。

ここでは、2つのトピックをendpointとしてサブスクライブしています。この記事の始めに書いた通り、トピックとはユーザーグループのようなものです。ここでは2つのトピックを作りました。ひとつはすべてのデバイスに対して、もうひとつはAndroidiOSのどちらかのみというものです。AWS SNSの設定に関してはAWSのdocumentを参照してみてください。


最後に、プッシュ通知イベントを発火します。下記、サンプルコードです。


これで全てです。それほど複雑ではないですよね。AWS SNSは便利ですし、比較的値段も安いです。ぜひ利用してみましょう。もし質問や意見、提案などございましたらぜひコメントに書いていただければと思います。

それでは。

ReactNative - "Could not get BatchedBridge, make sure your bundle is packaged properly”

ReactNativeでAndroidをリリースしようとした時に起こったエラーの対処法です。

Android Studioから Build > Generate Signed APKapp-release.apk を作ろうとしました。 この方法はローカル環境ではうまくいっているように見えるのですが、PlayStoreからダウンロードしたものを立ち上げようとするとクラッシュします。

下記エラーログです。

Could not get BatchedBridge, make sure your bundle is packaged properly.


結論から言うと、consoleからsigned apkを作らなければいけなかったということでした。 下記の方法でうまくいくはずです。 facebook.github.io

$ cd android &&./gradlew assembleRelease

もしAndroidバイスデバッグに使っているのであれば、下記のコマンドでUSB経由でapkをインストールできます。

$ adb install android/app/build/outputs/apk/app-release.apk


お役に立てれば嬉しいです。

React.js & redux-form のテストをmocha & chai で書く

reactjs, redux-form, mocha, chai


こんにちは。この記事ではredux-formをReact.jsで使った際のテストについて紹介したいと思います。 話をシンプルにするために、簡単なcomponentとreducerのテストを見せます。

下記がテスト用に使っているライブラリになります。

※コードはES6で書いてwebpack等でコンパイルすることを前提にしてます。

test
├── components
│   └── postcode.spec.js
├── reducers
│   └── index.spec.js
└── setup.js

Component test

ここでテストしているのは

  • componentが正しいタイトルを持っているか
  • componentが正しいfieldを持っているか
  • componentが正しい値を返すか

になります。 redux-formではそれぞれのcomponentにstoreを渡す必要があります。なので、ここではcomponentをProviderでラップしています。また、onSubmitのメソッドとして returnState を渡しているので、送信ボタンを押したあとの値をそこでチェックすることができます。

Reducers test

Tips for jsdom

もしチュートリアル通りにやっていれば、 mocha-jsdom: already a browser environment or mocha-jsdom invoked twice. use 'skipWindowCheck' というエラーをみたことがあるかもしれません。これを避けるために setup.js を用意しました。windowdocument を遣う場所でこれをロードしておけばこのエラーを避けることができます。

Test command

最後に、テストは下記のコマンドで実行することができます。

$ npm run test

in package.json

scripts: {
    test: mocha --compilers js:babel-core/register --colors ./test/**/*.spec.js
}

References

mocha-jsdom (to avoid mocha-jsdom: already a browser environment or mocha-jsdom invoked twice. use 'skipWindowCheck') https://github.com/rstacruz/mocha-jsdom/blob/master/examples/basic/test.js

redux-form integration test https://github.com/tylercollier/redux-form-test/blob/master/tests/integration/index.js

unit test https://github.com/tylercollier/redux-form-test/blob/master/tests/unit/index.js#L76

basic test syntax for redux http://redux.js.org/docs/recipes/WritingTests.html

syntax for chai http://chaijs.com/api/bdd/


それでは!