ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

unity接入steam支付

2022-05-13 14:01:24  阅读:423  来源: 互联网

标签:string err 接入 json unity appid steam txnInfo


接到策划需求,需要将移动端开发的游戏移植到steam平台。奈何策划水平有点次,信誓旦旦的说什么steam支付是使用dlc支付的,使用什么dlc币(窝里个大草),马的,不懂就别瞎咧咧,净给老子挖坑。
查了一圈资料,在steam后台配置若干steam相关dlc相关,就是没有相关与dlc相关支付接口,这时候才意识到公司策划真不靠谱,还老是逼逼开发,搞得一肚子气,马上就摔键盘走人,但是这才是给我挖的第一个坑。
踩了坑之后发现,dlc配置完成之后,是在steam商店里面起作用的,不是在游戏商店起作用,和游戏内购完全没有关系,steam里面的内购又叫做小额支付,相关文档在这里
在接入小额支付时候,需要一个关键参数key,文档解释key是Steamworks Web API 发行商验证密钥。对的,你没猜错,这是他们给我挖的第二个坑。当时注明要发行商密钥,可是偏偏他们给的还是用户密钥,接口调试不通,让他们确认的时候,还是一口咬定给我的是发行商密钥,mmp想打人。
好的,抱怨完了,接下来我们开始接入sdk,steam的文档很怪,明明都是中文可就是看不懂,网上翻了一遍又一遍资料终于给摸索出来了。

服务端接入

下面是相关服务器接入相关代码(go开发的,大家可进行相关参考,感觉坑的是请求Header参数构造以及下订单时参数的构造,这些在steam文档里面是没有的)

const (
	SANDBOX_URL          = "https://partner.steam-api.com/ISteamMicroTxnSandbox/"
	PRODUCT_URL          = "https://partner.steam-api.com/ISteamMicroTxn/"
	KEY                  = "--------------------MY KEY----------------------"      //这里替换成自己的发行商密钥
)

type userInfoResp struct {
	Response respInfo `json:"response"`
}
type userInfoParams struct {
	State    string `json:"state"`
	Country  string `json:"country"`
	Currency string `json:"currency"`
	Status   string `json:"status"`
}
type respInfo struct {
	Result string         `json:"result"`
	Params userInfoParams `json:"params"`
}

type steamOrderInfo struct {
	Response steamOrderResponse `json:"response"`
}
type steamOrderParams struct {
	Orderid string `json:"orderid"`
	Transid string `json:"transid"`
}
type steamOrderResponse struct {
	Result   string           `json:"result"`
	Params   steamOrderParams `json:"params"`
	ErrorObj ErrorObj         `json:"error"`
}

type ErrorObj struct {
	ErrorCode string `json:"errorcode"`
	ErrorDesc string `json:"errordesc"`
}

func getUrl(isSandbox bool) string {
	if isSandbox {
		return SANDBOX_URL
	} else {
		return PRODUCT_URL
	}
}

func steamPostReq(httpUrl string, data io.Reader) (*http.Response, error) {
	req, err := http.NewRequest("POST", httpUrl, data)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Accept-Language", "en_US")
	client := &http.Client{}
	resp, err := client.Do(req)
	return resp, err
}

// 获取用户所需的相关国家地区等信息
func GetUserInfo(write http.ResponseWriter, request *http.Request) {
	body := utils.GetRequestMap(request, "getUserInfo")
	appid := body["appid"].(string)
	steamid := body["steamid"].(string)
	isSandbox := body["isSandbox"].(bool)
	log.Info("Steam UserInfo Body %v", body)
	userInfo := getSteamUserInfo(appid, steamid, isSandbox)
	log.Info("Steam UserInfo UserInfo %v", userInfo)
	utils.ResultSuccess(write, userInfo)
}

func getSteamUserInfo(appid, steamid string, isSandbox bool) *userInfoParams {
	url := getUrl(isSandbox) + "GetUserInfo/v2/?key=%s&appid=%s&steamid=%s"
	url = fmt.Sprintf(url, KEY, appid, steamid)
	client := &http.Client{}
	resp, err := client.Get(url)
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Info("GetUserInfo err:%v", err)
		return nil
	}
	info := new(userInfoResp)
	err = json.Unmarshal(body, &info)
	if err != nil {
		log.Info("Get UserInfo Unmarshal err:", err)
		return nil
	}
	return &info.Response.Params
}

// InitTxn 用户请求下订单
func InitTxn(write http.ResponseWriter, request *http.Request) {
	txnInfo := utils.GetRequestMap(request, "initTxn")
	steamId, _ := txnInfo["steamid"].(string)
	appid, _ := txnInfo["appid"].(string)
	language := txnInfo["language"].(string)
	currency := txnInfo["currency"].(string)
	itemId, _ := txnInfo["itemid"].(string)
	amount, _ := txnInfo["amount"].(string)
	userId, _ := utils.CovToLong(txnInfo["userId"])
	description := txnInfo["description"].(string)
	userIdStr := strconv.FormatInt(userId, 10)
	orderId := userIdStr[len(userIdStr)-6:] + strconv.FormatInt(time.Now().Unix(), 10)
	isSandbox := txnInfo["isSandbox"].(bool)
	httpUrl := getUrl(isSandbox) + "InitTxn/v3/"

	dataStr := fmt.Sprintf(
		"key=%v"+
			"&orderid=%v"+
			"&steamid=%v"+
			"&appid=%v"+
			"&itemcount=%v"+
			"&language=%v"+
			"&currency=%v"+
			"&itemid[0]=%v"+
			"&qty[0]=%v"+
			"&amount[0]=%v"+
			"&description[0]=%v"+
			"&usersession=%v",
		KEY, orderId, steamId, appid, 1, language, currency, itemId, "1", amount, description, "client")
	data := strings.NewReader(dataStr)
	resp, err := steamPostReq(httpUrl, data)
	defer resp.Body.Close()
	content, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Info("Steam Purchase Fail:%v", err.Error())
	}
	steamOrderInfo := new(steamOrderInfo)
	err = json.Unmarshal(content, &steamOrderInfo)
	log.Info("Steam Purchase back:%v", string(content))
	utils.ResultSuccess(write, steamOrderInfo)
}

// FinalizeTxn 验证订单
func FinalizeTxn(write http.ResponseWriter, request *http.Request) {
	txnInfo := utils.GetRequestMap(request, "finalizeTxn")
	isSandbox := txnInfo["isSandbox"].(bool)
	orderid := txnInfo["orderid"].(string)
	appid := txnInfo["appid"].(string)
	httpUrl := getUrl(isSandbox) + "FinalizeTxn/v2/"
	dataStr := fmt.Sprintf("key=%v"+
		"&orderid=%v"+
		"&appid=%v", KEY, orderid, appid)
	data := strings.NewReader(dataStr)
	resp, err := steamPostReq(httpUrl, data)
	defer resp.Body.Close()
	content, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Info("Steam Purchase Confirm back Fail:%v", err.Error())
	}
	log.Info("Steam Purchase Confirm back:%v", string(content))
	steamOrderInfo := new(steamOrderInfo)
	err = json.Unmarshal(content, &steamOrderInfo)
	if err != nil {
		log.Error("Steam Purchase Confirm back response error :%v", err)
		return
	}
        //TODO 执行相关入库操作
        // ...
	utils.ResultSuccess(write, steamOrderInfo)
}

客户端的接入

客户端执行步骤Window>PackageManager>点击+>Add package from git URL,然后填入相关地址Add即可(这个地址可能版本有变动,具体的以文档为准)https://github.com/rlabrecque/Steamworks.NET/releases

在sdk引入项目后,你会发现,在项目的Assets目录的同级目录下,会生成一个steam_appid.txt文件,里面只存了一个appid,这个appid是一个默认值480,当你的app申请下来时,替换成自己的appid即可。需要注意的是项目平台需要切到PC平台,然后下载steam客户端,登录账号,才能正常进入编辑器,此时你打开steam会发现游戏正在运行,那就是指的你的unity编辑器。
开发过程中移动端和pc端会经常切换,而steam提供的宏定义DISABLESTEAMWORKS是关闭steam功能的,这个比较怪,也即是说默认情况下steam平台功能是开启的,再来回切平台时候要注意点。
在客户端点击支付之前,需要访问服务器接口GetUserInfo,获取接下来下订单所需的参数(country: ISO 3166-1-alpha-2 国家代码、currency:价格的 ISO 4217 货币代码。)这个推荐游戏启动时候就调用并存在本地。
接下来就是下订单所需的另外的参数
language

    public string GetCurrentGameLanguage()
    {
        return SteamApps.GetCurrentGameLanguage();
    }

通过C#调用,但是返回过来的不是文档上要求的 ISO 639-1 语言代码。为此续写一个转换方法,然后将转换之后的数值传递给服务器即可。

local languages = {
    ["arabic"] = "ar",
    ["bulgarian"] = "bg",
    ["schinese"] = "zh-CN",
    ["tchinese"] = "zh-TW",
    ["czech"] = "cs",
    ["danish"] = "da",
    ["dutch"] = "nl",
    ["english"] = "en",
    ["finnish"] = "fi",
    ["french"] = "fr",
    ["german"] = "de",
    ["greek"] = "el",
    ["hungarian"] = "hu",
    ["italian"] = "it",
    ["japanese"] = "ja",
    ["koreana"] = "ko",
    ["norwegian"] = "no",
    ["polish"] = "pl",
    ["portuguese"] = "pt",
    ["brazilian"] = "pt-BR",
    ["romanian"] = "ro",
    ["russian"] = "ru",
    ["spanish"] = "es",
    ["latam"] = "es-419",
    ["swedish"] = "sv",
    ["thai"] = "th",
    ["turkish"] = "tr",
    ["ukrainian"] = "uk",
    ["vietnamese"] = "vn",
}

function SteamUtil.GetWebAPI(key)
    return languages[key]
end

和其他的支付不同(如谷歌支付,苹果支付),其他的支付平台能够提供在不同地区商品的价格以及货币符号类型,在steam平台需要自己获取到地区然后根据自己的配置,将价格传递给服务器。
好的,现在如果你准备好了各种参数,然后打包,上传至steam,再在steam平台下载游戏,如果一切正常的话,调用服务器的下订单接口,成功的话会出来一个steam支付弹窗,如下:(打码主要是怕公司策划看到,毕竟程序的地位最低,测试都能给我们骂哭)

如果此时关闭支付弹窗,或者点击支付完成,在C#端会收到一个回调(首先回调要正确加入)

    private Action<uint, ulong> OnPurchaseCallback;
    private void OnEnable()
    {
        m_MicroTxnAuthorizationResponse =
            Steamworks.Callback<MicroTxnAuthorizationResponse_t>.Create(OnMicroTxnAuthorizationResponse);
    }

    private void OnMicroTxnAuthorizationResponse(MicroTxnAuthorizationResponse_t pCallback)
    {
        Debug.Log("[" + MicroTxnAuthorizationResponse_t.k_iCallback + " - MicroTxnAuthorizationResponse] - " +
                  pCallback.m_unAppID + " -- " + pCallback.m_ulOrderID + " -- " + pCallback.m_bAuthorized);

        OnPurchaseCallback?.Invoke(pCallback.m_unAppID, pCallback.m_ulOrderID);
    }

然后在回调中调用服务器的支付验证接口,验证正常的话就下发奖励。
至此,steam支付接入完成,再次咒骂一下垃圾策划!!!

标签:string,err,接入,json,unity,appid,steam,txnInfo
来源: https://www.cnblogs.com/Yellow0-0River/p/16266459.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有