Could not open URL... No Activity found to handle Intent - android

I'm trying to apply deep linking in my react native app. I followed the documentation and when trying to do the first test I had some problems, I believe it's because of using stack navigator and drawer menu.
Stack:
const SignedInStack = () => (
<Stack.Navigator>
<Stack.Screen name='Confluence' component={Confluence} />
<Stack.Screen name='QRCode' component={Main} />
<Stack.Screen name='Notifications' component={Notifications} />
</Stack.Navigator>
)
DrawerMenu:
const DrawerMenu = () => (
<Drawer.Navigator
screenOptions={{ headerShown: false }}
drawerContent={(props) => <CustomDrawerContent {...props} />}
>
<Drawer.Screen
name="SignedInStack"
component={SignedInStack}
/>
<Drawer.Navigator/>
);
App.js:
const App = () => (
<NavigationContainer linking={{
prefixes: ['example://'],
config: {
screens: {
Notifications: 'notifications',
},
},
}}>
<DrawerMenu />
</NavigationContainer>
);
My first useEffect on initial screen of my stack:
useEffect(() => {
Linking.openURL('example://app/notifications');
}, []);
Right after trying to redirect to the notifications screen I get the following error message:
"Error: Could not open URL 'example://app/notifications': No Activity found to handle Intent { act=android.intent.action.VIEW dat=example://app/notifications flg=0x10000000 }"

Instead of using Linking.openURL I used linkTo, as in the example below:
import { useLinkTo } from '#react-navigation/native';
...
const linkTo = useLinkTo();
useEffect(() => {
linkTo('/notifications');
}, []);

Related

This is the best way to use Stack Navigator and Drawer Navigator together?

I've been programming in React Native for a short time, and I know little about react-navigation. After trying a lot I managed to use stack navigator with a custom drawer navigator (side menu), but this seems to be very strange because my stack is inside my menu drawer like a screen.
My stack:
const SignedInStack = () => (
<Stack.Navigator>
<Stack.Screen name='Confluence' component={Confluence} />
<Stack.Screen name='QRCode' component={Main} />
</Stack.Navigator>
)
In the DrawerMenu:
const DrawerMenu = () => (
<Drawer.Navigator
screenOptions={{ headerShown: false }}
drawerContent={(props) => <CustomDrawerContent {...props} />}
detachInactiveScreens={false}
>
<Drawer.Screen
name="SignedInStack"
component={SignedInStack}
options={{
drawerItemStyle: { height: 0 }
}}
/>
<Drawer.Screen
name="QRCode"
component={Main}
/>
<Drawer.Navigator/>
);
In the App.js:
const App = () => (
<NavigationContainer>
<DrawerMenu />
</NavigationContainer>
);
Previously I use my drawer menu inside my stack, but the app had navigation problems.

Deeplink in react-native with nested navigators, app gets foregrounded but no navigation

I'm trying to deeplink back to my app after a successful authentication in a browser using a redirect URL. There's a few nested navigators in the app itself, so the set up looks like this:
Outer Stack:
return (
<SafeAreaProvider>
<NavigationContainer
theme={theme}
linking={linking}>
<Stack.Navigator
screenOptions={{
headerShown: false,
gestureEnabled: false
}}>
<Stack.Screen name="Login" component={LandingStackScreen} options={{
gestureEnabled: false,
}}/>
<Stack.Screen name="Home" component={HomeTabScreen} options={{
gestureEnabled: false,
}}/>
<Stack.Screen name="Logout" component={LogoutStackScreen} options={{
gestureEnabled: false,
}}/>
<Stack.Screen name="Register" component={RegistrationStackScreen} options={{
gestureEnabled: false,
}}/>
</Stack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
)
};
}
Inner Stack 1 (Home Stack):
function HomeTabScreen() {
return (
<HomeTab.Navigator
tabBarOptions={{
activeTintColor: '#059693',
inactiveTintColor: 'gray',
}}
sceneContainerStyle={{backgroundColor: 'transparent'}}
tabBar={props => <MyTabBar {...props} key={1} />}
>
<HomeTab.Screen name="Home" component={HomeStackScreen}/>
<HomeTab.Screen name="Analytics" component={AnalyticsStackScreen}/>
<HomeTab.Screen name="Add" component={Testing}/>
<HomeTab.Screen name="Dummy" component={Testing}/>
<HomeTab.Screen name="Coach" component={CoachDrawerScreen}/>
<HomeTab.Screen name="Profile" component={SettingsStackScreen}/>
</HomeTab.Navigator>
);
}
And Inner Stack 2 (Analytics Stack):
function AnalyticsStackScreen() {
return (
<AnalyticsStack.Navigator
screenOptions={{
headerShown: false,
}}>
<AnalyticsStack.Screen name="History" component={History} />
<AnalyticsStack.Screen name="Trends" component={Trends} />
<AnalyticsStack.Screen name="widgetpage" component={widgetPage} />
<AnalyticsStack.Screen name="widgetsuccess" component={successfulWidgetLogon} />
</AnalyticsStack.Navigator>
);
}
I'm trying to have the app redirect to the widgetsuccess component in the Analytics Stack (inner stack 2). I've set up a linking prop like this:
const linking = {
prefixes: ['https://myapp.com', 'myapp://'],
config: {
screens: {
Home: {
screens: {
Analytics: {
widgetsuccess: "widgetsuccess?:userId&:resource"
}
}
}
},
},
};
I've also changed the Android Manifest to add the "myapp" scheme and "widgetsuccess" host, alongside the android:launchMode="singleTask" and other intent-filter changes that are required. The redirect url will look like this: "myapp://widgetsuccess?userId=xxx-xxx-xxx&resource=xxx".
When the app successfully authenticates and redirects, it simply takes me back to the same page that the app was on originall. I've tried to just redirect to the initial home page, or any other page really and the same thing happens. I've obviously done something wrong, but can't figure out what, so if anyone has an idea, I would really appreciate the help. Cheers.
I had the same problem. The reason was in redirect url.
By your config I would test something like myapp://Home/Analytics/widgetsuccess?userId=xxx-xxx-xxx&resource=xxx
Notice that links like myapp:// works for ios, there is problem with it on android. For android I use intents, url like intent://...
This article may be usefull https://www.adjust.com/blog/dive-into-deeplinking/

Stack navigator doesn't work in release apk

I have Drawer and Stack navigators in my app
drawer
const Drawer = createDrawerNavigator();
export default class App extends Component {
render() {
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Games" component={GamesScreen} />
</Drawer.Navigator>
</NavigationContainer>
);
}
}
stack
import Cities from "../components/games/Cities";
const GScreen =({navigation}) =>{
return(
/*code*/
)
}
const Stack = createStackNavigator();
export default class GamesScreen extends Component {
render() {
return (
<Stack.Navigator>
<Stack.Screen name='Games' component={GScreen} options={{headerTitle:(props) => <Header props=
{this.state} {...props} />}}/>
<Stack.Screen name='Cities' component={Cities} options={{headerTitle:(props) => <Header props=
{this.state} {...props} />}}/>
</Stack.Navigator>
);
}
}
My app is working fine in debug mode, but in release only the drawer works.
When i ckick on a component just nothing happens

Left-to-right animation on Android with react-native-navigation when pushing new screen to stack

On Android with react-native-navigation, when pushing a new screen to the stack, I’d like the transition animation to be from left-to-right (or vice-versa, for RTL layout)
In iOS it‘s the default, where as on Android – it seems to be shown with cross-dissolve animation. how can I achieve the horizontal animation as in iOS?
Here is an example stack navigator for you:
import { createStackNavigator, CardStyleInterpolators } from "#react-navigation/stack";
class CompaniesIndex extends React.Component<
ICompaniesIndexProps,
ICompaniesIndexState
> {
render() {
return (
<CompanyStack.Navigator
mode="modal"
screenOptions={{
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS
}}
initialRouteName="AllCompanies">
<CompanyStack.Screen
options={{
title: "Firma Listesi",
header: (props) => <Header {...props} />,
}}
name="AllCompanies"
component={CompaniesAll}
/>
<CompanyStack.Screen
options={{
title: "Yeni Firma",
header: (props) => <Header {...props} />,
}}
name="NewCompany"
component={CompanyNew}
/>
<CompanyStack.Screen
options={{
title: "Firma Detayı",
header: (props) => <Header {...props} />,
}}
name="CompanyDetails"
component={CompanyDetails}
/>
</CompanyStack.Navigator>
);
}
}
You can achieve that with adding screenOptions={{cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS}} in your stack navigator.
For react-navigation#6.0.1, use animation: "slide_from_right" in screenOptions.
<Stack.Navigator
screenOptions={{
headerShown: false,
animation: "slide_from_right",
}}
if you use native-stack (#react-navigation/native-stack or react-native-screens/native-stack), just input 'stackAnimation' option in screenOptions of your Navigator!
import { createNativeStackNavigator } from 'react-native-screens/native-stack';
const Stack = createNativeStackNavigator();
<Stack.Navigator screenOptions={{ headerShown: false, stackAnimation: 'slide_from_right' }}>
<Stack.Screen name="First" component={FirstScreen} />
<Stack.Screen name="Second" component={SecondScreen} />
</Stack.Navigator>

React Native: Switch from createBottomTabNavigator to createMaterialBottomNavigator

I am fully aware that using createBottomTabNavigator will give you a nice iOS bottom tabs with no background color while createMaterialBottomNavigator will give you a background color and different setup on android device.
My goal is to to use createBottomTabNavigator on iOs device and then switch to createMaterialBottomNavigator on android device with all the setup like putting activeTintColor color, using shifting: true mode whenever you switch screen on android.
So what I did is I use the Platform API:
const MealsFavTabNavigator =
Platform.OS === 'android'
? createMaterialBottomNavigator(navTabConfig)
: createBottomTabNavigator();
And then, create a possible config:
const navTabConfig = {
options={{
tabBarIcon: ({ focused, color, size }) => (
<Ionicons name="ios-star" size={25} color={focused ? "tomato" : "black"} />
)
}}
};
Then tried to switch this on my navigator:
<MealsFavTabNavigator.Screen
name="Meals"
component={MealsNavigator}
navTabConfig
/>
Which did not work. Here's the full code:
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { Ionicons } from '#expo/vector-icons';
import { Platform } from 'react-native';
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
import CategoriesScreen from '../screens/CategoriesScreen';
import CategoryMealsScreen from '../screens/CategoryMealsScreen';
import MealDetailScreen from '../screens/MealDetailScreen';
import FavoritesScreen from '../screens/FavoritesScreen';
import HeaderButton from '../components/HeaderButton';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { CATEGORIES } from '../data/dummy-data';
import Colors from '../constants/colors';
const MealsNav = createStackNavigator();
const MealsNavigator = () => {
return (
<MealsNav.Navigator
mode="modal"
screenOptions={{
headerStyle: {
backgroundColor: Colors.primaryColor,
},
headerTintColor: '#fff',
headerTitleStyle: {
fontSize: 17
}
}}
>
<MealsNav.Screen
name="Categories"
component={CategoriesScreen}
options={{
title: 'Meals Categories'
}}
/>
<MealsNav.Screen
name="CategoryMeals"
component={CategoryMealsScreen}
options={({ route }) => {
const catId = route.params.categoryId;
const selectedCategory = CATEGORIES.find((cat) => cat.id === catId);
return {
title: selectedCategory.title,
};
}}
/>
<MealsNav.Screen
name="MealDetail"
component={MealDetailScreen}
options={{
title: 'Meal Detail',
headerRight: () => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title='Favorite'
iconName='ios-star'
onPress={() => console.log('Mark as the favorite')}
/>
</HeaderButtons>
),
}}
/>
</MealsNav.Navigator>
);
};
const MealsFavTabNavigator =
Platform.OS === 'android'
? createMaterialBottomNavigator(navTabConfig)
: createBottomTabNavigator();
const navTabConfig = {
options={{
tabBarIcon: ({ focused, color, size }) => (
<Ionicons name="ios-star" size={25} color={focused ? "tomato" : "black"} />
)
}}
};
const MealsTabNav = () => {
return (
<NavigationContainer>
<MealsFavTabNavigator.Navigator
tabBarOptions={{
activeTintColor: 'tomato',
inactiveTintColor: 'black',
}}>
<MealsFavTabNavigator.Screen
name="Meals"
component={MealsNavigator}
navTabConfig
/>
<MealsFavTabNavigator.Screen
name="Favorites"
component={FavoritesScreen}
options={{
tabBarIcon: ({ focused, color, size }) => (
<Ionicons name="ios-star" size={25} color={focused ? "tomato" : "black"} />
)
}}
/>
</MealsFavTabNavigator.Navigator>
</NavigationContainer>
);
};
export default MealsTabNav;
How can I attain my goal of switching from createBottomTabNavigator to createMaterialBottomNavigator and then applying the basic styles on createMaterialBottomNavigator such as activeTintcolor and shifting mode.
Please help! I am super stuck!
Your approach is correct only little change that you need to do is the way you use the props.
The below code is a generic example, I'm not using your components
The tab creation is same but the when you get the props its better if you can use a function like below.
Here the function will return the props for the appropriate navigator and we use the spread operator to pass the props.
You can chose to do this only tabBarOptions but this example shows for all props which is more flexible.
const Tab = Platform.OS === 'ios' ? createMaterialBottomTabNavigator() : createBottomTabNavigator();
const getNavigationOptions = () => {
if (Platform.OS === 'ios') {
//Props for the ios navigator
return {
labeled: false,
initialRouteName: 'Settings',
activeColor: 'red',
inactiveColor: 'white'
};
}
//Props for any other OS navigator
return {
initialRouteName: 'Home',
tabBarOptions: { activeTintColor: 'red' },
};
};
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator {...getNavigationOptions()}>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
To apply this to your project
//Keep this line as it is
const MealsFavTabNavigator =
Platform.OS === 'android'
? createMaterialBottomNavigator()
: createBottomTabNavigator();
<MealsFavTabNavigator.Navigator {...getNavigationOptions()}>
And update the getNavigationOptions with your own probs based on the platform
Did you try the following?
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
const Tab = createMaterialBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}

Categories

Resources