在 Windows Phone 8 上在 Unity 中发出 post 请求

Making a post request in Unity on Windows Phone 8

我正在尝试从 Unity 平台对 windows phone 8 发出 post 请求。我不想使用 unity WWW 方法,因为这会阻止渲染(并且不是线程安全的)。

以下代码在编辑器和 Android 上有效,但在为 WP8 构建它时出现以下错误。

System.Byte[] System.Net.WebClient::UploadData(System.String,System.String,System.Byte[])` doesn't exist in target framework.

这里解释了这个错误的原因

It’s because Windows Phone 8 uses a different flavor of .NET called .NET for Windows Phone which is missing some of the types available on other platforms. You’ll have to either replace these types with different ones or implement them yourself. - http://docs.unity3d.com/Manual/wp8-faq.html

这是我的代码

using (WebClient client = new WebClient())
{
    client.Encoding = System.Text.Encoding.UTF8;
    client.Headers[HttpRequestHeader.ContentType] = "application/json";

    byte[] requestData = new byte[0];
    string jsonRequest = "{}";
    if (data != null) 
    {
        string tempRequest = Converter.SerializeToString (data);
        jsonRequest = "{\"Data\": \"" + tempRequest + "\"}";

        requestData = System.Text.Encoding.UTF8.GetBytes(jsonRequest);
    }

    // below line of code is the culprit    
    byte[] returnedData = client.UploadData(url, "POST", requestData);

    if(returnedData.Length > 0)
    {
        // do stuff
    }
}

我也尝试过 WebRequests,但是 GetResponse() 破坏了它,并且 HttpClient 不存在。

那么,如何在 windows phone 8 上 post Unity 中的数据而不使用 WWW?

根据评论请求更新 - WebRequests

此代码使用 HttpWebRequest 在编辑器和 Android 上有效,但在 windows phone 上会抛出代码下方列出的错误。

var request = (System.Net.HttpWebRequest) System.Net.WebRequest.Create(url); 
request.ContentType = "application/json";
request.Method = "POST";

var sw = new System.IO.StreamWriter(request.GetRequestStream(), System.Text.Encoding.UTF8);

sw.Write(jsonRequest); // jsonRequest is same variable as in above code, string with json object.
sw.Close();

var re = request.GetResponse();

string resultString = "";
using (var outputStream = new System.IO.StreamReader(re.GetResponseStream(), System.Text.Encoding.UTF8))
{
    resultString = outputStream.ReadToEnd();
}

if(resultString.Length > 0)
{}

错误 1:

Error: method System.IO.Stream System.Net.HttpWebRequest::GetRequestStream() doesn't exist in target framework.

错误 2:

System.Net.WebResponse System.Net.HttpWebRequest::GetResponse() doesn't exist in target framework.

更新更多细节 - UploadStringAsync

使用此代码发出异步请求,它在编辑器中再次运行良好,在 WP8 上抛出错误。

bool isCompleted = false;
byte[] returnedData = null;
client.UploadDataCompleted += 
   new UploadDataCompletedEventHandler((object sender, UploadDataCompletedEventArgs e) => 
{
        Debug.Log("return event");
        returnedData = e.Result;
        isCompleted =true;
});

Debug.Log("async call start");
client.UploadDataAsync(new Uri(url), requestData);

while(isCompleted == false){
    Thread.Sleep(100);
}

if(returnedData.Length > 0)
{}

错误 1

method System.Void System.Net.WebClient::add_UploadDataCompleted(System.Net.UploadDataCompletedEventHandler) doesn't exist in target framework.

错误 2

Error: method System.Void System.Net.WebClient::UploadDataAsync(System.Uri,System.Byte[]) doesn't exist in target framework.

错误 3

Error: type System.Net.UploadDataCompletedEventArgs doesn't exist in target framework.

错误 4

Error: method System.Byte[] System.Net.UploadDataCompletedEventArgs::get_Result() doesn't exist in target framework.

我不知道 Unity 是否对您施加了任何潜在限制,但 Windows Phone 8 具有执行此操作的 WebClient.UploadStringAsync method and the WebClient.UploadStringCompleted event

HttpWebRequest 也应该有效(同样,我不知道任何 Unity 限制 - 请参阅上面的评论要求澄清)。

您不能统一使用这些框架,因为它们是线程化的/异步的/使用其他版本的 .Net

简而言之:

  • Unity 在仅接受 .Net 3.5 的单声道版本上运行
  • Unity 不允许您启动线程、任务或任何接近真正异步的东西
  • 不过你可以实现这些。

要在 windows phone 上执行此操作,您需要创建一个 class 库(实际上是两个),unity 称之为插件

那为什么要两个 dll?

因为编辑器需要一个模型 dll(如果你也想为桌面实现它,则需要实际的 dll)实现与 windows phone 上兼容的 dll 相同的接口.

要明确:

  • 编辑器的 dll(在 Assets/Plugins 中)需要兼容 .Net 3.5 和桌面
  • 放置在Assets/plugins/WP8中的dll需要兼容windowsphone.Net子集(我记得你可以是没有pb的.Net 4.5)

所以你应该在一个dll中实现那个功能,然后在unity中引用它,最后直接调用它。

一切都在这里解释:http://docs.unity3d.com/Manual/wp8-plugins-guide-csharp.html

它比看起来更简单。

我知道你说过你不想使用 WWW class,但你给出的理由在我看来毫无意义。

如果您使用协程检查“.isDone”标志而不使用 Thread.Sleep() 检查它,它不会阻止渲染并且是线程安全的(因为 unity 只允许您访问它的信息在单个线程上)。

如果您想在另一个线程上访问 return 数据,您只需在主 unity 线程中读取该数据,然后将其传递给您想要使用它的任何线程。

Unity 的设计都是在单个线程上运行,以使经验不足的程序员的生活更轻松。虽然您应该能够使用 .NET 线程创建多个线程,但您将无法与任何 Unity 组件直接通信,但您可以将数据传回 Unity 并等待 Update 或 Unity 的另一次调用以使用该数据。我知道这并不能准确回答你的问题,但如果你不能解决它,我认为值得再次查看 WWW class 和使用它的最佳实践。

使用下面的代码让它在 windows phone 上运行。在 Android 和 WP8 上的编辑器中编译和运行(耶!)。还没有在 iOS 上试过。

也在这里写了一个post:Create Web requests for unity that work on all platforms, even WP8

/// <summary>
/// Make post request to url with given paramaters
/// </summary>
/// <param name="url">URL to post data to http://server.com/method </param>
/// <param name="data">{ Data: data }</param>
/// <returns>string server response</returns>
public string PostData(string url, string data)
{
    // json request, hard coded right now but use "data" paramater to set this value.
    string jsonRequest = "{\"Data\": \"data\"}"; // the json request

    var request = System.Net.WebRequest.Create(url) as System.Net.HttpWebRequest;

    // this could be different for your server
    request.ContentType = "application/json"; 

    // i want to do post and not get
    request.Method = "POST"; 

    // used to check if async call is complete
    bool isRequestCallComplete = false;

    // store the response in this
    string responseString = string.Empty;

    request.BeginGetRequestStream(ar =>
    {
        var requestStream = request.EndGetRequestStream(ar);
        using (var sw = new System.IO.StreamWriter(requestStream))
        {
            // write the request data to the server
            sw.Write(jsonRequest);

            // force write of all content 
            sw.Flush();
        }

        request.BeginGetResponse(a =>
        {
            var response = request.EndGetResponse(a);
            var responseStream = response.GetResponseStream();
            using (var sr = new System.IO.StreamReader(responseStream))
            {
                // read in the servers response right here.
                responseString = sr.ReadToEnd();
            }
            // set this to true so the while loop at the end stops looping.
            isRequestCallComplete = true;
        }, null);

    }, null);

    // wait for request to complete before continuing
    // probably want to add some sort of time out to this 
    // so that the request is stopped after X seconds.
    while (isRequestCallComplete == false) { Thread.Sleep(50); }

    return responseString;
}