Appearance
接入新渠道
IMPORTANT
当我们需要在U8SDK中接入一个新渠道SDK时,我们心里应该牢记一点:接入过程和游戏工程没有半点关系。也就是说,游戏开发和SDK接入是完全解耦的。
所以,接入的时候,不要想着游戏中怎样怎样,严格按照下面的步骤进行接入,然后使用Demo母包进行测试即可。
预备知识
对于一个联运渠道SDK来说, 总体上我们需要接入他们登录、登出、切换账号、数据上报、实名查询认证、支付、退出游戏等接口。 在U8SDK框架中,我们将这些接口抽象成了两类API:用户API和支付API。
其中用户API包括:登录、登出、切换账号、数据上报、实名查询、实名认证、退出游戏;支付API包括:支付。 如果渠道SDK没有提供对应的API,则无须实现对用的API。
在U8SDK框架中,这两类API分别对应com.u8.sdk.IUser接口和com.u8.sdk.IPay接口。 在接入渠道SDK的时候, 基本的逻辑就是实现这两个接口中的API。
我们可以看下IUser.java中的API:
java
public interface IUser extends IPlugin{
public static final int PLUGIN_TYPE = Constants.PLUGIN_TYPE_USER;
/***
* 登录
*/
public void login();
/**
* 部分渠道可能有特殊的需求
* 比如MSDK,有微信登录和QQ登录。游戏可能需要在游戏中
* 增加微信和QQ登录按钮,然后通过customData来选择
* 调用的是微信还是QQ
* @param customData
*/
public void loginCustom(String customData);
/***
* 切换帐号
*/
public void switchLogin();
/***
* 显示帐号中心
*/
public boolean showAccountCenter();
/***
* 登出
*/
public void logout();
/***
* 发送扩展数据
* @param extraData
*/
public void submitExtraData(UserExtraData extraData);
/***
* SDK的退出方法
*/
public void exit();
/***
* 上传礼包兑换码
*
*/
public void postGiftCode(String code);
/***
* 实名注册方法
*/
public void realNameRegister();
/***
* 防沉迷系统查询接口
*/
public void queryAntiAddiction();
/**
* 查询商品信息,比如需要调用渠道那边接口,去查询商品,并显示在游戏界面上
*/
public void queryProducts();
}
我们再看下IPay.java中的API:
java
public interface IPay extends IPlugin{
public static final int PLUGIN_TYPE = Constants.PLUGIN_TYPE_PAY;
/***
* 调用支付界面
* @param data
*/
public void pay(PayParams data);
}
创建工程
1、创建渠道接入工程
U8SDK_Projects是一个的Android Studio工程,里面有U8SDK3、U8SDKDemo、U8SDKRelease以及各个渠道SDK和插件SDK的接入子工程。 接入新渠道的时候,我们需要在这个目录下,创建一个子工程。
我们在U8SDK_Projects目录下提供了一个python辅助脚本——create_proj.py,使用该辅助脚本,我们可以快速创建一个渠道接入子工程。
在U8SDK_Projects目录下,启动命令行,执行如下命令:
bash
python create_proj.py -t AAA -p AAA -s 2
-t : 指定渠道子工程的名称,比如你想创建一个U8SDK_AAA这样的子工程,那么就指定为AAA
-p : 指定类名前缀,比如生成的子工程中类名是AAASDK.java,AAAUser.java和AAAPay.java,那么就指定为AAA
-s : 是否前后端都生成; 1:前后端都生成;2:只生成客户端部分;3:只生成Server端部分
使用上述命令之后,我们可以看到在U8SDK_Projects目录下生成了一个U8SDK_AAA子工程,这个就是我们即将要编写接入代码的工程。 然后你就可以用AS打开U8SDK_Projects开始接入了。
2、添加依赖
在接入新渠道的时候,我们需要在渠道SDK的接入文档中,将它需要的依赖jar和aar,或者gradle依赖配置添加到我们刚刚创建的接入工程中来。
WARNING
编写接入代码的时候,我们不需要处理渠道SDK接入文档中的资源(res)和assets目录下的文件。这些等我们接入代码编写完成之后,可以一起配置到打包工具中。加入jar、aar或者gradle依赖,只是为了让我们的接入代码可以顺利编译,从而生成u8sdk_aaa.jar。
如果渠道有提供jar包或者aar,那么我们可以直接将这些文件拷贝到U8SDK_AAA/libs目录下;如果渠道有需要的gradle依赖配置,我们需要将gradle依赖配置添加到U8SDK_AAA/build.gradle中。
依赖配置好之后,我们在AS编辑器中gradle视图里,重新同步刷新一下gradle配置,让添加的依赖生效。 然后我们就可以开始代码的编写了。
实现接入逻辑
NOTE:所有渠道SDK需要接入的方法,都大同小异。我们将其归为三大类: 1、初始化: 大部分渠道都有初始化方法,有的需要在Activity的onCreate中调用;有的则需要在Application的onCreate中调用 2、用户相关:包含[登录]、[切换帐号]、[登出]、[个人中心]、[提交玩家数据]、[退出确认框] 3、支付:用户充值(有些渠道提供多种充值方式,我们选择最合适的一种接入即可)
在U8SDK中,我们将所有需要实现的渠道SDK的接口,都封装在一个单例类中。所以,比如这里,我们U8SDK_AAA接入工程,我们定义一个AAASDK这样一个单例类,在这个单例类中,实现所有渠道SDK要求的方法。这些方法包含上面三大类中所有的方法:
java
package com.u8.sdk;
public class AAASDK {
private static AAASDK instance;
private String appID;
private String appKey;
private AAASDK(){
}
public static AAASDK getInstance(){
if(instance == null){
instance = new AAASDK();
}
return instance;
}
public void initSDK(SDKParams params){
this.parseSDKParams(params);
this.initSDK();
}
private void initSDK(){
//TODO::这里调用AAA的SDK初始化方法
}
private void parseSDKParams(SDKParams params){
this.appID = params.getString("AAA_APPID");
this.appKey = params.getString("AAA_APPKEY");
}
public void login(){
//TODO::这里调用AAA的登录方法
}
public void switchLogin(){
//TODO::这里调用AAA切换帐号的方法
//如果没有提供切换帐号的方法,那么切换帐号的逻辑就是[先登出,再登录],也就是先调用logout,再调用login
}
public void logout(){
//TODO::调用AAA的登出方法
}
public void showUserCenter(){
//TODO::调用AAA显示个人中心的方法
//如果AAA没有提供对应的接口,则不用实现该方法
}
public void exit(){
//TODO::调用AAA显示退出确认框接口
//如果AAA没有提供对应的接口,则不用实现该方法
}
public void submitGameData(UserExtraData data){
//TODO::调用AAA上报玩家数据接口
//如果AAA没有提供对应的接口,则不用实现该方法
}
public void pay(PayParams data){
//TODO::调用AAA充值接口
}
}
具体的接入,可以参考U8SDK_Projects目录下已经接好的渠道SDK工程。
触发U8SDK事件
NOTE:接入工程中,在初始化成功,失败;登录成功,失败;切换帐号成功,失败;登出成功,失败;支付成功,失败 等时刻,都需要往抽象层抛出对应的事件,以便抽象层中能够分发这些事件,这样游戏接入工程监听这些事件,就能做对应的逻辑处理。
1、普通事件
所有的错误或者失败时,都可以通过调用U8SDK.getInstance().onResult()方法抛出对应的事件。比如:
初始化成功:U8SDK.getInstance().onResult(U8Code.CODE_INIT_SUCCESS, "init success");
初始化失败:U8SDK.getInstance().onResult(U8Code.CODE_INIT_FAIL, "init failed");
登录失败:U8SDK.getInstance().onResult(U8Code.CODE_LOGIN_FAIL, "login failed.resultCode:"+resultCode);
......
所有事件类型都在U8Code中定义的常量。
一般对于无关紧要的事件,也就是不需要游戏中做特殊处理,或者不需要传递很多参数的事件,我们都采用这种方式。
2、登录成功事件
SDK登录成功时,需要调用U8SDK.getInstance().onLoginResult(String ext)方法,抛出登录成功事件。
SDK登出成功之后,一般会返回一些用户信息和token或者session之类的,用于登录认证的凭据。我们需要将登录认证需要的参数传给U8Server进行二次认证。但是二次认证是统一在抽象层做的。
这里我们直接将登录认证需要的参数,通过ext参数传到抽象层中即可。
如果含有多个参数,可以采用json格式;如果只有一个参数,直接传这个参数即可。或者你也可以采用其他的格式,只要U8Server那边也根据同样的格式进行解析。
3、切换帐号成功事件
SDK切换帐号成功的事件,有可能有两种情况,一个是仅仅登出当前登录用户,弹出登录框;一个是切换帐号并且已经登录了另一个帐号。
对于第一个情况,我们调用U8SDK.getInstance().onSwitchAccount()
游戏中监听对应的事件时,收到onSwitchAccount时,需要返回游戏的登录界面,并显示SDK的登录界面
对于第二个情况,我们调用U8SDK.getInstance().onSwitchAccount(String ext)接口。里面的参数格式和登录成功一致
游戏中监听对应的事件时,收到该事件时,需要返回游戏的登录界面,并直接将用户信息显示一下,无需弹出SDK登录界面
4、登出成功事件
SDK登出成功之后,或者用户在SDK个人中心界面中点击登出时,我们需要抛出一个U8SDK.getInstance().onLogout()事件。
游戏中监听对应的事件时,收到onLogout时,需要返回游戏的登录界面让用户重新登录
5、支付成功
因为网游一般支付都是异步通知到游戏服务器的,SDK返回的支付成功,并不能代表玩家真的拿到游戏币了。所以,客户端SDK返回的支付成功事件,我们一般不需要做特殊的逻辑处理。
所以支付成功,我们依然使用onResult接口,抛出一个支付成功的事件即可。
U8SDK.getInstance().onResult(U8Code.CODE_PAY_SUCCESS, "pay success");
实现IUser接口
NOTE:所有插件的实现类,都必须包含一个构造函数,这个构造函数,必须含有一个Activity类型的参数。
为了实现用户相关的功能,我们需要实现IUser接口,实现IUser中定义的一些接口。根据当前SDK支持的方法,在对应的接口中,调用之前我们定义的单例类中封装的方法。
其中isSupportMethod方法,必须实现。返回当前渠道SDK支持的接口。
同时,如果SDK仅仅要求在Activity的onCreate中初始化SDK,那么直接在IUser的实现类的构造函数中调用初始化方法即可。
java
package com.u8.sdk;
import com.u8.sdk.utils.Arrays;
import android.app.Activity;
public class AAAUser implements IUser {
private String[] supportedMethods = {"login","switchLogin","logout","exit"};
/**
* 必须定义包含一个Activity参数的构造函数,否则实例化的时候,会失败
*
* 一般SDK初始化方法的调用也在这里调用。除非SDK要求要在Application对应的方法调用。
* @param context
*/
public AAAUser(Activity context){
AAASDK.getInstance().initSDK(U8SDK.getInstance().getSDKParams());
}
/**
* 判断当前插件是否支持接口中定义的方法
*/
@Override
public boolean isSupportMethod(String methodName) {
return Arrays.contain(supportedMethods, methodName);
}
/**
* 打开SDK登录界面
*/
@Override
public void login() {
AAASDK.getInstance().login();
}
/**
* 这个方法暂时弃用
*/
@Override
public void loginCustom(String customData) {
}
@Override
public void switchLogin() {
AAASDK.getInstance().switchLogin();
}
@Override
public boolean showAccountCenter() {
return false;
}
@Override
public void logout() {
AAASDK.getInstance().logout();
}
@Override
public void submitExtraData(UserExtraData extraData) {
}
@Override
public void exit() {
AAASDK.getInstance().exit();
}
@Override
public void realNameRegister() {
}
@Override
public void queryAntiAddiction() {
}
}
实现IPay接口
NOTE:所有插件的实现类,都必须包含一个构造函数,这个构造函数,必须含有一个Activity类型的参数。
为了实现支付的功能,我们需要实现IPay接口,实现IPay中定义的接口。根据当前SDK支持的方法,在对应的接口中,调用之前我们定义的单例类中封装的方法。
其中isSupportMethod方法,直接返回true即可。因为该插件只有一个pay方法。
java
package com.u8.sdk;
import android.app.Activity;
public class AAAPay implements IPay {
public AAAPay(Activity context){
}
@Override
public boolean isSupportMethod(String methodName) {
return true;
}
/**
* 打开SDK支付界面
*/
@Override
public void pay(PayParams data) {
AAASDK.getInstance().pay(data);
}
}
配置config.xml
NOTE:每个渠道SDK,都需要一个config.xml配置文件,配置当前渠道SDK的参数信息,插件信息,版本信息等。供打包工具解析使用。config.xml的格式固定
xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
<params>
<param name="AAA_APPID" required="1" showName="AppID" desc="渠道SDK分配的appID" bWriteInManifest="0" bWriteInClient="1" />
<param name="AAA_APPKEY" required="1" showName="AppKey" desc="渠道SDK分配的appKey" bWriteInManifest="0" bWriteInClient="1" />
<param name="AAA_TEST" required="1" showName="测试" desc="测试写入Manifest.xml" bWriteInManifest="1" bWriteInClient="0" />
<param name="AAA_TEST2" required="0" value="1" showName="测试2" desc="测试直接填写value" bWriteInManifest="1" bWriteInClient="0" />
</params>
<operations>
<operation step="1" type="mergeManifest" from="SDKManifest.xml" to="AndroidManifest.xml" />
<operation step="2" type="copyRes" from="assets" to="assets" />
<operation step="3" type="copyRes" from="libs" to="lib" />
<operation step="4" type="copyRes" from="res" to="res" />
<operation step="5" type="copyRes" from="root" to="" />
</operations>
<plugins>
<plugin name="com.u8.sdk.BaiduUser" type="1" desc="用户登录接口"/>
<plugin name="com.u8.sdk.BaiduPay" type="2" desc="用户支付接口"/>
</plugins>
<extraR>
<package name="com.pps.dynamicload.library" />
</extraR>
<dependencies>
<dependency name="com.android.support:appcompat-v7:25.3.1" />
</dependencies>
<version>
<versionCode>1</versionCode>
<versionName>3.3.1</versionName>
</version>
</config>
可以看到这个配置文件中,总共分为四块内容:
1、params
NOTE:这个配置是为了兼容U8SDK老的命令行打包工具,如果你使用的是打包后台或者桌面版打包客户端,那么params里面留空就可以,然后在后台添加参数Meta即可。
params中定义了我们需要配置的参数的key,以及参数的一些属性。
1) name:当前参数的key,这个key建议以渠道SDK为前缀,可以避免冲突。
2) required:当前参数是否需要在游戏的渠道配置文件中配置。required="1":需要配置;required="0":不需要配置。注意为0的时候,那么value必须在这里填写。
3) showName:显示的名称(无实际用处)
4) desc:该参数的说明(无实际用处)
5) bWriteInManifest:该参数是否写到AndroidManifest.xml的meta-data中。bWriteInManifest="1":写入;bWriteInManifest="0":不写入
6)bWriteInClient:该参数是否写到assets目录下的developer_config.properties文件中。bWriteInClient="1":写入;bWriteInClient="0":不写入
比如之前,我们在AAASDK的parseSDKParams中解析了两个参数[AAA_APPID]和[AAA_APPKEY]。其对应的配置就在这里。
注意,除了required="0"的参数的value直接配置在这里,说明这个参数的值每个游戏都一样,无需各个游戏都去配置。required="1"的话,这里不用配置value。value是在每个游戏的配置目录下的config.xml中对应该渠道的sdk-params中进行配置的。因为每个游戏的value都不一样。
有些渠道SDK,要求参数在meta-data中,key固定的。那么需要将参数配置在这里,key就是渠道要求的key。同时bWriteInManifest="1"即可。
2、operations
operations中定义了当前打包工具需要处理的操作。
1) step: 操作步骤
2) type:操作类型。[mergeManifest]:合并manifest.xml;[copyRes]:拷贝资源目录;
3) from:从这个文件或者目录进行合并或者拷贝
4) to: 合并到或者拷贝到这个文件或者目录
3、plugins
plugins中配置了当前该渠道对应的插件的实现类,也就是我们刚刚实现IUser和IPay两个接口的类
1) name:插件实现类的全类名。注意:必须包含包名的全路径
2) type:对应的插件类型。[1]:用户插件;[2]:支付插件;[3]:推送插件;[4]:分享插件;[5]:分析统计插件;
3) desc:描述(无实际用处)
4、extraR(可选)
extraR中定义了其他需要生成R.java的包名, 某些渠道SDK中直接使用R引用的情况下,我们可能需要该配置。
1) package: 配置需要生成R.java的包名。 如果有多个,可以添加多个pacakge配置。
5、dependencies(可选)
dependencies中配置gradle依赖,如果渠道SDK中有依赖的gradle配置,我们可以在这里添加,这样打包工具在打包的时候,会自动处理gradle依赖并完成合并操作。
1)dependency: 配置一条gradle依赖。如果有多个依赖配置,可以添加多个配置。
6、version
version中配置了当前渠道SDK的版本信息
1) versionCode:自定义的值,需要用到渠道SDK更新机制之后,每次可以增加1
2) versionName: 当前渠道SDK的真实版本
配置SDKManifest.xml
NOTE:每个渠道SDK,都需要一个SDKManifest.xml配置文件,在这里配置渠道SDK需要的Activity,Service,Reciever,Provider等组件,以及配置渠道SDK需要的权限信息
xml
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<permissionConfig>
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
</permissionConfig>
<applicationConfig keyword="com.aaa.login.LoginActivity"
proxyApplication="com.u8.sdk.AAAProxyApplication">
<!-- 这里一定不要把渠道SDK的Demo中用到的Activity等拷贝进来了 -->
<activity
android:name="com.aaa.login.LoginActivity"
android:configChanges="orientation|navigation|screenSize|keyboard|keyboardHidden"
android:exported="false"
android:excludeFromRecents="true"
android:theme="@style/bdp_dialog_style_fullscreen"/>
<!-- other activity,service,provider,reciever... -->
</applicationConfig>
</manifest>
可以看到这个配置中,只有两大块内容:
1、permissionConfig
permissionConfig中配置渠道SDK需要的权限等信息,这些权限信息最终会被合并到最终的AndroidManifest.xml中。注意这里的权限不要重复了。
2、applicationConfig
applicationConfig中配置渠道SDK中所有配置在application节点中的组件。比如Activity,Serivice,Reciever,Provider等。
1) 这个节点有两个属性。keyword一般直接填写为applicationConfig中第一个组件的name即可。proxyApplication则是U8SDK中处理渠道SDK需要Application继承或者调用对应方法时的解决方案。
关于U8SDK中Application的解决方案可以看这里:[适配Application](http://www.uustory.com/?p=1434)
2) 有些渠道SDK在提供的AndroidManifest.xml中,有一些meta-data,这些meta-data中配置了当前渠道的参数信息。如果这个参数每个游戏都不同,那么需要将这些参数删除,并配置到上面的config.xml的params中,key就是这里meta-data对应的name。同时将bWriteInManifest设置为"1"
3) 一般我们拷贝渠道SDK需要的AndroidManifest.xml中的权限和组件,都是去他们提供的Demo工程的AndroidManifest.xml中拷贝。在拷贝的时候,注意不要将Demo自己定义的Activity等组件拷贝过来了。记得认真过滤一下
渠道SDK接入成功之后,我们Alt+F12快捷键,打开命令行,输入gradlew :U8SDK_AAA:generateJar 编译该子工程。 编译成功之后,会在U8SDK_AAA/build/lib目录下生成一个u8sdk_aaa.jar。
经过上面的步骤,我们这个AAA渠道SDK的接入工作就结束了。
接下来,我们需要将该渠道配置到打包工具中,让我们的母包可以打出该渠道SDK的渠道包,请看下一篇文档渠道SDK在打包工具中的配置