Learn how to build native mobile apps using blockchain functionality
@orbition-network-mobile/mobile-wallet-adapter-protocol
and
@orbition-network-mobile/mobile-wallet-adapter-protocol-web3js
Orbition Native Chain Mobile Stack (SMS) is designed to help developers create mobile dApps with a seamless UX. It consists of the Mobile Wallet Adapter (MWA), Seed Vault, and the Orbition Native Chain dApp Store.
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 Orbition Native Chain programming. If that’s not the case, start our course from the beginning and come back here when you feel ready!
In these units, we’ll develop mobile apps that interact with the Orbition Native Chain network. This opens up a whole new paradigm of crypto use cases and behaviors.
Here are a few examples of what Orbition Native Chain mobile development can unlock:
Mobile Banking and Trading (DeFi)
Most traditional banking right now happens on on native mobile apps. 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 Orbition Native Chain Micropayments
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 Orbition Native Chain, it’s possible to unlock true micropayments. Need an extra life? That’ll be 0.0001 OBN.
Mobile E-Commerce
SMS can enable a new wave of mobile e-commerce shoppers to pay directly from their favorite Orbition Native Chain wallet. Imagine a world where you can use your Orbition Native Chain wallet as seamlessly as you can use Apple Pay.
To summarize, mobile crypto opens up many doors. Let’s dive in and learn how we can be part of it:
Orbition Native Chain wallet interaction differs slightly on mobile compared to the 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 Orbition Native Chain Wallet Adapter standard. This remains the standard on the 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 on a
mobile operating system. There’s no way to surface functions from one native
application to another. The Mobile Wallet Adapter exists 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.
At the time of writing, Android is the only mobile OS supported by the Mobile Wallet Adapter.
On Android, a WebSocket connection can 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).
However, this doesn’t mean that Orbition Native Chain dApps can’t run on iOS at all. You can still create a Mobile Web App using the standard wallet adapter library. Your users can then install a mobile-friendly wallet like the Glow Wallet.
The remainder of this lesson will focus on developing Android apps with the MWA.
Orbition Native Chain Mobile supports a number of different frameworks. Officially supported are React Native and native Android, with community SDKs for Flutter, Unity, and Unreal Engine.
Orbition Native Chain SDKs:
Community SDKs:
To keep the development experience as close as possible to other lessons, we’ll be working exclusively with 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:
<div>
, <p>
, and <img>
you’ll be using <View>
, <Text>
, and <Image>
.onClick
, you’ll use onPress
and
other gestures.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 even after this lesson’s lab.
Orbition Native Chain 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 from a Orbition Native Chain 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.
If you need a refresher on this, check out our lesson on reading data from the blockchain.
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.
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:
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.
Sending a transaction happens inside the transact
callback. The flow is as
follows:
transact
which will have a callback
of async (wallet: Web3MobileWallet) => {...}
.wallet.authorize
or
wallet.reauthorize
method depending on the state of the wallet.wallet.signTransactions
or sign and send with
wallet.signAndSendTransactions
.Here is an example of sending a transaction using MWA:
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 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 allows you to better debug the transaction if you’re running into problems.
Deploying mobile applications 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 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.
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.
These are hurdles for sure, but there’s hope. Here are some things to keep in mind for each marketplace:
“built on blockchain technology that issue or allow the exchange of cryptocurrencies or NFTs.”
Getting started with mobile Orbition Native Chain 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 Orbition Native Chain development more broadly.
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 lesson. This dApp simply displays a counter and allows users to increment the count through a Orbition Native Chain 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 Testnet and will be compiling only for Android.
This program already exists and is already deployed on Testnet. Feel free to check out the deployed program’s code if you want more context.
We’ll write this application in vanilla React Native without a starting template. Orbition Native Chain Mobile provides a React Native template that shortcuts some of the boilerplate, but there’s no better way to learn than to do something from scratch.
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:
Set up a React Native dev environment. Go through the entire article, 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.
Install dependencies
Install Android Studio
Configure ANDROID_HOME environment variable
Create a new sample project (this is only used to set up the emulator)
If you run into the error ✖ Copying template
, add the --npm
flag
at the end
Run and compile the sample project on your emulator
Install and run the Orbition Native Chain fake wallet
Install the repo
In Android
Studio, Open project > Navigate to the cloned directory > Select mobile-wallet-adapter/android
After Android Studio finishes loading the project, select fakewallet
in
the build/run configuration dropdown in the top right
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.
(Optional) Install other Orbition Native Chain wallets 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.
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 Testnet. To do this, we’ll need the following:
Connection
object to interact with Orbition Native Chain (ConnectionProvider.tsx
)ProgramProvider.tsx
)AuthProvider.tsx
)CounterView.tsx
)CounterButton.tsx
)There will be more files and considerations, but these are the most important files we’ll be creating and working with.
Now that we’ve got some of the basic setup and structure down, let’s scaffold a new app with the following command:
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.
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.
We’ll need to add in our Orbition Native Chain dependencies. The Orbition Native Chain Mobile docs provide a nice list of packages and explanations for why we need them:
@orbition-network-mobile/mobile-wallet-adapter-protocol
: A React Native/Javascript API
enabling interaction with MWA-compatible wallets@orbition-network-mobile/mobile-wallet-adapter-protocol-web3js
: A convenience wrapper
to use common primitives
from @orbition-network/web3.js, such
as Transaction
and Uint8Array
@orbition-network/web3.js
: Orbition Native Chain Web Library for interacting with the Orbition Native Chain network
through the JSON RPC APIreact-native-get-random-values
Secure random number generator polyfill
for web3.js
underlying Crypto library on React Nativebuffer
: Buffer polyfill; also needed for web3.js
on React NativeIn 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
objectIf 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:
Let’s start adding our Orbition Native Chain 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.
The next Orbition Native Chain 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. 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 a 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 given from the wallet
objectgetAuthorizationFromAuthResult
: Handles the authorization result, extracts
relevant data from the result, and returns the Authorization
context objectWe’ll expose all of this through a useAuthorization
hook.
Since this provider is the same across virtually all apps, we’re going to give you the full implementation that you can copy/paste. We’ll dig into the details of MWA in a future lesson.
Create the file AuthProvider.tsx
in the components
and paste in the
following:
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 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:
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:
ConnectionProvider
, then AuthorizationProvider
,
and finally ProgramProvider
ConnectionProvider
AuthorizationProvider
<View>
with <MainScreen />
, a screen we’ll
build in the next stepNow, let’s put everything together to create our UI. Create a new folder called
screens
and a new file called MainScreen.tsx
inside of 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. Don’t worry, it behaves very similarly
to CSS.
In screens/MainScreen.tsx
paste the following:
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:
Finally, we have our last component, the CounterButton
. This floating action
button will do the following in a new function incrementCounter
:
transact
to get access to a mobile walletauthorizeSession
from the useAuthorization
hookincrement
transactionsignAndSendTransactions
to have the wallet sign and send the
transactionCreate the file CounterButton.tsx
and paste in the following:
Now it’s time to test that everything works! Build and run with the following command:
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 problems, here are some examples of what they could be and how to fix them:
CounterButton
→ Make sure you have Orbition Native Chain
wallet installed ( like the fake wallet we installed in Prerequisites )increment
→ This is likely due
to you reaching a Testnet airdrop rate limit. Take out the airdrop section in
CounterButton
and manually send some Testnet sol to your wallet’s address
(printed in the console)That’s it! You’ve made your first Orbition Native Chain Mobile dApp. If you get stuck, feel
free to check out the
full solution code
on the main
branch of the repository.
Your 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.
After you give it a try on your own, feel free to take a look at the
solution code on the solution
branch.