如何将WhatsApp聊天记录导出至Flutter应用并上传至应用数据库?
实现WhatsApp聊天记录导出并上传到Flutter应用数据库的完整方案
我来帮你一步步拆解这个需求的实现逻辑——因为WhatsApp并没有开放自动导出聊天记录的API,所以我们得结合它的内置导出功能,配合Flutter的文件接收、解析能力来完成整个流程:
一、引导用户手动导出WhatsApp聊天记录
你没办法通过代码直接触发WhatsApp导出,只能引导用户完成内置的导出操作,同时可以用url_launcher快速打开目标聊天界面提升体验:
- 用
url_launcher打开指定聊天(示例代码):import 'package:url_launcher/url_launcher.dart'; void openWhatsAppChat(String phoneNumber) async { final uri = Uri.parse("whatsapp://send?phone=$phoneNumber"); if (await canLaunchUrl(uri)) { await launchUrl(uri); } else { throw "Could not open WhatsApp"; } } - 然后在应用内提示用户执行以下操作:
- 进入目标聊天后,点击右上角菜单 → 更多 → 导出聊天
- 选择「不含媒体」(生成.txt文件)或「含媒体」(生成.zip压缩包)
- 在分享选项中选择你的Flutter应用作为接收方
二、配置Flutter应用接收分享的文件
要让应用能接收WhatsApp导出的文件,需要分别配置Android和iOS的文件接收权限,再用第三方包监听分享事件:
1. 平台配置
- Android:在
AndroidManifest.xml的<activity>标签内添加intent-filter,支持.txt和.zip文件:<intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> <data android:mimeType="application/zip" /> </intent-filter> - iOS:在
Info.plist中添加文件类型声明:<key>CFBundleDocumentTypes</key> <array> <dict> <key>CFBundleTypeName</key> <string>Text File</string> <key>LSHandlerRank</key> <string>Alternate</string> <key>LSItemContentTypes</key> <array> <string>public.plain-text</string> </array> </dict> <dict> <key>CFBundleTypeName</key> <string>Zip Archive</string> <key>LSHandlerRank</key> <string>Alternate</string> <key>LSItemContentTypes</key> <array> <string>public.zip-archive</string> </array> </dict> </array>
2. Flutter端监听分享事件
使用receive_sharing_intent包监听用户分享的文件,示例代码:
import 'package:receive_sharing_intent/receive_sharing_intent.dart'; import 'dart:io'; StreamSubscription? _sharedFileSubscription; List<SharedMediaFile>? _receivedFiles; @override void initState() { super.initState(); // 监听实时分享的文件 _sharedFileSubscription = ReceiveSharingIntent.getMediaStream() .listen((List<SharedMediaFile> files) { setState(() { _receivedFiles = files; if (_receivedFiles?.isNotEmpty == true) { // 拿到文件后开始处理 processExportedFile(_receivedFiles!.first.path); } }); }, onError: (err) { print('接收文件出错: $err'); }); // 处理应用未启动时的分享请求 ReceiveSharingIntent.getInitialMedia().then((List<SharedMediaFile> files) { setState(() { _receivedFiles = files; if (_receivedFiles?.isNotEmpty == true) { processExportedFile(_receivedFiles!.first.path); } }); }); } @override void dispose() { _sharedFileSubscription?.cancel(); super.dispose(); }
三、解析WhatsApp导出的聊天记录
WhatsApp导出的.txt文件有固定格式,每条记录大致为[YYYY-MM-DD HH:MM:SS] 发送者: 消息内容,可以用正则表达式解析:
// 定义聊天消息模型 class ChatMessage { final DateTime timestamp; final String sender; final String content; ChatMessage({required this.timestamp, required this.sender, required this.content}); } Future<List<ChatMessage>> parseWhatsAppTxt(String filePath) async { final file = File(filePath); final content = await file.readAsString(); final lines = content.split('\n'); final chatList = <ChatMessage>[]; // 匹配聊天记录的正则表达式(适配多数地区格式) final chatRegex = RegExp(r'\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] (.*?): (.*)'); ChatMessage? lastMessage; for (final line in lines) { final match = chatRegex.firstMatch(line); if (match != null) { // 新的聊天记录 final timestamp = DateTime.parse(match.group(1)!); final sender = match.group(2)!; final content = match.group(3)!; lastMessage = ChatMessage(timestamp: timestamp, sender: sender, content: content); chatList.add(lastMessage); } else if (lastMessage != null && line.isNotEmpty) { // 处理多行消息(WhatsApp换行消息没有前缀) lastMessage = ChatMessage( timestamp: lastMessage.timestamp, sender: lastMessage.sender, content: '${lastMessage.content}\n$line', ); chatList[chatList.length - 1] = lastMessage; } } return chatList; }
如果用户导出的是带媒体的.zip文件,需要先用archive包解压,提取里面的.txt文件和媒体资源后再分别处理。
四、上传解析后的聊天记录到数据库
解析完成后,用http包将数据发送到你的后端API(假设用REST接口):
import 'package:http/http.dart' as http; import 'dart:convert'; Future<void> uploadChats(List<ChatMessage> chats) async { final apiUrl = Uri.parse('https://你的后端接口地址/upload-chats'); final chatData = chats.map((chat) => { 'timestamp': chat.timestamp.toIso8601String(), 'sender': chat.sender, 'content': chat.content, }).toList(); final response = await http.post( apiUrl, headers: {'Content-Type': 'application/json'}, body: jsonEncode({'chats': chatData}), ); if (response.statusCode == 200) { print('聊天记录上传成功'); } else { throw Exception('上传失败: ${response.body}'); } }
如果需要上传媒体文件,改用MultipartRequest实现:
Future<void> uploadMedia(String filePath) async { final apiUrl = Uri.parse('https://你的后端接口地址/upload-media'); final request = http.MultipartRequest('POST', apiUrl); request.files.add(await http.MultipartFile.fromPath('media', filePath)); final response = await request.send(); if (response.statusCode == 200) { print('媒体文件上传成功'); } else { throw Exception('媒体上传失败'); } }
注意事项
- WhatsApp的导出格式可能因语言/地区略有差异,需要测试不同场景调整正则表达式
- 处理大文件时建议逐行读取,避免内存溢出
- 记得用
permission_handler包申请存储访问权限(Android的READ_EXTERNAL_STORAGE、iOS的文档访问权限)
内容的提问来源于stack exchange,提问作者Aizan Sagheer
相关产品推荐
相关产品推荐

