C SDK 使用说明

在使用前,請先閱讀 數據模型 的介绍。

1. 整合神策分析 SDK

開發者可以在 C 程式中整合 神策分析 SDK,使用神策分析採集並分析用戶數據。

從 GitHub 下載 神策分析 SDK 的原始碼,可在本地編譯,透過靜態庫的形式加入專案中,也可以直接將來源檔案引入專案中。 SDK 原始碼包括:

./LICENSE
./Makefile 				// Makefile
./sensors_analytics.h 	// SDK 頭檔案
./sensors_analytics.c 	// SDK 來源檔案
./demo.c 				// Demo 程式,使用 LoggingConsumer 將 log 檔輸出到本機硬碟
CPP

開發者編譯 SDK 後,會產生靜態庫:

./output/include/sensors_analytics.h
./output/lib/libsensorsanalytics.a
CPP

SDK 符合 ANSI C99 規範,部分功能依賴 POSIX 函式庫,不依賴第三方函式庫。

開發者透過 C SDK 在程式中記錄用戶行為數據。 SDK 將格式化的行為數據以 log 檔的形式輸出到本地硬碟檔案中,開發者需要透過神策分析LogAgent 工具 將 log 檔傳輸到神策分析中。LogAgent 工具 確保 log 傳輸的時效性和完整性。

2. 初始化神策分析 SDK

在程式中使用

// 初始化神策分析物件
//
//  @param consumer<in>         log數據的“消費”方式
//  @param sa<out>              初始化的神策分析執行個體
//
// @return SA_OK 初始化成功,否則初始化失敗
int sa_init(struct SAConsumer* consumer, struct SensorsAnalytics** sa);
CPP

初始化神策分析執行個體,透過它實作 SDK 各項功能。其中第一個參數 consumer 物件負責“消費”用戶行為 log,在程式中使用

// 初始化 Logging Consumer
//
//  @param file_name<in>    log 檔案名,例如: /data/logs/http.log
//  @param consumer<out>    SALoggingConsumer 執行個體
//
// @return SA_OK 初始化成功,否則初始化失敗
int sa_init_logging_consumer(const char* file_name, SALoggingConsumer** consumer);
CODE

初始化 SALoggingConsumer  執行個體,它負責將用戶行為 log 輸出到本地磁碟。


// 初始化 SALogingConsumer 執行個體
SALoggingConsumer* consumer = NULL;
if (SA_OK != sa_init_logging_consumer("./demo.out", &consumer)) {
    fprintf(stderr, "Failed to initialize the consumer.");
    return 1;
}

SensorsAnalytics *sa = NULL;
if (SA_OK != sa_init(consumer, &sa)) {
    fprintf(stderr, "Failed to initialize the SDK.");
    return 1;
}

// ... 使用神策分析進行各種操作

// 將本地快取的數據同步到檔案或 Sensors Analtycis 中
sa_flush(sa);
// 釋放 Sensors Analtycis 執行個體
sa_free(sa);
CPP


3. 追蹤事件

首次接入神策分析時,建議先追蹤 3~5 個關鍵的事件,只需要幾行程式碼,便能體驗神策分析的分析功能。例如:

  • 圖片社交產品,可以追蹤用戶瀏覽圖片和評論事件
  • 電商產品,可以追蹤用戶註冊、瀏覽商品和下訂單等事件

用戶透過

// 跟蹤一個用戶的行為
//
//  @param distinct_id<in>      用戶ID
//  @param event<in>            事件名稱
//  @param properties<in>       事件屬性,SAProperties 物件,NULL表示無事件屬性
//  @param sa<in/out>           SensorsAnalytics 執行個體
//
// @return SA_OK 追蹤成功,否則追蹤失敗
#define sa_track(distinct_id, event, properties, sa)
CPP

介面記錄事件。開發者必須傳入用戶 ID(distinct_id)和事件名(event)兩個參數,標記用戶和事件名稱,同時,開發者可以在第三個參數傳入一個 SAProperties 物件,為事件增加自定義事件屬性,傳入 NULL 表示無自定義事件屬性,在自定義屬性中需要包含 $is_login_id 屬性來說明 distinct_id 是否為登入 ID。以電商產品為例,可以這樣追蹤一次購物行為:

// 記錄用戶提交訂單事件

// 初始化事件屬性
properties = sa_init_properties();
if (NULL == properties) {
    fprintf(stderr, "Failed to initialize the properties.");
    return 1;
}

// 增加作業系統屬性,透過請求中的UA,可以解析出用戶使用裝置的作業系統是 iOS
assert(SA_OK == sa_add_string("$os", "iOS", strlen("iOS"), properties));
// 增加作業系統版本屬性
assert(SA_OK == sa_add_string("$os_version", "10.0.0", strlen("10.0.0"), properties));
// 增加 IP 網址屬性,$ip 是預設屬性,神策分析會自動根據這個解析省份、城市
assert(SA_OK == sa_add_string("$ip", "123.123.123.123", strlen("123.123.123.123"), properties));
// 增加商品名稱屬性
assert(SA_OK == sa_add_string("product_name", "XX手机", 8, properties));
// 增加商品價格屬性
assert(SA_OK == sa_add_number("product_price", 5888, properties));
//  $is_login_id 屬性判斷 distinct_id 是否為登入 ID,如果是則設定為 SA_TRUE,否則為 SA_FALSE,預設為 SA_FALSE
assert(SA_OK == sa_add_bool("$is_login_id", SA_TRUE, properties);
// 記錄購買商品事件
assert(SA_OK == sa_track(cookie_id, "SubmitOrder", properties, sa));

// 釋放事件屬性執行個體
sa_free_properties(properties);
CPP

3.1 事件屬性

如前文中的範例,開發者追蹤的事件可以自定義事件的屬性,例如購買商品事件中,將商品 ID、商品分類等資訊作為事件屬性。在後續的分析工作中,事件屬性可以作為統計過濾條件使用,也可以作為維度進行多維分析。對於事件屬性,神策分析有一些限制:

  • 事件屬性是一个 SAProperties 對象,SDK 提供介面由開發者進行初始化和釋放;
  • SAProperties 中每個元素描述一個事件屬性,屬性名稱必需是字串型別,以大小寫字母開頭,由字母和數字組成,長度不超過100個字元;
  • SAProperties 中元素的值為事件屬性值,支援 StringNumberBoolList 和 Date,對於神策分析中事件屬性的更多限制,請參考 數據格式

開發者可以透過以下介面,向 SAProperties 物件加入屬性值,如加入 Bool 型別的屬性:

// 向事件屬性或用戶屬性增加 Bool 型別的屬性
//
// @param key<in>           屬性名稱
// @param bool_<in>         SABool 物件,屬性值
// @param properties<out>   SAProperties 物件
//
// @return SA_OK 增加成功,否則失敗
int sa_add_bool(const char* key, SABool bool_, SAProperties* properties);
CPP

其中屬性名稱必須為大小寫字母開頭、長度不超過100的由字母和數字組成的字串。加入 Number 型別的屬性:

// 向事件屬性或用戶屬性增加 Number 型別的屬性
//
// @param key<in>           屬性名稱
// @param number_<in>       屬性值
// @param properties<out>   SAProperties 對象
//
// @return SA_OK 增加成功,否則失败
int sa_add_number(const char* key, double number_, SAProperties* properties);
CPP

加入 Date 型別的屬性,其中第一個參數為單位為秒的時間戳,如系統函數 time(NULL) 的回傳值,第二個參數為毫秒部分:

// 向事件属性或用戶屬性增加 Date 型別的屬性
//
// @param key<in>           屬性名稱
// @param seconds<in>       時間戳,單位為秒
// @param microseconds<in>  時間戳中毫秒部分
// @param properties<out>   SAProperties 物件
//
// @return SA_OK 增加成功,否則失敗
int sa_add_date(const char* key, time_t seconds, int microseconds, SAProperties* properties);
CPP

加入String 型別的屬性,字串必須為 UTF-8 編碼,字串長度為實際的 UTF-8 長度,如一個中文字佔 3 個位元組:

// 向事件屬性或用戶屬性增加 String 型別的屬性
//
// @param key<in>           屬性名稱
// @param string_<in>       字串的 Handle
// @param length<in>        字串長度
// @param properties<out>   SAProperties 物件
//
// @return SA_OK 增加成功,否則失敗
CPP

向 List 型別的屬性中增加 String 物件:

// 向事件屬性或用戶屬性的 List 型別的屬性中插入新物件,物件必須是 String 型別的
//
// @param key<in>           屬性名稱
// @param string_<in>       字串的 Handle
// @param length<in>        字串長度
// @param properties<out>   SAProperties 物件
//
// @return SA_OK 增加成功,否則失敗
int sa_append_list(
        const char* key,
        const char* string_,
        unsigned int length,
        SAProperties* properties);
CPP

具體使用方式,可以參考上一節中的範例。

3.1.1 系统預設屬性

如前文中範例,事件屬性中以 '$' 開頭的屬性為系統預設屬性,在自定義事件屬性中填入對應 '$' 開頭的屬性值可以覆蓋這些預設屬性:

  • $ip - 透過 sa_add_string() 向 SAProperties 物件加入該屬性,神策分析會自動根據 IP 網址解析用戶的省份、城市資訊;
  • $time - 透過 sa_add_date()SAProperties 物件加入該屬性,神策分析將事件時間設定為屬性值的時間。請注意,神策分析預設會過濾忽略 2 年前或 1 小時後的數據,如需修改這個限制請聯繫我們的技術支援。

關於其他更多預設屬性,請參考 數據格式 中 '預設屬性' 一節。

4. 用戶識別

在伺服器端應用中,神策分析也要求為每个事件設定用戶的 Distinct Id,這有助於神策分析提供更準確的留存率等數據。

對於註冊用戶,推薦使用系统中的用戶 ID 作為 Distinct Id,不建議使用用戶名、Email、手機號碼等可以被修改的資訊。

4.1 用戶註冊/登入

當同一個用戶的 Distinct Id 發生變化時(一般情況為匿名用戶註冊行為),可以透過

// 關聯匿名用戶和註冊用戶
//
// @param distinct_id<in>       用戶的註冊 ID
// @param origin_id<in>         被關聯的用戶匿名 ID
// @param properties<in>        事件屬性
// @param sa<in/out>            SensorsAnalytics 物件
//
// @return SA_OK 追蹤關聯事件成功,否則失敗
#define sa_track_signup(distinct_id, origin_id, properties, sa)
CPP

將舊的 Distinct Id 和新的 Distinct Id 關聯,以確保用戶分析的準確性。例如:

// 初始化神策分析 SDK ...

// 用戶未註冊前的匿名 ID (匿名 ID 由前端傳過來)
const char* anonymous_id = '9771C579-71F0-4650-8EE8-8999FA717761';
# 未註冊前的匿名用戶瀏覽商品
assert(SA_OK == sa_track(anonymous_id, "ViewProduct", NULL, sa));

properties = sa_init_properties();
if (NULL == properties) {
    fprintf(stderr, "Failed to initialize the properties.");
    return 1;
}

// 向事件屬性增加用戶的註冊管道
assert(SA_OK == sa_add_string("register", "Baidu", 5, properties));

// 用戶註冊 ID
const char* login_id = "abcdefg";

// 關聯註冊用戶與匿名用戶
assert(SA_OK == sa_track_signup(login_id, anonymous_id, properties, sa));

// 釋放事件屬性
sa_free_properties(properties);
CPP

注意,對同一個用戶,sa_track_signup() 一般情況下建議只呼叫一次(通常在用戶 註冊 時呼叫),用戶 登入 前後的行為的關聯建議在業務端實作。在神策分析 1.13 版本之前,多次呼叫 sa_track_signup() 时,只有第一次關聯行為是有效的。神策分析 1.13 版本之後提供了多裝置 id 關聯的方法。更詳細的說明請參考 標識用戶,並在必要時聯繫我們的技術支援人員。

5. 設定用戶屬性

為了更準確地提供針對人群的分析服務,神策分析 SDK 可以設定用戶屬性,如年齡、性別等。用戶可以在留存分析、分佈分析等功能中,使用用戶屬性作為過濾條件或以用戶屬性作為維度進行多維分析。使用

// 設定用戶屬性,如果某個屬性已經在該用戶的屬性中存在,則覆蓋原有屬性
//
// @param distinct_id<in>       用戶 ID
// @param properties<in>        用戶屬性
// @param sa<in/out>            SensorsAnalytics 物件
//
// @return SA_OK 設定成功,否則失敗
#define sa_profile_set(distinct_id, properties, sa)
CPP

設定用戶屬性,例如在電商應用中,用戶註冊時,填入了一些個人資訊,可以用Profile介面記錄下來:

properties = sa_init_properties();
if (NULL == properties) {
    fprintf(stderr, "Failed to initialize the properties.");
    return 1;
}

// 用戶的註冊管道
assert(SA_OK == sa_add_string("register", "Baidu", 5, properties));
// 用戶註冊日期
assert(SA_OK == sa_add_date("$signup_time", time(NULL), 0, properties));
// 用戶是否購買過商品
assert(SA_OK == sa_add_bool("is_vip", SA_FALSE, properties));
// $is_login_id 屬性判斷 distinct_id 是否為登入 ID,如果是則設定為 SA_TRUE,否則為 SA_FALSE,預設為 SA_FALSE
assert(SA_OK == sa_add_bool("$is_login_id", SA_TRUE, properties);

// 設定用戶屬性
assert(SA_OK == sa_profile_set(login_id, properties, sa));

sa_free_properties(properties);
CPP

對於不再需要的用戶的一個屬性,可以透過

// 刪除某用戶的一個屬性
//
// @param distinct_id<in>       用戶 ID
// @param key<in>               用戶屬性名稱
// @param sa<in/out>            SensorsAnalytics 物件
//
// @return SA_OK 設定成功,否則失敗
#define sa_profile_unset(distinct_id, key, sa)
CPP

介面將屬性刪除。也可以透過

// 刪除某用戶所有屬性
//
// @param distinct_id<in>       用戶 ID
// @param sa<in/out>            SensorsAnalytics 物件
//
// @return SA_OK 設定成功,否則失敗
#define sa_profile_delete(distinct_id, sa)
CPP

介面將某個用戶的所有屬性刪除。

用戶屬性中,屬性名稱與屬性值的約束條件與事件屬性相同,詳細說明請參數據格式

5.1 記錄初次設定的属性

對於只在首次設定時有效的屬性,我們可以使用

// 設定用戶屬性,如果某個屬性已經在該用戶的屬性中存在,則忽略該操作
//
// @param distinct_id<in>       用戶 ID
// @param properties<in>        用戶屬性
// @param sa<in/out>            SensorsAnalytics 物件
//
// @return SA_OK 設置成功,否則失败
#define sa_profile_set_once(distinct_id, properties, sa)
CPP

介面記錄這些屬性。與 sa_profile_set() 介面不同的是,如果被設定的用戶屬性已存在,則這條記錄會被忽略而不會覆蓋已有數據>,如果屬性不存在則會自動建立。因此,sa_profile_set_once() 比較適用於為用戶設定首次啟用時間、首次註冊時間等屬性。例如:

// 記錄用戶首次登入時間
properties = sa_init_properties();
if (NULL == properties) {
    fprintf(stderr, "Failed to initialize the properties.");
    return 1;
}

// 用戶首次使用時間
assert(SA_OK == sa_add_date("first_time", time(NULL), 0, properties));

//  $is_login_id 屬性判斷 distinct_id 是否為登入 ID,如果是則設定為 SA_TRUE,否則為 SA_FALSE,預設為 SA_FALSE
assert(SA_OK == sa_add_bool("$is_login_id", SA_TRUE, properties);

// 記錄用戶屬性
assert(SA_OK == sa_profile_set_once(cookie_id, properties, sa));

sa_free_properties(properties);
CPP

5.2 數值型別的屬性

對於數值型的用戶屬性,可以使用

// 增加或減少用戶屬性中的 Number 型別屬性的值
//
// @param distinct_id<in>       用戶 ID
// @param properties<in>        用戶屬性,必須為 Number 型別的屬性
// @param sa<in/out>            SensorsAnalytics 物件
//
// @return SA_OK 設定成功,否則失敗
#define sa_profile_increment(distinct_id, properties, sa)
CPP

對屬性值進行累加。常用於記錄用戶付費次數、付費額度、積分等屬性。例如:

// 在用戶屬性中記錄用戶支付金額
properties = sa_init_properties();
if (NULL == properties) {
    fprintf(stderr, "Failed to initialize the properties.");
    return 1;
}

// 累加用戶支付金額
assert(SA_OK == sa_add_number("pay", 5888, properties));
// 用戶獲得頭銜
assert(SA_OK == sa_append_list("title", "VIP", 3, properties));

// 記錄搜尋商品事件
assert(SA_OK == sa_profile_increment(login_id, properties, sa));

sa_free_properties(properties);
CPP

5.3 列表型別的屬性

對於用戶喜愛的電影、用戶評價過的餐廳等屬性,可以透過

// 向用戶屬性中的 List 屬性增加新元素
//
// @param distinct_id<in>       用戶 ID
// @param properties<in>        用戶屬性,必須為 List 型別的屬性
// @param sa<in/out>            SensorsAnalytics 物件
//
// @return SA_OK 設定成功,否則失敗
#define sa_profile_append(distinct_id, properties, sa)
CPP

介面記錄列表型屬性。需要注意的是,列表型屬性中的元素必須為 String 類型,且元素的值會自動去重。關於列表型別限制請見 數據格式 7.3 屬性長度限制

介面範例請參考前一節中的程式碼。