hina-cloud-js-sdk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,405 @@
1
+ import { AjaxSend, BatchSend, BeaconSend, ImageSend } from "./http";
2
+ import {
3
+ HinaDataStore,
4
+ addProps,
5
+ getPresetProperties,
6
+ initLatestProps,
7
+ } from "./property";
8
+ import { Log, SDKDebug, _ } from "./utils";
9
+ import AutoTrack from "./autoTrack";
10
+ import plugin from "./plugin";
11
+
12
+ let defaultPara = {
13
+ name: "",
14
+ showLog: false,
15
+ autoTrackConfig: {
16
+ clickAutoTrack: false,
17
+ stayAutoTrack: false,
18
+ },
19
+ stayAutoTrackConfig: {},
20
+ imgUseCrossOrigin: false,
21
+ isSinglePage: false, //自动采集web浏览事件
22
+ batchSend: false,
23
+ appJsBridge: false,
24
+ sendType: "image",
25
+ dataSendTimeout: 3000,
26
+ isTrackDeviceId: false,
27
+ presetProperties: {
28
+ latest_utm: true,
29
+ latest_traffic_source_type: true,
30
+ latest_search_keyword: true,
31
+ latest_referrer: true,
32
+ url: true,
33
+ title: true,
34
+ },
35
+ };
36
+
37
+ class HinaDataLib {
38
+ constructor() {
39
+ if (!HinaDataLib.instance) {
40
+ HinaDataLib.instance = this;
41
+ this.config = {};
42
+ this.initialized = false;
43
+ this._ = _;
44
+ }
45
+ return HinaDataLib.instance;
46
+ }
47
+
48
+ setConfig(config) {
49
+ if (_.check.isObject(config)) {
50
+ _.extend(this.config, config);
51
+ }
52
+ }
53
+
54
+ getConfig(propName) {
55
+ return this.config[propName];
56
+ }
57
+
58
+ //初始化时需要启动全埋点
59
+ init(para) {
60
+ if (_.check.isEmptyObject(this.config)) {
61
+ this.setConfig(_.extend({}, defaultPara, para));
62
+
63
+ Log.showLog = this.getConfig("showLog");
64
+ SDKDebug.serverUrl = this.getConfig("serverUrl");
65
+
66
+ _.initUrlChange();
67
+
68
+ // 初始化存储和属性
69
+ HinaDataStore.load(this.config);
70
+ initLatestProps(this.config);
71
+ this.store = HinaDataStore;
72
+
73
+ //初始化请求参数
74
+ let sendType = this.getConfig("sendType");
75
+ if (!["image", "ajax", "beacon"].includes(sendType)) {
76
+ this.setConfig({
77
+ sendType: "image",
78
+ });
79
+ }
80
+
81
+ if (
82
+ this.getConfig("batchSend") === true ||
83
+ _.check.isObject(this.getConfig("batchSend"))
84
+ ) {
85
+ this.batchSender = new BatchSend(this.config);
86
+ this.batchSender.batchInterval();
87
+ }
88
+
89
+ //初始化全埋点
90
+ let autoTrackConfig = this.getConfig("autoTrackConfig");
91
+ let stayAutoTrackConfig = this.getConfig("stayAutoTrackConfig");
92
+ let autoTrackInstance = new AutoTrack(
93
+ autoTrackConfig,
94
+ stayAutoTrackConfig,
95
+ this
96
+ );
97
+ this.autoTrackInstance = autoTrackInstance;
98
+ autoTrackInstance.initWebClick();
99
+ autoTrackInstance.initWebStay();
100
+ autoTrackInstance.listenSinglePage();
101
+ this.initialized = true;
102
+ Log.log("hinaSDK initialized successfully");
103
+ _.mitt.emit("hasInit");
104
+ } else {
105
+ Log.log("hinaSDK has been initialized");
106
+ }
107
+ }
108
+
109
+ sendRequest(data, callback) {
110
+ data = addProps(data, this);
111
+ data.send_time = _.now();
112
+ Log.log(data);
113
+ let useAppJsBridge = this.getConfig("appJsBridge");
114
+ if (useAppJsBridge) {
115
+ let jsBridge = window.Hina_Cloud_H5_Bridge || {};
116
+ if (_.check.isObject(jsBridge) && jsBridge.track) {
117
+ // android
118
+ jsBridge.track(data.event, data.type, JSON.stringify(data));
119
+ if (_.check.isFunction(callback)) callback();
120
+ Log.log("The data has been sent to the Android side");
121
+ return;
122
+ } else if (_.info.os() === "iOS") {
123
+ // ios
124
+ let iosTracker = window.webkit?.messageHandlers?.hinaNativeTracker;
125
+ if (iosTracker?.postMessage) {
126
+ let param = JSON.stringify({
127
+ eventName: data.event,
128
+ eventType: data.type,
129
+ properties: data
130
+ });
131
+ iosTracker.postMessage(param);
132
+ if (_.check.isFunction(callback)) callback();
133
+ Log.log("The data has been sent to the iOS side");
134
+ return;
135
+ }
136
+ }
137
+ Log.log("The app JSBridge data transmission has failed.");
138
+ }
139
+ let isBatchSend = this.getConfig("batchSend");
140
+ if (isBatchSend) {
141
+ new BatchSend(this.config).add(data);
142
+ } else {
143
+ if (!_.check.isString(data)) {
144
+ data = JSON.stringify(data);
145
+ }
146
+ let base64Data = _.base64Encode(data);
147
+ let crc = "crc=" + _.hashCode(base64Data);
148
+ let urlData =
149
+ "data=" +
150
+ _.encodeURIComponent(base64Data) +
151
+ "&ext=" +
152
+ _.encodeURIComponent(crc);
153
+
154
+ let sendType = this.getConfig("sendType");
155
+ let para = {
156
+ callback,
157
+ data: urlData,
158
+ serverUrl: this.getConfig("serverUrl"),
159
+ dataSendTimeout: this.getConfig("dataSendTimeout"),
160
+ };
161
+ switch (sendType) {
162
+ case "ajax":
163
+ new AjaxSend(para).run();
164
+ break;
165
+
166
+ case "beacon":
167
+ new BeaconSend(para).run();
168
+ break;
169
+
170
+ default:
171
+ new ImageSend(
172
+ _.extend(para, {
173
+ imgUseCrossOrigin: this.getConfig("imgUseCrossOrigin"),
174
+ })
175
+ ).run();
176
+ break;
177
+ }
178
+ }
179
+ }
180
+
181
+ quick(name, ...args) {
182
+ let list = {
183
+ autoTrack: this.autoTrackInstance.autoTrack,
184
+ autoTrackSinglePage: this.autoTrackInstance.autoTrackSinglePage,
185
+ };
186
+
187
+ return list[name].call(this.autoTrackInstance, args);
188
+ }
189
+
190
+ track(e, p, c) {
191
+ let cb = _.check.isFunction(c) ? c : () => {};
192
+ if (_.check.isString(e) && _.check.isObject(p)) {
193
+ this.sendRequest(
194
+ {
195
+ type: "track",
196
+ event: e,
197
+ properties: p,
198
+ },
199
+ cb
200
+ );
201
+ } else {
202
+ Log.log("eventName must be a sting and properties must be an object");
203
+ }
204
+ }
205
+
206
+ setUserUId(uid, callback) {
207
+ if (_.check.isNumber(uid) || _.check.isString(uid)) {
208
+ uid = String(uid);
209
+ } else {
210
+ Log.log("setUserUId: uid must be string or number");
211
+ return;
212
+ }
213
+
214
+ let firstId = this.store.getFirstId();
215
+ let accountId = this.store.getAccountId();
216
+
217
+ if (uid === accountId && !firstId) {
218
+ Log.log("setUserUId: uid is equal to account_id");
219
+ return;
220
+ }
221
+
222
+ if (uid !== accountId) {
223
+ if (!firstId) {
224
+ this.store.set("firstId", accountId);
225
+ }
226
+ this.store.setAccountId(uid);
227
+
228
+ this.sendRequest(
229
+ {
230
+ account_id: this.store.getAccountId(),
231
+ type: "track_signup",
232
+ event: "H_signUp",
233
+ properties: {},
234
+ },
235
+ callback
236
+ );
237
+ }
238
+ }
239
+
240
+ getDeviceUId() {
241
+ return this.store.getAnonymousId();
242
+ }
243
+
244
+ setDeviceUId(uid, isSave) {
245
+ let firstId = this.store.getFirstId();
246
+ if (_.check.isUndefined(uid)) {
247
+ let uuid = _.UUID();
248
+ if (firstId) {
249
+ this.store.set("firstId", uuid);
250
+ } else {
251
+ this.store.setAccountId(uuid);
252
+ }
253
+ } else if (_.check.isNumber(uid) || _.check.isString(uid)) {
254
+ uid = String(uid);
255
+ if (isSave === true) {
256
+ if (firstId) {
257
+ this.store.set("firstId", uid);
258
+ } else {
259
+ this.store.set("accountId", uid);
260
+ }
261
+ } else {
262
+ if (firstId) {
263
+ this.store.change("firstId", uid);
264
+ } else {
265
+ this.store.change("accountId", uid);
266
+ }
267
+ }
268
+ }
269
+ }
270
+
271
+ userSet(p, c) {
272
+ if (_.check.isObject(p) && !_.check.isEmptyObject(p)) {
273
+ this.sendRequest(
274
+ {
275
+ type: "user_set",
276
+ properties: p,
277
+ },
278
+ c
279
+ );
280
+ }
281
+ }
282
+
283
+ userSetOnce(p, c) {
284
+ if (_.check.isObject(p) && !_.check.isEmptyObject(p)) {
285
+ this.sendRequest(
286
+ {
287
+ type: "user_setOnce",
288
+ properties: p,
289
+ },
290
+ c
291
+ );
292
+ }
293
+ }
294
+
295
+ userAdd(p, c) {
296
+ if (_.check.isString(p)) {
297
+ let s = p;
298
+ p = {
299
+ [s]: 1,
300
+ };
301
+ }
302
+
303
+ function isCheck(para) {
304
+ for (let s in para) {
305
+ if (s in para && !/-*\d+/.test(String(para[s]))) {
306
+ Log.log("userAdd: value is must be number");
307
+ return false;
308
+ }
309
+ }
310
+ return true;
311
+ }
312
+
313
+ if (_.check.isObject(p) && !_.check.isEmptyObject(p) && isCheck(p)) {
314
+ this.sendRequest(
315
+ {
316
+ type: "user_add",
317
+ properties: p,
318
+ },
319
+ c
320
+ );
321
+ }
322
+ }
323
+
324
+ userUnset(p, c) {
325
+ let obj = {};
326
+ if (_.check.isString(p)) {
327
+ let s = p;
328
+ p = [s];
329
+ }
330
+
331
+ if (_.check.isArray(p)) {
332
+ _.each(p, function (v) {
333
+ if (_.check.isString(v)) {
334
+ obj[v] = true;
335
+ } else {
336
+ Log.log(
337
+ "userUnset: value inside the array must be string and have already been filtered out",
338
+ v
339
+ );
340
+ }
341
+ });
342
+ this.sendRequest(
343
+ {
344
+ type: "user_unset",
345
+ properties: obj,
346
+ },
347
+ c
348
+ );
349
+ } else {
350
+ Log.log("userUnset: param must be an array or string");
351
+ }
352
+ }
353
+
354
+ userDelete(c) {
355
+ this.sendRequest(
356
+ {
357
+ type: "user_delete",
358
+ },
359
+ c
360
+ );
361
+ this.store.setAccountId(_.UUID());
362
+ this.store.set("firstId", "");
363
+ }
364
+
365
+ registerCommonProperties(para) {
366
+ this.store.set("props", para);
367
+ }
368
+
369
+ getPresetProperties() {
370
+ return getPresetProperties();
371
+ }
372
+
373
+ use(pluginName, option) {
374
+ if (!_.check.isString(pluginName)) {
375
+ Log.log("pluginName must be string");
376
+ return;
377
+ }
378
+
379
+ if (!(pluginName in plugin)) {
380
+ Log.log("please write a valid plugin name");
381
+ return;
382
+ }
383
+
384
+ new plugin[pluginName]().init(this, option);
385
+ }
386
+ }
387
+
388
+ const hina = new Proxy(new HinaDataLib(), {
389
+ get(target, prop) {
390
+ if (_.check.isFunction(target[prop])) {
391
+ return function (...args) {
392
+ if (!target.initialized && prop !== "init") {
393
+ console.log("sdk not yet initialized!");
394
+ return;
395
+ }
396
+ return target[prop].apply(target, args);
397
+ };
398
+ }
399
+ return target[prop];
400
+ },
401
+ });
402
+
403
+ window.hinaDataStatistic = hina;
404
+
405
+ export default hina;