React Native SDK - 卸载跟踪

文档

卸载跟踪

通过将推送通知服务与 Singular SDK 集成,跟踪应用程序的卸载情况,以衡量用户留存率并优化重新参与活动。

重要:谷歌已于 2018 年 4 月弃用 GCM API。 所有安卓卸载跟踪实施均使用 Firebase Cloud Messaging (FCM)。

安卓卸载跟踪

前提条件

在 React Native 应用程序中实施卸载跟踪之前,请按照 "设置 Android 卸载跟踪 "指南在 Singular 平台中配置您的应用程序。


系统要求

卸载跟踪需要 Firebase Cloud Messaging 和特定的设备配置。

FCM 要求(源):

  • 安卓版本:设备必须运行 Android 4.1 (API 16) 或更高版本
  • Google Play 服务:设备必须安装 Google Play Store 应用程序
  • 模拟器支持:支持带有 Google API 的 Android 4.1 或更高版本模拟器
  • 分发:应用程序可在 Google Play Store 之外分发,同时仍支持卸载跟踪

注意:不支持的 Android 版本或没有 Google Play 服务的设备上的用户将不会被跟踪卸载。


实施步骤

第 1 步:安装 Firebase 软件包

为核心功能和消息支持添加 React Native Firebase 依赖项。

bash
npm install @react-native-firebase/app
npm install @react-native-firebase/messaging

第 2 步:配置 Firebase

将 Firebase 配置文件添加到您的 React Native Android 项目中。

  1. 在 Firebase 控制台项目中注册 Android 应用程序
  2. 下载google-services.json 并将其放入android/app/
  3. 确认 Firebase 消息传递依赖项已添加到您的项目中

有关详细设置说明,请参阅React Native Firebase Android 设置


第 3 步:请求通知权限

在获取 FCM 令牌之前,向用户申请通知权限(Android 13+ 需要)。

JavaScript
import messaging from '@react-native-firebase/messaging';
import { Platform, PermissionsAndroid } from 'react-native';

async function requestNotificationPermission() {
  if (Platform.OS === 'android') {
    if (Platform.Version >= 33) {
      // Android 13+ requires explicit permission request
      const granted = await PermissionsAndroid.request(
        PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
      );
      return granted === PermissionsAndroid.RESULTS.GRANTED;
    }
    // Android 12 and below automatically have permission
    return true;
  }

  // iOS permission handled separately
  return true;
}

第 4 步:获取并注册 FCM 令牌

请求权限后,使用setUninstallToken() 获取 FCM 设备令牌并在 Singular 注册。

New ArchitectureOld Achitecture
// TurboModule direct API (React Native 0.76+ New Architecture)
import React, { useEffect } from 'react';
import NativeSingular from 'singular-react-native/jsNativeSingular';
import messaging from '@react-native-firebase/messaging';
import { Platform } from 'react-native';

export default function App() {
  useEffect(() => {
    if (Platform.OS === 'android') {
      initializeAndroidUninstallTracking();
    }
  }, []);

  async function initializeAndroidUninstallTracking() {
    try {
      // Request notification permission (Android 13+)
      const hasPermission = await requestNotificationPermission();

      if (!hasPermission) {
        console.warn('Notification permission denied - uninstall tracking unavailable');
        return;
      }

      // Get FCM token
      const token = await messaging().getToken();

      if (token) {
        // Register token with Singular for uninstall tracking
        NativeSingular.setUninstallToken(token);
        console.log('FCM token registered with Singular:', token);
      } else {
        console.warn('No FCM token available');
      }
    } catch (error) {
      console.error('Error setting up uninstall tracking:', error);
    }
  }

  async function requestNotificationPermission() {
    // Implementation from Step 3 above
    if (Platform.Version >= 33) {
      const { PermissionsAndroid } = require('react-native');
      const granted = await PermissionsAndroid.request(
        PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
      );
      return granted === PermissionsAndroid.RESULTS.GRANTED;
    }
    return true;
  }

  return (
    // Your app components
    null
  );
}

有关完整的方法文档,请参阅setUninstallToken 参考资料


步骤 5:处理令牌刷新

每当FCM令牌刷新时,就用Singular更新令牌,以保持准确的卸载跟踪。

New ArchitectureOld Achitecture
// TurboModule direct API (React Native 0.76+ New Architecture)
import React, { useEffect } from 'react';
import NativeSingular from 'singular-react-native/jsNativeSingular';
import messaging from '@react-native-firebase/messaging';
import { Platform } from 'react-native';

export default function App() {
  useEffect(() => {
    if (Platform.OS === 'android') {
      // Set up token refresh listener
      const unsubscribe = messaging().onTokenRefresh((token) => {
        console.log('FCM token refreshed:', token);

        // Update Singular with new token
        NativeSingular.setUninstallToken(token);
      });

      // Clean up listener on unmount
      return () => unsubscribe();
    }
  }, []);

  return (
    // Your app components
    null
  );
}

最佳做法:FCM 令牌可以随时刷新(应用程序更新、设备还原等)。请始终订阅onTokenRefresh 事件,以便用最新令牌保持 Singular 的更新。


iOS 卸载跟踪

前提条件

按照《设置 iOS 卸载跟踪》指南在 Singular 平台上配置 iOS 应用程序。

iOS 卸载跟踪基于苹果推送通知服务(APNs)技术。如果您的应用程序不支持推送通知,请参阅 Apple 的 "使用 APNs 注册您的应用程序 "指南


实施步骤

步骤 1:请求 iOS 通知授权

向用户请求通知权限并获取 APNS 设备令牌。

JavaScript
import messaging from '@react-native-firebase/messaging';
import { Platform } from 'react-native';

async function requestIOSNotificationPermission() {
  if (Platform.OS !== 'ios') {
    return false;
  }

  try {
    const authStatus = await messaging().requestPermission();
    const enabled =
      authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
      authStatus === messaging.AuthorizationStatus.PROVISIONAL;

    if (enabled) {
      console.log('iOS notification authorization status:', authStatus);
      return true;
    }

    return false;
  } catch (error) {
    console.error('Error requesting iOS notification permission:', error);
    return false;
  }
}

步骤 2:检索和注册 APNS 令牌

获取 APNS 设备令牌,并在获得授权后使用setUninstallToken() 在 Singular 注册。

New ArchitectureOld Achitecture
// TurboModule direct API (React Native 0.76+ New Architecture)
import React, { useEffect } from 'react';
import NativeSingular from 'singular-react-native/jsNativeSingular';
import messaging from '@react-native-firebase/messaging';
import { Platform } from 'react-native';

export default function App() {
  useEffect(() => {
    if (Platform.OS === 'ios') {
      initializeIOSUninstallTracking();
    }
  }, []);

  async function initializeIOSUninstallTracking() {
    try {
      // Request notification authorization
      const hasPermission = await requestIOSNotificationPermission();

      if (!hasPermission) {
        console.warn('Notification permission denied - uninstall tracking unavailable');
        return;
      }

      // Register for remote notifications (required for APNS)
      await messaging().registerDeviceForRemoteMessages();

      // Get APNS token
      const apnsToken = await messaging().getAPNSToken();

      if (apnsToken) {
        // Register token with Singular for uninstall tracking
        NativeSingular.setUninstallToken(apnsToken);
        console.log('APNS token registered with Singular:', apnsToken);
      } else {
        console.warn('No APNS token available');
      }
    } catch (error) {
      console.error('Error setting up iOS uninstall tracking:', error);
    }
  }

  async function requestIOSNotificationPermission() {
    // Implementation from Step 1 above
    const authStatus = await messaging().requestPermission();
    return authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
           authStatus === messaging.AuthorizationStatus.PROVISIONAL;
  }

  return (
    // Your app components
    null
  );
}

令牌格式:getAPNSToken() 获取的 APNS 令牌已格式化为十六进制字符串,这是 Singular 的正确格式。


步骤 3:处理令牌刷新(iOS)

如果 APNS 令牌在应用程序生命周期内发生变化,则使用 Singular 更新令牌。

New ArchitectureOld Achitecture
// TurboModule direct API (React Native 0.76+ New Architecture)
import React, { useEffect } from 'react';
import NativeSingular from 'singular-react-native/jsNativeSingular';
import messaging from '@react-native-firebase/messaging';
import { Platform } from 'react-native';

export default function App() {
  useEffect(() => {
    if (Platform.OS === 'ios') {
      // Set up token refresh listener
      const unsubscribe = messaging().onTokenRefresh((token) => {
        console.log('APNS token refreshed:', token);

        // Update Singular with new token
        NativeSingular.setUninstallToken(token);
      });

      // Clean up listener on unmount
      return () => unsubscribe();
    }
  }, []);

  return (
    // Your app components
    null
  );
}

完整的跨平台实施

统一卸载跟踪设置

通过正确的错误处理和令牌刷新逻辑,为 Android 和 iOS 平台实施卸载跟踪。

New ArchitectureOld Achitecture
// TurboModule direct API (React Native 0.76+ New Architecture)
import React, { useEffect } from 'react';
import NativeSingular from 'singular-react-native/jsNativeSingular';
import messaging from '@react-native-firebase/messaging';
import { Platform, PermissionsAndroid } from 'react-native';

export default function App() {
  useEffect(() => {
    initializeUninstallTracking();
    const unsubscribe = setupTokenRefreshListener();

    // Clean up listener on unmount
    return () => {
      if (typeof unsubscribe === 'function') unsubscribe();
    };
  }, []);

  async function initializeUninstallTracking() {
    try {
      if (Platform.OS === 'android') {
        await setupAndroidUninstallTracking();
      } else if (Platform.OS === 'ios') {
        await setupIOSUninstallTracking();
      }
    } catch (error) {
      console.error('Error initializing uninstall tracking:', error);
    }
  }

  async function setupAndroidUninstallTracking() {
    // Request permission for Android 13+
    if (Platform.Version >= 33) {
      const granted = await PermissionsAndroid.request(
        PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
      );

      if (granted !== PermissionsAndroid.RESULTS.GRANTED) {
        console.warn('Android notification permission denied');
        return;
      }
    }

    // Get and register FCM token
    const token = await messaging().getToken();

    if (token) {
      NativeSingular.setUninstallToken(token);
      console.log('Android FCM token registered:', token);
    } else {
      console.warn('Failed to retrieve Android FCM token');
    }
  }

  async function setupIOSUninstallTracking() {
    // Request iOS notification authorization
    const authStatus = await messaging().requestPermission();
    const authorized =
      authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
      authStatus === messaging.AuthorizationStatus.PROVISIONAL;

    if (!authorized) {
      console.warn('iOS notification permission denied');
      return;
    }

    // Register for remote notifications
    await messaging().registerDeviceForRemoteMessages();

    // Get and register APNS token
    const apnsToken = await messaging().getAPNSToken();

    if (apnsToken) {
      NativeSingular.setUninstallToken(apnsToken);
      console.log('iOS APNS token registered:', apnsToken);
    } else {
      console.warn('Failed to retrieve iOS APNS token');
    }
  }

  function setupTokenRefreshListener() {
    // Listen for token refresh events
    const unsubscribe = messaging().onTokenRefresh((token) => {
      console.log(`${Platform.OS.toUpperCase()} token refreshed:`, token);
      NativeSingular.setUninstallToken(token);
    });

    return unsubscribe;
  }

  return (
    // Your app components
    null
  );
}

验证和故障排除

验证实施

在部署到生产环境之前,确认卸载跟踪工作正常。

  1. 检查日志:验证令牌注册是否以正确格式出现在控制台日志中
  2. 测试令牌生成:确保在授予权限后首次启动应用程序时生成令牌
  3. 监控仪表板:在 24-48 小时后检查 Singular 仪表板上的卸载跟踪数据
  4. 测试令牌刷新:清除应用程序数据并验证重新启动应用程序时令牌更新是否正确

常见问题

  • 令牌未生成:验证 Firebase 依赖项是否已正确安装,Firebase 是否已配置到 React Native 项目中
  • 权限被拒绝:检查用户是否授予了通知权限(Android 13+ 和所有 iOS 版本都需要
  • 令牌未更新:确保您已订阅两个平台的onTokenRefresh 事件
  • 数据缺失:确认设备符合平台要求(Android 4.1+ 支持 Google Play 服务,iOS 支持 APNs
  • 配置错误:确认已在应用程序的 Singular 平台设置中启用卸载跟踪功能
  • Firebase 设置:对于 Android,请确保google-services.json 位于android/app/ 中。对于 iOS,请确保GoogleService-Info.plist 已添加到 Xcode 项目中。

其他资源:有关详细的故障排除,请参阅《Android 卸载跟踪设置指南》、《iOS 卸载跟踪设置指南》React Native Firebase 消息文档