You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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";
      }
    }
    
  • 然后在应用内提示用户执行以下操作:
    1. 进入目标聊天后,点击右上角菜单 → 更多 → 导出聊天
    2. 选择「不含媒体」(生成.txt文件)或「含媒体」(生成.zip压缩包)
    3. 在分享选项中选择你的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 19:49:11