main.swift 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import JavaScriptCore
  2. import Alamofire
  3. func downloadJSFile(url: URL, completion: @escaping (Result<String, Error>) -> Void) {
  4. AF.download(url).responseData { (response) in
  5. switch response.result {
  6. case .success(let data):
  7. if let jsString = String(data: data, encoding: .utf8) {
  8. completion(.success(jsString))
  9. } else {
  10. completion(.failure(NSError(domain: "Download Error", code: -1, userInfo: nil)))
  11. }
  12. case .failure(let error):
  13. completion(.failure(error))
  14. }
  15. }
  16. }
  17. func createJSContext() -> JSContext {
  18. let ctx = JSContext()
  19. // 注入 console.log
  20. ctx?.evaluateScript("var console = { log: function(message) { _consoleLog(message) } }")
  21. let consoleLog: @convention(block) (String) -> Void = { message in
  22. print("JS 打印: \(message)")
  23. }
  24. ctx?.setObject(unsafeBitCast(consoleLog, to: AnyObject.self), forKeyedSubscript: "_consoleLog" as (NSCopying & NSObjectProtocol)?)
  25. // 注入AF
  26. ctx?.evaluateScript("var AF = { request: function(url, method, data, headers, callback) { _request(url, method, data, headers, callback) } }")
  27. let af: @convention(block) (String, String, String?, [String: String]?, JSValue?) -> Void = { url, method, data, headers, callback in
  28. var request = URLRequest(url: URL(string: url)!)
  29. request.httpMethod = method
  30. if method == "POST" {
  31. if let data = data {
  32. request.setValue("application/json", forHTTPHeaderField: "Content-Type")
  33. request.httpBody = data.data(using: .utf8)
  34. }
  35. }
  36. if let headers = headers {
  37. request.headers = HTTPHeaders(headers)
  38. }
  39. AF.request(request).response { response in
  40. if let data = response.data {
  41. callback?.call(withArguments: [String(data: data, encoding: .utf8), nil])
  42. }
  43. if let error = response.error {
  44. debugPrint(response)
  45. callback?.call(withArguments: [nil, error.localizedDescription])
  46. }
  47. }
  48. }
  49. ctx?.setObject(unsafeBitCast(af, to: AnyObject.self), forKeyedSubscript: "_request" as (NSCopying & NSObjectProtocol)?)
  50. // 捕捉JS运行异常
  51. ctx?.exceptionHandler = { context, exception in
  52. if let exception = exception {
  53. debugPrint(exception)
  54. print("JS 执行异常: \(exception)")
  55. }
  56. }
  57. return ctx!
  58. }
  59. func testDetail(url: String, ctx: JSContext) -> Void {
  60. if let detailFunction = ctx.objectForKeyedSubscript("detail") {
  61. print(detailFunction)
  62. let result = detailFunction.call(withArguments: [url])
  63. print(result?.toString())
  64. let resolveHandler: @convention(block) (JSValue?) -> Void = { resolvedValue in
  65. if let value = resolvedValue {
  66. print("解析成功: ", value)
  67. }
  68. }
  69. let rejectHandler: @convention(block) (JSValue?) -> Void = { rejectedValue in
  70. if let value = rejectedValue {
  71. print("解析失败:", value)
  72. }
  73. }
  74. if let thenFunction = result?.objectForKeyedSubscript("then") {
  75. print("Then:", thenFunction.toString())
  76. // 调用 then 函数,并传入回调函数
  77. thenFunction.call(withArguments: [unsafeBitCast(resolveHandler, to: AnyObject.self)])
  78. }
  79. if let catchFunction = result?.objectForKeyedSubscript("catch") {
  80. print("Catch:", catchFunction.toString())
  81. // 调用 catch 函数,并传入回调函数
  82. catchFunction.call(withArguments: [unsafeBitCast(rejectHandler, to: AnyObject.self)])
  83. }
  84. }
  85. }
  86. func testSearch(keyword: String, ctx: JSContext) -> Void {
  87. if let searchFunction = ctx.objectForKeyedSubscript("search") {
  88. print(searchFunction)
  89. let result = searchFunction.call(withArguments: [keyword, nil])
  90. print(result?.toString())
  91. let resolveHandler: @convention(block) (JSValue?) -> Void = { resolvedValue in
  92. if let value = resolvedValue {
  93. print("搜索成功: ", value)
  94. }
  95. }
  96. let rejectHandler: @convention(block) (JSValue?) -> Void = { rejectedValue in
  97. if let value = rejectedValue {
  98. print("搜索失败:", value)
  99. }
  100. }
  101. if let thenFunction = result?.objectForKeyedSubscript("then") {
  102. print("Then:", thenFunction.toString())
  103. // 调用 then 函数,并传入回调函数
  104. thenFunction.call(withArguments: [unsafeBitCast(resolveHandler, to: AnyObject.self)])
  105. }
  106. if let catchFunction = result?.objectForKeyedSubscript("catch") {
  107. print("Catch:", catchFunction.toString())
  108. // 调用 catch 函数,并传入回调函数
  109. catchFunction.call(withArguments: [unsafeBitCast(rejectHandler, to: AnyObject.self)])
  110. }
  111. }
  112. }
  113. let ctx = createJSContext()
  114. if let url = URL(string: "http://hubgit.cn/ben/be-ytb/raw/master/js/info.js") {
  115. downloadJSFile(url: url) { result in
  116. switch result {
  117. case .success(let jsString):
  118. print("下载远程JS成功")
  119. ctx.evaluateScript(jsString)
  120. // testDetail(url: "https://www.youtube.com/watch?v=7wNb0pHyGuI", ctx: ctx)
  121. testSearch(keyword: "周杰伦", ctx: ctx)
  122. case .failure(let error):
  123. print("Download Error: \(error)")
  124. }
  125. }
  126. }
  127. RunLoop.main.run()