Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

Build A Ripple XRP Wallet For Android And iOS With Ionic Framework

TwitterFacebookRedditLinkedInHacker News

A few days ago I released, what turned out to be, a very popular article around developing a Ripple XRP wallet. It was titled, Create a Cross-Platform Desktop Ripple XRP Wallet with Vue.js and Electron, and it focused on cross-platform desktop application development. A popular request on Twitter was around developing a mobile Android and iOS wallet for Ripple XRP coins.

We’re going to see how to use Ionic Framework and Angular to create a Ripple XRP wallet for Android and iOS. Because our desktop application focused on the JavaScript stack, our mobile application will be able to recycle a lot of our code.

There are a lot of mobile frameworks that make use of JavaScript. For example, React Native, NativeScript, and Ionic Framework are all options for mobile development with JavaScript. However, the Ripple library is only Node.js or browser compatible. You might be wondering, well if it is Node.js compatible, what is the problem? The problem is that it uses libraries that aren’t yet available for native frameworks like NativeScript and React Native. Because Ionic Framework operates within a packaged web browser, we’ll be able to use the browser compatible version of the library.

So what do we plan on building in this example? Take a look at the screenshot below.

Ionic Framework Ripple XRP Wallet for Android and iOS

We’re trying to reproduce what we saw in the previous example, but this time mobile friendly. We’re going to take an address, look up the balance, and compare it to the current market value using libraries and public APIs.

Create a New Mobile Project with Ionic Framework

At this point we’re going to assume your computer is properly configured for Android and iOS development and that you have the Ionic Framework CLI installed. Using the CLI, create a new project with the following command:

ionic start ionic-ripple-wallet blank

This will leave us with a clean Ionic Framework project, which as of now, is version 3.9.2. We won’t be including any Node Package Module (NPM) dependencies for this particular project.

At this point we can get our JavaScript library for Ripple and start implementing some logic.

Building the Ripple Library for the Web Browser

Before we can start developing, we need to build the Ripple library for use in web browsers. Remember, our previous example had full Node.js support, so we could use NPM. We don’t have that luxury for this example as we’ll get errors if we tried.

Outside your Ionic Framework project, execute the following commands:

git clone https://github.com/ripple/ripple-lib
cd ripple-lib
npm install
npm run build

The above commands will clone the latest ripple-lib project code and build for browser usage. You’ll end up with a build directory with several different JavaScript files.

For best results, we’re going to work with the versioned file. In my scenario, I’ll be using ripple-0.17.9.min.js, but feel free to use the latest or whatever version you’ve built.

Take the ripple-0.17.9.min.js file and copy it to your Ionic Framework project’s src/assets/js/ directory.

The Ripple library has a dependency on lodash so we’ll need to download it as well. Download lodash.js and place it in your Ionic Framework project’s src/assets/js/ directory.

With the Ripple and lodash libraries in place, let’s start development.

Implement Ripple XRP Wallet Functionality with APIs and Libraries

We’re going to start with the easy stuff such as project preparation before we jump into some cool business logic. Open the project’s src/index.html file and include the following two lines:

<script src="assets/js/lodash.js"></script>
<script src="assets/js/ripple-0.17.9-min.js"></script>

For clarity, your src/index.html file should look something like the following in the end:

<!DOCTYPE html>
<html lang="en" dir="ltr">
    <head>
        <meta charset="UTF-8">
        <title>Ionic App</title>
        <meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
        <meta name="format-detection" content="telephone=no">
        <meta name="msapplication-tap-highlight" content="no">
        <link rel="icon" type="image/x-icon" href="assets/icon/favicon.ico">
        <link rel="manifest" href="manifest.json">
        <meta name="theme-color" content="#4e8ef7">
        <!-- add to homescreen for ios -->
        <meta name="apple-mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-status-bar-style" content="black">
        <script src="assets/js/lodash.js"></script>
        <script src="assets/js/ripple-0.17.9-min.js"></script>
        <!-- cordova.js required for cordova apps (remove if not needed) -->
        <script src="cordova.js"></script>
        <!-- un-comment this code to enable service worker
        <script>
            if ('serviceWorker' in navigator) {
                navigator.serviceWorker.register('service-worker.js')
                .then(() => console.log('service worker installed'))
                .catch(err => console.error('Error', err));
            }
        </script>-->
        <link href="build/main.css" rel="stylesheet">
    </head>
    <body>
        <!-- Ionic's root component and where the app will load -->
        <ion-app></ion-app>
        <!-- The polyfills js is generated during the build process -->
        <script src="build/polyfills.js"></script>
        <!-- The vendor js is generated during the build process
        It contains all of the dependencies in node_modules -->
        <script src="build/vendor.js"></script>
        <!-- The main bundle js is generated during the build process -->
        <script src="build/main.js"></script>
    </body>
</html>

We’ve added the scripts to the <head> because we want them to be loaded and available before Angular starts doing its magic. Since we’ll be issuing HTTP requests, we’ll need to add the Angular HTTP module.

Open the project’s src/app/app.module.ts file and make it look like the following:

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';
import { HttpModule } from "@angular/http";

import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';

@NgModule({
    declarations: [
        MyApp,
        HomePage
    ],
    imports: [
        BrowserModule,
        IonicModule.forRoot(MyApp),
        HttpModule
    ],
    bootstrap: [IonicApp],
    entryComponents: [
        MyApp,
        HomePage
    ],
    providers: [
        StatusBar,
        SplashScreen,
        {provide: ErrorHandler, useClass: IonicErrorHandler}
    ]
})
export class AppModule {}

You’ll notice that we’ve just imported the HttpModule and added it to the imports array of the @NgModule block. Now we’ll be able to use it in our components.

Alright, this is where the actual development begins.

Open the project’s src/pages/home/home.ts file and include the following TypeScript. Don’t worry, we’ll break it down after.

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { Http } from "@angular/http";
import { Observable } from "rxjs";

declare var ripple: any;

@Component({
    selector: 'page-home',
    templateUrl: 'home.html'
})
export class HomePage {

    private api: any;
    public address: any;
    public wallet: any;
    public market: any;

    public constructor(public navCtrl: NavController, private http: Http) {
        this.api = new ripple.RippleAPI({ server: "wss://s1.ripple.com/" });
        this.address = "rn7HJDaYaEcDJvcELQFbnGXAEo2YA1RLNc";
        this.wallet = {
            balance: 0,
            usd: 0
        };
        this.market = {};
    }

    public ngOnInit() {
        Observable.forkJoin([this.getWalletBalance(), this.getMarketValue()])
            .subscribe(result => {
                this.wallet.balance = result[0].value;
                this.wallet.usd = (result[0].value * result[1].price_usd).toFixed(2)
                this.market = result[1];
            });
    }

    public getWalletBalance() {
        return Observable
            .fromPromise(this.api.connect())
            .switchMap(() => Observable.fromPromise(this.api.getBalances(this.address)))
            .map(balance => balance[0])
            .do(() => this.api.disconnect());
    }

    public getMarketValue() {
        return this.http.get("https://api.coinmarketcap.com/v1/ticker/ripple/")
            .map(result => result.json())
            .map(result => result[0]);
    }

}

So what is happening in the above code? Notice the following line:

declare var ripple: any;

Remember, we’ve included our libraries in the src/index.html file rather than NPM. For this reason we’ll have to declare the library variable to prevent TypeScript compilation errors.

In the constructor method we are initializing our variables:

public constructor(public navCtrl: NavController, private http: Http) {
    this.api = new ripple.RippleAPI({ server: "wss://s1.ripple.com/" });
    this.address = "rn7HJDaYaEcDJvcELQFbnGXAEo2YA1RLNc";
    this.wallet = {
        balance: 0,
        usd: 0
    };
    this.market = {};
}

We are defining the Ripple server and an address. I’ve provided my own public address, rn7HJDaYaEcDJvcELQFbnGXAEo2YA1RLNc, but you could easily use the ripple-keypairs library to get your address from your private key.

To get your wallet balance, you’d call the getWalletBalance function:

public getWalletBalance() {
    return Observable
        .fromPromise(this.api.connect())
        .switchMap(() => Observable.fromPromise(this.api.getBalances(this.address)))
        .map(balance => balance[0])
        .do(() => this.api.disconnect());
}

To keep things Angular friendly, we’re going to work with observables rather than promises. We create a new observable, convert our connection promise into an observable, switch to another observable stream after connecting, the new observable stream will get our balance, and then we’ll disconnect from the API. When we subscribe to this observable, everything in the chain happens. Welcome to RxJS and reactive extensions!

The getMarketValue function is a little simpler:

public getMarketValue() {
    return this.http.get("https://api.coinmarketcap.com/v1/ticker/ripple/")
        .map(result => result.json())
        .map(result => result[0]);
}

For to get the market value of Ripple, we just call the CoinMarketCap API and transform the result. Nothing fancy is happening here.

Using the two functions is where things get interesting. When the Angular ngOnInit lifecycle hook triggers, we have the following:

public ngOnInit() {
    Observable.forkJoin([this.getWalletBalance(), this.getMarketValue()])
        .subscribe(result => {
            this.wallet.balance = result[0].value;
            this.wallet.usd = (result[0].value * result[1].price_usd).toFixed(2)
            this.market = result[1];
        });
}

We want to subscribe to both observables in parallel similar to Promise.all and this can be done with a forkJoin operator. When the observables have finished, we can do some basic math to figure out the dollar value for our XRP coins.

Now we can jump over to the HTML markup. Open the project’s src/pages/home/home.html and include the following:

<ion-header>
    <ion-navbar>
        <ion-title>
            XRP Wallet
        </ion-title>
    </ion-navbar>
</ion-header>

<ion-content padding>
    <ion-card>
        <ion-card-content>
            <h1>{{ wallet.balance }} XRP</h1>
            <p>{{ wallet.usd }} USD</p>
        </ion-card-content>
    </ion-card>
    <ion-card>
        <ion-list>
            <ion-item>Price: ${{ market.price_usd }}</ion-item>
            <ion-item>Market Cap: ${{ market.market_cap_usd }}</ion-item>
            <ion-item>1H Change: {{ market.percent_change_1h }}%</ion-item>
            <ion-item>24H Change: {{ market.percent_change_24h }}%</ion-item>
            <ion-item>7D Change: {{ market.percent_change_7d }}%</ion-item>
        </ion-list>
    </ion-card>
</ion-content>

<ion-footer>
    <ion-toolbar>
        <p style="padding: 0 12px">2017 &copy; thepolyglotdeveloper.com</p>
    </ion-toolbar>
</ion-footer>

Nothing fancy is happening in the above markup. We’re using some Ionic Framework tags and rendering our public variables to the screen.

At this point, you should be able to build for either Android or iOS.

Conclusion

You just saw how to create a mobile Ripple XRP coin wallet for Android and iOS using web technologies with Ionic Framework. While not a native mobile application, we chose Ionic Framework and the WebView because ripple-lib was browser friendly and not compatible with the native frameworks.

If you wanted to, you could take the previous Vue.js with Electron tutorial, swap out Vue.js, and include Angular. You could even rely strictly on the renderer process with the browser version of the library.

My public Ripple XRP address is rn7HJDaYaEcDJvcELQFbnGXAEo2YA1RLNc if you’re interested in donating some coin.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in C#, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Unity. Nic writes about his development experiences related to making web and mobile development easier to understand.