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

Azure Spatial Anchor Android端await CreateAnchorAsync卡住问题求助

Azure Spatial Anchor Android平台锚点保存卡顿问题

问题背景

原本在HoloLens上运行正常的Azure Spatial Anchor(ASA)锚点保存功能,适配Android平台时出现异常:调用await _spatialAnchorManager.CreateAnchorAsync(cloudSpatialAnchor);时代码卡住,无任何报错信息。

此前为确保环境数据采集充分,曾使用while循环等待SessionStatus.RecommendedForCreateProgress达标,但该逻辑在Android上会直接导致应用冻结,因此已注释。HoloLens端无此问题,暂不认为是锚点保存失败的直接原因。

核心代码

private async Task CreateAnchor(Vector3 position)
{
    //Create Anchor GameObject. We will use ASA to save the position and the rotation of this GameObject.
    if (!InputDevices.GetDeviceAtXRNode(XRNode.Head).TryGetFeatureValue(CommonUsages.devicePosition, out Vector3 headPosition))
    {
        headPosition = Vector3.zero;
    }

    Quaternion orientationTowardsHead = Quaternion.LookRotation(position - headPosition, Vector3.up);

    GameObject anchorGameObject = GameObject.Instantiate(_CubePrefab);

    anchorGameObject.GetComponent<MeshRenderer>().material.color = Color.white;
    anchorGameObject.transform.position = position;
    anchorGameObject.transform.rotation = orientationTowardsHead;
    anchorGameObject.transform.localScale = Vector3.one * 0.1f;

    //Add and configure ASA components
    CloudNativeAnchor cloudNativeAnchor = anchorGameObject.AddComponent<CloudNativeAnchor>();

    if (cloudNativeAnchor.CloudAnchor == null)
    {
        await cloudNativeAnchor.NativeToCloud();
    }

    CloudSpatialAnchor cloudAnchor = cloudNativeAnchor.CloudAnchor;

    // Then we create a new local cloud anchor
    CloudSpatialAnchor cloudSpatialAnchor = new CloudSpatialAnchor();
    // Now we set the local cloud anchor's position to the native XR anchor's position
    cloudSpatialAnchor.LocalAnchor = await anchorGameObject.FindNativeAnchor().GetPointer();
    // Check to see if we got the local XR anchor pointer
    if (cloudSpatialAnchor.LocalAnchor == IntPtr.Zero)
    {
        return;
    }
  
    //Collect Environment Data
    /*while (!_spatialAnchorManager.IsReadyForCreate) // debug 20.12.2022
    {
        float createProgress = _spatialAnchorManager.SessionStatus.RecommendedForCreateProgress;
        UnityEngine.Debug.Log($"ASA - Move your device to capture more environment data: {createProgress:0%}");
    }*/
    try
    {
        // Now that the cloud spatial anchor has been prepared, we can try the actual save here.
        await _spatialAnchorManager.CreateAnchorAsync(cloudSpatialAnchor);
        bool saveSucceeded = cloudSpatialAnchor != null;
        if (!saveSucceeded)
        {
            return;
        }
        _foundOrCreatedAnchorGameObjects.Add(anchorGameObject);
        _createdAnchorIDs.Add(cloudSpatialAnchor.Identifier);
        anchorGameObject.GetComponent<MeshRenderer>().material.color = Color.green;
    }
    catch (Exception exception)
    {
        UnityEngine.Debug.LogException(exception);
    }
}

已尝试操作

  • 取消注释while循环等待环境数据采集进度,应用直接冻结

求助问题

如何解决代码卡在await _spatialAnchorManager.CreateAnchorAsync(cloudSpatialAnchor);处且无报错的问题?


解决方案建议

1. 修复环境数据采集的阻塞问题

原来的while循环会阻塞主线程导致Android应用冻结,改用协程+异步回调的方式等待采集完成:

private IEnumerator WaitForCreateReady(Vector3 position)
{
    while (!_spatialAnchorManager.IsReadyForCreate)
    {
        float progress = _spatialAnchorManager.SessionStatus.RecommendedForCreateProgress;
        UnityEngine.Debug.Log($"ASA 环境数据采集进度: {progress:P0}");
        yield return new WaitForSeconds(0.5f); // 避免高频刷新占用资源
    }
    // 采集完成后执行锚点创建
    _ = ExecuteCreateAnchor(position);
}

// 重构锚点创建核心逻辑
private async Task ExecuteCreateAnchor(Vector3 position)
{
    // 此处放置原CreateAnchor方法中除环境等待外的所有逻辑
    if (!InputDevices.GetDeviceAtXRNode(XRNode.Head).TryGetFeatureValue(CommonUsages.devicePosition, out Vector3 headPosition))
    {
        headPosition = Vector3.zero;
    }

    Quaternion orientationTowardsHead = Quaternion.LookRotation(position - headPosition, Vector3.up);
    GameObject anchorGameObject = GameObject.Instantiate(_CubePrefab);
    anchorGameObject.GetComponent<MeshRenderer>().material.color = Color.white;
    anchorGameObject.transform.position = position;
    anchorGameObject.transform.rotation = orientationTowardsHead;
    anchorGameObject.transform.localScale = Vector3.one * 0.1f;

    CloudNativeAnchor cloudNativeAnchor = anchorGameObject.AddComponent<CloudNativeAnchor>();
    if (cloudNativeAnchor.CloudAnchor == null)
    {
        await cloudNativeAnchor.NativeToCloud();
    }

    CloudSpatialAnchor cloudSpatialAnchor = new CloudSpatialAnchor();
    var nativeAnchor = anchorGameObject.FindNativeAnchor();
    if (nativeAnchor == null)
    {
        UnityEngine.Debug.LogError("找不到Native Anchor");
        return;
    }
    cloudSpatialAnchor.LocalAnchor = await nativeAnchor.GetPointer();
    if (cloudSpatialAnchor.LocalAnchor == IntPtr.Zero)
    {
        UnityEngine.Debug.LogError("LocalAnchor指针无效");
        return;
    }

    try
    {
        await _spatialAnchorManager.CreateAnchorAsync(cloudSpatialAnchor);
        bool saveSucceeded = cloudSpatialAnchor != null;
        if (!saveSucceeded)
        {
            return;
        }
        _foundOrCreatedAnchorGameObjects.Add(anchorGameObject);
        _createdAnchorIDs.Add(cloudSpatialAnchor.Identifier);
        anchorGameObject.GetComponent<MeshRenderer>().material.color = Color.green;
    }
    catch (Exception exception)
    {
        UnityEngine.Debug.LogException(exception);
    }
}

调用时替换原逻辑:

// 不再直接调用CreateAnchor,改为启动协程等待采集完成
StartCoroutine(WaitForCreateReady(targetPosition));

2. 强化LocalAnchor有效性校验

Android平台上FindNativeAnchor().GetPointer()可能返回隐性无效指针,添加多层校验:

var nativeAnchor = anchorGameObject.FindNativeAnchor();
if (nativeAnchor == null)
{
    UnityEngine.Debug.LogError("Native Anchor对象为空");
    return;
}
cloudSpatialAnchor.LocalAnchor = await nativeAnchor.GetPointer();
if (cloudSpatialAnchor.LocalAnchor == IntPtr.Zero)
{
    UnityEngine.Debug.LogError("LocalAnchor指针无效");
    return;
}

3. 检查Android权限与网络配置

  • 确保AndroidManifest.xml中添加必要权限:
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
  • 排查网络连接:Android平台可能存在代理、防火墙拦截ASA云端请求,可通过抓包或Unity日志查看网络请求状态。

4. 验证SDK版本兼容性

检查Azure Spatial Anchor SDK版本是否与Unity XR插件(如AR Foundation/ARCore)版本匹配,Android平台对版本兼容性要求更严格,建议使用ASA官方文档推荐的配套版本。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 16:50:22