achorein / expo-share-intent

🚀 Simple share intent in an Expo Native Module
MIT License
218 stars 15 forks source link

When sharing an image with my application, the route handling by default takes me to +not-found.tsx in my expo-router application. #118

Open cback97 opened 2 months ago

cback97 commented 2 months ago

When sharing an image with my application, the route handling by default takes me to +not-found.tsx in my expo-router application

Share image to my expo-router application is the step to reproduce

Environment

System:
  OS: macOS 14.6.1
  CPU: (10) arm64 Apple M1 Max
  Memory: 5.68 GB / 64.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 22.8.0
    path: ~/.nvm/versions/node/v22.8.0/bin/node
  Yarn:
    version: 3.6.4
    path: ~/.nvm/versions/node/v22.8.0/bin/yarn
  npm:
    version: 10.8.2
    path: ~/.nvm/versions/node/v22.8.0/bin/npm
  Watchman: Not Found
Managers:
  CocoaPods:
    version: 1.15.2
    path: /opt/homebrew/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 24.0
      - iOS 18.0
      - macOS 15.0
      - tvOS 18.0
      - visionOS 2.0
      - watchOS 11.0
  Android SDK: Not Found
IDEs:
  Android Studio: 2022.2 AI-222.4459.24.2221.10121639
  Xcode:
    version: 16.0/16A242d
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 18.0.1
    path: /usr/bin/javac
  Ruby:
    version: 2.6.10
    path: /usr/bin/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.2.0
    wanted: 18.2.0
  react-native:
    installed: 0.74.5
    wanted: 0.74.5
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: Not found
  newArchEnabled: Not found
iOS:
  hermesEnabled: true
  newArchEnabled: false
achorein commented 2 months ago

cannot reproduce with the example.

I think you should have something like this in your 404 page, the example uses the Home in [...unmatched] and then redirect :

  useEffect(() => {
    if (hasShareIntent) {
      // we want to handle share intent event in a specific page
      router.replace({
        pathname: "shareintent",
      });
    }
  }, [hasShareIntent]);
cback97 commented 2 months ago

here is my implementation! :) @achorein

app/_layout.tsx

  return (
    <ShareIntentProvider
      options={{
        resetOnBackground: true,
        // debug: true,
        onResetShareIntent: () => router.replace("/"),
      }}
    >
      <GestureHandlerRootView style={{ flex: 1 }}>
        <ToastProvider>
          <SelectedProductProvider>
            <Stack
              screenOptions={{
                headerShown: false,
                contentStyle: { backgroundColor: BrandNeutrals.white },
              }}
              initialRouteName="index"
            >
              <Stack.Screen name="index" />
            </Stack>
          </SelectedProductProvider>
        </ToastProvider>
      </GestureHandlerRootView>
    </ShareIntentProvider>
  );

index.tsx will then route me to home.tsx where I am using the following

  useEffect(() => {
    async function runEffect(fileUri: string) {
      try {
        const base64 = await FileSystem.readAsStringAsync(fileUri, {
          encoding: FileSystem.EncodingType.Base64,
        });
        setImage(base64);
      } catch (error) {
        console.error("Error converting file to base64", error);
      }
    }

    if (!hasShareIntent || !shareIntent.files) return;

    const filePath = shareIntent.files[0].path;

    runEffect(filePath);
  }, [hasShareIntent, resetShareIntent, shareIntent]);

Everything else works as it should, but the navigation always routes me to +not-found.tsx.

For reference, here is my index file

import { Redirect } from "expo-router";
import React, { useEffect, useState } from "react";
import checkFirstLaunch from "./util/checkFirstLaunch";

const SetInitialRoute = () => {
  const [sIsFirstLaunch, _setIsFirstLaunch] = useState<boolean | null>(null);
  useEffect(() => {
    const aDetermineFirstLaunch = async () => {
      try {
        const aFirstLaunch = await checkFirstLaunch();
        _setIsFirstLaunch(aFirstLaunch);
      } catch (error) {
        console.error(error);
        // Assume it's not the first launch if there's an error
        _setIsFirstLaunch(false);
      }
    };

    void aDetermineFirstLaunch();
  }, []);

  /**
   * This if statement handles the loading state
   * we want sIsFirstLaunch to be null while we're determining the status
   * sIsFirstLaunch will be true every time after the first launch
   */
  if (sIsFirstLaunch === null) {
    return null;
  }

  return sIsFirstLaunch ? (
    <Redirect href={"/splash"} />
  ) : (
    <Redirect href={"/home"} />
  );
};

export default SetInitialRoute;
cback97 commented 2 months ago

cannot reproduce with the example.

I think you should have something like this in your 404 page, the example uses the Home in [...unmatched] and then redirect :

  useEffect(() => {
    if (hasShareIntent) {
      // we want to handle share intent event in a specific page
      router.replace({
        pathname: "shareintent",
      });
    }
  }, [hasShareIntent]);

In attempt to doing this, we are still brought to the not found screen briefly which is not a solution. I'm just curious where the package is trying to bring me on launch or on navigating to the foreground.

nechmads commented 3 weeks ago

I get the same behavior when sharing urls into the app but only on iOS, so I had to basically handle intent in two different places: on my _layout file as well as on the not found file, and use Platform to make sure I don't handle the same intent twice. Would love to know if there is a better solution. (React Native 75 + Expo 51)

markwitt1 commented 4 days ago

Whats the status on this one? Whats the difference between unmatched and not-found?