出的windows包,图集乱了

资源打包使用的是yooasset插件。
用的unity自带的图集工具。

打出来的包,UI上显示的image全白了,或者是图片显示了一整张图集。

来来回回测试了多次,才发现。

atlas中的include in build需要取消勾选。这样打出来的ab包里的图集才正确显示。

不太清楚原因。问题解决就先不细纠了。

iphone微信小游戏报错

iphone下微信小游戏忽然进不去了。

vConsole中显示log:

Render Pipeline error : the XR layout still contains active passes. Executing XRSystem.EndLayout() right now.

Texture creation failed. ‘R32G32B32A32_SFloat’ is not supported for Render usage on this platform

很是奇怪啊,小游戏里怎么触发了调用XR。
试了很多方式都没找到原因。
想到既然提示了需要调用 XRSystem.EndLayout。那出错的代码估计在这个调用的附近,打开URP脚本搜索该调用,果真搜索到了。
查看前后逻辑,发现需要camera上打开AllowXRRendering选项,才会打开XRSystem。
但小游戏是webgl,本身就不显示AllowXRRendering这个选项,也无法操作。
这种情况下,用记事本打开场景prefab,发现果真这个选项被选中了。用记事本修改,取消选中,保存出包,问题修复.

UGUI真机上图片丢失的问题

看此处:https://docs.unity.cn/cn/2021.1/ScriptReference/U2D.SpriteAtlasManager-atlasRequested.html

SpriteAtlasManager.atlasRequested

描述

在任何 Sprite 绑定到 SpriteAtlas 但无法在运行时找到图集资源时触发。

这通常意味着精灵被打包到了一个未包含在编译版本中的图集内

此回调不期望用户的立即响应。相反,它传递一个 System.Action。用户可以在日后加载图集对象,并使用此 System.Action 传回加载后的图集。 using UnityEngine; using UnityEngine.U2D;

public class AtlasLoader : MonoBehaviour { void OnEnable() { SpriteAtlasManager.atlasRequested += RequestAtlas; }

void OnDisable() { SpriteAtlasManager.atlasRequested -= RequestAtlas; }

void RequestAtlas(string tag, System.Action<SpriteAtlas> callback) { var sa = Resources.Load<SpriteAtlas>(tag); callback(sa); } }

另请参阅:U2D.SpriteAtlasManager.RequestAtlasCallback。

UGUI检测当前是否点中UI

UGUI判断当前是否有点中UI

<code>    // true:当前点中了UI
    public static bool IsTouchOnUI()
    {
        //check mouse PC平台检测鼠标
        if (EventSystem.current.IsPointerOverGameObject())
        {
            return true;
        }

        //check touch 手机检测每个touch
        if (Input.touchCount > 0 &amp;&amp; Input.touches&#91;0].phase == TouchPhase.Began)
        {
            if (EventSystem.current.IsPointerOverGameObject(Input.touches&#91;0].fingerId))
            {
                return true;
            }
        }

        return false;
    }</code>

Unsupported version number [55.0] (maximum 54.0, Java 10)

Caused by: java.io.IOException: Can’t read [/opt/android-sdk-linux/platforms/android-33/optional/android.car.jar] (Can’t process class [android/car/Car$CarServiceLifecycleListener.class] (Unsupported version number [55.0] (maximum 54.0, Java 10)))

最近google play要求sdk升至33。将一个unity 2021工程升至sdk33出包时提示上面的错误。

搜索得知,unity2021默认自带gradle使用的是
com.android.tools.build:gradle:4.0.1

使用的proguard版本是net.sf.proguard:proguard-gradle:6.0.3

需要升至6.1.1

使用以下方式升至6.1.1

<code> buildscript{
 
configurations.all {
    resolutionStrategy {
        // We want version 5.3.2 instead of 5.2.1.
        force 'net.sf.proguard:proguard-gradle:6.1.1'
    }
}
}</code>

记android老工程打包需要的两个小问题

一个老的项目,前两个月还可以打包成功。突然打包失败了。

记录一下解决过程:

1、jcenter()已失效,改为mavenCentral()

添加阿里云镜像:

<code>            google()
            mavenCentral()
	    maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
            maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter' }
 </code>


2、Installed Build Tools revision 31.0.0 is corrupted

  1. go to the location "C:\Users\user\AppData\Local\Android\Sdk\build-tools\31.0.0"
  2. find a file named d8.bat. This is a Windows batch file.
  3. rename d8.bat to dx.bat.
  4. in the folder lib (“C:\Users\user\AppData\Local\Android\Sdk\build-tools\31.0.0\lib”)
  5. rename d8.jar to dx.jar

iPhone手机图标抖动

最近看了iphone手机上的图标抖动算法,提供一个实现

<code>using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RotationAnimation : MonoBehaviour
{
    // Start is called before the first frame update
    public float duration = 0.25f;
    public float displacement = 1.0f;
    public float degreesRotation = 2.0f;

    public bool play = false;

    public bool enablePos;
    public bool enableRotation;

  
    public bool useXY = false;
    public bool useXZ = true;
    public bool useYZ = false;

    private Position position;
    private Rotation rotation;

    private void Awake()
    {
 
        Init();

        StartPlay();
    }

    public void StartPlay()
    {
        play = true;

        position.startTime = Time.realtimeSinceStartup;
        rotation.startTime = Time.realtimeSinceStartup;
    }
    public void StopPlay()
    {
        play = false;
        transform.localPosition = Vector3.zero;
        transform.localRotation = Quaternion.Euler(transform.localRotation.x, 0f, transform.localRotation.z);
    }

    public void  Update()
    {

        if (play)
        {
            if (enablePos)
            {
                position.Update();
            }
            if (enableRotation)
            {
                rotation.Update();
            }
        }
    }

 

    public void Init()
    {
        var negativeDisplacement = -1.0f * displacement;

        position = new Position();
        position.transform = transform;
        position.duration = duration;
        position.positions = new Vector2&#91;] { 
            new Vector2(negativeDisplacement,negativeDisplacement),
            new Vector2(0,0),
            new Vector2(negativeDisplacement,0),
            new Vector2(0,negativeDisplacement),
            new Vector2(negativeDisplacement,negativeDisplacement),
        };
        position.useXY = useXY;
        position.useXZ = useXZ;
        position.useYZ = useYZ;
        

        rotation = new Rotation();
        rotation.transform = transform;
        rotation.duration = duration;
        rotation.rotations = new float&#91;] {
         -1.0f * degreesRotation ,
         degreesRotation ,
        -1.0f * degreesRotation 
        };
        rotation.useXY = useXY;
        rotation.useXZ = useXZ;
        rotation.useYZ = useYZ;
    }

    class Position
    {
        public float startTime;
        public float delayTime;
        public float duration;
        public Vector2&#91;] positions;
        public Transform transform;
        public bool useXZ = true;
        public bool useXY = false;
        public bool useYZ = false;

        public void Update()
        {
            
            // 线性插值
            float time = Time.realtimeSinceStartup - startTime;
            if (time &lt;= delayTime)
            {
                return;
            }

            int rate = (int)(time / duration);
            float lerp = (time - rate * duration)/duration;
            int index = rate % (positions.Length-1);
            var startPos = positions&#91;index];
            var endPos = positions&#91;index + 1];
            //Debug.Log("index: " + index);

            Vector2 pos = Vector2.Lerp(startPos, endPos,lerp);
            if (useXZ)
            {
                transform.localPosition = new Vector3(pos.x, transform.localPosition.y, pos.y);
            }else if (useXY)
            {
                transform.localPosition = new Vector3(pos.x, pos.y, transform.localPosition.z);
            }
            else if (useYZ)
            {
                transform.localPosition = new Vector3(transform.localPosition.x, pos.x,  pos.y);
            }
        }
    }
    class Rotation
    {
        public float startTime;
        public float delayTime;
        public float duration;
        public float&#91;] rotations;
        public Transform transform;
        public bool useXZ = true;
        public bool useXY = false;
        public bool useYZ = false;

        public void Update()
        {
            // 线性插值
            float time = Time.realtimeSinceStartup - startTime;
            if (time &lt;= delayTime)
            {
                return;
            }

            int rate = (int)(time / duration);
            float lerp = (time - rate * duration)/duration;
            int index = rate % (rotations.Length - 1);
            var start = rotations&#91;index];
            var end = rotations&#91;index + 1];

            float rotation = Mathf.Lerp(start, end, lerp);

            //Debug.Log(start + " " + end +  " value:"+rotation+" lerp:" + lerp+" index:"+index);
            if (useXZ)
            {
                transform.localRotation = Quaternion.Euler(transform.localRotation.x, rotation, transform.localRotation.z);
            }else if (useXY)
            {
                transform.localRotation = Quaternion.Euler(transform.localRotation.x,transform.localRotation.y, rotation);
            }
            else if (useYZ)
            {
                transform.localRotation = Quaternion.Euler(rotation,transform.localRotation.y, transform.localRotation.z);
            }
        }
    }

 
    
}
</code>

unity下ssl证书验证失败

“System.IO.IOException: The authentication or decryption has failed. —> Mono.Security.Protocol.Tls.TlsException: The authentication or decryption has failed.\r\n at Mono.Security.Protocol.Tls.RecordProtocol.ProcessAlert (AlertLevel alertLevel, AlertDescription alertDesc) [0x00000] in :0 \r\n at Mono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback (IAsyncResult asyncResult) [0x00000] in :0 \r\n — End of inner exception stack trace —\r\n at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (IAsyncResult asyncResult) [0x00000] in :0 “

线上正在跑的一个项目,突然出现如上的错误。很久之前我就知道了,unity中可以强制设置为不验证ssl证书,但我好奇的是,这个是线上正在跑的项目,SSL证书也没有出现更换的情况,为什么突然间就验证失败了。

一开始猜测会不会是证书本身的问题,用了几个检测SSL证书网站进行检测,结果正常。

和运维排查了一下午没找到原因。这个地方请求失败对客户端目前并无大影响,后续准备修改代码避免这个检测。

周一来公司时,又对这个事比较好奇了,决定再重新理一下头绪,看是不是漏了什么线索没有发现。从头开始重新一步一步推测。

在检测SSL证书时,突然发现证书只支持TLS1.2

这里出现了一丝疑惑,难道配的证书不支持TLS1.0/1.1,又找到几个检测工具测试了,也显示不支持TLS1.0/1.1。
找到公司里另一个支持TLS1.0/1.1的域名进行测试,可以成功访问。

将这个情况反馈给运维,运维同学才想到,前一段时间将运行环境容器化,容器默认只开启了TLS1.2。

修改为支持TLS1.0/1.1后,线上问题解决,不用重新发包了.yeah.

记下谷歌支付失败的相关情况

consumeValue

支付可能的失败原因:

1、未安装谷歌服务框架(google services framework)

2、当前使用的谷歌帐号所在地区未开放付费

3、谷歌框架服务无法正常访问网络

4、谷歌服务框架 “后台弹权权限” 未开启。(注:这个权限国外手机是不可见,默认开启。 出现这个错误,仅限在Oppo,Vivo,Xiaomi等国内品牌手机,需要手动打开此权限)

5、上一次支付成功的订单尚未消单(consume purchase)。 (注:需要完成消单后同支付档位才可再次支付。短时间内多次支付同档位礼包比较容易出现)

6、手机上存在多谷歌帐号时,支付会优先使用安装此APP的帐号进行支付,如果该谷歌帐号所在地区无支付权限,则APP无法支付。(注:出现该问题时,需要先删除APP,从系统中退出安装此APP的帐号。然后重新安装APP即可支付)。

7、不是从google play下载安装,该种情况下无法支付。

shell gbk转utf8

iconv -f GB18030 -t UTF-8 0101.html

去除文章中的换行:

tr -d “\n”

for循环多行数据

<code>    IFS=$'\n'
    for line in $list
    do
       echo "line:$line"
    done</code>


<code>     </code>