zoukankan      html  css  js  c++  java
  • Unity3d发布IOS(包含u3d自带IAP内购)的流程-小白篇(三)-u3d配置ios内购部分

      上一篇地址:https://www.cnblogs.com/yzxhz/p/9572272.html

      在上一篇说道ios内购网页端的配置,配置好证书appID配置文件以及真机调试设备后,

      这篇文章还需要用到:内购产品的ID,内购产品的公共秘钥

      接下来就进入u3d操作环节。

      u3d可以与ios的代码进行相互调用,这样就可以用oc代码编写ios内购,然后再从unity调用,方法网上有,不过对于我这种看不懂oc的菜鸟来说,实在是为难我了。。。不过好在unity提供了一个IAP插件,解决了这个大问题。

      首先,想办法获取这个插件,可以去Windows=>Generel=> Asset Store  里面搜索 “Unity IAP”,图中第一个免费的就是。

    或者也可以在Windows=>Generel=> Services 

    里面找到上图红圈部分(注意后面这里,无论是插件在方法1找到还是2找到的,都要把上图这里的状态改为ON),点进去后

    这里没有导入的话显示的是Import,我已近导入了,就显示的是Update,点击导入即可。

    上述两种方法都要把Services的内购状态改为ON,还有都要登录账号才能操作。

     

    接下来,上代码:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Net;
    using System.Text;
    using LitJson;
    using UnityEngine;
    using UnityEngine.Purchasing;
    using UnityEngine.Networking;
    
    namespace TianBoWang.Function
    {
        [Serializable]
        public class Products
        {
            public string id;
            public int productType;
    
        }
    
        /// <summary>
        /// 购买管理
        /// </summary>
        public class PurchaseManager : MonoBehaviour, IStoreListener
        {
            public List<Products> products = new List<Products>();
            public string publicKey;
            ConfigurationBuilder builder;
            private IStoreController m_Controller;
            private IAppleExtensions m_AppleExtensions;
            private int productIndex;
            private static bool isInited = false;
            private bool isInitFailed = false;
    
            void Awake()
            {
    
                if (!isInited)
                {
                    InitPurchase();
                }
            }
    
            /// <summary>
            /// 初始化
            /// </summary>
            void InitPurchase()
            {
    
                var module = StandardPurchasingModule.Instance();
                builder = ConfigurationBuilder.Instance(module);
    
                for (int i = 0; i < products.Count; i++)
                {
                    builder.AddProduct(products[i].id, (ProductType)products[i].productType);
                }
    
                UnityPurchasing.Initialize(this, builder);
            }
            /// <summary>
            /// 初始化成功
            /// </summary>
            /// <param name="controller">Controller.</param>
            /// <param name="extensions">Extensions.</param>
            public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
            {
    
                m_Controller = controller;
                m_AppleExtensions = extensions.GetExtension<IAppleExtensions>();
                m_AppleExtensions.RegisterPurchaseDeferredListener(OnDeferred);
    
                isInited = true;
    
            }
            /// <summary>
            /// iOS 网络延迟错误
            /// </summary>
            /// <param name="item">Item.</param>
            private void OnDeferred(Product item)
            {
                // Debug.Log("网络连接不稳");
            }
    
            /// <summary>
            /// 初始化失败
            /// </summary>
            /// <param name="error">Error.</param>
            public void OnInitializeFailed(InitializationFailureReason error)
            {
                isInitFailed = true;
                Debug.Log("IAPInitializeFailed!!!" + "Reason:" + error);
            }
    
            /// <summary>
            /// 恢复购买
            /// </summary>
            public void RestorePurchases()
            {
    
                if (Application.platform == RuntimePlatform.IPhonePlayer ||
                    Application.platform == RuntimePlatform.OSXPlayer)
                {
    
                    if (!isInited)
                    {
                        //loading.SetActive(false);
                        InitPurchase();
                    }
    
                    StartCoroutine("InitAndRestore");
                }
    
            }
    
            IEnumerator InitAndRestore()
            {
    
                if (isInitFailed || !isInited)
                {
                    //初始化失败
                    StopCoroutine("InitAndRestore");
    
                }
                yield return new WaitUntil(() => { return m_Controller != null && m_AppleExtensions != null; });
    
                m_AppleExtensions.RestoreTransactions((result) =>
                {
                    // The first phase of restoration. If no more responses are received on ProcessPurchase then 
                    // no purchases are available to be restored.
                    Debug.Log("RestorePurchases continuing: " + result + ". If no further messages, no purchases available to restore.");
    
                    if (result)
                    {
                        //产品已经restore,不过官方的解释是恢复过程成功了,并不代表所购买的物品都恢复了
                    }
                    else
                    {
                        // 恢复失败
                    }
    
                    StopCoroutine("InitAndRestore");
                });
    
            }
    
            /// <summary>
            /// 购买产品  购买的第几个    按钮点击
            /// </summary>
            /// <param name="index">Index.</param>
            public void OnPurchaseClicked(int index)
            {
    
                if (Application.platform == RuntimePlatform.IPhonePlayer ||
                    Application.platform == RuntimePlatform.OSXPlayer)
                {
    
                    if (!isInited)
                        InitPurchase();
                    StartCoroutine("InitAndPurchase", index);
                }
            }
            IEnumerator InitAndPurchase(int index)
            {
    
                if (isInitFailed || !isInited)
                {
                    //初始化失败
                    StopCoroutine("InitAndPurchase");
    
                }
    
                yield return new WaitUntil(() => { return m_Controller != null && m_AppleExtensions != null; });
    
                m_Controller.InitiatePurchase(products[index].id);
                StopCoroutine("InitAndPurchase");
            }
    
    
            /// <summary>
            /// 购买成功回调
            /// </summary>
            /// <returns>The purchase.</returns>
            /// <param name="e">E.</param>
            public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
            {
                //使用id判断是否是当前购买的产品,我这里只有一个产品,所以就是products[0]
                if (e.purchasedProduct.definition.id == products[0].id)
                {
                    string transactionReceipt = m_AppleExtensions.GetTransactionReceiptForProduct(e.purchasedProduct);
                    StartCoroutine("CheckRecipe", transactionReceipt);//使用苹果的服务器进行验证订单是否有效
                }
    
                return PurchaseProcessingResult.Complete;
            }
    
    
            public void OnPurchaseFailed(Product i, PurchaseFailureReason p)
            {
                //购买失败的逻辑
            }
    
    
    
            HttpWebRequest request;
            IEnumerator CheckRecipe(string s)
            {
                JsonData json = new JsonData();
                json["receipt-data"] = s;
                json["password"] = publicKey;
    
                Uri urlReal = new Uri("https://buy.itunes.apple.com/verifyReceipt");//正式验证网址
                                                                                    //   Uri urlSandBox = new Uri("https://sandbox.itunes.apple.com/verifyReceipt");//沙箱测试验证网址
                using (UnityWebRequest www = new UnityWebRequest(urlReal, "POST"))
                {
                    byte[] postBytes = Encoding.UTF8.GetBytes(json.ToJson());
                    www.uploadHandler = (UploadHandler)new UploadHandlerRaw(postBytes);
                    www.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
                    www.SetRequestHeader("Content-Type", "application/json");
                    www.timeout = 20;//20秒后超时
                    yield return www.Send();
                    if (www.isNetworkError)
                    {
                        //Debug.Log("网络错误:"+www.error);
                    }
                    else
                    {
                        if (www.responseCode == 200)
                        {
                            JsonData resoultJson = JsonMapper.ToObject(www.downloadHandler.text);
                            if (resoultJson["status"].ToString() == "0")
                            {
                                //验证成功的逻辑
                            }
                            else
                            {
                                //验证失败的逻辑
                            }
                        }
                    }
                }
    
                StopCoroutine("CheckRecipe");
            }
        }
    }

    2018/12/21补充:

    m_Controller.products.WithID(/*<Product>.id*/).metadata.localizedPriceString;
    

    使用这种方法获取iap后台的价格以及货币符号

    使用方法:我这里使用的是LitJson插件, 将代码挂到任意物体

    有几个需要购买的产品就在size里面写几。

    id就是每个要购买的产品的id(苹果后台获取)

    product Type代表类型,(0表示消耗品,1表示费消耗品,2表示订阅)

    下面的public key是苹果后台产品的公共秘钥

    然后在按钮点击的时候调用其中的购买方法( void OnPurchaseClicked(int i) ) 参数i代表在面板上加的第几个产品、,以及恢复购买方法( void RestorePurchases())即可。

    其中有几处需要自己写逻辑的地方,我已经代码注释标明了,例如购买成功、失败之后要执行的逻辑等。

    在二次验证的时候有一些坑:

    1.二次验证向服务器发送不能使用WWW通讯。

    2.不要使用C#的HttpWebRequest,这个鬼东西当你在协程中使用的时候,网络不好就会出现程序假死!要使用unity内置的 UnityWebRequest。

    3.测试的时候用沙箱验证网址测试,送审的时候别忘了使用正式验证网址,不然被打回。

    在二次验证中返回的正确/错误代码以及意思:

    0 验证成功
    21000 App Store不能读取你提供的JSON对象
    21002 receipt-data域的数据有问题
    21003 receipt无法通过验证
    21004 提供的shared secret不匹配你账号中的shared secret
    21005 receipt服务器当前不可用
    21006 receipt合法,但是订阅已过期。服务器接收到这个状态码时,receipt数据仍然会解码并一起发送
    21007 receipt是Sandbox receipt,但却发送至生产系统的验证服务
    21008 receipt是生产receipt,但却发送至Sandbox环境的验证服务
  • 相关阅读:
    Merge Sorted Array
    Remove Duplicates from Sorted List
    Climbing Stairs
    Plus One
    微信开发 (四) 微信网页授权
    基于注解的实现获取微信openId1
    利用TortoiseGit(小乌龟)将项目上传至GitHub网站
    微信网页授权多次回调code请求
    安装git之后,桌面出现蓝色问号的解决方法
    两个日期之间的日历
  • 原文地址:https://www.cnblogs.com/yzxhz/p/9618665.html
Copyright © 2011-2022 走看看