跳到主要内容
版本:v4

UE5 SDK 开发指南

本文介绍如何在游戏中加入排行榜系统。

当前 UE5 插件仅支持 Android、iOS,不支持 Tap PC。

集成前准备​

  1. 参考 开发者中心配置 创建应用、配置包名与签名证书
  2. 参考 UE5 集成指南完成 TapSDK 基础接入
  3. 排行榜模块依赖于 TapTap 登录模块,开发者接入前应先完成 TapTap 登录的接入

在开发者中心创建排行榜并记录排行榜 ID,等待初始化和登录成功后再调用排行榜接口。

权限说明​

Android 权限说明​

该模块在 Android 平台需要如下权限:

权限使用目的权限申请时机
网络权限用于访问网络数据用户首次使用该功能时会申请权限
网络状态权限用于检查网络连接状态(如 Wi-Fi 或移动数据是否可用)用户首次使用该功能时会申请权限
写入外部存储权限用于保存排行榜分享图片到设备存储用户首次使用分享功能时会申请权限

该模块将在 Android 应用中添加如下权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

iOS 权限说明​

该模块在 iOS 平台需要如下权限:

权限使用目的权限申请时机
相册权限保存图片到相册用户首次使用该功能时会申请权限

在 Project Settings > Platforms > iOS > Additional Plist Data 中添加以下内容,并替换授权文案:

<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册以保存图片</string>

SDK 获取​

参考 UE5 集成指南完成 TapCore 基础接入。再从下载页下载相同版本的 TapLogin、TapProfile、TapLeaderboard,放入项目的 Plugins 目录并启用。

添加模块依赖​

在游戏模块的 <GameModule>.Build.cs 中添加:

PublicDependencyModuleNames.AddRange(new string[]
{
"TapCore",
"TapLogin",
"TapProfile",
"TapLeaderboard",
});

修改 Build.cs 后重新生成项目文件并编译。

注册排行榜事件回调​

排行榜 SDK 提供事件回调接口,用于处理排行榜相关事件,如用户未登录等状态。

// LeaderboardCallbackHandler.h:用于排行榜事件和分享回调
#pragma once
#include "TapLeaderboard.h"
#include "LeaderboardCallbackHandler.generated.h"

UCLASS()
class ULeaderboardCallbackHandler : public UObject,
public ITapLeaderboardCallback, public ITapLeaderboardShareCallback
{
GENERATED_BODY()

public:
virtual void OnLeaderboardResult_Implementation(int32 Code, const FString& Message) override
{
if (Code == 500102)
{
// 显示登录入口,登录成功后由玩家重新打开榜单。
}
UE_LOG(LogTemp, Log, TEXT("Leaderboard event [%d]: %s"), Code, *Message);
}

// 分享事件的实现见下方“设置分享回调”
virtual void OnShareSuccess_Implementation(const FString& LocalPath) override;
virtual void OnShareFailed_Implementation(const FString& ErrorMessage) override;


};

在接收结果的游戏对象类中声明成员:

UPROPERTY()
TObjectPtr<ULeaderboardCallbackHandler> LeaderboardHandler;
// 初始化和登录成功后,在游戏对象的成员函数中创建并注册
LeaderboardHandler = NewObject<ULeaderboardCallbackHandler>(this);
TScriptInterface<ITapLeaderboardCallback> Callback;
Callback.SetObject(LeaderboardHandler.Get());
Callback.SetInterface(Cast<ITapLeaderboardCallback>(LeaderboardHandler.Get()));
UTapLeaderboard::RegisterLeaderboardCallback(Callback);

// 不再监听时,使用同一回调对象取消注册
// UTapLeaderboard::UnregisterLeaderboardCallback(Callback);

用上述 UPROPERTY 成员持有处理对象,直到停止事件和分享监听。下方数据请求直接传入 Delegate,不依赖该对象或事件回调注册。

设置分享功能​

设置分享回调后,排行榜H5页面会显示分享按钮,用户点击分享按钮后,排行榜截图会保存到本地,并触发分享成功回调。开发者可以根据自己的需要判断是否实现分享失败的回调方法。

配置 FileProvider​

在 Android 平台向外部应用分享排行榜图片时,需配置 FileProvider。通过项目的 Android UPL 或构建配置,将以下内容加入 AndroidManifest.xml 的 application 节点:

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>

同时将以下资源打包为 res/xml/file_paths.xml:

<paths>
<files-path name="shared_images" path="shared_images/" />
</paths>

调用 getUriForFile 时,authority 使用当前包名加 .fileprovider。如项目已有 FileProvider,可在其路径资源中添加上述目录,并使用该 provider 的 authority,无需重复声明。

设置分享回调​

分享回调需实现 ITapLeaderboardShareCallback 接口。

void ULeaderboardCallbackHandler::OnShareSuccess_Implementation(const FString& LocalPath)
{
// 处理排行榜分享图片保存成功
// LocalPath 为本地图片路径,可用于分享到系统
UE_LOG(LogTemp, Log, TEXT("Share image saved: %s"), *LocalPath);
}

void ULeaderboardCallbackHandler::OnShareFailed_Implementation(const FString& ErrorMessage)
{
// 处理分享失败(可选实现)
UE_LOG(LogTemp, Warning, TEXT("Share failed: %s"), *ErrorMessage);
}

// 设置分享回调(在打开排行榜前调用,LeaderboardHandler 需实现分享回调接口)
TScriptInterface<ITapLeaderboardShareCallback> ShareCallback;
ShareCallback.SetObject(LeaderboardHandler.Get());
ShareCallback.SetInterface(Cast<ITapLeaderboardShareCallback>(LeaderboardHandler.Get()));
UTapLeaderboard::SetShareCallback(ShareCallback);

// 不再接收分享结果时,传入空接口
// UTapLeaderboard::SetShareCallback(TScriptInterface<ITapLeaderboardShareCallback>{});

打开排行榜页面​

打开排行榜H5页面对话框,支持总榜和好友榜两种类型。

提示

如果排行榜页面显示不完整、按钮被遮挡或布局方向异常,请先确认 TapSDK 初始化时的 ScreenOrientation 参数是否与游戏实际屏幕方向一致。

#include "TapLeaderboard.h"

FString LeaderboardId = TEXT("your_leaderboard_id");

// 打开总榜
UTapLeaderboard::OpenLeaderboard(LeaderboardId, TEXT("public"));

// 打开好友榜(登录时需申请 UserFriends 授权)
UTapLeaderboard::OpenLeaderboard(LeaderboardId, TEXT("friends"));

打开用户个人资料​

展示指定用户的个人资料对话框,传入用户的openId。

// 使用 OpenId 打开用户个人资料
UTapLeaderboard::ShowTapUserProfile(TEXT("user_open_id"), TEXT(""));

// 或使用 UnionId,OpenId 和 UnionId 二选一,另一个传空字符串
UTapLeaderboard::ShowTapUserProfile(TEXT(""), TEXT("user_union_id"));

提交分数​

批量提交用户排行榜分数,一次最多提交 5 个分数。

#include "TapLeaderboard.h"

FTapLeaderboardScoreItem ScoreItem;
ScoreItem.LeaderboardId = TEXT("your_leaderboard_id");
ScoreItem.Score = 1000;

FTapLeaderboardScoreItem AnotherScoreItem;
AnotherScoreItem.LeaderboardId = TEXT("another_leaderboard_id");
AnotherScoreItem.Score = 2000;

TArray<FTapLeaderboardScoreItem> Scores{ScoreItem, AnotherScoreItem};
UTapLeaderboard::SubmitScores(
Scores,
FTapLeaderboardSubmitCallback::CreateLambda([](const FTapSubmitScoresResult& Result)
{
for (const FTapSubmitScoreResultItem& Item : Result.Items)
{
UE_LOG(LogTemp, Log, TEXT("Board: %s, score: %lld, new best: %d"),
*Item.LeaderboardId, Item.RawScore, Item.bNewBest);
}
}),
FTapLeaderboardErrorCallback::CreateLambda([](const FString& Operation, int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Warning, TEXT("%s failed [%d]: %s"), *Operation, Code, *Message);
if (Code == 500102)
{
// 引导用户登录,登录成功后再重试。
}
}));

获取排行榜数据​

分页获取排行榜数据,支持总榜和好友榜。

FString LeaderboardId = TEXT("your_leaderboard_id");
FString Collection = TEXT("public"); // 总榜:public,好友榜:friends
FString NextPage = TEXT(""); // 首次请求传空字符串,加载更多时传上次返回的 NextPage
FString PeriodToken = TEXT(""); // 空字符串表示当前周期,连续分页使用同一周期
// 查询历史周期时,使用返回的 Leaderboard.AvailablePeriods 中的 PeriodToken。

UTapLeaderboard::LoadLeaderboardScores(
LeaderboardId, Collection, NextPage, PeriodToken,
FTapLeaderboardScoresCallback::CreateLambda([](const FTapLeaderboardScoresResult& Result)
{
// 加载下一页时,使用 Result.NextPage 和 Result.Leaderboard.Period.PeriodToken。
// Result.NextPage 为空时停止分页。
for (const FTapLeaderboardScore& Score : Result.Scores)
{
UE_LOG(LogTemp, Log, TEXT("Rank: %lld, player: %s, score: %s"),
Score.Rank, *Score.User.Name, *Score.ScoreDisplay);
}
}),
FTapLeaderboardErrorCallback::CreateLambda([](const FString& Operation, int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Warning, TEXT("%s failed [%d]: %s"), *Operation, Code, *Message);
if (Code == 500102)
{
// 引导用户登录,登录成功后再重试。
}
}));

获取当前用户分数​

获取当前登录用户在指定排行榜的分数和排名。

FString LeaderboardId = TEXT("your_leaderboard_id");
FString Collection = TEXT("public"); // 总榜:public,好友榜:friends
FString PeriodToken = TEXT(""); // 空字符串表示当前周期

UTapLeaderboard::LoadCurrentPlayerLeaderboardScore(
LeaderboardId, Collection, PeriodToken,
FTapLeaderboardCurrentScoreCallback::CreateLambda([](const FTapUserScoreResult& Result)
{
// CurrentUserScore 是值类型,无需判空;默认值不能用于判断用户是否已提交成绩。
const FTapLeaderboardScore& Score = Result.CurrentUserScore;
UE_LOG(LogTemp, Log, TEXT("Rank: %lld, score: %lld"), Score.Rank, Score.Score);
}),
FTapLeaderboardErrorCallback::CreateLambda([](const FString& Operation, int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Warning, TEXT("%s failed [%d]: %s"), *Operation, Code, *Message);
if (Code == 500102)
{
// 引导用户登录,登录成功后再重试。
}
}));

获取用户相近分数​

查询当前用户附近的其他用户成绩。

FString LeaderboardId = TEXT("your_leaderboard_id");
FString Collection = TEXT("public"); // 总榜:public,好友榜:friends
FString PeriodToken = TEXT(""); // 空字符串表示当前周期
int32 MaxCount = 10; // 最大返回数量

UTapLeaderboard::LoadPlayerCenteredScores(
LeaderboardId, Collection, PeriodToken, MaxCount,
FTapLeaderboardScoresCallback::CreateLambda([](const FTapLeaderboardScoresResult& Result)
{
for (const FTapLeaderboardScore& Score : Result.Scores)
{
UE_LOG(LogTemp, Log, TEXT("Rank: %lld, player: %s, score: %s"),
Score.Rank, *Score.User.Name, *Score.ScoreDisplay);
}
}),
FTapLeaderboardErrorCallback::CreateLambda([](const FString& Operation, int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Warning, TEXT("%s failed [%d]: %s"), *Operation, Code, *Message);
if (Code == 500102)
{
// 引导用户登录,登录成功后再重试。
}
}));

错误处理​

排行榜 SDK 的数据请求通过 FTapLeaderboardErrorCallback 返回错误,开发者可根据错误码进行处理。

错误码说明​

错误码错误类型描述
500000排行榜周期已过期提示用户排行榜周期已结束,引导查看其他周期
500001排行榜 ID 未找到检查排行榜ID是否正确,提示用户排行榜不存在
500002排行榜参数错误leaderboard_id 与 client_id 不匹配
500101当前用户未授权获取此产品(服务)提示用户权限不足,联系管理员
500102用户未登录引导用户登录
500199未知错误通用错误处理,建议重试或联系技术支持

UE5 未初始化或平台不可用时返回 -1,具体原因见 Message。

错误处理示例​

可将以下 Delegate 作为请求的失败回调参数:

auto OnError = FTapLeaderboardErrorCallback::CreateLambda([](const FString& Operation, int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Warning, TEXT("%s failed [%d]: %s"), *Operation, Code, *Message);
if (Code == 500102)
{
// 引导用户登录,登录成功后再重试。
}
});