#15 - A Complete Guide to Mint Solana NFTs through a Mobile App (Android)
- Creat candy machine through Metaplex js
- Creat a Pixel 4 Android virtual device
- Run react-native app on Android Emulator
- Upload image and metadata to Arweave
- Mint Solana NFT through candy machine
The demo procedure is running on solana devnet
├── 📂 metaplex-candy-machine-example
│ │
│ └── 📄 creator.js
│
└── 📂 mobile-nft-mint-example
│
├── 📂 andorid
│
├── 📂 ios
│
├── 📂 patch
│ |
│ └── 📂 arweave
│
├── 📂 src
│ │
│ ├── 📂 components
│ │
│ ├── 📂 hooks
│ │ │
│ │ ├─ ─ 📄 useAuthorization.ts
│ │ │
│ │ ├── 📄 useGuardedCallback.ts
│ │ │
│ │ └── 📄 useUploader.ts
│ │ │
│ │ └── 📄 useMinter.ts
│ │
│ ├── 📄 App.tsx
│ |
│ └── 📄 MainScreen.tsx
│
└── 📂 types
Since Solana Mobile SDK hasn't support iOS yet. You can't connect wallet with @solana/mobile-wallet-adapter on iOS devices. As a result, this tutorial only works on Android right now.
There are two ways to develop React Native App.
- Expo Go
- React Native CLI
We don't talk about which one is better here. The point is I have tried to run this code with Expo Go. However it still has some issues when using @solana/mobile-wallet-adapter, but it works fine with React Native CLI.
So I suggest you to use React Native CLI method to setting up your development environment.
And remeber select Pixel 4 which is the newest verison has Play Store inside.

Select Pixel 4
System Image please select "S API Level 31"

Select S API Level 31
After you run up your virtual Pixel 4, remember to install Phantom or Solflare.
- https://github.com/BoxInThePARK/metaplex-candy-machine-example
$ git clone https://github.com/BoxInThePARK/metaplex-candy-machine-example.git
$ cd metaplex-candy-machine-example
$ pnpm install
- https://github.com/BoxInThePARK/mobile-nft-mint-example
$ git clone https://github.com/BoxInThePARK/mobile-nft-mint-example.git
$ cd mobile-nft-mint-example
$ yarn
- Set Arweave Package to Local PatchRight now,
arweave-js
hasn't completely supported react-native yet. Therefore, if you want to upload image or metadata to Arweave network througharweave-js
package. You will address some issues occured by some needed packages are unable to resolve on react-native. Because react-native doesn't have them.To solve these problems, not only you should install other packages, you also need to do small modification on the package's sourcecode. This is the reason why we setarweave-js
as a local patch,Here are the steps:- Installyarn add text-encoding
- Modify source code// In patch/arweave/node/lib/utils.js...// Line 61const {TextEncoder} = require('text-encoding');
//In metaplex-candy-machine-example
touch .env
Paste this to .env
//In .env
ARWEAVE_KEY=[The key you get from "Set Arweave Wallet"]
METAPLEX_PRIVATE_KEY=[The secret key of your test wallet address]
$ pnpm create-candy-machine
> [email protected] create-candy-machine ../metaplex-candy-machine-example
> node ./creator.js
publicKey [your wallet address]
Upload Collection Metadata
metadataUrl https://arweave.net/xxxxxxxxx
Initialize Metaplex
Create the Collection NFT
Create the Candy Machine
Done
candyMachine_address [new cm address]
Then you can get a new candy machine address.
//In mobile-nft-mint-example
touch .env
Paste this to .env
//In .env
REACT_APP_ARWEAVE_KEY=[The key you get from "Set Arweave Wallet"]
REACT_APP_METAPLEX_PRIVATE_KEY=[The secret key of your test wallet address]
REACT_APP_CANDY_MACHINE_ADDRESS=[The candy machine address you get from Part 1]
Recommend to have two terminal windows here.
Run the Metro
$ yarn start --reset-cache
Install App
$ yarn android
Set Wallet to devnet
// In src/hooks/useAuthorization.ts
...
// Line 66
uri: 'https://book.solmeet.dev/',


//Initialize Metaplex
console.log('Initialize Metaplex');
const metaplex = Metaplex.make(connection).use(
keypairIdentity(metapleKeypair),
);
const treasury = metaplex.identity().publicKey;
//Find Candy Machine with Address
console.log('Fetch the Candy Machine');
let candyMachine = await metaplex.candyMachines().findByAddress({
address: new PublicKey(REACT_APP_CANDY_MACHINE_ADDRESS),
});
console.log('Update the Candy Machine');
await metaplex.candyMachines().update({
candyMachine,
guards: {
botTax: {lamports: sol(0.01), lastInstruction: true},
solPayment: {amount: sol(0.1), destination: treasury},
startDate: {date: toDateTime('2022-10-17T16:00:00Z')},
// All other guards are disabled...
},
});
//Insert Item and Refresh Candy Machine
console.log('Insert Item to the Candy Machine');
await metaplex.candyMachines().insertItems({
candyMachine,
items: [{name: metaData.name, uri: metaData.id}],
});
candyMachine = await metaplex.candyMachines().refresh(candyMachine);
//Mint
console.log('Mint');
const {nft} = await metaplex.candyMachines().mint({
candyMachine,
collectionUpdateAuthority: metapleKeypair.publicKey,
owner: selectedAccount.publicKey,
});


- https://reactnative.dev/docs
- https://github.com/solana-mobile/mobile-wallet-adapter
- https://github.com/solana-mobile/mobile-wallet-adapter/tree/main/examples/example-react-native-app
- https://github.com/metaplex-foundation/js-examples/tree/main/mint-ui-example
- https://docs.metaplex.com/programs/token-metadata/overview
- https://github.com/thuglabs/arweave-image-uploader