skip to Main Content

I have deep links set up on a React-Native app. iOS works fine.
On Android, if the app is already in the background the deep link works.
However, if the app is booting up fresh, the deep link opens the app but doesn’t trigger the redirect.
As far as I can see, the link is available in the MainActivity onCreate() function via the intent.
When the app opens I am processing the link but in this case, Linking.getInitialURL() produces a null value.

The caveat here is that I have a SplashActivity which is set as the android.intent.category.LAUNCHER.
This passes back to the MainActivity (and as I say, the deep link is there in extras).

I’ve tried making MainActivity the LAUNCHER and but this results in multiple instances of the app opening when a deep link is triggered vs opening the app via the home screen.

Both MainActivity and SplashActivity are set to android:launchMode="singleTask"

Can anyone offer any insight into the correct way of setting this up on Android.

2

Answers


  1. Chosen as BEST ANSWER

    This was a little complicated but I think I have a working solution now.

    SplashActivity is set as this in my manifest:

    <intent-filter>
      <action android:name="android.intent.action.VIEW" />
      <category android:name="android.intent.category.DEFAULT" />
      <category android:name="android.intent.category.BROWSABLE" />
      <data android:scheme="myapp" />
    </intent-filter>
    

    The SplashActivity does the following (where url is the deeplink):

    Intent intent = new Intent(this, MainActivity.class);
    try {
      Uri data = getIntent().getData();
      if(data!=null) {
        intent.putExtra("url", data.toString());
      }
    }
    catch (Exception e) { }
    startActivity(intent);
    finish();
    

    ...then in MainActivity I have the following to catch the deep link on a fresh app open:

    public void onCreate(Bundle savedInstanceState) {
        ...
        if(getIntent().hasExtra("url")) {
          String urlString = getIntent().getStringExtra("url");
          getIntent().putExtra("url", urlString);
          getIntent().setData(Uri.parse(urlString));
          getIntent().setAction(Intent.ACTION_VIEW);
        }
        SplashScreen.show(this);
        super.onCreate(savedInstanceState);
      } 
    

    as well as

    @Override
    public void onNewIntent(Intent intent) {
      if(intent.hasExtra("url")) {
        String urlString = intent.getStringExtra("url");
        intent.setData(Uri.parse(urlString));
        intent.setAction(Intent.ACTION_VIEW);
      }
      super.onNewIntent(intent);
      setIntent(intent);
    }
    

    ...so that Linking.getInitialURL() over on the react-native side now picks up the deep link if the app was in the background or if it's opening from closed state.

    This also prevents the 'multiple instance' problem so there is only ever 1 open.


  2. Would you try this in your AndroidManifest.xml

        <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
        android:windowSoftInputMode="adjustResize"
        android:launchMode="singleTask"
        android:exported="true">
          <intent-filter android:autoVerify="true">
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
          <intent-filter>
              <action android:name="android.intent.action.VIEW" />
              <category android:name="android.intent.category.DEFAULT" />
              <category android:name="android.intent.category.BROWSABLE" />
              <data android:scheme="myredirecturl" />
          </intent-filter>
      </activity>
    

    and in you app.js file

    useEffect(() => {
        const handleUrl = async ({ url }) => {   
        const checkInitialUrl = async () => {
            const initialUrl = await Linking.getInitialURL();
            if (initialUrl) {   
            }
        };
    
        Linking.addEventListener('url', handleUrl);
    
        checkInitialUrl();
    
        // Add AppState change listener
        const handleAppStateChange = (nextAppState) => {
            if (nextAppState === 'active') {
                // App is in the foreground, check for the URL again
                checkInitialUrl();
            }
        };
    
        AppState.addEventListener('change', handleAppStateChange);
    
        // Clean up event listeners on component unmount
        return () => {
            Linking.removeEventListener('url', handleUrl);
            AppState.removeEventListener('change', handleAppStateChange);
        };
    }, [])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search