main.swift 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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("JavaScript Console.log: " + 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("JavaScript Exception: \(exception)")
  54. }
  55. }
  56. return ctx!
  57. }
  58. func testSearch(keyword: String, ctx: JSContext) -> Void {
  59. if let jsFunction = ctx.objectForKeyedSubscript("search") {
  60. let promise = jsFunction.call(withArguments: ["周杰伦", nil])
  61. // 检查返回值是否为 Promise
  62. // 获取 Promise 的 then 函数
  63. if let thenFunction = promise?.objectForKeyedSubscript("then") {
  64. // 调用 then 函数,并传入回调函数
  65. thenFunction.call(withArguments: [ { (resolvedValue: JSValue?) in
  66. if let value = resolvedValue {
  67. print("搜索成功", value)
  68. }
  69. }, { (rejectedReason: JSValue?) in
  70. if let reason = rejectedReason {
  71. print("搜索失败", reason)
  72. }
  73. }])
  74. }
  75. }
  76. }
  77. let ctx = createJSContext()
  78. if let url = URL(string: "http://hubgit.cn/ben/be-ytb/raw/master/js/info.js") {
  79. downloadJSFile(url: url) { result in
  80. switch result {
  81. case .success(let jsString):
  82. print("下载远程JS成功")
  83. ctx.evaluateScript(jsString)
  84. testSearch(keyword: "周杰伦", ctx: ctx)
  85. case .failure(let error):
  86. print("Download Error: \(error)")
  87. }
  88. }
  89. }
  90. RunLoop.main.run()