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
相关产品推荐
相关产品推荐

