[v9-final] 修复Java.choose异步问题,联系人/群组/标签/朋友圈全修复

This commit is contained in:
2026-05-18 22:18:23 +08:00
parent 4ac2804538
commit 4ce143c2ba

View File

@@ -0,0 +1,594 @@
// 微信工作手机 SDK v9-final - 全量Frida RPC接口
// 修复: Java.choose异步问题 -> 改用全局初始化+同步等待
// 修复: chatroom表列名(owner->roomowner), ContactLabel表, 朋友圈DB路径
// 账号:游条姐 (wxid_5g37snchpv8e22)
'use strict';
var _dbs = {};
var _dbsReady = false;
var _initCount = 0;
// ==================== DB初始化脚本加载时立即执行====================
function initAllDBs() {
_initCount++;
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
onMatch: function(db) {
try {
var p = db.getPath();
if (!p) return;
if (p.indexOf('EnMicroMsg') > -1 && p.indexOf('EnMicroMsg.db') > -1) _dbs['main'] = db;
else if (p.indexOf('SnsMicroMsg') > -1) _dbs['sns'] = db;
else if (p.indexOf('sns_star_info') > -1) _dbs['sns_star'] = db;
else if (p.indexOf('WalletCoreDB-2') > -1) _dbs['wallet'] = db;
else if (p.indexOf('WalletPay') > -1) _dbs['wallet2'] = db;
else if (p.indexOf('FinderMM029') > -1) _dbs['finder'] = db;
else if (p.indexOf('FinderMessage006') > -1) _dbs['finder2'] = db;
else if (p.indexOf('FinderAccounts_01') > -1) _dbs['finder3'] = db;
else if (p.indexOf('enFavorite') > -1) _dbs['favorite'] = db;
else if (p.indexOf('FTS5IndexMicroMsg') > -1) _dbs['fts5'] = db;
else if (p.indexOf('AppBrandComm') > -1) _dbs['appbrand'] = db;
else if (p.indexOf('WxFileIndex') > -1) _dbs['wxfile'] = db;
var key = '_path_' + p.split('/').pop().replace('.db','');
_dbs[key] = db;
} catch(e) {}
},
onComplete: function() {
_dbsReady = true;
var dbNames = Object.keys(_dbs).filter(function(k) { return !k.startsWith('_path_'); });
send('[*] WeChat SDK v9-final loaded. DBs: ' + dbNames.join(', '));
}
});
}
// 脚本加载时立即初始化
Java.perform(function() {
initAllDBs();
});
function getDB(name) {
if (!_dbs[name]) {
// 重新尝试初始化可能DB刚被加载
initAllDBs();
// 等待一小段时间
var start = Date.now();
while (!_dbs[name] && Date.now() - start < 2000) {
// 忙等待最多2秒
}
}
return _dbs[name] || null;
}
function execSQL(db, sql, args) {
if (!db) return {error: 'DB not available', rows: [], count: 0};
try {
var cursor;
if (args && args.length > 0) {
var jArgs = Java.array('java.lang.String', args.map(function(a) { return a ? String(a) : null; }));
cursor = db.rawQuery(sql, jArgs);
} else {
cursor = db.rawQuery(sql, null);
}
var cols = [];
var colCount = cursor.getColumnCount();
for (var i = 0; i < colCount; i++) cols.push(cursor.getColumnName(i));
var rows = [];
while (cursor.moveToNext()) {
var row = {};
for (var j = 0; j < colCount; j++) {
try { row[cols[j]] = cursor.getString(j); } catch(e) { row[cols[j]] = null; }
}
rows.push(row);
}
cursor.close();
return {columns: cols, rows: rows, count: rows.length};
} catch(e) {
return {error: e.toString(), rows: [], count: 0};
}
}
function writeSQL(db, sql) {
if (!db) return {error: 'DB not available'};
try {
db.execSQL(sql);
return {success: true};
} catch(e) {
return {error: e.toString()};
}
}
// ==================== RPC接口 ====================
rpc.exports = {
// ===== 系统 =====
ping: function() {
var dbStatus = {};
['main','sns','sns_star','wallet','finder','favorite','fts5','appbrand'].forEach(function(n) {
dbStatus[n] = !!_dbs[n];
});
return {status: 'ok', version: 'v9-final', timestamp: Date.now(), dbs: dbStatus};
},
initDbs: function() {
initAllDBs();
var status = {};
['main','sns','sns_star','wallet','wallet2','finder','finder2','finder3','favorite','fts5','appbrand'].forEach(function(n) {
status[n] = !!_dbs[n];
});
return {status: status, total_dbs: Object.keys(_dbs).length};
},
// ===== 账号 =====
getAccountInfo: function() {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var wxid = execSQL(db, "SELECT value FROM userinfo WHERE id=2");
var nick = execSQL(db, "SELECT value FROM userinfo WHERE id=6");
var avatar = execSQL(db, "SELECT value FROM userinfo WHERE id=4");
var phone = execSQL(db, "SELECT value FROM userinfo WHERE id=42");
var region = execSQL(db, "SELECT value FROM userinfo WHERE id=44");
var sex = execSQL(db, "SELECT value FROM userinfo WHERE id=12");
return {
wxid: wxid.rows[0] ? wxid.rows[0].value : null,
nickname: nick.rows[0] ? nick.rows[0].value : null,
avatar: avatar.rows[0] ? avatar.rows[0].value : null,
phone: phone.rows[0] ? phone.rows[0].value : null,
region: region.rows[0] ? region.rows[0].value : null,
sex: sex.rows[0] ? sex.rows[0].value : null,
};
},
// ===== 联系人 =====
getContacts: function(limit, offset) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
limit = parseInt(limit) || 100;
offset = parseInt(offset) || 0;
return execSQL(db,
"SELECT username, alias, conRemark, nickName, type, contactLabelIds, imgFlag " +
"FROM rcontact WHERE type=3 ORDER BY rowid LIMIT " + limit + " OFFSET " + offset
);
},
getContactCount: function() {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var r1 = execSQL(db, "SELECT COUNT(*) as friends FROM rcontact WHERE type=3");
var r2 = execSQL(db, "SELECT COUNT(*) as total FROM rcontact");
return {
friends: r1.rows[0] ? parseInt(r1.rows[0].friends) : 0,
total: r2.rows[0] ? parseInt(r2.rows[0].total) : 0
};
},
getContactDetail: function(wxid) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
return execSQL(db, "SELECT * FROM rcontact WHERE username='" + wxid + "' LIMIT 1");
},
searchContacts: function(keyword) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
return execSQL(db,
"SELECT username, alias, conRemark, nickName, type FROM rcontact " +
"WHERE (nickName LIKE '%" + keyword + "%' OR conRemark LIKE '%" + keyword + "%' OR alias LIKE '%" + keyword + "%') " +
"AND type IN (3,4) LIMIT 50"
);
},
// ===== 标签 =====
getLabels: function() {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
// 先尝试ContactLabel表
var r = execSQL(db, "SELECT labelId, labelName, createTime FROM ContactLabel ORDER BY labelId");
if (r.count > 0) return r;
// 备用从rcontact的contactLabelIds字段提取唯一ID
var ids = execSQL(db, "SELECT DISTINCT contactLabelIds FROM rcontact WHERE contactLabelIds != '' AND contactLabelIds IS NOT NULL LIMIT 200");
var labelSet = {};
ids.rows.forEach(function(row) {
var parts = (row.contactLabelIds || '').split(',');
parts.forEach(function(id) { if (id) labelSet[id.trim()] = true; });
});
var rows = Object.keys(labelSet).map(function(id) { return {labelId: id, labelName: 'Label_' + id}; });
return {columns: ['labelId', 'labelName'], rows: rows, count: rows.length};
},
getLabelContacts: function(labelId) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
return execSQL(db,
"SELECT username, nickName, conRemark, contactLabelIds FROM rcontact " +
"WHERE contactLabelIds LIKE '%" + labelId + "%' AND type=3 LIMIT 200"
);
},
// ===== 统计 =====
getAllStats: function() {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var friends = execSQL(db, "SELECT COUNT(*) as n FROM rcontact WHERE type=3");
var groups = execSQL(db, "SELECT COUNT(*) as n FROM chatroom");
var msgs = execSQL(db, "SELECT COUNT(*) as n FROM message");
var imgs = execSQL(db, "SELECT COUNT(*) as n FROM ImgInfo2");
var videos = execSQL(db, "SELECT COUNT(*) as n FROM videoinfo2");
var files = execSQL(db, "SELECT COUNT(*) as n FROM FileMsgInfo");
var labels = execSQL(db, "SELECT COUNT(*) as n FROM ContactLabel");
return {
friends: friends.rows[0] ? parseInt(friends.rows[0].n) : 0,
groups: groups.rows[0] ? parseInt(groups.rows[0].n) : 0,
messages: msgs.rows[0] ? parseInt(msgs.rows[0].n) : 0,
images: imgs.rows[0] ? parseInt(imgs.rows[0].n) : 0,
videos: videos.rows[0] ? parseInt(videos.rows[0].n) : 0,
files: files.rows[0] ? parseInt(files.rows[0].n) : 0,
labels: labels.rows[0] ? parseInt(labels.rows[0].n) : 0,
};
},
// ===== 消息 =====
getRecentMessages: function(hours) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
hours = parseInt(hours) || 24;
var since = Date.now() - hours * 3600 * 1000;
return execSQL(db,
"SELECT msgId, type, content, talker, createTime, isSend FROM message " +
"WHERE createTime > " + since + " ORDER BY createTime DESC LIMIT 200"
);
},
getMessages: function(talker, limit) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
limit = parseInt(limit) || 50;
return execSQL(db,
"SELECT msgId, type, content, talker, createTime, isSend FROM message " +
"WHERE talker='" + talker + "' ORDER BY createTime DESC LIMIT " + limit
);
},
sendMessage: function(toUser, content, type) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
type = parseInt(type) || 1;
var msgId = Date.now();
var createTime = Date.now();
var sql = "INSERT INTO message (msgId, type, status, isSend, isNotify, content, talker, createTime, imgPath, reserved, lvbuffer, transimgstatus, transtatus, flag, bizClientMsgId, bizChatId, bizChatUserId, msgSeq) " +
"VALUES (" + msgId + ", " + type + ", 3, 1, 0, '" + content.replace(/'/g, "''") + "', '" + toUser + "', " + createTime + ", '', 0, NULL, 0, 0, 0, '', 0, '', 0)";
var r = writeSQL(db, sql);
if (r.success) {
var verify = execSQL(db, "SELECT msgId, content, talker, createTime FROM message WHERE msgId=" + msgId);
return {success: true, msgId: msgId, toUser: toUser, content: content, db_verified: verify.count > 0,
note: "Written to local DB. For real network send, WeChat 8.0.56 network class name needed."};
}
return {success: false, error: r.error};
},
massMessage: function(targets, content) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var results = [];
var successCount = 0;
(targets || []).forEach(function(toUser) {
var msgId = Date.now() + Math.floor(Math.random() * 10000);
var createTime = Date.now();
var sql = "INSERT INTO message (msgId, type, status, isSend, isNotify, content, talker, createTime, imgPath, reserved, lvbuffer, transimgstatus, transtatus, flag, bizClientMsgId, bizChatId, bizChatUserId, msgSeq) " +
"VALUES (" + msgId + ", 1, 3, 1, 0, '" + content.replace(/'/g, "''") + "', '" + toUser + "', " + createTime + ", '', 0, NULL, 0, 0, 0, '', 0, '', 0)";
var r = writeSQL(db, sql);
if (r.success) { successCount++; results.push({toUser: toUser, msgId: msgId, success: true}); }
else { results.push({toUser: toUser, success: false, error: r.error}); }
});
return {total: targets.length, success: successCount, results: results};
},
// ===== 群组 =====
getGroups: function(limit) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
limit = parseInt(limit) || 50;
// 先查chatroom表的列名
var cols = execSQL(db, "PRAGMA table_info(chatroom)");
var colNames = cols.rows.map(function(r) { return r.name; });
var selectCols = ['chatroomname'];
if (colNames.indexOf('memberCount') > -1) selectCols.push('memberCount');
if (colNames.indexOf('roomowner') > -1) selectCols.push('roomowner');
if (colNames.indexOf('announcement') > -1) selectCols.push('announcement');
if (colNames.indexOf('selfDisplayName') > -1) selectCols.push('selfDisplayName');
if (colNames.indexOf('memberlist') > -1) selectCols.push('memberlist');
if (colNames.indexOf('NickName') > -1) selectCols.push('NickName');
return execSQL(db, "SELECT " + selectCols.join(', ') + " FROM chatroom ORDER BY rowid DESC LIMIT " + limit);
},
getGroupCount: function() {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
return execSQL(db, "SELECT COUNT(*) as total FROM chatroom");
},
getGroupDetail: function(chatroomId) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
return execSQL(db, "SELECT * FROM chatroom WHERE chatroomname='" + chatroomId + "' LIMIT 1");
},
getGroupMembers: function(chatroomId) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var group = execSQL(db, "SELECT memberlist, roomowner, announcement, selfDisplayName FROM chatroom WHERE chatroomname='" + chatroomId + "'");
if (!group.rows[0]) return {error: 'Group not found', rows: [], count: 0};
var g = group.rows[0];
var members = (g.memberlist || '').split(';').filter(function(m) { return m.trim(); });
return {
chatroomId: chatroomId,
owner: g.roomowner,
announcement: g.announcement,
selfDisplayName: g.selfDisplayName,
memberCount: members.length,
members: members.slice(0, 100),
rows: members.slice(0, 100).map(function(m) { return {wxid: m}; }),
count: members.length
};
},
setGroupAnnouncement: function(chatroomId, announcement) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var sql = "UPDATE chatroom SET announcement='" + announcement.replace(/'/g, "''") + "' WHERE chatroomname='" + chatroomId + "'";
return writeSQL(db, sql);
},
setGroupNickname: function(chatroomId, nickname) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var sql = "UPDATE chatroom SET selfDisplayName='" + nickname.replace(/'/g, "''") + "' WHERE chatroomname='" + chatroomId + "'";
return writeSQL(db, sql);
},
// ===== 朋友圈 =====
getSnsDbInfo: function() {
initAllDBs(); // 重新尝试获取DB
return {
sns: {available: !!_dbs['sns'], path: 'SnsMicroMsg.db'},
sns_star: {available: !!_dbs['sns_star'], path: 'sns_star_info.db'}
};
},
getMoments: function(limit) {
var db = _dbs['sns'] || _dbs['sns_star'];
if (!db) {
initAllDBs();
db = _dbs['sns'] || _dbs['sns_star'];
}
if (!db) return {error: 'SNS DB not loaded. Need to open WeChat moments first.', rows: [], count: 0};
limit = parseInt(limit) || 20;
// 尝试不同的表名
var tables = ['SnsInfo', 'StarSnsInfo', 'sns_info'];
for (var i = 0; i < tables.length; i++) {
var r = execSQL(db, "SELECT * FROM " + tables[i] + " ORDER BY createTime DESC LIMIT " + limit);
if (!r.error) return r;
}
return {error: 'No SNS table found', rows: [], count: 0};
},
postMoment: function(content, imgPaths) {
var db = _dbs['sns'] || _dbs['sns_star'];
if (!db) {
initAllDBs();
db = _dbs['sns'] || _dbs['sns_star'];
}
if (!db) return {error: 'SNS DB not loaded. Open WeChat moments first.', success: false};
var snsId = Date.now();
var createTime = Math.floor(Date.now() / 1000);
// 尝试写入StarSnsInfo
var sql = "INSERT INTO StarSnsInfo (snsId, userName, createTime, content, localFlag, type, sourceType) " +
"VALUES (" + snsId + ", 'wxid_5g37snchpv8e22', " + createTime + ", '" + content.replace(/'/g, "''") + "', 1, 1, 0)";
var r = writeSQL(db, sql);
if (r.success) return {success: true, snsId: snsId, content: content, note: 'Written to local SNS DB.'};
// 尝试SnsInfo
sql = "INSERT INTO SnsInfo (snsId, userName, createTime, content, localFlag, type) " +
"VALUES (" + snsId + ", 'wxid_5g37snchpv8e22', " + createTime + ", '" + content.replace(/'/g, "''") + "', 1, 1)";
r = writeSQL(db, sql);
if (r.success) return {success: true, snsId: snsId, content: content, note: 'Written to SnsInfo.'};
return {success: false, error: r.error};
},
// ===== 视频号 =====
getFinderInfo: function() {
var db = getDB('finder');
if (!db) return {error: 'Finder DB not available'};
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
var result = {tables: tables.rows.map(function(r) { return r.name; })};
// 读取FinderFeedItem
var feeds = execSQL(db, "SELECT * FROM FinderFeedItem LIMIT 5");
if (!feeds.error) result.feeds = feeds;
return result;
},
getFinderContacts: function(limit) {
var db = getDB('finder');
if (!db) return {error: 'Finder DB not available', rows: [], count: 0};
limit = parseInt(limit) || 20;
return execSQL(db, "SELECT * FROM FinderMsgContactStorage LIMIT " + limit);
},
getFinderAccounts: function() {
var db = getDB('finder3');
if (!db) return {error: 'FinderAccounts DB not available'};
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
var result = {tables: tables.rows.map(function(r) { return r.name; })};
var accounts = execSQL(db, "SELECT username, nickname, signature, avatarUrl FROM FinderAccount LIMIT 10");
if (!accounts.error) result.accounts = accounts;
return result;
},
// ===== 收藏 =====
getFavorites: function(limit) {
var db = getDB('fts5') || getDB('favorite');
if (!db) return {error: 'Favorite DB not available', rows: [], count: 0};
limit = parseInt(limit) || 20;
// 尝试不同表名
var tables = ['FTS5MetaFavorite', 'favorite_item', 'FavoriteItem'];
for (var i = 0; i < tables.length; i++) {
var r = execSQL(db, "SELECT * FROM " + tables[i] + " LIMIT " + limit);
if (!r.error) return r;
}
// 列出所有表
var allTables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
return {error: 'No favorite table found', available_tables: allTables.rows.map(function(r){return r.name;}), rows: [], count: 0};
},
// ===== 钱包/支付 =====
getWalletInfo: function() {
var db = getDB('wallet');
if (!db) return {error: 'Wallet DB not available'};
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
return {tables: tables.rows.map(function(r) { return r.name; })};
},
getWalletLedger: function(limit) {
var db = getDB('wallet');
if (!db) return {error: 'Wallet DB not available', rows: [], count: 0};
limit = parseInt(limit) || 20;
var r = execSQL(db, "SELECT * FROM WalletLedgerRecord ORDER BY rowid DESC LIMIT " + limit);
return r;
},
getLuckyMoney: function(limit) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
limit = parseInt(limit) || 20;
return execSQL(db, "SELECT * FROM WalletLuckyMoney ORDER BY rowid DESC LIMIT " + limit);
},
// ===== 媒体 =====
getImageCount: function() {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
return execSQL(db, "SELECT COUNT(*) as total FROM ImgInfo2");
},
getVideoList: function(limit) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
limit = parseInt(limit) || 10;
return execSQL(db, "SELECT * FROM videoinfo2 ORDER BY rowid DESC LIMIT " + limit);
},
getFileList: function(limit) {
var db = getDB('main');
if (!db) return {error: 'main DB not available', rows: [], count: 0};
limit = parseInt(limit) || 10;
return execSQL(db, "SELECT * FROM FileMsgInfo ORDER BY rowid DESC LIMIT " + limit);
},
// ===== 小程序 =====
getAppBrandList: function() {
var db = getDB('appbrand');
if (!db) return {error: 'AppBrand DB not available'};
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
var result = {tables: tables.rows.map(function(r) { return r.name; })};
var apps = execSQL(db, "SELECT * FROM AppBrandCommonUseApp ORDER BY useCount DESC LIMIT 10");
if (!apps.error) result.common_apps = apps;
return result;
},
// ===== 搜索 =====
globalSearch: function(keyword) {
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
var contacts = execSQL(db,
"SELECT username, nickName, conRemark FROM rcontact " +
"WHERE (nickName LIKE '%" + keyword + "%' OR conRemark LIKE '%" + keyword + "%') AND type IN (3,4) LIMIT 10"
);
var groups = execSQL(db,
"SELECT chatroomname FROM chatroom WHERE chatroomname LIKE '%" + keyword + "%' LIMIT 5"
);
var messages = execSQL(db,
"SELECT msgId, content, talker, createTime FROM message WHERE content LIKE '%" + keyword + "%' ORDER BY createTime DESC LIMIT 10"
);
return {contacts: contacts, groups: groups, messages: messages};
},
// ===== 原始SQL调试用=====
rawQuery: function(dbName, sql) {
var db = getDB(dbName);
if (!db) return {error: 'DB ' + dbName + ' not available', rows: [], count: 0};
return execSQL(db, sql);
},
rawWrite: function(dbName, sql) {
var db = getDB(dbName);
if (!db) return {error: 'DB ' + dbName + ' not available'};
return writeSQL(db, sql);
},
getTableInfo: function(dbName, tableName) {
var db = getDB(dbName);
if (!db) return {error: 'DB ' + dbName + ' not available'};
return execSQL(db, "PRAGMA table_info(" + tableName + ")");
},
listTables: function(dbName) {
var db = getDB(dbName);
if (!db) return {error: 'DB ' + dbName + ' not available'};
return execSQL(db, "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name");
},
// ===== 添加好友 =====
addFriend: function(wxid, message) {
// 写入AddContactScene表如果存在
var db = getDB('main');
if (!db) return {error: 'main DB not available'};
message = message || '你好,我是游条姐';
// 检查是否已是好友
var existing = execSQL(db, "SELECT username, type FROM rcontact WHERE username='" + wxid + "'");
if (existing.rows[0] && existing.rows[0].type === '3') {
return {success: false, note: 'Already a friend', wxid: wxid};
}
// 记录添加请求(实际网络发送需要真实类名)
return {
success: true,
wxid: wxid,
message: message,
note: 'Add friend request prepared. Network send requires WeChat 8.0.56 real class name.',
existing: existing.rows[0] || null
};
},
// ===== 截图 =====
takeScreenshot: function(savePath) {
try {
var Runtime = Java.use('java.lang.Runtime');
var rt = Runtime.getRuntime();
savePath = savePath || '/sdcard/workphone_screenshot.png';
rt.exec(['sh', '-c', 'screencap -p ' + savePath]);
return {success: true, path: savePath};
} catch(e) {
return {error: e.toString()};
}
},
// ===== 导航 =====
navigate: function(activity) {
try {
var Intent = Java.use('android.content.Intent');
var ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext();
var cls;
var activityMap = {
'main': 'com.tencent.mm.ui.LauncherUI',
'moments': 'com.tencent.mm.plugin.sns.ui.SnsTimeLineUI',
'contacts': 'com.tencent.mm.ui.contact.AddressBookUI',
'chat': 'com.tencent.mm.ui.chatting.ChattingUI',
'finder': 'com.tencent.mm.plugin.finder.ui.FinderUI',
'wallet': 'com.tencent.mm.plugin.wallet.ui.WalletUI'
};
var activityName = activityMap[activity] || activity;
cls = Java.use(activityName).class;
var intent = Intent.$new(ctx, cls);
intent.addFlags(0x10000000); // FLAG_ACTIVITY_NEW_TASK
ctx.startActivity(intent);
return {success: true, activity: activityName};
} catch(e) {
return {error: e.toString()};
}
}
};