main.swift 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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. print("JS 执行异常: \(exception)")
  54. }
  55. }
  56. return ctx!
  57. }
  58. func testDetail(url: String, ctx: JSContext) -> Void {
  59. if let detailFunction = ctx.objectForKeyedSubscript("detail") {
  60. print(detailFunction)
  61. let result = detailFunction.call(withArguments: [url])
  62. print(result?.toString())
  63. let resolveHandler: @convention(block) (JSValue?) -> Void = { resolvedValue in
  64. if let value = resolvedValue {
  65. print("解析成功: ", value)
  66. }
  67. }
  68. let rejectHandler: @convention(block) (JSValue?) -> Void = { rejectedValue in
  69. if let value = rejectedValue {
  70. print("解析失败:", value)
  71. }
  72. }
  73. if let thenFunction = result?.objectForKeyedSubscript("then") {
  74. print("Then:", thenFunction.toString())
  75. // 调用 then 函数,并传入回调函数
  76. thenFunction.call(withArguments: [unsafeBitCast(resolveHandler, to: AnyObject.self)])
  77. }
  78. if let catchFunction = result?.objectForKeyedSubscript("catch") {
  79. print("Catch:", catchFunction.toString())
  80. // 调用 catch 函数,并传入回调函数
  81. catchFunction.call(withArguments: [unsafeBitCast(rejectHandler, to: AnyObject.self)])
  82. }
  83. }
  84. }
  85. func testSearch(keyword: String, ctx: JSContext) -> Void {
  86. if let searchFunction = ctx.objectForKeyedSubscript("search") {
  87. print(searchFunction)
  88. let result = searchFunction.call(withArguments: [keyword, nil])
  89. print(result?.toString())
  90. let resolveHandler: @convention(block) (JSValue?) -> Void = { resolvedValue in
  91. if let value = resolvedValue {
  92. print("搜索成功: ", value)
  93. }
  94. }
  95. let rejectHandler: @convention(block) (JSValue?) -> Void = { rejectedValue in
  96. if let value = rejectedValue {
  97. print("搜索失败:", value)
  98. }
  99. }
  100. if let thenFunction = result?.objectForKeyedSubscript("then") {
  101. print("Then:", thenFunction.toString())
  102. // 调用 then 函数,并传入回调函数
  103. thenFunction.call(withArguments: [unsafeBitCast(resolveHandler, to: AnyObject.self)])
  104. }
  105. if let catchFunction = result?.objectForKeyedSubscript("catch") {
  106. print("Catch:", catchFunction.toString())
  107. // 调用 catch 函数,并传入回调函数
  108. catchFunction.call(withArguments: [unsafeBitCast(rejectHandler, to: AnyObject.self)])
  109. }
  110. }
  111. }
  112. let ctx = createJSContext()
  113. if let url = URL(string: "http://hubgit.cn/ben/be-ytb/raw/master/js/info.js") {
  114. downloadJSFile(url: url) { result in
  115. switch result {
  116. case .success(let jsString):
  117. print("下载远程JS成功")
  118. ctx.evaluateScript(jsString)
  119. testDetail(url: "https://www.youtube.com/watch?v=7wNb0pHyGuI", ctx: ctx)
  120. // testSearch(keyword: "周杰伦", ctx: ctx)
  121. case .failure(let error):
  122. print("Download Error: \(error)")
  123. }
  124. }
  125. }
  126. RunLoop.main.run()