自动记账安全说明 与代码公开
很多用户关心自动记账到底在后台做了什么,会不会读取聊天内容、支付密码或者银行卡信息。为了让你用得更放心,小账 Lite 将核心的 自动记账解析逻辑公开展示,用最直接的方式告诉你:我们只关注 与记账相关的金额、类型和来源,不会碰你不愿意被看到的隐私内容。
只监听支付通知
自动记账只会处理来自 微信支付、支付宝 等支付类通知,不会读取聊天记录、朋友圈、图片等内容。逻辑中通过 packageName 精确判断来源。
只解析金额和方向
我们只从通知文本中提取 金额、是“收入还是支出”、来自微信还是支付宝,不会提取银行卡号、手机号、支付密码等任何敏感字段。
本地解析、可控开关
所有解析逻辑都在本地完成,并且有 独立的开关和自定义规则。你可以只开启微信、只开启支付宝,甚至完全关闭自动记账。
自动记账核心代码片段
语言为 Dart,运行在 App 本地,并不会把原始通知内容上传到服务器。
Expense parseTransactionText(String text, String type2) {
double amount = 0.0;
String type = '';
Map<String, String> nameObj = {
'支出': '其他',
'收入': '收入',
'收款': '收入',
'支付': '其他',
'wx': '微信',
'zfb': '支付宝',
};
try {
if (text.contains('收款') || text.contains('收入')) {
type = '收款';
} else if (text.contains('支出')) {
type = '支出';
} else if (text.contains('支付')) {
type = '支出';
}
RegExp amountRegExp = RegExp(r'(\d+\.\d{2})\s*元');
Match? amountMatch = amountRegExp.firstMatch(text);
if (amountMatch != null) {
amount = double.parse(amountMatch.group(1)!);
} else {
RegExp fallbackAmountRegExp =
RegExp(r'[¥¥]?\s*(\d+\.\d{2})(?=\D|$)');
Match? fallbackMatch = fallbackAmountRegExp.firstMatch(text);
if (fallbackMatch != null) {
amount = double.parse(fallbackMatch.group(1)!);
}
}
} catch (e) {
print('解析错误: $e');
}
return Expense(
amount: amount,
category: nameObj[type] ?? '其他',
description: "AI自动记录-" + nameObj[type2]!,
date: DateTime.now(),
);
}
Future<void> _handleAutoExpenseNotification(Map<String, dynamic> data) async {
final nativeHandled = data["nativeHandled"] == true;
if (nativeHandled == true) {
return;
}
final prefs = await SharedPreferences.getInstance();
List<dynamic> customRules = [];
final rawRules = prefs.getString('auto_book_custom_rules_v1');
if (rawRules != null && rawRules.isNotEmpty) {
try {
customRules = jsonDecode(rawRules) as List<dynamic>;
} catch (_) {
customRules = [];
}
}
final wechatEnabled = prefs.getBool('auto_book_wechat_enabled') ?? true;
final alipayEnabled = prefs.getBool('auto_book_alipay_enabled') ?? true;
final packageName = data["packageName"] ?? "";
String text = data["text"] ?? "";
final normalized = _normalizeText(text);
final matchedCustom = _matchesCustomRules(normalized, customRules);
if (packageName != 'com.tencent.mm' &&
packageName != 'com.eg.android.AlipayGphone' &&
!matchedCustom) {
return;
}
final isWeChat = packageName == 'com.tencent.mm';
if (isWeChat && !matchedCustom && !_isNormalWeChatPayNotification(normalized)) {
return;
}
if (isWeChat && !wechatEnabled && !matchedCustom) {
return;
}
if (!isWeChat && !alipayEnabled && !matchedCustom) {
return;
}
final title = (data["title"] ?? "").toString();
final postTime = (data["postTime"] ?? "").toString();
final id = (data["id"] ?? "").toString();
String sig;
Expense expense;
if (isWeChat) {
expense = parseTransactionText(normalized, 'wx');
} else {
expense = parseTransactionText(normalized, 'zfb');
if (expense.amount == 0.0) {
expense = parseTransactionText(title, 'zfb');
}
}
if (expense.amount == 0.0) {
return;
}
final direction = expense.category == '收入' ? 'in' : 'out';
String source;
if (matchedCustom) {
source = 'custom';
} else if (isWeChat) {
source = 'wx';
} else {
source = packageName;
}
sig = '$source|$direction|${expense.amount.toStringAsFixed(2)}';
if (_isDuplicate(sig)) {
return;
}
final processedExpense = await _maybeEditAutoExpenseRemark(expense);
final toAdd = processedExpense ?? expense;
if (!mounted) {
return;
}
Provider.of<ExpenseProvider>(context, listen: false).addExpense(toAdd);
await _updateForegroundTodayTotal();
_markProcessed(sig);
final ttsEnabled = prefs.getBool('tts_enabled') ?? false;
if (ttsEnabled) {
if (expense.category == '其他') {
await audiotext(
"已支出${expense.amount.toStringAsFixed(2)}元",
onError: (msg) {
print("TTS错误: $msg");
},
);
} else {
await audiotext(
"已收入${expense.amount.toStringAsFixed(2)}元",
onError: (msg) {
print("TTS错误: $msg");
},
);
}
}
}
这段代码在安全上做了哪些事情?
1)严格限制来源: 只有包名是 微信支付(com.tencent.mm)、 支付宝(com.eg.android.AlipayGphone) 或你自己配置的自定义规则才会被处理,其它 App 的通知全部直接忽略。
2)用户可控开关:
通过 auto_book_wechat_enabled
和 auto_book_alipay_enabled
两个开关,可以单独关闭微信或支付宝的自动记账。
3)只解析金额与收支方向:
代码里用正则 (\d+\.\d{2}) 元
去提取金额,只关心类似 “88.88 元” 这样的数字,不会把整条通知内容存起来。
4)重复拦截机制:
通过 _isDuplicate(sig)
生成签名,防止同一笔通知被多次记账。
5)本地备注可编辑:
在记账前调用 _maybeEditAutoExpenseRemark
,让你有机会本地修改备注,所有处理都在本机完成。
6)语音播报可选:
只有在你打开 tts_enabled 的情况下,
才会播报 “已支出/已收入 xx 元”,没有任何额外信息被朗读或上报。
数据存储与上传说明
自动记账生成的账单会以 标准 JSON 格式 保存到本地数据库中,如果你开启云端同步,数据会在 加密通道 中上传,仅包含记账必需的字段(金额、分类、时间、来源),不会上传原始通知全文。
如果你仍然对隐私有顾虑,可以选择 关闭自动记账功能,仅使用手动记账, 小账 Lite 的所有核心功能依然可以使用。