Skip to content

Android 接入文档

接入说明

  • Android SDK Demo 下载
  • (必须适配 android 11系统版本,否则会影响渠道上架)
  • 推荐使用Unity 导出 Android Studio 项目出包方式
  • 如游戏首次接入,要做好 Android 手机全面屏适配(常见适配方式一般都是默认全屏展示,顶部刘海或摄像头相关不能影响到游戏相关 UI 功能,否则云测时会影响评级)
  • 确保所有调用SDK的接口都放在()调用
  • Unity 中调用到 java 中的接口注意需要切换到 UI 线程再调用 SDK 的接口
  • 请务必详细查看文档,如有对某些接入部分存在疑问可直接在对接群与技术沟通
  • 本文档会不定期更新,如涉及接口变动会在群内同步消息,更多更新内容请查看FastSdk更新日志
  • 注意在AndroidManifest.xml中的application标签下增加以下配置:android:resizeableActivity="false"

Maven 仓库配置

project:build.gradle

xml
buildscript {
    repositories {
        maven {
            url 'https://sdk.wdyxgames.com/nexus/repository/sdk-public/'
        }
    }
}

allprojects {
    repositories {
        maven {
            url 'https://sdk.wdyxgames.com/nexus/repository/sdk-public/'
        }
    }
}

app:build.gradle

xml
dependencies {
    implementation 'com.hoolai.access.open:hoolai-core:1.0.6.0'
}

app:AndroidManifest.xml特殊处理

注意

由于使用打包工具会动态替换apk中的包名,请按照以下规则在接入时对AndroidManifest.xml中的配置进行修改替换,否则会出现无法将渠道包同时安装到一台设备或异常闪退等

xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.hoolai.access.channel.impl">

    <!-- 示例 -->
    <uses-permission android:name="android.permission.INTERNET" />
    
    <!-- application中有以下三个新增配置,必加(游戏无自定义 Application 时android:name需要配置 HLApplication)-->
    <application
        android:name="com.hoolai.access.open.fastaccess.HLApplication"
        android:allowBackup="false"
        android:extractNativeLibs="true"
        android:resizeableActivity="false"
        android:requestLegacyExternalStorage="true"
        android:usesCleartextTraffic="true">
     
        <meta-data 
            android:name="android.max_aspect" 
            android:value="2.5"
            android:allowBackup="false"
            android:requestLegacyExternalStorage="true"/>
        <activity
            android:name="游戏的主Activity"
            android:configChanges="screenLayout|orientation|keyboardHidden|keyboard|fontScale|layoutDirection|density|smallestScreenSize|screenSize|uiMode|navigation|touchscreen|locale|mnc|mcc"
            android:launchMode="standard">
            ...
            <!-- copy以下内容到游戏的启动类中,必接 -->
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="hlscheme" android:host="hlhost"/>
            </intent-filter>
            <!-- 懂球帝分享配置(选接) -->
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <!--game可自定义,与请求参数保持一致即可 -->
                <data android:scheme="game" />
            </intent-filter>
            
        </activity>

        <!-- MAIN_ACTIVITY标签的value=游戏的入口类Activity全路径,否则应用宝渠道登录失败 -->
        <!-- 该标签必须加 -->
        <meta-data
            android:name="MAIN_ACTIVITY"
            android:value="游戏的主Activity,如com.demo.GameActivity"/>
      
        <!-- 注意!!!! ${applicationId}需要替换成hlApplicationId --> 
        <!-- 以下为示例 无需copy -->
        <!-- TODO 原配置 -->
        <provider
            android:name="xx.FileProvider"
            android:authorities="${applicationId}.Fileprovider"
            ... /> 
        <!-- TODO 修改后 -->
        <provider
            android:name="xx.FileProvider"
            android:authorities="hlApplicationId.Fileprovider"
            ... /> 
        <!-- 以上为示例 无需copy -->
    </application>

</manifest>

注意

如集成过三方SDK,AndroidManifest文件中包含${applicationId}的配置会被自动替换成当前APK包的包名,会导致出渠道包时无法再被替换,需要研发人员出包后进行自检

自检流程

1.在Android Studio中打开apk包,找到AndroidManifest.xml文件里的package标签,该标签对应的值即该apk的包名。

2.在此文件中搜索该包名,将所有包含此包名的配置(package="包名"配置除外)复制到工程的AndroidManifest文件中,并全部替换成hlApplicationId,重新打包即可。

3.确保游戏Activity的启动模式设置为 android:launchMode="standard"。

接口文档

Application接入(),注意该配置在 AndroidManifest.xml中需要声明

  • 方式一:游戏无自定义Application时使用HLApplication
  • 方式二:游戏有自定义Application且继承HLApplication.class时无需处理
  • 方式三:游戏有自定义Application且未继承HLApplication.class时需要进行以下调用
  • 以上三种配置完成后,请检查AndroidManifest.xml中<application android:name="xxxx.xxxx.XXXApplication"是否配置,此处必须配置
java
public class YourApplication extends YourBaseApplication {

    @Override
    public void onCreate() {
        super.onCreate();
        FastSdk.onApplicationCreate(this);
    }

    @Override
    public void onTerminate() {
        super.onTerminate();
        FastSdk.onTerminate(this);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        FastSdk.onConfigurationChanged(this, newConfig);
    }

    @Override
    protected void attachBaseContext(Context context) {
        super.attachBaseContext(context);
        FastSdk.attachBaseContext(this, context);
    }
}

SDK功能接入

初始化()

注意

  • SDK初始化期间,解决游戏黑屏的建议:准备一张名为"unity_static_splash"的图片,拷贝至res/drawable目录即可
  • 游戏启动后首先调用此接口,后才能进行热更/版本检测/游戏初始化/登录等功能调用
  • 在未收到初始化回调或收到onInitFailed时,游戏不可进行后续功能调用
  • 初始化失败时建议引导用户重新初始化或重启游戏
java
//游戏启动类(非闪屏类)onCreate 生命周期事件中
//SDK初始化回调
FastSdk.hlSystemListener = new HLSystemListener() {
    @Override
    public void onInitSuccess(InitResult initResult) {
        //初始化成功,回调参数InitResult:gameId,channelId,channel
        //gameId 产品 id,登录验证时会需要该值
        //channelId 产品下不同渠道的 id 值
        //channel 渠道值,如 xiaomi,huawei 等
    }

    @Override
    public void onInitFailed(String reason) {
       //建议做弹框提示,可增加重启按钮或退出程序按钮
    }

    @Override
    public void onCustomExit() {
        //游戏自定义退出界面 ,实现退出逻辑,否则会出现渠道审核不通过情况
        //demo只是示例,请勿直接照搬demo
        new AlertDialog.Builder(GameActivity.this)
                .setTitle("游戏退出弹窗")
                .setMessage("我是游戏的弹窗界面哦")
                .setNegativeButton("取消", null)
                .setPositiveButton("确定", (dialog, which) -> onExitSuccess(s))
                .setCancelable(false).show();
    }

    @Override
    public void onExitSuccess(String result) {
        //建议游戏按照下面代码逻辑,退出程序兼容性最好
        //否则可能会造成oppop、vivo等渠道退出不彻底,导致再次点击启动应用黑屏
        moveTaskToBack(true);
        finish();
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intent);
        android.os.Process.killProcess(android.os.Process.myPid());
    }

    @Override
    public void onUpdate(String data) {
        //版本升级(接口预留)
    }
};
//SDK账号回调
FastSdk.hlAccountListener = new HLAccountListener() {
    @Override
    public void onRefreshUser(LoginResult result) {
         //小号切换,此回调中之需要游戏验证用户合法性问题,无小号可忽略
         //如果游戏不支持内部切换玩家信息,游戏需要先登出,再登录(不需要重新初始化)
    }

    @Override
    public void onLoginSuccess(LoginResult result) {
        //登录成功
    }

    @Override
    public void onLoginFailed(String reason) {
        //登录失败
    }

    @Override
    public void onLogout(Object... var1) {
       //登出
    }
};
//SDK支付回调
FastSdk.hlPaymentListener = new HLPaymentListener() {
    @Override
    public void onPaySuccess(String result) {
        //支付成功,仅表示回调状态ok,以 server 端通知发货为准
        //注意 result 可能为空字符串
    }

    @Override
    public void onPayFailed(String reason) {
        //支付失败,注意 reason 可能为空字符串
    }
    
    
    @Override
    public void onQuerySuccess(List<GoodsInfo> list) {
        //海外游戏用到,获取商品列表用于展示
    }
};
//SDK分享回调(注意某些三方分享是收不到回调的,比如微信分享)
FastSdk.hlShareListener = new HLShareListener() {
    @Override
    public void onShareSuccess() {
        //分享成功
    }

    @Override
    public void onShareFailed(String reason) {
        //分享失败
    }
};


//注意:调用onCreate之前需要将以上用到的接口先进行实例化
FastSdk.onCreate(this);

InitResult

参数名类型描述
gameIdint产品id
channelString渠道名称
channelIdint渠道id

LoginResult

参数名类型描述
uidlong用户id
accessTokenString令牌
nickNameString昵称
channelUidString渠道用户id
channelString渠道名称
serverAreaString扩展参数

GoodsInfo

参数名类型描述
itemIdString商品id
itemNameString商品名称
itemCountString商品数量
itemPriceString商品金额
showTagString国内可忽略
currencyString货币类型

登录()

注意

  • 调用此方法时确保已经执行“game_init_result”事件报送,更多具体内容请查阅 游戏自定义报送
  • 初始化未收到回调或初始化失败时禁止调用登录接口
java
FastSdk.login();

数据上报()

注意(支付之前必须先进行基础数据上报)

  • 上报事件类型(EventType)分为四种:创角、进服、升级、自定义
  • 创角、进服、升级事件上报时,roleId、roleName、serverId、serverName参数不能为空且必传,否则影响支付功能!!其他必接数据请查看
java
//eventType取值:
//创角: EventType.CreateRole
//进服: EventType.EnterServer
//升级: EventType.LevelUp
//前三种是必须上报,下面这种根据运营需求进行自定义事件上报
//自定义点:EventType.CustomerEvent
//设置自定义点位后必须设置setExtendAction("xx"),setPhylum("xx")等

PlayerInfo playerInfo = new PlayerInfo();
playerInfo.setRoleId("32424");//角色唯一标识id,必传
playerInfo.setRoleName("昵称");//必传,String
playerInfo.setRoleLevel("6");//必传,注意字符串必须是数字,比如"123"
playerInfo.setZoneId("1");//必传,没有可传默认值"1",注意字符串中的值必须为数字
playerInfo.setZoneName("华东大区");//必传,没有可传默认值,比如"1区"等
playerInfo.setServerId("1");//必传,没有可传默认值"1",注意字符串中的值必须为数字
playerInfo.setServerName("区名称");//必传,没有可传默认值,比如"1区"等
playerInfo.setBalance("66");//必传,获取不到时传""
playerInfo.setVip("5");//必传
playerInfo.setPartyname("帮派名称");//非必传
        
//扩展信息,支持String、int、double三种数据类型
playerInfo.addExtra("aaa", "test");
playerInfo.addExtra("bbc", 100);
playerInfo.addExtra("ccc", 1.2);
playerInfo.setClassField("");//事件结果,可不填
//playerInfo.setPhylum("");//扩展数据报送时需要按照提供的事件编号填写,如:1
//playerInfo.setExtendAction("点位名称"); //基础打点不传,自定义打点传
FastSdk.report(EventType.EnterServer, PlayerInfo playerInfo);

注意

  • 需要接入CLS网络探测功能的同学注意!!!点击查看规则详情
  • 该功能请在SDK初始化之后尽早报送,可以单独报送,也可以跟着其他点位一起上报
  • 探测地址可以是域名或IP
  • 探测地址中的冒号用@替换,避免格式错误
  • 探测地址的key必须使用以下三个字段:gameResourceUrl,gameLoginServerUrl,gameServerUrl

如:playerInfo.setExtra("key:value,gameResourceUrl:http@xxx/open/init, gameServerUrl:tcp@111.222.333.6@8888");

EventType

参数名描述是否必填
EventType.CreateRole创建角色
EventType.EnterServer游戏进服
EventType.LevelUp角色升级
EventType.CustomerEvent自定义

PlayerInfo

参数名类型描述是否必填
roleIdString角色id
roleNameString角色名称
roleLevelString等级
zoneIdString大区id,没有大区传serverId值
zoneNameString大区名称,没有大区传serverName值
serverIdString服务器id
serverNameString服务器名称
balanceString余额
vipStringvip等级
partyNameString公会名称
appVersionString应用版本号
appResVersionString游戏资源版本号
extendActionString事件名称
roleCreateTimeString角色创建时间
phylumString事件id,参考“客户端数据上报”文档
classFieldString事件结果,ok/fail
extraString扩展信息(注意:cls报点用到该字段)

登出

java
FastSdk.logout();

支付(),报送进服或创角之后调用,否则无法拉起支付

java
PayParams payParams = new PayParams();
payParams.setItemId("item60");//商品ID,非必传
payParams.setItemName("60钻石");//商品名称,非必传
payParams.setAmount(100);//商品金额,必传,单位:分
payParams.setNotifyUrl("");//支付回调地址
//扩展信息,回调时原样返回,因为各渠道回调参数限制不一致。
//回调参数暂时只支持长度255。callBackInfo中不要使用这些符号:“|”、“=”、“+”、“/”。
payParams.setCallbackInfo("支付扩展信息,游戏透传参数");
payParams.setCurrency("CNY");//国内可不传或CNY
FastSdk.pay(payParams);

注意:防抖处理建议

  • SDK已做防抖处理,3秒内仅触发首次支付。
  • 建议客户端在触发购买事件时弹出遮罩层,防止玩家重复点击。收到支付回调后关闭遮罩,若未收到回调,则设置超时时间,超时后自动关闭遮罩。
  • 缓存支付数据并在支付完成后进行 Check 是不必要的。若快速点击不同档位,可能实际支付第一笔却缓存第二笔,导致支付成功但 Check 不通过。支付成功弹框应以 SDK 回调为准。

PayParams

参数名类型描述是否必填
itemIdString商品id
itemNameString商品名称
amountint金额,单位:分
countint数量,默认填1
callbackInfoString透传字段
notifyUrlString支付回调地址
currencyString货币类型,默认:CNY
optMap<String, String>扩展参数

退出程序

java
FastSdk.exit();

获取商品列表信息

java
//注意:国内游戏可不接入此方法
FastSdk.queryGoodsInfo();

生命周期方法()

java
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    FastSdk.onSaveInstanceState(outState);
}

@Override
protected void onStart() {
    super.onStart();
    FastSdk.onStart(this);
}

@Override
protected void onResume() {
    super.onResume();
    FastSdk.onResume(this);
}

@Override
protected void onStop() {
    super.onStop();
    FastSdk.onStop(this);
}

@Override
protected void onPause() {
    super.onPause();
    FastSdk.onPause(this);
}

@Override
protected void onRestart() {
    super.onRestart();
    FastSdk.onRestart(this);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    FastSdk.onDestroy(this);
}

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    FastSdk.onNewIntent(intent);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    FastSdk.onActivityResult(this, requestCode, resultCode, data);
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    FastSdk.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    FastSdk.onConfigurationChanged(this, newConfig, getResources());
}

@Override
public void onBackPressed() {
    FastSdk.exit();
}

@Override
public Resources getResources() {
    return FastSdk.getResources(super.getResources());
}
//以下为更新内容
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    FastSdk.onRestoreInstanceState(savedInstanceState);
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    FastSdk.onWindowFocusChanged(hasFocus);
}

分享

java
ShareParams params = new ShareParams();
params.setTitle("标题");
params.setContent("内容");
params.setPicPath("picPath");//本地或网络图片链接
//分享链接(懂球帝固定为:dongqiudi://share/circle/)
params.setShareUrl("http://xx.com");

//微信图片
params.setBmp(bmp); 

FastSdk.share(ShareType.WX, ShareType.ChildType.WX_CHAT, params);

ShareType

参数名类型描述
QQShareTypeQQ分享
WXShareType微信分享
DQDShareType懂球帝分享
FACEBOOKShareTypeFacebook分享
SYSTEMShareType系统分享

ShareType.ChildType

参数名类型描述
WX_CHATShareType.ChildType微信聊天
WX_CIRCLEShareType.ChildType微信朋友圈
WX_FAVORITESShareType.ChildType微信收藏
QQ_TEXT_AND_QQZONEShareType.ChildType分享文字且同步到到QQ空间
QQ_IMG_AND_QQZONEShareType.ChildType分享图片且同步到到QQ空间
QQ_TEXTShareType.ChildType分享文字
QQ_IMGShareType.ChildType分享图片
DQDShareType.ChildType懂球帝
FACEBOOK_LINKShareType.ChildTypefacebook链接
FACEBOOK_IMGShareType.ChildTypefacebook图片
FACEBOOK_VIDEOShareType.ChildTypefacebook视频
SYSTEM_TEXTShareType.ChildType系统分享文字链接
SYSTEM_IMGShareType.ChildType系统分享图片
SYSTEM_FILEShareType.ChildType系统分享文件

ShareParams

参数名类型描述是否必填
idString懂球帝id,仅懂球帝
wxTypeint1:聊天,2:朋友圈,3:收藏
qqTypeint1:默认,2:纯图
showQQZoneboolean是否展示到QQ空间
titleString标题
contentString内容
picPathString图片url
shareUrlString分享链接
callbackUrlString懂球帝回调url,仅懂球帝
bmpBitmap微信图片,仅微信图片分享

权限申请()

注意

政策要求敏感权限申请时被拒绝后不能申请多次,所以SDK限制申请次数为一次。用户申请权限时,可设置是否显示提示框(默认false),当为true且再次调用时会弹出提示框引导用户进行手动授权。一般拒绝该权限会影响业务功能时显示此弹框。

java
//单个危险权限申请,返回申请结果 
boolean hasPermission = FastSdk.checkPermission(Activity activity, 
    String permission, boolean showRefuseDialog);
//activity:当前页上下文
//permission:权限名称
//showRefuseDialog:是否显示弹框,默认true,非必传!
boolean hasPermission = FastSdk.checkPermission(activity, 
    Manifest.permission.WRITE_EXTERNAL_STORAGE, true);
if(hasPermission){
    //your code
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    FastSdk.onRequestPermissionsResult(requestCode, permissions, grantResults);
    //权限申请结果回调,查看是否被授予
    if (requestCode == Math.abs(Manifest.permission.WRITE_EXTERNAL_STORAGE.hashCode())){
        if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
            Logger.i("权限已被允许");
            //your code
        }else{
            Logger.i("权限已被拒绝");
        }
    }
}

方舟报送(已废弃)

java
String action = "game_xxx";
Map<String, Object> hashMap = new HashMap<>();
hashMap.put("xxx", 123);
hashMap.put("ooo", "321");
FastSdk.gameDataReport(action, hashMap);

方舟参数

参数名类型描述是否必填
actionString事件名称
hashMapMap<String, Object>事件内容

CD-KEY(选接,礼包码兑换)

java
AccessActivityDataInfo info = new AccessActivityDataInfo();
info.setCode("兑换码");
FastSdk.accessParticipate(AccessActivityType.CD_KEY, info);

CD-KEY参数

参数名类型描述是否必填
typeAccessActivityType活动类型
infoAccessActivityDataInfo兑换码对象

Q&A

初始化失败,出现“非正版应用”提示,如何处理?

签名文件不正确,如果没有签名文件可联系运营同学。

账密登录时没有账号?

账密登录方式没有注册功能,需要运营同学提供账号/密码。

如何测试沙箱环境支付?

和运营同学确认,确保已开启沙箱环境,并确保账号已加入测试白名单。

无法拉起支付?

检查进入游戏时是否报送创角或进服事件。

支付成功不到账?

1.检查提供的支付回调url是否正确。

2.检查支付接口,在支付参数中是否调用了setNotifyUrl(url),如果调用了则会优先回调此url。

渠道包中从游戏内登出时悬浮球不隐藏

游戏未调用Fastsdk.logout(),建议游戏“设置”界面做两个按钮:“切换服务器”、“切换账号”。在点击“切换账号”时调用Fastsdk.logout(),点击“切换服务器”时无需登出直接回到选服界面即可。

Hoolai Access SDK