You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中C#如何等待Android插件的异步I/O操作?

在Unity中让C#等待Android插件异步操作的可行方案

我之前也踩过这个坑,Unity的C#代码没法直接阻塞等待Android插件的异步操作——毕竟Java侧的异步逻辑是跑在自己的线程里的,硬卡主线程只会让Unity直接卡死。核心思路是利用Unity提供的跨端回调机制,配合C#的同步工具来实现“等待”效果,下面给你两种靠谱的实现方式:

方案一:用TaskCompletionSource实现异步等待(推荐现代C#风格)

这种方式贴合C#的异步编程范式,代码更简洁易维护,还能方便处理异常。

第一步:Android插件侧代码(Java)

首先要在Android插件里完成异步操作后,通过UnityPlayer.UnitySendMessage把结果回调给Unity的C#代码:

import android.os.AsyncTask;
import com.unity3d.player.UnityPlayer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class AndroidAsyncHandler {
    // 单例模式方便Unity调用
    private static AndroidAsyncHandler instance;
    public static AndroidAsyncHandler getInstance() {
        if (instance == null) {
            instance = new AndroidAsyncHandler();
        }
        return instance;
    }

    // 异步执行HTTP Get,完成后回调Unity
    public void performAsyncGet(String url, String unityGameObjName, String callbackMethod) {
        new AsyncTask<String, Void, String>() {
            @Override
            protected String doInBackground(String... params) {
                try {
                    URL urlObj = new URL(params[0]);
                    HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
                    conn.setRequestMethod("GET");
                    if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                        BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                        StringBuilder sb = new StringBuilder();
                        String line;
                        while ((line = reader.readLine()) != null) {
                            sb.append(line);
                        }
                        reader.close();
                        return sb.toString();
                    } else {
                        return "Error: HTTP Response Code " + conn.getResponseCode();
                    }
                } catch (Exception e) {
                    return "Error: " + e.getMessage();
                }
            }

            @Override
            protected void onPostExecute(String result) {
                // 把结果回调给Unity指定的GameObject和方法
                UnityPlayer.UnitySendMessage(unityGameObjName, callbackMethod, result);
            }
        }.execute(url);
    }
}

第二步:Unity侧C#代码

用TaskCompletionSource把Android的回调转换成C#的Task,实现异步等待:

using UnityEngine;
using System.Threading.Tasks;

public class AndroidAsyncWaiter : MonoBehaviour
{
    private TaskCompletionSource<string> _asyncTaskSource;

    private void Awake()
    {
        // 确保这个GameObject不被销毁,否则回调会丢失
        DontDestroyOnLoad(gameObject);
    }

    // 对外暴露的异步方法,调用后会等待Android操作完成
    public async Task<string> WaitForAndroidAsyncOperation(string targetUrl)
    {
        _asyncTaskSource = new TaskCompletionSource<string>();

        // 获取Android插件实例并调用异步方法
        AndroidJavaClass handlerClass = new AndroidJavaClass("com.yourpackage.AndroidAsyncHandler");
        AndroidJavaObject handlerInstance = handlerClass.CallStatic<AndroidJavaObject>("getInstance");
        handlerInstance.Call("performAsyncGet", targetUrl, gameObject.name, "OnAndroidOperationCompleted");

        // 等待Task完成并返回结果
        string result = await _asyncTaskSource.Task;
        _asyncTaskSource = null;
        return result;
    }

    // 这个方法是Android回调的目标,必须是public且参数匹配
    public void OnAndroidOperationCompleted(string result)
    {
        if (_asyncTaskSource != null && !_asyncTaskSource.Task.IsCompleted)
        {
            if (result.StartsWith("Error:"))
            {
                _asyncTaskSource.SetException(new System.Exception(result));
            }
            else
            {
                _asyncTaskSource.SetResult(result);
            }
        }
    }

    // 测试调用示例
    public async void TestAsyncWait()
    {
        try
        {
            string response = await WaitForAndroidAsyncOperation("https://example.com");
            Debug.Log("Android异步操作结果: " + response);
        }
        catch (System.Exception e)
        {
            Debug.LogError("异步操作失败: " + e.Message);
        }
    }
}

方案二:用协程+标志位实现等待(适合传统Unity开发习惯)

如果你的项目更偏向Unity传统协程开发,也可以用标志位配合协程循环检查来实现等待:

using UnityEngine;
using System.Collections;

public class AndroidCoroutineWaiter : MonoBehaviour
{
    private bool _isOperationDone;
    private string _operationResult;
    private bool _isErrorOccurred;

    private void Awake()
    {
        DontDestroyOnLoad(gameObject);
    }

    // 启动协程等待Android操作完成
    public IEnumerator WaitForAndroidOperation(string targetUrl)
    {
        // 重置状态标志
        _isOperationDone = false;
        _operationResult = null;
        _isErrorOccurred = false;

        // 调用Android插件异步方法
        AndroidJavaClass handlerClass = new AndroidJavaClass("com.yourpackage.AndroidAsyncHandler");
        AndroidJavaObject handlerInstance = handlerClass.CallStatic<AndroidJavaObject>("getInstance");
        handlerInstance.Call("performAsyncGet", targetUrl, gameObject.name, "OnCoroutineOperationCompleted");

        // 每帧检查操作是否完成,直到状态改变
        while (!_isOperationDone)
        {
            yield return null;
        }

        // 处理结果
        if (_isErrorOccurred)
        {
            Debug.LogError("Android操作出错: " + _operationResult);
        }
        else
        {
            Debug.Log("Android操作结果: " + _operationResult);
        }
    }

    // Android回调的目标方法
    public void OnCoroutineOperationCompleted(string result)
    {
        _isOperationDone = true;
        if (result.StartsWith("Error:"))
        {
            _isErrorOccurred = true;
        }
        _operationResult = result;
    }

    // 测试调用示例
    public void TestCoroutineWait()
    {
        StartCoroutine(WaitForAndroidOperation("https://example.com"));
    }
}

关键注意事项

  • Android侧必须用UnityPlayer.UnitySendMessage回调Unity,这个方法是线程安全的,会把回调消息放到Unity主线程的消息队列里,避免跨线程问题。
  • 回调目标的GameObject必须始终存在,所以一定要加DontDestroyOnLoad,否则回调会丢失。
  • 如果是WebSocket这种长连接场景,逻辑完全类似:Java侧的WebSocket回调(onOpen、onMessage、onClose)都通过UnitySendMessage通知C#,C#侧用对应的同步机制处理(比如用TaskCompletionSource等待连接成功,用事件订阅接收消息)。
  • 绝对不要在C#侧用while(true)死循环等待,会直接卡死Unity主线程,必须用协程或者异步Task的方式。

内容的提问来源于stack exchange,提问作者Ariam1_catalist_number_666

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:04:42