Repository navigation
Add react-native-sdk package - #2745
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a new @onflow/react-native-sdk package that brings Flow blockchain integration to React Native and Expo applications. The package provides the same hooks as react-sdk plus native mobile components (Connect and Profile) for wallet management. Additionally, it includes improvements to the WalletConnect integration in fcl-react-native for better mobile deep linking support and disconnect handling.
Key changes:
- New React Native SDK package with hooks, components, and providers
- Enhanced WalletConnect service with deep link transformation for mobile wallets
- Refactored disconnect logic to properly clean up WalletConnect sessions
- Updated demo with mobile starter template promotion
Reviewed changes
Copilot reviewed 26 out of 27 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/react-native-sdk/package.json | Package manifest for the new React Native SDK |
| packages/react-native-sdk/src/index.ts | Main entry point re-exporting hooks, components, and types |
| packages/react-native-sdk/src/provider/FlowProvider.tsx | Provider component that sets up Flow client and context |
| packages/react-native-sdk/src/provider/GlobalTransactionProvider.tsx | Provider for tracking global transaction state |
| packages/react-native-sdk/src/components/Connect.tsx | Wallet connection button with profile modal |
| packages/react-native-sdk/src/components/Profile.tsx | User profile component displaying balance and wallet info |
| packages/react-native-sdk/src/icons/*.tsx | Icon components for UI elements |
| packages/fcl-react-native/src/walletconnect/service.ts | Enhanced deep link transformation for mobile wallets |
| packages/fcl-react-native/src/walletconnect/client.ts | New disconnect utility function |
| packages/fcl-react-native/src/fcl-react-native.ts | Refactored unauthenticate to use shared disconnect logic |
| packages/fcl-react-native/src/client.ts | Updated createFlowClient with disconnect integration |
| packages/demo/src/components/starter-banner.tsx | Added mobile starter template card |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } & ( | ||
| | {vaultIdentifier: string; erc20Address?: never} | ||
| | {vaultIdentifier?: never; erc20Address: string} | ||
| ) |
There was a problem hiding this comment.
The TokenConfig type doesn't allow both vaultIdentifier and erc20Address to be specified simultaneously, which prevents supporting tokens that exist on both Cadence and EVM. Consider allowing both properties to be optional without mutual exclusion to support cross-VM tokens.
| } & ( | |
| | {vaultIdentifier: string; erc20Address?: never} | |
| | {vaultIdentifier?: never; erc20Address: string} | |
| ) | |
| vaultIdentifier?: string | |
| erc20Address?: string | |
| } |
There was a problem hiding this comment.
Correct as it is because you must specify one or the other like in react-sdk
| // Transform uid format (e.g., "frw#authz") to deeplink URL (e.g., "frw://authz") | ||
| // Service UIDs use # as separator but mobile deeplinks need :// | ||
| if (uid && uid.includes("#") && !uid.includes("://")) { | ||
| return uid.replace("#", "://") |
There was a problem hiding this comment.
The string replacement logic assumes UIDs always have exactly one '#' character. If a UID contains multiple '#' characters, only the first will be replaced, potentially creating an invalid deep link. Consider using a more robust transformation that handles edge cases or validates the UID format.
| return uid.replace("#", "://") | |
| const [scheme, ...rest] = uid.split("#"); | |
| return scheme + "://" + rest.join("#"); |
There was a problem hiding this comment.
not needed because in case it has multiple "#" it's a wrong uid and it should error
| @@ -0,0 +1,59 @@ | |||
| # @onflow/react-native-sdk | |||
|
|
|||
| A React Native library that provides hooks for interacting with the Flow blockchain. It helps you authenticate users, run Cadence scripts and transactions, listen to events, and manage network configuration directly from your components. Fully compatible with Expo. | |||
There was a problem hiding this comment.
Can we add a line here about it being comparable to the React SDK and add a link. We could maybe add a link to the hooks section of the playground as well.
| </FlowProvider> | ||
| ``` | ||
|
|
||
| ## 🪝 Available Hooks |
There was a problem hiding this comment.
I would put a link to a full list in case it gets out of date. And also put a note like here is a look at some of the hooks available just to account for the list becoming not up to date.
| | {vaultIdentifier?: never; erc20Address: string} | ||
| ) | ||
|
|
||
| export interface ConnectProps { |
There was a problem hiding this comment.
Are these the same as the connect component? Should it be shared? How do we make sure these don't get out of sync. Or maybe it doesn't matter if they do since they are separate components?
There was a problem hiding this comment.
Yep for the components i'd keep them separated because they could have different implementations, like in this case where there is a reduced interface.
| ) | ||
| } | ||
|
|
||
| const styles = StyleSheet.create({ |
There was a problem hiding this comment.
Is the component themeable like React SDK? I don't think we need to bother with that, but on the docs/playground we should make a note that theming is not available in the React Native SDK.
There was a problem hiding this comment.
No, it's not themeable right now for sake of simplicity (i saw we were doing some changes also on react-sdk so i avoided doing that). Yep, i omitted the theme section in the Docs (PR).
| minHeight: 48, | ||
| }, | ||
| disconnectedButton: { | ||
| backgroundColor: "#0F172A", |
There was a problem hiding this comment.
Can we make a file to share the colors across components? Same with any other styling constants.
| if (!chainId) return [] | ||
|
|
||
| const getFlowTokenAddress = () => { | ||
| if (chainId === "emulator" || chainId === "local") |
There was a problem hiding this comment.
We should have constants for these
There was a problem hiding this comment.
I agree with you that constants would be cleaner, but useFlowChainId return value is a string and probably it's ok and flexible enough with the forking changes we are doing where the chainId can be mainnet-fork, etc
| const address = getFlowTokenAddress().replace("0x", "") | ||
| return [ | ||
| { | ||
| symbol: "FLOW", |
There was a problem hiding this comment.
Constant for this as well
There was a problem hiding this comment.
What should be constant? It's implemented exactly as the Profile component in the react-sdk and it's already getting the address from contracts constants. If it's the name or symbol hopefully it won't ever change 😂
| : CONTRACT_ADDRESSES.mainnet.FlowToken | ||
| } | ||
|
|
||
| const address = getFlowTokenAddress().replace("0x", "") |
There was a problem hiding this comment.
We should use the withPrefix method we have
There was a problem hiding this comment.
Yep updated with correct method also on react-sdk profile component for consistency
|
|
||
| const displayAddress = useMemo(() => { | ||
| if (!user?.addr) return "" | ||
| return `${user.addr.slice(0, 6)}...${user.addr.slice(-4)}` |
There was a problem hiding this comment.
Can we move this to a helper? I feel like we must do this often
There was a problem hiding this comment.
Yes make sense. I've created a util function "truncateAddress" in react-core and updated usage in both react-sdk and react-native-sdk using it
| }, | ||
| } | ||
|
|
||
| export function FlowProvider({ |
There was a problem hiding this comment.
How similar is this to the provider we already have? Can't be shared?
There was a problem hiding this comment.
The providers (react-sdk and react-native-sdk) share interfaces and contexts from react-core (FlowConfig, FlowConfigContext, FlowClientContext, QueryClient setup) but the implementation differs due to platform requirements:
- react-sdk: Uses fcl and web-specific ConnectModal
- react-native-sdk: Uses fcl-react-native and mobile-specific ConnectModalProvider
The core logic (config context, client creation, query client setup) is identical, the difference is the fcl import and modal provider which are platform specific, so for this their implementation is different.
There was a problem hiding this comment.
I think you might be able to just wrap this at a platform-level @mfbz
i.e.
function Foo() {
const flowClient = //platform-specific impl
return (<>
<FlowProvider flowClient={flowClient}>
</)
}
(or similar)
There was a problem hiding this comment.
Yes, the fact was that the FlowProvider for react-native-sdk still needed some platform-specific implementation, like the ConnectModalProvider to show the connect modal and some other minor things that were needed in order to make it have the same usage as the react-sdk provider. For this reason, even if i created a FlowProviderCore wrapper it would have inside only a few things and it would still need a platform specific implementation so i kept them with the same interface but separated.
| import {QueryClient} from "@tanstack/react-query" | ||
| import {FlowQueryClientContext} from "@onflow/react-core" | ||
|
|
||
| export function FlowQueryClientProvider({ |
There was a problem hiding this comment.
In this case they are basically the same. I have moved it to react-core so that it's reused for both react-sdk and react-native-sdk, thanks for the catch!
Added react-native-sdk package, similar to react-sdk but for react-native applications. It fully supports all the same hooks available in react-sdk, plus the connect and profile components. It leverages fcl-react-native for managing blockchain interactions and it's compatible to both react-native and expo applications.
Here's some screenshots: