diff --git a/README.md b/README.md
index 381ac32..410cd5d 100644
--- a/README.md
+++ b/README.md
@@ -4,68 +4,73 @@ objectives:
- Explain the benefits of creating mobile-first dApp experiences
- Explain the high level Mobile Wallet Adapter (MWA) flow
-- Explain the high level differences between React and React native
+- Explain the high level differences between React and React Native
- Create a simple Android Solana dApp using React Native
+description:
+ "Learn how to build native mobile apps using blockchain functionality"
---
-# TL;DR
+## Summary
-- The Solana Mobile Wallet Adapter introduces a new protocol and flow for mobile apps to interact with wallets\
- - The Mobile Wallet Adapter creates a web socket connection between mobile apps and mobile wallets, allowing apps to submit transactions for signing
-- The simplest way to get started creating Solana mobile applications is with Solana Mobile's React Native packages `@solana-mobile/mobile-wallet-adapter-protocol` and `@solana-mobile/mobile-wallet-adapter-protocol-web3js`
- - React native is very similar to React with a few mobile quirks
+- The Solana Mobile Wallet Adapter (MWA) introduces a new protocol and flow for mobile apps to interact with wallets.
+ - The Mobile Wallet Adapter creates a web socket connection between mobile apps and mobile wallets, allowing native mobile apps to submit transactions for signing
+- The simplest way to get started creating Solana mobile applications is with Solana Mobile's [React Native packages](https://docs.solanamobile.com/react-native/setup) `@solana-mobile/mobile-wallet-adapter-protocol` and `@solana-mobile/mobile-wallet-adapter-protocol-web3js`
+ - React Native is very similar to React with a few mobile quirks
-# Overview
+## Overview
-Solana has gone mobile! For a long time, dApps were web-first rather than mobile-first. That started to change with the announcement of the Solana Mobile Stack (SMS) in 2022. This stack is designed to create dApps that provide a seamless mobile UX. It consists of the [Mobile Wallet Adapter (MWA)](https://docs.solanamobile.com/getting-started/overview#mobile-wallet-adapter), [Seed Vault](https://docs.solanamobile.com/getting-started/overview#seed-vault) and the [Solana dApp Store](https://docs.solanamobile.com/getting-started/overview#solana-dapp-store).
+Solana has gone mobile! For a long time, dApps were web-first rather than mobile-first. That started to change with the announcement of the Solana Mobile Stack (SMS) in 2022. This stack is designed to help developers create mobile dApps with a seamless UX. It consists of the [Mobile Wallet Adapter (MWA)](https://docs.solanamobile.com/getting-started/overview#mobile-wallet-adapter), [Seed Vault](https://docs.solanamobile.com/getting-started/overview#seed-vault) and the [Solana dApp Store](https://docs.solanamobile.com/getting-started/overview#solana-dapp-store).
-Most relevant to your development journey is the Mobile Wallet Adapter. The simplest way to get started is to use the Mobile Wallet Adapter with React Native to create a simple Android app. This lesson assumes you're familiar with React and Solana programming. If that's not the case, [start our course from the beginning](./intro-to-cryptography.md) and come back here when you feel ready!
+Most relevant to your development journey is the Mobile Wallet Adapter (MWA). The simplest way to get started is to use the Mobile Wallet Adapter with React Native to create a simple Android app. This lesson assumes you're familiar with React and Solana programming. If that's not the case, [start our course from the beginning](https://github.com/solana-foundation/developer-content/blob/main/content/courses/intro-to-solana/intro-to-cryptography.md) and come back here when you feel ready!
-## Intro To Solana Mobile
+### Intro To Solana Mobile
-Between the Solana Mobile Stack and the Saga mobile device, Solana Mobile has a lot of connotations. For the purposes of this course, we'll be focused on mobile application development where the apps interact with the Solana network. This opens up a whole new paradigm of Crypto use cases and behaviors.
+In these units, we'll develop mobile apps that interact with the Solana network.
+This opens up a whole new paradigm of blockchain use cases and behaviors.
-### Solana Mobile Use Cases
+#### Solana Mobile Use Cases
The crypto mobile market has a lot of untapped potential. With the right apps, everyone can walk around with the power of Solana in their pockets. Here are a few examples of what Solana mobile development can unlock:
**Mobile Banking and Trading (DeFi)**
-DeFi apps aren't new, but they're often web-bound and don't have a great mobile experience. By comparison, most traditional banking right now happens on mobile. With SMS, you can now bank and trade with your own wallet, where you hold your own keys.
+DeFi apps aren't new, but they're often web-bound and don't have a great mobile experience. By comparison, most traditional banking right now happens on mobile. With SMS, you can now bank and trade using native mobile apps with your own wallet, where you hold your own keys.
**Mobile Gaming with Solana Micropayments**
-Traditional mobile games are a cash cow. 50% of the video game industry’s valuation is due to Mobile gaming with "micropayments." However, due to payment facilitator fees, these in-game purchases usually have a minimum of $0.99. With Solana, it's possible to unlock true micropayments. Need an extra life? How about pay 0.0001 sol?
+Mobile games account for roughly 50% of the video game industry’s total value, largely due to small in-game purchases. However, payment processing fees usually mean these in-game purchases have a minimum of $0.99 USD. With Solana, it's possible to unlock true micropayments. Need an extra life? That'll be 0.0001 SOL.
**Mobile E-Commerce**
SMS can enable a new wave of mobile e-commerce shoppers to pay directly from their favorite Solana wallet. Imagine a world where you can use your Solana wallet as seamlessly as you can use Apply Pay.
-Mobile crypto is the future, and Solana knows this. Let’s dive in and learn how we can be part of it.
+To summarize, mobile blockchain opens up many doors. Let’s dive in and learn how
+we can be part of it:
-### How it differs
+#### How Solana development differs between native mobile apps and web
Solana wallet interaction differs slightly on mobile compared to web. The core wallet functionality is the same: the wallet holds your private keys and uses them to sign and send transactions. To avoid having different interfaces between wallets, developers abstracted that functionality into the Solana Wallet Adapter standard. This remains the standard on web. The mobile counterpart is the Mobile Wallet Adapter (MWA).
-The differences between the two standards are due to the different construction of web vs mobile wallets. Web wallets are just browser extensions that inject wallet adapter functions into the `window` object of your webpage. This gives your site access to them. Mobile wallets, however, are native applications. There's no way to surface functions from one native application to another. The Mobile Wallet Adapter exists as a workaround to enable any app, written in any language, to connect to a native wallet app.
+The differences between the two standards are due to the different construction of web vs mobile wallets. Web wallets are just browser extensions that inject wallet adapter functions into the `window` object of your webpage. This gives your site access to them. Mobile wallets, however, are native applications on a
+mobile operating system. There's no way to surface functions from one native application to another. The Mobile Wallet Adapter exists as a workaround to enable any app, written in any language, to connect to a native wallet app.
-We'll dig into the specifics of the Mobile Wallet Adapter in a later lesson, but it effectively opens a WebSocket between applications to facilitate communication. That way a separate app can provide the wallet app with the transaction to be signed and sent, and the wallet app can respond with appropriate status updates.
+We'll dig into the specifics of the Mobile Wallet Adapter in a [later lesson](https://github.com/solana-foundation/developer-content/blob/main/content/courses/mobile/mwa-deep-dive.md), but it effectively opens a WebSocket between applications to facilitate communication. That way a separate app can provide the wallet app with the transaction to be signed and sent, and the wallet app can respond with appropriate status updates.
-### Supported Operating Systems
+#### Supported Operating Systems
At the time of writing, Android is the only mobile OS supported by the Mobile Wallet Adapter.
-On `Android`, a websocket connection is able to persist between apps, even when the wallet app is in the background.
+On Android, a WebSocket connection is able to persist between apps, even when the wallet app is in the background.
-On `iOS`, the lifetime of a connection between apps is purposefully limited by the operating system. Specifically, iOS will quickly suspend connections when an app is pushed to the background. This kills the MWA websocket connection. This is an inherent design difference between iOS and Android (probably made to preserve battery, network usage, etc).
+On iOS, the lifetime of a connection between apps is purposefully limited by the operating system. Specifically, iOS will quickly suspend connections when an app is pushed to the background. This kills the MWA websocket connection. This is an inherent design difference between iOS and Android (probably made to preserve battery, network usage, etc).
-However, this doesn’t mean that Solana dApps can’t run on iOS at all. You can still create a Mobile Web App using the [standard wallet adapter](https://github.com/solana-labs/wallet-adapter)` library. Your users can then install a mobile-friendly wallet like the [Glow Wallet](https://glow.app/).
+However, this doesn’t mean that Solana dApps can’t run on iOS at all. You can still create a Mobile Web App using the [standard wallet adapter](https://github.com/solana-labs/wallet-adapter) library. Your users can then install a mobile-friendly wallet like the [Glow Wallet](https://glow.app/).
-This lesson will focus on developing Android apps with the MWA.
+The remainder of this lesson will focus on developing Android apps with the MWA.
### Supported Frameworks
-Solana Mobile supports a number of different frameworks. Officially supported are React native and native Android, with community SDKs for Flutter, Unity, and Unreal Engine.
+Solana Mobile supports a number of different frameworks. Officially supported are React Native and native Android, with community SDKs for Flutter, Unity, and Unreal Engine.
**Solana SDKs:**
@@ -80,28 +85,30 @@ Solana Mobile supports a number of different frameworks. Officially supported ar
To keep the development experience as close as possible with other lessons, we'll be working exclusively with React Native.
-## React to React Native
+### From React to React Native
React Native takes the React web framework and applies it to mobile applications. However, while React and React Native feel very similar, there are differences. The best way to understand these differences is to experience them while coding. But, to give you a head start here is a list of some differences to keep in mind:
- React Native compiles down to native iOS and Android applications while React compiles down to a collection of web pages.
-- In React, you use JSX to program with HTML and CSS, with React Native you use similar syntax to manipulate native UI components. Instead of `
`, `
` and `
` you'll be using ``, `` and ``.
+- In React, you use JSX to program with HTML and CSS, with React Native you use similar syntax to manipulate native UI components. It's more like using a UI library like Chakra or Tailwind UI. Instead of ``, `
` and `
` you'll be using ``, `` and ``.
- Interactions are different. Instead of `onClick`, you'll use `onPress` and other gestures.
-- Many standard React packages may not be compatible with React Native. Fortunately, there are a React Native counterparts to most popular libraries.
+- Many standard React and Node packages may not be compatible with React Native. Fortunately, there are React Native counterparts to the most popular libraries and you can often use polyfills to make Node packages available. If you're not familiar with polyfills, take a look at the [MDN docs](https://developer.mozilla.org/en-US/docs/Glossary/Polyfill). In short, polyfills actively replace Node-native libraries to make them work anywhere Node is not running.
- Setting up a development environment in React Native can be challenging. This will require setting up Android Studio to compile to Android and XCode for iOS. React Native has a [really good guide](https://reactnative.dev/docs/environment-setup?guide=native) for this.
- For regular development and testing, you'll use a physical mobile device or an emulator to run your code. This relies on a tool called Metro that comes pre-installed. React native's setup guide also covers this.
-- React Native gives you access to the phone's hardware that React can't provide. This includes things like the phone's accelerometer, allocated storage, and more.
-- React Native introduces new config files and build folders. For example `ios` and `android` contain platform specific information, then then we have config files like `Gemfile` and `metro.config.js`. Generally, leave all configurations alone and just worry about writing your code, the starting point for which will be in `App.tsx`.
+- React Native gives you access to the phone's hardware that React can't provide. This includes things like the phone's camera, accelerometer, and more.
+- React Native introduces new config files and build folders. For example, the `ios` and `android` directories contain platform-specific information. Additionally, there are config files like `Gemfile` and `metro.config.js`. Generally, leave all configurations alone and just worry about writing your code, the starting point for which will be in `App.tsx`.
-There is a learning curve, but if you know React you're not nearly as far from being able to develop mobile apps as you think! It may feel jarring to start, but after a few hours of React native development you'll start to feel much more comfortable. You'll likely feel much more confident after [this lesson's demo](#demo).
+There is a learning curve, but if you know React you're not nearly as far from being able to develop mobile apps as you think! It may feel jarring to start, but after a few hours of React Native development, you'll start to feel much more comfortable. You'll likely feel much more confident even after [this lesson's lab](#lab).
-## Creating a Solana dApp with React Native
+### Creating a Solana dApp with React Native
-Solana React Native dApps are virtually identical to React dApps. The primary difference is in the wallet interaction. Instead of the wallet being available in the browser, your dApp will create an MWA session with the wallet app of your choosing using a websocket. Fortunately, most of this is abstracted for you in the MWA library.
+Solana React Native dApps are virtually identical to React dApps. The primary difference is in the wallet interaction. Instead of the wallet being available in the browser, your dApp will create an MWA session with the wallet app of your choosing using a websocket. Fortunately, this is abstracted for you in the MWA
+library. The only difference you'll need to know is anytime you need to make a call to the wallet you'll be using the `transact` function, which we'll talk about soon.
-
+
-### Reading data
+
+#### Reading data
Reading data from a Solana cluster in React Native is the exact same as in React. You use the `useConnection` hook to grab the `Connection` object. Using that, you can get account info. Since reading is free, we don’t need to actually connect to the wallet.
@@ -109,15 +116,15 @@ Reading data from a Solana cluster in React Native is the exact same as in React
const account = await connection.getAccountInfo(account);
```
-If you need a refresher on this, check out our [lesson on reading data from the blockchain](./intro-to-reading-data.md).
+If you need a refresher on this, check out our [lesson on reading data from the blockchain](https://github.com/solana-foundation/developer-content/blob/main/content/courses/intro-to-solana/intro-to-reading-data.md).
-### Connecting to a wallet
+#### Connecting to a wallet
-Writing data to the blockchain has to happen through a transaction. Transactions have to be signed by one or more private keys and sent to an RPC provider. This virtually always happens through a wallet application.
+Writing data to the blockchain has to happen through a transaction. Transactions have to be signed by one or more secret keys and sent to an RPC provider. This virtually always happens through a wallet application.
-Typical wallet interaction happens by calling out to a browser extension. On mobile, you use a websocket to start an MWA session. Specifically, you use Android intents where the dApp broadcasts its intent with the `solana-wallet://` scheme.
+Typical wallet interaction happens by calling out to a browser extension. On mobile, you use a WebSocket to start an MWA session. Specifically, you use Android intents where the dApp broadcasts its intent with the `solana-wallet://` scheme.
-
+
When the wallet app receives this intent, it opens a connection with the dApp that initiated the session. Your dApp sends this intent using the `transact` function:
@@ -127,23 +134,25 @@ transact(async (wallet: Web3MobileWallet) => {
}
```
-This will give you access to the `Web3MobileWallet` object. You can then use this to send transactions to the wallet.
+This will give you access to the `Web3MobileWallet` object. You can then use this to send transactions to the wallet. Again, when you want to access the wallet, it has to be through the function `transact` function's callback.
+
+#### Signing and sending transactions
-### Sending transactions
+Sending a transaction happens inside the `transact` callback. The flow is as follows:
-Transacting with a wallet through the MWA has a few extra steps compared to the web counterpart. The flow is as follows:
+1. Establish a session with a wallet using `transact` which will have a callback of `async (wallet: Web3MobileWallet) => {...}`.
+2. Inside the callback, request authorization with the `wallet.authorize` or `wallet.reauthorize` method depending on the state of the wallet.
+3. Sign the transaction with `wallet.signTransactions` or sign and send with `wallet.signAndSendTransactions`.
-1. Establish a session with a wallet using `transact`
-2. Request Authorization with the `authorizeSession(wallet)` function from the `useAuthorization()` hook.
-3. Sign Transaction with `wallet.signTransactions` or sign and send with `wallet.signAndSendTransactions`.
+
-
+You may want to create a `useAuthorization()` hook to manage the wallet's authorization state. We'll practice this in the [Lab](#lab).
-Note that `await authorizeSession(wallet)` will also reauthorize a session if one has already been established. Generally, if you want to send a transaction to the blockchain the following code snippet is what you’ll need:
+Here is an example of sending a transaction using MWA:
```tsx
-const {authorizeSession} = useAuthorization();
-const {connection} = useConnection();
+const { authorizeSession } = useAuthorization();
+const { connection } = useConnection();
const sendTransactions = (transaction: Transaction)=> {
@@ -160,57 +169,59 @@ const sendTransactions = (transaction: Transaction)=> {
const signature = await wallet.signAndSendTransactions({
transactions: [transaction],
});
- })
-}
+ });
+};
```
-### Debugging
+#### Debugging
Since two applications are involved in sending transactions, debugging can be tricky. Specifically, you won’t be able to see the wallet's debug logs the way you can see your dApps logs.
Fortunately, [Logcat on Android Studio](https://developer.android.com/studio/debug/logcat) makes it possible to see logs from all applications on your device.
-If you prefer not to use Logcat, the other method you could try is to only use the wallet to sign transactions, and then send them in your code. This will allows you to better debug the transaction if you’re running into problems.
+If you prefer not to use Logcat, the other method you could try is to only use the wallet to sign transactions, and then send them in your code. This allows you to better debug the transaction if you’re running into problems.
-### Releasing
+#### Releasing
-Deploying mobile application can be difficult on its own. It's often even more difficult when it's a crypto app. There are two main reasons for this: customer safety and circumnavigating the marketplace fee.
+Deploying mobile application can be difficult on its own. It's often even more difficult when it's a blockchain app. There are two main reasons for this: customer safety and and financial incentives.
-First, most of the mobile app marketplaces have policies restricting blockchain involvement. Crypto is new enough that it's a regulatory wildcard. Platforms feel they're protecting users by being strict with blockchain-related apps.
+First, most of the mobile app marketplaces have policies restricting blockchain involvement. Blockchain is new enough that it's a regulatory wildcard. Platforms feel they're protecting users by being strict with blockchain-related apps.
-Second, if you use crypto for "purchases" in-app, you’ll be seen as circumnavigating the platform’s fee (anywhere from 15-30%). This is explicitly against app store policies as the platform is trying to protect its revenue stream.
+Second, in some marketplaces, using blockchain-based apps for in-app "purchases" can be seen as circumnavigating the platform’s fee (typically 15-30%). This explicitly violates certain app store policies, as these platforms aim to protect their revenue streams.
These are hurdles for sure, but there's hope. Here are some things to keep in mind for each marketplace:
-- **App Store (iOS) -** We only talked about android today for the technical MWA reason. However, their policies are also some of the most strict and make it hard for Solana dApps to exist. For now, Apple has some pretty strict anti-crypto policies. Wallets seem to be fine, but they'll flag and likely reject anything that seems like a "purchase" using crypto.
-- **Google Play (Android) -** Google is generally more relaxed, but there are still a few things to be aware of. As of this writing in Sep ‘23, Google is rolling out [new crypto policies](https://www.theverge.com/2023/7/12/23792720/android-google-play-blockchain-crypto-nft-apps) to make it more clear what they will and will not allow. Take a look.
-- **Steam -** Does not allow crypto games at all
- > “built on blockchain technology that issue or allow the exchange of cryptocurrencies or NFTs.”
- >
+- **App Store (iOS) -** We only talked about Android today for the technical MWA reason. However, their policies are also among the strictest, making it difficult for Solana dApps to thrive. Currently, Apple has some pretty strict anti-blockchain and NFT policies, and its In-App Purchase system does not
+ support crypto.
+- **Google Play (Android) -** Google is generally more relaxed, but there are still a few things to be aware of. In December 2023, Google rolled out new policies for [blockchain-based apps](https://www.theverge.com/2023/7/12/23792720/android-google-play-blockchain-crypto-nft-apps) to clarify their rules.
+- **Steam -** Does not allow games based on blockchain technology
+ > “games based on blockchain technology that issue or allow the exchange of
+ > cryptocurrencies or NFTs are banned."
- **Download Sites / Your Site -** Depending on the target platform, you can make your dApp available for download on your own site. However, most users are wary of downloading mobile applications from websites.
- **dApp Store (Solana) -** Solana saw the issues with mobile dApp distribution on other platform app stores and decided to make their own. As part of the SMS stack, they created the [Solana dApp Store](https://docs.solanamobile.com/getting-started/overview#solana-dapp-store).
-## Conclusion
+### Conclusion
-Getting started with mobile Solana development is fairly straightforward thanks to SMS. Remember to look at our other lessons if you need a refresher on Solana development more broadly.
+Getting started with mobile Solana development is fairly straightforward thanks to SMS. While React Native is slightly different than React, the code you have to write is more similar than different. The primary difference is that the portion of your code that interacts with wallets will exist within the `transact` callback. Remember to look at our other lessons if you need a refresher on Solana development more broadly.
-# Demo
+## Lab
-Let's practice this together by building a simple Android mobile counter dApp with React Native. The app will interact with the Anchor counter program that we made in the [Intro to client-side Anchor development](https://www.soldev.app/course/intro-to-anchor-frontend) lesson. In this app, we’ll be able to see the current count, connect our wallet, and increment the count. We’ll be doing this all on Devnet, and will be compiling only for Android.
+Let's practice this together by building a simple Android mobile counter dApp with React Native. The app will interact with the Anchor counter program that we made in the [Intro to client-side Anchor development](https://www.soldev.app/course/intro-to-anchor-frontend) lesson. This dApp simply displays a counter and allows users to increment the count through a Solana program. In this app, we’ll be able to see the current count, connect our wallet, and increment the count. We’ll be doing this all on Devnet, and will be compiling only for Android.
This program already exists and is already deployed on Devnet. Feel free to check out the [deployed program's code](https://github.com/Unboxed-Software/anchor-ping-frontend/tree/solution-decrement) if you want more context.
We’ll write this application in vanilla React Native without a starting template. Solana Mobile provides a [React Native template](https://docs.solanamobile.com/react-native/react-native-scaffold) that shortcuts some of the boilerplate, but there's no better way to learn than to do something from scratch.
-### 0. Prerequisites
+#### 0. Prerequisites
React Native allows us to write mobile applications using similar patterns as React. However, under the hood our React code needs to be compiled down to languages and frameworks that work with the device's native OS. This requires a few prerequisite setup items:
-1. [Setup a React Native dev environment](https://reactnative.dev/docs/environment-setup?guide=native#creating-a-new-application). Go through the ***entire article*** following the steps using Android as the target OS. For convenience, we've typed out the high level steps below. Keep in mind that the source article might change from the time of writing to when you're reading this. The source article is your source of truth here.
+1. [Setup a React Native dev environment](https://reactnative.dev/docs/environment-setup?guide=native#creating-a-new-application). Go through the [**_entire article_**](https://reactnative.dev/docs/environment-setup?guide=native#creating-a-new-application), using Android as the target OS. For convenience, we've typed out the high level steps below. Keep in mind that the source article might change from the time of writing to when you're reading this. The source article is your source of truth here.
1. Install dependencies
2. Install Android Studio
- 3. Configure **ANDROID_HOME** environment variable
- 4. Create a new sample project (this is only used to set up the emulator)
+ 3. Install the Android SDK
+ 4. Configure **ANDROID_HOME** environment variable
+ 5. Create a new sample project (this is only used to set up the emulator)
1. If you run into the error `✖ Copying template`, add the `--npm` flag at the end
```bash
@@ -234,20 +245,20 @@ React Native allows us to write mobile applications using similar patterns as Re
2. In Android Studio, `Open project > Navigate to the cloned directory > Select mobile-wallet-adapter/android`
3. After Android Studio finishes loading the project, select `fakewallet` in the build/run configuration dropdown in the top right
- 
+ 
4. For debugging, you’ll want to use `Logcat`. Now that your fake wallet is running on the emulator, go to `View -> Tool Windows -> Logcat`. This will open up a console logging out what’s happening with fake wallet.
- 3. (Optional) Install other Solana wallets like Phantom on the Google Play store.
+ 3. (Optional) Install other [Solana wallets](https://solana.com/ecosystem/explore?categories=wallet) on the Google Play store.
Lastly, if you run into Java versioning issues - you’ll want to be on Java version 11. To check what you’re currently running type `java --version` in your terminal.
-### 1. Plan out App Structure
+#### 1. Plan out App Structure
Before we do any coding, let's conceptualize the outline of the app. Again, this app will connect to and interact with the counter program we've already deployed to Devnet. To do this, we'll need the following:
-- A `Connection` object to interact with Solana. (`ConnectionProvider.tsx`)
-- Access to our counter program. (`ProgramProvider.tsx`)
-- Connection to a wallet to sign and send requests. (`AuthProvider.tsx`)
+- A `Connection` object to interact with Solana (`ConnectionProvider.tsx`)
+- Access to our counter program (`ProgramProvider.tsx`)
+- Authorization for a wallet to sign and send requests (`AuthProvider.tsx`)
- Text to display our counter value (`CounterView.tsx`)
- A button to press to increment our count (`CounterButton.tsx`)
@@ -255,7 +266,7 @@ There will be more files and considerations, but these are the most important fi
### 2. Create the App
-Now that you've got some of the basic setup and structure down, let’s create a new app with the following command:
+Now that you've got some of the basic setup and structure down, let’s scaffold a new app with the following command:
```bash
npx react-native@latest init counter --npm
@@ -263,30 +274,31 @@ npx react-native@latest init counter --npm
This scaffolds a new React Native project for us called `counter`.
-Let's make sure everything is set up properly by starting the default app and running it on our android emulator.
+Let's make sure everything is set up properly by starting the default app and running it on our Android emulator.
```bash
cd counter
npm run android
```
-This should open and run the app in your Android emulator. If you run into problems, check to make sure you’ve accomplished everything in the prerequisite section.
+This should open and run the app in your Android emulator. If you run into problems, check to make sure you’ve accomplished everything in the [prerequisites section](#0-prerequisites).
### 3. Install Dependencies
-We’ll need to add in our Solana dependencies. [The Solana Mobile docs provide a nice list of packages](https://docs.solanamobile.com/react-native/setup) we need and why we need them:
+We’ll need to add in our Solana dependencies. [The Solana Mobile docs provide a nice list of packages](https://docs.solanamobile.com/react-native/setup) and explanations for why we need them:
-- `@solana-mobile/mobile-wallet-adapter-protocol`: A React Native/Javascript API enabling interaction with MWA-compatible wallets.
-- `@solana-mobile/mobile-wallet-adapter-protocol-web3js`: A convenience wrapper to use common primitives from [@solana/web3.js](https://github.com/solana-labs/solana-web3.js) – such as `Transaction` and `Uint8Array`.
-- `@solana/web3.js`: Solana Web Library for interacting with Solana network through the [JSON RPC API](https://docs.solana.com/api/http).
-- `react-native-get-random-values` Secure random number generator polyfill for `web3.js` underlying Crypto library on React Native.
-- `buffer` Buffer polyfill also needed for `web3.js` on React Native.
+- `@solana-mobile/mobile-wallet-adapter-protocol`: A React Native/Javascript API enabling interaction with MWA-compatible wallets
+- `@solana-mobile/mobile-wallet-adapter-protocol-web3js`: A convenience wrapper to use common primitives from [@solana/web3.js](https://github.com/solana-labs/solana-web3.js) – such as `Transaction` and `Uint8Array`
+- `@solana/web3.js`: Solana Web Library for interacting with the Solana network through the [JSON RPC API](https://docs.solana.com/api/http)
+- `react-native-get-random-values` Secure random number generator polyfill for `web3.js` underlying Crypto library on React Native
+- `buffer` Buffer polyfill also needed for `web3.js` on React Native
In addition to this list, we'll add two more packages:
- `@coral-xyz/anchor`: The Anchor TS client.
- `assert`: A polyfill that lets Anchor do its thing.
+- `text-encoding-polyfill`: A polyfill needed to create the `Program` object
-If you’re not familiar: polyfills actively replace node-native libraries to make them work anywhere Node is not running. We’ll finish our polyfill setup shortly.
+If you’re not familiar: polyfills actively replace Node-native libraries to make them work anywhere Node is not running. We’ll finish our polyfill setup shortly.
For now, install dependencies using the following command:
@@ -298,10 +310,11 @@ npm install \
react-native-get-random-values \
buffer \
@coral-xyz/anchor \
- assert
+ assert \
+ text-encoding-polyfill
```
-### 4. ConnectionProvider.tsx
+#### 4. Create ConnectionProvider.tsx
Let’s start adding our Solana functionality. Create a new folder called `components` and within it, a file called `ConnectionProvider.tsx`. This provider will wrap the entire application and make our `Connection` object available throughout. Hopefully you're noticing a pattern: this is identical to the React patterns we've used throughout the course.
@@ -335,7 +348,7 @@ export function ConnectionProvider(props: ConnectionProviderProps){
{children}
);
-};
+}
export const useConnection = (): ConnectionContextState =>
useContext(ConnectionContext);
@@ -343,20 +356,20 @@ export const useConnection = (): ConnectionContextState =>
### 5. AuthProvider.tsx
-The next Solana provision we’ll need is the auth provider. This is the main difference between mobile and web development. What we’re implementing here is roughly equivalent to the `WalletProvider` that we’re used to in web apps. However, since we're using Android and its natively installed wallets, the flow to connect and utilize them is a bit different. Most notably, we need to follow the mobile wallet adapter protocol (MWA).
+The next Solana provision we’ll need is the auth provider. This is one of the main differences between mobile and web development. What we’re implementing here is roughly equivalent to the `WalletProvider` that we’re used to in web apps. However, since we're using Android and its natively installed wallets, the flow to connect and utilize them is a bit different. Most notably, we need to follow the MWA protocol.
We do this by providing the following in our `AuthProvider`:
- `accounts`: If the user has multiple wallets, different accounts are maintained in this array of Accounts.
- `selectedAccount`: The current selected account for the transaction.
-- `authorizeSession(wallet)`: Authorizes (or reauthorizes, if token is expired) the wallet for the user and returns an account which will act as the selected account for the session.
-- `deauthorizeSession(wallet)`: Deauthorizes the `selectedAccount`.
+- `authorizeSession(wallet)`: Authorizes (or reauthorizes, if token is expired) the `wallet` for the user and returns an account which will act as the selected account for the session. The `wallet` variable is from the callback of the `transact` function you call independently anytime you want to interact with a wallet.
+- `deauthorizeSession(wallet)`: Deauthorizes the `wallet`.
- `onChangeAccount`: Acts as an handler when `selectedAccount` is changed.
We’re also going to throw in some utility methods:
-- `getPublicKeyFromAddress(base64Address)`: Creates a new Public Key object from the Base64 address.
-- `getAuthorizationFromAuthResult`: Handles the authorization result, extracts relevant data from the result, and returns the `Authorization` context object.
+- `getPublicKeyFromAddress(base64Address)`: Creates a new Public Key object from the Base64 address given from the `wallet` object
+- `getAuthorizationFromAuthResult`: Handles the authorization result, extracts relevant data from the result, and returns the `Authorization` context object
We’ll expose all of this through a `useAuthorization` hook.
@@ -499,7 +512,7 @@ export function AuthorizationProvider(props: AuthProviderProps) {
const deauthorizeSession = useCallback(
async (wallet: DeauthorizeAPI) => {
- if (authorization?.authToken == null) {
+ if (authorization?.authToken === null) {
return;
}
@@ -548,11 +561,11 @@ export function AuthorizationProvider(props: AuthProviderProps) {
export const useAuthorization = () => React.useContext(AuthorizationContext);
```
-### 6. ProgramProvider.tsx
+#### 6. Create ProgramProvider.tsx
The last provider we need is our program provider. This will expose the counter program we want to interact with.
-Since we're using the Anchor TS client to interact with our program, we need the program's IDL. Start by creating a root-level folder called `models`, then create a new file `anchor-counter.ts`. Paste the contents of the [Anchor Counter IDL](../assets/counter-rn-idl.ts) into this new file.
+Since we're using the Anchor TS client to interact with our program, we need the program's IDL. Start by creating a root-level folder called `models`, then create a new file `anchor-counter.ts`. Paste the contents of the [Anchor Counter IDL](https://github.com/solana-foundation/developer-content/blob/main/public/assets/courses/unboxed/counter-rn-idl.ts) into this new file.
Next, create the file `ProgramProvider.tsx` inside of `components`. Inside we'll create the program provider to surface our program and the counter PDA.
@@ -642,19 +655,20 @@ export function ProgramProvider(props: ProgramProviderProps) {
export const useProgram = () => useContext(ProgramContext);
```
-### 7. App.tsx
+#### 7. Modify App.tsx
Now that we have all our providers, let’s wrap our app with them. We're going to re-write the default `App.tsx` with the following changes:
- Import our providers and add in our polyfills
- Wrap the app first with `ConnectionProvider`, then `AuthorizationProvider`, and finally `ProgramProvider`.
-- Pass in our Devnet endpoint to the `ConnectionProvider`, and our cluster to `AuthorizationProvider`
+- Pass in our Devnet endpoint to the `ConnectionProvider`
+- Pass our cluster to `AuthorizationProvider`
- Replace the default internal `` with `` which we'll build in the next step
-We'll start by importing our polyfills, replacing our global `Buffer` with the one from the `buffer` library, and adding the rest of our imports:
```tsx
// Polyfills at the top
+import "text-encoding-polyfill";
import "react-native-get-random-values";
import { Buffer } from "buffer";
global.Buffer = Buffer;
@@ -665,11 +679,7 @@ import { AuthorizationProvider } from "./components/AuthProvider";
import { ProgramProvider } from "./components/ProgramProvider";
import { MainScreen } from "./screens/MainScreen"; // Going to make this
import React from "react";
-```
-Then we can replace the contents of `App` with our providers wrapped around `MainScreen`. Remember, `MainScreen` doesn't exist yet, but we'll come back to it in the next step!
-
-```tsx
export default function App() {
const cluster = "devnet";
const endpoint = clusterApiUrl(cluster);
@@ -689,11 +699,13 @@ export default function App() {
}
```
-### 8. MainScreen.tsx
+#### 8. Create MainScreen.tsx
Now, let’s put everything together to create our UI. Create a new folder `screens` and a new file `MainScreen.tsx` inside it. In this file, we are only structuring the screen to display two yet-to-be created components: `CounterView` and `CounterButton`.
-Additionally, in this file we're introducing React Native's `StyleSheet`. This is another difference from regular react, but behaves very similarly to CSS.
+Additionally, in this file we're introducing React Native's `StyleSheet`. This is another difference from regular React. Don't worry, it behaves very similarly to CSS.
+
+In `screens/MainScreen.tsx` paste the following:
```tsx
import {StatusBar, StyleSheet, View} from 'react-native';
@@ -735,9 +747,11 @@ export function MainScreen() {
}
```
-### 9. CounterView.tsx
+#### 9. Create CounterView.tsx
-The `CounterView` is the first of our two program-specific files. Its only job is to fetch and listen for updates on our `Counter` account. Since we’re only listening here, we don’t have to do anything MWA related. It should look identical to a web application.
+The `CounterView` is the first of our two program-specific files. `CounterView`'s only job is to fetch and listen for updates on our `Counter` account. Since we’re only listening here, we don’t have to do anything MWA-related. It should look identical to a web application. We'll use our `Connection` object to listen for the `programAddress` specified in `ProgramProvider.tsx`. When the account is changed, we update the UI.
+
+In `components/CounterView.tsx` paste the following:
```tsx
import {View, Text, StyleSheet} from 'react-native';
@@ -798,14 +812,20 @@ export function CounterView() {
}
```
-### 10. CounterButton.tsx
+#### 10. Create CounterButton.tsx
-Finally, we have our last component, the `CounterButton`. This button will do the following:
+Finally, we have our last component, the `CounterButton`. This floating action button will do the following in a new function `incrementCounter`:
- Call `transact` to get access to a mobile wallet
-- Authorize the session with `authorizeSession`
+- Authorize the session with `authorizeSession` from the `useAuthorization` hook
+- Request a Devnet airdrop to fund the transaction if not enough Devnet SOL is available
- Create an `increment` transaction
-- Have the wallet `signAndSendTransactions`
+- Call `signAndSendTransactions` to have the wallet sign and send the transaction
+
+The fake Solana wallet we use generates a new keypair every
+time you restart the fake wallet app, requiring that we want to check for funds
+and airdrop every time. This is for demo purposes only, you can't do this in
+production.
Create the file `CounterButton.tsx` and fill in the following:
@@ -924,7 +944,7 @@ export function CounterButton() {
}
```
-### 11. Build and Run
+#### 11. Build and Run
Now it’s time to test that everything works! Build and run with the following command:
@@ -934,18 +954,23 @@ npm run android
This will open the app in your emulator, click the + button in the bottom right. This will open up the "fake wallet". The "fake wallet" has various options to assist in debugging. The image below outlines the buttons to tap to properly test your app:
-
+
-If you run into some problems here are what they could be:
+If you run into some problems, here are some examples of what they could be and how to fix them:
- Application does not build → Exit Metro with ctrl+c and try again
- Nothing happens when you press the `CounterButton` → Make sure you have Solana wallet installed ( like the fake wallet we installed in Prerequisites )
-- You get stuck in a forever loop while calling `increment` → This is likely due to you reaching a Devnet airdrop rate limit. Take out the airdrop section in `CounterButton` and manually send some Devnet sol to your wallet’s address (printed in the console)
+- You get stuck in a forever loop while calling `increment` → This is likely due to you reaching a Devnet airdrop rate limit. Take out the airdrop section in `CounterButton` and manually send some Devnet SOL to your wallet’s address (printed in the console)
+
+That's it! You've made your first Solana Mobile dApp. If you get stuck, feel free to check out the [full solution code](https://github.com/Unboxed-Software/solana-react-native-counter) on the `main` branch of the repository.
-If you get stuck, feel free to check out the [full solution code](https://github.com/Unboxed-Software/solana-react-native-counter) on the `main` branch of the repository.
+## Challenge
-# Challenge
+You’re challenge today is to take our app and add a decrement function. Simply add another button and call the `decrement` function on our program. This instruction already exists on the program and its IDL, so you simply need to write client code to call it.
-You’re challenge today is to take our app and add a decrement function. Simply add another button and call the `decrement` function on our program. This instruction already exists on the program and its IDL, so you simply need to write client code to call the instruction.
+After you give it a try on your own, feel free to take a look at the [solution code on the `solution` branch](https://github.com/Unboxed-Software/solana-react-native-counter/tree/solution).
-If you want, take a look at the [solution code on the `solution` branch](https://github.com/Unboxed-Software/solana-react-native-counter/tree/solution).
\ No newline at end of file
+
+Push your code to GitHub and
+[tell us what you thought of this lesson](https://form.typeform.com/to/IPH0UGz7#answers-lesson=c15928ce-8302-4437-9b1b-9aa1d65af864)!
+