読者です 読者をやめる 読者になる 読者になる

そーす

福岡在住のプログラマ

Imageコンポーネントは画像をキャッシュする

ReactNativeの標準のImageコンポーネントはキャッシュ機構があります。

なので、以前に取得したURLの画像の場合はキャッシュが読まれます(期限は無さそう)

同じURLの画像が更新される仕様のAPIなどではこれは厄介です…

ちなみにいくつかIssueが上がってました。

github.com

2017/03/20現在ではキャッシュの削除機構は存在せず、ワークアラウンドで対応するか、他のOSSライブラリで対応するしか無いようです。

ちなみに私はとりあえずMath.random()をパラメータに付加してキャッシュを回避する方法を取りました。

BackAndroidはremoveEventListenerではなくaddEventListenerの返り値のオブジェクトを使おう

React ReactNative

facebook.github.io

Andoroidの戻るボタンが押された時のイベントをハンドリングするAPIです。 なんか公式ドキュメント見るとaddEventListerでセットしたハンドラの破棄はremoveEventListerを使わないといけないっぽいですが、 ソースを見てみる

addEventListener: function (
    eventName: BackPressEventName,
    handler: Function
  ): {remove: () => void} {
    _backPressSubscriptions.add(handler);
    return {
      remove: () => BackAndroid.removeEventListener(eventName, handler),
    };
  },

removeメソッドを持つオブジェクトを返してますね。

ちなみに現在のmasterではBackAndroidはDeprecatedになってます。

github.com

BackHandlerというAPIに変わるそうです。

github.com

NetInfo.isConnectedはiOSでは常にfalseを返すという罠

ReactNative

issue上がってます

github.com

再現方法

NetInfo.isConnectedを使うだけ。 Androidはちゃんとしたネットワークの接続状況を返してくれますが、iOSは常にfalse…

原因

github.com

ワークアラウンド

なんと公式ドキュメントのサンプルにまで書いてあります…直さないのかな…

facebook.github.io

NetInfo.isConnected.fetch().then(isConnected => {
  console.log('First, is ' + (isConnected ? 'online' : 'offline'));
});
function handleFirstConnectivityChange(isConnected) {
  console.log('Then, is ' + (isConnected ? 'online' : 'offline'));
  NetInfo.isConnected.removeEventListener(
    'change',
    handleFirstConnectivityChange
  );
}
NetInfo.isConnected.addEventListener(
  'change',
  handleFirstConnectivityChange
);

地味にめんどい…

そもそもiOSのfetchAPIがネットがつながってないときにエラー返さないのが問題なんだけど…

【追記】 fetchにもtimeout設定されてた。

iOSのみ、ModalとAlertを同時に使うとModalが消えないバグがある

Javascript ReactNative React iOS Android

issue上がってます

github.com

再現方法

例えば通信処理中にインジケータ(くるくるするやつ)を出して、通信終わったらインジケータ消してレスポンスに応じてダイアログでユーザに通知したいとかあるじゃないですか。

このインジケータの表示にModalを使って通知にAlertIOSを使ったりすると起きます。

原因

Modalはshow/hide時はアニメーションを付加することができるのですが、このアニメーションの終了前にAlertを追加してしまうのが原因のようです。これは困った。

ワークアラウンド

いくつか上がってます

Modalのアニメーションを切る

一番変更の少ない方法です。上手く行くことを確認しました。 ProgressViewコンポーネントを作ってしまっていて、animationプロパティを変更するだけだったのでこれでとりあえず対応してます。 ただ、やっぱ見た目が悪い…

setTimeoutで終了を待つ

これはちょっと…。変更の手間が多いですね。

DroidKaigiに出席した

Android

3月9,10日に新宿で開催されたDroidKaigi2017に参加してきました。

スピーカーでは無いです。

スピーカーの皆様、スタッフの皆様、超お疲れ様でした。

あの規模のイベント回すのはとても大変だし準備も相当大変だっただろうとお察しします。

個人的にも大満足のイベントでした。

2日間座りっぱなしで話聞くのって体力いるなって思いました、鍛えます。エンジニアって体力いるのね。

(訳あって1日目終わった後に御茶ノ水から西新宿まで1時間30分歩いたのが一番キツかったです

元々は全然行く気無かったんですが、仕事仲間が行くって話をCEOが聞いて「行かないの?経費で行ってきていいよ」って行ってくれたので行きました。ありがとうございました。

2月末でそもそも売り切れてるんじゃないかなーと思ってみてみたらちょうど増員したあとで参加出来ました。

基本的に私は勉強会に対しては

  1. 登壇者として行き、自分を知ってもらう。外との繋がりを作る
  2. 自分が日頃アンテナを張ってる情報やトライしている事に対する答え合わせ

という考えがあり、今回は2が目的で行ってきました。

今回に関してはDroidKaigiが日本で一番大きいAndroidアプリ開発者向けのカンファレンスということで

雰囲気を感じてみたいと言うのが一番でしたが。

聞いたセッションを個別に感想とか書くとすごく長くなるので省略しますが、

2日間終わってみて答え合わせ的には70〜80点位でした。

アンテナ張ってる領域に話は結構自分がわかる話も多く、張っているアンテナや自分の行動が

あまりズレていないということがわかり少しホッとしました。

これで全然分からない話ばかりだったらかなり自信無くしてましたね(笑

結構ニッチな領域だったりの話は分からない事が多かったのですが、聞いてて思ったのはやはり業務で使ってみてどうだったかという実践を踏まえた話ばかりだったということです。

「業務では使えないけど、興味あるから調べてみよう」

というのは(私の経験上)結構時間をムダにすることが多く、業務で使える領域を調べるか業務で使える領域を拡大していくかがやはり重要だなぁとしみじみ感じました。

やっぱ業務時間使ったほうが時間使えるし集中できるし責任もあるし成長早いよね。

何はともあれDroidKaigi楽しかったです。

来年は発表者になれたら行きます。

DroidKaigi関係無いけど宿をAirbnbで取ったのですが、最悪でした。ビジネスホテルの方がマシでした。

ReactNative製アプリをデバッグするときのTips

Android ReactNative

実機デバッグはVysorを使おう

chrome.google.com

実機の画面をキャプチャしてPCに転送してくれます。

キャプチャ画面でクリックやスクロール、タイピングもできるので非常に便利です。

ReactNativeのRELOAD機能はR2回押しで実機だと出来ないのでコレを使うと非常に便利です。

実機でデバッグオプションを表示する

デバッグオプションはオプションキーを押すと出てきますが、最近の端末はオプションキーがありません。

なので、adbを使ってオプションキーイベントを送ると表示されます。

 adb shell input keyevent KEYCODE_MENU

【追記】 なお端末をシェイクしても出るようです。

f:id:saburesan:20170228105827p:plain

基本はChromeコンソール、重いようだったらlogcatで

chromeコンソールデバッグはオブジェクトの中身がプルダウンで見ることができるので非常に便利です。 しかしながら非常に重かったり、そのせいで動作がカクつくことがあります。 chromeコンソールデバッグで無くてもよいのであれば、adb logcatを使いましょう

adb logcat | grep React

ReactでgrepするとReactNativeのログのみ見ることが出来ます。

react-native run-XXXがうまくいかないことがある

ReactNativeのプロセスが複数立ち上がっていたりするのでpsコマンドで確認して不要なプロセスはkillしましょう

ps aux | grep React

ReactNativeのソースを読んで見る(Android編①)

AndroidStudio Java Javascript React ReactNative

*Android編①って書いてるけどAndroid編②があるとかiOS編があるとかは未定です

ReactNativeの「Native」の部分がどう動いてるのか気になったのでソース見てみました。 細かい所まで見てないですし、間違った認識かもしれませんのであしからず。

エントリポイントはMainActivity

AndroidManifestにはMainActivityとDevSettingsActivityでaction.MainがMainActivityでここからアプリがスタートするようです。 DevSettingsActivityはデバッグ用のメニュー(ReloadやLiveReloadなどのメニュー)を表示するためのアクティビティのようです。

MainActivity

ReactActivityというAbstractClassを継承したクラスで自動でgetMainComponentNameがオーバライドされてプロジェクト名を返すようになっています。

ReactActivity

Activityを継承しDefaultHardwareBackBtnHandler, PermissionAwareActivityを実装したクラスです。 基本的にはActivityでしか受け取れないイベント(ライフサイクルやonActivityResultなど)が起きたときにReactActivityDelegateに伝播するクラスです。DefaultHardwareBackBtnHandlerはJSModuleから呼び出されonBackPressedを実行するinvokeDefaultOnBackPressedのみをインターフェースとして持っており、PermissionAwareActivityはActivityのパーミッション関連のメソッドと全く同じメソッドが定義されたインターフェースです。 ちなみにデフォルトで生成されるMainActivityはandroid.app.Activityを継承していますが android.support.v4.app.FragmentActivityを継承したReactFragmentActivityも用意してあります。サポートパッケージを使う場合はこちらに変更するようです。

ReactActivityDelegate

このクラスも基本的にはReactActivityから伝播されたイベントをReactInstanceManagerに伝播しています。 デバッグ時のメニュー表示に必要なパーミッションの処理もこのクラスで処理されています。 onCreateでloadAppメソッドでReactRootViewのインスタンスが生成され、startReactApplicationを実行した後setContentViewされます。

ReactRootView

このクラスはSizeMonitoringFrameLayoutを継承しRootViewを実装しています。 SizeMonitoringFrameLayoutはonSizeChanged発生時にリスナを発火してくれるだけのFrameLayoutのサブクラスです。 RootViewは子ViewにMotionイベントが発生した時に呼ばれるonChildStartedNativeGestureだけを持つインターフェースです。 ReactRootViewは基本的にタッチイベントやViewの表示領域の変更(回転やキーボードの有無)をJS側へ通知する処理をしています。 onMeasureが呼ばれ描画領域が確定するとattachToReactInstanceManagerが呼ばれReactInstanceManagerのインスタンスメソッドattachMeasuredRootViewが呼ばれReactRootViewが渡されます。 デフォルトではReactInstanceManagerはXReactInstanceManagerImplのインスタンスがセットされます。

XReactInstanceManagerImpl

このクラスはまだ全然理解出来てません。 setupReactContextでReactRootViewの初期化を行っています。 XReactInstanceManagerImplはReactRootViewの配列をフィールドに持っており、個々の初期化はattachMeasuredRootViewToInstanceで行われています。 attachMeasuredRootViewToInstanceはReactRootViewとCatalystInstanceを引数に持ち、CatalystInstanceクラスはJS<->JavaAPI呼び出しをする環境を提供してくれるらしいです。

UIManagerModule

catalystInstance.getNativeModule(UIManagerModule.class)でUIManagerModuleのインスタンスを取得してます。このクラスはReactContextBaseJavaModuleを継承しており、これはJS側からJavaのコードを呼ぶために必要なものです。自分でJavaからAPIを呼びたい時はこのクラスのサブクラスをつくります。 UIManagerModuleはJSのComponentからイベントを受け取り、フィールドのUIImplementationのインスタンスに伝播します。 UIManagerModuleのaddMeasuredRootViewメソッドでは引数のReactRootViewをフィールドのUIImplementationに登録しています。

UIImplementation

最終的にコイツがReactRootViewを持ち、JSのComponentからイベント受け取って描画すると思われる(この実装は今後読む

ReactNative雑感

React ReactNative Javascript iOS Android

最近自社のアプリ(iOS,Swift/Android, Kotlin)をReactNative化しているので使ってみた雑感など。

導入のきっかけ

自社アプリのiOS(Swift)とAndroid(Kotlin)は私が一人で作って運用しています。

なんで一人かというと社内でアプリをかけるのは私しかいないからです。

そんなわけで、新しい機能の追加や修正などは2つのプロジェクトを触らなければならなくて非常に手間がかかるんですよ。

そんなわけでちょっと開発が落ち着いたのを見計らって巷で話題(?)のReactNativeを調べ始めたのがきっかけです。

ちなみにJavascriptはほぼ初心者です。

調査段階でのメリット

  • iOS, Androidでコードの共通化ができる(100%ではない)
  • iOS, Androidのネイティブコードを呼び出すことができる(既存のコードを再利用できる?)
  • RectをベースにしたJavascriptとJSXスタイル
  • レイアウトがHTML, CSSスタイルで記述でき、Flexboxスタイルで画面対応ができる
  • HotReload, LiveReload機能がありコードの変更が即時反映される(XcodeやAndroidStudioのビルド待ちが無い)
  • Javascriptが勉強したいんじゃ(個人の気持ちです

調査段階でのデメリット

  • まだベータ版
  • 情報が少ない
  • 日本での人気をあまり感じない
  • JavascriptもReactも初めて(個人の問題です

実際に触ってみて

書き始めてまだ4日くらいですが、基本的な部分は一通り試しました。

調査段階のメリットデメリットとの差分を少し書きます。

調査段階でのメリットについて

iOS, Androidでコードの共通化ができる(100%ではない)

かなりの部分共通化出来ました。 今のところそこまでネイティブでViewを分ける必要は無いのでネイティブのダイアログを読んだりする程度に留めてます。

iOS, Androidのネイティブコードを呼び出すことができる

出来ました。 公式のリファレンスはObj-cとJavaでしたが、SwiftとKotlinでも問題無く呼ぶことが出来ました。 ただXcodeがObj-c <-> Siwftのブリッジの設定を上手くやってくれなくてちょっとハマりました。

RectをベースにしたJavascriptとJSXスタイル。レイアウトがHTML, CSSスタイルで記述でき、Flexboxスタイルで画面対応ができる

これはめっちゃ良かったです。 AndroidStudioのXmlエディタがすごく優秀なのにくらべ、XcodeのStoryboardはめっちゃ使いづらくSnapKitを使ってコードでView書いてたのですがビルドしないと見れないし色々と辛みがありました。 HTML、CSSの知識があれば問題無く書ける感じで非常に良かったです。

HotReload, LiveReload機能がありコードの変更が即時反映される(XcodeやAndroidStudioのビルド待ちが無い)

これもいいですね。実機でも動くのでデバッグがかなり楽です。 AndroidとiOS2つも起動するとLiveReloadは1つだけしか出来ませんが、HotReloadはどちらも使えるのでデバッグが同時にできるのも非常に良かったです。 ただ、まだ結構バグが多くて上手く行かないことも多かったです。

Javascriptが勉強したいんじゃ(個人の気持ちです

勉強になりました。 ReactNativeはES6で書けるのでそっちの勉強にはなります。

ちなみに本を2冊読んでからはじめました。

www.oreilly.co.jp

www.oreilly.co.jp

調査段階のデメリットについて

まだベータ版

ですね。まだまだバグが多いです。 ハマった時になかなか正解に行き着かないのでそういう時間は結構かかりました。 結構デバッグが大変で、Chromeデバッグログの確認とかできるのですがこれをするとめちゃくちゃ重くなります。 iOSChrome使ってますが、Androidadb logcat | grep Reactで見てます。

情報が少ない

公式リファレンス通りに動かないこともあります。

日本での人気をあまり感じない

TweetDeckでKotlinとReactNative垂れ流してるけどKotlinの日本人ツイートめっちゃ多いのにReactNativeは超少ない。 ちょいちょいブログとかで記事見るけどあんまり好印象の記事見ない…

JavascriptもReactも初めて(個人の問題です

大変でした。 とは言っても2日も書いていればなれます。 設計はFluxを使ってるんですが、これもよくわからなくて azuさんの神資料をもとに実装したらなんか理解した感じになったのでよかったです(?)

10分で実装するFlux

感想

全然まとまりないけど雑記だからね!! 両OSを1ソースで書けるけど、今はそこまで開発速度出てないのでネイティブの方が早そう… まぁでも上手くやれば運用は楽かもしれない。 ビルド待ちが無い分開発のストレスは少ない。 以前はてブで話題だった「もうNativeOnly開発者はいらないのかもしれない」というタイトルの記事については、うーん触った感じは真逆な印象。 ぶっちゃけReactNative使ってもちゃんとしたアプリ作りたいならUIKit, AndroidSDKの知識は必須。あとネイティブのAPIも普通に使えなきゃいけないからSwift, Obj-c, Java, Kotlinの知識とかも必要になってくる。 要はチーム編成の問題で、iOSアプリ, Androidアプリ担当がちゃんといるんならそれで済むし、ReactNativeでロジック部分共通化したいってなればiOSネイティブ部分担当とAndroidネイティブ部分担当とReactNativeロジック担当みたいな構成になるのかな(適当

まぁ銀の弾丸は無いってことで。

http://www.jp.square-enix.com/magazine/gansma/gangan/b_ichi/img/comics-03.jpg

B壱 | ガンスマ情報局 | SQUARE ENIX

(ソウルイーター超人気出たけどコイツ出なかったなぁ…)

Kotlin Android Extensionsで注意すること

Android AndroidStudio Kotlin

f:id:saburesan:20160906091652j:plain

とくにハマった訳ではないですがやらかしそうなミスだなぁと思ったので。

Kotlin Android ExtensinsとはViewの参照を自動で作ってくれるAndroidのためのPluginです。

kotlinlang.org

findViewByIdしなくてもID名から自動で参照を作ってくれるので非常に便利です。

f:id:saburesan:20170214104202p:plain

使い方

app以下のbuild.gradleに

apply plugin: 'kotlin-android-extensions'

を追加するだけ。

仕組み

Kotlin側ではR.id.xxxのxxxでViewへアクセスできるので、thisがViewクラスまたはサブクラスの場合、そのViewに対してxxxのIDをfindViewByIdをしているだけです。

Javaデコンパイルするとこんな感じ

ViewPager var7 = (ViewPager)this.findViewById(id.viewPager);

毎回findViewByIdするのはパフォーマンス悪いんじゃないかなーと思ったらキャッシュする機構がちゃんとありました。

...
 private HashMap _$_findViewCache;
...
 public View _$_findCachedViewById(int var1) {
      if(this._$_findViewCache == null) {
         this._$_findViewCache = new HashMap();
      }

      View var2 = (View)this._$_findViewCache.get(Integer.valueOf(var1));
      if(var2 == null) {
         var2 = this.findViewById(var1);
         this._$_findViewCache.put(Integer.valueOf(var1), var2);
      }

      return var2;
   }

   public void _$_clearFindViewByIdCache() {
      if(this._$_findViewCache != null) {
         this._$_findViewCache.clear();
      }

   }
...

この機構ですが、ActivityまたはFragment内でしか使われていないようです。 Viewのサブクラス内だと現状毎回findViewByIdしてるっぽくて、あんまりパフォーマンス良くないようです。 (Fragment無しのViewのサブクラスベースで作ってて後から気づいた…

注意点

インポートに注意

Kotlin Android Extensionsを使うとレイアウトファイルのViewのIDを元に参照できるようにkotlinx.android.synthetic.main.<レイアウト名>.*をインポートしなければいけません。 この時に、複数のレイアウトファイルで同じIDを使っている場合にインポート候補が複数出ます。 もし、間違ったレイアウトをインポートしても静的解析ではエラーは検出出来ません。 仕組みで紹介したようにthisに対してfindViewByIdしているのでViewが無ければヌルポです。

Viewの中でthisが変わった時に注意

Viewのサブクラス内でインナークラスを定義したり、apply, runなどを使ってthisが変わる場合も注意が必要です。 私はapplyで初期値の設定などを行うのですが、

viewPager.apply {
            adapter = pagerAdapter
}
tabLayout.apply {
            addTab(newTab().setText(R.string.item_state_a))
            addTab(newTab().setText(R.string.item_state_b))
            addTab(newTab().setText(R.string.item_state_c))
            viewPager.currentItem = 1
        }

こう書くとonTabSelectedのviewpagerがヌルポで死にます。 applyに渡されたブロック内ではthisがレシーバになるので例ではtabLayoutからviewPagerを探そうとしてヌルポになります。

まとめ

気をつけていればあまり起こることは無いのかもしれないです。 インポートのミスについては気をつけるしかないのですが、 Viewのサブクラス内ではキャッシュされないであるとかthisが変わる際にミスが起きやすいなどの対策としては インスタンス変数として保持するようにするのが一番効果的だと思います。

private val viewPager by lazy { view_pager } //view_pagerはKotlin Android Extensionsの参照

KotlinからJavaのクラスを利用するときにAccessorが上手く生成されないことがある

Android AndroidStudio Java Kotlin

f:id:saburesan:20160906091652j:plain

Kotlin小ネタなんですが、KotlinからJavaのクラスを利用するときにjavaのSetter, GetterメソッドからKotlinのAccecorに自動で変換してくれる機能があります。

例えば、 Java側で

class Text {
...
public void setText(String text) {...}

public String getText() {...}
}

このようなTextクラスをKotlin側で利用する場合

val text = Text()
text.text = "hoge" //setter
text.text              //getter "hoge"が返る

このように使うことが出来ます。

基本的には非常に便利なのですが、Java側のSetter/Getterの定義の仕方で上手く動作しない場合があるようです。

AndroidのEditTextクラスで起きました。

EditTextクラスにはEditable getText(), _setText(Charsequence c)というメソッドがあります。

Setter/Getterで型が違うのですがKotlin側ではtextアクセサが生成されます。

補完にもsetText, getTextは無いです。

f:id:saburesan:20170212233107p:plain

そして型はEditableになっています。

型がEditableになっているのでtextアクセサ経由でStringクラスをセット出来なくなります!!!

AndroidStudio上だとこのようにエラーになります。

f:id:saburesan:20170212231444p:plain

画像見てもらうと分かるように、setText(“”)と書いている部分は警告も何も出ていません。

Kotlinのアクセサが使える場合にJavaのSetter/Getterを書くと画像のgetText()のように黄色い波線で警告が出ます。

f:id:saburesan:20170212231859p:plain

しかし、setText(“”)の方は何も出ていません。

ということはKotlinが生成したtextアクセサのSetterはsetText()と別物と解釈されているということです。

でもtextアクセサとsetTextの定義を見てみるとどちらも同じTextView#setText(Charsequence text)を参照しています。

試しにKotlinバイトコードデコンパイルしてJavaのコードを見てみると…

Kotlin

f:id:saburesan:20170212232717p:plain

Java

f:id:saburesan:20170212232749p:plain

やはり同じでしたね。

わざわざEditableのサブクラスに変換したのにCharsequenceにキャストすんのかい。

とは言え、setText(Editable)という存在しないメソッドがKotlin側で定義されちゃってるようですね。

これはバグなんですかね。

DIY子供の絵本棚

DIY ナフコ Sketch

f:id:saburesan:20170130075220j:plain

設計

Sketchを使って作りました。

f:id:saburesan:20170130075446p:plain

よくある形です。

本棚は3段にして、下はおもちゃ箱です。 扉が開閉します。重いので1歳のうちの子は開けることができないです。

近くのナフコに89mm * 19mm * 183mmの木材が200円で売ってたのでそれで作れる範囲にしました。 また、お得コーナーに60cmカットされてたのが17本あったのでそれも買いました。カット代節約。

木材カットはナフコで1回20円でやってくれます。 183cmから60cmを3本の場合3回必要です。 これを2本やるのですが単純に倍になるわけでは無く、カットする機械に乗れば1回で済むので2本でも3回で済みます。

とか考えてカットする木材の長さは少ないほうがカット代もかからないので、今回の設計では木材は2パターンの長さしか無いです。

工程

写真は撮ってないので無いです。

金額

3000円位。

期間

1日位

感想

設計してからだったのであとは作業でした。

ただ、安い木を使ったのもあって微妙な曲がり具合で調整が必要な箇所が結構ありました。

最終的にいい感じに仕上がって良かったです(適当

子供はなんか珍しそうに見てて、1段目の本を2段目に、2段目の本を3段目に置いて遊んでました。

大人にとってはなんでもない事ですが、子供にとってはそういうことも初めてのことで楽しいんでしょうね。

子供の視点って面白い。

何はともあれ気にってくれてるようで良かった。

f:id:saburesan:20170130142527j:plain

Redash外で閲覧画面を作る

f:id:saburesan:20170112205438p:plain

RedashのDashboardは使いづらいです(個人的には

なぜなら縦横幅が基本固定値で横に最大でも2個しか並べられない仕様だからです。(グラフに関しては縦幅を変更出来ます)

Redashは作ったグラフなどを外部でも表示できる機能を提供しています。

やり方

外部に表示したいクエリの画面へ行き、グラフを選択します。

左したに[Embed]というリンクがあるのでクリックすると

f:id:saburesan:20170118181606p:plain

このような画面がでるので、このiframeのタグか、画像URLをimageタグのsrcとして使うと外部サイトでも読み込むことが出来ます。

iframeと画像での機能の違いを説明します。

iframe

メリット

iframeで読み込む場合、Dashboardと全く同じGUI機能が提供されます。

f:id:saburesan:20170118182449p:plain

リロードも設定どおりで行ってくれるので組み込むのが楽です。

デメリット

iframe自体に縦横の設定は出来ますが、縦横にスクロールする形でスケールされます。

f:id:saburesan:20170118182827p:plain

設置エリアが狭い場合はスクロールして見る必要があります。

画像

メリット

縦横幅は自由に変更出来ます(もちろんアスペクト比がおかしくなると歪みますが)。

f:id:saburesan:20170118184218p:plain

なので、管理画面などで横4つとかならべることもできるので1画面に複数置きたい場合などに便利です。

デメリット

Dashboard上で扱えるようにGUI機能は全くありません。画像ですからね。

更新がされない訳ではなく画像のソース自体は同じURLで更新されるので、反映させるにはページをリロードする必要があります。

まとめ

Redahのグラフを外部で表示する場合のメリット・デメリットを説明しました。 私の会社では1画面に14のグラフを画像で並べて常に表示するディスプレイがあります。更新はJSでリロードさせています。 こういう使い方の場合は画像の方がいいでしょう。 すべてのグラフを使ったことがあるわけではないので多少間違いがあるかもしれません!

RedashのデータソースにGoogleAnalyticsを追加する

f:id:saburesan:20170112205438p:plain

*2017年1月15日現在ではRedashのGoogleAnalytics対応はαバージョンということになっているので、今後方法が変わるかもしれません。

Google Developer Consoleでプロジェクトを作成

console.developers.google.com

f:id:saburesan:20170117151718p:plain

サービスアカウントキーを登録する

左側のナビゲーションの「認証情報」→「認証情報を作成」→「サービスアカウントキー」を選択します。

f:id:saburesan:20170116072001p:plain

「サービスアカウント」は「新しいサービスアカウント」を選びます。

サービスアカウント名を入力してキーはJSONにして「作成」を押してサービスアカウントの作成は完了です。

f:id:saburesan:20170117143435p:plain

この時サービスアカウントIDはメモしておきましょう。 また、JSONファイルがダウンロードされますが、これもRedash連携の時に必要です。

Google Analyticsにサービスアカウントを登録する

連携させたいGoogleAnalyticsの「管理」タブ→「ユーザ管理」からサービスアカウントのメールアドレスのユーザを登録します。 権限は「表示と分析」で大丈夫です。

f:id:saburesan:20170117144242p:plain

これでサービスアカウントとGoogleAnalyticsの連携は完了です。

Redashと連携

ここまでくればあとはRedashのデータソース追加画面で

「Type」を「Google Analytics」にして、GoogleDeveloperConsoleでダウンロードしたJSONファイルをアップロードすれば完了です。

f:id:saburesan:20170117144857p:plain

クエリを作成する

GoogleAnalyticsのクエリは0から作るのは非常に大変なので、QueryExplorerというサービスを使いましょう。

Query Explorer — Google Analytics Demos & Tools

たとえば、1ヶ月分の日次新規ユーザを見たい場合は以下のような入力になります。

f:id:saburesan:20170117151541p:plain

これを入力して「Run Query」を押すと画面したの方に結果が得られますが、 その中の「Direct link to this Report」のGETパラメータ(画像赤枠の部分)をコピーします。

f:id:saburesan:20170117150843p:plain

あとはコピーしたパラメータをRedashの「New Query」でクエリとして保存すれば完了です。

まとめ

RedashとGoogleAnalyticsの連携について解説しました。 ブログ執筆現在ではα版ですので変更が予想されますので上手くいかなくなるかもしれませんがご了承ください。

Redash概要

Analytics Redash SQL

f:id:saburesan:20170112205438p:plain

redash.io

概要

Redashはデータの分析や可視化を効率よく行えるBIツールです。

豊富なデータソースとクエリの登録

Redashは連携データソースとして登録できるソフトウェアやサービスが豊富です。 2017年1月12日現在でこれだけのデータソースに対応しています。 f:id:saburesan:20170112205209p:plain

接続しているデータベースに対してsqlのクエリやAPIのパラメータなどを記録できます。 sqlの場合はカラム名は補完も効くのでクエリを書くのが非常に楽です。 また、snippetを登録できるのでよく使うクエリなどを登録すると補完で使うことが出来ます。

https://redash.io/assets/images/temp/browser1.png Redash公式サイトより転載

可視化が容易

クエリの結果を可視化するときの可視化パターンが豊富です。折れ線グラフやコホート、パイチャートなど大体必要そうなものは揃っています。

https://redash.io/assets/images/temp/browser2.png

Redash公式サイトより転載

外部連携

外部サービスとの連携も容易です。 例えばSlack botにも公式で対応しています。

qiita.com

またグラフなどを外部サービス上で表示する機能も提供されていて、現状はiframeと画像形式で提供されています。 データの可視化に関しては豊富に取り揃えていますが、それらをまとめて閲覧するようの「Dashboard」機能では横1 or 2カラムしか対応しておらず1画面に表示する量が少ないです。 なので閲覧画面のみ自社の管理画面などで自由にカスタマイズすることができます。

新規登録

今回はOSSの方ではなく有料プランの方で勧めます(2017年1月12日現在ではトライアル期間があります) 下記新規登録ページから新規登録します。 https://app.redash.io/signup

フォームを入力するとすぐにDashboardへ遷移します。

Dashboard

f:id:saburesan:20170113070055p:plain

画像はログイン直後の画面です。 今回よく使う機能のみ紹介します。

Dashboards

Dashboardとは複数の可視化したグラフなどを纏めて閲覧できる機能です。 ヘッダーの「Dashboard」ボタンをクリックすると現在作られているDashboardの一覧と新規Dashboardへのリンクが表示されます。

Queries

Queriesは接続したデータソースに対するクエリやパラメータを保存する機能です。 ヘッダーのQueries->New Queryから以下の画面へ遷移します。 f:id:saburesan:20170113071327p:plain

Query編集画面ではクエリの編集とそのクエリの結果をもとにどのように可視化するかの編集ができます(後日解説)

Data source

f:id:saburesan:20170113071923p:plain

データソースを登録出来ます。 私はMySQLとGoogleAnalyticsを使ったことがあります。 MySQLの連携は難しくないですが、GoogleAnalyticsの連携が個人的に色々と結構面倒くさかったので後日まとめたいと思います。 MySQLを登録する場合、RedashはIPアドレス52.71.84.157からMySQLへアクセスするので事前にこのIPからのアクセスを許可する必要があります。

f:id:saburesan:20170113073414p:plain

あとはフォームに必要な項目を入力して接続テストが成功すれば登録完了です。 接続したデータソースからQueryを登録するには、「New Query」画面の「Data Source」の一覧から選択することで可能です。

まとめ

かなりざっとしたRedashのDashboardの紹介になってしまいましたが、今後はもっと細かい機能の使い方を紹介したいと思います。