You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无需第三方SDK,Flutter延迟深度链接参数丢失解决方案咨询

自定义Flutter延迟深度链接解决方案(无第三方依赖)

针对你遇到的「应用未安装时跳转商店后深度链接参数丢失」问题,以下是一套完全自定义的实现方案,分为网页端、Android端、iOS端、Flutter统一处理四个部分:

核心思路

通过后端临时存储深度链接参数,配合平台专属的安装归因机制,在应用首次启动时恢复参数:

  1. 网页端捕获深度链接,生成唯一UUID,将参数与UUID绑定存储到后端(设7天过期)
  2. 跳转应用商店时携带UUID
  3. 应用安装后首次启动,通过平台API获取UUID,请求后端取回深度链接参数并处理

1. 网页端实现

// 检测应用是否已安装并处理跳转
function handleDeeplink() {
  const currentDeeplink = window.location.href;
  const appSchemeUrl = `yourapp://${new URL(currentDeeplink).pathname}${new URL(currentDeeplink).search}`;
  const uuid = self.crypto.randomUUID(); // 生成唯一标识

  // 先尝试打开应用
  window.location.href = appSchemeUrl;

  // 1秒后未跳转则进入商店逻辑
  setTimeout(() => {
    // 把深度链接参数和UUID存到后端(这里用fetch示例)
    fetch('https://your-backend.com/api/save-deeplink', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({uuid, deeplink: currentDeeplink})
    });

    // 跳转对应商店,携带UUID
    const storeUrl = /Android/i.test(navigator.userAgent)
      ? `https://play.google.com/store/apps/details?id=com.your.app.id&referrer=${uuid}`
      : `https://apps.apple.com/us/app/your-app-name/id1234567890?cid=${uuid}`;
    
    // 同时把参数存在本地存储,作为iOS端的备用方案
    localStorage.setItem('pending_deeplink', currentDeeplink);
    window.location.href = storeUrl;
  }, 1000);
}

2. Android端实现

利用Google Play Referrer API获取安装时携带的UUID,再请求后端取回参数:

步骤1:集成依赖

在android/app/build.gradle中添加:

dependencies {
  implementation 'com.android.installreferrer:installreferrer:2.2'
}

步骤2:Flutter端调用获取Referrer

使用google_play_referrer插件简化调用:

import 'package:google_play_referrer/google_play_referrer.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

Future<void> restoreAndroidDeeplink() async {
  final referrerDetails = await GooglePlayReferrer.installReferrer;
  final uuid = referrerDetails.referrer;
  
  if (uuid != null && uuid.isNotEmpty) {
    // 请求后端获取深度链接
    final response = await http.get(Uri.parse('https://your-backend.com/api/get-deeplink?uuid=$uuid'));
    if (response.statusCode == 200) {
      final data = jsonDecode(response.body);
      final deeplink = data['deeplink'];
      // 用你已集成的app_link处理链接
      await AppLink().processLink(Uri.parse(deeplink));
      // 通知后端标记该UUID已使用,避免重复处理
      await http.post(Uri.parse('https://your-backend.com/api/mark-used'), body: {'uuid': uuid});
    }
  }
}

3. iOS端实现

iOS无法直接获取商店跳转参数,采用「透明WebView读取网页本地存储」的方案:

Flutter端代码

在应用首次启动时加载专用页面,读取网页存储的参数:

import 'package:webview_flutter/webview_flutter.dart';
import 'package:flutter/material.dart';

Future<void> restoreIOSDeeplink(BuildContext context) async {
  final webViewController = WebViewController()
    ..loadRequest(Uri.parse('https://your-redirect-page.com/fetch-deeplink'))
    ..setJavaScriptMode(JavaScriptMode.unrestricted)
    ..addJavaScriptChannel(
      'DeeplinkChannel',
      onMessageReceived: (JavaScriptMessage message) {
        final deeplink = message.message;
        if (deeplink.isNotEmpty) {
          // 处理深度链接
          AppLink().processLink(Uri.parse(deeplink));
        }
        Navigator.pop(context); // 关闭透明WebView
      },
    );

  // 显示透明WebView,获取参数后自动关闭
  showDialog(
    context: context,
    barrierDismissible: false,
    builder: (_) => Dialog(
      backgroundColor: Colors.transparent,
      child: SizedBox(height: 0, width: 0, child: WebViewWidget(controller: webViewController)),
    ),
  );
}

网页端fetch-deeplink页面代码

<script>
window.addEventListener('load', () => {
  const deeplink = localStorage.getItem('pending_deeplink');
  if (deeplink) {
    window.DeeplinkChannel.postMessage(deeplink);
    localStorage.removeItem('pending_deeplink'); // 清除已处理的参数
  }
  setTimeout(() => window.close(), 500); // 确保参数传递完成
});
</script>

4. Flutter统一启动逻辑

在应用入口处理首次启动的参数恢复:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:io';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final prefs = await SharedPreferences.getInstance();
  final isFirstLaunch = prefs.getBool('is_first_launch') ?? true;

  if (isFirstLaunch) {
    // 根据平台处理参数恢复
    if (Platform.isAndroid) {
      await restoreAndroidDeeplink();
    } else if (Platform.isIOS) {
      // 需在MaterialApp context中调用,可延迟到首页initState处理
    }
    await prefs.setBool('is_first_launch', false);
  }

  runApp(const MyApp());
}

关键注意事项

  • 后端存储需设置过期时间(建议7天),定期清理无效数据
  • Android端需确保Referrer API权限配置正确,避免被广告拦截工具影响
  • iOS端需在Info.plist中添加网页域名的权限,允许WebView访问
  • 处理参数后需标记为已使用,防止应用重复触发跳转逻辑

内容的提问来源于stack exchange,提问作者Taniksha Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 19:23:14