React Native: Linking fails on Android

6
open
tuomohopia
tuomohopia
Posted 4 months ago

React Native: Linking fails on Android #588

Linking Fail

On React Native

Wallet Connect fails to link on React Native, observed on Android.

Problem

What happens when I'm attempting connector.connect() in the below code is that Android wants to open a website link to https://walletconnect.org/wallets instead of a deep link to an wallet app on the same device.

I have the following supported wallet apps installed on my Android phone:

  • MetaMask
  • Trust Wallet

The code looks something like this

import { useWalletConnect, withWalletConnect } from '@walletconnect/react-native-dapp'

const Registration = () => {
	const connector = useWalletConnect()

	return (
		<Button
			onPress={async () => {
				try {
					connector.connect({ chainId: 56 })
				} catch (err) {
					console.error("Error adding a Wallet with WalletConnect", err)
				}
			}}
		/>
	)
}

export default withWalletConnect(Registration, {
	redirectUrl: "myapp://home",
	storageOptions: {
		// @ts-expect-error: inconsistent dependency types
		asyncStorage: AsyncStorage,
	},
})

Cause

Now, I checked the lib code generated to node_modules for @walletconnect/react-native-dapp, and it goes like this:

        if (Platform.OS === 'android') {
            const canOpenURL = await Linking.canOpenURL(uri);
            if (!canOpenURL) {
                Linking.openURL('https://walletconnect.org/wallets');
                throw new Error('No wallets found.');
            }
            await Linking.openURL(uri);
        }

So evidently, Linking.canOpenURL(uri) fails. This results in the code defaulting to opening a website URL as seen above instead of trying to connect to a wallt app.

Logging the uri, it reads like wc:[email protected]?bridge=https%3A%2F%2Fj.bridge.walletconnect.org&key=d95c899bd3d92499da8c39f797111efa95cebb46081f0f79b88dd752948d4750

Is this a valid URI that the app should be checking if there are other apps using this scheme or not?

tuomohopia
tuomohopia
Created 4 months ago

Experimenting with the code, I just found that by erasing this if-clause from the lib code, I'm able to correctly open the link as a walletconnect link again with Trust Wallet and MetaMask installed on my device:

            if (!canOpenURL) {
                Linking.openURL('https://walletconnect.org/wallets');
                throw new Error('No wallets found.');
            }

However, I don't know what actually produces this code to node_modules/@walletconnect/react-native-dapp/dist/providers/WalletConnectProvider.js.

cawfree
cawfree
Created 4 months ago

Hey, thanks a lot for raising @tuomohopia!

It's certainly strange that Linking is saying that we can't open a URL that it will succeed in opening... This feels like it could be a higher-up problem in React Native, or the target wallet isn't conforming to the intended response specification, either way it's probably out of our scope to fix.

What might be the best solution is to try and immediately open the URL via Linking.openURL, and catch if this doesn't succeed. This way we could try and open the URL immediately, and if this fails, back up to navigating the user to the download page. What do you think?

tuomohopia
tuomohopia
Created 4 months ago

@cawfree I agree on both counts; that it's odd behavior from react-native' s Linking and that fixing that is outside of what we can realistically do to make this work here.

Your suggestion is likewise great that we still get on a fallback path in case it fails. I will check if it actually throws in such scenario and adjust my code.

For navigating to the downloads page straight away - I'm just thinking is this ideal behavior? For example in my own app, I'd like my app to actually display a message explaining the situation rather than the app oddly just opening some website with various wallet icons, saying something about a Wallet Connect protocol that most of the common smartphone users have never even heard of.

cawfree
cawfree
Created 4 months ago

@tuomohopia

For navigating to the downloads page straight away - I'm just thinking is this ideal behavior? For example in my own app, I'd like my app to actually display a message explaining the situation rather than the app oddly just opening some website with various wallet icons, saying something about a Wallet Connect protocol that most of the common smartphone users have never even heard of.

Yeah, I completely agree, this flow is pretty unintuitive as it stands. Maybe we could add a callback prop to the WalletConnectProvider which is called if Linking.openURL fails. Would you be interested in allowing this prop to be non-required, and default to opening the selected wallet's web URL? This way we can leave it up to the implementer to override the action if desired.

clxyder
clxyder
Created 4 weeks ago

I have stumbled into the same issue, I believe it's because the following statement in the Linking.canOpenUrl() documentation.

The Promise will reject on Android if it was impossible to check if the URL can be opened or when targetting Android 11 (SDK 30) if you didn't specify the relevant intent queries in `AndroidManifext.xml`.