赞
踩
encryptIos_until.dart
import 'encrypt_ios_platform_interface.dart'; export 'package:encrypt_ios/encrypt_ios_until.dart'; class EncryptIosUntil { String KEY; String IV; EncryptIosUntil({this.KEY = "xxxxxxxxxxxxxxxx", this.IV = "vvvvvvvvvvvvvvvv"});//这里是配置默认的key和iv,各16字节 Future<String?> encryptStr({required String str,String? key, String? iv}){ return EncryptIosPlatform.instance.encryptStr(key??KEY,iv??IV,str); } Future<String?> decryptStr({required String str,String? key, String? iv}){ return EncryptIosPlatform.instance.decryptStr(key??KEY,iv??IV,str); } Future<bool?> encryptFile({required String src,required String desc,String? key, String? iv}){ return EncryptIosPlatform.instance.encryptFile(key??KEY,iv??IV, src, desc); } Future<bool?> decryptFile({required String src,required String desc,String? key, String? iv}){ return EncryptIosPlatform.instance.decryptFile(key??KEY,iv??IV, src, desc); } }
encrypt_ios_platform_interface.dart
import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'encrypt_ios_method_channel.dart'; abstract class EncryptIosPlatform extends PlatformInterface { EncryptIosPlatform() : super(token: _token); static final Object _token = Object(); static EncryptIosPlatform _instance = MethodChannelEncryptIos(); static EncryptIosPlatform get instance => _instance; static set instance(EncryptIosPlatform instance) { PlatformInterface.verifyToken(instance, _token); _instance = instance; } Future<String?> encryptStr(String key,String iv,String str){ throw UnimplementedError('encryptStr() has not been implemented.'); } Future<String?> decryptStr(String key,String iv,String str){ throw UnimplementedError('decryptStr() has not been implemented.'); } Future<bool?> encryptFile(String key,String iv,String src,String desc){ throw UnimplementedError('encryptFile() has not been implemented.'); } Future<bool?> decryptFile(String key,String iv,String src,String desc){ throw UnimplementedError('decryptFile() has not been implemented.'); } }
encrypt_ios_method_channel.dart
import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'encrypt_ios_platform_interface.dart'; /// An implementation of [EncryptIosPlatform] that uses method channels. class MethodChannelEncryptIos extends EncryptIosPlatform { /// The method channel used to interact with the native platform. @visibleForTesting final methodChannel = const MethodChannel('encrypt_ios'); @override Future<String?> encryptStr(String key,String iv,String str) async { final enStr = await methodChannel.invokeMethod<String>('encryptStr',<String, dynamic>{ 'key': key, 'iv': iv, 'str': str }); return enStr; } @override Future<String?> decryptStr(String key,String iv,String str) async { final deStr = await methodChannel.invokeMethod<String>('decryptStr',<String, dynamic>{ 'key': key, 'iv': iv, 'str': str }); return deStr; } @override Future<bool?> decryptFile(String key, String iv, String src, String desc) async { final result = await methodChannel.invokeMethod<bool>('decryptFile',<String, dynamic>{ 'key': key, 'iv': iv, 'src': src, 'desc': desc }); return result; } @override Future<bool?> encryptFile(String key, String iv, String src, String desc) async { final result = await methodChannel.invokeMethod<bool>('encryptFile',<String, dynamic>{ 'key': key, 'iv': iv, 'src': src, 'desc': desc }); return result; } }
添加 s.dependency ‘CommonCryptoModule’
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. # Run `pod lib lint encrypt.podspec` to validate before publishing. # Pod::Spec.new do |s| s.name = 'encrypt' s.version = '0.0.1' s.summary = 'A new Flutter project.' s.description = <<-DESC A new Flutter project. DESC s.homepage = 'http://example.com' s.license = { :file => '../LICENSE' } s.author = { 'Your Company' => 'email@example.com' } s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'Flutter' s.dependency 'CommonCryptoModule' s.platform = :ios, '9.0' # Flutter.framework does not contain a i386 slice. s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } s.swift_version = '5.0' end
搜索Swift找到对应的.swift文件进行修改
SwiftEncrypIosPlugin.swift
import Flutter import UIKit import CryptoSwift import CommonCrypto public class SwiftEncryptIosPlugin: NSObject, FlutterPlugin { public static func register(with registrar: FlutterPluginRegistrar) { let channel = FlutterMethodChannel(name: "encrypt_ios", binaryMessenger: registrar.messenger()) let instance = SwiftEncryptIosPlugin() registrar.addMethodCallDelegate(instance, channel: channel) } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { //传入参数 let arg = call.arguments //获取必要的key与iv if let args = arg as? [String: Any], let key = args["key"] as? String, let iv = args["iv"] as? String { let keyData = Data(bytes: key, count: key.count) let ivData = Data(bytes: iv, count: iv.count) switch call.method {//区分调用方法 case "encryptStr": if let str = args["str"] as? String{ debugPrint("encryptStr->str:"+str) let deData = aesCBC(operation: kCCEncrypt, data: Data(bytes: str.bytes, count: str.count), keyData: keyData, ivData: ivData) debugPrint("encryptStr->destr:"+deData.base64EncodedString()) result(deData.base64EncodedString())//编码base64返回,与Android端相同 }else{ result(FlutterError(code: "-1", message: "iOS could not extract " + "flutter arguments in method: (encryptStr),missing parameter 'str'", details: nil)) } case "decryptStr": if let str = args["str"] as? String{ debugPrint("decryptStr->str:"+str) let strData = Data(base64Encoded: str)//需要先解码base64,再进行解密 let deData = aesCBC(operation: kCCDecrypt, data:strData!, keyData: keyData, ivData: ivData) let deStr = String(bytes: deData.bytes,encoding: String.Encoding.utf8)//转utf-8输出 debugPrint("decryptStr->destr:",deStr) result(deStr) }else{ result(FlutterError(code: "-1", message: "iOS could not extract " + "flutter arguments in method: (encryptStr),missing parameter 'str'", details: nil)) } case "encryptFile": if let src = args["src"] as? String, let desc = args["desc"] as? String{ var isSuccess = false do{ isSuccess = try aesCBCFile(operation: kCCEncrypt, keyData: keyData, ivData: ivData, _srcPath: src, _descPath: desc) result(isSuccess) }catch{ result(FlutterError(code: "-1", message: error.localizedDescription, details: nil)) } }else{ result(FlutterError(code: "-1", message: "iOS could not extract " + "flutter arguments in method: (encryptFile),missing parameter 'src/desc'", details: nil)) } case "decryptFile": if let src = args["src"] as? String, let desc = args["desc"] as? String{ var isSuccess = false do{ isSuccess = try aesCBCFile(operation: kCCDecrypt, keyData: keyData, ivData: ivData, _srcPath: src, _descPath: desc) result(isSuccess) }catch{ result(FlutterError(code: "-1", message: error.localizedDescription, details: nil)) } }else{ result(FlutterError(code: "-1", message: "iOS could not extract " + "flutter arguments in method: (decryptFile),missing parameter 'src/desc'", details: nil)) } default : result("iOS " + UIDevice.current.systemVersion) } }else{ result(FlutterError(code: "-1", message: "iOS could not extract " + "flutter arguments in : missing parameter(key or iv)", details: nil)) } } // AES加解密 public func aesCBC(operation: Int, data:Data, keyData: Data, ivData: Data) -> Data { let dataLength = data.count let cryptLength = size_t(dataLength + kCCBlockSizeAES128) var cryptData = Data(count:cryptLength) let keyLength = size_t(kCCKeySizeAES128) let options = CCOptions(kCCOptionPKCS7Padding) var numBytesEncrypted :size_t = 0 let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in data.withUnsafeBytes {dataBytes in ivData.withUnsafeBytes {ivBytes in keyData.withUnsafeBytes {keyBytes in CCCrypt(CCOperation(operation), CCAlgorithm(kCCAlgorithmAES), options, keyBytes, keyLength, ivBytes, dataBytes, dataLength, cryptBytes, cryptLength, &numBytesEncrypted) } } } } if UInt32(cryptStatus) == UInt32(kCCSuccess) { cryptData.removeSubrange(numBytesEncrypted..<cryptData.count) } else { print("Error: \(cryptStatus)") } return cryptData; } public func aesCBCFile(operation: Int, keyData: Data, ivData: Data, _srcPath:String,_descPath:String) throws -> Bool{ debugPrint("FileSrc:"+_srcPath) debugPrint("FileDesc:"+_descPath) let startTime = CFAbsoluteTimeGetCurrent()//记录方法开始时间 if !(FileManager.default.fileExists(atPath: _srcPath)) {//判断源文件是否存在 throw URLError(URLError.cannotWriteToFile,userInfo: ["message":"can't find file by srcPath"]) } let inputStream = InputStream(fileAtPath: _srcPath) if inputStream == nil {//判断源文件流是否存在 throw URLError(URLError.cannotWriteToFile,userInfo: ["message":"can't find file by srcPath"]) } var srcFileSize : Int = 0 let src = try FileManager.default.attributesOfItem(atPath: _srcPath) srcFileSize = Int(src[FileAttributeKey.size] as! UInt64) debugPrint("Begin,SrcFileSize:",srcFileSize) //初始化目标文件流,如果存在目标文件,进行移除 if(FileManager.default.fileExists(atPath: _descPath)){ try FileManager.default.removeItem(atPath: _descPath) } FileManager.default.createFile(atPath: _descPath, contents: nil) let outputStream = OutputStream(toFileAtPath: _descPath, append: true)! outputStream.open() //初始化加解密 let keyLength = size_t(kCCKeySizeAES128) let options = CCOptions(kCCOptionPKCS7Padding) var cryptor: CCCryptorRef? // defer { // CCCryptorRelease(cryptor) // } let status = keyData.withUnsafeBytes {keyBytes in ivData.withUnsafeBytes {ivBytes in CCCryptorCreate(CCOperation(operation), CCAlgorithm(kCCAlgorithmAES), options, keyBytes, keyLength, ivBytes, &cryptor) } }//创建加解密对象 inputStream?.open()//开启输入流 var bufused = 0//bufused为实际加解密所进行的字符个数 var finalPointer:UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>.allocate(capacity: 1)//保存CCCryptorUpdate的结果 let bufferSize = 1024*1024//缓冲区大小 while inputStream!.hasBytesAvailable{ let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)//缓冲区 let read = inputStream!.read(buffer, maxLength: bufferSize)//读取数据流到缓冲区 if (read == 0){ buffer.deallocate()//清空缓冲区 break } var readData = Data(bytes: buffer, count: read) var readLength = readData.count let resultLength = size_t(readData.count + kCCBlockSizeAES128)//保存加解密后数组的长度 var updateData = [UInt8](repeating: 0, count: resultLength)//保存加解密后的数据 var cryptStatus = readData.withUnsafeBytes {readBytes in CCCryptorUpdate(cryptor, readBytes, readLength, &updateData, resultLength , &bufused)//进行加解密 } if UInt32(cryptStatus) == UInt32(kCCSuccess) { updateData.removeSubrange(bufused..<resultLength)//保存实际进行的加解密个数,去除原本多余的字符 } else { print("Error: \(cryptStatus)") } outputStream.write(updateData, maxLength: updateData.count)//写入文件 finalPointer.initialize(from: updateData, count: 1)//记录修改,直接地址相连接,避免了内存溢出 buffer.deallocate()//清空缓冲区 } //数据读取完毕,关闭读取文件流 inputStream!.close() CCCryptorFinal(cryptor, finalPointer, srcFileSize, &bufused)//通过CCCryptorFinal可以获得srcFileSize-updateResult.count大小的且合并后不影响updateResult的数组 CCCryptorRelease(cryptor)//释放内存 let bufferPointer = UnsafeMutableBufferPointer(start: finalPointer, count: bufused)//截取有效地址 let result = outputStream.write(Array(bufferPointer), maxLength: bufused)//转为数组并写入文件 //数据写入完毕,关闭写入文件流 outputStream.close() var descFileSize : Int = 0 let desc = try FileManager.default.attributesOfItem(atPath: _descPath) descFileSize = Int(desc[FileAttributeKey.size] as! UInt64) debugPrint("Finish,DescFileSize:",descFileSize) //记录结束时间 let endTime = CFAbsoluteTimeGetCurrent() debugPrint(String(format:"aesCBCFile Function usage time :%.2f second", (endTime - startTime))) return true } }
pubspec.yaml
flutter:
plugin:
platforms:
# android:
# package: com.handcent.encrypt
# pluginClass: EncryptUntil
ios:
pluginClass: SwiftEncrypIosPlugin
转载请注明出处
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。