Unity接入谷歌支付

一.接入前准备

  1.申请一个google play开发者账号,这里我是有google play开发账号的,毕竟我们的APP是发谷歌市场的

  2.提前准备好一个apk(不需要集成支付sdk,占位用),在google play控制台上传你的apk,这里你可以发封闭测试里面去

  3.发布一个alpha或者beta的版本,发布之前需要点亮以下选项(提交商品详情内容)(确定内容分级)(选择发布范围)等,之后才能正常发布(选择内部测试即可,alpha测试还需要)

  4.添加测试人员,等应用审核通过之后,会得到一个地址,把地址发给对方,让对方点击同意加入测试即可

 

   5.需要创建应用内商品(商品id,商品描述,定价),按提示填就可以了,注意确保商品id唯一

6.在账户详细信息里面,添加许可测试的邮箱账号,许可测试响应改为 “RESPOND_NORMALLY或者LICENSED”(一般选择LICENSED),点击保存,需要一两分钟生效,记得弄这一步,这个很坑,你不弄,你测试人员就一直不会出现测试卡测试的模式

 

 

7.检查你的包名和签名文件是否和Google Console 上面上传的apk包是否一致(网站:https://console.cloud.google.com/apis/credentials?pli=1&project=api-project-68117872)

  8.检查版本号是否和Google console发布的apk版本是否一致

  9.检查你是否可以购买,是否绑定了银行卡,手机支不支持Google支付,手机是否有Google服务(实际支付才需要绑定,测试支付不用绑定也可以)

  10.测试登录和支付都需要vpn

二.打包配置

1.firebase创建项目,配置包名和打包使用的Cert的SHA-1密钥

2.下载配置json文件,放在Assets\Plugins\Android下(网址:https://console.cloud.google.com/apis/credentials?project=api-project-68117872)

3.baseProjectTemplate.gradle的repositories增加mavenCentral(),dependencies增加classpath 'com.google.gms:google-services:4.3.10'

4. launcherTemplate.gradle增加apply plugin: 'com.google.gms.google-services',

dependencies增加implementation project(':unityLibrary')

                implementation 'androidx.core:core-ktx:1.3.2'

implementation 'androidx.appcompat:appcompat:1.2.0'

                implementation 'com.google.android.material:material:1.3.0'

                implementation 'androidx.multidex:multidex:2.0.1'    

                implementation 'androidx.legacy:legacy-support-v4:1.0.0'

implementation platform('com.google.firebase:firebase-bom:29.0.1')

                implementation 'com.google.firebase:firebase-analytics-ktx'

                implementation 'com.google.android.gms:play-services-auth:19.2.0'

implementation "com.android.billingclient:billing:4.0.0"

                implementation "com.android.billingclient:billing-ktx:4.0.0"

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2'

                implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"

  1. android段增加

viewBinding {

        enabled = true

    }

 buildFeatures {

        dataBinding = true

        viewBinding = true

}

6.文件末尾加上task copyJsonFile {

    copy {        

        from('../../../Assets/Plugins/Android/')

        into('./')

        include(‘google-services.json’)

    }

}

preBuild.dependsOn copyJsonFile

7.AndroidManifest.xml所有android:debuggable="false",且增加

<activity android:name="com.ycy.googleplugin.MainActivity" android:label="googleplugin">

增加支付权限:

<uses-permission android:name="com.android.vending.BILLING" />

<uses-permission android:name="com.farsitel.bazaar.permission.PAY_THROUGH_BAZAAR" />

8.proguard-user.txt增加-keep classmembers class com.ycy.googleplugin.MainActivity {public*;}

9.添加googleplugin.aar文件到Assets\Plugins\Android(aar文件在谷歌支付登录相关插件。-Unity3D文档类资源-CSDN下载

10.检查一下工程中是否含有字节跳动、巨量引擎等第三方收集玩家手机隐私信息的sdk,被谷歌后台检测到没有及时处理应用会被下架处理,处理之后得等审核之后才能继续更新测试轨道的应用

10.2021版本的In App Purchasing插件打包的时候可能跟引用的两个库

implementation "com.android.billingclient:billing:4.0.0"和

implementation "com.android.billingclient:billing-ktx:4.0.0"冲突,打包的时候请注意移除这个插件

三.客户端代码

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ycynet.AccountSDK;

public abstract class SDKGoogle
{
    public class LoginResult
    {
        public int success = -1;//-1进行中0失败1成功
        public string err_msg = "";
        public string id = "";
        public string token = "";

        public override string ToString()
        {
            return "success==" + success.ToString() + "err_msg:  " + err_msg + "id:  " + id + "  token: " + token;
        }
    }

    public abstract void Init(string serverClientId);
    public abstract void Login();
    public abstract LoginResult GetLoginResult();
    public abstract string PayForOrder(string accountId, string serverOrderId, string productId);

    [Serializable]
    public class SDKGoogle_Consumes
    {        
        public List<string> lst;
    }
    [Serializable]
    public class SDKGoogle_ConsumeReq
    {
        public long tm;
        public string tokenAccOrders;
    }

    /// <summary>
    /// 消费通知,要在全局存在对象中有相应方法,如SDKMgr中定义相同方法
    /// </summary>
    /// <param name="consumeInfo"></param>
    public void OnNotifyGooglePlayBuyConsumeSuccess(string consumeInfo)
    {
        SDKGoogle_Consumes ss = JsonUtility.FromJson<SDKGoogle_Consumes>(string.Format("{ \"lst\" : {0}}", consumeInfo));
        string consumeUrl = "http://ycygamesupport.ycyhero.com/api/payment/PaymentRcvResponse?pp=googleplay";
        SDKGoogle_ConsumeReq _postData = new SDKGoogle_ConsumeReq();
        _postData.tm = TimeUtil.getNowInt();
        _postData.tokenAccOrders = string.Join("|", ss.lst);
        Debug.Log("pay..tm==" + _postData.tm + " tokenOrder==" + _postData.tokenAccOrders);
        HttpConnect.Post(consumeUrl, _postData, OnNotifyGooglePlayBuyConsumeSuccessCb);
    }

    public void OnNotifyGooglePlayBuyConsumeSuccessCb(string data)
    {
        Debug.Log(data);
    }
}

#if UNITY_ANDROID
public class SDKGoogle_AND : SDKGoogle
{
    private static SDKGoogle_AND _instance = null;
    public static SDKGoogle_AND Instance { get { if (_instance == null) _instance = new SDKGoogle_AND(); return _instance; } }

    public AndroidJavaObject ClassObject = new AndroidJavaObject("com.ycy.googleplugin.MainActivity");

    private AndroidJavaObject getApplicationContext()
    {
        using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
        {
            using (AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity"))
            {
                return jo.Call<AndroidJavaObject>("getApplicationContext");
            }
        }
    }
    private AndroidJavaObject getCurrentActivity()
    {
        using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
        {
            return jc.GetStatic<AndroidJavaObject>("currentActivity");
        }
    }

    /// <summary>
    /// 谷歌初始化
    /// </summary>
    /// <param name="serverClientId">googleConsle 后台的客户端ID,类型是web应用</param>
    public override void Init(string serverClientId)
    {
        ClassObject.Call("sdkInit", serverClientId, getCurrentActivity());
    }
    
    public override void Login()
    {
        ClassObject.Call("signIn");
    }

    public override LoginResult GetLoginResult()
    {
        return JsonUtility.FromJson<LoginResult>(ClassObject.Call<string>("getLoginResult"));
    }
    public override string PayForOrder(string accountId, string serverOrderId, string productId)
    {
        return ClassObject.Call<string>("payForOrder",accountId,serverOrderId,productId);
    }
}
#endif


#if UNITY_IOS
public class SDKGoogle_IOS
{
    private static SDKGoogle_IOS _instance = null;
    public static SDKGoogle_IOS Instance { get { if (_instance == null) _instance = new SDKGoogle_IOS(); return _instance; } }

#region DllImport
    [System.Runtime.InteropServices.DllImport("__Internal")]
    private static extern void _internalInitWithAppKeyAndChannel_Tracking(string appKey, string channelId);

    [System.Runtime.InteropServices.DllImport("__Internal")]
    private static extern void _internalSetRegisterWithAccountID_Tracking(string account);

    [System.Runtime.InteropServices.DllImport("__Internal")]
    private static extern void _internalSetLoginWithAccountID_Tracking(string account);

    [System.Runtime.InteropServices.DllImport("__Internal")]
    private static extern void _internalSetRyzf_Tracking(string ryTID, string ryzfType, string hbType, float hbAmount);

    [System.Runtime.InteropServices.DllImport("__Internal")]
    private static extern void _internalSetDD_Tracking(string ryTID, string hbType, float hbAmount);

    [System.Runtime.InteropServices.DllImport("__Internal")]
    private static extern void _internalSetEvent_Tracking(string EventName);

    [System.Runtime.InteropServices.DllImport("__Internal")]
    private static extern void _internalSetTrackViewDuration_Tracking(string viewID, long duration);

    [System.Runtime.InteropServices.DllImport("__Internal")]
    private static extern void _internalSetAdShow_Tracking(string adPlatform, string adid);

    [System.Runtime.InteropServices.DllImport("__Internal")]
    private static extern void _internalSetAdClick_Tracking(string adPlatform, string adid);

    [System.Runtime.InteropServices.DllImport("__Internal")]
    private static extern void _internalSetTrackAppDuration_Tracking(long duration);

    [System.Runtime.InteropServices.DllImport("__Internal")]
    private static extern string _internalGetDeviceId_Tracking();

    [System.Runtime.InteropServices.DllImport("__Internal")]
    private static extern void _internalSetPrintLog_Tracking(bool printLog);
#endregion

    public void init(string appKey, string channelId)
    {
        _internalInitWithAppKeyAndChannel_Tracking(appKey, channelId);
    }

    public void register(string account)
    {
        _internalSetRegisterWithAccountID_Tracking(account);
    }
    public void login(string account)
    {
        _internalSetLoginWithAccountID_Tracking(account);
    }
    public void setryzfStart(string ryTID, string ryzfType, string hbType, float hbAmount) { }
    public void setryzf(string ryTID, string ryzfType, string hbType, float hbAmount)
    {
        _internalSetRyzf_Tracking(ryTID, ryzfType, hbType, hbAmount);
    }
    public void setEvent(string eventName)
    {
        _internalSetEvent_Tracking(eventName);
    }
    public void setTrackAppDuration(long duration)
    {
        _internalSetTrackAppDuration_Tracking(duration);
    }
}
#endif

四.上传到谷歌后台

五.开始测试

  1. 上传后一般需要20分钟之后,手机打开之前的那个测试链接才会更新,如果没有更新,尝试清除谷歌商店的缓存,并重新打开测试链接
  2. 测试的支付的时候一定要注意,最好清除浏览器的缓存和谷歌商店的缓存,并清除所有登录的谷歌账号,安卓机退出谷歌账号是在设置里面,确保本机只有一个谷歌账号,不同的账号可能会出现唤起不了支付的状况(被坑的很惨一个),哪怕你的账号都是可以支付的
  3. 测试的时候注意看应用版本,有时候应用可能没有更新

六.注意事项

1在"APK"页面里,有一个“选择使用网址”,把这个网址给你的测试人员,让你的测试人员用他的google账号点进去,点那个“成为测试人员”(前提是你把他加进了测试人员列表), 只有这样才能测试商品支付。

2保证 versionCode 和版本号与你上传的apk的包的一样。(每次上传的包versioncode必须大于一次上传的包否则谷歌会提示异常)

  1. 保证后台和你传入的购买商品的 id 一致,请确认打包apk的包名以及签名皆一致。
  2. 可能封闭式测试、内部测试同时开启造成测试用户乱序。(测试的时候最好关暂停其中一个轨道)
  3. 检查账号所在地是不是在开启地区/国家范围内(正常情况不需要)
  4. 清空谷歌市场APP缓存和浏览器缓存重新登录(必须确保测试连接登录的账号和googlePlay登录的账号一致否则可能出现支付唤起不了支付界面的情况)
  5. 服务端和客户端都需要vpn

七.支付返回CODE(BillingResponseCode)

// *     int SERVICE_TIMEOUT = -3;//服务超时

// *     int FEATURE_NOT_SUPPORTED = -2;//不支持功能

// *     int SERVICE_DISCONNECTED = -1;//服务单元已断开

// *     int OK = 0;//成功

// *     int USER_CANCELED = 1;//用户按上一步或取消对话框

// *     int SERVICE_UNAVAILABLE = 2;//网络连接断开

// *     int BILLING_UNAVAILABLE = 3;//所请求的类型不支持 Google Play 结算服务 AIDL 版本

// *     int ITEM_UNAVAILABLE = 4;//请求的商品已不再出售。

// *     int DEVELOPER_ERROR = 5;//提供给 API 的参数无效。此错误也可能说明应用未针对结算服务正确签名或设置,或者在其清单中缺少必要的权限。

// *     int ERROR = 6;//API 操作期间出现严重错误

// *     int ITEM_ALREADY_OWNED = 7;//未能购买,因为已经拥有此商品

// *     int ITEM_NOT_OWNED = 8;//未能消费,因为尚未拥有此商品

 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值