Documentation Index Fetch the complete documentation index at: https://mintlify.com/frol/near-connect-ios/llms.txt
Use this file to discover all available pages before exploring further.
Overview
This guide walks you through building a minimal iOS app that connects to NEAR wallets. You’ll implement:
✅ Wallet connection with the selector UI
✅ Displaying the connected account
✅ Disconnecting the wallet
✅ Session persistence across app launches
Step 1: Create the Wallet Manager
The NEARWalletManager is the core class that manages wallet state and operations. Create it once and share it throughout your app using SwiftUI’s environment.
NEARConnectExampleApp.swift
Alternative: Custom Init
import SwiftUI
import NEARConnect
@main
struct NEARConnectExampleApp : App {
@StateObject private var walletManager = NEARWalletManager ()
var body: some Scene {
WindowGroup {
ContentView ()
. environmentObject (walletManager)
}
}
}
The wallet manager automatically loads previously connected accounts from UserDefaults on initialization. If a user was signed in when they closed the app, they’ll still be signed in when they open it again.
Step 2: Build the Connection UI
Create a view that displays the connection status and allows users to connect or disconnect:
import SwiftUI
import NEARConnect
struct ContentView : View {
@EnvironmentObject var walletManager: NEARWalletManager
var body: some View {
VStack ( spacing : 20 ) {
Text ( "NEAR Connect Demo" )
. font (. largeTitle )
. fontWeight (. bold )
if walletManager.isSignedIn, let account = walletManager.currentAccount {
// Connected state
VStack ( spacing : 12 ) {
Image ( systemName : "checkmark.circle.fill" )
. font (. system ( size : 60 ))
. foregroundColor (. green )
Text ( "Connected" )
. font (. headline )
Text (account. accountId )
. font (. title3 )
. fontWeight (. semibold )
Text ( "via \( account. walletId ) " )
. font (. caption )
. foregroundColor (. secondary )
Button ( "Disconnect" ) {
walletManager. disconnect ()
}
. buttonStyle (. borderedProminent )
. tint (. red )
}
} else {
// Disconnected state
VStack ( spacing : 12 ) {
Image ( systemName : "wallet.pass" )
. font (. system ( size : 60 ))
. foregroundColor (. blue )
Text ( "Not Connected" )
. font (. headline )
. foregroundColor (. secondary )
Button ( "Connect Wallet" ) {
walletManager. connect ()
}
. buttonStyle (. borderedProminent )
}
}
}
. padding ()
. fullScreenCover ( isPresented : $walletManager. showWalletUI ) {
WalletBridgeSheet ()
. environmentObject (walletManager)
}
}
}
Key Points
@EnvironmentObject : Access the shared wallet manager
isSignedIn : Reactive boolean that updates when connection state changes
currentAccount : Contains accountId, publicKey, and walletId when connected
connect() : Triggers the wallet selector UI
disconnect() : Signs out and clears stored credentials
showWalletUI : Binding that controls when to present the wallet sheet
The WalletBridgeSheet is a pre-built component that handles the WebView presentation and all wallet interactions. You don’t need to build your own UI for wallet operations.
Step 3: Run Your App
Build and run your app on a simulator or device:
Build & Run
Press ⌘R or click the Play button in Xcode.
Connect a Wallet
Tap Connect Wallet . The wallet selector UI will appear with a list of available NEAR wallets.
Choose a Wallet
Select a wallet from the list. For testing:
MyNearWallet (web): Works in simulator and device
HOT Wallet (Telegram): Requires device with Telegram installed
Approve Connection
Follow the wallet’s authentication flow. For web wallets, you’ll see a browser-like interface. For native wallets, the app will deep link to the wallet app.
Connected!
Once approved, the UI automatically updates to show your connected account. The wallet sheet dismisses automatically.
Try force-quitting and relaunching the app. Your connection persists across sessions!
Step 4: Send Your First Transaction
Now that you can connect a wallet, let’s send some NEAR tokens:
import SwiftUI
import NEARConnect
struct TransactionView : View {
@EnvironmentObject var walletManager: NEARWalletManager
@State private var recipientId = ""
@State private var amount = "0.01"
@State private var isProcessing = false
@State private var showError = false
@State private var errorMessage = ""
var body: some View {
Form {
Section ( "Transfer Details" ) {
TextField ( "Recipient (e.g., bob.near)" , text : $recipientId)
. textInputAutocapitalization (. never )
HStack {
TextField ( "Amount" , text : $amount)
. keyboardType (. decimalPad )
Text ( "NEAR" )
. foregroundColor (. secondary )
}
}
Section {
Button ( "Send NEAR" ) {
Task { await sendTransaction () }
}
. disabled (isProcessing || recipientId. isEmpty )
}
}
. fullScreenCover ( isPresented : $walletManager. showWalletUI ) {
WalletBridgeSheet ()
. environmentObject (walletManager)
}
. alert ( "Error" , isPresented : $showError) {
Button ( "OK" , role : . cancel ) {}
} message : {
Text (errorMessage)
}
}
private func sendTransaction () async {
guard let yoctoAmount = NEARWalletManager. toYoctoNEAR (amount) else {
errorMessage = "Invalid amount"
showError = true
return
}
isProcessing = true
defer { isProcessing = false }
do {
let result = try await walletManager. sendNEAR (
to : recipientId,
amountYocto : yoctoAmount
)
print ( "✅ Transaction successful!" )
print ( "Hash: \( result. transactionHashes . first ?? "" ) " )
// Clear form
recipientId = ""
amount = "0.01"
} catch {
errorMessage = error. localizedDescription
showError = true
}
}
}
Understanding the Flow
User Enters Details
The form collects the recipient account ID and amount in NEAR.
Convert to YoctoNEAR
NEARWalletManager.toYoctoNEAR(_:) converts human-readable amounts (“1.5 NEAR”) to the protocol’s base unit (“1500000000000000000000000 yoctoNEAR”).
Call sendNEAR
This async method:
Sets showWalletUI = true (opens the wallet sheet)
Passes the transaction to the wallet
Waits for user approval
Returns the transaction hash
Wallet Approval
The wallet displays transaction details and asks the user to approve or reject.
Result
Success : TransactionResult with transaction hashes
Failure : Throws NEARError with a descriptive message
Auto-dismiss : The wallet sheet closes automatically on completion
Always convert user-entered amounts to yoctoNEAR before sending. Sending “1” as the amount means 1 yoctoNEAR (nearly zero NEAR), not 1 NEAR.
Step 5: Call a Smart Contract
Interact with NEAR smart contracts using callFunction:
import SwiftUI
import NEARConnect
struct ContractView : View {
@EnvironmentObject var walletManager: NEARWalletManager
@State private var message = "Hello from iOS!"
@State private var isProcessing = false
var body: some View {
VStack ( spacing : 20 ) {
Text ( "Guest Book Demo" )
. font (. title )
TextField ( "Your message" , text : $message)
. textFieldStyle (. roundedBorder )
. padding ()
Button ( "Add Message to Guest Book" ) {
Task { await addMessage () }
}
. buttonStyle (. borderedProminent )
. disabled (isProcessing)
}
. padding ()
. fullScreenCover ( isPresented : $walletManager. showWalletUI ) {
WalletBridgeSheet ()
. environmentObject (walletManager)
}
}
private func addMessage () async {
isProcessing = true
defer { isProcessing = false }
do {
let result = try await walletManager. callFunction (
contractId : "guest-book.near" ,
methodName : "add_message" ,
args : [ "text" : message],
deposit : "0" // No NEAR attached
)
print ( "✅ Message added!" )
print ( "Hash: \( result. transactionHashes . first ?? "" ) " )
message = "" // Clear input
} catch {
print ( "❌ Error: \( error. localizedDescription ) " )
}
}
}
Method Parameters
contractId : The account ID of the smart contract (e.g., "guest-book.near")
methodName : The contract method to call (e.g., "add_message")
args : A dictionary of arguments encoded as JSON
gas : Optional, defaults to "30000000000000" (30 TGas)
deposit : NEAR tokens to attach (in yoctoNEAR), defaults to "0"
The SDK automatically Base64-encodes your args dictionary before sending it to the contract, matching the NEAR protocol’s requirements.
Common Patterns
Check Connection Status Before Operations
guard walletManager.isSignedIn else {
print ( "Please connect a wallet first" )
return
}
// Proceed with transaction...
Handle Busy State
Button ( "Send Transaction" ) {
Task { await sendTransaction () }
}
. disabled (walletManager. isBusy )
The isBusy property is true whenever a wallet operation is in progress.
Query Account Balance
Task {
do {
let accountInfo = try await walletManager. viewAccount ()
if let amountYocto = accountInfo[ "amount" ] as? String {
let nearAmount = NEARWalletManager. formatNEAR ( yoctoNEAR : amountYocto)
print ( "Balance: \( nearAmount ) NEAR" )
}
} catch {
print ( "Failed to fetch balance: \( error ) " )
}
}
Switch Networks
// Set before connecting
walletManager. network = . testnet
// Or reconnect on network change
if walletManager.isSignedIn {
walletManager. disconnect ()
}
walletManager. network = . mainnet
walletManager. connect ()
Changing networks while connected doesn’t automatically reconnect. Always disconnect first, change the network, then reconnect.
Error Handling
All async wallet operations throw NEARError:
do {
let result = try await walletManager. sendNEAR (
to : "recipient.near" ,
amountYocto : "1000000000000000000000000"
)
print ( "Success: \( result. transactionHashes . first ?? "" ) " )
} catch NEARError. notSignedIn {
print ( "User needs to connect a wallet first" )
} catch NEARError. operationInProgress {
print ( "Another operation is already running" )
} catch NEARError. walletError ( let message) {
print ( "Wallet error: \( message ) " )
} catch NEARError. webViewNotReady {
print ( "Bridge is still initializing" )
} catch {
print ( "Unexpected error: \( error ) " )
}
Error Types
Error When It Occurs .notSignedInUser hasn’t connected a wallet .operationInProgressAnother wallet operation is already running .walletError(String)The wallet rejected the operation or encountered an error .webViewNotReadyThe JavaScript bridge hasn’t finished loading .rpcError(String)NEAR RPC request failed (e.g., in viewAccount())
Complete Example App
The repository includes a full-featured example app demonstrating:
Wallet connection and session persistence
Token transfers with amount validation
Smart contract calls with JSON arguments
Message signing (NEP-413)
Delegate actions (NEP-366 meta transactions)
Account balance queries
Error handling and loading states
Clone and run it:
git clone https://github.com/frol/near-connect-ios.git
cd near-connect-ios
open Example/NEARConnectExample.xcodeproj
Build and run the NEARConnectExample target to see all features in action.
Next Steps
API Reference Explore the complete NEARWalletManager API with detailed examples
Message Signing Implement authentication and authorization with off-chain message signing
Advanced Transactions Build complex transactions with multiple actions
Example Code Browse production-ready code samples on GitHub