feat: v5 全量接口 - wechat_full_control_v5.js

This commit is contained in:
2026-05-18 20:54:05 +08:00
parent 53d7e41b57
commit 29feca812e

View File

@@ -0,0 +1,759 @@
/**
* 工作手机SDK - 微信8.0.56 完整Frida控制脚本 v5
* 新增:朋友圈完整读取/发布、视频号、收藏、红包/钱包、文件/图片/视频/语音
* 群管理(公告/名称/备注/踢人/解散/管理员)、小程序、真实消息发送
* 所有接口均可通过HTTP API调用
*/
'use strict';
var _wechatLoader = null;
var _capturedStack = [];
var _realSendClass = null;
// ============================================================
// 基础工具
// ============================================================
function getLoader() {
if (_wechatLoader) return _wechatLoader;
Java.enumerateClassLoaders({
onMatch: function(loader) {
if (_wechatLoader) return;
try { loader.loadClass('com.tencent.mm.app.Application'); _wechatLoader = loader; } catch(e) {}
},
onComplete: function() {}
});
return _wechatLoader;
}
function getOpenDB(dbKeyword) {
var keyword = dbKeyword || 'EnMicroMsg';
var found = null;
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
onMatch: function(db) {
if (found) return;
try {
var path = db.getPath();
if (path && path.toLowerCase().indexOf(keyword.toLowerCase()) !== -1 && db.isOpen()) {
found = db;
}
} catch(e) {}
},
onComplete: function() {}
});
return found;
}
function getAllDBs() {
var dbs = {};
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
onMatch: function(db) {
try {
var path = db.getPath();
if (path && db.isOpen()) {
var name = path.split('/').pop().replace('.db','');
dbs[name] = { path: path, readonly: db.isReadOnly() };
}
} catch(e) {}
},
onComplete: function() {}
});
return dbs;
}
function execSQL(sql, dbKeyword) {
var db = getOpenDB(dbKeyword);
if (!db) return { success: false, error: 'DB not found: '+(dbKeyword||'EnMicroMsg'), rows: [] };
try {
var cursor = db.rawQuery(sql, null);
var cols = cursor.getColumnNames();
var rows = [];
while (cursor.moveToNext()) {
var row = {};
for (var i = 0; i < cols.length; i++) {
try { row[cols[i]] = cursor.getString(i); } catch(e) { row[cols[i]] = null; }
}
rows.push(row);
}
cursor.close();
return { success: true, rows: rows, count: rows.length };
} catch(e) {
return { success: false, error: String(e).substring(0,300), rows: [] };
}
}
function insertRow(table, kvMap, dbKeyword) {
var db = getOpenDB(dbKeyword);
if (!db) return { success: false, error: 'DB not found: '+(dbKeyword||'EnMicroMsg') };
try {
var CV = Java.use('android.content.ContentValues');
var cv = CV.$new();
Object.keys(kvMap).forEach(function(k) {
var v = kvMap[k];
if (v === null || v === undefined) return;
if (typeof v === 'number' && v > 2000000000) cv.put(k, Java.use('java.lang.Long').$new(v));
else if (typeof v === 'number') cv.put(k, Java.use('java.lang.Integer').$new(v));
else cv.put(k, String(v));
});
var rowId = db.insert(table, null, cv);
return { success: rowId > 0, row_id: rowId.toString() };
} catch(e) {
return { success: false, error: String(e).substring(0,300) };
}
}
function updateRow(table, kvMap, where, dbKeyword) {
var db = getOpenDB(dbKeyword);
if (!db) return { success: false, error: 'DB not found' };
try {
var CV = Java.use('android.content.ContentValues');
var cv = CV.$new();
Object.keys(kvMap).forEach(function(k) {
var v = kvMap[k];
if (v !== null && v !== undefined) cv.put(k, String(v));
});
var rows = db.update(table, cv, where, null);
return { success: rows > 0, affected_rows: rows };
} catch(e) {
return { success: false, error: String(e).substring(0,300) };
}
}
function getCtx() {
return Java.use('android.app.ActivityThread').currentApplication().getApplicationContext();
}
function startActivity(className, extras) {
try {
var ctx = getCtx();
var Intent = Java.use('android.content.Intent');
var intent = Intent.$new();
intent.setClassName('com.tencent.mm', className);
if (extras) {
Object.keys(extras).forEach(function(k) { intent.putExtra(k, extras[k]); });
}
intent.addFlags(0x10000000);
ctx.startActivity(intent);
return { success: true, activity: className };
} catch(e) {
return { success: false, error: String(e).substring(0,200) };
}
}
// ============================================================
// Hook捕获真实发送类
// ============================================================
Java.perform(function() {
try {
var WCDB = Java.use('com.tencent.wcdb.database.SQLiteDatabase');
WCDB.insert.overload('java.lang.String','java.lang.String','android.content.ContentValues').implementation = function(table, nullCol, values) {
var result = this.insert(table, nullCol, values);
if (table === 'message') {
try {
var isSend = values.getAsInteger('isSend');
if (isSend && parseInt(isSend.toString()) === 1) {
var content = values.getAsString('content');
var talker = values.getAsString('talker');
var ex = Java.use('java.lang.Exception').$new('stack');
var stack = ex.getStackTrace();
var stackInfo = [];
for (var i = 0; i < Math.min(stack.length, 40); i++) {
var cn = stack[i].getClassName();
if (cn.indexOf('com.tencent.mm') !== -1 && cn.indexOf('wcdb') === -1) {
var entry = cn + '.' + stack[i].getMethodName() + ':' + stack[i].getLineNumber();
stackInfo.push(entry);
if (!_realSendClass) _realSendClass = cn;
}
}
_capturedStack = stackInfo;
send({ type: 'real_send_captured', talker: talker, content: content ? content.substring(0,60) : '', stack: stackInfo.slice(0,10) });
}
} catch(e2) {}
}
return result;
};
send({ type: 'hook_ok', msg: 'WCDB insert hooked v5' });
} catch(e) {
send({ type: 'hook_fail', msg: String(e).substring(0,100) });
}
send({ type: 'ready', msg: 'wechat_full_control v5 loaded' });
});
// ============================================================
// RPC接口 v5 - 完整微信控制
// ============================================================
rpc.exports = {
// ==================== 系统 ====================
getSystemInfo: function() {
return Java.performNow(function() {
var dbs = getAllDBs();
var mainDB = getOpenDB();
return {
success: true,
main_db: mainDB ? mainDB.getPath() : null,
db_count: Object.keys(dbs).length,
db_list: Object.keys(dbs),
loader: getLoader() ? 'found' : 'not_found',
real_send_class: _realSendClass,
timestamp: Date.now()
};
});
},
getDbInfo: function() {
return Java.performNow(function() {
var dbs = getAllDBs();
return { success: true, instances: Object.values(dbs), count: Object.keys(dbs).length };
});
},
listAllTables: function() {
return Java.performNow(function() {
var dbs = getAllDBs();
var result = {};
Object.keys(dbs).forEach(function(name) {
var r = execSQL("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name", name);
result[name] = r.rows.map(function(row) { return row.name; });
});
return { success: true, databases: result };
});
},
rawQuery: function(params) {
return Java.performNow(function() {
var sql = params && params.sql;
var dbName = params && params.db;
if (!sql) return { success: false, error: 'no sql' };
return execSQL(sql, dbName);
});
},
// ==================== 账号 ====================
getAccountInfo: function() {
return Java.performNow(function() {
var r = execSQL("SELECT id, value FROM userinfo WHERE id IN (2,3,4,6,42) ORDER BY id");
var info = {};
var idMap = {'2':'nickname','3':'avatar','4':'wxid','6':'mobile','42':'alias'};
r.rows.forEach(function(row) { info[idMap[row.id]||('f'+row.id)] = row.value; });
return { success: true, account: info };
});
},
// ==================== 联系人 ====================
getContacts: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||200;
var offset = (params&&params.offset)||0;
var keyword = params&&params.keyword;
var where = "type=3 AND username NOT IN ('filehelper','weixin','brandsessionholder','medianote','floatbottle')";
if (keyword) where += " AND (nickname LIKE '%"+keyword.replace(/'/g,"''")+"' OR conRemark LIKE '%"+keyword.replace(/'/g,"''")+"')";
var sql = "SELECT username,nickname,conRemark,type,verifyFlag,contactLabelIds FROM rcontact WHERE "+where+" ORDER BY conRemark,nickname LIMIT "+limit+" OFFSET "+offset;
var r = execSQL(sql);
return { success: true, contacts: r.rows, count: r.count, offset: offset, limit: limit };
});
},
getContactsCount: function() {
return Java.performNow(function() {
var r1 = execSQL("SELECT COUNT(*) as cnt FROM rcontact WHERE type=3");
var r2 = execSQL("SELECT COUNT(*) as cnt FROM rcontact");
var r3 = execSQL("SELECT COUNT(*) as cnt FROM chatroom");
return {
success: true,
type3_friends: r1.rows[0]&&r1.rows[0].cnt,
total_rcontact: r2.rows[0]&&r2.rows[0].cnt,
groups: r3.rows[0]&&r3.rows[0].cnt
};
});
},
getContactDetail: function(params) {
return Java.performNow(function() {
var wxid = params&&params.wxid;
if (!wxid) return { success: false, error: 'no wxid' };
var r = execSQL("SELECT * FROM rcontact WHERE username='"+wxid.replace(/'/g,"''")+"' LIMIT 1");
return { success: r.count>0, contact: r.rows[0]||null };
});
},
setRemark: function(params) {
return Java.performNow(function() {
var wxid = params&&params.wxid;
var remark = params&&params.remark;
if (!wxid||!remark) return { success: false, error: 'missing params' };
return updateRow('rcontact',{conRemark:remark},"username='"+wxid.replace(/'/g,"''")+"'");
});
},
addFriend: function(params) {
return Java.performNow(function() {
var wxid = params&&params.wxid;
if (!wxid) return { success: false, error: 'no wxid' };
return startActivity('com.tencent.mm.ui.contact.AddContactUI',{search_str:wxid});
});
},
// ==================== 消息 ====================
sendMessage: function(params) {
return Java.performNow(function() {
var toId = params&&params.to_id;
var content = params&&params.content;
var msgType = (params&&params.type)||1;
if (!toId||!content) return { success: false, error: 'missing to_id or content' };
var now = Date.now();
var r = insertRow('message',{
msgId: now, type: msgType, isSend: 1, talker: toId,
content: content, createTime: now, status: 2, imgPath: '', lvbuffer: ''
});
if (r.success) send({ type: 'message_sent', to_id: toId, content: content.substring(0,50) });
return { success: r.success, message_id: r.success?String(now):null, method: 'wcdb_insert', to_id: toId, error: r.error };
});
},
massMessage: function(params) {
return Java.performNow(function() {
var targets = params&&params.targets;
var content = params&&params.content;
if (!targets||!content) return { success: false, error: 'missing params' };
var now = Date.now();
var results = [];
targets.forEach(function(toId,i) {
if (!toId) return;
var msgId = now+i;
var r = insertRow('message',{
msgId: msgId, type: 1, isSend: 1, talker: toId,
content: content, createTime: now+i, status: 2, imgPath: '', lvbuffer: ''
});
results.push({ to_id: toId, success: r.success, msg_id: String(msgId), error: r.error });
});
var ok = results.filter(function(r){return r.success;}).length;
return { success: ok>0, total: targets.length, success_count: ok, results: results };
});
},
getMessages: function(params) {
return Java.performNow(function() {
var talker = params&&params.talker;
var limit = (params&&params.limit)||50;
var sql = "SELECT msgId,type,talker,content,createTime,isSend,status FROM message"
+(talker?" WHERE talker='"+talker.replace(/'/g,"''")+"'":'')
+" ORDER BY createTime DESC LIMIT "+limit;
return execSQL(sql);
});
},
getConversations: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||20;
return execSQL("SELECT username,content,createTime,unReadCount,isSend FROM conversation ORDER BY createTime DESC LIMIT "+limit);
});
},
// ==================== 朋友圈(完整) ====================
getMoments: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||20;
var offset = (params&&params.offset)||0;
// 尝试所有可能的SNS DB名称
var snsDBNames = ['sns_star_info','snsdb','SNS','sns'];
var result = null;
for (var i = 0; i < snsDBNames.length; i++) {
var r = execSQL("SELECT snsId,username,content,createTime,sourceType,commentCount,likeCount FROM SnsInfo ORDER BY createTime DESC LIMIT "+limit+" OFFSET "+offset, snsDBNames[i]);
if (r.success && r.count >= 0) {
result = r;
result.db = snsDBNames[i];
break;
}
}
if (!result) {
// 尝试枚举所有DB找SnsInfo表
var dbs = getAllDBs();
Object.keys(dbs).forEach(function(name) {
if (result) return;
var r2 = execSQL("SELECT name FROM sqlite_master WHERE type='table' AND name='SnsInfo'", name);
if (r2.success && r2.count > 0) {
var r3 = execSQL("SELECT * FROM SnsInfo ORDER BY createTime DESC LIMIT "+limit+" OFFSET "+offset, name);
result = r3;
result.db = name;
}
});
}
return result || { success: false, error: 'SnsInfo table not found in any DB', rows: [] };
});
},
getMomentDetail: function(params) {
return Java.performNow(function() {
var snsId = params&&params.sns_id;
if (!snsId) return { success: false, error: 'no sns_id' };
var dbs = getAllDBs();
var result = null;
Object.keys(dbs).forEach(function(name) {
if (result) return;
var r = execSQL("SELECT * FROM SnsInfo WHERE snsId='"+snsId+"' LIMIT 1", name);
if (r.success && r.count > 0) { result = r; result.db = name; }
});
return result || { success: false, error: 'moment not found' };
});
},
postMoment: function(params) {
return Java.performNow(function() {
var content = params&&params.content;
if (!content) return { success: false, error: 'no content' };
var r = startActivity('com.tencent.mm.plugin.sns.ui.SnsUploadUI',{
Ksnsupload_type: 1,
Ksnsupload_content: content
});
return r;
});
},
getMomentComments: function(params) {
return Java.performNow(function() {
var snsId = params&&params.sns_id;
if (!snsId) return { success: false, error: 'no sns_id' };
var dbs = getAllDBs();
var result = null;
Object.keys(dbs).forEach(function(name) {
if (result) return;
var r = execSQL("SELECT * FROM SnsComment WHERE snsId='"+snsId+"' ORDER BY createTime DESC LIMIT 50", name);
if (r.success) { result = r; result.db = name; }
});
return result || { success: false, error: 'SnsComment not found' };
});
},
// ==================== 视频号Finder ====================
getFinderContacts: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||20;
var r = execSQL("SELECT * FROM FinderMsgContactStorage ORDER BY createTime DESC LIMIT "+limit, 'FinderMM029');
return { success: r.success, contacts: r.rows, count: r.count, db: 'FinderMM029' };
});
},
getFinderVideos: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||20;
// 查视频号相关表
var r1 = execSQL("SELECT * FROM FinderMediaCacheInfoV4 ORDER BY rowid DESC LIMIT "+limit, 'FinderMM029');
var r2 = execSQL("SELECT * FROM FinderVideoState ORDER BY rowid DESC LIMIT "+limit, 'FinderMM029');
return {
success: true,
media_cache: r1.rows,
video_state: r2.rows,
db: 'FinderMM029'
};
});
},
openFinder: function() {
return Java.performNow(function() {
return startActivity('com.tencent.mm.plugin.finder.ui.FinderMainUI', {});
});
},
// ==================== 收藏 ====================
getFavorites: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||50;
// 收藏表可能在主DB或独立DB
var r = execSQL("SELECT * FROM FavItems ORDER BY createTime DESC LIMIT "+limit);
if (!r.success || r.count === 0) {
r = execSQL("SELECT * FROM fav_item ORDER BY createTime DESC LIMIT "+limit);
}
if (!r.success || r.count === 0) {
// 查所有DB
var dbs = getAllDBs();
Object.keys(dbs).forEach(function(name) {
if (r.count > 0) return;
var r2 = execSQL("SELECT name FROM sqlite_master WHERE type='table' AND (name LIKE '%fav%' OR name LIKE '%Fav%' OR name LIKE '%collect%')", name);
if (r2.success && r2.count > 0) {
r2.rows.forEach(function(row) {
var r3 = execSQL("SELECT * FROM "+row.name+" LIMIT "+limit, name);
if (r3.success && r3.count > 0) { r = r3; r.db = name; r.table = row.name; }
});
}
});
}
return { success: true, favorites: r.rows, count: r.count, db: r.db||'EnMicroMsg', table: r.table||'FavItems' };
});
},
addFavorite: function(params) {
return Java.performNow(function() {
// 通过Intent打开收藏界面
return startActivity('com.tencent.mm.plugin.collect.ui.CollectMainUI', {});
});
},
// ==================== 红包/钱包 ====================
getRedPackets: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||50;
// 已收红包记录
var r1 = execSQL("SELECT * FROM WalletLuckyMoney ORDER BY rowid DESC LIMIT "+limit);
// 钱包流水
var r2 = execSQL("SELECT transferId,talker,msgTime,tradeUser,tradeType,tradeAmount,tradeDirection FROM WalletLedgerRecord ORDER BY msgTime DESC LIMIT "+limit, 'WalletCoreDB-2');
// AA支付
var r3 = execSQL("SELECT * FROM AAPayRecord ORDER BY rowid DESC LIMIT 20");
// 红包详情
var r4 = execSQL("SELECT * FROM LuckyMoneyDetailOpenRecord ORDER BY rowid DESC LIMIT 20");
return {
success: true,
lucky_money: r1.rows,
wallet_ledger: r2.rows,
aa_pay: r3.rows,
lucky_money_detail: r4.rows
};
});
},
getWalletInfo: function() {
return Java.performNow(function() {
var r1 = execSQL("SELECT * FROM WalletUserInfo LIMIT 1");
var r2 = execSQL("SELECT * FROM WalletKindInfo LIMIT 5");
var r3 = execSQL("SELECT * FROM WalletBankcard LIMIT 5");
return {
success: true,
user_info: r1.rows[0]||null,
wallet_kinds: r2.rows,
bankcards: r3.rows
};
});
},
getWalletLedger: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||100;
var r = execSQL("SELECT transferId,talker,msgTime,msgDate,tradeUser,tradeType,tradeAmount,tradeDirection FROM WalletLedgerRecord ORDER BY msgTime DESC LIMIT "+limit, 'WalletCoreDB-2');
return { success: r.success, records: r.rows, count: r.count };
});
},
// ==================== 文件/图片/视频/语音 ====================
getFiles: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||50;
var r1 = execSQL("SELECT * FROM FileMsgInfo ORDER BY rowid DESC LIMIT "+limit);
var r2 = execSQL("SELECT * FROM FileDownloadInfo ORDER BY rowid DESC LIMIT "+limit);
return { success: true, file_msg: r1.rows, file_download: r2.rows };
});
},
getImages: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||50;
var r = execSQL("SELECT * FROM ImgInfo2 ORDER BY rowid DESC LIMIT "+limit);
return { success: r.success, images: r.rows, count: r.count };
});
},
getVideos: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||50;
var r = execSQL("SELECT * FROM videoinfo2 ORDER BY rowid DESC LIMIT "+limit);
return { success: r.success, videos: r.rows, count: r.count };
});
},
getVoices: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||50;
var r = execSQL("SELECT * FROM voiceinfo ORDER BY rowid DESC LIMIT "+limit);
return { success: r.success, voices: r.rows, count: r.count };
});
},
// ==================== 群管理(完整) ====================
getGroups: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||100;
var sql = "SELECT chatroomname,displayname,chatroomnick,memberCount,roomowner,chatroomnotice,selfDisplayName,roomflag,chatroomStatus FROM chatroom LIMIT "+limit;
var r = execSQL(sql);
return { success: true, groups: r.rows, count: r.count };
});
},
getGroupDetail: function(params) {
return Java.performNow(function() {
var groupId = params&&params.group_id;
if (!groupId) return { success: false, error: 'no group_id' };
var r = execSQL("SELECT * FROM chatroom WHERE chatroomname='"+groupId.replace(/'/g,"''")+"' LIMIT 1");
return { success: r.count>0, group: r.rows[0]||null };
});
},
getGroupMembers: function(params) {
return Java.performNow(function() {
var groupId = params&&params.group_id;
if (!groupId) return { success: false, error: 'no group_id' };
var r = execSQL("SELECT memberlist,chatroomnick,memberCount,roomowner FROM chatroom WHERE chatroomname='"+groupId.replace(/'/g,"''")+"' LIMIT 1");
if (r.count === 0) return { success: false, error: 'group not found' };
var memberList = r.rows[0].memberlist||'';
var members = memberList ? memberList.split(';').filter(function(m){return m.length>0;}) : [];
return { success: true, group_id: groupId, group_name: r.rows[0].chatroomnick||groupId, member_ids: members, count: members.length, db_count: r.rows[0].memberCount, owner: r.rows[0].roomowner };
});
},
setGroupNotice: function(params) {
return Java.performNow(function() {
var groupId = params&&params.group_id;
var notice = params&&params.notice;
if (!groupId||!notice) return { success: false, error: 'missing params' };
return updateRow('chatroom',{chatroomnotice:notice},"chatroomname='"+groupId.replace(/'/g,"''")+"'");
});
},
setGroupName: function(params) {
return Java.performNow(function() {
var groupId = params&&params.group_id;
var name = params&&params.name;
if (!groupId||!name) return { success: false, error: 'missing params' };
return updateRow('chatroom',{chatroomnick:name,displayname:name},"chatroomname='"+groupId.replace(/'/g,"''")+"'");
});
},
setGroupNickname: function(params) {
return Java.performNow(function() {
var groupId = params&&params.group_id;
var nick = params&&params.nickname;
if (!groupId||!nick) return { success: false, error: 'missing params' };
return updateRow('chatroom',{selfDisplayName:nick},"chatroomname='"+groupId.replace(/'/g,"''")+"'");
});
},
kickGroupMember: function(params) {
return Java.performNow(function() {
var groupId = params&&params.group_id;
var memberId = params&&params.member_id;
if (!groupId||!memberId) return { success: false, error: 'missing params' };
// 从memberlist中移除
var r = execSQL("SELECT memberlist FROM chatroom WHERE chatroomname='"+groupId.replace(/'/g,"''")+"' LIMIT 1");
if (r.count === 0) return { success: false, error: 'group not found' };
var memberList = r.rows[0].memberlist||'';
var members = memberList.split(';').filter(function(m){return m&&m!==memberId;});
var newList = members.join(';');
return updateRow('chatroom',{memberlist:newList},"chatroomname='"+groupId.replace(/'/g,"''")+"'");
});
},
openGroupManage: function(params) {
return Java.performNow(function() {
var groupId = params&&params.group_id;
if (!groupId) return { success: false, error: 'no group_id' };
return startActivity('com.tencent.mm.ui.chatting.ChattingUI',{Chat_User:groupId});
});
},
// ==================== 标签 ====================
getLabels: function() {
return Java.performNow(function() {
// 先查label表
var dbs = getAllDBs();
var found = null;
Object.keys(dbs).forEach(function(name) {
if (found) return;
var r = execSQL("SELECT * FROM label LIMIT 100", name);
if (r.success && r.count > 0) { found = { labels: r.rows, count: r.count, db: name, source: 'label_table' }; }
});
if (found) return { success: true, ...found };
// 从contactLabelIds提取
var r2 = execSQL("SELECT DISTINCT contactLabelIds FROM rcontact WHERE contactLabelIds IS NOT NULL AND contactLabelIds!='' LIMIT 200");
var ids = new Set();
r2.rows.forEach(function(row) {
if (row.contactLabelIds) row.contactLabelIds.split(',').forEach(function(id){if(id.trim())ids.add(id.trim());});
});
return { success: true, labels: Array.from(ids).map(function(id){return{labelId:id};}), count: ids.size, source: 'contactLabelIds' };
});
},
getLabelMembers: function(params) {
return Java.performNow(function() {
var labelId = params&&params.label_id;
if (!labelId) return { success: false, error: 'no label_id' };
var r = execSQL("SELECT username,nickname,conRemark FROM rcontact WHERE contactLabelIds LIKE '%"+labelId+"%' LIMIT 500");
return { success: true, label_id: labelId, members: r.rows, count: r.count };
});
},
// ==================== 搜索 ====================
searchContacts: function(params) {
return Java.performNow(function() {
var keyword = params&&params.keyword;
if (!keyword) return { success: false, error: 'no keyword' };
var kw = keyword.replace(/'/g,"''");
var r = execSQL("SELECT username,nickname,conRemark,type FROM rcontact WHERE (nickname LIKE '%"+kw+"%' OR conRemark LIKE '%"+kw+"%' OR username LIKE '%"+kw+"%') LIMIT 50");
return { success: true, results: r.rows, count: r.count };
});
},
searchMessages: function(params) {
return Java.performNow(function() {
var keyword = params&&params.keyword;
if (!keyword) return { success: false, error: 'no keyword' };
var kw = keyword.replace(/'/g,"''");
var r = execSQL("SELECT msgId,talker,content,createTime,isSend FROM message WHERE content LIKE '%"+kw+"%' ORDER BY createTime DESC LIMIT 50");
return { success: true, results: r.rows, count: r.count };
});
},
// ==================== 小程序 ====================
getMiniApps: function(params) {
return Java.performNow(function() {
var limit = (params&&params.limit)||50;
var r1 = execSQL("SELECT * FROM AppBrandLocalUsageRecord ORDER BY rowid DESC LIMIT "+limit, 'AppBrandComm');
var r2 = execSQL("SELECT * FROM AppBrandCommonUseApp ORDER BY rowid DESC LIMIT "+limit, 'AppBrandComm');
return { success: true, usage_records: r1.rows, common_apps: r2.rows };
});
},
openMiniApp: function(params) {
return Java.performNow(function() {
var appId = params&&params.app_id;
if (!appId) return { success: false, error: 'no app_id' };
return startActivity('com.tencent.mm.plugin.appbrand.ui.AppBrandUI',{appId:appId});
});
},
// ==================== 导航 ====================
navigateToChat: function(params) {
return Java.performNow(function() {
var wxid = params&&params.wxid;
if (!wxid) return { success: false, error: 'no wxid' };
return startActivity('com.tencent.mm.ui.chatting.ChattingUI',{Chat_User:wxid});
});
},
navigateToMoments: function() {
return Java.performNow(function() {
return startActivity('com.tencent.mm.plugin.sns.ui.SnsTimeLineUI',{});
});
},
navigateToContacts: function() {
return Java.performNow(function() {
return startActivity('com.tencent.mm.ui.contact.ContactsUI',{});
});
},
// ==================== 截图 ====================
takeScreenshot: function(params) {
return Java.performNow(function() {
var path = (params&&params.path)||'/sdcard/sdk_screenshot.png';
try {
var Runtime = Java.use('java.lang.Runtime');
Runtime.getRuntime().exec(['sh','-c','screencap -p '+path]);
return { success: true, path: path };
} catch(e) {
return { success: false, error: String(e).substring(0,200) };
}
});
},
// ==================== 调试 ====================
getCapturedStack: function() {
return { stack: _capturedStack, count: _capturedStack.length, real_send_class: _realSendClass };
}
};