Unity 之 接入IOS内购过程解析【文末源码】

这篇具有很好参考价值的文章主要介绍了Unity 之 接入IOS内购过程解析【文末源码】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

看完此文章你可以了解IOS内购接入全过程,可以学习到Unity从零接入内购功能。另外此博文和文末源码没有涉及到掉单补单部分逻辑。

需要准备

  • 一台mac系统机器
  • 苹果开发者账号
  • Unity2019.4.x (不同版本,3步骤略有不同)
  • Xcode (我的版本12.5)

内购导图

Unity 之 接入IOS内购过程解析【文末源码】

一,效果展示

Unity 之 接入IOS内购过程解析【文末源码】


二,苹果后台

PS:若公司已有运营人员在后台操作过了,可以跳过此步骤。注意测试机上还是需要登陆沙箱账号奥。

2.1 注册应用程序

  1. 首先打开苹果开发者官网:https://developer.apple.com/

  2. 点击登陆并点“Account”,在Apple Developer Center中,导航到相应的标识符部分:

Unity 之 接入IOS内购过程解析【文末源码】

  1. 添加新的 App ID 以创建与 Apple 的基本应用程序实体。

    • 注意:使用显式应用程序 ID。通配符应用 ID (com.example.*) 不能用于使用应用内购买的应用。

    • 注意:在开发者中心创建 App ID 后,即可在 iTunes Connect 中使用它。

Unity 之 接入IOS内购过程解析【文末源码】

  1. 导航到iTunes Connect并创建一个应用程序,以与游戏建立商店关系:

Unity 之 接入IOS内购过程解析【文末源码】

  1. 使用新创建的 App ID 作为应用的 Bundle ID:

Unity 之 接入IOS内购过程解析【文末源码】

2.2 添加应用内购买

  1. 选择功能并使用加号 (“+”) 按钮添加新的应用内购买:
    Unity 之 接入IOS内购过程解析【文末源码】

  2. 选择产品类型:

Unity 之 接入IOS内购过程解析【文末源码】

  1. 指定产品标识符,并根据要求填写其他字段。
  • 注意:此处的“产品 ID”与游戏源代码中使用的标识符相同,通过AddProduct()或AddProducts()添加到Unity IAP ConfigurationBuilder实例。

Unity 之 接入IOS内购过程解析【文末源码】

2.3 测试IAP

  1. 使用iTunes Connect创建沙盒测试器以在您的测试设备的iTunes帐户上使用。为此,请导航至iTunes Connect > Users and Roles,然后选择加号 (“+”) 按钮。

PS:详情可查看AppleSandbox Tester文档,。

Unity 之 接入IOS内购过程解析【文末源码】

Unity 之 接入IOS内购过程解析【文末源码】

  1. Xcode项目配置
    Xcode 项目中Bundle IdentitifierTeamiTunes Connect 中使用的一致
    PS:Unity中的包名也应该保持一致

Unity 之 接入IOS内购过程解析【文末源码】

  1. 在测试设备登陆沙箱测试账号
    Unity 之 接入IOS内购过程解析【文末源码】

三,下载IAP包

3.1 下载Package

打开Windows -> Package Manager 下载 In App Purchasing
Unity 之 接入IOS内购过程解析【文末源码】

3.2 打开Srever配置

  1. 打开服务窗口,在服务窗口中查找和启用应用内购买
    Unity 之 接入IOS内购过程解析【文末源码】

  2. 选择项目ID(当前登录的账号)
    Unity 之 接入IOS内购过程解析【文末源码】

  3. 启用In-APP Purchasing (有的时候切换慢,需要等一会)
    Unity 之 接入IOS内购过程解析【文末源码】

  4. 回答问题
    问:这款应用主要面向13岁以下的儿童(是就勾选,不是不勾选)Unity 之 接入IOS内购过程解析【文末源码】

  5. 有个报错
    我没有解决也没有影响,需要解决的话按照下面的提示操作一下
    Unity 之 接入IOS内购过程解析【文末源码】


四,代码逻辑

4.1 逻辑分析

  1. 实现IStoreListener接口,接口提供四个回调函数,分别是初始化成功、失败,购买成功、失败;

  2. 编写初始化逻辑,完善初始化成功、失败回调接口函数;

  3. 编写调用购买逻辑,完善购买成功、失败回调接口函数;

  4. 实际开发中需要限制,购买按钮只被点击一次。

代码结构就是这样了,详细解释代码注释已经写得很清楚了,这里不再赘述。

使用时将代码挂载到场景即可进行初始化,然后创建Button监听代码中的OnClickPurchase方法即可打包测试。

PS:注意需要将goodsList数组中的key换成你后台申请的

4.2 示例源码

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Purchasing;

/// <summary>
/// IAP管理类
/// </summary>
public class IAPManager : MonoBehaviour, IStoreListener
{
    /// <summary>
    /// 需要换成对应游戏后台的key
    /// </summary>
    private string[] goodsList = new string[]
    {
        "com.czhenya.gold.1",
        "com.czhenya.gold.2",
        "com.czhenya.gold.3"
    };

    // 控制器
    private IStoreController controller;

    // 苹果扩展
    private IAppleExtensions appleExtensions;

    // 谷歌商店扩展
    private IGooglePlayStoreExtensions googlePlayStoreExtensions;

    // 是否可以发起购买
    private bool isCanOnClickBubBtn = false;

    void Start()
    {
        Init();
    }

    /// <summary>
    /// 初始化
    /// </summary>
    private void Init()
    {
        // 没有网络,IAP会一直初始化
        if (Application.internetReachability == NetworkReachability.NotReachable)
        {
            Debug.Log("----- 用户没有连接网络 IAP不可用 ------");
        }

        var module = StandardPurchasingModule.Instance();
        ConfigurationBuilder builder = ConfigurationBuilder.Instance(module);
        // builder.AddProduct("商品id1", ProductType.Consumable); 
        // ProductType :和后台说明对应
        // consumable:可消费的,如游戏中的金币,用完还可以再购买。
        // non-consumable:不可销毁的,一次购买,永久生效。比如去广告,解锁游戏关卡,这种商品只能购买一次。
        // subscription:订阅的,这种一般用于新闻、杂志、或者app里面的月卡。可以按月或者按年收费。
        for (int i = 0; i < goodsList.Length; i++)
        {
            builder.AddProduct(goodsList[i], ProductType.Consumable);
        }

        // 开始初始化
        UnityPurchasing.Initialize(this, builder);
    }

    /// <summary>
    /// 初始化成功 -- 接口函数
    /// </summary>
    /// <param name="controller"></param>
    /// <param name="extensions"></param>
    public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    {
        Debug.Log("【Unity IAP】初始化成功 IAP initialize success");
        isCanOnClickBubBtn = true;
        this.controller = controller;

        // 回调赋值
        this.appleExtensions = extensions.GetExtension<IAppleExtensions>();
        this.googlePlayStoreExtensions = extensions.GetExtension<IGooglePlayStoreExtensions>();

        //登记 购买延迟 监听器
        appleExtensions.RegisterPurchaseDeferredListener(OnDeferred);
    }

    //购买延迟提示
    private void OnDeferred(Product item)
    {
        Debug.Log("【Unity IAP】 网速慢.................");
    }

    /// <summary>
    /// 初始化失败回调 -- 接口函数
    /// </summary>
    /// <param name="error"></param>
    public void OnInitializeFailed(InitializationFailureReason error)
    {
        Debug.LogError("【Unity IAP】初始化失败 OnInitializeFailed, reason:" + error.ToString());
    }

    /// <summary>
    /// 购买失败回调 -- 接口函数
    /// </summary>
    /// <param name="i"></param>
    /// <param name="p"></param>
    public void OnPurchaseFailed(Product i, PurchaseFailureReason p)
    {
        Debug.LogError("【Unity IAP】购买失败 OnPurchaseFailed,reason:" + p.ToString());
        if (this.onPurchaseFailed != null)
        {
            this.onPurchaseFailed();
            this.onPurchaseFailed = null;
        }
    }

    /// <summary>
    /// 购买成功回调 -- 接口函数
    /// </summary>
    /// <param name="e"></param>
    /// <returns></returns>
    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
    {
        Debug.LogError("【Unity IAP】购买过程 purchase finished, apple return receipt:" + e.purchasedProduct.receipt);

        if (this.onPurchaseSuccess != null)
        {
            this.onPurchaseSuccess(e.purchasedProduct.receipt);
            this.onPurchaseSuccess = null;
        }

        return PurchaseProcessingResult.Complete;
    }

    /// <summary>
    /// 支付失败回调
    /// </summary>
    private Action onPurchaseFailed;

    /// <summary>
    /// 支付成功回调
    /// </summary>
    private Action<string> onPurchaseSuccess;

    /// <summary>
    /// 购买产品
    /// </summary>
    /// <param name="productId">产品ID</param>
    /// <param name="onFailed">失败回调</param>
    /// <param name="onSuccess">成功回调</param>
    public void PurchaseProduct(string productId, Action onFailed, Action<string> onSuccess)
    {
        this.onPurchaseFailed = onFailed;
        this.onPurchaseSuccess = onSuccess;

        if (controller != null)
        {
            var product = controller.products.WithID(productId);
            if (product != null && product.availableToPurchase)
            {
                Debug.Log("【Unity IAP】开始购买");
                controller.InitiatePurchase(productId);
            }
            else
            {
                Debug.LogError("【Unity IAP】失败回调 no product with productId:" + productId);
                if (this.onPurchaseFailed != null)
                {
                    this.onPurchaseFailed();
                }
            }
        }
        else
        {
            Debug.LogError("【Unity IAP】失败回调 controller is null,can not do purchase");
            if (this.onPurchaseFailed != null)
            {
                this.onPurchaseFailed();
            }
        }
    }

    /// <summary>
    /// 发起购买函数  -- 商城按钮监听
    /// </summary>
    /// <param name="i"></param>
    public void OnClickPurchase(int i)
    {
        // 正式项目时需限制 -- 不允许多次点击 

        Debug.Log("【Unity IAP】发起购买函数 " + Application.internetReachability);
        if (Application.internetReachability == NetworkReachability.NotReachable)
        {
            Debug.Log("【Unity IAP】用户没网... ");
            return;
        }

        PurchaseProduct(goodsList[0], OnBuyFailed, OnBuySuccess);
    }

    /// <summary>
    /// 购买失败回调
    /// </summary>
    void OnBuyFailed()
    {
        Debug.Log("【Unity IAP】购买失败回调 OnBuyFailed...");
    }

    /// <summary>
    /// 购买成功回调
    /// </summary>
    /// <param name="str"></param>
    void OnBuySuccess(string str)
    {
        Debug.Log("【Unity IAP】购买成功回调 OnBuySuccess..." + str);
        //会得到下面这样一个字符串
        //{"Store":"AppleAppStore",
        //"TransactionID":"1000000845663422",
        //"Payload":"MIIT8QYJKoZIhvcNAQcCoIIT4jCCE94CAQExBBMMIIBa ... 还有N多 ..."}
    }
}

五,打包测试

代码配置和手动配置选择一个习惯用的方式即可。

5.1 代码配置

由于内购需要系统库StoreKit.frameworkiAd.framework。为了不每次打包Xcode时都手动添加,所以创建打包配置代码。(复制下面文件,放到Editor文件夹下)

using System.IO;
using UnityEditor;
using UnityEngine;
#if UNITY_IOS
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
#endif

/// <summary>
/// 打包自动配置文件
/// </summary>
public class CZYConfigEditor
{
#if UNITY_IOS
    [PostProcessBuildAttribute(100)]
    public static void onPostProcessBuild(BuildTarget target, string targetPath)
    {
        if (target != BuildTarget.iOS)
        {
            return;
        }

        string projPath = PBXProject.GetPBXProjectPath(targetPath);
        PBXProject proj = new PBXProject();
        proj.ReadFromString(File.ReadAllText(projPath));
        string unityTarget = proj.GetUnityFrameworkTargetGuid();

        #region 系统依赖库

        proj.AddFrameworkToProject(unityTarget, "StoreKit.framework", false);
        proj.AddFrameworkToProject(unityTarget, "iAd.framework", false);

        #endregion

        string content = proj.WriteToString();
        File.WriteAllText(projPath, content);
    }
#endif
}

5.2 手动配置

不写上面代码的话,打包出Xcode工程后,需要手动添加StoreKit.frameworkiAd.framework

Unity 之 接入IOS内购过程解析【文末源码】

然后正常打包进行测试~ 即可完成开篇效果。


六,问题汇总

6.1 示例日志

  • IAP初始化成功日志:
    Unity 之 接入IOS内购过程解析【文末源码】

  • 购买成功回调日志:

【Unity IAP】购买成功回调 OnBuySuccess…{“Store”:“AppleAppStore”,“TransactionID”:“1000000866663121”,“Payload”:“MIIT8QYJKoZIhvcNAQcCo
…中间省略N多行…
jSYLAk”}
System.Action`1:Invoke(T)
IAPMgr:ProcessPurchase(PurchaseEventArgs)
UnityEngine.Purchasing.PurchasingManager:ProcessPurchaseIfNew(Product)
UnityEngine.Purchasing.JSONStore:OnPurchaseSucceeded(String, String, String)
System.Action:Invoke()
UnityEngine.Purchasing.Extension.UnityUtil:Update()

6.2 注意事项

  • 真机测试的时候,一定要退出原来的账号(app store 登录的账号退出),才能用沙盒测试账号。
  • 请务必使用真机来测试,一切以真机为准。
  • 项目的Bundle identifier需要与您申请AppID时填写的bundleID一致,不然会无法请求到商品信息。
  • 沙盒环境测试appStore内购流程的时候,请使用没越狱的设备。
  • 沙盒的测试账号和你请求商品信息没有关系。请求商品信息的流程是,你在后台配置好了内购商品,并且将其添加到了需要集成内购功能的App中,然后你请求商品。请求到商品后的流程是这样的,苹果系统会自动弹出登录框让你登录账号。然后根据提示操作进行购买,这里的账号就是你配置的沙盒测试账号。

6.3 参考链接

官方文档 Unity IAP

官方手册 Unity IAP

6.4 文末源码

其实源码以及步骤都在上面分享过了,若还有什么不明白的,可以点击下面链接下载,积分不够的童鞋关注下方卡片公号​,回复:IOS内购 即可获得Demo源码~

源码链接文章来源地址https://www.toymoban.com/news/detail-416583.html


到了这里,关于Unity 之 接入IOS内购过程解析【文末源码】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java接入内购 Apple Pay、Google Play

    内购流程: 客户端向服务器发起请求生成预订单,服务器校验后生成预订单返回客户端。若调起支付界面后未支付,则通知服务器取消本订单。 客户端拿到预订单号后,在玩家完成付款操作后,携带预订单号请求支付平台,将预订单号存储在支付平台中,并获取支付凭证。

    2024年04月16日
    浏览(27)
  • iOS - 订阅型内购指南

    一、App Store Connect 帮助 二、测试 三、订阅状态 四、问题思考 1、订阅归属: 以往的消耗性内购, 通常会生成订单ID对应到苹果的内购ID及用户id,对于我们来说,内购仅仅只是个支付工具,而订阅型内购有一整套销售模型 订阅内购是跟随AppleID的,但是在开发过程中,我们是获

    2024年02月11日
    浏览(29)
  • iOS_苹果内购详细步骤

    什么是Apple Pay? 简单说是一种“支付工具”。对于国外流行信用卡,Apple Pay很符合美国的国情。但对于中国,微信支付、支付宝支付更加便利符合中国的人的行为习惯。 说到这你可能就理解了,Apple Pay,就是类比支付宝类似的线上线下支付工具。 Apple Pay和 支付宝、微信一样

    2023年04月09日
    浏览(28)
  • IOS内购自动续费订阅测试

    一、IOS 内购类型 1、 消耗型商品: 只可使用一次的产品,使用之后即失效,必须再次购买。 示例 :抽奖券。 2、 非消耗型商品: 只需购买一次,不会过期或随着使用而减少的产品。 示例 :游戏 App 的赛道。 3、 自动续期订阅: 允许用户在固定时间段内购买动态内容的产品

    2024年02月16日
    浏览(25)
  • Java服务端接入苹果内购。实现票据二次校验、自动续期订阅

    记录一下 Java 服务端接入苹果内购。 苹果规定在 APP Store上架的 APP 使用苹果自己的支付方式(IAP内购),并且苹果会抽30%的税。 上架商品包括:消耗性,非消耗性,自动续期订阅,非续期订阅。上架商品可在 APP Store后台配置。 由用户完成付款操作后,苹果返回 票据 给 IO

    2024年02月02日
    浏览(32)
  • MAC机器Unity接入iOS SDK安装cocoapods全攻略

    要在Unity3D里面接入iOS SDK,因此又在新mac上配置了一道环境。机器是Mac mini,芯片是M2,OS为Sonoma 14.2。 若Unity3D工程里面有EDM4U插件,且配置了Dependencies文件(文件内配置了iosPod),那么在导出XCode的工程时,会自动安装CocoaPods,但多半会失败。失败原因多是机器自带的ruby版本

    2024年04月29日
    浏览(26)
  • Unity iOS平台接入微信SDK,实现微信登录等功能

    文章目录 一、前言 二、流程 1、申请开发者账号 2、创建应用 3、下载SDK 4、导入到Unity中 5、编写Objective-C代码 5.1、CustomAppController.mm 5.2、WXApiManager.h 5.3、WXApiManager.mm 5.4、注册回调对象 5.5、封装初始化接口 5.6、封装登录接口 5.7、其他接口封装 6、XCodeAPI 7、关于Universal Link 8、

    2024年02月13日
    浏览(100)
  • 【手撕源码】vue3响应式原理解析(文末抽奖)

    🐱 个人主页: 不叫猫先生 🙋‍♂️ 作者简介:2022年度博客之星前端领域TOP 2,前端领域优质作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀! 💫优质专栏:vue3从入门到精通、TypeScript从入门到实践 📢 资料领取:前端进阶资料以及文中源

    2024年02月03日
    浏览(27)
  • Unity如何快速接入iOS和GooglePlay的成就排行榜等GameCenter功能

    一般在游戏开发中,经常有成就排行榜的需求,按照我们的理解,通常是要自己导入谷歌的sdk,或者苹果的sdk,然后封装后通过桥接来调用。 不用这么复杂,本鱼蛋(egostudio 防爬)告诉大家一个方法,其实Unity已经帮我们封装好了,直接调用接口即可。 目前支持的功能有: 用

    2024年02月04日
    浏览(34)
  • 【iOS内购支付】Uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑(手把手教程)

    Hello!又是很长时间没有写博客了,因为最近又开始从事新项目,也是第一次接触关于uniapp开发原生IOS应用的项目,在这里做一些关于我在项目中使用苹果内购支付所实现的方式以及要注意的事项,希望能给正在做uniapp开发ios应用需要使用苹果内购支付的小伙伴一些帮助! 原

    2023年04月25日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包