入门指引
LEVEL INFINITE PASS 资源可以帮助业务屏蔽底层账号认证的实现细节,同时也包括繁琐的 UI 开发。业务可以使用 LEVEL INFINITE PASS 统一的登录能力快速并安全地上线。
根据本文中的步骤接入 LEVEL INFINITE PASS 后,游戏只需几行代码即可支持 LEVEL INFINITE PASS 和其他第三方身份供应商(本文中称为 "渠道")的身份验证功能。
前提条件
使用登录组件完成客户端登录流程
步骤1:导入 LI PASS 插件
- Unity
- Unreal Engine
- SDK 1.27 及之后版本
- SDK 1.24 ~ 1.26
- SDK 1.24 之前版本
Unity 2021 ~ Unity 6
Unity 2021 ~ Unity 2022
Unity 2018 ~ Unity 2022
目录 StreamingAssets/LevelInfinite
使用于 Player Network SDK V1.20.01 及以上版本,目录 StreamingAssets/INTLGameNative
使用于 Player Network SDK V1.20.00 及以下版本。
-
将
LevelInfinite
、Plugins
和StreamingAssets/LevelInfinite
文件夹复制到游戏项目的Assets
目录后,再使用 Unity 导入。文件夹 说明 LevelInfinite LI PASS 引擎层代码 Plugins LI PASS 平台层库文件 StreamingAssets/LevelInfinite LI PASS 业务逻辑资源,可热更
2. [可选] 从项目中移除程序集。
LI PASS 从 V1.08 版本开始支持程序集。如果项目不支持程序集,请执行以下步骤来移除:
- 删除以下程序集定义文件。
- 修改
luaSvr.cs
,将程序集名从LevelInfinite
换成Assembly-CSharp
。 - 联系 Player Network 助手获取不带程序集的
AssetBundle
包。
-
在 Unity 菜单栏,选择 INTLLua > All > Clear 删除
Assets/LevelInfinite/Runtime/INTLGameNative/Scripts/LuaObject
目录。
如果删除成功,则自动弹窗提示生成 Unity 的 Lua 接口。如未弹窗,在 Unity 菜单栏选择 INTL > INTLLua > All > Make 来手动触发弹窗。 -
在弹窗中,点击 Generate 生成 C# 导出到 Lua 的接口。
-
在
Assets/LevelInfinite/Runtime/INTLGameNative/Scripts/LuaObject
目录中查看接口导出文件是否成功生成。注意存在 Custom 和 Unity 文件夹代表接口文件生成成功。
- Custom 文件夹:自定义类接口导出到 Lua。
- Unity 文件夹:Unity 引擎类接口导出到 Lua。
6. [可选] 切换加载方式。
加载方式默认为 Editor 模式,用于在编辑器中正常跑通 LI PASS 流程。业务可选择在开发时,通过在菜单栏 LevelInfinite > AssetLoadMode 中选择对应的加载方式,将加载方式切换成 StreamingAssets 模式。
加载模式的选择不影响构建发布包的加载模式(默认 CDN)。
选项 | 说明 |
---|---|
Editor | 对应 INTL_DEBUG_LUA 宏,读取本地 Lua 文件 |
StreamingAssets | 对应 INTL_USE_LOCAL_ASSETS 宏,加载 StreamingAssets 中的 AssetBundle |
CDN | 对应 Player Network 控制台 AssetBundle ,如果控制台资源加载失败则加载 StreamingAssets 中的 AssetBundle |
7. [可选] 完成 Unity 主机游戏的项目配置。
-
安装并激活 Input System 包:
注意Input System 需要 Unity 2019.1 或更高版本与 .NET Framework 4 运行,不适用于运行 .NET Framework 3.5 的项目。
在 XSX 真机运行时需匹配 1.6.1 版本的 Input System,同时附带安装
com.unity.inputsystem.gxdk-1.0.1
的拓展包,如果遇到引入问题请联系 Player Network 助手。更多详情,请参见 Input System 安装指南.
-
从 Unity 的主菜单中,进入 Window > Package Manager 以打开 Unity Package Manager。
-
点击 Advanced,确认 Show Preview Packages 已启用。
-
从左侧的列表中,选择最新的 Input System 包后,点击 Install。
-
从 Unity 的主菜单中,进入 Edit > Project Settings后,点击 Player。
-
将 Active Input Handling 的值设置为
Input System Package (New)
。
-
-
添加宏定义:
-
从 Unity 的主菜单中,进入 Edit > Project Settings 后,点击 Player。
-
打开 Other Settings 面板,浏览至 Scripting Define Symbols。
-
将
INTL_CONSOLE_GAME_INPUT
添加到文本框中,使用分号分隔。 -
在
Assets/LevelInfinite
中打开程序集定义文件LevelInfinite.asmdef
,然后在 Assembly Definition References 中添加Unity.InputSystem
。
-
- SDK 1.26 及之后版本
- SDK 1.26 之前版本
UE4.21 ~ UE4.27 & UE5 ~ UE5.5
UE4.21 ~ UE4.27 & UE5 ~ UE5.4
-
将
LevelInfinite
文件夹拷贝至目标项目的Plugins
文件夹中。如果项目没有Plugins
文件夹,请创建一个。警告在 Cook 的时候如果报错
LongPackageNameToFilename failed to convert '/LevelInfinite'. Path does not map to any roots
,需要修改 Cook 的路径/LevelInfinite -> /LevelInfinite/
,一般常出现在低于 UE4.27 版本。注意在 LI PASS V1.16 之前的版本,LI PASS 插件必须要放到
Plugins/LevelInfinite
目录中。如果业务要自定义路径,要对应修改PLUGIN_LI_CONTENT_PATH
、LI_LUA_BASE_PATH
和FRAME_LUA_BASE_PATH
变量并重新编译。
在 LI PASS V1.16 或之后的版本,LI PASS 插件自动根据业务配置的自定 义路径,动态加载资源文件。说明LevelInfiniteAssetVersion.lua
的文件拓展名为 LUA 而并非 LUAC,是因为里面包含了 LI PASS 的版本号,方便业务同学了解我们的 LI PASS 版本,便于定位问题。 -
打开游戏模块的构建文件,即
{项目名}.Build.cs
文件,并按照示例将LevelInfinite
插件添加为模块的私有依赖:public INTLSample(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay" });
// Add the following code
PrivateDependencyModuleNames.AddRange(new string[] {
"INTLCore",
"INTLFoundation",
"INTLConfig",
"LevelInfinite"
});
} -
将 LI PASS Lua 资源打进首包,在 Packaging/Additional Non-Asset 选项中添加:
../Plugins/LevelInfinite/Content
注意业务需要根据实际存放
LevelInfinite
文件夹的路径进行填写,例如实际存放路径是../Plugins/Template/LevelInfinite
,则在此需要添加的是../Plugins/Template/LevelInfinite/Content
。 -
将 LI PASS uasset 资源打进首包,在 Packaging/Additional Asset 选项中添加:
-
/LevelInfinite
-
步骤2:配置 LI PASS
业务可选择使用编辑器的可视化配置编辑工具来进行 LI PASS 的配置,或直接打开工程目录修改 INTLConfig.ini 文件。以下步骤将介绍如何使用编辑器轻松配置 LI PASS。
有关各配置项的详情,可在编辑器选中选项来自动展示选项的简述,或参见 LI PASS 客户端配置 查看完整的配置项列 表。
在编辑器运行时生效需要重启引擎,否则构建安装包时则自动生效。
- Unity
- Unreal Engine
-
通过编辑器工具栏 INTL > LI INIConfig Window 打开可视化配置编辑工具。
-
通过编辑器工具栏 LITools > Config Editor 打开可视化配置编辑工具。
-
将
ACCOUNT_SDK_KEY
和ACCOUNT_APP_ID
设置为 Player Network 控制台分配的值。注意在 LI PASS V1.16 之前的版本,将
ACCOUNT_URL
设置为https://test-pass.intlgame.com
来定义 LI PASS 测试环境。
在 LI PASS V1.16 或之后的版本,此配置项为选填。 -
为所需的平台配置指定的第三方登录渠道。
例如,ACCOUNT_THIRD_CHANNEL_ANDROID = Facebook,Google
。完整的配置列表,请参见 配置。
4. [可选] 第三方渠道登录时获取玩家邮箱。
要在第三方渠道登录时获取玩家邮箱需先设置对应权限。
- 基于合规考虑,可针对特定来源对返回 的
email
做 mask 处理,如有需求请联系 Player Network 助手打开。 - 可在后台流水日志中上报 hash 后的
base64(sha256(email))
,如有需求请联系 Player Network 助手打开。 - 可用于验证玩家信息或绑定列表是否包含
email
信息,如有需求请联系 Player Network 助手打开。 - 可用于 iOS Firebase 的 Private Set Membership(PSM)功能,详见 Firebase iOS 工程配置。
以下为支持返回玩家邮箱的第三方渠道:
Apple
Apple 获取玩家邮箱需要玩家授权,如果玩家拒绝授权将无法获取到玩家邮箱,详见 Login
接口传入 email
和 fullName
。
-
使用编辑工具,将
email
权限添加到 [Dynamic] 下的APPLE_LOGIN_PERMISSION
。 -
在 Player Network 控制台 开启 email 返 回功能,将 return_email 设置为 YES,详细步骤请参见 第三方渠道配置。
在 Player Network 控制台 开启 email 返回功能,将 return_email 设置为 YES,详细步骤请参见 第三方渠道配置。
-
使用编辑工具,将
email
权限添加到 [Dynamic] 下的FACEBOOK_LOGIN_PERMISSION
。如果INTLConfig.ini
没有配置FACEBOOK_LOGIN_PERMISSION
,则会自动带上email
权限。 -
在 Meta for Developers 配置 email 权限。email 权限需要有 高级访问级别,才能让所有应用都能获取到玩家的 email。
-
在 Player Network 控制台开启 email 返回功能,将 return_email 设置为 YES,详细步骤请参见 第三方渠道配置。
-
在 Twitter Developer Platform 的 User authentication settings 下,勾选 Request email from users。
-
在 Player Network 控制台 开启 email 返回功能,将 return_email 设置为 YES,详细步骤请参见 第三方渠道配置。
步骤3:初始化 LI PASS
- Unity
- Unreal Engine
步骤4:处理 LI PASS 回调
无需处理 LI PASS 内部回调事件,否则可能会拦截 LI PASS 正常的回调流程,导致登录异常。
根据以下示例,处理打开登录面板 OpenLoginPanel
和自动登录 AutoLogin
等回调事件。
- Unity
- Unreal Engine
开发人员需添加 AuthResultObserver、AuthBaseResultObserver 和 LIEventObserver 回调来处理登录组件和用户中心的事件。回调数据结构为 INTLAuthResult,其中包含登录信息和账号信息,例如 OpenID、账号绑定信息和账号注销状态。
// Add callbacks
public void AddAuthBaseObserver()
{
INTLAPI.AddAuthBaseResultObserver(OnAuthBaseResultEvent);
}
// Remove callbacks
public void RemoveAuthBaseObserver()
{
INTLAPI.RemoveAuthBaseResultObserver(OnAuthBaseResultEvent);
}
// Add callbacks
public void AddAuthObserver()
{
INTLAPI.AddAuthResultObserver(OnAuthResultEvent);
}
// Remove callbacks
public void RemoveAuthObserver()
{
INTLAPI.RemoveAuthResultObserver(OnAuthResultEvent);
}
// Handle AuthResultObserver callback result
private void OnAuthResultEvent(INTLAuthResult AuthResult)
{
switch (AuthResult.MethodId)
{
// LI PASS third channel / LI channel enter game
case (int)INTLMethodID.LI_LOGIN_ENTER_GAME:
if(AuthResult.RetCode == (int)ERROR_CODE.SUCCESS) {
Debug.Log("LI PASS Login success");
} else {
Debug.Log("LI PASS Login failed, ret_code = " + AuthResult.RetCode + ", ret_msg = " + AuthResult.RetMsg);
LevelInfinite.OpenLoginPanel();
}
break;
// LI PASS autologin enter game
case (int)INTLMethodID.LI_AUTOLOGIN_ENTER_GAME:
if(AuthResult.RetCode == (int)ERROR_CODE.SUCCESS) {
Debug.Log("LI PASS Autologin success");
} else {
Debug.Log("LI PASS Autologin failed, ret_code = " + AuthResult.RetCode + ", ret_msg = " + AuthResult.RetMsg);
LevelInfinite.OpenLoginPanel();
}
break;
default:
break;
}
}
// Process the INTLBaseResult callback
public void OnAuthBaseResultEvent(INTLBaseResult ret)
{
Debug.Log($"MethodID: {ret.MethodId}");
string methodTag = "";
if (ret.MethodId == (int)INTLMethodID.INTL_AUTH_LOGOUT)
{
methodTag = "Logout";
}
ShowLogInNewLine(methodTag + Tools.Instance.GetRetString(ret));
}
// Add callbacks
LevelInfinite.AddLIEventObserver(OnLIBaseEventResult);
// Handle LIEventObserver callback result
private void OnLIBaseEventResult(LIBaseEventResult liRet)
{
Debug.Log("<color=#ff00ff>OnLIBaseEventResult. lIEventType : " + Enum.GetName(typeof(LIEventType), liRet.lIEventType) + ", extraJson:" + liRet.extraJson + "</color>");
ShowLogInNewLine("OnLIBaseEventResult. lIEventType : " + Enum.GetName(typeof(LIEventType), liRet.lIEventType) + ", extraJson:" + liRet.extraJson);
switch (liRet.lIEventType)
{
// LI PASS Init Finish
case LIEventType.GN_READY:
// LevelInfinite.AutoLogin()
// LevelInfinite.OpenLoginPanel()
break;
// LI PASS Panel Open
case LIEventType.LIP_PANEL_OPEN:
break;
// LI PASS Panel Close
case LIEventType.LIP_PANEL_CLOSE:
break;
// LI PASS Open Login Panel
case LIEventType.OPEN_LOGIN:
break;
// LI PASS Close Login Panel
case LIEventType.CLOSE_LOGIN:
break;
// LI PASS Open Account Center
case LIEventType.OPEN_ACCOUNT_CENTER:
break;
// LI PASS Close Account Center
case LIEventType.CLOSE_ACCOUNT_CENTER:
break;
// LI PASS Close Delete Account Panel
case LIEventType.CLOSE_DELETE_ACCOUNT:
break;
// LI PASS Close Parent Certificate Panel
case LIEventType.CLOSE_PARENT_CERTIFICATE:
break;
// LI PASS Close Parent Tip Panel
case LIEventType.CLOSE_PARENT_TIP:
break;
// LI PASS Close Parent Deny Panel
case LIEventType.CLOSE_PARENT_DENY:
break;
// LI PASS Init Repeat
case LIEventType.GN_REPEAT:
break;
// LI PASS Closed
case LIEventType.GN_DISABLED:
break;
default:
break;
}
}
// Remove callbacks
LevelInfinite.RemoveLIEventObserver(OnLIBaseEventResult);
开发人员也可添加 LILuaErrorObserver 回调处理 Lua 错误。
开发人员需添加 AuthResultObserver、AuthBaseResultObserver 和 LIEventObserver 回调来处理登录组件和用户中心的事件。回调数据结构为 FINTLAuthResult,其中包含登录信息和账号信息,例如 OpenID、账号绑定信息和账号注销状态。
//configure callback
FINTLAuthBaseEvent authBaseEvent;
authBaseEvent.AddUObject(this, &OnAuthBaseResult_Implementation);
UINTLSDKAPI::SetAuthBaseResultObserver(authBaseEvent);
// Remove callbacks
UINTLSDKAPI::GetAuthBaseResultObserver().Clear();
//Handle AuthBaseResult callback result
void OnAuthBaseResult_Implementation(FINTLAuthBaseResult ret)
{
UE_LOG(LogTemp, Warning, TEXT("MethodID: %d"), ret.MethodId);
}
// Add callbacks
AuthResultObserver = UINTLSDKAPI::GetAuthResultObserver().AddUObject(this, &ULevelInfiniteWindow::OnAuthResult_Callback);
// Handle AuthResultObserver callback result
void ULevelInfiniteWindow::OnAuthResult_Callback(FINTLAuthResult AuthResult)
{
if(AuthResult.MethodId == (int32)LIEnterGameMethodId::kLILoginEnterGame)
{
FString logStr;
if(AuthResult.RetCode == INTL_NAMESPACE::ErrorCode::SUCCESS)
{
logStr = TEXT("LI PASS login success");
}else{
ULevelInfiniteAPI::OpenLoginPanel();
logStr = FString::Printf(TEXT("LI PASS login failed, ret_code = %d, ret_msg = %s"), AuthResult.RetCode, *AuthResult.RetMsg);
}
UE_LOG(LogTemp, Warning, TEXT("%s"), *logStr);
} else if (AuthResult.MethodId == (int32)LIEnterGameMethodId::kLIAutoLoginEnterGame){
if(AuthResult.RetCode == INTL_NAMESPACE::ErrorCode::SUCCESS)
{
UE_LOG(LogTemp, Warning, TEXT("LI PASS Autologin success"));
}else{
ULevelInfiniteAPI::OpenLoginPanel();
UE_LOG(LogTemp, Warning, TEXT("LI PASS Autologin failed, ret_code = %d, ret_msg = %s"), AuthResult.RetCode, *AuthResult.RetMsg);
}
}
}
// Remove callbacks
UINTLSDKAPI::GetAuthResultObserver().Remove(AuthResultObserver);
// Add callbacks
FDelegateHandle LIEventObserver;
LIEventObserver = ULevelInfiniteAPI::GetEventDelegate().AddUObject(this, &ULevelInfiniteWindow::OnLIEvent_Callback);
// Handle LIEventObserver callback result
void ULevelInfiniteWindow::OnLIEvent_Callback(FLIBaseEvent Event)
{
FString logStr;
switch(Event.EventType){
// LI PASS Closed
case ELIEventType::GN_DISABLED:
{
break;
}
// LI PASS Panel Open
case ELIEventType::LIP_PANEL_OPEN:
// LI PASS Open Login Panel
{
logStr = TEXT("LI PASS panel open");
break;
}
// LI PASS Panel Close
case ELIEventType::LIP_PANEL_CLOSE:
{
logStr = TEXT("LI PASS panel close");
break;
}
// LI PASS Open Login Panel
case ELIEventType::LOGIN_PANEL_OPEN:
{
logStr = TEXT("Login panel open");
break;
}
// LI PASS Close Login Panel
case ELIEventType::LOGIN_PANEL_CLOSE:
{
logStr = TEXT("Login panel close");
break;
}
// LI PASS Open Account Center
case ELIEventType::ACCOUNT_CENTER_OPEN:
{
logStr = TEXT("Account center open");
break;
}
// LI PASS Close Account Center
case ELIEventType::ACCOUNT_CENTER_CLOSE:
{
logStr = TEXT("Account center close");
break;
}
// LI PASS Save Protocol Version
case ELIEventType::SET_PROVISION:
{
logStr = FString::Printf(TEXT("LI set provision: %s"), *Event.ExtraJson);
break;
}
// LI PASS Real Name Compliance Success
case ELIEventType::COMPLIANCE_AGE_SUCESS:
{
logStr = TEXT("LI age and region compliance success");
break;
}
// LI PASS Minor Compliance Success
case ELIEventType::COMPLIANCE_MINOR_SUCESS:
{
logStr = TEXT("LI minor compliance success");
break;
}
// LI PASS Close Parent Tip Panel
case ELIEventType::CLOSE_PARENT_TIP_PANEL:
{
logStr = TEXT("LI close parent tip panel");
break;
}
// LI PASS Close Parent Deny Panel
case ELIEventType::CLOSE_PARENT_DENY_PANEL:
{
logStr = TEXT("LI close parent deny tip panel");
break;
}
// LI PASS Close Parent Certificate Panel
case ELIEventType::CLOSE_PARENT_CERTIFICATE_PANEL:
{
logStr = TEXT("LI close parent certificate panel");
break;
}
// LI PASS Close Delete Account Panel
case ELIEventType::CLOSE_DELETE_ACCOUNT_PANEL:
{
logStr = TEXT("LI close delete account panel");
break;
}
// LI PASS Init Repeat
case ELIEventType::INTL_REPEAT:
{
break;
}
// LI PASS Init Finish
case ELIEventType::GN_READY:
{
// ULevelInfiniteAPI::AutoLogin();
// ULevelInfiniteAPI::OpenLoginPanel();
break;
}
}
}
// Remove callbacks
ULevelInfiniteAPI::GetEventDelegate().Remove(LIEventObserver);
开发人员也可添加 LILuaErrorObserver 回调处理 Lua 错误。
步骤5:设置 LI PASS 界面和邮件的语言
开发人员需要设置所有 LI PASS 界面和邮件使用的语言,因此需要使用 语言代码 作为入参调用 SetLanguage
。建议此处设置的语言与游戏语言保持一致,以确保一致性。否则,LI PASS 界面和电子邮件中使用的语言可能与游戏使用的语言不同。
- Unity
- Unreal Engine
LevelInfinite.SetLanguage("zh-Hans");
ULevelInfiniteAPI::SetLanguage(TEXT("zh-Hans"));
步骤6:设置 UI 根节点
在使用任何其他 LI PASS 功能之前,需调用 SetUIRoot
设置所有 LI PASS 界面的根节点。
设置 UI 根节点后,请不要销毁该节点,否则 LI PASS UI 界面无法挂载,会产生预期外的行为。
LI PASS 界面的释放请通过界面按钮操作,不要强制销毁。在切换场景时若由 Unity 控制 GC(垃圾回收)可能发生,会造成空指针错误出现。
- Unity
- Unreal Engine
有关分辨率的详细设置,请参见 设置 UI 根节点。
LevelInfinite.SetUIRoot(uiRoot);
Unreal Engine 需要将根节点铺满整个屏幕。
ULevelInfiniteAPI::SetUIRoot(uiRoot);
步骤7:设置发布地区
LI PASS 登录组件内置默认的合规流程,需要开发人员使用 allowList
和 blockList
数组作为入参调用 UpdateCountryList
。allowList
数组应包含 LI PASS 国家地区选择页面需要展示的国家地区的 ISO 3166-1 数字代码,而 blockList
数组应包含不应显示的国家或地区代码。
此处指定的国家和地区将用于 LI PASS 登录组件内置的合规工作流程中。
- Unity
- Unreal Engine
string[] allowArray = new string[] {"496","400"};
string[] blockArray = new string[] {"400"};
LevelInfinite.UpdateCountryList(allowArray,blockArray);
TArray<FString> allowList;
allowList.Add(TEXT("496"));
allowList.Add(TEXT("400"));
TArray<FString> blockList;
blockList.Add(TEXT("400"))
ULevelInfiniteAPI::UpdateCountryList(allowList,blockList);
步骤8:添加 LI PASS 功能
Unreal Engine 主机平台游戏内账号绑定
游戏内账号绑定功能仅用于 Unreal Engine 中的主机平台,其他平台无需接入。
此功能用于在游戏页面内拉起绑定 LI PASS 页面。
// 添加登录态监听代码
AuthResultObserver = UINTLSDKAPI::GetAuthResultObserver().AddUObject(this, &UFloatingSidebar::OnAuthResult_Callback);
// 查询当前用户的绑定关系
UINTLSDKAPI::QueryBindInfo();
// 处理查询绑定关系的回调
void UFloatingSidebar::OnAuthResult_Callback(FINTLAuthResult AuthResult)
{
UE_LOG(LogTemp, Warning, TEXT("UFloatingSidebar::OnAuthResult_Callback AuthResult.MethodId: %d"),AuthResult.MethodId);
if(AuthResult.MethodId == (int32)LIMethodId::kLIQueryBindInfo) {
if(AuthResult.RetCode == INTL_NAMESPACE::ErrorCode::SUCCESS)
{
UE_LOG(LogTemp, Warning, TEXT("LI query bind info success bindlist = %s"), *AuthResult.BindList);
TArray <TSharedPtr<FJsonValue>> bindInfoArray;
TSharedRef<TJsonReader<TCHAR>>jsonReader = TJsonReaderFactory<TCHAR>::Create(AuthResult.BindList);
bool isSe = FJsonSerializer::Deserialize(jsonReader, bindInfoArray);
if (isSe)
{
UE_LOG(LogTemp, Warning, TEXT("LI query bind info format JsonObject success"));
bool haveBindLI = false;
FString liEmail;
for(int i = 0; i < bindInfoArray.Num(); i++)
{
int32 channelId = bindInfoArray[i]->AsObject()->GetIntegerField("channelid");
FString email = bindInfoArray[i]->AsObject()->GetStringField("email");
UE_LOG(LogTemp, Warning, TEXT("LI query bind info channelId = %d, email = %s"), channelId, *email);
if(channelId == (int32)EINTLLoginChannel::kChannelLevelInfinite) {
haveBindLI = true;
liEmail = email;
break;
}
}
if(!haveBindLI) {
// 打开游戏内绑定的页面
ULevelInfiniteAPI::OpenBindAccount();
} else {
// 当前用户已绑定 LI PASS,无需进行后续的引导绑定操作
UE_LOG(LogTemp, Warning, TEXT("Account have bind LI"));
}
} else {
UE_LOG(LogTemp, Warning, TEXT("LI query bind info format JsonObject failed"));
}
}else{
UE_LOG(LogTemp, Warning, TEXT("LI query bind info failed, ret_code = %d, ret_msg = %s"), AuthResult.RetCode, *AuthResult.RetMsg);
// token失效的情况
FINTLAuthResult CurrentAuthResult;
if (UINTLSDKAPI::GetAuthResult(CurrentAuthResult)) {
EINTLLoginChannel channel = static_cast<EINTLLoginChannel>(CurrentAuthResult.ChannelID);
if (channel == EINTLLoginChannel::kChannelPS5) {
FString permissions = "psn:s2s openid id_token:psn.basic_claims";
ULevelInfiniteAPI::LoginChannelWithLIPass(channel, permissions, "{}");
} else if (channel == EINTLLoginChannel::kChannelXbox) {
ULevelInfiniteAPI::LoginChannelWithLIPass(channel, "", "{}");
} else {
ULevelInfiniteAPI::LoginChannelWithLIPass(channel, "", "{}");
}
}
}
}
}
功能示例:

使用 Web 组件完成 Web 端登录流程
LI PASS Web 组件具备登录、注册、绑定及预约功能,并支持同一业务(即 GAME_ID)下多套配置,可以满足您在各种网页场景的 LI PASS 以及第三方渠道的账号需求,与游戏客户端内账号互通。
只需几行代码就可完成接入,让您的网页无须再逐一接入 API,告别自行搭建交互和 UI。
推荐使用 Player Network 控制台 配置 Web 组件 功能,配置更简单、更新更灵活。
已通过代码形式配置的业务,可前往 Player Network 控制台新增 Web 端配置,从控制台下发的配置将覆盖网页的代码配置。
如有疑问,请联系 Player Network 助手。
步骤1:引入 SDK
从 CDN
安装 Web SDK。
// SDK 联调版本包
<script src="https://test-common-web.intlgame.com/sdk-cdn/infinite-pass/latest/index.umd.js"></script>
<link rel="stylesheet" href="https://test-common-web.intlgame.com/sdk-cdn/infinite-pass/latest/index.css" />
// SDK 正式版本包
<script src="https://common-web.intlgame.com/sdk-cdn/infinite-pass/latest/index.umd.js"></script>
<link rel="stylesheet" href="https://common-web.intlgame.com/sdk-cdn/infinite-pass/latest/index.css" />