123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- import JavaScriptCore
- import Alamofire
- import Alamofire
- import Foundation
-
- //// 扩展SessionManager以支持多个Cookies
- //extension SessionManager {
- // static let multipleCookiesSessionManager: SessionManager = {
- // let configuration = URLSessionConfiguration.default
- // configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
- //
- // let manager = SessionManager(configuration: configuration)
- //
- // // 自定义处理Cookies的方式
- // manager.delegate.taskWillPerformHTTPRedirection = { session, task, response, request in
- // if let headers = response.allHeaderFields as? [String: String],
- // let setCookies = HTTPCookie.cookies(withResponseHeaderFields: headers, for: request.url!) {
- // for cookie in setCookies {
- // HTTPCookieStorage.shared.setCookie(cookie)
- // }
- // }
- // return request
- // }
- //
- // return manager
- // }()
- //}
- //
- //// 使用扩展的SessionManager发送请求
- //SessionManager.multipleCookiesSessionManager.request("https://www.youtube.com/watch?v=5GJWxDKyk3A").response { response in
- // debugPrint(response)
- //}
- func downloadJSFile(url: URL, completion: @escaping (Result<String, Error>) -> Void) {
- AF.download(url).responseData { (response) in
- switch response.result {
- case .success(let data):
- if let jsString = String(data: data, encoding: .utf8) {
- completion(.success(jsString))
- } else {
- completion(.failure(NSError(domain: "Download Error", code: -1, userInfo: nil)))
- }
- case .failure(let error):
- completion(.failure(error))
- }
- }
- }
- func createJSContext() -> JSContext {
- let ctx = JSContext()
-
- // 注入 console.log
- ctx?.evaluateScript("var console = { log: function(message) { _consoleLog(message) } }")
- let consoleLog: @convention(block) (String) -> Void = { message in
- print("JS 打印: \(message)")
- }
- ctx?.setObject(unsafeBitCast(consoleLog, to: AnyObject.self), forKeyedSubscript: "_consoleLog" as (NSCopying & NSObjectProtocol)?)
-
- // 注入AF
- ctx?.evaluateScript("var AF = { request: function(url, method, data, headers, callback) { _request(url, method, data, headers, callback) } }")
- let af: @convention(block) (String, String, String?, [String: String]?, JSValue?) -> Void = { url, method, data, headers, callback in
- var request = URLRequest(url: URL(string: url)!)
- request.httpMethod = method
-
- if method == "POST" {
- if let data = data {
- request.setValue("application/json", forHTTPHeaderField: "Content-Type")
- request.httpBody = data.data(using: .utf8)
- }
- }
-
- if let headers = headers {
- request.headers = HTTPHeaders(headers)
- }
-
- AF.request(request).response { response in
- if let data = response.data {
- var headerJsonString = ""
- if let headers = response.response?.allHeaderFields as? [String: String] {
- do {
- let jsonData = try JSONSerialization.data(withJSONObject: headers, options: [])
- if let jsonString = String(data: jsonData, encoding: .utf8) {
- headerJsonString = jsonString
- }
- } catch {
-
- }
- }
- callback?.call(withArguments: [String(data: data, encoding: .utf8), headerJsonString, nil])
- }
- if let error = response.error {
- debugPrint(response)
- callback?.call(withArguments: [nil, nil, error.localizedDescription])
- }
- }
- }
- ctx?.setObject(unsafeBitCast(af, to: AnyObject.self), forKeyedSubscript: "_request" as (NSCopying & NSObjectProtocol)?)
-
- // 捕捉JS运行异常
- ctx?.exceptionHandler = { context, exception in
- if let exception = exception {
- debugPrint(exception)
- print("JS 执行异常: \(exception)")
- }
- }
-
- return ctx!
- }
- func testDetail(url: String, ctx: JSContext) -> Void {
- let startTime = DispatchTime.now()
- if let detailFunction = ctx.objectForKeyedSubscript("detail") {
- let result = detailFunction.call(withArguments: [url])
- let completionHandler: @convention(block) (JSValue) -> Void = { result in
- print("详情结果!!: \(result.toDictionary())")
- let endTime = DispatchTime.now()
- let nanoTime = endTime.uptimeNanoseconds - startTime.uptimeNanoseconds
- let timeInterval = Double(nanoTime) / 1_000_000_000
- print("耗时: \(timeInterval) seconds")
- }
- let completionFunction = unsafeBitCast(completionHandler, to: AnyObject.self)
- result?.invokeMethod("then", withArguments: [completionFunction])
- }
- }
- func testSearch(keyword: String, ctx: JSContext) -> Void {
- if let search = ctx.objectForKeyedSubscript("search") {
- let result = search.call(withArguments: [keyword])
- let completionHandler: @convention(block) (JSValue) -> Void = { result in
- print("搜索结果!!: \(result.toDictionary())")
- }
- let completionFunction = unsafeBitCast(completionHandler, to: AnyObject.self)
- result?.invokeMethod("then", withArguments: [completionFunction])
- }
- }
- let ctx = createJSContext()
- let remote = "https://d3crpuooyqht8f.cloudfront.net/e76b32a6-42a0-4682-a30c-0b5c2d75e5b9"
- let local = "file:///Users/ben/Desktop/app/be/be-ytb/js/bundle.js"
- if let url = URL(string: remote) {
- downloadJSFile(url: url) { result in
- switch result {
- case .success(let jsString):
- print("下载远程JS成功")
- ctx.evaluateScript(jsString)
- testDetail(url: "https://www.youtube.com/watch?v=JByDbPn6A1o", ctx: ctx)
- // testSearch(keyword: "周杰伦", ctx: ctx)
- case .failure(let error):
- print("Download Error: \(error)")
- }
- }
- }
- RunLoop.main.run()
|