ARTICLE AD BOX
I'm trying to test Facebook's Deep Link Tester, apparently it works on android devices, on iPhones it works on some devices that I used (iPhone 16 - iOS 26). I also tested another device which is the iPhone 13 Pro Max and iPhone 11 (both iOS 18.5), which both don't work.
My guess is that it has something to do with the device itself.
I have the following specs:
React Native 0.66.4
react-native-fbsdk-next 13.4.1
import React, { useEffect, useRef } from 'react'; import { Provider } from 'react-redux'; import { store, persistor } from '_services/store-service'; import { PersistGate } from 'redux-persist/integration/react'; import { StatusBar, useColorScheme, Platform, AppState } from 'react-native'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { Colors } from 'react-native/Libraries/NewAppScreen'; import AppNavigator from '_navigations/app-navigator'; import TipProvider from 'react-native-tip'; import { LoginBackground } from '_atoms'; import NotificationHandler from '_utils/notification-handler'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { Settings, AppLink } from 'react-native-fbsdk-next'; import { requestTrackingPermission } from 'react-native-tracking-transparency'; import AsyncStorage from '@react-native-async-storage/async-storage'; import {navigationRef} from '_navigations/root-navigator' const App = () => { const isDarkMode = useColorScheme() === 'dark'; const backgroundStyle = { backgroundColor: isDarkMode ? Colors.darker : Colors.lighter }; // Use a ref to ensure we don't try to fetch the link multiple times in one session const isInitialMount = useRef(true); useEffect(() => { if (isInitialMount.current) { runFullAuthFlow(); isInitialMount.current = false; } const subscription = AppState.addEventListener('change', (nextAppState) => { // If user comes back from Settings after denying permission, re-check if (nextAppState === 'active' && Platform.OS === 'ios') { runFullAuthFlow(); } }); return () => subscription.remove(); }, []); const runFullAuthFlow = async () => { try { // 1. Always initialize SDK first Settings.initializeSDK(); if (Platform.OS === 'ios') { // 2. Request ATT (Crucial for iOS Deferred Links) const status = await requestTrackingPermission(); // 3. Inform Facebook SDK if it's allowed to track // Meta won't match the deferred link without this being true await Settings.setAdvertiserTrackingEnabled(status === 'authorized'); if (status === 'authorized') { await handleDeferredLink(); } else if (status === 'denied' || status === 'restricted') { console.log("FB: Tracking denied. Deferred links will likely fail."); navigationRef.navigate('NotAllowedTracking'); } } else { // Android: No ATT required, straight to fetching await handleDeferredLink(); } } catch (error) { console.error("FB: Initialization Error:", error); } }; const handleDeferredLink = async () => { try { // Check if we've already processed a link for this install to avoid loops const hasHandled = await AsyncStorage.getItem('fb_deferred_handled'); if (hasHandled === 'true') return; console.log('FB: Checking Meta servers for deferred link...'); const url = await AppLink.fetchDeferredAppLink(); if (url) { console.log("FB: Success! Link received:", url); const params = extractParams(url); // Save the data and mark as handled await AsyncStorage.setItem('facebook_attribution', JSON.stringify(params)); await AsyncStorage.setItem('fb_deferred_handled', 'true'); } else { console.log("FB: No link found (Organic install or link expired)."); } } catch (error) { console.error("FB: Error fetching deferred link:", error); } }; const extractParams = (url) => { const params = {}; const regex = /[?&]([^=#]+)=([^&#]*)/g; let match; while ((match = regex.exec(url))) { params[match[1]] = match[2]; } return params; }; return ( <Provider store={store}> <PersistGate loading={<LoginBackground />} persistor={persistor}> <SafeAreaProvider style={backgroundStyle}> <StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} /> <GestureHandlerRootView style={{ flex: 1 }}> <AppNavigator /> </GestureHandlerRootView> <TipProvider /> <NotificationHandler /> </SafeAreaProvider> </PersistGate> </Provider> ); }; export default App;