新手 discover.google.com 砲

この「discover.google.com」からのリファラ。

URLにアクセスしても見つからない。

きっと今後のアクセスの本線になりそうなやつで。

【1日1万PV超えも】Google Chromeオススメコンテンツに掲載される3つのコツ。 | マルチにハマって借金背負って島流し。

discover.google.comとは何?謎の参照元discover.google.com が何かを調べてみた【Googleアナリティスクの使い方】 - 魂を揺さぶるヨ!

辻正浩 | Masahiro Tsujiさんのツイート: "これは、googleapis comが徐々に減ってdiscover google comが増え続けているので、移行してる感じですね。 解析しやすくなるのはいいなあ。どうかこの調子でChrome新タブ以外のDiscover表示エリアもトラッキングできるようにしてください……… https://t.co/9VPQRBKuli"

googleapis.com、discover.google.com(chromeのオススメ欄)のセッションでアクセスアップ、狙い方は? - フリーランスの投資戦略

【ブログ運営記事】あんまり見かけない流入元を調べてみた【気になるアクセス元】 - 胃もたれ沢 吐瀉夫の日常

軽く浴びましましたが、国内キュレーターより感度はいい雰囲気。

要注意です。


【仮想通貨】Cryptowatch Public Market REST API を眺める

キャバ嬢に

「リップル買っちゃった。名前がかわいいし。」

などと言われて即全てを手放しました、おはようございます。

そんな下落が止まらない仮想通貨たち。

仮想通貨全体の上げ下げを把握することができます。

Cryptowatch - live Bitcoin price charts

ここではAPIにてリアルタイムな情報を公開しています。

無料では当然制限はついてきますが。

Public Market REST API - Cryptowatch

いくつか簡単にデータを取得してみましょう。

Prices

Returns the current price for all supported markets. Some values may be out of date by a few seconds.

Example: https://api.cryptowat.ch/markets/prices

価格です。量が多いので日本円絡みのものだけ見てみます。


~ $ curl -s https://api.cryptowat.ch/markets/prices | jq "." | grep jpy
    "bitflyer:btcfxjpy": 990450,
    "bitflyer:btcjpy": 980519,
    "bitflyer:btcjpy-biweekly-futures": 984440,
    "bitflyer:btcjpy-weekly-futures": 984750,
    "bitmex:btcjpy-quarterly-futures": 9342,
    "kraken:btcjpy": 980085,
    "kraken:ethjpy": 102171,
    "kraken:repjpy": 0,
    "kraken:xrpjpy": 0,
    "kraken:zecjpy": 0,
    "quoine:bchjpy": 139770.97,
    "quoine:btcjpy": 1010138.75,
    "quoine:ethjpy": 107000,

いくつかは価格が「0」となっていますが。

JSON形式で、項目としては


"(取引所):(通貨ペア)": 価格円

が取得できるようです。

もうひとつみてみます。

Asset
Returns a single asset. Lists all markets which have this asset as a base or quote.

Example: https://api.cryptowat.ch/assets/btc

こちらでは以下のようなものが取得できます。


~ $ curl -s https://api.cryptowat.ch/assets/jpy | jq '.'
{
  "result": {
    "id": 104,
    "symbol": "jpy",
    "name": "Japanese Yen",
    "fiat": true,
    "markets": {
      "quote": [
        {
          "id": 89,
          "exchange": "kraken",
          "pair": "btcjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/kraken/btcjpy"
        },
        {
          "id": 100,
          "exchange": "kraken",
          "pair": "ethjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/kraken/ethjpy"
        },
        {
          "id": 120,
          "exchange": "kraken",
          "pair": "repjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/kraken/repjpy"
        },
        {
          "id": 126,
          "exchange": "kraken",
          "pair": "zecjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/kraken/zecjpy"
        },
        {
          "id": 140,
          "exchange": "kraken",
          "pair": "xrpjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/kraken/xrpjpy"
        },
        {
          "id": 184,
          "exchange": "quoine",
          "pair": "btcjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/quoine/btcjpy"
        },
        {
          "id": 196,
          "exchange": "quoine",
          "pair": "ethjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/quoine/ethjpy"
        },
        {
          "id": 206,
          "exchange": "quoine",
          "pair": "bchjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/quoine/bchjpy"
        },
        {
          "id": 215,
          "exchange": "bitflyer",
          "pair": "btcjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/bitflyer/btcjpy"
        },
        {
          "id": 217,
          "exchange": "bitflyer",
          "pair": "btcjpy-weekly-futures",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/bitflyer/btcjpy-weekly-futures"
        },
        {
          "id": 218,
          "exchange": "bitflyer",
          "pair": "btcjpy-biweekly-futures",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/bitflyer/btcjpy-biweekly-futures"
        },
        {
          "id": 409,
          "exchange": "bitflyer",
          "pair": "btcfxjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/bitflyer/btcfxjpy"
        },
        {
          "id": 248,
          "exchange": "bitmex",
          "pair": "btcjpy-quarterly-futures",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/bitmex/btcjpy-quarterly-futures"
        },
        {
          "id": 424,
          "exchange": "bitmex",
          "pair": "btcjpy-monthly-futures",
          "active": false,
          "route": "https://api.cryptowat.ch/markets/bitmex/btcjpy-monthly-futures"
        }
      ]
    }
  },
  "allowance": {
    "cost": 162263,
    "remaining": 7999837737
  }
}

これを見ると個別のチャートを参照できるURLは


https://api.cryptowat.ch/markets/(取引所)/(通貨ペア)

であることがわかります。

他にもたくさんのデータが取得できるようです。

さあ、みんなもやってみよう。

 

👉 Kotlin 今どきよくある JSON リクエストからのパース hatena-bookmark


FCM と Notification の併用をやめてバックグラウンド受信時にうれしがる

ややこしすぎな気がします。

この記事のタイトルも書いてて意味不明です。

以下のような、FCMにJSONをPOSTしてアプリで受ける場合の話です。


curl https://fcm.googleapis.com/fcm/send -X POST \
--header "Authorization: key=FirebaseConsoleのプロジェクトの設定、クラウドメッセージングのタブにあるサーバーキー" \
--Header "Content-Type: application/json" \
 -d '
 {
   "to":"/topics/all",
   "data":{
     "title":"New Notification!",
     "body":"Test"
   },
   "priority":"high"
 }'

このPOSTするJSONに含まれるデータ構造によって、アプリ側で受信する場合の処理の流れ変わって見通しが悪くなります。

きれいにまとめられています。

Firebase Notificationでアプリの状態による挙動の違いについて - Qiita

アプリがフォアグラウンドにある場合、このServiceのonMessageReceived()が呼び出されることになります。

アプリがバックグラウンドにある場合はこのonMessageReceived()は呼ばれることはなく、システム側で自動的にシステムトレイに通知を表示します。

"data"ブロックはConsoleからも含めることはできます(詳細オプションのカスタムデータで指定できる)。しかし、Consoleでは"notification"ブロックを省略することができません(メッセージ文を入力しないと送信できない)。

送信したメッセージに"data"ブロックがあっても、"notification"ブロックが存在する限り、アプリがバックグラウンドにある状態ではFirebaseMessagingServiceのonMessageReceived()は呼ばれません。

"data"ブロックの内容を受け取れないわけではありません。通知をクリックして起動したActivityのintentに含まれることになります。

"data"ブロックの内容の処理が、フォアグラウンド時に受け取ったときはFirebaseMessagingServiceで、バックグラウンドのときにはActivityでとなってしまって煩雑です。

実際に試してみると、これら書かれてることすごく良く分かります。

結局、この"notification"ブロックの特典としては、

アプリがバックグラウンド状態で受信した場合にのみ、アプリ側の実装なしで通知トレイに入る。

ということだけでしょうか、おおまかですが。

すべてのメッセージ受信時にonMessageReceived()が呼び出されれば、アプリがフォアグラウンドにあるかバックグラウンドにあるかを気にする必要がなくなります。

なるほど。

では、入れ子にしたらいいんじゃないかと。

例えば、


{
  // ...

  "notification": {
    "title" : "News!!",
    "body" : "New Product Release!!"
  },

  "data": {
    "user": "Yamada Taro",
    "age": 20
  },

  // ...
}

を以下のように入れ子にする。


{
  // ...

  "data": {
    "user": "Yamada Taro",
    "age": 20,

    "notification": {
      "title" : "News!!",
      "body" : "New Product Release!!"
    }

  },

  // ...
}

すべてサービスで受けることができます。


class  MyFirebaseMessagingService : FirebaseMessagingService() {

  override fun onMessageReceived(message: RemoteMessage) {

    // ...

    // 2層目以下はStringで送られてくるのでMap化
    message.data["notification"]?.let {
      val notification : Map<String, String> =
        Gson().fromJson(it, object : TypeToken<HashMap<String, String>>() {}.type)
      sendNotification(notification)
    }

  }

  // サンプルを参考に
  private fun sendNotification(notification: Map<String, String>) {
    val intent = Intent(this, MainActivity::class.java)
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)

    val pendingIntent = PendingIntent.getActivity(this, 0, intent,
        PendingIntent.FLAG_ONE_SHOT)

    val channelId = getString(R.string.default_notification_channel_id)
    val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
    val notificationBuilder = NotificationCompat.Builder(this, channelId)
        .setSmallIcon(android.R.drawable.ic_notification_overlay)
        .setContentTitle(notification["title"])
        .setContentText(notification["body"])
        .setAutoCancel(true)
        .setSound(defaultSoundUri)
        .setContentIntent(pendingIntent)

    val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

    notificationManager.notify(0, notificationBuilder.build())
  }

quickstart-android/MyFirebaseMessagingService.java at master · firebase/quickstart-android

元々、Firebase てのは、敷居を下げてマーケティングなどに利用を広めようとしてるのかな。