Flutter SDK - リファラーショートリンクのサポート

ドキュメント

短いリファラーリンクの作成

ユーザー間のアトリビューションを可能にし、オーガニックな紹介からのアプリのインストールを追跡する、共有可能な短いリファラーリンクを生成します。

バージョン要件この機能を使用するには、SDKバージョン1.0.7以降が必要です。短いリンクは、作成後30日間有効です。

概要

ショートリファラーリンクとは

ショートリンクは、長い、パラメータいっぱいのシンギュラーリンクを、SMS、ソーシャルメディア、アプリ内招待で共有するのに便利な、コンパクトで安全なURLに変換します。

ショートリンクを動的に作成することで、ユーザーがお友達と共有し、アプリのダウンロードや使用を招待することができます。各ショートリンクは参照ユーザーを追跡するので、バイラルの成長を測定し、新規インストールを特定の支持者に帰属させることができます。


実装要件

必要なコンポーネント

ショートリファラーリンクを作成する前に、これらの要素を集めてください:

  • 単一リンク:アプリのダウンロードにユーザーを誘導するベーストラッキングリンク。設定方法については、シンギュラーリンクのFAQを参照してください。
  • 動的パラメータ:リンクにコンテキストを追加するオプションのカスタムパラメータ。トラッキングリンクパラメータで利用可能なオプションを見る
  • リファラー情報:リンクを共有するユーザーの名前と ID を入力して、新規インストールのリファラーへの帰属を可能にします。

SDKメソッド

CreateReferrerShortLink

カスタムパラメータと成功およびエラー状態のコールバックハンドラを使用して、短いリファラーリンクを生成します。

メソッドのシグネチャ

static void createReferrerShortLink(
  String baseLink,
  String referrerName,
  String referrerId,
  Map<String, String> passthroughParams,
  void Function(String? shortLinkURL, String? error) completionHandler
)

パラメータ

  • baseLink:元の Singular トラッキングリンクの URL。
  • referrerName:参照元ユーザーの表示名
  • referrerId:参照元ユーザーの一意な識別子
  • passthroughParams:追加の動的パラメータを含むマップ (ない場合は空のマップを渡す)
  • completionHandler:パラメータを含むコールバック関数(String? shortLinkURL, String? error)

メソッドの完全なドキュメントについてはcreateReferrerShortLink のリファレンスを参照ください。


基本的な使用例

カスタムパラメータでショートリンクを作成し、 成功コールバックで共有ロジックを実装します。

Dart
import 'package:flutter/material.dart';
import 'package:singular_flutter_sdk/singular.dart';
import 'package:share_plus/share_plus.dart';

class ReferralScreen extends StatelessWidget {
  void handleShareReferral() {
    // Create custom parameters for the link
    final parameters = {
      'channel': 'sms',
      'campaign_id': 'summer_promo_2025',
      'referral_type': 'friend_invite'
    };

    // Generate the short referrer link
    Singular.createReferrerShortLink(
      'https://sample.sng.link/D52wc/cuvk?pcn=test',  // Base Singular Link
      'John Doe',                                      // Referrer name
      'user_12345',                                    // Referrer ID
      parameters,                                      // Custom parameters
      (shortLink, error) {
        if (error != null) {
          // Error occurred during link creation
          print('Error creating short link: $error');
          _showErrorDialog('Failed to create share link. Please try again.');
        } else if (shortLink != null) {
          // Success - short link was created
          print('Generated short link: $shortLink');

          // Share the link using share_plus package
          shareLink(shortLink);
        }
      }
    );
  }

  void shareLink(String shortLink) {
    try {
      Share.share(
        'Join me on this awesome app! $shortLink',
        subject: 'App Invitation'
      );
      print('Link shared successfully');
    } catch (error) {
      print('Error sharing link: $error');
      _showErrorDialog('Failed to share link');
    }
  }

  void _showErrorDialog(String message) {
    // Your dialog implementation
    print('Error: $message');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Referral')),
      body: Center(
        child: ElevatedButton(
          onPressed: handleShareReferral,
          child: Text('Share Referral Link'),
        ),
      ),
    );
  }
}

高度な実装

再試行ロジック、ロード状態、クリップボードフォールバックを含む完全な紹介システムを実装します。

Dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:singular_flutter_sdk/singular.dart';
import 'package:share_plus/share_plus.dart';

class ReferralManager extends StatefulWidget {
  final String userId;
  final String userName;
  final String baseLink;

  const ReferralManager({
    Key? key,
    required this.userId,
    required this.userName,
    required this.baseLink,
  }) : super(key: key);

  @override
  _ReferralManagerState createState() => _ReferralManagerState();
}

class _ReferralManagerState extends State<ReferralManager> {
  bool _isGenerating = false;
  String? _lastGeneratedLink;

  Future<String> _generateShortLink({int retryCount = 0}) async {
    final parameters = {
      'channel': 'in_app',
      'campaign_id': 'organic_referral',
      'user_tier': 'premium',
      'referral_timestamp': DateTime.now().millisecondsSinceEpoch.toString()
    };

    final completer = Completer<String>();

    Singular.createReferrerShortLink(
      widget.baseLink,
      widget.userName,
      widget.userId,
      parameters,
      (shortLink, error) async {
        if (error != null) {
          // Retry logic with exponential backoff
          if (retryCount < 3) {
            final delay = Duration(seconds: (1 << retryCount)); // 1s, 2s, 4s
            print('Retrying in ${delay.inSeconds}s... (Attempt ${retryCount + 1}/3)');

            await Future.delayed(delay);
            try {
              final result = await _generateShortLink(retryCount: retryCount + 1);
              completer.complete(result);
            } catch (e) {
              completer.completeError(e);
            }
          } else {
            completer.completeError(Exception(error));
          }
        } else if (shortLink != null) {
          setState(() {
            _lastGeneratedLink = shortLink;
          });
          completer.complete(shortLink);
        } else {
          completer.completeError(Exception('Unknown error occurred'));
        }
      }
    );

    return completer.future;
  }

  Future<void> _handleShare() async {
    setState(() {
      _isGenerating = true;
    });

    try {
      final shortLink = await _generateShortLink();
      print('Short link generated: $shortLink');

      // Attempt to share
      await Share.share(
        '${widget.userName} invited you to join! $shortLink',
        subject: 'App Invitation from ${widget.userName}'
      );

      // Track share event
      Singular.event('referral_link_shared');
      print('Link shared successfully');
    } catch (error) {
      print('Error in share flow: $error');

      // Fallback: Copy to clipboard if available
      if (_lastGeneratedLink != null) {
        await Clipboard.setData(ClipboardData(text: _lastGeneratedLink!));
        _showDialog(
          'Link Copied',
          'Failed to share, but the referral link has been copied to your clipboard!',
        );
      } else {
        _showDialog(
          'Error',
          'Failed to generate referral link. Please check your connection and try again.',
        );
      }
    } finally {
      setState(() {
        _isGenerating = false;
      });
    }
  }

  Future<void> _copyToClipboard() async {
    if (_lastGeneratedLink != null) {
      await Clipboard.setData(ClipboardData(text: _lastGeneratedLink!));
      _showDialog('Copied!', 'Referral link copied to clipboard');
    } else {
      _showDialog('No Link', 'Please generate a link first');
    }
  }

  void _showDialog(String title, String message) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(title),
        content: Text(message),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: Text('OK'),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        if (_isGenerating)
          CircularProgressIndicator()
        else ...[
          ElevatedButton(
            onPressed: _handleShare,
            child: Text('Share Referral Link'),
          ),
          if (_lastGeneratedLink != null) ...[
            SizedBox(height: 16),
            OutlinedButton(
              onPressed: _copyToClipboard,
              child: Text('Copy Link'),
            ),
          ],
        ],
      ],
    );
  }
}

実装のベストプラクティス

エラー処理

ネットワーク障害、無効なパラメータ、またはサーバーの問題を管理するために、コールバックに堅牢なエラー処理を実装します。

  • 再試行ロジック:一過性のネットワークエラーに対する指数関数的バックオフを実装します。
  • ユーザー・フィードバック:リンク作成失敗時に明確なエラーメッセージを表示
  • フォールバック・オプション:代替共有方法の提供(例:短いリンク作成に失敗した場合、完全なシンギュラーリンクを共有する)
  • 検証:問題を早期に発見するために、createReferrerShortLink を呼び出す前にパラメータを検証します。

トラッキングと分析

リファラー情報を活用して、バイラルループを構築し、オーガニックな成長を測定する。

ベストプラクティス社内のユーザー識別システムと一致する一貫したリファラーIDを使用する。これにより、次のことが可能になります:

  • 新規インストールを特定の参照ユーザーに帰属させる。
  • 紹介に成功したユーザーに報酬を与える
  • バイラル係数とKファクターメトリクスの追跡
  • 最も価値のあるブランド支持者を特定

リンクの有効期限

共有戦略において、30日間のリンクライフサイクルを計画する。

重要:ショートリンクは30日で失効します。長期的なキャンペーンや永続的な共有機能の場合は、定期的に新しいショートリンクを生成するか、予備として完全なシンギュラーリンクを使用してください。


一般的な使用例

アプリ内紹介プログラム

パーソナライズされた紹介リンクを使って、ユーザーがアプリから直接友達を招待できるようにします。

  • 報酬システム:紹介者を追跡し、友達登録に成功したユーザーに報酬を与えます。
  • ソーシャル共有:SMS、WhatsApp、Eメール、ソーシャルメディア用のshare_plusパッケージと統合します。
  • パーソナライズされた招待:パーソナライズするために紹介者の名前を共有メッセージに含めることができます。

ユーザー生成コンテンツ

ユーザーが他のユーザーと共有したいコンテンツを作成した場合、共有可能なリンクを作成します。

  • コンテンツのアトリビューション:どのコンテンツが最もアプリのインストールを促進したかを追跡
  • クリエイターの認識:新規ユーザーをコンテンツ作成者に帰属させ、ゲーミフィケーションを実現します。
  • キャンペーンタグ付け:コンテンツの種類やカテゴリーに基づいた動的なパラメータを追加

イベント招待

どの出席者が新規ユーザーを連れてきたかを追跡するイベント招待用のユニークなリンクを生成します。

  • イベントコンテキスト:リンクパラメータにイベントIDと詳細を含める
  • 参加者のトラッキング:イベントからイベントへのバイラル拡散を測定
  • ネットワーク効果:コンバージョン率の高いイベントを特定