虚幻引擎 SDK - 支持深度链接

文件

添加深度链接支持

深度链接可引导用户访问应用程序中的特定内容。当用户在已安装应用的设备上点击深层链接时,应用会直接打开到目标内容,如产品页面或特定体验。

奇异跟踪链接支持标准深度链接(适用于已安装的应用)和延迟深度链接(适用于新安装的应用)。有关详细信息,请参阅深度链接常见问题解答奇异链接常见问题解答


要求

先决条件

完成Singular Links 先决条件,以启用 iOS 和 Android 平台的深度链接。

注意

  • 本指南假定您的组织正在使用Singular Links- Singular 于 2019 年推出的跟踪链接技术。老客户可能正在使用传统的跟踪链接。
  • 您应用程序的深度链接目的地需要在 Singular 的应用程序页面上进行配置(请参阅配置深度链接 URL)。

SDK 配置

实施 Singular 链接处理程序

Singular SDK 提供了一种基于委托的处理机制,用于在应用程序打开时从 Singular 跟踪链接获取深度链接、延迟深度链接和直通参数。

可用参数

  • 深度链接:用户点击链接时应用程序中的目标 URL(在 "管理链接 "页面中配置)。
  • 传递:通过跟踪链接传递的自定义数据,用于附加上下文或营销活动元数据。
  • IsDeferred(是否延迟):表示链接是否为延迟深度链接(新安装为 true,现有安装为 false)。

在应用程序中添加深度链接处理程序

配置深层链接处理程序,以便在应用启动时处理传入的深层链接数据。这必须在初始化 Singular SDK 之前完成。

实施步骤

  1. 在类头文件中添加所需的 Singular 包含项。
  2. 实现一个方法来处理OnSingularLinksResolved回调。
  3. 在 SDK 初始化前创建并注册USingularDelegates对象。
  4. 使用OnSingularLinksResolved.AddDynamic() 注册处理程序方法。
  5. 在处理程序方法中处理深层链接参数。
C++
// Add to the include section of your class header
#include "SingularLinkParams.h"
#include "SingularDelegates.h"

// In your class header, declare the handler method
UFUNCTION()
void OnSingularLinksResolved(const FSingularLinkParams& LinkParams);

// In your class implementation file, implement the handler method
void UYourGameInstance::OnSingularLinksResolved(const FSingularLinkParams& LinkParams)
{
    // Extract parameters from the tracking link
    const FString Deeplink = LinkParams.SingularLinksParams["deeplink"];
    const FString Passthrough = LinkParams.SingularLinksParams["passthrough"];
    const bool IsDeferred = LinkParams.SingularLinksParams["isDeferred"] == "true";

    // Log the parameters
    UE_LOG(LogTemp, Log, TEXT("Deep Link Resolved"));
    UE_LOG(LogTemp, Log, TEXT("Deeplink: %s"), *Deeplink);
    UE_LOG(LogTemp, Log, TEXT("Passthrough: %s"), *Passthrough);
    UE_LOG(LogTemp, Log, TEXT("Is Deferred: %s"), IsDeferred ? TEXT("true") : TEXT("false"));

    // Handle deep link routing
    if (!Deeplink.IsEmpty())
    {
        HandleDeepLinkNavigation(Deeplink, IsDeferred);
    }
}

void UYourGameInstance::HandleDeepLinkNavigation(const FString& Url, bool IsDeferred)
{
    // Your deep link routing logic
    UE_LOG(LogTemp, Log, TEXT("Routing to: %s (Deferred: %s)"), 
           *Url, IsDeferred ? TEXT("true") : TEXT("false"));

    // Example: Parse the URL and navigate to appropriate content
    if (Url.Contains(TEXT("product")))
    {
        NavigateToProduct(Url);
    }
    else if (Url.Contains(TEXT("promo")))
    {
        NavigateToPromotion(Url);
    }
    else
    {
        NavigateToHome();
    }
}

// Register the delegate BEFORE initializing the Singular SDK
void UYourGameInstance::InitializeSingular()
{
    // Create the delegates object
    USingularDelegates* SingularDelegates = 
        CreateDefaultSubobject<USingularDelegates>(TEXT("SingularLinksHandler"));

    // Register the deep link handler
    SingularDelegates->OnSingularLinksResolved.AddDynamic(
        this, 
        &UYourGameInstance::OnSingularLinksResolved
    );

    UE_LOG(LogTemp, Log, TEXT("Singular Link Handler registered"));

    // Now initialize the SDK
    bool Success = USingularSDKBPLibrary::Initialize(
        TEXT("YOUR_SDK_KEY"),
        TEXT("YOUR_SDK_SECRET"),
        60,    // Session timeout
        TEXT(""),    // Custom user ID
        true,  // Enable SKAdNetwork
        false, // Manual SKAN management
        0,     // Wait for tracking authorization
        false, // OAID collection
        true,  // Enable logging
        3,     // Log level
        false, // Clipboard attribution
        TEXT(""),    // Facebook App ID
        TEXT("")     // Custom SDID
    );

    if (Success)
    {
        UE_LOG(LogTemp, Log, TEXT("Singular SDK initialized successfully"));
    }
}

重要:必须在调用USingularSDKBPLibrary::Initialize()之前注册委托。如果在初始化后注册处理程序,它将无法接收深度链接回调。


处理程序行为

了解深度链接解析

当用户点击奇异链接时,深层链接处理程序会根据应用程序是刚安装还是已安装而有不同的行为。

全新安装(延迟深度链接)

刚安装时,应用程序启动时不存在打开 URL。Singular 会完成归因,以确定跟踪链接是否包含深度链接值。

延迟深度链接流程

  1. 用户点击配置了深度链接值的 Singular 跟踪链接。
  2. 用户安装并首次打开应用程序。
  3. Singular SDK 向 Singular 服务器发送第一个会话。
  4. 归因完成并从跟踪链接中识别深层链接。
  5. 深层链接值返回处理程序IsDeferred = true

测试延迟深度链接

  1. 从测试设备上卸载应用程序(如果当前已安装)。
  2. iOS:重置您的 IDFA。Android:重置 Google Advertising ID (GAID)。
  3. 点击设备上的 Singular 跟踪链接(确保配置了深度链接值)。
  4. 安装并打开应用程序。

归因应成功完成,延迟的深度链接值将传递给您的处理程序。

开发测试提示:在使用不同软件包名称或捆绑 ID 的开发构建测试深度链接时,请专门为开发应用的标识符配置跟踪链接。点击测试链接后,通过虚幻引擎或特定于平台的工具将开发构建直接安装到设备上,而不是从应用商店下载生产应用。


已安装(即时深度链接)

当应用程序已安装时,点击奇异链接可使用通用链接(iOS)或安卓应用程序链接技术立即打开应用程序。

即时深度链接流程

  1. 用户点击 Singular 跟踪链接。
  2. 操作系统会提供一个包含整个 Singular 跟踪链接的开放 URL。
  3. 在 SDK 初始化过程中,Singular 会解析该 URL。
  4. Singular 会提取deeplinkpassthrough值。
  5. 通过处理程序返回的值为IsDeferred = false

直通参数

使用用于营销活动元数据、用户细分或自定义信息的直通参数,从跟踪链接点击中获取其他数据。

如果跟踪链接中包含passthrough (_p) 参数,处理程序的Passthrough 参数就会包含相应数据。

C++
void UYourGameInstance::OnSingularLinksResolved(const FSingularLinkParams& LinkParams)
{
    // Extract passthrough data
    const FString PassthroughData = LinkParams.SingularLinksParams["passthrough"];

    if (!PassthroughData.IsEmpty())
    {
        // Parse JSON passthrough data
        TSharedPtr<FJsonObject> JsonObject;
        TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(PassthroughData);

        if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
        {
            // Extract campaign metadata
            FString CampaignId;
            if (JsonObject->TryGetStringField(TEXT("campaign_id"), CampaignId))
            {
                UE_LOG(LogTemp, Log, TEXT("Campaign ID: %s"), *CampaignId);
            }

            FString UserSegment;
            if (JsonObject->TryGetStringField(TEXT("segment"), UserSegment))
            {
                UE_LOG(LogTemp, Log, TEXT("User Segment: %s"), *UserSegment);
            }

            FString PromoCode;
            if (JsonObject->TryGetStringField(TEXT("promo_code"), PromoCode))
            {
                UE_LOG(LogTemp, Log, TEXT("Promo Code: %s"), *PromoCode);
                ApplyPromoCode(PromoCode);
            }

            // Use the data in your app
            ApplyCampaignSettings(CampaignId, UserSegment);
        }
        else
        {
            UE_LOG(LogTemp, Warning, TEXT("Failed to parse passthrough data"));
        }
    }
}

void UYourGameInstance::ApplyCampaignSettings(const FString& CampaignId, const FString& Segment)
{
    // Your campaign-specific logic
    UE_LOG(LogTemp, Log, TEXT("Applying campaign settings for: %s (Segment: %s)"), 
           *CampaignId, *Segment);
}

直通 URL 示例:
https://yourapp.sng.link/A1b2c/abc123?_dl=myapp://product/123&_p={"campaign_id":"summer2025","segment":"premium","promo_code":"SAVE20"}

处理程序将接收passthrough 参数,该参数包含包含营销活动元数据的 JSON 字符串。


FSingularLinkParams 参考

参数详细信息

FSingularLinkParams 对象包含传递给深度链接处理程序的跟踪链接详细信息。

参数 类型 说明
deeplink FString 在 Singular 的 "管理链接 "页面中配置的深度链接目标 URL。该值将用户导向特定的应用内内容。
passthrough FString 添加到跟踪链接的直通参数,通常用于活动元数据、用户细分或应用程序需要处理的自定义数据。
isDeferred bool 表示链接是否配置为延迟深度链接。对于新安装(延迟),返回true ;对于现有安装(即时),返回false

方法签名

C++
// Callback method signature for Singular Links
void OnSingularLinksResolved(const FSingularLinkParams& linkParams)

// Access parameters using the SingularLinksParams map:
const FString Deeplink = linkParams.SingularLinksParams["deeplink"];
const FString Passthrough = linkParams.SingularLinksParams["passthrough"];
const bool IsDeferred = linkParams.SingularLinksParams["isDeferred"] == "true";

深度链接路由实现

构建深度链接路由器

实施集中式深度链接路由系统,根据深度链接 URL 结构将用户导航到特定内容。

C++
// Deep Link Router class implementation
class UDeepLinkRouter : public UObject
{
public:
    void RouteDeepLink(const FString& DeepLinkUrl, bool IsDeferred)
    {
        UE_LOG(LogTemp, Log, TEXT("Routing deep link: %s (Deferred: %s)"), 
               *DeepLinkUrl, IsDeferred ? TEXT("true") : TEXT("false"));

        // Parse the URL scheme
        if (DeepLinkUrl.StartsWith(TEXT("myapp://product/")))
        {
            FString ProductId = ExtractParameter(DeepLinkUrl, TEXT("myapp://product/"));
            NavigateToProduct(ProductId);
        }
        else if (DeepLinkUrl.StartsWith(TEXT("myapp://category/")))
        {
            FString CategoryName = ExtractParameter(DeepLinkUrl, TEXT("myapp://category/"));
            NavigateToCategory(CategoryName);
        }
        else if (DeepLinkUrl.StartsWith(TEXT("myapp://promo")))
        {
            NavigateToPromotions();
        }
        else if (DeepLinkUrl.StartsWith(TEXT("myapp://profile")))
        {
            NavigateToUserProfile();
        }
        else
        {
            // Default fallback
            UE_LOG(LogTemp, Warning, TEXT("Unknown deep link format, navigating to home"));
            NavigateToHome();
        }

        // Track deep link usage
        TrackDeepLinkEvent(DeepLinkUrl, IsDeferred);
    }

private:
    FString ExtractParameter(const FString& Url, const FString& Prefix)
    {
        FString Param;
        if (Url.Split(Prefix, nullptr, &Param))
        {
            // Remove query parameters if present
            FString CleanParam;
            if (Param.Split(TEXT("?"), &CleanParam, nullptr))
            {
                return CleanParam;
            }
            return Param;
        }
        return FString();
    }

    void NavigateToProduct(const FString& ProductId)
    {
        UE_LOG(LogTemp, Log, TEXT("Navigating to product: %s"), *ProductId);
        // Your product screen navigation logic
    }

    void NavigateToCategory(const FString& CategoryName)
    {
        UE_LOG(LogTemp, Log, TEXT("Navigating to category: %s"), *CategoryName);
        // Your category screen navigation logic
    }

    void NavigateToPromotions()
    {
        UE_LOG(LogTemp, Log, TEXT("Navigating to promotions"));
        // Your promotions screen navigation logic
    }

    void NavigateToUserProfile()
    {
        UE_LOG(LogTemp, Log, TEXT("Navigating to user profile"));
        // Your profile screen navigation logic
    }

    void NavigateToHome()
    {
        UE_LOG(LogTemp, Log, TEXT("Navigating to home screen"));
        // Your home screen navigation logic
    }

    void TrackDeepLinkEvent(const FString& DeepLink, bool IsDeferred)
    {
        // Track deep link usage with Singular
        TMap<FString, FString> EventAttributes;
        EventAttributes.Add(TEXT("deep_link_url"), DeepLink);
        EventAttributes.Add(TEXT("is_deferred"), IsDeferred ? TEXT("true") : TEXT("false"));

        USingularSDKBPLibrary::EventWithAttributes(
            TEXT("deep_link_opened"), 
            EventAttributes
        );
    }
};

最佳实践:将深度链接打开作为 Singular 中的自定义事件进行跟踪,以衡量深度链接营销活动的效果,了解哪些内容的参与度最高。


重要注意事项

实施注意事项

  • 注册时间:始终在初始化 Singular SDK之前注册深层链接处理程序。处理程序必须在 SDK 处理跟踪链接之前就位。
  • 线程安全:处理程序回调可能会在后台线程上执行。确保使用虚幻引擎的线程安全机制将任何 UI 更新或导航逻辑分派给游戏线程。
  • URL 方案:为您的深层链接设计一致的 URL 方案(例如myapp://product/,myapp://category/ ),以简化路由逻辑和维护。
  • 回退处理:对于无法识别或畸形的深度链接,应始终实施回退导航(通常是返回主屏幕),以防止应用程序崩溃或用户体验不佳。
  • 测试两种流程:同时测试即时深度链接(已安装应用)和延迟深度链接(全新安装),以确保在所有情况下都能正确处理。
  • 参数验证:在使用深层链接之前,验证从深层链接中提取的所有参数,以防止恶意或畸形 URL 导致的安全问题或崩溃。
  • 平台配置:完成特定平台配置(iOS 通用链接、Android 应用链接),详见奇异链接先决条件指南。

生产检查表:在启动深度链接营销活动之前,请验证:(1)在 SDK 初始化之前注册了处理程序;(2)完成了特定平台的配置;(3)在 Singular 面板中配置了深度链接;(4)路由逻辑处理了所有预期的 URL 模式;(5)成功测试了即时流和延迟流。


其他资源