-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Document Expo & React Native SDK instructions (#1047)
* Document Expo & React Native SDK instructions * edits * move RN before Expo
- Loading branch information
1 parent
4cbdad7
commit 63206d2
Showing
1 changed file
with
186 additions
and
100 deletions.
There are no files selected for viewing
286 changes: 186 additions & 100 deletions
286
wallet/how-to/connect/set-up-sdk/javascript/react-native.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,150 +1,236 @@ | ||
--- | ||
sidebar_label: React Native | ||
sidebar_label: React Native and Expo | ||
sidebar_position: 4 | ||
--- | ||
|
||
# Use MetaMask SDK with React Native | ||
import Tabs from '@theme/Tabs'; | ||
import TabItem from '@theme/TabItem'; | ||
|
||
Import [MetaMask SDK](../../../../concepts/sdk/index.md) into your React Native dapp to enable your | ||
users to easily connect to the MetaMask browser extension and MetaMask Mobile. | ||
# Use MetaMask SDK with React Native and Expo | ||
|
||
:::tip Example | ||
See the [example React Native dapp](https://github.com/MetaMask/metamask-sdk/tree/main/packages/examples/reactNativeDemo) | ||
in the JavaScript SDK GitHub repository for advanced use cases. | ||
::: | ||
Import [MetaMask SDK](../../../../concepts/sdk/index.md) into your React Native or Expo dapp to | ||
enable your users to easily connect to the MetaMask browser extension and MetaMask Mobile. | ||
|
||
## Prerequisites | ||
|
||
- A [React Native](https://reactnative.dev/docs/0.71/getting-started) project set up with React Native version 0.71 or above | ||
- [MetaMask Mobile](https://github.com/MetaMask/metamask-mobile) version 5.8.1 or above | ||
- [Yarn](https://yarnpkg.com/getting-started/install) or | ||
[npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) | ||
- [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) | ||
|
||
## Steps | ||
|
||
### 1. Install the SDK | ||
### 1. Create a new project | ||
|
||
:::info Coming soon | ||
A `metamask-react-native-sdk` package that simplifies the installation of the SDK for React Native | ||
dapps is coming soon. | ||
::: | ||
Create a new React Native or Expo project using the following commands: | ||
|
||
Use [`rn-nodeify`](https://github.com/tradle/rn-nodeify) to install the SDK. | ||
In your project directory, install `rn-nodeify`: | ||
<Tabs> | ||
<TabItem value="React Native"> | ||
|
||
```bash | ||
yarn add --dev rn-nodeify | ||
``` | ||
```bash | ||
npx react-native@latest init MyProject | ||
``` | ||
|
||
or | ||
</TabItem> | ||
<TabItem value="Expo"> | ||
|
||
```bash | ||
npm i --dev rn-nodeify | ||
``` | ||
```bash | ||
npx create-expo-app devexpo --template | ||
``` | ||
|
||
Install the `rn-nodeify` libraries: | ||
</TabItem> | ||
</Tabs> | ||
|
||
```bash | ||
yarn add react-native-crypto | ||
yarn add react-native-randombytes | ||
yarn add crypto | ||
yarn add process | ||
yarn add stream | ||
yarn add events | ||
``` | ||
### 2. Install the SDK | ||
|
||
In your project's `package.json` file, insert the `rn-nodeify` command into the postinstall script: | ||
Install the SDK and its dependencies using the following commands: | ||
|
||
```json title="package.json" | ||
"scripts": { | ||
..., | ||
"postinstall": "rn-nodeify --install 'crypto,process,stream,events' --hack" | ||
} | ||
``` | ||
<Tabs> | ||
<TabItem value="React Native"> | ||
|
||
`rn-nodeify` creates a `shim.js` file in your project root directory. | ||
Import it in the root file of your application: | ||
```bash | ||
npm install eciesjs @metamask/sdk-react [email protected] @react-native-async-storage/async-storage node-libs-react-native react-native-background-timer react-native-randombytes react-native-url-polyfill react-native-get-random-values | ||
``` | ||
|
||
```bash | ||
import './shim' | ||
``` | ||
</TabItem> | ||
<TabItem value="Expo"> | ||
|
||
Install `react-native-background-timer`: | ||
```bash | ||
npx expo install expo-crypto @metamask/sdk-react [email protected] @react-native-async-storage/async-storage node-libs-expo react-native-background-timer react-native-randombytes react-native-url-polyfill [email protected] | ||
``` | ||
|
||
```bash | ||
yarn add react-native-background-timer | ||
</TabItem> | ||
</Tabs> | ||
|
||
cd ios && pod install && cd .. | ||
``` | ||
### 3. Update the configuration file | ||
|
||
Install MetaMask SDK: | ||
If you're using Expo, run the following command to create a default Metro configuration file: | ||
|
||
```bash | ||
yarn add @metamask/sdk | ||
npx expo customize metro.config.js | ||
``` | ||
|
||
Run the postinstall script after everything is installed: | ||
In React Native or Expo, update the default Metro configuration file to the following: | ||
|
||
```bash | ||
yarn postinstall | ||
``` | ||
<Tabs> | ||
<TabItem value="React Native"> | ||
|
||
```javascript title="metro.config.js" | ||
const { | ||
getDefaultConfig, | ||
mergeConfig, | ||
} = require("@react-native/metro-config"); | ||
|
||
const defaultConfig = getDefaultConfig(__dirname); | ||
|
||
const config = { | ||
transformer: { | ||
getTransformOptions: async () => ({ | ||
transform: { | ||
experimentalImportSupport: false, | ||
inlineRequires: true, | ||
}, | ||
}), | ||
}, | ||
resolver: { | ||
extraNodeModules: { | ||
...require("node-libs-react-native"), | ||
}, | ||
}, | ||
}; | ||
|
||
module.exports = mergeConfig(defaultConfig, config); | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="Expo"> | ||
|
||
```javascript title="metro.config.js" | ||
const config = getDefaultConfig(__dirname); | ||
|
||
config.resolver.extraNodeModules = { | ||
...require("node-libs-expo"), | ||
}; | ||
|
||
config.transformer.getTransformOptions = async () => ({ | ||
transform: { | ||
experimentalImportSupport: false, | ||
inlineRequires: true, | ||
}, | ||
}); | ||
|
||
module.exports = config; | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
### 4. Add import statements | ||
|
||
Add the following import statements to the React Native or Expo entry file: | ||
|
||
Finally, install the necessary pods that come with the libraries: | ||
<Tabs> | ||
<TabItem value="React Native"> | ||
|
||
```javascript title="index.js or App.tsx" | ||
import "node-libs-react-native/globals"; | ||
import "react-native-url-polyfill/auto"; | ||
import "react-native-get-random-values"; | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="Expo"> | ||
|
||
```javascript title="App.tsx" | ||
import "node-libs-expo/globals"; | ||
import "react-native-url-polyfill/auto"; | ||
import "react-native-get-random-values"; | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
### 5. Prebuild the project | ||
|
||
If you're using Expo, prebuild the project using the following command: | ||
|
||
```bash | ||
cd ios && pod install && cd .. | ||
npx expo prebuild | ||
``` | ||
|
||
### 2. Use the SDK | ||
React Native doesn't require prebuilding. | ||
|
||
### 6. Run the project | ||
|
||
Run the React Native or Expo project on Android or iOS using the following commands: | ||
|
||
<Tabs> | ||
<TabItem value="React Native"> | ||
|
||
```bash | ||
npx react-native run-android | ||
npx react-native run-ios | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="Expo"> | ||
|
||
```bash | ||
npx expo run:android | ||
npx expo run:ios | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
Import, instantiate, and use the SDK by adding something similar to the following to your project script: | ||
### 7. Use the SDK | ||
|
||
Initialize and use the SDK in your React Native or Expo project using the `useSDK` hook. | ||
The following code snippets demonstrate how to use the hook. | ||
|
||
Import the hook: | ||
|
||
```javascript | ||
import MetaMaskSDK from '@metamask/sdk'; | ||
import { Linking } from 'react-native'; | ||
import BackgroundTimer from 'react-native-background-timer'; | ||
|
||
const MMSDK = new MetaMaskSDK({ | ||
openDeeplink: (link) => { | ||
Linking.openURL(link); // Use React Native Linking method or another way of opening deeplinks. | ||
}, | ||
timer: BackgroundTimer, // To keep the dapp alive once it goes to background. | ||
dappMetadata: { | ||
name: 'My dapp', // The name of your dapp. | ||
url: 'https://mydapp.com', // The URL of your website. | ||
}, | ||
}); | ||
|
||
const ethereum = MMSDK.getProvider(); | ||
|
||
const accounts = await ethereum.request({ method: 'eth_requestAccounts' }); | ||
import { useSDK } from "@metamask/sdk-react"; | ||
``` | ||
|
||
You can configure the SDK using any [options](../../../../reference/sdk-js-options.md) and call any | ||
[provider API methods](../../../../reference/provider-api.md). | ||
Always call [`eth_requestAccounts`](/wallet/reference/eth_requestaccounts) using | ||
[`ethereum.request(args)`](../../../../reference/provider-api.md#windowethereumrequestargs) first, | ||
since it prompts the installation or connection popup to appear. | ||
Initialize the SDK in your main component: | ||
|
||
:::note Important SDK options | ||
- Use [`dappMetadata`](../../../../reference/sdk-js-options.md#dappmetadata) to display information | ||
about your dapp in the MetaMask connection modal. | ||
- Use [`modals`](../../../../reference/sdk-js-options.md#modals) to [customize the logic and UI of | ||
the displayed modals](../../../display/custom-modals.md). | ||
- Use [`infuraAPIKey`](../../../../reference/sdk-js-options.md#infuraapikey) to | ||
[make read-only RPC requests](../../../use-3rd-party-integrations/js-infura-api.md) from your dapp. | ||
::: | ||
```javascript | ||
const { connect, disconnect, account, chainId, ethereum } = useSDK(); | ||
``` | ||
|
||
You can use [EthersJS](https://docs.ethers.io/v5/getting-started/) with your React Native app: | ||
Connect to MetaMask: | ||
|
||
```javascript | ||
const provider = new ethers.providers.Web3Provider(ethereum); | ||
const connectWallet = async () => { | ||
try { | ||
await connect(); | ||
} catch (error) { | ||
console.error("Failed to connect wallet:", error); | ||
} | ||
}; | ||
``` | ||
|
||
// Get the balance of an account (by address or ENS name, if supported by network). | ||
const balance = await provider.getBalance(ethereum.selectedAddress); | ||
Handle your dapp's state: | ||
|
||
// Often you need to format the output to something more user-friendly, | ||
// such as in ether (instead of wei). | ||
const balanceInETH = ethers.utils.formatEther(balance); | ||
// '0.182826475815887608' | ||
```javascript | ||
useEffect(() => { | ||
// Use the 'account' and 'chainId' returned by 'useSDK' | ||
if (account && chainId) { | ||
// Handle account and network changes | ||
} | ||
}, [account, chainId]); | ||
``` | ||
|
||
Disconnect from MetaMask: | ||
|
||
```javascript | ||
const disconnectWallet = async () => { | ||
await disconnect(); | ||
}; | ||
``` | ||
|
||
## Examples | ||
|
||
See the [example React Native dapp](https://github.com/MetaMask/metamask-sdk/tree/main/packages/examples/reactNativeDemo) | ||
and the [example Expo dapp](https://github.com/MetaMask/metamask-sdk/tree/main/packages/examples/expo-demo) | ||
in the JavaScript SDK GitHub repository for more detailed implementations. |