[Unity]腾讯SDK踩坑之路(5)--应用宝省流量更新+米大师托管模式坑

        之前项目平台没有定好是大厂独代模式,所以在大厂提出省流量更新问题的时候,大厂给的建议是用大厂自家的应用宝省流量更新功能,说是项目组自己去写这个功能的话,需要的时间估计会有点超过预期,想了一下,也对,对接的事项这么多,不能花太多时间去研究,然后就坑了。

        MSDK上的应用宝省流量更新接起来非常快,只要MSDK接好,调用几个接口,接入游戏加上拼UI啥的,估计1个小时左右就能完成,而且在线上测试的时候,全量更新和增量更新功能都非常棒。自认为没有问题的时候,大厂测试人员反馈有的真机在增量更新的时候不能安装,有解析包时出现问题,咨询大厂的技术后,得到一个情况是MSDK的应用宝省流量更新算法太老了,不支持Android7.0以上设备,然后我马不停蹄地找了2部机子,一部Android4.4.4,一部Android9.0,测试Android4.4.4可以增量更新,Android9.0不可以。那咋办,大厂技术给的解决方案是单独接入应用宝省流量更新SDK。

        哎,死循环啊,跟大厂对接感觉就是一个套路啊,接完一个SDK,再继续接另外一个SDK。咋办,还是硬上啊。避免和MSDK冲突,应用宝省流量更新SDK需要用带external的jar包。

        按照文档,修改AndroidManifest文件,将MSDK上的配置android:name="com.tencent.tmdownloader.TMAssistantDownloadService"修改成android:name="com.tencent.external.tmdownloader.TMAssistantDownloadService",

        添加provider,也是带external的:

        代码就照着MSDK和官方文档一样:

/**
     * 自更新任务监听,包括检查更新回调和下载状态回调
     */
    private ITMSelfUpdateListener mSelfUpdateListener = new ITMSelfUpdateListener() {
        /**
         * 更新时的下载状态回调
         * @param state 状态码
         * @param errorCode 错误码
         * @param errorMsg 错误信息
         */
        @Override
        public void onDownloadAppStateChanged(int state, int errorCode, String errorMsg) {
            StringBuilder sb = new StringBuilder();
            sb.append(state + "|");
            sb.append(errorCode + "|");
            sb.append(errorMsg);
            UnityPlayer.UnitySendMessage("GameMain", "OnDownloadAppState", sb.toString());
        }

        /**
         * 点击普通更新时的下载进度回调
         * @param receiveDataLen 已经接收的数据长度
         * @param totalDataLen 全部需要接收的数据长度(如果无法获取目标文件的总长度,此参数返回-1)
         */
        @Override
        public void onDownloadAppProgressChanged(final long receiveDataLen, final long totalDataLen) {
            StringBuilder sb = new StringBuilder();
            sb.append(receiveDataLen + "|");
            sb.append(totalDataLen);
            UnityPlayer.UnitySendMessage("GameMain", "OnDownloadAppProgress", sb.toString());
        }

        /**
         * 检查更新返回更新信息回调
         * @param tmSelfUpdateUpdateInfo 更新信息结构体
         */
        @Override
        public void onUpdateInfoReceived(TMSelfUpdateUpdateInfo tmSelfUpdateUpdateInfo) {
            long newApkSize = 0;
            long pathSize = 0;
            int state = TMSelfUpdateUpdateInfo.STATUS_CHECKUPDATE_FAILURE;
            int updateMethod = TMSelfUpdateUpdateInfo.UpdateMethod_NoUpdate;
            String updateDownloadUrl = "";
            String newFeature = "";

            try
            {
                if (null != tmSelfUpdateUpdateInfo) {
                    state = tmSelfUpdateUpdateInfo.getStatus();
                    if (state == TMSelfUpdateUpdateInfo.STATUS_CHECKUPDATE_FAILURE) {
                        StringBuilder sb = new StringBuilder();
                        sb.append(newApkSize + "|");
                        sb.append(pathSize + "|");
                        sb.append(state + "|");
                        sb.append(updateMethod + "|");
                        sb.append(updateDownloadUrl + "|");
                        sb.append(newFeature);
                        UnityPlayer.UnitySendMessage("GameMain", "OnCheckUpdate", sb.toString());
                        return;
                    }
                    newApkSize = tmSelfUpdateUpdateInfo.getNewApkSize();
                    pathSize = tmSelfUpdateUpdateInfo.getPatchSize();
                    updateMethod = tmSelfUpdateUpdateInfo.getUpdateMethod();
                    updateDownloadUrl = tmSelfUpdateUpdateInfo.getUpdateDownloadUrl();
                    newFeature = tmSelfUpdateUpdateInfo.getNewFeature();
                    StringBuilder sb = new StringBuilder();
                    sb.append(newApkSize + "|");
                    sb.append(pathSize + "|");
                    sb.append(state + "|");
                    sb.append(updateMethod + "|");
                    sb.append(updateDownloadUrl + "|");
                    sb.append(newFeature);
                    UnityPlayer.UnitySendMessage("GameMain", "OnCheckUpdate", sb.toString());
                    return;
                }
            }
            catch(Exception e)
            {
                Log.e("ZP: ", "onUpdateInfoReceived: " + e.toString());
            }
            newApkSize = 0;
            pathSize = 0;
            state = TMSelfUpdateUpdateInfo.STATUS_CHECKUPDATE_FAILURE;
            updateMethod = TMSelfUpdateUpdateInfo.UpdateMethod_NoUpdate;
            updateDownloadUrl = "";
            newFeature = "";
            StringBuilder sb = new StringBuilder();
            sb.append(newApkSize + "|");
            sb.append(pathSize + "|");
            sb.append(state + "|");
            sb.append(updateMethod + "|");
            sb.append(updateDownloadUrl + "|");
            sb.append(newFeature);
            UnityPlayer.UnitySendMessage("GameMain", "OnCheckUpdate", sb.toString());
        }
    };

    /**
     * 应用宝状态监听
     */
    private YYBDownloadListener mDownloadYYBCallback = new YYBDownloadListener() {
        /**
         * 预下载应用宝状态变化回调
         *
         * @param url  指定任务的url
         * @param state 下载状态: 取自 TMAssistantDownloadTaskState.DownloadSDKTaskState_*
         * @param errorCode 错误码
         * @param errorMsg 错误描述,有可能为null
         */
        @Override
        public void onDownloadYYBStateChanged(String url, int state, int errorCode, String errorMsg) {
            StringBuilder sb = new StringBuilder();
            sb.append(state + "|");
            sb.append(errorCode + "|");
            sb.append(errorMsg + "|");
            sb.append(url);
            UnityPlayer.UnitySendMessage("GameMain", "OnDownloadYYBState", sb.toString());
        }

        /**
         * 预下载应用宝进度回调
         *
         * @param url 当前任务的url
         * @param receiveDataLen 已经接收的数据长度
         * @param totalDataLen 全部需要接收的数据长度(如果无法获取目标文件的总长度,此参数返回 -1)
         */
        @Override
        public void onDownloadYYBProgressChanged(String url, long receiveDataLen, long totalDataLen) {
            StringBuilder sb = new StringBuilder();
            sb.append(receiveDataLen + "|");
            sb.append(totalDataLen + "|");
            sb.append(url);
            UnityPlayer.UnitySendMessage("GameMain", "OnDownloadYYBProgress", sb.toString());
        }

        /**
         * 查询应用宝的下载状态:当用户调了查询应用宝状态时回调
         *
         * @param url 当前任务的url
         * @param state 下载状态: 取自 TMAssistantDownloadTaskState.DownloadSDKTaskState_*
         * @param receiveDataLen 已经接收的数据长度
         * @param totalDataLen 全部需要接收的数据长度(如果无法获取目标文件的总长度,此参数返回 -1)
         */
        @Override
        public void onCheckDownloadYYBState(String url, int state, long receiveDataLen, long totalDataLen) {
//TODO 检查应用宝下载状态处理逻辑
        }
    };

    private static boolean bIsInitSelfUpdateSDK = false;
    /**
     * 初始化省流量更新SDK,传入的Context必须为ApplicationContext
     */
    public void initSelfUpdateSDK(Object object, String channel) {
        Activity activity = (Activity)object;
        if(activity != null)
        {
            bIsInitSelfUpdateSDK = true;
            //附加参数的bundle,一般情况下传空,可以由外部传入场景信息等,具体字段可参考示例{@link TMSelfUpdateConst}中BUNDLE_KEY_*的定义(详见注2)
            Bundle bundle = new Bundle();
            bundle.putString(TMSelfUpdateConst.BUNDLE_KEY_SCENE, "FOO");
            TMAssistantSDK.get().initSelfUpdate(activity.getApplicationContext(), channel, mSelfUpdateListener, mDownloadYYBCallback, bundle);
        }
    }

    public void DestroyUpdate()
    {
        TMAssistantSDK.get().destroy();
    }

    public void CheckNeedUpdate()
    {
        TMAssistantSDK.get().checkSelfUpdate();
    }

    public void StartSaveUpdate(boolean isUseYYB)
    {
        TMAssistantSDK.get().startSelfUpdate(isUseYYB);
    }

        米大师托管模式的问题,之前公司其他项目组有接过米大师,我们项目就按照他们的方式来接,在正式测试的时候,大厂反馈我们的接法有问题,是假托管,不是真托管,如果是YSDK,不是独代的话,没问题。客户端改动量不是很大,服务器改动就有点夸张了。之前假托管的方式,服务器还让我做了补单功能,自己只写了一半,分享下,如果有人刚好跟我一样是用假托管,还可以用上。

/// 
    /// 订单文件名
    /// 
    private string m_saveOrderFileName = "saveOrder.txt";

    /// 
    /// 上次的订单
    /// 
    private OrderData m_lastOrderData;
	
	#region Midas订单数据
    public class OrderDataJson
    {
        public Dictionary> before;//打开Midas之前
        public Dictionary> after;//充值成功(需要删除before中的数据)
    }

    public class OrderData
    {
        public string openID;
        public string openKey;
        public string offerId;
        public string pf;
        public string pfkey;
        public string zoneid;
        public string userType;
        public string money;
        public string passport;
        public int serverid;
        public int device;
        public int bIsSandBox;
        public long savetime;
        public byte bHasUsed;//向服务器请求发货:0表示还没有请求过,1表示已经请求过(但是还是发货失败)
    }

    private bool IsStringEqual(string str1, string str2)
    {
        bool bIsEqual = false;

        if (!string.IsNullOrEmpty(str1) && !string.IsNullOrEmpty(str2))
            bIsEqual = str1.Equals(str2);

        return bIsEqual;
    }

    private bool IsOrderDataEqual(OrderData order1, OrderData order2)
    {
        bool bIsEqual = false;

        bIsEqual = IsStringEqual(order1.openID, order2.openID)
            && IsStringEqual(order1.openKey, order2.openKey)
            && IsStringEqual(order1.offerId, order2.offerId)
            && IsStringEqual(order1.pf, order2.pf)
            && IsStringEqual(order1.pfkey, order2.pfkey)
            && IsStringEqual(order1.zoneid, order2.zoneid)
            //&& IsStringEqual(order1.userType, order2.userType)
            && IsStringEqual(order1.money, order2.money)
            //&& IsStringEqual(order1.passport, order2.passport)
            && order1.serverid == order2.serverid
            && order1.device == order2.device
            && order1.bIsSandBox == order2.bIsSandBox
            && order1.savetime == order2.savetime;

        return bIsEqual;
    }

    /// 
    /// 生成订单
    /// 
    /// 
    /// 
    private OrderData BuildOrder(APMidasGameRequest req)
    {
        OrderData orderData = new OrderData();
        orderData.openID = req.openId;
        orderData.openKey = req.openKey;
        orderData.offerId = req.offerId;
        orderData.pf = req.pf;
        orderData.pfkey = req.pfKey;
        orderData.zoneid = req.zoneId;
        //orderData.userType = GetUserType();
        orderData.money = req.saveValue;
        //orderData.device = MobileUtility.GetPlatofrmID();
        //orderData.bIsSandBox = SDKUtility.GetIsSandBox();
        DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
        orderData.savetime = (DateTime.Now.ToUniversalTime().Ticks - startTime.ToUniversalTime().Ticks) / 10000000;
        orderData.bHasUsed = 0;
        return orderData;
    }

    /// 
    /// 订单是否有效
    /// 
    /// 
    /// 
    private bool GetIsOrderDataValidate(OrderData orderData)
    {
        bool bIsValidate = false;
        bIsValidate = orderData != null && !string.IsNullOrEmpty(orderData.money) && !string.IsNullOrEmpty(orderData.openID);

        return bIsValidate;
    }

    /// 
    /// 获取订单文件路径
    /// 
    /// 
    private string GetSaveOrderFileName()
    {
        string saveOrderFilePath = Application.persistentDataPath + "/" + m_saveOrderFileName;
        if (!File.Exists(saveOrderFilePath))
        {
            FileStream fs = File.Create(saveOrderFilePath);
            fs.Close();
        }

        return saveOrderFilePath;
    }
    #endregion


    public OrderData GetOrderData(string openID, string rmb)
    {
        OrderData tempOrderData = null;

        string saveOrderFilePath = GetSaveOrderFileName();
        if (!string.IsNullOrEmpty(saveOrderFilePath))
        {
            try
            {
                StreamReader reader = new StreamReader(saveOrderFilePath);
                var content = reader.ReadToEnd().Trim();
                reader.Close();

                OrderDataJson tempOrderDataJson = null;
                if (string.IsNullOrEmpty(content))
                    tempOrderDataJson = new OrderDataJson();
                else
                    tempOrderDataJson = JsonMapper.ToObject(content);

                //if (tempOrderDataJson.after != null)
                //{
                //    foreach (var tempOpenIDOrderDict in tempOrderDataJson.after)
                //    {
                //        foreach (var tempMoneyOrderDict in tempOpenIDOrderDict.Value)
                //        {
                //            for (int i = 0; i < tempMoneyOrderDict.Value.Length; ++i)
                //            {
                //                tempMoneyOrderDict.Value[i].bHasUsed = 0;
                //            }
                //        }
                //    }
                //}
            }
            catch(Exception e)
            {
                Debug.LogError(e.ToString());
            }
        }

        return tempOrderData;
    }

    /// 
    /// 储存Midas的订单信息
    /// 
    /// 
    /// 是否在充值前
    private void SaveMidasOrder(OrderData orderData, bool bIsBefore)
    {
        if (!GetIsOrderDataValidate(orderData)) return;

        string saveOrderFilePath = GetSaveOrderFileName();
        if (string.IsNullOrEmpty(saveOrderFilePath)) return;

        try
        {
            StreamReader reader = new StreamReader(saveOrderFilePath);
            var content = reader.ReadToEnd().Trim();
            reader.Close();

            OrderDataJson tempOrderDataJson = null;
            if (string.IsNullOrEmpty(content))
                tempOrderDataJson = new OrderDataJson();
            else
                tempOrderDataJson = JsonMapper.ToObject(content);

            string firstKey = orderData.openID;
            string secondKey = orderData.money;
            if (bIsBefore)//充值前
            {
                if (tempOrderDataJson.before == null)
                    tempOrderDataJson.before = new Dictionary>();
                
                if (!tempOrderDataJson.before.ContainsKey(firstKey))
                {
                    List temOrderList = new List();
                    temOrderList.Add(orderData);
                    Dictionary tempOrderDict = new Dictionary();
                    tempOrderDict.Add(secondKey, temOrderList.ToArray());
                    tempOrderDataJson.before.Add(firstKey, tempOrderDict);
                }
                else
                {
                    Dictionary tempOrderDict = tempOrderDataJson.before[firstKey];
                    if(!tempOrderDict.ContainsKey(secondKey))
                    {
                        List temOrderList = new List();
                        temOrderList.Add(orderData);
                        tempOrderDict.Add(secondKey, temOrderList.ToArray());
                    }
                    else
                    {
                        List temOrderList = new List(tempOrderDict[secondKey]);
                        temOrderList.Add(orderData);
                        tempOrderDict[secondKey] = temOrderList.ToArray();
                        tempOrderDataJson.before[firstKey] = tempOrderDict;
                    }
                }
            }
            else//充值后
            {
                if (tempOrderDataJson.after == null)
                    tempOrderDataJson.after = new Dictionary>();

                if (!tempOrderDataJson.after.ContainsKey(firstKey))
                {
                    List temOrderList = new List();
                    temOrderList.Add(orderData);
                    Dictionary tempOrderDict = new Dictionary();
                    tempOrderDict.Add(secondKey, temOrderList.ToArray());
                    tempOrderDataJson.after.Add(firstKey, tempOrderDict);
                }
                else
                {
                    Dictionary tempOrderDict = tempOrderDataJson.after[firstKey];
                    if (!tempOrderDict.ContainsKey(secondKey))
                    {
                        List temOrderList = new List();
                        temOrderList.Add(orderData);
                        tempOrderDict.Add(secondKey, temOrderList.ToArray());
                    }
                    else
                    {
                        List temOrderList = new List(tempOrderDict[secondKey]);
                        temOrderList.Add(orderData);
                        tempOrderDict[secondKey] = temOrderList.ToArray();
                        tempOrderDataJson.after[firstKey] = tempOrderDict;
                    }
                }

                // 移除充值前的订单
                if (tempOrderDataJson.before != null && tempOrderDataJson.before.ContainsKey(firstKey) && tempOrderDataJson.before[firstKey].ContainsKey(secondKey))
                {
                    List temOrderList = new List(tempOrderDataJson.before[firstKey][secondKey]);
                    for (int i = 0; i < temOrderList.Count; ++i)
                    {
                        if (IsOrderDataEqual(temOrderList[i], orderData))
                        {
                            temOrderList.RemoveAt(i);
                            break;
                        }
                    }
                    tempOrderDataJson.before[firstKey][secondKey] = temOrderList.ToArray();
                }
            }

            StreamWriter writer = new StreamWriter(new FileStream(saveOrderFilePath, FileMode.Create));
            writer.Write(JsonMapper.ToJson(tempOrderDataJson));
            writer.Flush();
            writer.Close();
        }
        catch (Exception e)
        {
            Debug.LogError(e.ToString());
        }
    }

    /// 
    /// 删除Midas的订单信息
    /// 
    /// 
    /// 
    private void RemoveMidasOrder(OrderData orderData, bool bIsBefore)
    {
        if (!GetIsOrderDataValidate(orderData)) return;

        string saveOrderFilePath = GetSaveOrderFileName();
        if (string.IsNullOrEmpty(saveOrderFilePath)) return;

        try
        {
            StreamReader reader = new StreamReader(saveOrderFilePath);
            var content = reader.ReadToEnd().Trim();
            reader.Close();

            OrderDataJson tempOrderDataJson = null;
            if (string.IsNullOrEmpty(content))
                tempOrderDataJson = new OrderDataJson();
            else
                tempOrderDataJson = JsonMapper.ToObject(content);

            string firstKey = orderData.openID;
            string secondKey = orderData.money;
            if (bIsBefore)//充值前
            {
                if (tempOrderDataJson.before != null && tempOrderDataJson.before.ContainsKey(firstKey) && tempOrderDataJson.before[firstKey].ContainsKey(secondKey))
                {
                    List temOrderList = new List(tempOrderDataJson.before[firstKey][secondKey]);
                    for (int i = 0; i < temOrderList.Count; ++i)
                    {
                        if (IsOrderDataEqual(temOrderList[i], orderData))
                        {
                            temOrderList.RemoveAt(i);
                            break;
                        }
                    }
                    tempOrderDataJson.before[firstKey][secondKey] = temOrderList.ToArray();
                }
            }else
            {
                if (tempOrderDataJson.after != null && tempOrderDataJson.after.ContainsKey(firstKey) && tempOrderDataJson.after[firstKey].ContainsKey(secondKey))
                {
                    List temOrderList = new List(tempOrderDataJson.after[firstKey][secondKey]);
                    for (int i = 0; i < temOrderList.Count; ++i)
                    {
                        if (IsOrderDataEqual(temOrderList[i], orderData))
                        {
                            temOrderList.RemoveAt(i);
                            break;
                        }
                    }
                    tempOrderDataJson.after[firstKey][secondKey] = temOrderList.ToArray();
                }
            }

            StreamWriter writer = new StreamWriter(new FileStream(saveOrderFilePath, FileMode.Create));
            writer.Write(JsonMapper.ToJson(tempOrderDataJson));
            writer.Flush();
            writer.Close();
        }
        catch (Exception e)
        {
            Debug.LogError(e.ToString());
        }
    }
	
	/// 2.生成支付回调对象
    private class MyMidasPayCallback : MidasPayCallback
    {
        void MidasPayCallback.OnMidasLoginExpired()
        {
            TencentSDKManager.Instance.SetMessage("MainScript.OnMidasLoginExpired");
        }

        void MidasPayCallback.OnMidasPayFinished(APMidasResponse result)
        {
            TencentSDKManager.Instance.SetMessage("MainScript.OnMidasPayFinished: Pay result = " + result.ToString());
            if (result.resultCode == 0)//充值成功
            {
                TencentSDKManager.Instance.SetMessage("充值成功");
                if (TencentSDKManager.Instance.m_payType == MidasPayType.GameMoney)
                {
                    TencentSDKManager.Instance.SaveMidasOrder(TencentSDKManager.Instance.m_lastOrderData, false);
                }
            }
            else//充值失败
            {
                TencentSDKManager.Instance.SetMessage("充值失败");
                if (TencentSDKManager.Instance.m_payType == MidasPayType.GameMoney)
                {
                    TencentSDKManager.Instance.RemoveMidasOrder(TencentSDKManager.Instance.m_lastOrderData, true);
                }
            }
        }
    }

 

你可能感兴趣的:(Unity)