モバイルから収集する

モバイルプラットフォーム上で、Flipで分析するために必要なデータを収集する方法を紹介します。

1. 関数を定義する

初めに、後のステップで利用する関数を定義します。これらの関数はHTTP APIをベースに作成されています。

  • 下のコードを、適当なファイルにコピー&ペーストして下さい。

🚧

現時点では、匿名ユーザーのID(anonymousId)を作成・格納するロジックは実装されていません。実装方法が分かる方がいましたら、[email protected]までご連絡ください。

import Foundation

class Flip {
  let INGESTION_KEY = "プロジェクトの収集キー" // プロジェクトの設定画面に表示されている値に変更して下さい
  let TRACK_ENDPOINT = "https://app.flip.inc/v1/track"
  let IDENTIFY_ENDPOINT = "https://app.flip.inc/v1/identify"
  
  static let shared = Flip()
  
  private init() {}
  
  func track(name: String,
             userId: String? = nil,
             anonymousId: String? = nil,
             properties: [String: Any]? = nil,
             userProperties: [String: Any]? = nil) {
    var updatedUserProperties = userProperties ?? [:]
    updatedUserProperties["platform"] = "ios"

    post(endpoint: TRACK_ENDPOINT, requestBody: [
			"name": name,
			"originalUserId": userId ?? NSNull(),
			"anonymousId": anonymousId ?? NSNull(),
			"properties": properties ?? NSNull(),
			"userProperties": updatedUserProperties
    ])
  }

  func identify(userId: String? = nil,
                anonymousId: String? = nil,
                properties: [String: Any]? = nil) {
    var updatedProperties = properties ?? [:]
    updatedProperties["platform"] = "ios"

    post(endpoint: IDENTIFY_ENDPOINT, requestBody: [
			"originalUserId": userId ?? NSNull(),
			"anonymousId": anonymousId ?? NSNull(),
			"properties": updatedProperties
    ])
  }
  
  private func post(endpoint: String, requestBody: [String: Any]) {
    guard let url = URL(string: endpoint) else {
      print("[Flip] Invalid URL")
      return
    }
    
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    
    var updatedRequestBody = requestBody
    updatedRequestBody["ingestionKey"] = INGESTION_KEY
    
    do {
      request.httpBody = try JSONSerialization.data(withJSONObject: updatedRequestBody, options: [])
    } catch {
      print("[Flip] \(error)")
      return
    }
    
    let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
      if let error = error {
        print("[Flip] \(error)")
        return
      }
      
      if let httpResponse = response as? HTTPURLResponse, !(200...299).contains(httpResponse.statusCode), let data = data {
        do {
          if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let message = json["message"] as? String {
            print("[Flip] \(httpResponse.statusCode) \(message)")
          }
        } catch {
          print("[Flip] \(error)")
        }
      }
    }
    task.resume()
  }
}

import java.net.HttpURLConnection
import java.net.URL
import org.json.JSONObject

class Flip private constructor() {
  companion object {
    private const val INGESTION_KEY = "プロジェクトの収集キー" // プロジェクトの設定画面に表示されている値に変更して下さい
    private const val TRACK_ENDPOINT = "https://app.flip.inc/v1/track"
    private const val IDENTIFY_ENDPOINT = "https://app.flip.inc/v1/identify"
		
    val shared = Flip()
  }

  fun track(
    name: String,
    userId: String? = null,
    anonymousId: String? = null,
    properties: Map<String, Any>? = null,
    userProperties: Map<String, Any>? = null
  ) {
    val body = mutableMapOf(
   		"name" to name,
      "originalUserId" to userId,
      "anonymousId" to anonymousId,
      "properties" to properties,
      "userProperties" to (userProperties?.plus("platform" to "android") ?: mapOf("platform" to "android"))
    )
    post("https://app.flip.inc/v1/track", body)
  }

  fun identify(
    userId: String? = null,
    anonymousId: String? = null,
    properties: Map<String, Any>? = null
  ) {
    val body = mutableMapOf(
			"originalUserId" to userId,
			"anonymousId" to anonymousId,
			"properties" to (properties?.plus("platform" to "android") ?: mapOf("platform" to "android"))
    )
    post("https://app.flip.inc/v1/identify", body)
  }
  
  private fun post(endpoint: String, requestBody: Map<String, Any>) {
		val url = URL(endpoint)
	  val connection = url.openConnection() as HttpURLConnection
    
    try { 
      connection.requestMethod = "POST"
      connection.setRequestProperty("Content-Type", "application/json")
      connection.doOutput = true
      
      val body = JSONObject(requestBody.plus("ingestionKey" to INGESTION_KEY))
      connection.outputStream.write(body.toString().toByteArray(Charsets.UTF_8))

      val responseCode = connection.responseCode
      if (responseCode !in 200..299) {
        val response = connection.inputStream.bufferedReader().use { it.readText() }
        val jsonResponse = JSONObject(response)
        val message = jsonResponse.optString("message")
        println("[Flip] $responseCode $message")
      }
    } catch (e: Exception) {
      println("[Flip] $e")
    } finally {
      connection.disconnect()
    }
  }
}
import "dart:convert";
import "dart:io";

class Flip {
  final String INGESTION_KEY = "プロジェクトの収集キー"; // プロジェクトの設定画面に表示されている値に変更して下さい
  final String TRACK_ENDPOINT = "https://app.flip.inc/v1/track";
  final String IDENTIFY_ENDPOINT = "https://app.flip.inc/v1/identify";
  
  static final Flip _singleton = Flip._internal();

  factory Flip() {
    return _singleton;
  }

  Flip._internal();

  void track(
    String name,
    String? userId,
    String? anonymousId,
    Map<String, dynamic>? properties,
    Map<String, dynamic>? userProperties
  ) {
    _post(TRACK_ENDPOINT, {
      "name": name,
      "originalUserId": userId,
      "anonymousId": anonymousId,
      "properties": properties,
      "userProperties": {
        ...?userProperties,
        "platform": "flutter",
      },
    });
  }

  void identify(
    String? userId,
    String? anonymousId,
    Map<String, dynamic>? properties
  ) {
    _post(IDENTIFY_ENDPOINT, {
      "originalUserId": userId,
      "anonymousId": anonymousId,
      "properties": {
        ...?properties,
        "platform": "flutter",
      },
    });
  }
  
  Future<void> _post(
    String endpoint,
    Map<String, dynamic> requestBody
  ) async {
    var url = Uri.parse(endpoint);
    var client = HttpClient();

    try {
      var request = await client.postUrl(url);
      request.headers.contentType = ContentType.json;
      request.write(json.encode({
        ...requestBody,
        "ingestionKey": INGESTION_KEY,
      }));
      
      var response = await request.close();

      if (response.statusCode != 200) {
        var responseBody = await response.transform(utf8.decoder).join();
        var jsonResponse = json.decode(responseBody);
        var message = jsonResponse["message"];
        print("[Flip] ${response.statusCode} $message");
      }
    } catch (e) {
      print("[Flip] $e");
    } finally {
      client.close();
    }
  }
}

2. イベントを収集する

イベントを収集することで、ユーザーの一つ一つの操作を記録できるようになります。各引数の具体的な役割に関しては、HTTP APIを参考にして下さい。

  • ユーザーが特定の操作を実行した直後(例. 機能を利用)に、次のコードが呼ばれるようにペーストして下さい。コードの内容は自由に変更して構いません。
Flip.shared.track(
  name: "message_sent",
  userId: "usr_GXfryD0JQivyGa97TgGsT",
  anonymousId: nil,
  properties: [
    "message_type": "画像付きテキスト",
    "character_count": 32
  ],
  userProperties: [
    "email": "[email protected]",
    "name": "Tanaka Masaki",
    "position": "プロダクトマネージャー"
  ]
)
Flip.shared.track(
  name = "message_sent",
  userId = "usr_GXfryD0JQivyGa97TgGsT",
  anonymousId = null,
  properties = mapOf(
    "message_type" to "画像付きテキスト",
    "character_count" to 32
  ),
  userProperties = mapOf(
    "email" to "[email protected]",
    "name" to "Tanaka Masaki",
    "position" to "プロダクトマネージャー"
  )
)
Flip().track(
  "message_sent",
  "usr_GXfryD0JQivyGa97TgGsT",
  null,
  {
    "message_type": "画像付きテキスト",
    "character_count": 32
  },
  {
    "email": "[email protected]",
    "name": "Tanaka Masaki",
    "position": "プロダクトマネージャー"
  },
);

3. ユーザー情報を更新する

下のコードを追加することで、イベントを収集することなく、特定のユーザーの情報を更新できます。各引数の具体的な役割に関しては、HTTP APIを参考にして下さい。

  • ユーザーの情報が変更された直後(例. 新規登録・オンボーディング)に、次のコードが呼ばれるように下のコードをペーストして下さい。コードの内容は自由に変更して構いません。
Flip.shared.identify(
  userId: "usr_GXfryD0JQivyGa97TgGsT",
  anonymousId: nil,
  properties: [
    "email": "[email protected]",
    "name": "Tanaka Masaki",
    "position": "プロダクトマネージャー"
  ]
)
Flip.shared.identify(
  userId = "usr_GXfryD0JQivyGa97TgGsT",
  anonymousId = null,
  properties = mapOf(
    "email" to "[email protected]",
    "name" to "Tanaka Masaki",
    "position" to "プロダクトマネージャー"
  )
)
Flip().identify(
  "usr_GXfryD0JQivyGa97TgGsT",
  null,
  {
    "email": "[email protected]",
    "name": "Tanaka Masaki",
    "position": "プロダクトマネージャー"
  },
);