Unity 接入IAP(上)Android篇
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity 接入IAP(上)Android篇相关的知识,希望对你有一定的参考价值。
参考技术A 很多项目都会遇到内购和订阅相关模块,这里我总结一下内购接入的时候遇到的各种坑,以及内购测试的时候,有什么比较好的方法测试。本篇先介绍android篇。打开Unity编辑器,找到Servic,启用IAP 服务。(启动后也会默认打开数据分析服务)
IAP设置页面,需要设置app适用年龄,根据自己产品自行选择年龄是否13+,然后需要去注意有个Options选项,需要填入一个Google Public Key,这个Key在Google后台,关联产品后就有了,会自动填写上。
接下来就是IAP文档的内容了,建议去官网看文档,这里我把基本框架写出来。
参考: https://docs.unity3d.com/cn/current/Manual/UnityIAP.html
首先创建一个IAPManager
初始化IAP,并且创建好所有内购产品(提前在后台生成ProduceID)
创建IAPItem时候,传入产品ID和产品类型要与后台一致。
初始化成功:
初始化失败:
购买产品,传入对应产品ID:
购买成功:
购买失败:
这几个方法,一定打好log,这里就是核心的几个内购方法,另外当接入google结算库时候,要引入Google.Play.Billing时候,编辑器可能报错找不到。
在Player Settings -> Other Settings 添加宏定义:
教你高速高效接入SDK——Unity统一接入渠道SDK(Android篇)
U8SDK的设计之初,就是为了可以支持各种游戏引擎开发的游戏,而不不过Android的原生平台。眼下一大半的手游,都是採用Unity3D和Cocos2dx开发,那么这里,我们就先来一步步给大家演示,用Unity开发的游戏,怎样通过U8SDK来高速地完毕多家渠道SDK的接入。
Unity研发的手游,仅仅须要调用U8SDK抽象层就可以完毕多家渠道SDK的接入。而不须要在Unity中耦合各个渠道SDK,保证游戏层逻辑层的简单,以及SDK部分的绝对重用。
以下,我们看看,在Unity中调用U8SDK主要须要完毕的工作:
1、建立一个Androidproject,作为U8SDK和Unity平台通信的中间协调project
2、定义一致的通信数据类型,我们这里採用JSON格式
3、在Unity中,通过C#完毕一套统一的SDK调用接口。给逻辑层调用。同一时候多个平台(Android,IOS,PC等)的接口全然同样。
这一篇。我们就先来完毕第一步和第二步。
1,新建一个Androidproject,将IsLibrary设置为true。将该project作为库project,这样当你编译的时候,会在bin文件夹下产生一个jar包。而不是一个apk
2,设置依赖project为U8SDK2抽象层project,同一时候将Unity3D提供的Android的jar包,拷贝到该project的libs文件夹下
3、然后建立两个类,一个为U8UnityContext ,这个类继承UnityPlayerActivity 。也是游戏的启动Activity。
4、还有一个是IU8SDKListener 的实现类,主要实现一些SDK的回调方法
我们先来看看这两个类的实现。之后再来解释一些关键的东西:
public class U8UnityContext extends UnityPlayerActivity{ public final static String CALLBACK_GAMEOBJECT_NAME = "(u8sdk_callback)"; //unity中接收回调通知的GameObject的名称 public final static String CALLBACK_INIT = "OnInitSuc"; //SDK初始化成功的回调方法名称和Unity中一致 public final static String CALLBACK_LOGIN = "OnLoginSuc"; //SDK登录成功的回调方法名称和Unity中一致 public final static String CALLBACK_SWITCH_LOGIN = "OnSwitchLogin"; //SDK切换帐号的回调方法名称和Unity中一致 public final static String CALLBACK_LOGOUT = "OnLogout"; //SDK登出的回调方法名称和Unity中一致 public final static String CALLBACK_PAY = "OnPaySuc"; //SDK支付成功回调方法名称和Unity中一致 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initSDK(); } //U8SDK 初始化 public void initSDK(){ U8SDK.getInstance().setSDKListener(new UnityU8SDKListener(this)); U8SDK.getInstance().init(this); U8SDK.getInstance().onCreate(); } //登录接口 public void login(){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().login(); } }); } //自己定义登录接口 public void loginCustom(final String customData){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().login(customData); } }); } //切换帐号接口 public void switchLogin(){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().switchLogin(); } }); } //显示用户中心接口 public void showAccountCenter(){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().showAccountCenter(); } }); } //登出 public void logout(){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().logout(); } }); } //提交扩展数据 public void submitExtraData(String data){ final UserExtraData extraData = parseGameData(data); U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().submitExtraData(extraData); } }); } //SDK退出接口 public void exit(){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().exit(); } }); } //支付接口 public void pay(String data){ final PayParams params = parsePayParams(data); U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8Pay.getInstance().pay(params); } }); } //SDK是否支持退出确认功能 public boolean isSupportExit(){ return U8User.getInstance().isSupport("exit"); } //SDK是否支持用户中心 public boolean isSupportAccountCenter(){ return U8User.getInstance().isSupport("showAccountCenter"); } //SDK是否支持登出 public boolean isSupportLogout(){ return U8User.getInstance().isSupport("logout"); } //向Unity中发送消息 public void sendCallback(String name, String jsonParams){ if(jsonParams == null){ jsonParams = ""; } UnityPlayer.UnitySendMessage(CALLBACK_GAMEOBJECT_NAME, name, jsonParams); } private UserExtraData parseGameData(String str){ UserExtraData data = new UserExtraData(); try { JSONObject json = new JSONObject(str); data.setDataType(json.getInt("dataType")); data.setRoleID(json.getString("roleID")); data.setRoleName(json.getString("roleName")); data.setRoleLevel(json.getString("roleLevel")); data.setServerID(json.getInt("serverID")); data.setServerName(json.getString("serverName")); data.setMoneyNum(json.getInt("moneyNum")); } catch (JSONException e) { e.printStackTrace(); } return data; } private PayParams parsePayParams(String str){ PayParams params = new PayParams(); try{ JSONObject json = new JSONObject(str); params.setProductId(json.getString("productId")); params.setProductName(json.getString("productName")); params.setProductDesc(json.getString("productDesc")); params.setPrice(json.getInt("price")); params.setRatio(0);//该字段废弃不用 params.setBuyNum(json.getInt("buyNum")); params.setCoinNum(json.getInt("coinNum")); params.setServerId(json.getString("serverId")); params.setServerName(json.getString("serverName")); params.setRoleId(json.getString("roleId")); params.setRoleName(json.getString("roleName")); params.setRoleLevel(json.getInt("roleLevel")); params.setPayNotifyUrl("");//该字段废弃不用 params.setVip(json.getString("vip")); params.setOrderID(json.getString("orderID")); params.setExtension(json.getString("extension")); }catch(Exception e){ e.printStackTrace(); } return params; } public void onActivityResult(int requestCode, int resultCode, Intent data){ U8SDK.getInstance().onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data); } public void onStart(){ U8SDK.getInstance().onStart(); super.onStart(); } public void onPause(){ U8SDK.getInstance().onPause(); super.onPause(); } public void onResume(){ U8SDK.getInstance().onResume(); super.onResume(); } public void onNewIntent(Intent newIntent){ U8SDK.getInstance().onNewIntent(newIntent); super.onNewIntent(newIntent); } public void onStop(){ U8SDK.getInstance().onStop(); super.onStop(); } public void onDestroy(){ U8SDK.getInstance().onDestroy(); super.onDestroy(); } public void onRestart(){ U8SDK.getInstance().onRestart(); super.onRestart(); } }
public class UnityU8SDKListener implements IU8SDKListener{ private U8UnityContext context; private boolean isSwitchAccount = false; //当前是否为切换帐号 public UnityU8SDKListener(U8UnityContext context){ this.context = context; } @Override public void onResult(final int code, String msg) { // TODO Auto-generated method stub U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { switch(code){ case U8Code.CODE_INIT_SUCCESS: context.sendCallback(U8UnityContext.CALLBACK_INIT, null); break; case U8Code.CODE_INIT_FAIL: Toast.makeText(context, "SDK初始化失败", Toast.LENGTH_SHORT).show(); break; case U8Code.CODE_LOGIN_FAIL: //这里不须要提示。一般SDK有提示 //Toast.makeText(context, "SDK登录失败", Toast.LENGTH_SHORT).show(); break; case U8Code.CODE_PAY_FAIL: Toast.makeText(context, "支付失败", Toast.LENGTH_SHORT).show(); break; case U8Code.CODE_PAY_SUCCESS: Toast.makeText(context, "支付成功,到账时间可能稍有延迟", Toast.LENGTH_SHORT).show(); break; } } }); } //此接口已经废弃 @Override public void onInitResult(InitResult result) { // TODO Auto-generated method stub // 此接口已经废弃 } //SDK登录成功的回调 @Override public void onLoginResult(String data) { Log.d("U8SDK", "SDK 登录成功,不用做处理,在onAuthResult中处理登录成功, 參数例如以下:"); Log.d("U8SDK", data); this.isSwitchAccount = false; tip("SDK登录成功"); } //切换帐号。须要回到登录界面,并弹出SDK登录界面 @Override public void onSwitchAccount() { context.sendCallback(U8UnityContext.CALLBACK_SWITCH_LOGIN, null); } //切换帐号,并登录成功。到这里和Login的回调onLoginResult一样 @Override public void onSwitchAccount(String data) { Log.d("U8SDK", "SDK 切换帐号并登录成功,不用做处理。在onAuthResult中处理登录成功, 參数例如以下:"); Log.d("U8SDK", data); this.isSwitchAccount = true; tip("切换帐号成功"); } //登出,须要回到登录界面,并弹出SDK登录界面 @Override public void onLogout() { context.sendCallback(U8UnityContext.CALLBACK_LOGOUT, null); } //SDK登录成功之后。去U8Server进行登录认证 @Override public void onAuthResult(UToken authResult) { if(!authResult.isSuc()){ tip("SDK登录认证失败,确认U8Server是否配置"); return; } JSONObject json = new JSONObject(); try{ json.put("isSuc", authResult.isSuc()); json.put("isSwitchAccount", isSwitchAccount); if(authResult.isSuc()){ json.put("userID", authResult.getUserID()); json.put("sdkUserID", authResult.getSdkUserID()); json.put("username", authResult.getUsername()); json.put("sdkUsername", authResult.getSdkUsername()); json.put("token", authResult.getToken()); } }catch(Exception e){ e.printStackTrace(); } context.sendCallback(U8UnityContext.CALLBACK_LOGIN, json.toString()); } //对于手机网游,不须要实现这个接口,由于网游支付是通过server回调通知加虚拟币的。 //这个接口主要用于单机游戏。作为单机的支付结果回调接口 @Override public void onPayResult(PayResult result) { //TODO } private void tip(final String tip){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { Toast.makeText(context, tip, Toast.LENGTH_SHORT).show(); } }); } }
在U8UnityContext 中,我们定义了一系列的接口。这些接口就是给Unity中调用的。
比方Login,switchLogin,logout等。而这些方法本身不过对U8SDK抽象层提供的方法进行了一个简单的包裹。通过,U8SDK.getInstance().runOnMainThread()来让全部的接口都在UI主线程中完毕。
关于U8SDK的初始化,有两部分。第一部分是U8SDK本身的初始化,包含參数的读取和解析等,这个须要将AndroidManifest.xml中application接口的android:name设置为”com.u8.sdk.U8Application”。注意,这里一定要设置,否则U8SDK无法初始化。假设,游戏有自己的某些业务须要在Application中完毕,能够通过实现U8SDK提供的IApplicationListener接口来完毕。
第二部分须要在Activity的onCreate中完毕(依据游戏不同,也能够在Unity中合适的地方调用初始化接口),包含,设置U8SDK的回调监听,初始化载入插件,以及调用onCreate回调。表现为下面三步:
U8SDK. getInstance().setSDKListener (new UnityU8SDKListener(this));
U8SDK. getInstance().init(this);
U8SDK. getInstance().onCreate();
UnityU8SDKListener 是U8SDK的回调简体接口的实现类。全部SDK相关的回调都是通过这些接口完毕的。
onLoginResult: SDK登录成功的回调
onSwitchAccount: SDK中切换帐号的回调
onLogout: SDK登出的回调
onAuthResult: U8Server登录验证的回调
onResult: 全部SDK操作成功或者失败的状态回调
当我们收到部分回调的时候,我们须要通知到Unity中,包含之前。我们写的那些接口,比方Pay和submitExtraData都是含有參数的。
这里就来解决Unity和Android中通信的数据结构问题。尽管Unity和Android通信也能够使用复杂的结构,可是我还是推荐採用简单统一的数据协议比較好。这里我们选择JSON。简单高效。仅仅要保证。两边数据的key一致就能够了。
Unity调用Android的接口,比方Pay和submitExtraData都通过一个JSON字符串传递过来,然后这边解析一下。
对于Android中须要通知Unity中的也是一样,使用JSON格式的字符串,然后通过
UnityPlayer.UnitySendMessage(gameObject, methodName, jsonParams)接口来完毕通信。
好了,完毕这个,Android中的部分,就完毕了。再提醒一次,不要忘记配置AndroidManifest.xml哦,这里附上AndroidManifest.xml文件:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.u8.sdk" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="21" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" android:name="com.u8.sdk.U8Application"> <activity android:name="com.u8.sdk.U8UnityContext" android:label="@string/app_name" android:screenOrientation="landscape" android:launchMode="singleTask" android:configChanges="orientation|keyboardHidden|screenSize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
接下来。我们就须要在Unity中来完毕接下来的工作,能够看訪问这里查看:Unity手游接入渠道SDK(Unity篇)
以上是关于Unity 接入IAP(上)Android篇的主要内容,如果未能解决你的问题,请参考以下文章
Unity IAP接入google支付文档(2022年最新)
Unity实战篇 | unity接入QQ登录 详细过程——Android篇
Unity实战篇 | unity接入QQ登录 详细过程——Android篇
教你高速高效接入SDK——Unity统一接入渠道SDK(Android篇)