3

我正在使用 TVMLKit 开发 Apple TV 应用程序。我的应用程序的 JavaScript 代码尝试使用XMLHttpRequest. 服务器需要一个特定的用户代理,所以我尝试了这个:

var request = new XMLHttpRequest();
request.open("GET", url, true);
request.setRequestHeader("User-Agent", "MyApp");
request.send();

服务器收到不同的 User-Agent 标头:

User-Agent: <Projectname>/1 CFNetwork/758.1.6 Darwin/15.0.0

如果我将标头名称更改为不同的名称,它会显示在请求标头中。我猜 Apple 在发送请求之前正在替换 User-Agent 字段。有没有办法防止这种情况?

4

1 回答 1

0

After spending two days on investigating this question I've came to solution with creating native GET and POST methods in swift end exposing them to javascript. This isn't best solution but still I want to share it. Maybe it could help someone.

Here how it works

First we need to install Alamofire library. We will use it for creating requests.

Readme on github has all instructions you need to install it

After installing Alamofire we need to import it in AppDelegate.swift

import Alamofire

Then we need to create function in app controller (AppDelegate.swift) that will expose methods to javascript

func appController(appController: TVApplicationController, evaluateAppJavaScriptInContext jsContext: JSContext)
{
    let requests = [String : AnyObject]()

    let get: @convention(block) (String, String, [String : String]?) -> Void = { (cId:String, url:String, headers:[String : String]?) in

        Alamofire.request(.GET, url, headers: headers)
            .responseString { response in
                jsContext.evaluateScript("requests." + cId + "(" + response.result.value! + ")")
        }
    }

    let post: @convention(block) (String, String, [String : AnyObject]?, [String : String]?) -> Void = { (cId:String, url:String, parameters:[String : AnyObject]?, headers:[String : String]?) in

        Alamofire.request(.POST, url, parameters: parameters, headers: headers)
            .responseString { response in
                jsContext.evaluateScript("requests." + cId + "(" + response.result.value! + ")")
        }
    }

    jsContext.setObject(requests, forKeyedSubscript: "requests");
    jsContext.setObject(unsafeBitCast(get, AnyObject.self), forKeyedSubscript: "nativeGET");
    jsContext.setObject(unsafeBitCast(post, AnyObject.self), forKeyedSubscript: "nativePOST");
}

Full code of AppDelegate.swift you can find here

All set! Now we have access to nativeGET and nativePOST functions from javascript.

The last thing is to make requests and retrieve responses. I haven't understand how to make callback executions in swift so I've used jsonp approach using runtime generated functions and passing their names to native functions.

Here how it looks in javascript

export function get(url, headers = {}) {
    return new Promise((resolve) => {
        const cId = `get${Date.now()}`;
        requests[cId] = response => {
            delete requests[cId];
            resolve(response);
        }
        nativeGET(cId, url, headers);
    });
}

export function post(url, parameters = {}, headers = {}) {
    return new Promise((resolve) => {
        const cId = `post${Date.now()}`;
        requests[cId] = response => {
            delete requests[cId];
            resolve(response);
        }
        nativePOST(cId, url, parameters, headers);
    });
}

The code above is written in ES6 and you'll need to include Promise polifill in your TVJS app.

Now we can make GET and POST requests applying any header we need

post('http://example.com/', {
    login: 'xxx', 
    password: 'yyy'
}, {
    'User-Agent': 'My custom User-Agent'
})
于 2016-07-14T06:02:21.923 回答