Commit 1a9323f7 authored by 李增强's avatar 李增强

m

parent dd668db1
# 1.APP启动
```
{
event_name: "app_stage",
device_id:"",
event_data: [{
inter: "4G", // 网络情况
app_channel: "", // APP下载渠道
app_version: "1.0.0", // APP版本号
type: 2, // 1:启动APP, 2:APP从后台回到前台
appear_time: "1611540208", // 启动时间
disappear_time: "1611540208",// 关闭时间
extras: { // 此数据为自定义数据
user_id: "66713", // 用户id
source: 2, // 来源
...
}
}]
}
```
# 2.页面游览
```
{
event_name: "page_scan",
event_data: [{
inter: "4G", // 网络情况
app_channel: "", // APP下载渠道
app_version: "1.0.0", // APP版本号
page_id: "com.qm.app.goods", // 页面ID
last_page_id: "com.qm.app.home", // 上一个页面ID
appear_time: "1611540208", // 启动时间
disappear_time: "1611540208", // 关闭时间
extras: { // 此数据为自定义数据
user_id: "66713", // 用户id
source: 2, // 来源
goods_id: "15112231541", // 商品ID
...
}
}]
}
```
# 3.点击
```
{
event_name: "elem_click",
event_data: [{
inter: "4G", // 网络情况
app_channel: "", // APP下载渠道
app_version: "1.0.0", // APP版本号
page_id: "com.qm.app.goods", // 页面ID
click_id: "button", // 点击ID
click_time: "1611540208", // 点击时间
extras: { // 此数据为自定义数据
user_id: "66713", // 用户id
source: 2, // 来源
goods_id: "15112231541", // 商品ID
...
}
}]
}
```
# 4.曝光
```
{
event_name: "elem_exposure",
event_data: [{
inter: "4G", // 网络情况
app_channel: "", // APP下载渠道
app_version: "1.0.0", // APP版本号
page_id: "com.qm.app.goods", // 页面ID
exposure_id: "order_good_list", // 曝光ID
exposure_time: "1611540208", // 曝光时间
extras: { // 此数据为自定义数据
user_id: "66713", // 用户id
source: 2, // 来源
goods_id: "15112231541", // 商品ID
...
}
}]
}
```
# API数据格式
```
{
device_id:"",
projects:[{
event_name: "app_stage",
...
},{
event_name: "page_scan",
...
},{
event_name: "elem_click",
...
},{
event_name: "elem_exposure",
...
},{
event_name: "app_stage",
...
},{
event_name: "page_scan",
...
},{
event_name: "elem_click",
...
},{
event_name: "elem_exposure",
...
}]
}
```
## 数据上报
1. APP启动上报(回到前台)
2. 定时上报
## APP启动和页面游览上报
1. APP启动(进入前台)->APP关闭(进入后台),算一次上报
2. 页面启动(进入前台)->页面关闭(进入后台),算一次上报
## APP被杀死上报
1. APP被杀死时,APP和游览页面没有关闭关闭时间,正常情况无法算一次上报,在APP启动时直接上报所有
\ No newline at end of file
...@@ -2,88 +2,37 @@ library qm_tj; ...@@ -2,88 +2,37 @@ library qm_tj;
import 'dart:convert'; import 'dart:convert';
import 'package:qm_tj/src/utils.dart';
import 'src/db.dart'; import 'src/db.dart';
import 'src/http.dart'; import 'src/http.dart';
import 'package:crypto/crypto.dart' as crypto; import 'package:crypto/crypto.dart' as crypto;
import 'src/tj/app.dart';
class QMTJ { class QMTJ {
static DB _db; static DB _db;
static Http _http; static App _app;
static String _appStartUpId;
static Future<bool> ready;
static bool isDebug = false;
static void debug() { static void debug() {
isDebug = true; Utils.debug();
} }
static init() async { static init() async {
_http = Http(scheme: "http", host: "8.135.58.206", port: 8802); _db.init();
_appStartUpId = _md5(_getDateNow().toString()); _app = App(_db);
ready = new Future<bool>(() async {
_db = new DB();
await _db.init();
return true;
});
Future.delayed(Duration(seconds: 5)).then((value) { Future.delayed(Duration(seconds: 5)).then((value) {
uploadPageTj(); uploadPageTj();
}); });
} }
/// APP 启动
static void appStart({int source, Map<String, dynamic> extras}) async {
int type = 1;
int disappearTime = 0;
int appearTime = _getDateNow();
String id = _appStartUpId;
Map<String, dynamic> map = {
"id": id,
"type": type,
"source": source,
"disappear_time": disappearTime,
"appear_time": appearTime,
"extras": json.encode(extras),
};
await ready;
log("appStart", map);
await _db.db.insert("app_tj", map);
}
/// APP 可见 /// APP 可见
static void appAppear({int source, Map<String, dynamic> extras}) async { static void onAppResume({Map<String, dynamic> extras}) async {
// APP进入前台,重新生成启动id _app.onResume(extras: extras);
_appStartUpId = _md5(_getDateNow().toString());
int type = 2;
int disappearTime = 0;
int appearTime = _getDateNow();
String id = _appStartUpId;
Map<String, dynamic> map = {
"id": id,
"type": type,
"source": source,
"disappear_time": disappearTime,
"appear_time": appearTime,
"extras": json.encode(extras),
};
await ready;
log("appAppear", map);
await _db.db.insert("app_tj", map);
} }
/// APP 不可见 /// APP 不可见
static void appDisappear() async { static void onAppPause() async {
int disappearTime = _getDateNow(); _app.onPause();
Map<String, dynamic> map = {
"id": _appStartUpId,
"disappear_time": disappearTime,
};
await ready;
log("appDisappear", map);
_db.db.update("app_tj", {"disappear_time": disappearTime},
where: "id = ? and disappear_time = 0", whereArgs: [_appStartUpId]);
} }
/// PAGE 可见 /// PAGE 可见
...@@ -92,46 +41,46 @@ class QMTJ { ...@@ -92,46 +41,46 @@ class QMTJ {
String pageId, String pageId,
String lastPageId, String lastPageId,
Map<String, dynamic> extras}) async { Map<String, dynamic> extras}) async {
String extrasStr = json.encode(extras); // String extrasStr = json.encode(extras);
String id = _md5("${pageId}_${lastPageId}_$extrasStr"); // String id = _md5("${pageId}_${lastPageId}_$extrasStr");
int disappearTime = 0; // int disappearTime = 0;
int appearTime = _getDateNow(); // int appearTime = _getDateNow();
Map<String, dynamic> map = { // Map<String, dynamic> map = {
"id": id, // "id": id,
"source": source, // "source": source,
"page_id": pageId, // "page_id": pageId,
"last_page_id": lastPageId, // "last_page_id": lastPageId,
"appear_time": appearTime, // "appear_time": appearTime,
"disappear_time": disappearTime, // "disappear_time": disappearTime,
"extras": extrasStr, // "extras": extrasStr,
}; // };
await ready; // await _db.ready;
log("pageAppear", map); // log("pageAppear", map);
await _db.db.insert("page_tj", map); // await _db.db.insert("page_tj", map);
} }
/// PAGE 不可见 /// PAGE 不可见
static void pageDisappear( static void pageDisappear(
{String pageId, String lastPageId, Map<String, dynamic> extras}) async { {String pageId, String lastPageId, Map<String, dynamic> extras}) async {
String extrasStr = json.encode(extras); // String extrasStr = json.encode(extras);
String id = _md5("${pageId}_${lastPageId}_$extrasStr"); // String id = _md5("${pageId}_${lastPageId}_$extrasStr");
int disappearTime = _getDateNow(); // int disappearTime = _getDateNow();
Map<String, dynamic> map = { // Map<String, dynamic> map = {
"id": id, // "id": id,
"page_id": pageId, // "page_id": pageId,
"last_page_id": lastPageId, // "last_page_id": lastPageId,
"disappear_time": disappearTime, // "disappear_time": disappearTime,
"extras": extrasStr, // "extras": extrasStr,
}; // };
await ready; // await _db.ready;
log("pageDisappear", map); // log("pageDisappear", map);
await _db.db.update( // await _db.db.update(
"page_tj", // "page_tj",
{ // {
"disappear_time": disappearTime, // "disappear_time": disappearTime,
}, // },
where: "id = ? and disappear_time = 0", // where: "id = ? and disappear_time = 0",
whereArgs: [id]); // whereArgs: [id]);
} }
/// 点击 /// 点击
...@@ -143,20 +92,20 @@ class QMTJ { ...@@ -143,20 +92,20 @@ class QMTJ {
String pageId, String pageId,
String clickId, String clickId,
Map<String, dynamic> extras}) async { Map<String, dynamic> extras}) async {
int clickTime = _getDateNow(); // int clickTime = _getDateNow();
String extrasStr = json.encode(extras); // String extrasStr = json.encode(extras);
String id = _md5("${pageId}_${clickId}_${extrasStr}_${clickTime}"); // String id = _md5("${pageId}_${clickId}_${extrasStr}_${clickTime}");
Map<String, dynamic> map = { // Map<String, dynamic> map = {
"id": id, // "id": id,
"source": source, // "source": source,
"page_id": pageId, // "page_id": pageId,
"click_id": clickId, // "click_id": clickId,
"click_time": clickTime, // "click_time": clickTime,
"extras": extrasStr, // "extras": extrasStr,
}; // };
await ready; // await _db.ready;
log("tap", map); // log("tap", map);
await _db.db.insert("tap_tj", map); // await _db.db.insert("tap_tj", map);
} }
/// 曝光 /// 曝光
...@@ -168,65 +117,62 @@ class QMTJ { ...@@ -168,65 +117,62 @@ class QMTJ {
String pageId, String pageId,
String exposureId, String exposureId,
Map<String, dynamic> extras}) async { Map<String, dynamic> extras}) async {
int exposureTime = _getDateNow(); // int exposureTime = _getDateNow();
String extrasStr = json.encode(extras); // String extrasStr = json.encode(extras);
String id = _md5("${pageId}_${exposureId}_${extrasStr}_${exposureTime}"); // String id = _md5("${pageId}_${exposureId}_${extrasStr}_${exposureTime}");
Map<String, dynamic> map = { // Map<String, dynamic> map = {
"id": id, // "id": id,
"source": source, // "source": source,
"page_id": pageId, // "page_id": pageId,
"exposure_id": exposureId, // "exposure_id": exposureId,
"exposure_time": exposureTime, // "exposure_time": exposureTime,
"extras": extrasStr, // "extras": extrasStr,
}; // };
await ready; // await _db.ready;
log("exposure", map); // log("exposure", map);
await _db.db.insert("exposure_tj", map); // await _db.db.insert("exposure_tj", map);
} }
// 上传页面统计 // 上传页面统计
static void uploadPageTj() async { static void uploadPageTj() async {
await ready; // await _db.ready;
List<Map> list = await _db.db.query("page_tj", limit: 100, offset: 0); // List<Map> list = await _db.db.query("page_tj", limit: 100, offset: 0);
if (list.length == 0) { // if (list.length == 0) {
return; // return;
} // }
List<String> ids = []; // List<String> ids = [];
list = list.map((e) { // list = list.map((e) {
var item = { // var item = {
"app_version": '0.0.1', // "app_version": '0.0.1',
"app_channel": "APP渠道", // "app_channel": "APP渠道",
"devices_id": '3A26610FFE43D5838DDE7A40BA2E3E2C', // "devices_id": '3A26610FFE43D5838DDE7A40BA2E3E2C',
"inter": '4G', // "inter": '4G',
"source": e['source'], // "source": e['source'],
"page_id": e['page_id'], // "page_id": e['page_id'],
"last_page_id": e['last_page_id'], // "last_page_id": e['last_page_id'],
"come_time": e['appear_time'], // "come_time": e['appear_time'],
"out_time": e['disappear_time'], // "out_time": e['disappear_time'],
"extras": json.decode(e['extras']) // "extras": json.decode(e['extras'])
}; // };
ids.add(e['id']); // ids.add(e['id']);
Map project = { // Map project = {
"event_name": "page_scan", // "event_name": "page_scan",
"app": "xx", // "app": "xx",
"event_info": item // "event_info": item
}; // };
return project; // return project;
}).toList(); // }).toList();
print({"project": json.encode(list)}); // print({"project": json.encode(list)});
_http.post("/collection", {"project": json.encode(list)}).then( // }
(value) async {
if (isDebug) { // static Map<String, dynamic> getCommonParams() {
log("upload_page_tj", Map<String,dynamic>.from(value)); // return {
} // "inter": "网络情况",
if (value != null && value['code'] == 200) { // "app_channel": "APP渠道",
int result = await _db.db // "app_version": "APP版本",
.rawDelete("delete from page_tj where id in('${ids.join("','")}')"); // "device_id": "设备ID",
log("clear_page_tj", Map<String, dynamic>.from( // "source": "来源",
{"olength": list.length, "length": result})); // };
}
uploadPageTj();
});
} }
/// 获取当前时间戳,单位:秒 /// 获取当前时间戳,单位:秒
...@@ -241,13 +187,4 @@ class QMTJ { ...@@ -241,13 +187,4 @@ class QMTJ {
var digest = crypto.md5.convert(bytes); var digest = crypto.md5.convert(bytes);
return digest.toString(); return digest.toString();
} }
static void log(String type, Map<String, dynamic> map) {
if (!isDebug) {
return;
}
print("$type=======================s===========================$type");
print(map);
print("$type=======================e===========================$type");
}
} }
...@@ -5,21 +5,24 @@ import 'sql.dart'; ...@@ -5,21 +5,24 @@ import 'sql.dart';
class DB { class DB {
int _version = 1; int _version = 1;
Database db; Database db;
Future<bool> ready;
/// 打开数据库 /// 打开数据库
Future init() async { void init() {
var databasesPath = await getDatabasesPath(); ready = new Future<bool>(() async {
String path = join( var databasesPath = await getDatabasesPath();
databasesPath, String path = join(
'qm_tj.db', databasesPath,
); 'qm_tj.db',
db = await openDatabase(path, version: _version, );
onCreate: (Database db, int version) async { db = await openDatabase(path, version: _version,
await db.execute(SQL_APP_TJ_TABLE); onCreate: (Database db, int version) async {
await db.execute(SQL_PAGE_TJ_TABLE); await db.execute(SQL_APP_TJ_TABLE);
await db.execute(SQL_TAP_TJ_TABLE); await db.execute(SQL_PAGE_TJ_TABLE);
await db.execute(SQL_EXPOSURE_TJ_TABLE); await db.execute(SQL_TAP_TJ_TABLE);
await db.execute(SQL_EXPOSURE_TJ_TABLE);
});
return true;
}); });
} }
} }
enum TJAppModelTypes { startUp, resume }
class TJAppModel {
String inter;
String appChannel;
String appVersion;
TJAppModelTypes type;
int appearTime;
int disappearTime;
Map<String, dynamic> extras;
TJAppModel(
{this.inter,
this.appChannel,
this.appVersion,
this.type,
this.appearTime,
this.disappearTime,
this.extras});
}
...@@ -3,10 +3,13 @@ String SQL_APP_TJ_TABLE = ''' ...@@ -3,10 +3,13 @@ String SQL_APP_TJ_TABLE = '''
CREATE TABLE app_tj ( CREATE TABLE app_tj (
id VARCHAR(32) , id VARCHAR(32) ,
type TINYINT(4), type TINYINT(4),
source INTEGER(10),
appear_time INTEGER(10), appear_time INTEGER(10),
disappear_time INTEGER(10), disappear_time INTEGER(10),
extras VARCHAR(255) extras VARCHAR(255),
inter VARCHAR(255),
app_channel VARCHAR(255),
app_version VARCHAR(255),
) )
'''; ''';
// 页面可见或者不可见 // 页面可见或者不可见
......
import 'dart:convert';
import '../../src/db.dart';
import '../../src/utils.dart';
class App {
DB _db;
String _appStartUpId;
App(DB db) {
_db = db;
}
/// APP回到前台
void onResume({Map<String, dynamic> extras}) async {
int type = 2;
int disappearTime = 0;
int appearTime = Utils.getDateNow();
Map<String, dynamic> map = {
"id": _appStartUpId,
"type": type,
"appear_time": appearTime,
"disappear_time": disappearTime,
"extras": json.encode(extras)
};
Map<String, dynamic> common = await Utils.getCommonParams();
map.addAll(common);
// APP 启动生成本次启动ID
if (_appStartUpId == null) {
type = 1;
_appStartUpId = Utils.md5(Utils.getDateNow().toString());
}
await _db.ready;
Utils.log("app onResume", map);
await _db.db.insert("app_tj", map);
}
/// APP进入后台
void onPause() async {
int disappearTime = Utils.getDateNow();
Map<String, dynamic> map = {
"id": _appStartUpId,
"disappear_time": disappearTime,
};
await _db.ready;
Utils.log("app onPause", map);
await _db.db.insert("app_tj", map);
}
// 上传数据至接口
void upload() async {
await _db.ready;
List<Map> list = await _db.db.query("page_tj", limit: 100, offset: 0);
if (list.length == 0) {
return;
}
String deviceId = await Utils.getDeviceId();
bool result =
await Utils.uploadData({"device_id": deviceId, "projects": list});
if (result) {
List<String> ids = list.map((e) => e['id']).toList();
await _db.db
.rawDelete("delete from page_tj where id in('${ids.join("','")}')");
}
if (Utils.isDebug) {
Utils.log("upload_result", {"ok": result, "length": list.length});
}
if (list.length == 100) {
upload();
}
}
}
import 'dart:convert';
import 'http.dart';
import 'package:crypto/crypto.dart' as crypto;
import 'package:package_info/package_info.dart';
class Utils {
static String channel = '';
static bool isDebug = false;
static Http _http = Http(scheme: "http", host: "8.135.58.206", port: 8802);
/// 设置调试模式
static void debug() {
isDebug = true;
}
/// 设置渠道
static void setChannel(String s) {
channel = s;
}
/// 获取当前时间戳,单位:秒
static int getDateNow() {
int now = (DateTime.now().millisecondsSinceEpoch / 1000).floor();
return now;
}
// md5编码
static String md5(String data) {
var bytes = utf8.encode(data);
var digest = crypto.md5.convert(bytes);
return digest.toString();
}
// 获取app版本号
static Future<String> getAppVersion() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String version = packageInfo.version;
return version;
}
// 获取网络类型
static Future<String> getNetworkType() async {
return "4G";
}
// 获取设备ID
static Future<String> getDeviceId() async {
return "3A26610FFE43D5838DDE7A40BA2E3E2C";
}
// 获取公共参数
static Future<Map<String, dynamic>> getCommonParams() async {
String inter = await Utils.getNetworkType();
String appVersion = await Utils.getAppVersion();
return {
"inter": inter, // 网络情况
"app_channel": channel, // APP下载渠道
"app_version": appVersion, // APP版本号
};
}
// 上传数据
static Future<bool> uploadData(Map<String, dynamic> body) async {
var res = await _http.post("/collection", body);
if (isDebug) {
log("upload-res", res);
}
if (res != null && res['code'] == 200) {
return true;
}
return false;
}
static void log(String type, Map<String, dynamic> map) {
if (!isDebug) {
return;
}
print(
"qm_tj:$type=======================s===========================$type");
print("qm_tj:$map");
print(
"qm_tj:$type=======================e===========================$type");
}
}
...@@ -88,6 +88,13 @@ packages: ...@@ -88,6 +88,13 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.3.0-nullsafety.3" version: "1.3.0-nullsafety.3"
package_info:
dependency: "direct main"
description:
name: package_info
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.4.3+2"
path: path:
dependency: "direct main" dependency: "direct main"
description: description:
......
...@@ -13,7 +13,8 @@ dependencies: ...@@ -13,7 +13,8 @@ dependencies:
sdk: flutter sdk: flutter
sqflite: ^1.3.2+2 sqflite: ^1.3.2+2
path: ^1.6.4 path: ^1.6.4
crypto: 2.1.4 crypto: 2.1.4
package_info: 0.4.3+2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment