搜索插件、代码仓与 APP 分类

插件详情v2.2.0

flutter_redirectly

一个用于 Redirectly 动态链接的 Flutter 插件——类似于 Firebase 动态链接,但使用您自己的后端。

AndroidiOSmacOSWindowsLinux
近 30 天下载
69
喜欢数
24
Pub 分数
150

安装插件

flutter pub add flutter_redirectly

插件介绍

基于插件公开信息、社区数据与项目使用情况整理的选型参考。

flutter_redirectly 是一个 Flutter 插件,使用您自己的后端实现动态链接功能,是 Firebase 动态链接的替代方案。它支持跨 Android、iOS、macOS、Windows 和 Linux 平台的深度链接,可根据自定义逻辑实现无缝用户重定向。该插件简化了对传入链接的处理,并提供了用于程序化跟踪和管理重定向的工具。非常适合需要完全控制链接行为且不依赖第三方服务的应用。

适合场景

  • 处理自定义深度链接
  • 实施推荐跟踪
  • 使用自定义后端管理应用重定向
  • 启用跨平台链接共享
  • 支持离线链接解析

主要特点

  • 自托管动态链接
  • 跨平台支持
  • 自定义后端集成
  • 链接跟踪和分析
  • 用于重定向处理的简单 API

适合对象

  • 寻找 Firebase 替代方案的开发者
  • 需要自定义链接逻辑的应用
  • 具有现有后端基础设施的项目
  • 希望完全控制链接管理的团队
  • 跨平台应用程序

使用建议

  • 需要设置自定义后端
  • 需要正确的SSL配置
  • 手动处理链接过期
  • 与 Firebase 相比,内置分析功能有限
  • 需要额外的服务器端开发

原始 README

以下为关联源码仓库的 README 原文快照,最新内容请访问源码仓库。

Flutter Redirectly

A Flutter package for creating and handling dynamic links using your own Redirectly backend.

Installation

dependencies:
  flutter_redirectly: ^2.1.1

Quick Setup

1. Get Your API Key

Get your free API key from redirectly.app - sign up and create your subdomain to get started.

2. Configure Deep Links

Android - Add to android/app/src/main/AndroidManifest.xml:

<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="https" android:host="YOUR_SUBDOMAIN.redirectly.app" />
</intent-filter>

iOS - Add Associated Domains to ios/Runner/Runner.entitlements:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.developer.associated-domains</key>
    <array>
        <string>applinks:YOUR_SUBDOMAIN.redirectly.app</string>
    </array>
</dict>
</plist>

If this file doesn't exist, create it. Also ensure your app is properly signed and the Associated Domains capability is enabled in your Apple Developer account.

3. Initialize
import 'package:flutter_redirectly/flutter_redirectly.dart';

final redirectly = FlutterRedirectly();

await redirectly.initialize(RedirectlyConfig(
  apiKey: 'your-api-key-here',
  debug: true,
));
4. Handle Links
// Listen for incoming links
redirectly.onLinkClick.listen((linkClick) {
  print('Link: ${linkClick.originalUrl}');
  print('Slug: ${linkClick.slug}');
  
});

// Handle app launch from link
final initialLink = await redirectly.getInitialLink();
if (initialLink != null) {
  // Handle same as above
}
5. Track App Installs

The plugin automatically tracks app installs on first launch. Listen for install attribution events:

// Listen for app install events
redirectly.onAppInstalled.listen((installEvent) {
  if (installEvent.matched) {
    // User installed app after clicking a Redirectly link
    print('Install attributed to: ${installEvent.username}/${installEvent.slug}');
    print('Original click time: ${installEvent.clickedAt}');
    
    // Show personalized onboarding or deep link to specific content
    _handleAttributedInstall(installEvent);
  } else {
    // Organic install (no prior link click)
    print('Organic app install');
    _handleOrganicInstall();
  }
});

void _handleAttributedInstall(RedirectlyAppInstallResponse install) {
  // Example: Navigate to the content they were trying to reach
  if (install.linkResolution != null) {
    final target = install.linkResolution!.target;
    // Navigate to target URL or handle accordingly
  }
}

What gets tracked:

  • First app launch only (subsequent launches are ignored)
  • Device information (OS, version, timezone, language)
  • App information (version, build number)
  • Attribution matching with prior link clicks (if any)

Privacy-friendly:

  • No personal information is collected
  • Only standard app/device metadata
  • Tracking file prevents duplicate logging
  • All data stays within your Redirectly account
Deterministic Android attribution (Install Referrer)

Deferred deep link attribution used to match installs to prior link clicks only with a server side fingerprint (IP address and IP derived geo data). That match breaks when the device's IP changes between the link click and the first app launch, for example when switching from WiFi to cellular.

Since 2.2.0 the SDK makes Android attribution deterministic automatically. When Redirectly redirects a user to the Play Store, it embeds the click identifier in the Google Play Install Referrer; on the first launch the SDK reads it back (via the bundled play_install_referrer plugin) and the backend matches the exact click, regardless of IP changes. No setup is required.

Notes:

  • The referrer is read once, on the first launch install tracking call, and only on Android. On iOS, when Google Play Services are unavailable, or when the read fails or takes longer than 5 seconds, the SDK simply omits the referrer and the backend falls back to fingerprint matching.
  • Organic installs carry no Redirectly referrer and are reported as organic, as before.
  • If you need a custom referrer source, the optional installReferrerProvider callback in RedirectlyConfig overrides the built-in read:
await redirectly.initialize(RedirectlyConfig(
  apiKey: 'your-api-key-here',
  installReferrerProvider: () async => myCustomReferrerSource(),
));
6. Create Links
// Create a permanent link
final link = await redirectly.createLink(
  slug: 'my-link',
  target: 'https://example.com',
);
print('Created: ${link.url}');

// Create a temporary link (expires in 1 hour)
final tempLink = await redirectly.createTempLink(
  target: 'https://example.com',
  ttlSeconds: 3600,
);
print('Temp link: ${tempLink.url}');

Complete Attribution Flow

Here's how to implement a complete attribution flow:

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final redirectly = FlutterRedirectly();
  
  @override
  void initState() {
    super.initState();
    _initializeRedirectly();
  }
  
  Future<void> _initializeRedirectly() async {
    await redirectly.initialize(RedirectlyConfig(
      apiKey: 'your-api-key',
      debug: true,
    ));
    
    // Handle ongoing link clicks
    redirectly.onLinkClick.listen(_handleLinkClick);
    
    // Handle app install attribution
    redirectly.onAppInstalled.listen(_handleAppInstall);
    
    // Handle initial link if app was opened via link
    final initialLink = await redirectly.getInitialLink();
    if (initialLink != null) {
      _handleLinkClick(initialLink);
    }
  }
  
  void _handleLinkClick(RedirectlyLinkClick linkClick) {
    print('Link clicked: ${linkClick.slug}');
    
    if (linkClick.linkResolution != null) {
      // Navigate based on link target
      _navigateToTarget(linkClick.linkResolution!.target);
    }
  }
  
  void _handleAppInstall(RedirectlyAppInstallResponse install) {
    if (install.matched) {
      // Show attributed install welcome
      _showAttributedWelcome(install);
    } else {
      // Show standard onboarding
      _showStandardOnboarding();
    }
  }
  
  void _showAttributedWelcome(RedirectlyAppInstallResponse install) {
    // Example: Show personalized welcome message
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Welcome!'),
        content: Text('Thanks for installing from our ${install.slug} link!'),
        actions: [
          TextButton(
            onPressed: () {
              Navigator.of(context).pop();
              // Navigate to the content they were originally trying to reach
              if (install.linkResolution != null) {
                _navigateToTarget(install.linkResolution!.target);
              }
            },
            child: Text('Get Started'),
          ),
        ],
      ),
    );
  }
  
  void _navigateToTarget(String target) {
    // Handle navigation based on your app's routing
    print('Navigating to: $target');
  }
}

Error Handling

try {
  final link = await redirectly.createLink(slug: 'test', target: 'https://example.com');
} on RedirectlyError catch (e) {
  print('Error: ${e.message}');
}

API Reference

Configuration
RedirectlyConfig({
  required String apiKey,     // Your API key
  bool enableDebugLogging,   // Optional: debug mode
  InstallReferrerProvider? installReferrerProvider,
  // Optional override for the built-in Play Install Referrer read
  // (see section 5); omit it to use the bundled plugin automatically
})
Models
// Permanent link
RedirectlyLink({
  String id, slug, target, url,
  int clickCount,
  DateTime createdAt,
  Map<String, dynamic>? metadata,
})

// Temporary link  
RedirectlyTempLink({
  String id, slug, target, url,
  int ttlSeconds,
  DateTime expiresAt, createdAt,
})

// Link click event
RedirectlyLinkClick({
  String originalUrl, slug, username,
  DateTime receivedAt,
  RedirectlyError? error,
})

// App install attribution
RedirectlyAppInstallResponse({
  bool matched,              // Whether install was attributed to a link
  String? username, slug,    // Attribution details (if matched)
  DateTime? clickedAt,       // When original link was clicked (if matched)
  RedirectlyLinkResolution? linkResolution, // Original link details
  DateTime loggedAt,         // When install was logged
})
Streams
// Listen for link clicks (app running or launch)
Stream<RedirectlyLinkClick> redirectly.onLinkClick

// Listen for app install events (first launch only)
Stream<RedirectlyAppInstallResponse> redirectly.onAppInstalled

Testing Install Attribution

During development, you can test install attribution by:

  1. Delete and reinstall your app to simulate first install
  2. Clear app data on Android or delete from device on iOS
  3. Click a Redirectly link → install app → open app
  4. The onAppInstalled event should fire with matched: true

The plugin automatically prevents duplicate install logging by creating a tracking file on first launch.

Example

See the example app for a complete implementation.

Support

License

MIT License - see LICENSE file.

所属分类

依赖

依赖清单 6 项

源码仓库

使用此插件的项目

暂无相关数据。