解决游戏接入渠道SDK的繁琐工作。做到一次接入,通过打包工具生成不同的渠道安装包。
SDK接入框架
闪屏接入
定义一个Activity继承TSplashActivity
public class TestSplashActivity extends TSplashActivity {
@Override
protected void onCreate(Bundle savedInstance) {
//设置SDK的横竖屏
setLandScape(true);
super.onCreate(savedInstance);
}
public int getBackgroundColor() {
//当闪屏PNG图片无法铺满部分机型的屏幕时,设置与闪屏颜色配合的背景色会给用户更好的体验
return Color.WHITE;
}
@Override
public void onSplashStop() {
//闪屏结束后,启动游戏的Activity
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
this.finish();
}
}
AndroidManifest.xml 配置修改
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait" >
接入函数调用
方法 | 描述 |
---|---|
login | TSDK的登陆入口 |
logout | TSDK的登陆注销 |
pay | TSDK的支付入口 |
quit | 游戏退出调用 |
submitExtendData | 上传扩展数据 |
onResume | SDK生命周期函数,在activity的onResume 中调用 |
onPause | SDK生命周期函数,在activity的onPause中调用 |
onDestroy | SDK生命周期函数,在activity的onPause中调用 |
TSDK入口类为TSDKUserCenter,主要函数如下:
方法 | 描述 |
---|---|
login | TSDK的登陆入口 |
logout | TSDK的登陆注销 |
pay | TSDK的支付入口 |
quit | 游戏退出调用 |
submitExtendData | 上传扩展数据 |
onResume | SDK生命周期函数,在activity的onResume 中调用 |
onPause | SDK生命周期函数,在activity的onPause中调用 |
onDestroy | SDK生命周期函数,在activity的onPause中调用 |
函数介绍
-
登录介绍
调用TSDK的login登录,会调起相对应的SDK登录流程public static void login(Context context, GameParams params, ILoginCallback callback)
用于登录融合SDK。登录成功或取消登录ILoginCallback 均能监听到。
| 参数 | 描述 |能否为空|
| :------ | :------------------------------------------| -- |
| context | 当前Activity的context | 否 |
| params | 用于传递游戏登录的参数 | 否 |
| callback | 监听登录成功或取消登录的回调 | 否 |
| GameParams 属性| 描述 |
| :------ | :------------------------------------------ |
| frm | 来源 |
| fdata | 来源描述 |
LoginResponse 包含下列字段
public int code; //登陆状态CODE_SUCCESS = 1; CODE_FAIL = -1;
public String msg; //code=CODE_FAIL ,是msg会有相关的内容
public String uid; // 我方给出的不冲突用户id
public String channel; //渠道标识,用来区分用户来自哪个渠道
public String access_token;//令牌
public String c_uid; //渠道返回的uid,TSDK内部使用,请勿使用,一般情况为空;
public int adult; //成年-1未成年, 0未知, 1成年
-
注销登录介绍
调起融合SDK的logout注销,会调起相应的SDK注销流程public static void logout(Context context, GameParams params,ILogoutCallback callback)
用于注销登录。参数 描述 能否为空 context 当前Activity的context 否 params 用于传递游戏注销登录的参数 否 callback 监听注销登录的回调 否 GameParams 属性 描述 暂无
LogoutResponse 包含下列字段
public int code; //登出状态CODE_SUCCESS = 1; CODE_FAIL = -1;
public String msg; //code=CODE_FAIL ,是msg会有相关的内容
-
支付接口介绍
调起融合SDK的pay支付,会调起相应的SDK支付流程public static void pay(Context context, GameParams params, IPayCallback callback)
用于支付的方法。参数 描述 能否为空 context 当前Activity的context 否 params 用于传递游戏支付的参数 否 callback 监听支付的回调 否 GameParams 属性 描述 uid 用户id access_token 令牌 productId 商品id productName 商品名 price 金额(元) serverId 服务器id roleId 角色id roleName 角色名 roleLevel 角色等级 gold 游戏币,如钻石 extension 扩展字段 PayResponse 包含下列字段
public int code; //支付返回状态CODE_SUCCESS = 1; CODE_FAIL = -1; public String msg; //code=CODE_FAIL ,是msg会有相关的内容
-
游戏退出
调起融合SDK的quit退出,会调起相应的SDK退出流程public static void quit(Context context, GameParams params, IQuitCallback callback)
用于调起SDK的退出框的方法。参数 描述 能否为空 context 当前Activity的context 否 params 用于传游戏退出的参数 否 callback 监听退出的回调 否 GameParams 属性 描述 暂无 回调说明
//渠道带有退出框 @Override public void quitCallback(QuitResponse quitResponse) { Toast.makeText(this, "退出回调", Toast.LENGTH_SHORT).show(); if (quitResponse != null) { LogUtils.d(quitResponse.toString()); } finish(); } //渠道不带退出框 @Override public void onNo3rdQuitCallback(QuitResponse quitResponse) { quitDialog(); } private void quitDialog() { AlertDialog.Builder builder = new Builder(this); builder.setMessage("确定要退出吗?"); builder.setTitle("提示"); builder.setPositiveButton("确认", new android.content.DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); finish(); } }); builder.setNegativeButton("取消", new android.content.DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.create().show(); }
QuitResponse 包含下列字段
public int code; //支付返回状态CODE_SUCCESS = 1; CODE_FAIL = -1; public String msg; //code=CODE_FAIL ,是msg会有相关的内容
-
上传扩展数据
调起融合SDK的上传扩展数据接口,请在用户选择角色以及服务器后调用,否则无法正常支付public static void submitExtendData(Context context, GameParams params)
参数 描述 能否为空 context 当前Activity的context 否 params 用于传扩展字段 否 GameParams 属性 描述 score 分数 topnid 可选参数,排行榜标识,使用该参数需要确认对应ID的排行榜已经开通 roleId 角色id roleName 角色名 roleLevel 角色等级 zoneId 当前登录的游戏区服ID,必须为数字,且不能为0,若无,传入1 zoneName 当前登录的游戏区服名称,不能为空,不能为null,若无,传入游戏名称+”1区”,如”刀塔传奇1区” balance balance 当前用户游戏币余额,必须为数字,若无,传入0 vip vip 当前用户VIP等级,必须为数字,若无,传入1 partyName partyName 当前用户所属帮派,不能为空,不能为null,若无,传入”无帮派 上传数据接口需在三处调用,分别为进入服务器、玩家创建用户角色、玩家升级,有如下二点需注意:
a)若游戏中无对应接口功能,如游戏中无需创建角色,则可根据自身情况在合适位置进行调用,如登录成功后;
b)在上传游戏数据时,若存在无对应字段值的情况,可传入默认值,具体参见数据组成部分; -
生命周期函数调用
public static void onResume(Context context) public static void onPause(Context context) public static void onDestroy(Context context) SDK的生命周期函数,在程序的主Activity的生命周期相应函数中调用
抽象工厂
定义一个抽象工厂,规范需要实现的接入函数
public interface IChannel {
public void init(Context context, boolean isLandScape, IChannelInitCallback callback);
public void login(GameParams params);
public void pay(GameParams params);
public void logout(GameParams params);
public void quit(GameParams params);
public void onResume(Context context);
public void onPause(Context context);
public void onStop(Context context);
public void onDestroy(Context context);
public void submitExtendData(Context context, GameParams params);
}
调用对应的工厂实例
根据配置在 manifest 文件中的 CHANNEL_KEY 调用对应的工厂实例
public class DispatchChannel {
private static IChannel channel;
private static final String CHANNEL_KEY = "CHANNEL_KEY";
public static IChannel getChannel(Context context){
if(channel == null) {
ChannelFactory cf = new ChannelFactory();
String channelString = ChannelUtil.getChannel(context, SDKTools.getMetaData(context, CHANNEL_KEY));
channel = cf.createChannel(channelString);
}
return channel;
}
}
各渠道接入实现
AndroidManifest.xml中配置要调用的渠道以及对应渠道设置的代理Application
定义一个具体的渠道类实现 抽象工厂接口
public class Channel360 extends BaseChannel implements IChannel
调用渠道登陆成功后和服务端做一次用户绑定,返回用户信息
支付前请求一次服务端的支付参数信息,再调起渠道SDK支付
打包工具
1. 解母包(copy 到对应的工作目录)
apktool d -f -o $game_path $game_path${apk_suffix}
2. 资源处理
2.1 准备对应渠道的资源文件
assets(copy 到对应的工作目录)
t_splash_images //闪屏文件夹,不存在或为空则没有配闪屏
... //渠道此文件夹下的资源
libs (copy 到对应的工作目录 lib 下)
... //渠道的非 .jar 文件
res (copy 到对应的工作目录)
...
如碰到 strings.xml, styles.xml, colors.xml, dimens.xml, ids.xml, attrs.xml ... 则合并其内容
带有对应渠道角标的 ic_launcher 对应的文件夹
classes.dex (具体接入渠道的 .dex 文件) 后面会用到
具体命令如下
cp -R -f $game_path/* $channel_name/
cp -R -f $config_name/AndroidManifest.xml $channel_name/
cp -R -f $config_name/assets/* $channel_name/assets/
cp -R -f $config_name/libs/* $channel_name/lib/
cp -R -f $config_name/res/* $channel_name/res/
# 合并strings.xml ...
$tool/xml -f $game_path/res/values/ -s $channel_name/res/values/ -t $config_name/res/values/
if [ -d "$config_name/channel_icon" ];then
# 合成icon
$tool/icon -f $channel_name/res/drawable-ldpi/$icon_name.png -s $channel_name/res/drawable-ldpi/$icon_name.png -t $config_name/channel_icon/ldpi.png -x 0 -y 0
$tool/icon -f $channel_name/res/drawable-mdpi/$icon_name.png -s $channel_name/res/drawable-mdpi/$icon_name.png -t $config_name/channel_icon/mdpi.png -x 0 -y 0
$tool/icon -f $channel_name/res/drawable-hdpi/$icon_name.png -s $channel_name/res/drawable-hdpi/$icon_name.png -t $config_name/channel_icon/hdpi.png -x 0 -y 0
$tool/icon -f $channel_name/res/drawable-xhdpi/$icon_name.png -s $channel_name/res/drawable-xhdpi/$icon_name.png -t $config_name/channel_icon/xhdpi.png -x 0 -y 0
$tool/icon -f $channel_name/res/drawable-xxhdpi/$icon_name.png -s $channel_name/res/drawable-xxhdpi/$icon_name.png -t $config_name/channel_icon/xxhdpi.png -x 0 -y 0
$tool/icon -f $channel_name/res/drawable-xxxhdpi/$icon_name.png -s $channel_name/res/drawable-xxxhdpi/$icon_name.png -t $config_name/channel_icon/xxxhdpi.png -x 0 -y 0
fi
3. 处理 AndroidManifest.xml文件, 并覆盖到对应的工作目录
3.1 渠道权限添加
3.2 包名修改
3.3 activity name属性为全路径
3.4 渠道 activity 等内容合并
3.5 渠道参数在 meta-data
3.6自有的参数 meta-data
3.7具体对应的 CHANNEL_KEY meta-data
3.8 具体对应的 T_APPLICATION_PROXY_NAME meta-data
4. 生成 R.java 文件
4.1 建一个gen文件夹
mkdir -p $channel_name/gen
4.2 执行 aapt p ... 命令
aapt p -f -m -J $channel_name/gen -S $channel_name/res -I $tool/android.jar -M $channel_name/AndroidManifest.xml
5. 将 R.java 编译成对应的 .class 文件
javac -encoding UTF-8 $channel_name/gen/${package}${package_suffixs[$index]}/R.java
6. 将生成的 .class 文件生成 .dex 文件
$tool/dx --no-strict --dex --output=$channel_name/Rclasses.dex $channel_name/gen/$package/${package_suffixs[$index]}
7. 将生成的 .dex 文件 编译成 smali格式的文件合并到 (1)中复制的对应工作目录下的 smali 文件夹
java -jar $tool/baksmali.jar $channel_name/Rclasses.dex -o $channel_name/smali/
8. 将 (2)中准备好的 classes.dex 编译成 smali 格式的文件合并到 (1)中复制的对应工作目录下的 smali 文件夹
java -jar $tool/baksmali.jar $config_name/classes.dex -o $channel_name/smali/
9. 使用 apktool b ... 命令打包
apktool b -b ${channel_name}/
10. 使用 jarsinger 签名
jarsigner -keystore $tool/${keystore} -storepass ${keypass} -signedjar ${channel_name}/dist/${game_name}_signed.apk ${channel_name}/dist/${game_name}.apk "${keyalias}"
11. zipalign 命令进行 4 字节对齐优化产生最终的 apk 文件
$tool/zipalign -f 4 ${channel_name}/dist/${game_name}_signed.apk $dir/apk/${game_name}/${channel}.apk