一般应用都会集成用户行为统计,现在比较常用的就是友盟统计,Google Analytics,Flurry,MixPanel,由于工作需要,公司需要有自己的特殊需求,所以就仿照友盟写了一个自己公司的用户行为统计。 统计部分简单demo:https://github.com/niuxianbin/XBUsecActionStatistics
统计信息量很大,因此需要用的数据库,iOS当然就sqlite。统计的用户行为信息很多 ,比如:用户行为发生的时间,用户是匿名还是登录用户,用户是浏览还是点击,点击的是哪个界面等等很多,当然这些需求是更具公司的需求来的,以下使我们公司统计的用户行为部分参数(参数过多已删减):
dateCreate | 创建时间 |
userId |
用户ID 如果是匿名用户 值是机器码 否则填用户 ID |
anonymous | 匿名用户 true|false |
actionType | 1:浏览 2:点击 3:访问 4:刷新 |
label | 1:按钮 2:品牌 3:商品 4:分类 5:主题 6:广告 7:精品分类 |
dataSource | 1:pc 2:h5 3:android 4:ios |
pageId | 1:品牌商品列表 2:大图 3:品牌列表 4:发现 5:分类列表 6:分类商品列表 7:左侧分类列表 8:分类品牌 9:主题列表 10:主题商品列表 |
tgtId | 目标ID label为1时填0 label为3时填商品ID label为2时填品牌ID label为4时填分类ID label为5时填主题ID label为6时填广告ID label为7时填精品分类ID |
channel | 渠道名称 |
parentPageId | 上级页面 |
parentTgtId | 上级目标ID |
device | 设备型号 |
这个表对应得字段就是你用SQLite建的表的需要一一对应的字段,每当用户点击某一个对应的位置,就向本地数据库存储相应的一条记录。后台一般会提供一个请求方式为post接口,对应的参数是一个就是以上表中的字段,一般情况下,这个参数是个数组,可以一次发送很多条数据库记录。原理就是这样,应该友盟也是这种套路吧。
用户行为统计一般在项目中被单独封装成一个独立模块,只提供接口外部使用,我用的是FMDB第三方来实现的,部分源代码代码如下,如需完整demo,请稍后等待~~
1 创建数据库以及表的部分代码,
-(void)CreatDataBaseAndTable{
//1.创建数据库
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]stringByAppendingPathComponent:@"UserAction.sqlite"];
//创建数据库的队列(线程安全)
FMDatabaseQueue *dataBaseQ = [FMDatabaseQueue databaseQueueWithPath:path];
self.dataBaseQ = dataBaseQ;
[dataBaseQ inDatabase:^(FMDatabase *db) {
BOOL success = [db open];
if (success) {
//2.创建表(保留字段20个)
NSString *str = @"CREATE TABLE IF NOT EXISTS t_UserAction(id INTEGER PRIMARY KEY AUTOINCREMENT, dateCreate TEXT NOT NULL, userId TEXT NOT NULL, anonymous integer NOT NULL, actionType integer NOT NULL, label integer NOT NULL, dataSource integer NOT NULL, pageId integer NOT NULL, tgtId integer NOT NULL, parentPageId integer NOT NULL, parentTgtId integer NOT NULL, device TEXT NOT NULL,Reserved0 integer,Reserved1 integer,Reserved2 integer,Reserved3 integer,Reserved4 integer,Reserved5 integer,Reserved6 integer,Reserved7 integer,Reserved8 integer,Reserved9 integer,Reserved10 integer,Reserved11 TEXT)";
if ([db executeUpdate:str]) {
NSLog(@"表创建成功!");
}else{
NSLog(@"创建表失败!");
}
}else{
NSLog(@"数据库创建失败!");
}
}];
}
//创建数据库以及表的部分代码,一般来讲表中字段由于新的需求可能会变更,因此要预留保留字段。
2 遍历数据库信息发送给后台
NSString *strSql = @"SELECT * FROM t_UserAction";
NSMutableArray *arr=[NSMutableArray array];
NSMutableArray *TempDataArrM=[NSMutableArray array];
NSMutableArray *TempDataArrM1=[NSMutableArray array];
NSMutableArray *ParamStr=[NSMutableArray array];
//查询语句 执行的方法
[self.dataBaseQ inDatabase:^(FMDatabase *db) {
FMResultSet *set =[db executeQuery:strSql];
while ([set next]) {
//dateCreate
NSString *dateCreate = [set stringForColumn:@"dateCreate"];
//userId
NSString *userId= [set stringForColumn:@"userId"];
//dateCreate
int anonymous = [set boolForColumn:@"anonymous"];
//actionType
int actionType = [set intForColumn:@"actionType"];
//label
int label = [set intForColumn:@"label"];
//dataSource
int dataSource = [set intForColumn:@"dataSource"];
//pageId
int pageId = [set intForColumn:@"pageId"];
//tgtId
long tgtId = [set longForColumn:@"tgtId"];
//parentPageId
int parentPageId = [set intForColumn:@"parentPageId"];
//parentTgtId
long parentTgtId = [set longForColumn:@"parentTgtId"];
//device
NSString *device = [set stringForColumn:@"device"];
[TempDataArrM addObject:dateCreate];
[TempDataArrM1 addObject:dateCreate];
NSString *TempParamStr=[NSString stringWithFormat:@"{\"dateCreate\":\"%@\",\"userId\":\"%@\",\"anonymous\":%d,\"actionType\":%d,\"label\":%d,\"dataSource\":%d,\"pageId\":%d,\"tgtId\":%ld,\"parentPageId\":%d,\"parentTgtId\":%ld,\"device\":\"%@\",\"channel\":\"app_store\"}",dateCreate,userId,anonymous,actionType,label,dataSource,pageId,tgtId,parentPageId,parentTgtId,device];
[arr addObject:TempParamStr];
[ParamStr addObject:TempParamStr];
if (arr.count==100&&[UserActionSwitch isEqualToString:@"ON"]) {
NSString *TotleParam=[arr componentsJoinedByString:@","];
NSString *paramStr=[NSString stringWithFormat:@"{\"datas\":[%@]}",TotleParam];
[[nxbHttpTools sharedNetworkTools]POST:userAPI(@"mm.st.action.push/1.0") parameters:@{@"data":paramStr} success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
NSLog(@"大于100条数据:%@",responseObject);
//发送成功后删除记录
if ([responseObject[@"code"] intValue]==200) {
[TempDataArrM enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSString *creadeDate=TempDataArrM[idx];
[self DeleteTheRecord:creadeDate];
NSLog(@"单个删除元素");
}];
[TempDataArrM removeAllObjects];
}
} failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {
NSLog(@"%@",error);
}];
NSLog(@"%@",arr);
[arr removeAllObjects];
}
}
if (ParamStr.count>1&&ParamStr.count<100&&[UserActionSwitch isEqualToString:@"ON"]) {
NSString *TotleParam=[ParamStr componentsJoinedByString:@","];
NSLog(@"小于100条数据:%@",TotleParam);
NSString *paramStr1=[NSString stringWithFormat:@"{\"datas\":[%@]}",TotleParam];
[[nxbHttpTools sharedNetworkTools]POST:userAPI(@"mm.st.action.push/1.0") parameters:@{@"data":paramStr1} success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
NSLog(@"%@",responseObject);
//发送成功后删除记录
if ([responseObject[@"code"] intValue]==200) {
[TempDataArrM1 enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSString *creadeDate=TempDataArrM1[idx];
[self DeleteTheRecord:creadeDate];
}];
[TempDataArrM1 removeAllObjects];
}
} failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {
NSLog(@"%@",error);
}];
[ParamStr removeAllObjects];
}
}];
}
3 发送成功后将本地数据库对应的一条记录删除
-(void)DeleteTheRecord:(NSString *)dateCreate{
NSString *deleteSql = [NSString stringWithFormat:
@"delete from t_UserAction where dateCreate = '%@'",dateCreate];
[self.dataBaseQ inDatabase:^(FMDatabase *db) {
BOOL res = [db executeUpdate:deleteSql];
if (res) {
NSLog(@"发送完成,删除表中一条数据");
}else{
NSLog(@"发送失败,删除表中一条数据失败!");
}
}];
}
有其他疑问可以随时问我哦~