androidunity-game-enginesprite

SpriteRenderer changing sprite on runtime not working in android build?


If you try creating test scene, with a simple script to change sprite every a period of time.

The sprite doesn't change, but if you try to log the changed sprite name, you'll see it has changed successfully. Which means only the visual is not changing.

Testing on Unity 6000.0.3f1, and on android S24 Ultra

My TestSpriteRendererChange.cs script

using System.Collections;
using UnityEngine;

public class TestSpriteRendererChange : MonoBehaviour
{
    [SerializeField] private SpriteRenderer spriteRenderer;
    [SerializeField] private Sprite[] sprites;

    private void Start()
    {
        StartCoroutine(ChangeSprites());
    }

    private IEnumerator ChangeSprites()
    {
        var index = 0;

        foreach (var sprite in sprites)
        {
            Debug.Log($"before sprite: {spriteRenderer.sprite.name}");

            spriteRenderer.sprite = sprite;

            Debug.Log($"after sprite: {spriteRenderer.sprite.name}");

            yield return new WaitForSeconds(0.1f);

            index++;
        }

        if (index == sprites.Length)
        {
            index = 0;

            StopCoroutine(nameof(ChangeSprites));
            StartCoroutine(nameof(ChangeSprites));
        }
    }
}

Behaviour in unity editor

enter image description here

Behaviour in android device

enter image description here

This issue is related to URP 2D only, it works just fine in built-in-RP 2D projects.


Solution

  • This was an actual bug in unity 6000.0.3f1, so I did the following

    As a workaround for this issue, I've modified my script as follow :-

    I changed my TestSpriteRendererChange.cs to the following :-

    using System.Collections;
    using UnityEngine;
     
    public class TestSpriteRendererChange : MonoBehaviour
    {
        [SerializeField] private GameObject spriteGO;
        [SerializeField] private Sprite[] sprites;
     
        private void Start()
        {
            StartCoroutine(ChangeSprites());
        }
     
        private IEnumerator ChangeSprites()
        {
            var index = 0;
     
            foreach (var sprite in sprites)
            {
                // check if SpriteRenderer exists
                var hasComponent = spriteGO.TryGetComponent(out SpriteRenderer sr);
     
                // we could cash reference to sortingLayer and sortingOrder to avoid reset
                if (hasComponent)
                {
                    // we remove the component if exists
                    Destroy(sr);
                }
     
                // wait for end of frame to avoid null reference error
                yield return new WaitForEndOfFrame();
     
                // we add the SpriteRenderer component again
                var spriteRenderer = spriteGO.AddComponent<SpriteRenderer>();
     
                spriteRenderer.sprite = sprite;
     
                Debug.Log($"after sprite: {spriteRenderer.sprite.name}");
     
                yield return new WaitForSeconds(1f);
     
                index++;
            }
     
            if (index == sprites.Length)
            {
                index = 0;
     
                StopCoroutine(nameof(ChangeSprites));
                StartCoroutine(nameof(ChangeSprites));
            }
        }
    }
    

    By removing the SpriteRenderer component and adding it again, resolves the issue.

    Let me know if there is a better solution.