# GHOME SDK 开发手册 for Android

# 1. 前言

本文用于指导游戏开发商接入SDK,文中包含客户端的接入说明,以及服务器接口的介绍;

如您使用的SDK版本较旧(低于9.0),需要有额外的对照比较,可以从 这里 得到旧版本的接入说明。 (注意:该版本SDK已不符合当前国家隐私规范,建议升级)

# 2. SDK接入流程概述

  • 搭建SDK开发环境

  • 完成隐私政策展示逻辑(请务必在完成隐私的展示逻辑之后再进行调用初始化 以及游戏自身敏感权限申请(申请请务必避开初始化接口调用)等操作)(游戏使用sdk隐私政策弹框请接接口4; 游戏自己实现隐私政策弹框请接接口5接口6

  • 初始化SDK

  • 初始化成功,调用账号功能相关接口

  • 用户在进行购买时,调用支付功能相关接口

  • 其他功能接口,可根据业务需要适时调用

  • 接入第三方渠道的个性化功能时,可调用SDK扩展接口实现

  • 销毁SDK

  • 游戏在启动游戏时需对设备网络进行判断,若无网络的情况下,游戏需实现对用户的弹框提示。

  • GHome sdk中已占用的申请系统权限的code: 157, 159, 161, 165, 169( 游戏请勿使用这些code进行权限申请,以免冲突)

    更新需要注意点:

    sdk 9.8.0.2 需要删除如下在线依赖库配置(自动化打包优化需要,如下两个库已改成本地aar方式 引入):

        implementation 'com.alipay.sdk:alipaysdk-android:x.x.x'
        implementation 'com.tencent.mm.opensdk:wechat-sdk-android:x.x.x'
    
    1
    2
    1. sdk 9.8.0.1版本开始 Android Manifest 需要新增拷贝如下配置,新增的配置如下:

      <!-- 别名声明  begin-->
              <activity-alias
                  android:name="${applicationId}.wxapi.WXPayEntryActivity"
                  android:exported="true"
                  android:targetActivity="com.ghome.sdk.common.GHomeWXPayActivity">
              </activity-alias>
      
              <activity-alias
                  android:name="${applicationId}.wxapi.WXEntryActivity"
                  android:exported="true"
                  android:targetActivity="com.ghome.sdk.common.GHomeWXEntryActivity">
              </activity-alias>
      
              <activity-alias
                  android:name="${applicationId}.dyapi.DYEntryActivity"
                  android:exported="true"
                  android:targetActivity="com.ghome.sdk.common.DaoYuHandlerActivity"/>
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
    2. 删除对应的之前这三个Activity的声明以及对应手动新建的类(包名下 wxapi 以及 dyapi文件目录),已有的三个配置声明

      <activity
                  android:name="${applicationId}.dyapi.DYEntryActivity"
                  android:configChanges="keyboardHidden|orientation|screenSize"
                  android:exported="true"
                  android:launchMode="singleTask"
                  android:theme="@android:style/Theme.Translucent.NoTitleBar" />
      
              <!-- 微信登录 start-->
              <activity
                  android:name="${applicationId}.wxapi.WXEntryActivity"
                  android:exported="true"
                  android:label="@string/app_name"
                  android:launchMode="singleTask"
                  android:taskAffinity="com.ghome.sdk.demo"
                  android:theme="@android:style/Theme.Translucent.NoTitleBar" >
              </activity>
              <!-- 微信登录 end-->
      
              <activity
                  android:name="${applicationId}.wxapi.WXPayEntryActivity"
                  android:configChanges="keyboardHidden|orientation|screenSize"
                  android:exported="true"
                  android:launchMode="singleTop"
                  android:screenOrientation="portrait"/>
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24

# 隐私流程介绍

APP启动代码流程参考

含隐私相关建议,非常重要

流程 功能 备注
1 app启动
2 游戏初始化A a. 因国家隐私政策,建议如无必须可以后置执行,如果需要执行则不能包含用户信息获取逻辑
b. 游戏框架(例如:Untiy框架等)自身也可能导致隐私信息获取,游戏需要重点关注。【非常重要】
3 隐私接口

(游戏实现,或者使用 ghome sdk)
a. 使用 ghome sdk 隐私接口,会自行处理需要显示,但如果游戏使用则每次启动都需要调用
4 同意隐私

(用户点击隐私同意后,并产生回调)
a. 如果第3点使用ghome sdk模式,并ghome sdk当前判断不需要再次显示隐私条款,则会直接回调,即用户点过同意
5 游戏初始化B

(可含用户信息获取等)
a. 强烈建议游戏更多的初始化代码放在隐私条款同意之后执行,以免引起隐私相关的拒审
b. 如无特殊需求,游戏也可以省略初始化A,只保留初始化B模式,更不容易因隐私问题引起拒审
6 登录初始化

# 隐私模式说明(Ghome SDK 有关的函数使用顺序)

模式 1 :使用 Ghome SDK UI 显示隐私框
    游戏APP启动 
    -> 游戏初始化1(建议省去) 
    -> doPrivacyAgreement 
    -> 游戏初始化2 
    -> initialize 
    -> login

模式 2 :使用 Ghome SDK API 返回隐私 URL 后,游戏 APP UI 显示
    游戏APP启动 
    -> 游戏初始化1(建议省去) 
    -> getAgreementStatus 
    -> onUserAgreement(当用户点击同意后调用) 
    -> 游戏初始化2 
    -> initialize 
    -> login
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 三方登录支持说明

  • 目前支持三方登录:微信、QQ、微博、叨鱼、wegame
  • 支持通过 Ghome SDK 服务端配置动态设置是否支持三方登录,并支持选择其中某几个三方登录
  • !!!强烈建议!!! 游戏接入 SDK 时,完整的实现三方登录需要的接入需求并完成测试,这样未来在需要某个三方登录时,可以通过 Ghome SDK 服务端配置动态开启

已知需要注意点:

  1. 微信 & 叨鱼登录,在游戏APP接入时,有额外的配置要求,需要重点注意(建议预埋功能)
  2. wegame APP 腾讯目前可能不在运营(已下架),可能在三方登录支持上有瑕疵或者不流畅等各种问题

# GHome SDK调试日志开关

GHome.getInstance().setGHomeSDKDebuggable(true); //如果开启调试日志,发布包记得删除或设置成false关闭调试日志
1

# 3. 开发环境要求

# 3.1. 集成SDK文件到游戏工程

  • 将压缩包中的aar文件全部拷贝到游戏工程的libs里即可
  • 将游戏对应的oaid的证书文件放入assets(具体申请可浏览移动联盟官网 (opens new window),注意当前政策下证书存在有效期1年)
  • 在项目级的build.gradle中添加头条sdk相关库地址:
    buildscript {
    repositories {
        //.....


        //头条 begin
        maven {
            url 'https://artifact.bytedance.com/repository/Volcengine/'
        }
        //头条 end


        //热云 begin
        maven {
            url 'https://developer.hihonor.com/repo' //荣耀
        }
        //热云 end
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.1.1'
    //.....
    }
}

allprojects {
    repositories {
        //.....

        //头条 begin
        maven {
            url 'https://artifact.bytedance.com/repository/Volcengine/'
        }
        //头条 end


        //热云 begin
        maven {
            url 'https://developer.hihonor.com/repo' //荣耀
        }
        //热云 end
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  • 游戏已开启 AndroidX(建议开启) 游戏工程的build.gradle 需要添加的 在线依赖:
    api fileTree(includes: ['*.jar', '*.aar'], dir:  'libs')


    //ghome sdk 在线依赖部分 begin
    def bdVersion = "6.15.4"
    implementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bdVersion"

    implementation "com.bytedance.applog:RangersAppLog-All-convert:$bdVersion"
    //如果开发者项目本身未使用kotlin部分,则必须通过implementation远程依赖的形式进行kotlin的依赖
    implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61'

    implementation 'androidx.appcompat:appcompat:1.3.1'

    implementation 'com.google.code.gson:gson:2.10.1'
    implementation 'io.github.sinaweibosdk:core:13.10.1@aar'
    implementation 'com.squareup.okhttp3:okhttp:3.10.0'
    implementation 'com.geetest.sensebot:sensebot:4.4.2.1'

    implementation 'com.hihonor.mcs:ads-identifier:1.0.2.301' //荣耀
    //ghome sdk 在线依赖部分 end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  • 游戏工程未开启 AndroidX 游戏工程的build.gradle 需要添加的 在线依赖:
    api fileTree(includes: ['*.jar', '*.aar'], dir:  'libs')

    //ghome sdk 在线依赖部分 start
    def bdVersion = "6.15.4"
    implementation "com.bytedance.applog:RangersAppLog-Lite-cn:$bdVersion"
    implementation "com.bytedance.applog:RangersAppLog-All-convert:$bdVersion"
    //如果开发者项目本身未使用kotlin部分,则必须通过implementation远程依赖的形式进行kotlin的依赖
    implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61'

    implementation 'com.android.support:support-v4:28.0.0'

    implementation 'com.google.code.gson:gson:2.10.1'
    implementation 'io.github.sinaweibosdk:core:13.10.1@aar'
    implementation 'com.squareup.okhttp3:okhttp:3.10.0'
    implementation 'com.geetest.sensebot:sensebot:4.4.2.1'

    implementation 'com.hihonor.mcs:ads-identifier:1.0.2.301' //荣耀
    //ghome sdk在线依赖部分 end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 3.2. 配置AndroidManifest.xml文件

注意:

1、targetSdkVersion >= 30

2、minSdkVersion >= 23

3、游戏主activity启动模式设置为singleTask 需要重点回归测试下支付宝等第三方支付在支付中回到桌面再切换回游戏等场景是否会有卡住的问题

  • 修改游戏工程的AndroidManifest.xml文件中Application节点:

修改Application类为“com.ghome.sdk.GHomeApplication”,

<application
    android:name="com.ghome.sdk.GHomeApplication"
    android:usesCleartextTraffic="true"
    android:requestLegacyExternalStorage="true">
1
2
3
4
  • 如果游戏已经有自己自定义的Application(比如MyXXXGameApplication),那么该自定义的Application需要继承GHomeApplication类,并且需要在子类里重写一下onCreate(有些渠道需求特殊导致需要这样重写一下):
<application
    android:name="com.ghome.sdk.demo.MyXXXGameApplication"
    android:usesCleartextTraffic="true"
    android:requestLegacyExternalStorage="true">


public class MyXXXGameApplication extends GHomeApplication {
    @Override
    public void onCreate() {
        super.onCreate();
    }

    ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 请在游戏工程的AndroidManifest.xml文件中增加以下Activity等信息:
<!-- QQ登录 需要配置ID begin  android:scheme="tencent863321445"  -->
        <activity
            android:name="com.tencent.tauth.AuthActivity"
            android:noHistory="true"
            android:launchMode="singleTask" >
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="tencent+游戏在QQ平台申请的ID" />
            </intent-filter>


        <!-- QQ登录 需要配置ID end -->

        <!--快手渠道必须加入 start-->
        <!-- 放在游戏主Activity节点内部 -->
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.BROWSABLE" />
            <category android:name="android.intent.category.DEFAULT" />
            <!--  scheme定义规则 ks_ghome_[游戏名称缩写] -->
            <data
                android:host="home"
                android:scheme="ks_ghome_qyn" />
        </intent-filter>

    </activity>
    <!--快手渠道必须加入 end -->

    <activity-alias
            android:name="${applicationId}.wxapi.WXPayEntryActivity"
            android:exported="true"
            android:targetActivity="com.ghome.sdk.common.GHomeWXPayActivity">
    </activity-alias>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  • AndroidManifest.xml中可配置是否对获取手机状态权限进行申请
<!-- 是否需要在安卓10以下申请手机状态权限 ,ghome sdk默认true -->
<!-- 目前非常【建议】增加该配置,并值为false (很重要!!!)-->
        <meta-data android:name="NEED_READ_PHONE_STATE" android:value="false"/>
1
2
3

# 3.3. 接口回调相关code常量定义

常量类所在包路径 com.ghome.sdk.common.Constants :

public static final int ERROR_CODE_SUCCESS = 0;
public static final int ERROR_CODE_LOGIN_CANCEL = -100;
public static final int ERROR_PAY_FAILED = -10869604;
public static final int ERROR_USER_NOT_LOGIN = -10869607;
public static final int ERROR_LOGIN_FAILED = -10869608;
public static final int ERROR_PAY_CANCEL = -10869609;
public static final int ERROR_INIT_FAILED = -10869610;
public static final int ERROR_OPERATION_NOT_SUPPORTED = -10869613;

public static final int ERROR_CODE_QR_LOGIN_SUCCESS = -10869637;
public static final int ERROR_CODE_QR_PAY_SUCCESS = -10869638;
public static final int ERROR_CODE_QR_RESULT = -10869639;
public static final int ERROR_CODE_QR_CANCELED = -10869640;

public static final int EVENT_ACCOUNT_LOGOUT = 1;
public static final int EVENT_GAME_FORCE_CLOSE = 2;
public static final int EVENT_ACCOUNT_CHANGED = 3;
public static final int EVENT_ACCOUNT_LOGOUT_ONLY = 4;
public static final int EVENT_EXIT_GAME = 5;


常量类所在包路径 com.ghome.sdk.common.IGHomeApi :

public static final int EXTEND_COMMAND_SUBMIT_EXTEND_DATA = 1003;
public static final int EXTEND_COMMAND_EXIT_PAGE = 1005;

public static class FloatIconPosition{
public static final int LeftTop = 0;    // 悬浮窗显示在左上角
public static final int LeftMiddle = 1;   // 悬浮窗显示在左边中间
public static final int LeftBottom = 2;   // 悬浮窗显示在左下角
public static final int RightTop = 3;   // 悬浮窗显示在右上角
public static final int RightMiddle = 4;  // 悬浮窗显示在右边中间
public static final int RightBottom = 5;  // 悬浮窗显示在右下角
public static final int MiddleTop = 6;    // 悬浮窗显示在上边中间
public static final int MiddleBottom = 7; // 悬浮窗显示在下边中间
}

文档接口里使用的Callback所在包路径:
com.ghome.sdk.common.IGHomeApi.Callback;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# 4. 调用sdk的隐私协议展示功能

注意(重要):

游戏需使用sdk的隐私政策功能的话则必接,否则不要接

游戏可调用该接口展示用户协议(隐私协议相关逻辑都交给sdk处理, 游戏只需在启动游戏调用该接口并等待同意与否的回调即可)

  • 接口:

    doPrivacyAgreement(final Activity activity, final String appId, final Callback callback);

  • 参数说明:

    activity: Activity对象。

    appId:游戏在手游直通车平台上申请得到的ID。

    callback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 注意事项:

    如游戏是自己实现隐私协议相关弹框展示功能则无需调用该接口, 否则必接

  • 代码示例:

GHome.getInstance().doPrivacyAgreement(mContext, "791000008", new IGHomeApi.Callback() {
            @Override
            public void callback(int code, String message, Map<String, String> data) {
                if (code == Constants.ERROR_CODE_SUCCESS) {
                    //调用了sdk的隐私政策功能并得到同意,可继续游戏后续运行逻辑
                } else {
                    //玩家不同意隐私政策,游戏可根据自身需求 做直接退出游戏等操作
                    //finish();
                }
            }
        });
1
2
3
4
5
6
7
8
9
10
11

# 5. 获取是否需要展示隐私协议弹框

注意(重要):

游戏使用自己的隐私弹框逻辑的话则必接,否则不要接

  • 说明: 游戏在两种场景之前需要调用该接口获取是否显示隐私协议弹框。

    场景1: 启动游戏

    场景2: 调用GHome的login接口之前

  • 接口:

    getAgreementStatus(Activity activity, String appId, boolean isForLogin, Callback callback);

  • 参数说明:

    activity: Activity对象。

    appId:游戏在手游直通车平台上申请得到的ID。

    isForLogin: 是否是在去调用login接口之前的查询(true),(对应于启动游戏时的查询-false)

    callback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 注意事项:

    如游戏是自己实现隐私协议相关弹框展示功能则必接,否则请勿调用该接口; 并且在同意与否的操作时 需要调用反馈接口

  • 代码示例:

//启动游戏 false
GHome.getInstance().getAgreementStatus(mContext, mContext.gameId, false, new IGHomeApi.Callback() {
            @Override
            public void callback(int code, String message, Map<String, String> data) {
                if (code == 0 && data != null && data.get("status").equals("1")) {
                    //游戏方自己处理隐私政策展示功能
                    AlertDialog agreeDialog = new AlertDialog.Builder(mContext).setMessage(data.get("privacyContent")).setNegativeButton("不同意", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            GHome.getInstance().onUserAgreement(mContext, true, false);
                            //TODO exit game
                        }
                    }).setPositiveButton("同意并继续", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            GHome.getInstance().onUserAgreement(mContext, true, true);
                            //TODO 继续初始化或者登录行为
                        }
                    }).create();
                    agreeDialog.setCancelable(false);
                    agreeDialog.show();
                }else{
                     mGHome.login(mContext, mContext.loginCallback);
                }
            }
        });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 6. 隐私协议结果反馈接口

注意(重要):

游戏自己实现的隐私政策则必接,否则不接

游戏需要在隐私协议弹窗后,根据用户选择同意与否调用该接口。

  • 接口:

    onUserAgreement(Activity activity, boolean isUserAction, boolean isAgreed);

  • 参数说明:

    activity: Activity对象。

    isUserAction:是否用户主动同意隐私协议(主动选择true,其他选择或者选第一次选择之后后面默认选项false)

    isAgreed: 是否同意隐私协议

  • 注意事项: 如游戏没有隐私协议弹窗,则需要在后台配置参数,弹出SDK自带隐私协议弹窗。

  • 代码示例:

//用户选择弹框同意
GHome.getInstance().onUserAgreement(getActivity(), true, true);
//之后用户默认同意
GHome.getInstance().onUserAgreement(getActivity(), false, true);
1
2
3
4

# 7. 基础功能(必接)

# 7.1. SDK初始化接口(需要在用户同意隐私政策之后调用)

游戏客户端需要在游戏启动的第一个Activity的onCreate()方法中调用该接口(注意在super.onCreate(); 和 GHome.getInstance().onCreate(this); 之后),在调用GHome SDK其他API前需先调用此接口对SDK进行初始化。否则可能无法正常使用后续的接口。如果游戏在自身初始化的时候有动态权限申请,务必在权限申请完成后再调用G家初始化接口。

  • 接口:

    initialize(final Activity activity, final String gameId, final Callback callback);

  • 参数说明:

    activity: Activity对象。

    gameId: 游戏在手游直通车平台上申请得到的ID。

    callback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 注意事项:

    游戏在启动游戏时需对设备网络进行判断,若无网络的情况下,游戏需实现对用户的弹框提示。

    如果没有特别说明,在初始化接口成功之前调用其他接口都有可能出现错误,请确保初始化接口成功之后再调用其他接口。

  • 代码示例:

GHome.getInstance().initialize(this, "791000008", new Callback(){

  @Override
  public void callback(int code, String message, Map<String, String> data) {
    // success
    if(code == Constants.ERROR_CODE_SUCCESS){
      //初始化成功
    }  else if(code == Constants.ERROR_INIT_FAILED){
      //初始化失败 无需处理
    } else if(code == Constants.EVENT_ACCOUNT_LOGOUT){
      // 这里已经注销账号了,游戏需要在这里处理自己注销账号的逻辑(可在注销之后调用登录接口拉登录界面)
    } else if(code == Constants.EVENT_ACCOUNT_CHANGED){
      // 此处切换账号已经成功,游戏可以使用此处获得的userid和ticket去游戏服务端做登陆数据验证
      // 如果游戏需要,可以在登录成功后,通过data获取到以下信息。
      // userid是该玩家在我们平台的用户id号;
      // ticket是本次登录得到的票据,用来给游戏服务器向平台服务器验证本次登陆是否合法;
      System.out.println("userid=" + data.get("userid"));
      System.out.println("ticket=" + data.get("ticket"));
    } else if(code == Constants.EVENT_ACCOUNT_LOGOUT_ONLY){
      // 这里已经注销账号了,游戏需要在这里处理自己注销账号的逻辑(注销即可,不调登录)
    } else if(code == Constants.EVENT_EXIT_GAME){
      //当通过渠道悬浮窗点退出游戏,悬浮窗已退出通知游戏做退出游戏操作。游戏不需要弹退出确认框
    }
  }

});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 7.2. 更新游戏接口

在游戏自有的包体强更场景(玩家必须更新到最新包体才可以玩游戏) 玩家点击更新按钮时,按照示例代码调用taptap渠道相关接口。

  • 接口:

    boolean isTapTapChannel()

    void tapTapUpdateGame(final Activity act, final Callback updateCallback)

  • 参数说明:

    activity: Activity对象。

    updateCallback: 回调对象

  • 注意事项:

    包体强更场景 才需要调用该接口,普通更新无需调用

    • 游戏判断当前包体需强更时,当用户点击「更新」按钮时,则直接按照示例代码调用判断和更新接口。点击「取消」时,则关闭游戏或者提示玩家“不更新至最新版本,游戏无法玩”。

  • 代码示例:

if (GHome.getInstance().isTapTapChannel()){
                    GHome.getInstance().tapTapUpdateGame(BaseActivity.this, new Callback() {
                        @Override
                        public void callback(int i, String s, Map<String, String> map) {
                            DemoToastUtil.showToast(BaseActivity.this, "tapTapUpdateGame callback code = " + i + ", msg:" + s);
                            if (i == -1){
                                //取消更新
                            }
                        }
                    });
                }
1
2
3
4
5
6
7
8
9
10
11

# 7.3. 账号踢下线上报接口

踢下线登出SDK账号接口(注:需要游戏客户端在账号被踢下线消息时调用该接口)

  • 接口:

    kickOff(final Activity activity)

  • 参数说明:

    activity: Activity对象。

  • 注意事项:

    建议在用户被踢下线时调用该接口

  • 代码示例:

GHome.getInstance().kickOff(activity);
1

# 8. 账号功能(必接)

# 8.1. 客户端登录

# 8.1.1 客户端登录接口

游戏客户端可以调用登录接口为玩家提供登录功能。若用户第一次登录,将显示登录和注册的界面。若用户上次使用账号成功登录过,则会用该账号自动登录。 (重要:如果游戏使用自己的隐私政策弹框功能, 则需要在调用login之前调用查询是否需要弹隐私政策的接口,查询接口说明请参考 接口5

  • 接口:

    login(final Activity activity, final Callback callback);

  • 参数说明:

    activity: Activity对象。

    callback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 代码示例:

GHome.getInstance().login(this, new Callback() {

  @Override
  public void callback(int code, String message, Map<String, String> data) {
    // 登陆结果的回调。
    // 开发者可以仅处理登陆成功的情况。
    if (code == Constants.ERROR_CODE_SUCCESS) {
      // 如果游戏需要,可以在登录成功后,通过data获取到以下信息。
      // userid是该玩家在我们平台的用户id号;
      // ticket是本次登录得到的票据,用来给游戏服务器向平台服务器验证本次登陆是否合法;
      // isGuest如果有返回并且字符串是"true"表示是游客,不返回或其他表示非游客。
      System.out.println("userid=" + data.get("userid"));
      System.out.println("ticket=" + data.get("ticket"));

      // 登录成功,进入游戏界面,游戏开发者补充逻辑。
    }else if(code == Constants.ERROR_INIT_NOT_FINISHED){
      //可在此处再次调用初始化接口

      //mContext.loginEnter = true;
      //mContext.gameId = "791000008";
      //mGHome.initialize(mContext, mContext.gameId, mContext.initCallback);
    }else if (code == Constants.ERROR_CODE_LOGIN_CANCEL) {
      // 游戏客户端需要在这里处理返回至游戏界面,玩家点击屏幕或者登录按键时再次调用login接口弹出登录框
    }else{
      //登录失败无需处理
    }
  }

});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 8.1.2 登录接口额外配置(微信 和 叨鱼登录需要)

1、AndroidManifest下必须添加(支持微信三方登录需要)

            <activity-alias
            android:name="${applicationId}.wxapi.WXEntryActivity"
            android:exported="true"
            android:targetActivity="com.ghome.sdk.common.GHomeWXEntryActivity"/>

            <activity-alias
            android:name="${applicationId}.dyapi.DYEntryActivity"
            android:exported="true"
            android:targetActivity="com.ghome.sdk.common.DaoYuHandlerActivity"/>
1
2
3
4
5
6
7
8
9

# 8.2. 客户端登出接口

游戏客户端可以在游戏内需要登出账号的地方调用该接口,执行成功将删除自动登录的记录信息,玩家下次登录后将不再自动登录,而是显示出登录界面。

  • 接口:

    logout(final Activity activity, final Callback callback);

  • 参数说明:

    activity: Activity对象。

    callback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 代码示例:

GHome.getInstance().logout(this, new Callback() {
  @Override
  public void callback(int code, String message, Map<String, String> data) {
    if (code == Constants.ERROR_CODE_SUCCESS) {
      // 注销成功
    } else {
      // 注销失败
    }
  }
});
1
2
3
4
5
6
7
8
9
10

# 8.3. 切换账号接口

游戏里有切换账号入口的情况应调用这个接口来实现切换账号功能。

  • 接口:

    switchAccount(final Activity activity, final Callback agreementCallback, final Callback callback);

  • 参数说明:

    activity: Activity对象。

    agreementCallback: 用于接收隐私协议弹框的通知,收到该回调时游戏根据status状态弹出自己的隐私弹框,切记如果游戏方使用的sdk的隐私弹框功能则该参数传null对象 或 不传)

    callback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 代码示例:

//游戏使用sdk的隐私弹框功能, 第二个参数则传 null: GHome.getInstance().switchAccount(mContext, null, callback);

//游戏使用自己实现的隐私弹框功能,第二个参数传入agreementCallback对象, 示例如下:
GHome.getInstance().switchAccount(mContext, new IGHomeApi.Callback() {
            @Override
            public void callback(int code, String message, Map<String, String> data) {
                if (code == 0) {
                    //弹游戏自己的隐私政策弹框(通过data.get("privacyContent") 取内容)
                    if (data != null && data.get("status") != null && data.get("status").equals("1")) {
                        //模拟游戏方自己处理隐私政策展示功能 start
                        GameAgreementOperationDialog agreementDialog = new GameAgreementOperationDialog(getContext());
                        agreementDialog1.setContentUrl(data.get("privacyContent"));
                        agreementDialog1.setOperationListener(new GameAgreementOperationDialog.GameAgreementOperationListener() {
                            @Override
                            public void onOperateCallback(boolean isAgree) {
                                GHome.getInstance().onUserAgreement(mContext, true, isAgree);
                            }
                        });
                        agreementDialog.show();
                        //模拟游戏方自己处理隐私政策展示功能 end
                    } else {
                        GHome.getInstance().onUserAgreement(mContext, false, true);
                    }
                } else {
                }
            }
        }, new Callback() {
            @Override
            public void callback(int code, String msg, Map<String, String> data) {
                // 切换账号结果的回调。
                // 切换账号失败会有Toast提示,所以开发者可以不处理切换账号失败的情况。
                if (code == Constants.ERROR_CODE_SUCCESS) {
                    // 切换账号成功,通过data返回账号信息(获取用户信息同登录接口)。
                    // userid是该玩家在我们平台的用户id号;
                    // ticket是本次切换账号得到的票据,用来给游戏服务器向平台服务器验证本次登陆是否合法;
                    // isGuest如果有返回并且字符串是"true"表示是游客,不返回或其他表示非游客。
                    System.out.println("userid=" + data.get("userid"));
                    System.out.println("ticket=" + data.get("ticket"));
                    System.out.println("isGuest=" + "true".equal(data.get("isGuest") == null ? "" : data.get("isGuest")));
                } else if (code == Constants.ERROR_CODE_LOGIN_CANCEL) {
                    // 代表切换账号取消,但是此时已经是登出状态了
                    // 游戏客户端需要在这里做退出游戏还是重新打开登陆界面的处理
                } else {
                    //默认是切换账号失败,无需处理
                }
            }
        });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

# 8.4. 客户端注销删除账号接口

游戏客户端可以在游戏内提供注销账号的场所调用该接口,需要在收到注销回调成功之后退出回到登录。

  • 接口:

    writtenOff(final Activity activity, final Callback writtenOffCallback);

  • 参数说明:

    activity: Activity对象。

    writtenOffCallback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 代码示例:

GHome.getInstance().writtenOff(this, new Callback() {
  @Override
  public void callback(int code, String message, Map<String, String> data) {
    if (code == Constants.ERROR_CODE_SUCCESS) {
      // 注销删除账号成功,游戏这里退出游戏登录态回到登录页即可,(同logout处理
    } else {
      // 注销删除账号取消或者失败 无需处理
    }
  }
});
1
2
3
4
5
6
7
8
9
10

# 9. 支付功能(必接)

# 9.1. 客户端支付接口

游戏客户端可以在购买道具的地方调用该接口。这将打开支付界面,引导玩家支付该订单。用户结束支付操作后,SDK会回调游戏客户端,告知支付结果是否已经成功。

  • 接口:

    pay(final Activity activity, final String groupId, final String orderId, final String areaId, final String productId, final String extend, final Callback callback);

  • 参数说明:

    activity: Activity对象。

    groupId: 组ID。没有该实际数据则传空("")

    orderId: 游戏订单号。如果游戏需要记录订单号,可以传入唯一的字符串来标识此订单。

    areaId: 在 GPOP 上设置的区服的ID

    productId: 在 GPOP 上设置的商品的ID

    extend: 扩展参数,游戏可用于自行扩展,平台发货通知时将原样返回给游戏服务器。

    callback: 回调对象,用来回调执行结果,详情请参考代码事例。

入参必要性说明

  • 支付接口入参信息流转(例如 groupId、areaId 等):游戏APP客户端 -> Ghome SDK -> 支付服务端 -> 游戏服务端 -> 玩家信息数据库
  • 入参是否必须,入参数据是否有特别要求,主要有 【支付服务端 -> 游戏服务端】决定
  • 不同游戏可能存在不同的数据要求,因此游戏客户端研发对这些入参的value有疑虑时,需要向 Ghome SDK 服务端 & 游戏服务端 研发负责人确认value的必须性和合理性
  • 注意事项:

    由于可能发生网络延迟等等原因,有时候客户端返回的支付结果可能与实际情况有出入,所以最终订单是否支付成功,建议以平台服务器端的通知为准,客户端的通知结果仅作为参考。

  • 代码示例:

GHome.getInstance().pay(this, "111", "orderid_1724289303902", "1", "p001", "", new Callback() {
  @Override
  public void callback(int code, String message, Map<String, String> data) {
    if (code == Constants.ERROR_CODE_SUCCESS) {
      // 支付成功,游戏客户端可以在这里查询游戏服务器是否收到发货通知
      // 如果游戏服务器已经收到发货通知可以向用户发放道具
    } else {
      // 支付暂未成功,这种状态可能是用户未完成支付,也可能是尚未收到渠道的发货通知
      // 游戏客户可以不做处理,用户下次登录时再做查询
    }
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
  • callback出参的 Map data数据详情(客户端回传数据仅作参考使用,支付结果数据请以服务端为准):

     "S_orderid"   //透传收银台关闭时收银台回传的扩展数据,目前值是支付服务端下单成功的订单号(S10101290580xxxxxxxxxx1618000001)
     "orderid"     //对应游戏调用pay接口入参的游戏侧的订单号(orderid_1724289303902)
     "areaid"      //对应游戏调用pay接口入参的areaId
     "productid"   //对应游戏调用pay接口入参的productId
     "extend"      //对应游戏调用pay接口入参的extend
     "groupId"     //对应游戏调用pay接口入参的groupId
     "userid"      //userid
    
    1
    2
    3
    4
    5
    6
    7

# 9.2. 微信支付接入步骤

  • AndroidManifest添加如下配置:
        <activity-alias
            android:name="${applicationId}.wxapi.WXPayEntryActivity"
            android:exported="true"
            android:targetActivity="com.ghome.sdk.common.GHomeWXPayActivity">
        </activity-alias>
1
2
3
4
5

# 10. 扩展功能(可选)

# 10.1. 客户端获取游戏区服列表接口

游戏客户端可以调用该接口获取游戏在G家平台登记的区服配置。

  • 接口:

    getAreaConfig(final Activity activity, final Callback callback);

  • 参数说明:

    activity: Activity对象。

    callback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 注意事项:

    暂无

  • 代码示例:

GHome.getInstance().getAreaConfig(this, new Callback() {
  @Override
  public void callback(int code, String message, Map<String, String> data) {
    if (code == 0) {
      String json = data.get("data"));
    }
  }
});
1
2
3
4
5
6
7
8
  • JSON格式说明:
{
  "message":[
  {
    "area_code":"1",  // 开发商后台配置的区服ID
    "name":"area1"    // 开发商后台配置的区服名称
    "group_id":"1"    // 开发商后台配置的区组ID
    "group_name":"gourp1"    // 开发商后台配置的区组名称
  },
  ...
  ]
}
1
2
3
4
5
6
7
8
9
10
11

# 10.2. 客户端获取游戏商品列表接口

游戏客户端可以调用该接口获取游戏在G家平台登记的商品配置。

  • 接口:

    getProductConfig(final Activity activity, final Callback callback);

  • 参数说明:

    activity: Activity对象。

    callback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 注意事项:

    暂无

  • 代码示例:

GHome.getInstance().getProductConfig(this, new Callback() {
  @Override
  public void callback(int code, String message, Map<String, String> data) {
    if (code == 0) {
      String json = data.get("data"));
    }
  }
});
1
2
3
4
5
6
7
8
  • JSON格式说明:
{
  "message":[
  {
    "product_code":"com.gold100",  // 开发商后台配置的产品ID
    "item_name":"100 Gold",       // 开发商后台配置的产品名称
    "money":"10.00",          // 开发商后台配置的产品金额
    "type":0              // 0:Android游戏,1:IOS游戏,2:Android和IOS游戏
  },
  ...
  ]
}
1
2
3
4
5
6
7
8
9
10
11

# 10.3. 客户端获取一次性登录票据接口

游戏客户端在接入其他需要登录G家平台的应用时(如:客服、论坛等。),可以调用该接口获取一个一次性小票提供给应用完成登录。

  • 接口:

    getTicket(final Activity activity, final String appId, final String areaId, final Callback callback);

  • 参数说明:

    参数 类型 说明
    activity Activity Activity对象
    appId String 需要使用该票据完成登录的应用ID。
    areaId String 需要使用该票据完成登录的应用区ID,如果该应用没有区的概念可以传"0"
    callback Callback 回调对象,用来回调执行结果,详情请参考代码事例。
  • 注意事项:

    必须在登录成功之后才可以使用该接口

  • 代码示例:

GHome.getInstance().getTicket(mContext, appId, areaId, new Callback() {
                @Override
                public void callback(int code, String msg, Map<String, String> data) {
                    if (code == Constants.ERROR_CODE_SUCCESS) {
                        if (data != null) {
                            final String ticket = (String) data.get("ticket");
                            //获取成功  继续游戏验证登录逻辑。
                        } else {
                            DemoToastUtil.showToast(mContext, msg);
                        }
                    } else if(code == Constants.ERROR_NETWORK_TIMEOUT){
                        // 票据获取失败,但可以重试(包含网络问题)
                        // 游戏停留当前UI,并提示用户返回的 msg
                        // 用户点击msg关闭信息窗口后,可以点击“进入游戏”继续(重新走getticket流程)
                        DemoToastUtil.showToast(mContext, msg);
                    }else {
                        // 票据获取失败,但重试也可能回复(服务端有明确的特别错误码)
                        // 游戏停留当前UI,并提示用户返回的 msg
                        // 用户点击msg关闭信息窗口后,建议游戏实现App关闭(也可以关闭并重启)
                        DemoToastUtil.showToast(mContext, "code:" + code + " msg:" + msg);
                    }
                }
            });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 10.4. 打开二维码扫码

启动二维码扫码界面。(使用场景: 扫描游戏PC端二维码,授权使用手机当前已登录账号进行PC端的登录或者支付)

  • 接口:

    scanQRCode(final Activity activity, final String extend, final Callback callback);

  • 参数说明:

    activity: Activity对象。

    extend: 扩展字段,该字段会在扫码PC端二维码成功之后原样返回。

    callback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 注意事项:

    必须在登录成功之后才可以使用该接口。

  • 代码示例:

GHome.getInstance().scanQRCode(this, "randomInfo", new Callback() {
  @Override
  public void callback(int code, String message, Map<String, String> data) {
    if (code == Constants.ERROR_CODE_QR_LOGIN_SUCCESS) {
      // 扫码登录成功
    }
    else if (code == Constants.ERROR_CODE_QR_PAY_SUCCESS) {
      // 扫码支付成功
    }
    else if (code == Constants.ERROR_CODE_QR_RESULT) {
      //扫码授权结果信息,可以取data的qrdata 具体信息显示
      System.out.println("qrdata=" + data != null ? data.get("qrdata") : message);
      ToastUtil.showMessage(getActivity(), data != null ? data.get("qrdata") : message);
    }
    else if (code == Constants.ERROR_CODE_QR_CANCELED) {
      System.out.println("QR scan canceled"));
    }else if (code == Constants.ERROR_PAY_FAILED) {
      Log.debug(TAG, "QRCODE_DEBUG扫码支付失败!!! ");
    }else if (code == Constants.ERROR_USER_NOT_LOGIN) {
      Log.debug(TAG, "QRCODE_DEBUG未登录!!! ");//游戏收到后可以弹窗提示 和 拉起登录让用户重登
    } 
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 11. 渠道接口(必接)

# 11.1. 客户端上报游戏区接口

游戏客户端在用户选择区时需要调用该接口,否则数据报表将无法按区提供。

  • 接口:

    loginArea(final Activity activity, final String areaId, final String groupId);

  • 参数说明:

    activity: Activity对象。

    areaId: 用户进入游戏所选择的区ID。

    groupId: 组ID, 没有该实际数据则传空("")

  • 代码示例:

GHome.getInstance().loginArea(this, "1", "99");
1

# 11.2. 生命周期以及权限回调接口

注意(重要):

在游戏客户端主Activity中接入

  • 代码示例:
@Override
protected void onCreate() {
  super.onCreate();
  GHome.getInstance().onCreate(this);
}

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

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

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

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

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

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

@Override
protected void onNewIntent(Intent intent) {
  super.onNewIntent(intent);
  GHome.getInstance().onNewIntent(this, intent);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
  super.onActivityResult(requestCode, resultCode, intent);
  GHome.getInstance().onActivityResult(this, requestCode, resultCode, intent);
}

@Override
public void onBackPressed() {
  super.onBackPressed();
  GHome.getInstance().onBackPressed(this);
}

//申请权限回调接口
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
  super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  GHome.getInstance().onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}

@Override
    public void onWindowFocusChanged(boolean hasFocus){
        super.onWindowFocusChanged(hasFocus);
        GHome.getInstance().onWindowFocusChanged(this, hasFocus);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

# 11.3. 客户端显示/隐藏悬浮窗接口

游戏客户端需要在游戏登录成功之后显示悬浮窗,登出之后隐藏悬浮窗,否则可能无法通过渠道上线审核。

  • 接口:

    showFloatIcon(final Activity activity, final boolean show, final int position);

  • 参数说明:

    activity: Activity对象。

    show: true显示悬浮窗、false隐藏悬浮窗。

    position: 悬浮窗显示位置(部分渠道不支持悬浮窗位置设置,指定该参数可能没有效果)。

  • 代码示例:

// 在登成功之后调用
GHome.getInstance().showFloatIcon(this, true, IGHomeApi.FloatIconPosition.LeftTop);

// 在账号注销之后调用
GHome.getInstance().showFloatIcon(this, false, IGHomeApi.FloatIconPosition.LeftTop);
1
2
3
4
5

# 11.4. 第三方渠道SDK扩展接口

游戏客户端,请依据文档,在各个对应场景实现如下接口。

  • 接口:

    doExtend(final Activity activity, final int command, final Map<String, String> params, final Callback callback);

  • 参数说明:

    activity: Activity对象。

    command: 扩展接口编号(如: IGHomeApi.EXTEND_COMMAND_SUBMIT_EXTEND_DATA)

    params: 请求参数,类型为Map<String, String>

    callback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 注意事项:

    请严格按照文档要求在游戏内各个节点接入该接口。

  • 可从callback的data中获取到调用时候对应传入的"command"值,代码示例:

Callback callback = new Callback() {

  @Override
  public void callback(int code, String message, Map<String, String> data){
    //从data中获取到"command", 该方式适用于游戏使用同一个callback来调用doExtend接口的不同功能逻辑
     int command = Integer.parseInt(data.get("doExtendRequestCommand"));

     //游戏可根据回调code按需处理后续逻辑

  }
}
1
2
3
4
5
6
7
8
9
10
11
# 11.4.1 提交游戏扩展数据

渠道要求游戏在运行过程中提交一些用于运营需要的扩展数据,以便双方对游戏内容进行更深度的运营。游戏在接入时请将代码示例中的玩家数据改为真实数据。本接口需在以下情况下调用:

  1. 玩家登陆成功后角色信息确定之后调用。

  2. 角色等级发生变化的时候调用。

  3. 创建新角色时调用。

  • 参数说明:

    "data"=>真实运营数据(json字符串)

    //该接口的"submitType"的值为“createRole”,"selectServer","enterServer","levelUp","exitServer"

  • 注意事项:

    "submitType" 请务必根据各个场景正确传入以上对应值

  • 代码示例:

JSONObject jsonExData = new JSONObject(); 
try{
  jsonExData.put("submitType", "createRole"); // 上报场景:  "createRole", "selectServer"(选择服务器,账号登录成功 ,角色进入游戏前), "enterServer"(选择服务器进入游戏后), "levelUp"(角色升级) ,"exitServer"(退出服务器,退出游戏)
  jsonExData.put("roleId", "R0010");        // 当前登录的玩家角色ID              
  jsonExData.put("roleName", "令狐一冲");     // 当前登录的玩家角色名
  jsonExData.put("roleLevel", "99");        // 当前登录的玩家角色等级
  jsonExData.put("roleCreateTime", "1488264008");        // 角色创建时间,格式为unix时间戳,该时间为服务器时间,务必传一个数字
  jsonExData.put("roleLevelUpdateTime", "1488264008");        // 角色等级更新时间,格式为unix时间戳,该时间为服务器时间,务必传一个数字
  jsonExData.put("zoneId", 192825);       // 当前登录的游戏区服ID
  jsonExData.put("zoneName", "游戏一区-逍遥谷"); // 当前登录的游戏区服名称
    jsonExData.put("roleBalance", "游戏币余额");// 务必传一个数字,若无,传"0"
  jsonExData.put("vipLevel", "vip等级");// 务必传一个数字,若无,传入"0"
  jsonExData.put("partyName", "帮派名称");//若没有就传"无"
  jsonExData.put("professionid", "当前登录玩家的职业ID");//没有就传"0"
  jsonExData.put("Private", "当前登录玩家的职业名称");//没有就传"无"
  jsonExData.put("gender", "当前登录玩家的性别");//不能为空,不能为null,可传参数"男"、"女"、"无"
  jsonExData.put("payTotal", "0");//累计充值金额 元为单位,文不能为空,必须为数字,若没有就传"0"
  jsonExData.put("remainCoinNum", "0");//1级货币余额,例如此玩家钱袋里还有5000个元宝,不能为空,必须为数字,若无,传入"0"
  jsonExData.put("professionroleid", "职业称号ID");//不能为空,不能为null,没有就传 "0"
  jsonExData.put("professionrolename", "职业称号");//不能为空,不能为null,没有就传"无"
  jsonExData.put("power", "战力值");//不能为空,必须为数字,不能为null,没有就传“0”
  jsonExData.put("experience", "经验值");//不能为空,用户当前经验值,必须为数字,不能为null,若没有就传"0"
  jsonExData.put("balance", "帐号余额");//若没有则传 "0"

  jsonExData.put("partyid", "当前用户所属帮派帮派ID");//不能为空,必须为数字,不能为null,若无,传入 “0”
  jsonExData.put("partyroleid", "帮派称号ID");//帮派会长/帮主必传1,其他可自定义,不能为空,不能为null,若无,传入 “0”
  jsonExData.put("partyrolename", "帮派称号名称");//不能为空,不能为null,若无,传入“无”
} catch (JSONException e) {
}

Map<String, String> params = new HashMap<String, String>();
params.put("data", jsonExData.toString());

GHome.getInstance().doExtend(this, IGHomeApi.EXTEND_COMMAND_SUBMIT_EXTEND_DATA, params, new Callback() {

  @Override
  public void callback(int code, String message, Map<String, String> data){
    //通常游戏可以忽略该接口的执行结果
     if(code == Constants.ERROR_CODE_SUCCESS || 
      code == Constants.ERROR_OPERATION_NOT_SUPPORTED){
      //调用成功
      //code=ERROR_OPERATION_NOT_SUPPORTED表示渠道不支持该操作, 此情况游戏无需处理
     } 
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 11.4.2 游戏退出页接口

游戏退出时调用该接口(通常是玩家点击返回键等要触发游戏退出弹框的场景),等待该接口返回来确定是否需要弹出游戏自己的退出弹框

  • 代码示例:
GHome.getInstance().doExtend(this, IGHomeApi.EXTEND_COMMAND_EXIT_PAGE, new HashMap<String, String>(), new Callback() {

  @Override
  public void callback(int code, String message, Map<String, String> data){
    if(code == Constants.ERROR_OPERATION_NOT_SUPPORTED){
      //渠道无退出弹框,游戏需要显示自己的退出确认界面
    } else if(code == Constants.ERROR_CODE_SUCCESS) {
      //已显示渠道的退出游戏弹框并且玩家点击了确定退出,游戏在这里直接做退出游戏处理
    } else{
      //无需处理
    }
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
13

# 12. 其他接口(非必接)

# 12.1. 获取渠道号

# 12.1.1. 获取一级渠道号

游戏可调用以下接口来获取一级渠道号

  • 接口:

    getApplicationSuperChannel(Context context);

  • 参数说明:

    context 上下文(可通过getApplicationContext()获取)

  • 注意事项:

    在初始化完成前或完成后调用都可以。

  • 代码示例:

GHome.getInstance().getApplicationSuperChannel(getApplicationContext());
1
# 12.1.2. 获取二级渠道号

游戏可调用以下接口来获取二级渠道号

  • 接口:

    getCPSChannelCode(Context context);

  • 参数说明:

    context 上下文(可通过getApplicationContext()获取)

  • 代码示例:

GHome.getInstance().getCPSChannelCode(getApplicationContext());
1

# 12.2. 获取G家设备id

G家使用的设备id的字符串

  • 接口:

    getGHomeDeviceId(final Activity activity)

  • 参数说明:

    activity: Activity对象。

  • 代码示例:

GHome.getInstance().getGHomeDeviceId(this)
1

# 13. 获取用户条款和隐私政策(选接)

注意(重要):

9.1.0.0 版本开始该接口返回值结构有变化更新,记得根据示例进行同步修改

游戏获取用户条款和隐私政策页面的URL / html页面内容代码 (接入接口时根据自身需求二选一)

  • 接口:

    getAgreement(final Activity activity, final String appId, final Callback callback); //页面的URL

    getAgreementContent(final Activity activity, final String appId, final Callback callback); //html页面内容代码

  • 参数说明:

    activity: Activity对象。

    appId: 游戏在 GPOP 上申请得到的ID。

    callback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 代码示例:

  //获取页面url
  GHome.getInstance().getAgreement(mContext, "791000008", new Callback() {
    @Override
    public void callback(int code, String message, Map<String, String> data) {
    if (code == 0 && data != null) {
            String dataJson = data.get("data");
            //游戏自己解析该json. json内容字段说明请看文档
            GetAgreementVersionAContent content = GsonUtil.fromJson(dataJson, GetAgreementVersionAContent.class);
            if (content != null) {
                String agreementServiceUrl = null;
                String agreementPrivacyUrl = null;
                for (AgreementDetail detail : content.agreements) {
                    if (detail != null) {
                        if (detail.type == 1) {//服务协议
                            agreementServiceUrl = detail.url;
                        } else if (detail.type == 2) {//隐私政策
                            agreementPrivacyUrl = detail.url;
                        } else if (detail.type == 0) {//聚合页
                        }
                    }
                }
                Toast.makeText(mContext, "隐私政策Url:" + agreementPrivacyUrl + "\n服务协议Url: " + agreementServiceUrl, Toast.LENGTH_SHORT).show();
            }
        }
    }
  });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  //获取页面内容
  GHome.getInstance().getAgreementContent(mContext, "791000008", new Callback() {
    @Override
    public void callback(int code, String message, Map<String, String> data) {
    if (code == 0 && data != null) {
            String dataJson = data.get("data");
            //游戏自己解析该json. json内容字段说明请看文档
            GetAgreementVersionAContent content = GsonUtil.fromJson(dataJson, GetAgreementVersionAContent.class);
            if (content != null) {
                String agreementServiceCon = null;
                String agreementPrivacyCon = null;
                for (AgreementDetail detail : content.agreements) {
                    if (detail != null) {
                        if (detail.type == 1) {//服务协议
                            agreementServiceCon = detail.content;
                        } else if (detail.type == 2) {//隐私政策
                            agreementPrivacyCon = detail.content;
                        } else if (detail.type == 0) {//聚合页
                        }
                    }
                }
                Toast.makeText(mContext, "隐私政策Content:" + agreementPrivacyCon + "\n服务协议Content: " + agreementServiceCon, Toast.LENGTH_LONG).show();
            }
        }
    }
  });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  • data.get("data") JSON格式说明:
{
    "agreements":[
        {
            "type":2,
            "url":"https:\/\/sdkdl.sdoprofile.com\/ghome\/yinsizhengce.html",
            "content":"\r\n<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>隐私政策<\/tit.............. "
        },
        {
            "type":1,
            "url":"https:\/\/sdkdl.sdoprofile.com\/ghome\/yonghuxieyi.html",
            "content":"<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>用户协议<\/tit.........."
        },
        {
            "type":0,
            "url":"https:\/\/sdkdl.sdoprofile.com\/ghome\/ghome_union.html",
            "content":"<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>盛趣游戏用户协议和隐私政策..........."
        }
    ],
    "status":1,
    "version":2
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 14. 登录账号更换绑定手机号(选接)

使用第三方账号(微博,QQ,微信等)登录进游戏之后的换绑手机号功能接口

  • 接口:

    changeThirdBindPhone(Activity activity, String appId, Callback callback);

  • 参数说明:

    activity: Activity对象。

    appId: 游戏在 GPOP 上申请得到的ID。

    callback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 代码示例:

  GHome.getInstance().changeThirdBindPhone(mContext, "791000008", new Callback() {
    @Override
    public void callback(int code, String message, Map<String, String> data) {
    if (code == 0){
      Toast.makeText(mContext, "关联成功", Toast.LENGTH_SHORT).show();
    }else{
      Toast.makeText(mContext, "关联失败", Toast.LENGTH_SHORT).show();
    }
    }
  });
1
2
3
4
5
6
7
8
9
10

# 15. 敏感词过滤接口(非必接,请看注意事项)

【注意(重要):】

  1. 该接口仅仅是一个interface空接口,如果游戏需要在某些渠道使用渠道的敏感词接口(例如wegame),则需要调用这个接口。

  2. 在 ghome sdk 或其他渠道,不会有任何作用,“原文入参,原文出参”。游戏在这些场景需要自行实现所有敏感词过滤功能(或者使用其他第三方sdk)

  3. 一般建议使用该接口的游戏,可以单独实现母包(和官方登录或者其他渠道分开),以便在聊天、昵称设定(等所有用户可输入信息地方)实现渠道使用的敏感词过滤(目前仅仅wegame渠道支持)。

  4. 基于第三点仅仅是一种游戏的实现方案建议,如果游戏有其他方便实现的方案,也可以操作。但原则上是需要完成敏感词过滤,并了解 ghome sdk 仅仅是一个空接口(功能代理)。

  5. 另外,如果游戏在wegame渠道的母包中实现了一次自己的敏感词,则wegame渠道包则会:用户输入->游戏母包的敏感词过滤->ghome sdk 接口代理->wegame 敏感词->返回结果。

  6. 该接口我们不会记录任何调用信息,不会有任何日志,因为属于用户隐私的敏感信息。所以请上线前使用该接口的游戏都需要经过测试(所有场景,例如聊天、昵称设置、等等),线上是不会对用户记录任何有关的行为数据。

  • 接口:

    filterSensitiveWord(final Activity activity, final String inputWord, final Callback filterCallback);

  • 参数说明:

    activity: Activity对象。

    inputWord: 用户输入的文本信息。

    filterCallback: 回调对象,用来回调执行结果,详情请参考代码事例。

  • 代码示例:

   GHome.getInstance().filterSensitiveWord(mContext, etSensitiveW.getText().toString(), new IGHomeApi.Callback(){
   @Override
   public void callback(int code, String msg, Map<String, String> data){
   Toast.makeText(mContext, "敏感词接口过滤结果: " + data != null ? data.get("resultWord") : "", Toast.LENGTH_SHORT).show();
   }
   });
1
2
3
4
5
6

# 16. GShare(分享功能,按需选接)

# 16.1. 分享相关的AndroidManifest.xml 配置项:

<!-- gshare权限申请 (manifest标签内) 有录屏分享功能才需要添加 start -->
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <!-- gshare权限申请(manifest标签内) end -->


<!-- GShare (application标签内)start -->
        <!-- provider 方式分享 authorities 配置为: 包名.gshare.fileprovider-->
        <provider
            android:name="com.ghome.gshare.GShareProvider"
            android:authorities="${applicationId}.gshare.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true" >
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/share_file_provider_paths" />
        </provider>
        <!-- provider 方式分享 -->

        <!--录屏功能所需的service-->
        <service android:name="com.ghome.gshare.record.RecordService"
            android:enabled="true"
            android:exported="true"
            android:foregroundServiceType="mediaProjection">
        </service>
        <!--录屏功能所需的service-->

<!-- GShare(application标签内) end -->
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 16.2. 分享相关生命周期接口

注意:

游戏主activity中接入

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

        //gshare
        GShareInterface.onActivityResult(requestCode, resultCode, data);
    }

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

        //gshare
        GShareInterface.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

@Override
    protected void onDestroy() {
        super.onDestroy();

        //gshare
        GShareInterface.free();
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 16.3. 分享接口入参说明

分享类型:

GSharePlatformType sharePlatform = GSharePlatformType.WEIXIN_PLATFORM;

public enum GSharePlatformType
{
    WEIXIN_PLATFORM,//微信
    WEIXIN_CIRCLE_PLATFORM,//微信朋友圈
    QQ_PLATFORM,//QQ
    QZONE_PLATFORM,//QQ空间
    SINA_WB_PLATFORM,//新浪微博
    SDK_CHOOSE_PLATFORM;//弹出选择第三方平台UI
}
1
2
3
4
5
6
7
8
9
10
11

分享监听(系统分享调用即成功,所以这个回调是调用接口即返回):

MyShareListener shareListener;
// 分享监听
    public class MyShareListener implements GShareListener {
        @Override
        public void onComplete(GSharePlatformType platformType) {
            Toast.makeText(mContext, platformType + "share onComplete", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onError(GSharePlatformType platformType, String strErrMsg) {
            Toast.makeText(mContext, platformType + " share onError:" + strErrMsg, Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onCancel(GSharePlatformType platformType) {
            Toast.makeText(mContext, platformType + " share onCancel", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onOpen(GSharePlatformType platformType) {
            Toast.makeText(mContext, platformType + " app onOpen", Toast.LENGTH_SHORT).show();
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 16.4. 分享文字 (sharePlatform:微信, QQ, QQ空间,新浪微博,平台自动选择)

GShareTextMedia shareMedia = new GShareTextMedia();
((GShareTextMedia) shareMedia).setText("分享文字测试");

GShareInterface.getInstance(mContext).doShareWithSystemPrimal(mContext, sharePlatform, shareMedia, shareListener);
1
2
3
4

# 16.5. 分享图片 (sharePlatform:微信, 微信朋友圈,QQ, QQ空间,新浪微博,平台自动选择)

shareMedia = new GShareSystemPrimalImageMedia();
((GShareSystemPrimalImageMedia) shareMedia).setDescription("图片分享");
((GShareSystemPrimalImageMedia) shareMedia).addMediaPath(mContext.getExternalFilesDir(null).toString() + "/" + "gshare1.jpg");

GShareInterface.getInstance(mContext).doShareWithSystemPrimal(mContext, sharePlatform, shareMedia, shareListener);
1
2
3
4
5

# 16.6. 分享视频 (sharePlatform: 微信,QQ,平台自动选择)

shareMedia = new GShareSystemPrimalVideoMedia();
((GShareSystemPrimalVideoMedia) shareMedia).setDescription("可爱的狗子");
((GShareSystemPrimalVideoMedia) shareMedia).addMediaPath(mContext.getExternalFilesDir(null).toString() + "/"  + "gshare1.mp4");

GShareInterface.getInstance(mContext).doShareWithSystemPrimal(mContext, sharePlatform, shareMedia, shareListener);
1
2
3
4
5

# 16.7. 分享音乐 (sharePlatform:QQ,平台自动选择)

shareMedia = new GShareSystemPrimalMusicMedia();
((GShareSystemPrimalMusicMedia) shareMedia).setDescription("音乐分享.");
((GShareSystemPrimalMusicMedia) shareMedia).addMediaPath(mContext.getExternalFilesDir(null).toString() + "/" + "gshare1.mp3");

GShareInterface.getInstance(mContext).doShareWithSystemPrimal(mContext, sharePlatform, shareMedia, shareListener);
1
2
3
4
5

# 16.8. 分享录屏

// 初始化视频录制服务
        GShareInterface.initRecordService(mContext);

        MyShareListener shareListener = new MyShareListener();

        GShareRecordListener myListener = new GShareRecordListener() {
            @Override
            public void onStartRecordSuccess() {
                ((Button) view).setText("结束并分享");
            }

            @Override
            public void onStartRecordFailed(String message) {
                Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onEndRecordSuccess(final String videoPath) {
                Toast.makeText(mContext, "录屏成功" + videoPath, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onEndRecordFailed(String message) {
                Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
            }
        };

        if (((Button) view).getText().toString().equals("录屏开始")) {
            GShareInterface.startRecord(myListener);
        } else {
            ((Button) view).setText("录屏开始");
            GShareInterface.stopRecordAndShare(mContext, shareListener);
        }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 17. 附录:特殊说明

  • SDK常用类所在包:
import com.ghome.sdk.GHome;
import com.ghome.sdk.GHomeApplication;
import com.ghome.sdk.common.Constants;
import com.ghome.sdk.common.IGHomeApi;
import com.ghome.sdk.common.IGHomeApi.Callback;
1
2
3
4
5
  • 关于从低版本(8.X.X.X)升级到高版本(9.X.X.X)因为老的分类资源未删除可能出现的运行时res资源查找失败问题:

    示例报错内容

    java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.widget.TextView.setText(java.lang.CharSequense)' on a null object reference

    解决方案

    需要低版本接入过程引入的GHome SDK 相关的资源。删除旧资源时如果有需要可以参考 低版本GHome SDK资源list (opens new window)

Last Updated: 9/19/2024, 1:48:26 AM