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環境的驗證服務


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM