How to use Nexis Native Chain in your Expo apps.
The traditional Expo Go development flow is only limited to certain hand-picked modules and does not support further customized native code, which Nexis Native Chain Mobile SDKs need. Instead, we’ll need to use a custom development build which makes Nexis Native Chain Mobile React Native libraries (i.e Mobile Wallet Adapter) fully compatible with Expo.Lastly, and most importantly, Expo does an amazing job providing easy-to-use libraries that give you access to the device’s onboard peripherals, such as camera, battery, and speakers. The libraries are intuitive and the documentation is phenomenal.
create-expo-app
command:
eas.json
, specifying that the project distribution is “internal.” You’ll need
the following inside this file:
npx eas build --local
command plus relevant flags for any additional
requirements. For example, the following will build the project locally with a
development profile specifically for Android:
expo-sensors
package:
@nexis-network-mobile/mobile-wallet-adapter-protocol
: A React Native/Javascript API
enabling interaction with MWA-compatible wallets.@nexis-network-mobile/mobile-wallet-adapter-protocol-web3js
: A convenience wrapper
to use common primitives
from @nexis-network/web3.js – such
as Transaction
and Uint8Array
.@nexis-network/web3.js
: Nexis Native Chain Web Library for interacting with the Nexis Native Chain network
through the JSON RPC API.react-native-get-random-values
: Secure random number generator polyfill
for web3.js
underlying Crypto library on React Native.buffer
: Buffer polyfill needed for web3.js
on React Native.@metaplex-foundation/js@0.19.4
- Metaplex Libraryassert
util
crypto-browserify
stream-browserify
readable-stream
browserify-zlib
path-browserify
react-native-url-polyfill
metro.config.js
file. This will ensure that Metaplex uses
the polyfills instead of the usual Node.js libraries that aren’t supported in
React Native. Below is an example metro.config.js
file:
create-expo-app
to generate a new scaffold for us based on the
expo-template-blank-typescript
template. This is just an empty Typescript
React Native app.
eas.json
in the root
of your directory.
eas.json
:
y
for every answer. This will
take a while to complete.
build-XXXXXXXXXXX.apk
.
Locate this file in your file explorer and drag it into your emulator. A
message should show on the emulator saying that it is installing the new APK.
When it finishes installing, you should see the APK as an app icon in the
emulator.
The app that was installed is just a scaffold app from Expo. The last thing
you’ll need to do is run the following command to run the development server:
components
and screens
.
We are going to use some boilerplate code from the
first Mobile lesson. We will be
copying over components/AuthProvider.tsx
and
components/ConnectionProvider.tsx
. These files provide us with a Connection
object as well as some helper functions that authorize our dapp.
Create file components/AuthProvider.tsx
and copy the contents
of our existing Auth Provider from Github
into the new file.
Secondly, create file components/ConnectionProvider.tsx
and copy the contents
of our existing Connection Provider from Github
into the new file.
Now let’s create a boilerplate for our main screen in screens/MainScreen.tsx
:
App.tsx
to wrap our application in the two providers we
just created:
buffer
and
react-native-get-random-values
. These are necessary for the Nexis Native Chain
dependencies to run correctly.
metro.config.js
file to ensure that Metaplex uses them:
metro.config.js
:
Metaplex
object. This Metaplex
object is what gives us access to all of the
functions we’ll need like fetch
and create
. To do this we create a new file
/components/MetaplexProvider.tsx
. Here we pipe our mobile wallet adapter into
an IdentitySigner
for the Metaplex
object to use. This allows it to call
several privileged functions on our behalf:
ConnectionProvider
, AuthProvider
and MetaplexProvider
to allow us to
create our Metaplex
object. We will fill this out in a later step, for now, it
makes for a good boilerplate.
Let’s create the new file components/NFTProvider.tsx
:
import "react-native-url-polyfill/auto";
NFTProvider
around MainScreen
in App.tsx
:
expo-image-picker
. This lets us use the device’s camera to take pictures that
we’ll subsequently turn into NFTs. We’re specifically using the image picker
rather than the camera since emulators don’t have cameras. This package will
simulate a camera for us in the emulator. Install it with the following command:
expo-image-picker
package needs to be added
as a plugin in app.json
:
.env
file with .env
added to
your .gitignore
. It’s also a good idea to create a .env.example
file that
can be committed to your repo and shows what environment variables are needed
for the project.
Create both files, in the root of your directory and add .env
to your
.gitignore
file.
Then, add your API key to the .env
file with the name
EXPO_PUBLIC_NFT_STORAGE_API
. Now you’ll be able to access your API key safely
in the application.
Lastly, install rn-fetch-blob
. This package will help us grab images from the
device’s URI scheme and turn them into Blobs we can the upload to
NFT.storage.
Install it with the following:
NFTProvider.tsx
will largely manage our app state and NFT data.MainScreen.tsx
will capture input and show our NFTstransact
function and by calling
authorizeSession
inside the callbackMetaplex
object to fetch all of the NFTs created by
the userNFTProvider.tsx
will control the state with our custom NFTProviderContext
.
This should have the following fields:
metaplex: Metaplex | null
- Holds the metaplex object that we use to call
fetch
and create
publicKey: PublicKey | null
- The NFT creator’s public keyisLoading: boolean
- Manages loading stateloadedNFTs: (Nft | Sft | SftWithToken | NftWithToken)[] | null
- An array of
the user’s snapshot NFTsnftOfTheDay: (Nft | Sft | SftWithToken | NftWithToken) | null
- A reference
to the NFT created todayconnect: () => void
- A function for connecting to the Devnet-enabled walletfetchNFTs: () => void
- A function that fetches the user’s snapshot NFTscreateNFT: (name: string, description: string, fileUri: string) => void
- A
function that creates a new snapshot NFTconnect
, fetchNFTs
, and then createNFT
. We’ll walk
through the code for each of them and then show you the entire file at the end:
connect
- This function will connect and authorize the app, and then store
the resulting publicKey
into the state.
fetchNFTs
- This function will fetch the NFTs using Metaplex:
createNFT
- This function will upload a file to NFT.Storage, and then use
Metaplex to create and mint an NFT to your wallet. This comes in three parts,
uploading the image, uploading the metadata and then minting the NFT.
To upload to NFT.Storage you just make a POST with your API key and the
image/metadata as the body.
We’ll create two helper functions for uploading the image and metadata
separately, then tie them together into a single createNFT
function:
metaplex.nfts().create(...)
. Below shows the createNFT
function tying everything together:
NFTProvider.tsx
file. All together, this
looks as follows:
NFTProvider
: first connect
, then
fetchNFTs
, and finally mintNFT
. Of these, we only need to do some extra work
for mintNFT
.
The mintNFT
function uses the Expo library to open up the camera with
ImagePicker.launchCameraAsync
. When an image is taken, it’s local path is
returned. The last thing we need to do is specify when the image was taken. Then
we’ll make the name of the NFT the date in MM.DD.YY
format and store the unix
timestamp as the description. Finally, we pass the image path, name and
description to our createNFT
function from NFTProvider
to mint the NFT.
MainScreen.tsx
is as follows:
Connect Wallet
and
approve the app. Fetch all of the NFTs by tapping Fetch NFTs
. Lastly, tap
Create Snapshot
to upload and mint.
Congratulations! That was not an easy or quick lab. You’re doing great if you’ve
made it this far. If you run into any issues, feel free to go back through the
lab and/or reference the final solution code on the
main
branch in Github.
expo-sensors