achorein / expo-share-intent-demo

React Native Expo Share Intent Demonstration
89 stars 9 forks source link

getting a "this screen doesn't exist" with expo router #14

Closed spencerc99 closed 12 months ago

spencerc99 commented 12 months ago

hi there! thanks so much for making this demo

I got as far as getting it onto my iOS device using your useShareIntent hook, and my app successfully shows up in the share sheet! But when I send something to the app, I'm getting a "this screen doesn't exist." I wonder if it's due to using Expo Router? Would love any ideas!

361782FA-0020-4832-A462-B7184683ADC2_1_102_o

achorein commented 12 months ago

👋 Indeed my demo doesn't have a expo-router or react-navigation example.

To use expo-router you need to handle Unmatched Routes . It's the only screen where useShareIntent hook will work (allowing to get custom pathname).

Here an example for app/[...unmatched].js file :

export default function Unmatched() {
  const pathname = usePathname();
  const router = useRouter();

  const { shareIntent, resetShareIntent } = useShareIntent();

  return (
    <View style={styles.container}>
      <Text style={styles.gap}>Screen could not be found : {pathname}</Text>
      <Text style={styles.gap}>{JSON.stringify(shareIntent)}</Text>
      <Text
        onPress={() => {
          if (router.canGoBack()) {
            router.back();
          } else {
            router.replace("/");
          }
        }}
      >
        Go back.
      </Text>
    </View>
  );
}

You can also get the shareintent data from here and navigate to a specific screen with parameters to split the code. To detect your are coming from a share intent you can test the pathname like that :

  if (pathname?.includes(`dataurl=${Constants.expoConfig.scheme}sharekey`) && shareIntent) {
     router.replace({ pathname: 'shareintent', params: { shareIntent } })
  }

let me know if you managed to get it to work, I will update the documentation afterwards

spencerc99 commented 12 months ago

ahhh awesome thank you for the detailed explanation I'm very new to expo and expo router, so this is perfect info. Will try this out and let you know how it goes!

Btw did you figure out a way to test this in development? I notice that the default expo dev flow uses Expo Go in the simulator and so there's no share intent for the app there. What's the recommended way for testing this or do I have to actually build it and transfer it to my device each time?

achorein commented 12 months ago

We are using native code to make share intent works, so we can't use Expo Go and have to use a custom dev client, that's why the demo use expo prebuild --no-install command and then expo run:ios, instead of a simple expo start --ios. More information here

That way you can test your share intent into simulator, but that does not exempt you to test a complete build on device at the end of your development process to make sure all works as excepted :)

achorein commented 12 months ago

working example with expo router is now available on branch expo49-expo-router, enjoy !

spencerc99 commented 12 months ago

thank you for the help! Unfortunately, I still seem to be running into issues. I followed your code in the attached branch and was able to get it running in the emulator and successfully show up in the share intent screen. However, when I share to the app, I don't seem to be getting any share intent data when using the hook strangely.

https://github.com/achorein/expo-share-intent-demo/assets/14796580/771876e5-f49b-4738-a8d0-a35e229c1c51

In my logs, I see that the share intent is being set, but it's not causing my component to re-render or that useEffect you use to redirect to trigger.

image this is probably an error on my part, but wondering if you have any ideas?

code below:

// [...unmatched.tsx]
export default function NotFoundScreen() {
  const pathname = usePathname();
  const router = useRouter();
  const { shareIntent, resetShareIntent } = useShareIntent();
  console.log("pathname", pathname, shareIntent);
  useEffect(() => {
    console.log("checking share intent", pathname, shareIntent);
    if (
      pathname?.includes(`dataurl=${Constants.expoConfig?.scheme}sharekey`) &&
      shareIntent
    ) {
      console.log("redirecting!");
      router.replace({ pathname: "/(tabs)/home", params: { shareIntent } });
      resetShareIntent();
    }
  }, [shareIntent]);

  return (
    <>
      <Stack.Screen options={{ title: "Oops!" }} />
      <View style={styles.container}>
        <Text style={styles.title}>This screen doesn't exist.</Text>

        <Text
          style={styles.linkText}
          onPress={() => {
            if (router.canGoBack()) {
              router.back();
            } else {
              router.replace({ pathname: "/(tabs)/home" });
            }
          }}
        >
          Go back.
        </Text>
      </View>
    </>
  );
}

and my useShareIntent hook is the same except i added a "[rerendering] useShareIntentHook" log at the bottom before return

spencerc99 commented 12 months ago

thank you for the help! Unfortunately, I still seem to be running into issues. I followed your code in the attached branch and was able to get it running in the emulator and successfully show up in the share intent screen. However, when I share to the app, I don't seem to be getting any share intent data when using the hook strangely.

Screen.Recording.2023-09-20.at.3.10.03.PM.mov In my logs, I see that the share intent is being set, but it's not causing my component to re-render or that useEffect you use to redirect to trigger.

image this is probably an error on my part, but wondering if you have any ideas?

code below:

// [...unmatched.tsx]
export default function NotFoundScreen() {
  const pathname = usePathname();
  const router = useRouter();
  const { shareIntent, resetShareIntent } = useShareIntent();
  console.log("pathname", pathname, shareIntent);
  useEffect(() => {
    console.log("checking share intent", pathname, shareIntent);
    if (
      pathname?.includes(`dataurl=${Constants.expoConfig?.scheme}sharekey`) &&
      shareIntent
    ) {
      console.log("redirecting!");
      router.replace({ pathname: "/(tabs)/home", params: { shareIntent } });
      resetShareIntent();
    }
  }, [shareIntent]);

  return (
    <>
      <Stack.Screen options={{ title: "Oops!" }} />
      <View style={styles.container}>
        <Text style={styles.title}>This screen doesn't exist.</Text>

        <Text
          style={styles.linkText}
          onPress={() => {
            if (router.canGoBack()) {
              router.back();
            } else {
              router.replace({ pathname: "/(tabs)/home" });
            }
          }}
        >
          Go back.
        </Text>
      </View>
    </>
  );
}

and my useShareIntent hook is the same except i added a "[rerendering] useShareIntentHook" log at the bottom before return

well i tried again later and now it's magically working 😅 thanks for the help!

spencerc99 commented 12 months ago

btw is there a better way to remove the auto-generated

 "build": {
          "experimental": {
            "ios": {
              "appExtensions": [
                {
                  "targetName": "ShareExtension",
                  "bundleIdentifier": "supply.basket.share-extension",
                  "entitlements": {
                    "com.apple.security.application-groups": [
                      "group.supply.basket"
                    ]
                  }
                }
              ]
            }
          }
        }

that gets adds to "eas" in app.json. I seem to have to do it manually each time after build. Related to #1 (let me know if you want me to open a new issue)

spencerc99 commented 12 months ago

thank you for the help! Unfortunately, I still seem to be running into issues. I followed your code in the attached branch and was able to get it running in the emulator and successfully show up in the share intent screen. However, when I share to the app, I don't seem to be getting any share intent data when using the hook strangely. Screen.Recording.2023-09-20.at.3.10.03.PM.mov In my logs, I see that the share intent is being set, but it's not causing my component to re-render or that useEffect you use to redirect to trigger. image this is probably an error on my part, but wondering if you have any ideas? code below:

// [...unmatched.tsx]
export default function NotFoundScreen() {
  const pathname = usePathname();
  const router = useRouter();
  const { shareIntent, resetShareIntent } = useShareIntent();
  console.log("pathname", pathname, shareIntent);
  useEffect(() => {
    console.log("checking share intent", pathname, shareIntent);
    if (
      pathname?.includes(`dataurl=${Constants.expoConfig?.scheme}sharekey`) &&
      shareIntent
    ) {
      console.log("redirecting!");
      router.replace({ pathname: "/(tabs)/home", params: { shareIntent } });
      resetShareIntent();
    }
  }, [shareIntent]);

  return (
    <>
      <Stack.Screen options={{ title: "Oops!" }} />
      <View style={styles.container}>
        <Text style={styles.title}>This screen doesn't exist.</Text>

        <Text
          style={styles.linkText}
          onPress={() => {
            if (router.canGoBack()) {
              router.back();
            } else {
              router.replace({ pathname: "/(tabs)/home" });
            }
          }}
        >
          Go back.
        </Text>
      </View>
    </>
  );
}

and my useShareIntent hook is the same except i added a "[rerendering] useShareIntentHook" log at the bottom before return

well i tried again later and now it's magically working 😅 thanks for the help!

hmm I seem to experience that this works sporadically between restarts (and differs in behavior between using a link and an image). Any ideas on why that would be the case?

achorein commented 12 months ago

that gets adds to "eas" in app.json. I seem to have to do it manually each time after build. Related to #1 (let me know if you want me to open a new issue)

as mention you just have to add your projectId in app.json

hmm I seem to experience that this works sporadically between restarts (and differs in behavior between using a link and an image). Any ideas on why that would be the case?

ok I'm going to test it in more depth on my side

achorein commented 12 months ago

@spencerc99 i finally found a fix for this fee330a77cb9a0f7c4e802ec5716e9b30d681322.

So

spencerc99 commented 12 months ago

@achorein amazing!! i will check this out tonight.

I also realized there's an interface distinction between the share intent triggering the opening of the app with the data and apps opening a pop-up screen to handle the share in-context. Do you know if that's supported with the react-native-share-intent library you are using / if there's a different solution for that?

achorein commented 12 months ago

as mentioned in #15 this project does not support custom view for ios, all the share intent must be handle into the app.

I close the issue, I think we have covered the subject of expo-router. feel free to re-open if problem persist.