6. Set up the config
Create a new blank android project. Within the home directory, create a file called apikey.properties. We will then add the values obtained from the previous steps.
WALLET_ADDRESS="0x42703e1F2CCB08583088D96d71d4549Be08b52a7"
CONTRACT_ADDRESS="0x129Ff5b9D7C128527F3Be5ca5fb4F2E7A991482d"
WEB_SOCKET_URL="[wss://550b-105-163-1-231.ngrok.io](https://550b-105-163-1-231.ngrok.io)"
SEED="truth manual elephant border predict castle payment suspect mimic insect wish acoustic"
TOKEN_URI=""
For a recap:
- We obtained the WALLET_ADDRESS by taking the first public key after running the ganache command.
- We obtained the CONTRACT_ADDRESS after running
truffle migrate --network development
and taking the contract address from the 1_deploy_contract.js section. - We obtained the SEED after running the ganache command and obtaining the seed generated.
Within the build.gradle (module) under dependencies, add the _web3j _library.
// Add support for web3j
implementation 'org.web3j:core:4.8.7-android'
Add the configurations within the defaultConfig section of the build.gradle file.
// Load configuration from the apikey.properties file
buildConfigField("String", "WALLET_ADDRESS", apikeyProperties['WALLET_ADDRESS'])
buildConfigField("String", "CONTRACT_ADDRESS", apikeyProperties['CONTRACT_ADDRESS'])
buildConfigField("String", "WEB_SOCKET_URL", apikeyProperties['WEB_SOCKET_URL'])
buildConfigField("String", "SEED", apikeyProperties['SEED'])
buildConfigField("String", "TOKEN_URI", apikeyProperties['TOKEN_URI'])
Do not forget to add internet permissions within the AndroidManifest.xml file by adding the line below to the <application
tag.
<uses-permission android:name="android.permission.INTERNET" />
7. Develop the android wrapper
Using the _web3j _library, we can convert our solidity file into a java so that we can call the methods we have written in the solidity file.
web3j generate truffle --truffle-json .\build\contracts\lemurNFT.json -o ..\android\app\src\main\java\ -p com.example.lemur
After running this command successfully, a new java file LemurNFT.java will be generated. Place the file close to the MainActivity.kt file.
8. Create the UI
The user interface is pretty simple, we have a button called MINT. When the button is clicked, it runs the mintNFT _function in the _MainActivity.kt file.
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="mintNft"
android:text="@string/button_text"
tools:layout_editor_absoluteX="161dp"
tools:layout_editor_absoluteY="407dp" />
The whole activity_main.xml file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LemurNFT"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="mintNft"
android:text="@string/button_text"
tools:layout_editor_absoluteX="161dp"
tools:layout_editor_absoluteY="407dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
The app should look like this:
9. Adding global variables
In your MainActivity.kt add the following variables as global.
// inside of any of your application's code
var walletAddress: String = BuildConfig.WALLET_ADDRESS;
var contractAddress: String = BuildConfig.CONTRACT_ADDRESS;
var webSocketUrl: String = BuildConfig.WEB_SOCKET_URL;
var seed: String = BuildConfig.SEED;
var tokenUri: String = BuildConfig.TOKEN_URI;
private lateinit var credentials: Credentials;
This code loads all the configuration files from our _apikey.properties _file and the BuildConfig file.
We also have a credentials variable that will be initialized later on, and that is globally accessible by any function.
10. Load the credentials
Within the MainActivity.kt file add the following line of code.
/***
* Create credentials from a seed.
*/
fun loadCredentials(){
val masterKeypair = Bip32ECKeyPair.generateKeyPair(MnemonicUtils.generateSeed(seed, ""))
val path = intArrayOf(44 or HARDENED_BIT, 60 or HARDENED_BIT, HARDENED_BIT, 0, 0)
val x = Bip32ECKeyPair.deriveKeyPair(masterKeypair, path)
this.credentials = Credentials.create(x)
}
This generates a keypair (a public and private key) to sign our transactions.
11. Load the credentials
Within the MainActivity.kt file add the following line of code.
/***
* Create credentials from a seed.
*/
fun loadCredentials(){
val masterKeypair = Bip32ECKeyPair.generateKeyPair(MnemonicUtils.generateSeed(seed, ""))
val path = intArrayOf(44 or HARDENED_BIT, 60 or HARDENED_BIT, HARDENED_BIT, 0, 0)
val x = Bip32ECKeyPair.deriveKeyPair(masterKeypair, path)
this.credentials = Credentials.create(x)
}
This generates a keypair (a public and private key) to sign our transactions.
12. Show the response
We need to show the response after posting the transaction to the blockchain. With this, we will use a toast notification. Add the following code to the MainActivity.kt file.
/**
* Display the response as a toast notification.
*/
private fun showResponse(response: String){
val duration = Toast.LENGTH_LONG;
val toast = Toast.makeText(applicationContext, response, duration);
toast.show();
}
The function takes in a string and displays it in a toast notification.
13. Mint an NFT
Here the mintNft function is tied to a button in the main user interface. Once the button is clicked:
- The credentials will be loaded from the loadCredentials() function.
- A new instance of web3j instance will be created which will be used to connect to the node.
- We then load the smart contract which is the LemurNFT contract and provide the contract address, the WebSocket connection, the credentials, and the gas for the transactions.
- We then call the smart contract function to mint an NFT, providing the wallet address to mint an NFT to, and the tokenURI.
- We then log out the response using Log.e *and *also display the response through a toast notification.
/**
* Mint an nft when the mint button is clicked.
*/
fun mintNft(view: View) {
try {
loadCredentials();
val web3j: Web3j = createWeb3j()
val nft: LemurNFT = LemurNFT.load(contractAddress, web3j, credentials, DefaultGasProvider())
val transactionReceipt: TransactionReceipt = nft.mintNFT(walletAddress, tokenUri).send()
Log.e("Response", transactionReceipt.toString());
showResponse(transactionReceipt.toString());
} catch (e: Exception){
e.printStackTrace();
}
return;
}
The MainActivity.kt will then look like this:
package com.example.lemur
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import org.web3j.crypto.Bip32ECKeyPair
import org.web3j.crypto.Bip32ECKeyPair.HARDENED_BIT
import org.web3j.crypto.Credentials
import org.web3j.crypto.MnemonicUtils
import org.web3j.protocol.Web3j
import org.web3j.protocol.core.DefaultBlockParameterName
import org.web3j.protocol.core.methods.response.EthGetBalance
import org.web3j.protocol.core.methods.response.TransactionReceipt
import org.web3j.protocol.websocket.WebSocketService
import org.web3j.tx.gas.DefaultGasProvider
import java.math.BigInteger
import java.net.ConnectException
class MainActivity : AppCompatActivity() {
// inside of any of your application's code
var walletAddress: String = BuildConfig.WALLET_ADDRESS;
var contractAddress: String = BuildConfig.CONTRACT_ADDRESS;
var webSocketUrl: String = BuildConfig.WEB_SOCKET_URL;
var seed: String = BuildConfig.SEED;
var tokenUri: String = BuildConfig.TOKEN_URI;
private lateinit var credentials: Credentials;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
/**
* Mint an nft when the mint button is clicked.
*/
fun mintNft(view: View) {
try {
loadCredentials();
val web3j: Web3j = createWeb3j()
val nft: LemurNFT = LemurNFT.load(contractAddress, web3j, credentials, DefaultGasProvider())
val transactionReceipt: TransactionReceipt = nft.mintNFT(walletAddress, tokenUri).send()
Log.e("Response", transactionReceipt.toString());
showResponse(transactionReceipt.toString());
} catch (e: Exception){
e.printStackTrace();
}
return;
}
/**
* Display the response as a toast notification.
*/
private fun showResponse(response: String){
val duration = Toast.LENGTH_LONG;
val toast = Toast.makeText(applicationContext, response, duration);
toast.show();
}
/**
* Create a web3j web socket instance from the web socket url.
*/
private fun createWeb3j(): Web3j {
val webSocketService = WebSocketService(webSocketUrl, true)
try {
webSocketService.connect()
} catch (e: ConnectException) {
e.printStackTrace()
}
return Web3j.build(webSocketService)
}
/***
* Create credentials from a seed.
*/
private fun loadCredentials(){
val masterKeypair = Bip32ECKeyPair.generateKeyPair(MnemonicUtils.generateSeed(seed, ""))
val path = intArrayOf(44 or HARDENED_BIT, 60 or HARDENED_BIT, HARDENED_BIT, 0, 0)
val x = Bip32ECKeyPair.deriveKeyPair(masterKeypair, path)
this.credentials = Credentials.create(x)
}
}
When you click on the mint button, once you compile and run the application, a toast notification should show up with a transaction receipt.
14. Conclusion
Congratulations, you have been able to create an NFT smart contract and interact with it from an android app.
Top comments (0)