123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- import JavaScriptCore
- import Alamofire
- 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 {
- callback?.call(withArguments: [String(data: data, encoding: .utf8), nil])
- }
- if let error = response.error {
- debugPrint(response)
- callback?.call(withArguments: [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 {
- if let detailFunction = ctx.objectForKeyedSubscript("detail") {
- let result = detailFunction.call(withArguments: [url])
- let completionHandler: @convention(block) (JSValue) -> Void = { result in
- print("详情结果!!: \(result.toDictionary())")
- }
- 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()
- if let url = URL(string: "http://hubgit.cn/ben/be-ytb/raw/master/js/info.js") {
- downloadJSFile(url: url) { result in
- switch result {
- case .success(let jsString):
- print("下载远程JS成功")
- ctx.evaluateScript(jsString)
- testDetail(url: "https://www.youtube.com/watch?v=d0R-JyU4Btk", ctx: ctx)
- // testSearch(keyword: "周杰伦", ctx: ctx)
- case .failure(let error):
- print("Download Error: \(error)")
- }
- }
- }
- RunLoop.main.run()
|