React Navigation get Param from deep linking not working - ios

I have configured my router like:
const SwitchRouter = createSwitchNavigator(
{
Splash: {
screen: Launch,
path: 'hello/:code',
},
App: HomeStack,
},
{
initialRouteName: 'Splash',
}
);
I'm using a link in Safari, which launches my iOS app and then I should get a parameter from this link in my code.
I tried different with links but I was not able to get any parameter from them. Here is what I've tried:
myApp://hello/123
myApp://hello/?code=123
myApp://hello?code=123
My code which should get this code parementer is in my Launch screen as below:
const code = navigation.getParam('code', 'error');
The code value is always an error, my param here is never found.
Am I missing something here? I've been through all the GitHub and documentation of react-navigation I couldn't find a solution working for me.
I read some people have some issue getting their deep linking params in componentDidMount. Apparently they are not available.
So my code here in charge of getting my parameter 'code' I tried to use it inside componentDidMount/DidUpdate and even in the render but in all cases I can't get my param.

I figured that you cannot pass deeplink params to the first/initial screen.
You have to use a proxy instead:
const SwitchRouter = createSwitchNavigator(
{
CodeScreen: {
Screen: Code,
path: 'code/:code',
}
Splash: {
screen: Launch,
path: 'hello',
},
App: HomeStack,
},
{
initialRouteName: 'Splash',
}
});
class Code extends Component {
constructor(props) {
super(props);
const {navigation} = this.props;
const code = navigation.getParam('code', false);
navigation.navigate('hello', {code});
}
render() {
return (
<View>
</View>
);
}
}
Now you retrieve the 'code' param in your SplashScreen.

Related

Supabase Auth - redirectTo not working for OAuth

I am switching from Flutter to Supabase and am running into an issue with Authentication. Although I can successfully launch the URL with the correct redirect value, I keep getting redirected to the site URL which should only be used for web, not iOS or Android. Below is the function I am using for Apple but this is happening with all other providers as well.
const isWeb = Platform.OS === "web";
const redirectTo = isWeb
? "https://web.example.com/login-callback/"
: "com.example.react://login-callback/";
export const signInWithApple = async () => {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: "apple",
options: {
redirectTo: redirectTo,
},
});
if (error !== null) {
console.log(error?.message);
return "error";
} else {
console.log(data);
Linking.openURL(data.url);
return "success";
}
};
The URL that gets logged before launching is correct, for example, LOG {"provider": "apple", "url": "https://api.example.com/auth/v1/authorize?provider=apple&redirect_to=com.example.react%3A%2F%2Flogin-callback%2F"}, but I always get redirected to something like https://web.example.com/#access_token=*****. I had a similar issue with Flutter, and that was because I had not added the additional redirect in Supabase but I already did that. I also confirmed that I have CFBundleURLSchemes set in the info.plist for iOS but that did not fix it.
IF SELF-HOSTING:
Check that you do not have spaces after commas in ADDITIONAL_REDIRECT_URLS.
Correct ✅ :
ADDITIONAL_REDIRECT_URLS="URL,URL,URL"
Incorrect ❌ :
ADDITIONAL_REDIRECT_URLS="URL, URL, URL"

Why doesn't react-navigation open the correct url from deeplink when the app is closed?

I have a deeplinking configuration setup to open a specific page when a URL is clicked on the device. This is working fine when the app is open in the background, but if the app is closed, it just opens the app and does not navigate.
Here is my linking configuration:
const linking = {
prefixes: ["appname://"],
config: deepLinkRouting,
getStateFromPath(path:string, options:any) {
//build custom params
},
async getInitialURL() {
// Check if app was opened from a deep link
const url = await Linking.getInitialURL();
if (url != null) {
return url;
}
},
subscribe(listener) {
const onReceiveURL = ({ url }) => listener(url);
Linking.addEventListener('url', onReceiveURL);
return () => {
// Clean up the event listener
Linking.removeEventListener('url', onReceiveURL);
};
},
}
This linking object is provided as a prop to my <NavigationContainer/>
I am testing this on simulator with the npx uri-scheme open command. I notice when you close the app and reopen it, the app is rebuilt, so I'm wondering if this invalidates testing. Any help is appreciated!

Deeplinking with a domain name

I have the following code in my App.js:
import React, { useState, useRef, useEffect } from 'react';
import { SafeAreaView, Text } from 'react-native';
import { NavigationContainer, useLinking } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const Stack = createStackNavigator();
const Screen1 = () => <SafeAreaView><Text>Screen1</Text></SafeAreaView>;
const Screen2 = () => <SafeAreaView><Text>Screen2</Text></SafeAreaView>;
export default function App() {
const ref = useRef();
const [isReady, setIsReady] = useState(false);
const [initialState, setInitialState] = useState();
const { getInitialState } = useLinking(ref, {
prefixes: ['http://example.com', 'mychat://'],
config: {
screens: {
Screen2: 'screen-2',
},
},
});
useEffect(() => {
getInitialState().then((state) => {
if (state !== undefined) setInitialState(state);
setIsReady(true);
});
}, [getInitialState]);
if (!isReady) return null;
return (
<NavigationContainer ref={ref} initialState={initialState}>
<Stack.Navigator>
<Stack.Screen name='Screen1' component={Screen1} />
<Stack.Screen name='Screen2' component={Screen2} />
</Stack.Navigator>
</NavigationContainer>
);
}
Most of them are copied from https://reactnavigation.org/docs/deep-linking/ and https://reactnavigation.org/docs/use-linking/.
In the docs there is prefixes: ['https://mychat.com', 'mychat://'], I just changed https://mychat.com to http://example.com. But it doesn't seem to work.
When I open the following links in Safari:
mychat:// (works, gets redirected to app Screen1)
mychat://screen-2 (works, gets redirected to app Screen2)
http://example.com (just opens the link in the browser, no popup to redirect to app)
What change do I need to make to redirect the domain name to the mobile app? Am I missing something?
You need to use a domain that you have access to alongside a server.
Your server needs to host a couple of files, typically within the .well-known directory:
apple-app-site-association (note the .json is not needed)
assetlinks.json
You also need to enable some entitlements within your app for iOS, this may also be true for Android. On iOS, this will be enabling the Associated Domains entitlement alongside an entry for webcredentials:yourdomain.com
The documentation is pretty good to go through to give an understanding on what needs to be done in order to achieve Universal Links
https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html
https://developer.android.com/training/app-links/verify-site-associations
Examples:
iOS - https://stackoverflow.com/.well-known/apple-app-site-association
Android - https://stackoverflow.com/.well-known/assetlinks.json

No camera found on Chrome IOS with CapacitorJS and Ionic

I have created a PWA with ionic and capacitor JS following this guide: https://ionicframework.com/docs/react/your-first-app.
After i have added it to firebase and start testet the code, i have runned into a issue on Chrome on IOS mobiles. It works on android and also web browsers.
But when i click the take photo button it says "No camera found" and the browser dont ask to let me use the camera. If i try the same thing on Safari, then it asks for the camera.
Here is the url to see the test: https://phototest-46598.web.app/tab1
Does anybody experience the same problem? My guess is that it is a new problem since the guide seems to work without problems.
Here is my code - i have followed the linked tutorial but not added native support because i only want to use it as a PWA.
hooks/usePhotoGallery.js file
import { useState, useEffect } from "react";
import { useCamera } from '#ionic/react-hooks/camera';
import { CameraResultType, CameraSource, CameraPhoto, Capacitor,
FilesystemDirectory } from "#capacitor/core";
export function usePhotoGallery() {
const { getPhoto } = useCamera();
const [photos, setPhotos] = useState<Photo[]>([]);
const takePhoto = async () => {
const cameraPhoto = await getPhoto({
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
quality: 100
});
const fileName = new Date().getTime() + '.jpeg';
const newPhotos = [{
filepath: fileName,
webviewPath: cameraPhoto.webPath
}, ...photos];
setPhotos(newPhotos)
};
return {
photos,
takePhoto
};
}
export interface Photo {
filepath: string;
webviewPath?: string;
base64?: string;
}
Tab2.tsx file
import React from 'react';
import { camera, trash, close } from 'ionicons/icons';
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar,
IonFab, IonFabButton, IonIcon, IonGrid, IonRow,
IonCol, IonImg, IonActionSheet } from '#ionic/react';
import ExploreContainer from '../components/ExploreContainer';
import { usePhotoGallery } from '../hooks/usePhotoGallery';
import './Tab2.css';
const Tab2: React.FC = () => {
const { photos, takePhoto } = usePhotoGallery();
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Photo Gallery</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<IonGrid>
<IonRow>
{photos.map((photo, index) => (
<IonCol size="6" key={index}>
<IonImg src={photo.webviewPath} />
</IonCol>
))}
</IonRow>
</IonGrid>
<IonFab vertical="bottom" horizontal="center" slot="fixed">
<IonFabButton onClick={() => takePhoto()}>
<IonIcon icon={camera}></IonIcon>
</IonFabButton>
</IonFab>
</IonContent>
</IonPage>
);
};
export default Tab2;
The camera plugin when running on web uses navigator.mediaDevices.getUserMedia, which is not supported on Chrome for iOS (prior to iOS 14.3).
I've run your app and it says "No camera found" and under it there is a "Choose image" button, if you click it you'll be prompted to take a picture or choose from the photo library, that's the expected behavior, when there is no Camera or no support for navigator.mediaDevices.getUserMedia it fallbacks to using a input with type file.

React Native and iOS share button

I am trying to access iOS' share button where you can share content to all services, including messages etc...
Any idea how I could do this? Thanks
You now have a simple Share API in react-native.
import { Share } from "react-native"
Share.share(
{
title: "a title",
message: "some message",
// or
url: imageReference
},
(options)
);
See http://facebook.github.io/react-native/docs/share.html
You can achieve this out of the box in React Native - just use ActionSheetIOS.showShareActionSheetWithOptions. See the documentation here.
You might want to check out the react-native-share package, it should cover your usecase. You can also see more relevant packages on JS.Coach
It's much easier than you think. Adding to #MoOx answer further.
With the new share api available, you can easily share information with your React Native app by just using it with all variables and configuration. (see here)
import React from 'react';
import { Share, View, Button } from 'react-native';
const ShareExample = () => {
const onShare = async () => {
try {
const result = await Share.share({
message:
'React Native | A framework for building native apps using React',
});
if (result.action === Share.sharedAction) {
if (result.activityType) {
// shared with activity type of result.activityType
} else {
// shared
}
} else if (result.action === Share.dismissedAction) {
// dismissed
}
} catch (error) {
alert(error.message);
}
};
return (
<View style={{ marginTop: 50 }}>
<Button onPress={onShare} title="Share" />
</View>
);
};
export default ShareExample;

Resources