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

Flutter网络下载PDF加密存储、解密加载功能异常排查

项目背景

需实现从互联网获取PDF文件、加密后存储到本地设备,使用时解密加载PDF的功能,现有实现运行异常,以下是完整代码逻辑和问题定位结果。

现有实现代码

1. PDF抓取方法

Future<String> fetchThenStorePdf(DownloadedBook book) async {
  var pdfPath = await getBookUrl(book);
  book.bookFilePath = Uri.http('http://www.marakigebeya.com.et/mabdocuments/audio_e_books/fa872915-f364-4129-b373-06c1df078c00..pdf', pdfPath).toString();
  final response = await client
      .get(Uri.parse('${book.bookFilePath}'))
      .timeout(Duration(minutes: 3), onTimeout: () {
    throw Exception('connection timed out');
  });
  if (response.statusCode == 200) {
    print('The pdf file is ${response.bodyBytes}');
    return await storeEncryptedPdf(
      response.body,
      bookTitle: book.title,
    );
  } else {
    throw Exception('PDF file not found');
  }
}

2. 加密存储方法

Future<String> storeEncryptedPdf(String pdfByteFile,
    {required String bookTitle}) async {
  await PermissionHandler.requestStoragePermission();
  try {
    var directory = await getApplicationDocumentsDirectory();
    var bookDirectory = await Directory(path.join(
      '${directory.path}',
      'books',
    )).create(recursive: true);
    final filePath = path.join(bookDirectory.path, '$bookTitle');
    final file = File(filePath);
    var encryptedData = encryptionHandler.encryptData(pdfByteFile);
    await file.writeAsString(encryptedData, flush: true);
    return filePath;
  } catch (e) {
    throw Exception('File encryption failed');
  }
}

3. 加密实现(基于encrypt 5.0.1版本包)

String encryptData(String fileToEncrypt) {
  key = Key.fromUtf8(encryptionKeyString);
  iv = IV.fromUtf8(encryptionKeyString);
  final encrypter = Encrypter(
    AES(
      key,
      padding: null,
    ),
  );
  Encrypted encrypted = encrypter.encrypt(
    fileToEncrypt,
    iv: iv,
  );
  return encrypted.base64;
}

4. 解密读取方法

Future<String> decryptStoredPdf(String filePath) async {
  encryptionHandler.encryptionKeyString = 'theencryptionkey';
  final file = File(filePath);
  final byteFile = await file.readAsString();
  return encryptionHandler.decryptData(byteFile);
}

5. 解密实现

String decryptData(String filetoDecrypt) {
  key = Key.fromUtf8(encryptionKeyString);
  iv = IV.fromUtf8(encryptionKeyString);
  final encrypter = Encrypter(
    AES(
      key,
      padding: null,
    ),
  );
  String decrypted = encrypter.decrypt(
    Encrypted.from64(filetoDecrypt),
    iv: iv,
  );
  return decrypted;
} 
问题定位与修复方案
  • URI构造错误:Uri.http的第一个参数仅支持传入主机名,当前传入完整URL会导致最终请求地址格式异常,请求无法到达正确资源,可直接用Uri.parse拼接生成正确的PDF请求地址。
  • 二进制数据损坏:PDF属于二进制文件,直接调用response.body会默认按UTF-8规则解码二进制内容,非UTF-8编码的字节会丢失,导致原始PDF数据损坏,全程需用response.bodyBytes处理二进制数据,不要转换为普通字符串。
  • AES参数配置错误:AES要求密钥长度必须为16/24/32字节(对应AES-128/192/256),IV长度必须为16字节,若encryptionKeyString长度不符合要求会直接触发加解密失败;同时padding: null配置要求输入数据长度必须为16字节的整数倍,PDF文件长度大概率不满足该条件,需启用默认PKCS7填充。
  • 加解密数据类型错误:当前逻辑对字符串进行加解密,解密后返回的字符串无法直接被PDF加载组件识别,解密完成后需转换为字节数组再传入PDF渲染模块。

内容的提问来源于stack exchange,提问作者biniyam112

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 17:45:02