ios - Swift解压缩zip文件并从Gmail API的base64数据中查找xml文件

标签 ios swift xml gmail-api unzip

这个问题是关于 iOS 13 中使用 SwiftUI 和 Gmail API 的 DMARC 报告查看器应用程序。报告由谷歌以 xml 格式邮寄到我们的管理员电子邮件 ID,该格式将被压缩。所以基本上它是一个 zip 附件。所以在这里,GMail API 用于使用过滤器访问那些特定的邮件,并从 API 获取所有 base64 编码的数据。还将其解码为数据类型数据。那远没问题。下一部分是解压缩字节格式的 zip 文件的数据,并提取其中的 String 类型的 xml 文件。然后我需要解析 XML。我想我可以使用 XMLParser 进行解析。

问题:如何解压Data类型的zip文件,并从中获取String类型的xml文件?

INPUT: String in Base64 format from GMail API fetch (A zip file attachment with only 1 xml file inside)
OUTPUT: String in XML format
PLATFORM: iOS 13/Swift 5.2/SwiftUI/Xcode 11.4
ACTION: 

(INPUT)
base64: String | Decode -> Data
attachment.zip: Data | Decompress -> [Data]
ListOfFiles: [Data] | FirstIndex -> Data
dmarc.xml: Data | ContentOfXML -> String
(OUTPUT)

更新:我尝试了一个名为 Zip 的外部包它也失败了。

let path = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let url = path.appendingPathComponent(messageId+".zip")
do {
    try data.write(to: url)
} catch {
    print("Error while writing: "+error.localizedDescription)
}
do {
    let unzipDirectory = try Zip.quickUnzipFile(url)
    print(unzipDirectory)
} catch let error as NSError {
    print("Error while unzipping: "+error.localizedDescription)
}

此代码导致以下错误

Error while unzipping: The operation couldn’t be completed. (Zip.ZipError error 1.)

最佳答案

终于找到了。正如Ref 1中提到的那样, 电子邮件正文以 7 位 US-ASCII 数据编码。所以这就是base64解码不起作用的原因。

rfc1341 中所定义:

An encoding type of 7BIT requires that the body is already in a seven-bit mail- ready representation. This is the default value -- that is, "Content-Transfer-Encoding: 7BIT" is assumed if the Content-Transfer-Encoding header field is not present.

添加以下内容后整个代码有效。

let edata: String = result.data.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")

Ref 2 中所述,它只需要在从 gmail api 接收的 base64 数据中用 '+' 和 '_' 替换 '-' 上的字符。

func getAttachedData(messageId: String, attachmentId: String) {
    decode(self.urlBase+messageId+"/attachments/"+attachmentId+"?"+self.urlKey) { (result: Attachment) in
        let edata: String = result.data.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")
        if let data = Data(base64Encoded: edata, options: .ignoreUnknownCharacters) {
            let filemanager = FileManager.default
            let path = try! filemanager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
            let url = path.appendingPathComponent(messageId+".zip")
            do {
                try data.write(to: url)
            } catch {
                print("Error while writing: "+error.localizedDescription)
            }
            do {
                let unzipDirectory = try Zip.quickUnzipFile(url)
                print("Unzipped")
                do {
                    let filelist = try filemanager.contentsOfDirectory(at: unzipDirectory, includingPropertiesForKeys: [], options: [])

                    for filename in filelist {
                        print(filename.lastPathComponent)
                        print(filename.relativeString)
                        do {
                            let text = try String(contentsOf: filename, encoding: .utf8)
                            print(text)
                            DispatchQueue.main.async {
                                self.attachments.append(text)
                            }
                        } catch let error as NSError {
                            print("Error: \(error.localizedDescription)")
                        }
                    }
                } catch let error {
                    print("Error: \(error.localizedDescription)")
                }
            } catch let error as NSError {
                print("Error while unzipping: "+error.localizedDescription)
            }
        }
    }
}

引用 1:https://stackoverflow.com/a/58590759/2382813

引用 2:https://stackoverflow.com/a/24986452/2382813

关于ios - Swift解压缩zip文件并从Gmail API的base64数据中查找xml文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61968456/

相关文章:

php - 从 Web 服务器获取 JSON 数组到 iOS 的后台队列

ios - 如何将 "Open in.."函数添加到自定义 UIWebview?

iOS 9 使用快速操作选择标签栏索引,performActionForShortcutItem

Swift 奇怪的行为 - 函数内调用和函数外调用

ios - 当调用 UISearchBar.becomeFirstResponder() 时,键盘出现并立即消失

ios - 是否可以使用CoreLocation/MapKit查找纬度/经度附近的地址?

ios - 如何不断快速获取移动物体的x位置?

java - 在我的组件树窗口中找不到设备屏幕选项

python - 在 Python 中获取 XML 属性值列表

php - 没有数据库的轻型博客系统