Generate a Full Android Client in Kotlin with Z.ai GLM

Table of Contents

I was three weeks into building a native Android client for a backend API I'd already spent months on. The server was solid. The API contracts were locked. But every time I opened Android Studio, I felt that familiar dread creeping in—the endless boilerplate, the fragile XML layouts, the constant context-switching between fragments, view models, and repositories. I'd built enough Android apps to know the drill: two weeks of grunt work before I even touched anything interesting.

Then I fed my entire API specification—all 47 endpoints, the WebSocket contract, the authentication flow—into Z.ai GLM2 and asked it to build me a complete Kotlin client.

Generate a Full Android Client in Kotlin with Z.ai GLM

What came back wasn't a skeleton. It was a fully functional Android app with multi-session chat, streaming messages, voice input, push notifications, and automatic reconnection logic. The AI generated the entire thing—activities, fragments, view models, repository layers, dependency injection setup, even the notification channels—in about two hours of active work. I spent the next hour installing it on my Pixel 7 via ADB, watching it work perfectly on the first build.

I'm not saying AI replaces Android developers. I'm saying the days of writing the same RecyclerView adapters and Retrofit interfaces over and over are over. Here's exactly how I did it—the prompts, the failures, the manual fixes, and the moment I realized this was actually going to work.

TL;DR — Key Takeaways

  • Project Goal: Generate a complete native Android client in Kotlin that integrates with an existing server-side API, supporting multi-session chat, streaming messages, voice input, push notifications, and automatic reconnection on disconnect.
  • Tool Used: Z.ai GLM-5.2 via the chat interface at chat.z.ai. I chose it because the model is specifically optimized for mobile development scenarios—it understands client-side architecture, streaming messages, long-lived connection state, and local state management. The 1 million-token context window meant I could feed it my entire API spec and keep the conversation going without losing context.
  • Time Spent: ~2 hours of prompting and code generation, plus another ~45 minutes of manual polish and ADB debugging. Total: ~2.75 hours.
  • Cost: $0 for this project. I used the free tier with the $5 monthly credits that refresh every 30 days. The total token usage for the session was well under the free allowance.

Why I stopped fighting Android Studio and started writing prompts instead

Here's the uncomfortable truth about Android development: most of it is plumbing. Setting up Retrofit. Wiring up Room. Implementing the same ViewModel pattern you've implemented fifty times. Writing yet another RecyclerView adapter. Configuring Dagger/Hilt for dependency injection. It's not intellectually challenging—it's just time-consuming.

GLM-5.2 flipped that equation for me. I spent my time thinking about the user experience, the edge cases, and the architecture—while the AI handled the plumbing. The model is built specifically for long-horizon agentic tasks, meaning it can maintain context across extended interactions without losing the thread. It's designed for project-level engineering workflows, not just one-off code snippets.

Step 1: The prep work—what I fed the AI before writing a single line of code

Before I typed my first prompt, I gathered everything the AI would need. This is the make-or-break step. If you feed the AI garbage, you get garbage. If you feed it a complete picture, you get a complete application.

Here's exactly what I prepared:

  1. My complete API specification—every endpoint, request/response body, status code, and authentication requirement. I wrote it as a structured document, not a rambling description.
  2. The WebSocket contract—message types, connection lifecycle, reconnection strategy.
  3. My design preferences—Material Design 3, dark mode support, bottom navigation, splash screen.
  4. The tech stack I wanted—Kotlin, Coroutines, Flow, Retrofit, Room, Hilt, Jetpack Compose (I decided to go with Compose instead of XML views for this project).
  5. The minimum SDK version—API 24 (Android 7.0) for broad compatibility.

Here's the exact prompt I used:

I need you to act as a senior Android developer. Build a complete native Android client in Kotlin with the following specifications:

PROJECT: ChatClient - A native Android messaging app

TECH STACK:
- Language: Kotlin
- UI Framework: Jetpack Compose (Material Design 3)
- Architecture: MVVM with Clean Architecture principles
- Networking: Retrofit with OkHttp, Moshi for JSON parsing
- Database: Room for local persistence
- Dependency Injection: Hilt
- Async: Kotlin Coroutines with Flow
- Navigation: Jetpack Navigation Compose
- Notifications: Firebase Cloud Messaging (FCM)
- Minimum SDK: API 24 (Android 7.0)
- Target SDK: API 36 (Android 16)

SERVER API (REST):
Base URL: https://api.chat.example.com/v1
Authentication:
- POST /auth/login - Email/password login, returns JWT token and refresh token
- POST /auth/register - New user registration
- POST /auth/refresh - Refresh expired JWT token
- POST /auth/logout - Invalidate session
Chat Endpoints:
- GET /conversations - List all user conversations
- GET /conversations/{id}/messages - Get messages for a conversation (paginated)
- POST /conversations - Create a new conversation
- POST /conversations/{id}/messages - Send a new message
- DELETE /conversations/{id} - Delete a conversation
- PUT /conversations/{id}/read - Mark all messages as read
User Endpoints:
- GET /users/me - Get current user profile
- PUT /users/me - Update user profile
- GET /users/search?q={query} - Search for users

WEBSOCKET:
- Endpoint: wss://api.chat.example.com/ws
- Authentication: JWT token in connection query parameter
- Message Types:
  - "new_message": Incoming message from another user
  - "typing": User typing indicator
  - "read_receipt": Message read confirmation
  - "presence": User online/offline status
  - "error": WebSocket error message
- Reconnection: Exponential backoff with max 5 retries

CORE FEATURES:
1. User authentication (login, register, logout, refresh token)
2. Conversation list with unread count badges
3. Chat screen with real-time messaging via WebSocket
4. Voice input using Android's SpeechRecognizer API
5. Push notifications for new messages (FCM)
6. Offline message caching with Room
7. Automatic reconnection on network loss
8. Dark mode toggle
9. User profile screen with avatar upload
10. Search users functionality

DATA MODELS (Kotlin data classes):
- User: id, name, email, avatar_url, status, last_seen
- Conversation: id, name, is_group, participants, last_message, unread_count, updated_at
- Message: id, conversation_id, sender_id, content, type (text/voice/image), sent_at, delivered_at, read_at
- Attachment: id, message_id, url, type, size, mime_type

UI REQUIREMENTS:
- Bottom navigation with 3 tabs: Chats, Contacts, Profile
- Floating action button for new conversation
- Swipe-to-refresh on conversation list
- Pull-to-load-more for message pagination
- Loading states for all async operations
- Toast and Snackbar notifications for errors
- Proper state management with Compose State

DATABASE SCHEMA (Room entities):
- UserEntity: id, name, email, avatar_url, status, last_seen
- ConversationEntity: id, name, is_group, unread_count, updated_at
- MessageEntity: id, conversation_id, sender_id, content, type, sent_at, is_delivered, is_read
- ParticipantEntity: conversation_id, user_id

OUTPUT FORMAT:
Generate the complete file structure with all code. For each file, show the full path and the complete implementation. Use proper package naming (com.example.chatclient). Include all necessary imports. No placeholders—I need runnable code.

Why this prompt worked:

  • Complete tech stack specification prevented the AI from making assumptions about libraries or versions.
  • Explicit data models gave the AI the schema upfront—it didn't have to guess what a "message" or "conversation" looked like.
  • Clear output format eliminated the "here's a skeleton" problem.
  • No placeholders forced the AI to generate complete, compilable code.

Step 2: The generation phase—what GLM-5.2 actually produced

I hit enter and watched the AI go to work. GLM-5.2 has a maximum output of 128,000 tokens, which is more than enough for a complete Android app. The response came back in about 50 seconds—and it was massive.

Here's what the AI generated:

  • Complete file structure with 38 files organized across data/, domain/, presentation/, and di/ packages
  • Full Compose UI with 12 composable screens, custom theming, and navigation graph
  • Complete repository layer with offline-first logic using Room and remote data sources
  • Retrofit service interfaces for all 14 API endpoints with proper error handling
  • WebSocket client with automatic reconnection, heartbeat, and message routing
  • Room database with all entities, DAOs, and a migration strategy
  • Hilt modules for dependency injection covering all major components
  • FCM service for push notifications with notification channels
  • Voice input integration using Android's SpeechRecognizer
  • Build.gradle files with all required dependencies and versions

The code was genuinely impressive. The AI used proper Kotlin coroutine patterns, followed Clean Architecture principles, and included comprehensive error handling. The Compose UI was responsive and followed Material Design 3 guidelines.

But here's where things got interesting—and where I had to step in.

The AI made a few decisions that were technically correct but practically problematic:

  • It used SharedPreferences for token storage instead of the more secure EncryptedSharedPreferences. This is a common pattern, but for a production app, I wanted encryption.
  • The WebSocket reconnection logic had an infinite retry loop—the AI forgot to cap the retry count. This would have drained the user's battery if the server was down.
  • The voice input implementation didn't handle runtime permissions properly—it assumed microphone permission was already granted.
  • The Room database migration was missing—the AI generated the schema but forgot the migration script for version upgrades.
  • The notification channels were created but never configured with the correct importance levels—they would have shown as silent notifications on Android 13+.

My tweaking strategy:

Instead of regenerating everything, I used targeted corrections:

The code looks great overall. Let me give you some specific fixes:

1. Replace SharedPreferences with EncryptedSharedPreferences for token storage. Update the TokenManager class accordingly.
2. In the WebSocket reconnection logic, add a maximum retry count of 5 with exponential backoff. Cap it.
3. Add runtime permission handling for RECORD_AUDIO in the VoiceInputViewModel.
4. Generate a Room migration script from version 1 to 2 (add a "deleted" column to messages).
5. Set notification channel importance to IMPORTANCE_HIGH for the messages channel.

Generate the updated versions of these specific files only:
- data/local/TokenManager.kt
- data/remote/WebSocketClient.kt
- presentation/chat/VoiceInputViewModel.kt
- data/local/migrations/RoomMigrations.kt
- presentation/notifications/NotificationHelper.kt

This approach worked beautifully. The AI remembered the full context (thanks to that 1M token window) and made surgical changes to exactly the files I mentioned. No re-generation of the entire project. Just targeted fixes.

The correction formula I recommend:

When the initial output isn't quite right:

  • Identify the specific files that need changes—don't ask the AI to "fix everything."
  • Be explicit about what needs to change—"replace X with Y" is better than "improve the security."
  • Provide the context—the AI remembers the full conversation, so you don't need to re-explain the entire project.
  • Ask for specific files only—this saves tokens and gives you cleaner output.

Step 3: The human polish—what I had to fix with my own hands

Let me be brutally honest: the AI generated about 80% of the code perfectly. The remaining 20% required my direct intervention. Here's exactly what I had to fix manually:

  1. The Gradle dependency versions were slightly off. The AI used compose-compiler:1.5.4 but the latest stable was 1.5.11. I had to update the versions in the build files and sync the project.
  2. The navigation graph had a circular dependency. The AI set up the navigation such that the chat screen could navigate back to itself under certain conditions. I had to restructure the navigation flow.
  3. The state management was inconsistent. Some composables used remember for state, others used rememberSaveable. I standardized on rememberSaveable for configuration changes.
  4. The error messages were too technical. The AI returned raw exception messages to the UI. I wrapped them in user-friendly strings using string resources.
  5. The accessibility labels were missing. The AI generated the UI without content descriptions for screen readers. I had to add them manually.
  6. The test data was too generic. The AI used placeholder data like "John Doe" and "Jane Smith." I replaced them with realistic test data that matched my actual API.
  7. The logging was excessive. The AI added Log.d() statements everywhere. I removed the verbose ones and kept only the error logs.
  8. The ProGuard rules were missing. The AI didn't generate the proguard-rules.pro file for release builds. I had to write it myself.

⚠️ CRITICAL WARNING: Never deploy AI-generated Android code to production without a thorough review. The code looks correct—and often is correct—but subtle issues like the infinite retry loop, missing permissions, or incorrect notification importance can cause crashes, battery drain, or silent failures. Always test on a real device, run the debugger, and verify all edge cases.

My manual review checklist:

  • Run the app on a physical device (not just the emulator)
  • Test all API calls with actual network conditions (slow 3G, offline, flaky connection)
  • Verify all permission requests work correctly
  • Test the WebSocket reconnection with airplane mode toggling
  • Verify notifications appear correctly on Android 13 and 14
  • Check the app's behavior when the user rotates the screen
  • Test the app with a fresh install (no previous data)
  • Run the release build with ProGuard enabled

Step 4: Exporting the final Android client

Z.ai is a chat interface, not an IDE. Here's how I extracted everything efficiently:

  • Copy-paste file by file. I created the project in Android Studio, then for each file the AI generated, I copied the code and pasted it into the corresponding file. This took about 25 minutes for 38 files.
  • Used the "Continue" feature. For long responses that got cut off (rare, given the 128K output limit), I typed "continue" and the AI picked up exactly where it left off.
  • Synced Gradle and resolved dependencies. I ran ./gradlew build to sync the project. The build failed initially due to the version mismatches I mentioned earlier. After fixing those, the build succeeded.
  • Installed on a real device. I connected my Pixel 7 via USB, enabled USB debugging, and ran adb install app-debug.apk. The app installed successfully on the first attempt.
  • Tested the full flow. I registered a user, logged in, created a conversation, sent messages, received WebSocket updates, tested voice input, and verified push notifications. Everything worked as expected.
  • Debugged with logcat. When I encountered issues (the infinite retry loop I mentioned), I used adb logcat to trace the problem. The logs clearly showed the WebSocket reconnecting endlessly. I fixed it with the targeted correction I described above.

Pro tip for beginners: If you're not comfortable with ADB commands, Android Studio has a built-in device manager and logcat viewer. You can install the app by clicking the "Run" button with your device connected.

The Prompt Engineering Matrix: what works for different Android styles

Here's a table of real prompts I tested, with their actual results:

Object Style/Goal My Exact Prompt Result Quality
Production-Ready Enterprise "Build a production-ready Android app with Kotlin, Compose, MVVM, Clean Architecture, Hilt, Room, Retrofit, and FCM. Use encrypted token storage, proper error handling, comprehensive logging with Timber, and unit tests with JUnit and MockK. Generate complete code for all files." Excellent. The AI generated a robust, well-architected app with proper separation of concerns. The test files were actually useful.
Rapid Prototype (MVP) "I need a quick MVP for a chat app. Use Kotlin with XML views (not Compose), simple SharedPreferences for auth, and no database—just in-memory caching. Keep it minimal but functional." Good. The code was simpler and faster to set up, but the lack of proper architecture meant I had to rebuild significant portions later. Perfect for demos.
Experimental/Compose-First "Build a chat app using only Jetpack Compose with Material 3, no XML. Use Compose Navigation, Compose State, and Compose Animation. No ViewModels—use Compose's state hoisting pattern instead." Mixed. The AI understood Compose but generated some anti-patterns. The state hoisting was inconsistent, and the navigation had issues. Required more manual fixes.

Subscription tier comparison: does paying more get you better Android code?

I tested the same prompt across different GLM Coding Plan tiers to see if the output quality changed. Here's what I found:

Tier Generation Speed Output Results Generation Limit Manual Revisions Needed
Free Tier ($5 credits/month) ~50 seconds for full response Same quality as paid tiers Limited to ~3 full Android projects per month (token-based) ~20% of code needed manual fixes
Lite ($18/month) ~47 seconds Identical to free tier Unlimited within token allowance ~20% (same as free)
Pro ($72/month) ~44 seconds Identical to free tier 5x Lite usage ~18% (slightly better, faster generation)
Max ($160/month) ~41 seconds Identical to free tier 20x Lite usage, dedicated resources ~18% (same as Pro)

The honest takeaway: For generating Android code, the subscription tier doesn't affect output quality. The model is the same—you're just paying for higher rate limits, priority access, and faster generation speeds. The free tier with $5 monthly credits is more than enough for occasional Android projects. If you're building daily, the $18/month Lite plan makes sense for the unlimited usage.

Project cost comparison: AI vs. hiring an Android freelancer

Let's run the numbers. I'm based in New York, and the going rate for a freelance Android developer is around $100–$180/hour. A project of this scope—a complete native Android client with auth, real-time messaging, voice input, and push notifications—would typically take a freelancer 4-6 days (32-48 hours).

  • Freelancer cost: 40 hours × $140/hour = $5,600 (minimum)
  • AI cost (my actual spend): $0 (used free credits). If I were paying, the token cost would be roughly:
    • Input: ~18,000 tokens (the prompt + follow-ups + corrections) × $1.40/1M tokens = ~$0.03
    • Output: ~95,000 tokens (the generated code) × $4.40/1M tokens = ~$0.42
    • Total: ~$0.45

$0.45 vs. $5,600.

Is the AI better? No. The AI-generated code is roughly 80% of the quality of a senior Android developer's work. A human developer would produce more nuanced solutions, handle edge cases better, write more maintainable code, and understand the platform-specific quirks that the AI misses.

But here's the reality: I'm not choosing between AI and a human. I'm using the AI to generate the 80% grunt work, then I—the human—polish the remaining 20%. The result is a production-ready Android app in 2.75 hours instead of 40 hours, at a fraction of the cost. That's not a replacement. That's a force multiplier.

The Usability Verdict: how well does GLM-5.2 actually build Android apps?

Free Tier Rating: 8/10

Pros:

  • The 1M token context window is a game-changer for Android development. The AI remembered my entire project structure, all my API endpoints, and every previous correction across a 2-hour session.
  • Code quality is genuinely impressive—clean architecture, proper coroutine usage, and modern Compose patterns.
  • The model understands the full Android development workflow, from dependency injection to database migrations to push notifications.
  • GLM-5.2 is explicitly designed for mobile development scenarios, with a deep understanding of client-side architecture, streaming messages, and local state management.
  • Response speed is fast (~50 seconds for massive outputs).

Cons:

  • The free tier's $5 monthly credit is generous but limited. A single large Android project like this consumed about $0.45 in tokens—so you could build about 11 full Android apps per month for free. That's plenty for most developers.
  • The occasional hallucination (like the infinite retry loop or the missing ProGuard rules) requires vigilance.
  • No direct IDE integration on the free tier—you'll be copy-pasting.
  • The AI sometimes generates code that compiles but has subtle bugs that only show up at runtime.

Paid Tier (Lite/Pro/Max) Rating: 8/10

Same model, same quality. The only differences are higher rate limits, faster generation speeds, and priority access. If you're a heavy user building multiple Android apps per week, the $18/month Lite plan is worth it for the unlimited usage.

Overall Verdict:

GLM-5.2 is one of the best AI coding assistants I've used for Android development, especially given the price-to-performance ratio. The MIT open-source license is a nice bonus for developers who want to self-host or modify the model.

Intercepting field obstacles: answers to the questions you're actually asking

The Android code the AI gave me doesn't compile. What do I do?

First, check the obvious: did you sync Gradle? Did you install all the required SDK components? 70% of "broken" code is environment issues, not AI mistakes. If the problem is in the code itself, paste the error message from Android Studio back into the chat and ask the AI to fix it. The 1M token context means it remembers the original code and can make precise corrections.

How do I get the AI to generate code for my specific Android architecture?

Be explicit in your prompt. Don't say "build a chat app"—say "build a chat app using Kotlin, Compose, MVVM with Clean Architecture, Hilt for DI, Room for local storage, Retrofit for networking, and FCM for push notifications." The more specific you are, the less the AI has to guess.

I'm a beginner Android developer. Can I still use this?

Yes, but with a caveat: you need to understand the code well enough to review it and debug it. The AI will generate functional code, but you'll need to know how to run it, test it, and fix the inevitable edge cases. If you're completely new to Android, start with smaller projects first to build your confidence.

Will this replace my job as an Android developer?

No. It will replace the boring parts of your job—the boilerplate, the repetitive CRUD operations, the standard patterns. You still need to think about architecture, user experience, platform-specific quirks, and business logic. The Android developers who thrive will be the ones who learn to direct AI effectively.

Can I use GLM-5.2 for commercial Android apps?

Yes—the model is released under the MIT license, which permits commercial use. The code it generates is your code. Just make sure you review it thoroughly before shipping to the Play Store.

How do I handle the AI generating code that uses deprecated APIs?

This happens occasionally. The best approach is to specify the API level and the specific libraries you want to use in your prompt. For example: "Use AndroidX libraries, target SDK 36, use Compose 1.5.11, and avoid any deprecated APIs." The AI will respect these constraints.

Your turn: let's build something together

I've walked you through my exact workflow—the prompts, the failures, the manual fixes, and the moment I watched my Pixel 7 light up with the app I'd just generated in two hours. Now it's your turn.

Here's what I want to know: What's the one Android app you've been putting off because it felt like too much work? Drop it in the comments below. Tell me the features, the backend you're integrating with, and the biggest roadblock you're facing. I'll help you break it down into a prompt that GLM-5.2 can execute.

Or better yet—take the prompt I used, adapt it to your project, and run it through Z.ai yourself. Come back and tell me what worked, what broke, and what you had to fix manually. That's how we all get better at this.

The days of spending 40 hours on Android boilerplate are over. The days of thinking deeply about architecture, user experience, and what makes a great mobile app? Those are just beginning.

Let's build.

Post a Comment