NEU: Helius übernimmt Light Protocol
Erstelle in weniger als 5 Minuten eine mobile cNFT-Minter-App
Blog/Entwicklung

Erstelle in weniger als 5 Minuten eine mobile cNFT-Minter-App

Engineer für Developer ExperienceAnam Ansari auf XAnam Ansari auf LinkedIn
5 Min. Lesezeit

Was dich erwartet

Dieses Tutorial zeigt dir, wie du eine Android-App zum Minten von NFTs (nicht fungiblen Token) entwickelst. Nutzer sollen damit einfach Bilder aufnehmen und als komprimierte NFTs auf Solana minten können. Dafür verwenden wir die Helius Mint API. Mit dieser API kannst du komprimierte NFTs schneller minten und Boilerplate-Code minimieren. Das spart dir viel Zeit und Planungsaufwand. Wir entwickeln unsere Android-App mit Kotlin und Jetpack Compose.

Was sind komprimierte NFTs?

Komprimierte NFTs (cNFTs) verwenden Zustandskomprimierung und parallele Merkle-Bäume, um Speicherkosten zu senken. Komprimierte NFTs sind 2.400- bis 24.000-mal günstiger als ihre unkomprimierten Gegenstücke, behalten aber dieselben Strukturen bei.

Voraussetzungen

Bevor du mit diesem Tutorial beginnst, solltest du grundlegende Kenntnisse in der Android-Entwicklung mit Kotlin haben und mit Solana vertraut sein.

Tools

  • Android Studio: Giraffe | Version 2022.3.1
  • Emulator oder Mobilgerät: Damit testest du die App. Stelle sicher, dass eine MWA-kompatible Wallet-App installiert ist (Solfare wird empfohlen).

API-Schlüssel

Um die Helius Mint API zu verwenden, benötigst du einen API-Schlüssel. So erhältst du einen:

  1. Öffne dasHelius-Entwicklerportal.
  2. Erstelle mit deiner Solana-Wallet oder deinem Google- bzw. GitHub-Konto einen Account.
  3. Folge nach der Anmeldung den Anweisungen, um einen API-Schlüssel zu generieren.
  4. Bewahre diesen Schlüssel sicher auf, da du ihn in diesem Tutorial für API-Aufrufe benötigst.

App entwickeln

Schritt 1: Projekt einrichten

Wir haben für dieses Projekt eine Starter-Codebasis vorbereitet. 

Führe zunächst diese Schritte aus:

  1. Öffne das Starterpaket auf GitHub.
  2. Forke das Repository und klone es in deine lokale Umgebung.

Sobald der Code lokal verfügbar ist, gehst du wie folgt vor:

  1. Öffne das Projekt in Android Studio.
  2. Warte, bis Gradle den Build-Prozess abgeschlossen hat.
  3. Führe den Code aus.

Erkunde die Starter-App, um dich mit ihren Funktionen vertraut zu machen. Beachte den integrierten Button zum Verbinden einer Wallet. Damit kannst du eine Verbindung zu jeder Mobile Wallet Adapter-kompatiblen Wallet-App (MWA) herstellen. Mobile Wallet Adapter (MWA) ist eine Protokollspezifikation, die mobile dApps mit mobilen Wallet-Apps verbindet und so die Kommunikation für Solana-Transaktionen und das Signieren von Nachrichten ermöglicht. Der Mobile Wallet Adapter unterstützt diese Wallets. Außerdem findest du den Button „Foto aufnehmen“, mit dem du bereits ein Foto aufnehmen kannst.

Um den Helius-API-Schlüssel sicher in der Codebasis zu speichern, öffne die Datei local.properties und füge den API-Schlüssel hinzu. Diese Datei ist speziell für vertrauliche Informationen vorgesehen und wird von Git ignoriert. So bleibt dein API-Schlüssel geschützt.

api_key=<your-api-key>

Als Nächstes programmieren wir die Logik, mit der das aufgenommene Bild als komprimiertes NFT (cNFT) gemintet wird.

Schritt 2: Minting-Logik

Unser Ziel ist es, den Button „Foto aufnehmen“ mit der Kamerafunktion zu verknüpfen. So können Nutzer Bilder aufnehmen und als NFTs minten. Wir haben bereits Startercode bereitgestellt, um die Kamera zu öffnen und Bilder aufzunehmen. Jetzt erstellen wir eine Funktion, die den Minting-Prozess verwaltet.‍

Mint API von Helius

Diese Methode mintet ein komprimiertes NFT. Nach der Ausführung wartet sie, bis die Transaktion bestätigt wurde. Bei hoher Netzwerkauslastung kann das bis zu 60 Sekunden dauern. Weitere Informationen findest du in der Dokumentation.

Öffne zunächst java/com/example/hmint/MainViewModel.kt und erstelle in der Klasse MainViewModel die Funktion mintCNft:

Code
@HiltViewModel
class MainViewModel @Inject constructor(
    private val walletAdapter: MobileWalletAdapter,
    private val walletConnectionUseCase: WalletConnectionUseCase,
) : ViewModel() {
    
    // ...

    fun mintCNft(imageUri: Uri, nftName: String, user: String) =
        viewModelScope.launch {
            _state.update {
                _state.value.copy(
                    isLoading = true,
                )
            }
        }

}

‍Wir starten eine Coroutine, um die Minting-Logik innerhalb dieser Funktion auszuführen. Zunächst rufen wir den API-Schlüssel ab und definieren die erforderlichen Variablen sowie den requestBody. Später kannst du requestBody anpassen und je nach Bedarf weitere Attribute und Daten hinzufügen:

Code
withContext(viewModelScope.coroutineContext + Dispatchers.IO) {
    val apiKey = System.getProperty("api_key") ?: ""
    val url = URL("https://mainnet.helius-rpc.com/?api-key=$apiKey")
    val mediaType = "application/json".toMediaTypeOrNull()
    val requestBody = """
        {
            "jsonrpc": "2.0",
            "id": "helius-test",
            "method": "mintCompressedNft",
            "params": {
                "name": "$nftName",
                "symbol": "HM",
                "owner": "$user",
                "description": "This is a test cNFT minted by hMint app",
                "attributes": [
                    {
                        "trait_type": "hMint",
                        "value": "1"
                    }
                ],
                "imageUrl": "$imageUri",
                "sellerFeeBasisPoints": 6900
            }
        }
        ""${'"'}.trimIndent()
                                    
}

‍Anschließend erstellen wir die Anfrage und initialisieren einen OkHttpClient:

Code
val body = requestBody.toRequestBody(mediaType)
val request = Request.Builder()
    .url(url)
    .post(body)
    .addHeader("accept", "application/json")
    .addHeader("content-type", "application/json")
    .build()
val client = OkHttpClient()

‍Bevor wir den Client aufrufen, definieren wir die Antwort in einer Datenklasse. Erstelle ein neues Package namens data und darin eine neue Datei namens NFTResponse.kt. Definiere dort die Struktur der Antwort, die wir vom API-Aufruf erhalten.

Code
package com.example.hmint.data

data class NftMintResponse(
    val jsonrpc: String,
    val id: String,
    val result: MintResult
)

data class MintResult(
    val signature: String,
    val minted: Boolean,
    val assetId: String
)

‍Erweitere anschließend in der Klasse MainViewModel die Datenklasse WalletViewState um einen zusätzlichen Wert für mintResponse. Wir aktualisieren diesen Wert, sobald wir eine Antwort erhalten:

Code
data class WalletViewState(
    // ...
    val mintResponse: String = ""
)

‍Zurück in unserer Funktion mintCNft führen wir die Anfrage mit dem Client aus und behandeln Fehler oder Antworten entsprechend. Sobald eine Antwort eingeht, parsen wir die Daten mit Gson in die zuvor erstellte Datenklasse NFTMintResponse. Danach aktualisieren wir den Wert von mintResponse entsprechend:

Code
client.newCall(request).enqueue(object : Callback {
    override fun onFailure(call: Call, e: IOException) {
        // Handle failure
        e.printStackTrace()
        Log.d(TAG, "NFT Mint Failed")
        _state.update {
            _state.value.copy(
                isLoading = false,
                mintResponse = "Mint Failed"
            )
        }
    }

    override fun onResponse(call: Call, response: Response) {
        if (response.isSuccessful) {
            val responseBody = response.body?.string() ?: ""
            val gson = Gson()
            val nft = gson.fromJson(responseBody, NftMintResponse::class.java)
            Log.d(TAG, "NFT Mint Successful: $nft")
            _state.update {
                _state.value.copy(
                    isLoading = false,
                    mintResponse = "Minted Successfully"
                )
            }

        } else {
            // Handle non-successful response
            Log.d(TAG, "NFT Mint Failed: ${response.code}")
            _state.update {
                _state.value.copy(
                    isLoading = false,
                    mintResponse = "Minted Failed"
                )
            }
        }
    }
})

‍In unserer UI möchten wir Nutzer über das Ergebnis der Minting-Funktion informieren. Öffne dazu java/com/example/hmint/composables/MintButton.kt. Diese Datei enthält das Composable sowie den UI-Code und die Logik für die Bildaufnahme. Rufe in MintButton, wo wir cameraLauncher deklariert haben, unsere Funktion mintCNft auf. Füge außerdem Code hinzu, der nach der Aktualisierung von mintResponse einen Toast anzeigt.

Code
@Composable
fun MintButton(
    mainViewModel: MainViewModel = hiltViewModel()
) {

    val cameraLauncher =
        rememberLauncherForActivityResult(ActivityResultContracts.TakePicture()) {
            // ...
            mainViewModel.mintCNft(uri, "hMint", viewState.userAddress)
        }

    
    viewState.mintResponse.let { message ->
        if(message.isNotEmpty()){
            Toast.makeText(LocalContext.current, message, Toast.LENGTH_SHORT).show()
        }
    }

    // ...
}

Schritt 3: App ausführen

‍Die Programmierung ist abgeschlossen. Jetzt können wir die App ausführen. Verbinde zuerst deine Wallet und nimm dann ein Bild auf. Die App mintet daraus automatisch das NFT für dich.

Fazit

Gut gemacht! Du hast erfolgreich eine Android-App entwickelt, mit der Nutzer komprimierte NFTs minten können. Dank der Helius Mint API war das Minten von cNFTs noch nie so einfach und erfordert nur einen einzigen Aufruf.

Wie geht es weiter?

In dieser App kannst du noch vieles erkunden und verbessern. Eine mögliche Erweiterung ist die Integration der DAS API. Die Digital Asset Standard (DAS) API ist eine Open-Source-Spezifikation und ein System, das eine einheitliche Schnittstelle für die Interaktion mit digitalen Assets wie Token und NFTs bereitstellt. Sie unterstützt verschiedene Asset-Typen, darunter fungible Token, Standard-NFTs und komprimierte NFTs.  Mit der API kannst du alle geminteten komprimierten NFTs abrufen und in deiner App anzeigen. So erhalten Nutzer einen umfassenden Überblick über ihre digitalen Assets.

Relevante Ressourcen

Mit den folgenden Ressourcen kannst du deine Kenntnisse in der Android-Entwicklung mit Jetpack Compose, der Solana-Blockchain-Integration und der Interaktion mit APIs vertiefen:

Wenn du Hilfe oder Support benötigst, kontaktiere uns gerne auf Discord. Die vollständige Codebasis findest du zur weiteren Verwendung auf GitHub.

‍

Helius abonnieren

Bleib bei der Solana-Entwicklung auf dem Laufenden und erhalte Updates, wenn wir neue Beiträge veröffentlichen

Vergrößertes Bild