在 IOS WebView 中打开时处理来自 TXT 文件的数据
Handling Data From a TXT File When Opened In IOS WebView
背景
我正在 Swift
中重写一个 Android
应用程序。该应用程序的要点是它在 webView
中加载网站,允许用户登录,然后让他们访问名为 "Download Your Data".
的 link
问题
现在,当用户单击 IOS 中的 link 时,它会在视图中打开一个 txt 文件。所以整个 txt 文件出现在屏幕上的视图中。
在 Android 它下载文件,我可以通过文件系统访问它然后 POST
数据到服务器。
问题
考虑到数据出现在屏幕上并且没有下载或让我通过文件系统访问文件,
我可以通过哪些方式或方式访问此文件或文件中的数据,以便 post 将其发送到服务器?
示例代码
import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate {
var webView: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let viewUrl = URL(string: "https://www.example.com")
let viewUrlRequest = URLRequest(url: viewUrl!)
webView.load(viewUrlRequest)
}
}
解决方案
我处理这个问题的方法是在发出请求时嗅探流量。寻找必要的 headers 和 url 端点,然后在 Swift 中形成查询以处理文件下载。一旦我得到数据,我就可以用它做任何我想做的事。在我的情况下,我将它发布到服务器。
查尔斯
你可以找到Charles here
Charles is an HTTP proxy / HTTP monitor / Reverse Proxy that enables a
developer to view all of the HTTP and SSL / HTTPS traffic between
their machine and the Internet. This includes requests, responses and
the HTTP headers (which contain the cookies and caching information).
您将需要它来调查您需要发出的 http 请求,以便在您的应用程序中获取数据。通过这种方式,您可以务实地提出请求并控制应用程序的流程。
在我的应用程序中,我使用 javascript 模拟点击并强制下载。我必须将正确的 headers 附加到我使用 Charles
找到的 http 请求。
解法说明
这是一个使用 Swift 并注入 javascript 的示例。这显示了如何添加 headers 并发出 http 请求。你将不得不花时间弄清楚你需要改变什么来完成这项工作。但逻辑就在这里。
在我的例子中,我必须让用户登录网站,单击接受条款和条件的 link,然后单击 link 下载数据。如果你只需要达到一个终点那么你就不需要像我一样广泛。如果您确实需要模拟点击,那么我的代码应该会有很大帮助。
示例代码
import Foundation
import UIKit
class Downloader: NSObject {
enum Step { case idle, login, agreeToTerms, download }
var currentStep = Step.idle
var uiwebview: UIWebView!
var username: String = ""
var password: String = ""
var completion: ((Data?, Error?) -> Void)?
static var downloader: Downloader!
static func download(username: String, password: String, completion: @escaping (Data?, Error?) -> Void) {
if self.downloader == nil { self.downloader = Downloader() }
self.downloader.uiwebview = UIWebView(frame: CGRect(x: 0, y: 0, width: 320, height: 480))
self.downloader.uiwebview.scalesPageToFit = true
self.downloader.uiwebview.delegate = self.downloader
self.downloader.username = username
self.downloader.password = password
self.downloader.completion = completion
let url = URL(string: "URL-END-POINT-HERE")!
self.downloader.currentStep = .login
self.downloader.uiwebview?.loadRequest(URLRequest(url: url))
}
}
extension Downloader: UIWebViewDelegate {
func webViewDidFinishLoad(_ webView: UIWebView) {
if self.currentStep == .login, webView.request!.url?.absoluteString == "SOME-OTHER-URL-ACTION" {
let script = "document.getElementById('signInNew:inputUserId').value = '\(self.username)'; document.getElementById('signInNew:inputPassword').value = '\(self.password)'; document.getElementById('signInNew:signin_login').click()"
self.currentStep = .agreeToTerms
webView.stringByEvaluatingJavaScript(from: script)
} else if self.currentStep == .agreeToTerms, webView.request!.url?.absoluteString == "https://www.nslds.ed.gov/npas/pub/disclaimer.htm" {
self.currentStep = .download
webView.stringByEvaluatingJavaScript(from: "document.getElementsByClassName('button signIn')[0].click()")
} else if self.currentStep == .download, webView.request?.url?.absoluteString == "SOME-OTHER-URL-ACTION" {
let url = URL(string: "SOME-OTHER-URL-ACTION")!
var request = URLRequest(url: url)
var headers = request.allHTTPHeaderFields ?? [:]
if let cookies = HTTPCookieStorage.shared.cookies(for: url) {
for (key, value) in HTTPCookie.requestHeaderFields(with: cookies) { headers[key] = value }
}
// headers here - change these to the correct headers
headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
headers["Accept-Encoding"] = "gzip, deflate, sdch, br"
headers["Accept-Language"] = "en-US,en;q=0.8"
headers["Connection"] = "keep-alive"
headers["Referer"] = "URL-REFERER-HERE-END-POINT"
headers["User-Agent"] = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Mobile/14E8301"
//headers["Referer"] = "URL-REFERER-HERE-END-POINT"
request.allHTTPHeaderFields = headers
request.httpShouldHandleCookies = false
URLSession.shared.dataTask(with: request) { data, response, error in
self.completion?(data, error)
}.resume()
} else {
print("URL mismatch: \(webView.request!.url!.absoluteString)")
self.completion?(nil, NSError(domain: "Connection", code: 100, userInfo: [NSLocalizedDescriptionKey: "Check username & password \nDownload sequence mismatch"]))
}
}
}
背景
我正在 Swift
中重写一个 Android
应用程序。该应用程序的要点是它在 webView
中加载网站,允许用户登录,然后让他们访问名为 "Download Your Data".
问题
现在,当用户单击 IOS 中的 link 时,它会在视图中打开一个 txt 文件。所以整个 txt 文件出现在屏幕上的视图中。
在 Android 它下载文件,我可以通过文件系统访问它然后 POST
数据到服务器。
问题
考虑到数据出现在屏幕上并且没有下载或让我通过文件系统访问文件,
我可以通过哪些方式或方式访问此文件或文件中的数据,以便 post 将其发送到服务器?
示例代码
import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate {
var webView: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let viewUrl = URL(string: "https://www.example.com")
let viewUrlRequest = URLRequest(url: viewUrl!)
webView.load(viewUrlRequest)
}
}
解决方案
我处理这个问题的方法是在发出请求时嗅探流量。寻找必要的 headers 和 url 端点,然后在 Swift 中形成查询以处理文件下载。一旦我得到数据,我就可以用它做任何我想做的事。在我的情况下,我将它发布到服务器。
查尔斯
你可以找到Charles here
Charles is an HTTP proxy / HTTP monitor / Reverse Proxy that enables a developer to view all of the HTTP and SSL / HTTPS traffic between their machine and the Internet. This includes requests, responses and the HTTP headers (which contain the cookies and caching information).
您将需要它来调查您需要发出的 http 请求,以便在您的应用程序中获取数据。通过这种方式,您可以务实地提出请求并控制应用程序的流程。
在我的应用程序中,我使用 javascript 模拟点击并强制下载。我必须将正确的 headers 附加到我使用 Charles
找到的 http 请求。
解法说明
这是一个使用 Swift 并注入 javascript 的示例。这显示了如何添加 headers 并发出 http 请求。你将不得不花时间弄清楚你需要改变什么来完成这项工作。但逻辑就在这里。
在我的例子中,我必须让用户登录网站,单击接受条款和条件的 link,然后单击 link 下载数据。如果你只需要达到一个终点那么你就不需要像我一样广泛。如果您确实需要模拟点击,那么我的代码应该会有很大帮助。
示例代码
import Foundation
import UIKit
class Downloader: NSObject {
enum Step { case idle, login, agreeToTerms, download }
var currentStep = Step.idle
var uiwebview: UIWebView!
var username: String = ""
var password: String = ""
var completion: ((Data?, Error?) -> Void)?
static var downloader: Downloader!
static func download(username: String, password: String, completion: @escaping (Data?, Error?) -> Void) {
if self.downloader == nil { self.downloader = Downloader() }
self.downloader.uiwebview = UIWebView(frame: CGRect(x: 0, y: 0, width: 320, height: 480))
self.downloader.uiwebview.scalesPageToFit = true
self.downloader.uiwebview.delegate = self.downloader
self.downloader.username = username
self.downloader.password = password
self.downloader.completion = completion
let url = URL(string: "URL-END-POINT-HERE")!
self.downloader.currentStep = .login
self.downloader.uiwebview?.loadRequest(URLRequest(url: url))
}
}
extension Downloader: UIWebViewDelegate {
func webViewDidFinishLoad(_ webView: UIWebView) {
if self.currentStep == .login, webView.request!.url?.absoluteString == "SOME-OTHER-URL-ACTION" {
let script = "document.getElementById('signInNew:inputUserId').value = '\(self.username)'; document.getElementById('signInNew:inputPassword').value = '\(self.password)'; document.getElementById('signInNew:signin_login').click()"
self.currentStep = .agreeToTerms
webView.stringByEvaluatingJavaScript(from: script)
} else if self.currentStep == .agreeToTerms, webView.request!.url?.absoluteString == "https://www.nslds.ed.gov/npas/pub/disclaimer.htm" {
self.currentStep = .download
webView.stringByEvaluatingJavaScript(from: "document.getElementsByClassName('button signIn')[0].click()")
} else if self.currentStep == .download, webView.request?.url?.absoluteString == "SOME-OTHER-URL-ACTION" {
let url = URL(string: "SOME-OTHER-URL-ACTION")!
var request = URLRequest(url: url)
var headers = request.allHTTPHeaderFields ?? [:]
if let cookies = HTTPCookieStorage.shared.cookies(for: url) {
for (key, value) in HTTPCookie.requestHeaderFields(with: cookies) { headers[key] = value }
}
// headers here - change these to the correct headers
headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
headers["Accept-Encoding"] = "gzip, deflate, sdch, br"
headers["Accept-Language"] = "en-US,en;q=0.8"
headers["Connection"] = "keep-alive"
headers["Referer"] = "URL-REFERER-HERE-END-POINT"
headers["User-Agent"] = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Mobile/14E8301"
//headers["Referer"] = "URL-REFERER-HERE-END-POINT"
request.allHTTPHeaderFields = headers
request.httpShouldHandleCookies = false
URLSession.shared.dataTask(with: request) { data, response, error in
self.completion?(data, error)
}.resume()
} else {
print("URL mismatch: \(webView.request!.url!.absoluteString)")
self.completion?(nil, NSError(domain: "Connection", code: 100, userInfo: [NSLocalizedDescriptionKey: "Check username & password \nDownload sequence mismatch"]))
}
}
}