Flutter 8 min read Updated Aug 2026

How to Build a 4K Wallpaper App in Flutter Using NexWall Free REST API (Full 2026 Tutorial)

Step-by-step complete guide with source code to create an Android & iOS 4K wallpaper app using Flutter, Provider/Bloc, cached_network_image, and NexWall JSON API.

1. Introduction & Prerequisites

In this guide, we will build a production-grade 4K Wallpaper app in Flutter that fetches categorized wallpapers from the NexWall Free REST API. We will use the http package for network requests and cached_network_image for ultra-smooth edge caching.

2. Adding Dependencies

Add the following packages to your pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  http: ^1.2.0
  cached_network_image: ^3.3.1
  flutter_staggered_grid_view: ^0.7.0

3. Building the Wallpaper Model

Create a file named models/wallpaper_model.dart:

class WallpaperItem {
  final int id;
  final int categoryId;
  final String imageUrl;
  final String thumbnailUrl;
  final bool isPremium;
  final String resolution;

  WallpaperItem({
    required this.id,
    required this.categoryId,
    required this.imageUrl,
    required this.thumbnailUrl,
    required this.isPremium,
    required this.resolution,
  });

  factory WallpaperItem.fromJson(Map<String, dynamic> json) {
    return WallpaperItem(
      id: json['id'] ?? 0,
      categoryId: json['category_id'] ?? 0,
      imageUrl: json['image_url'] ?? '',
      thumbnailUrl: json['thumbnail_url'] ?? (json['image_url'] ?? ''),
      isPremium: json['is_premium'] ?? false,
      resolution: json['resolution'] ?? '2160x3840',
    );
  }
}

4. API Service Implementation

Create services/wallpaper_api_service.dart and paste your NexWall Bearer API token:

import 'dart:convert';
import 'package:http/http.dart' as http;
import '../models/wallpaper_model.dart';

class WallpaperApiService {
  static const String _baseUrl = 'https://nexwall.kodnextech.com/api/developer/v1';
  static const String _apiKey = 'YOUR_NEXWALL_BEARER_API_KEY';

  static Future<List<WallpaperItem>> fetchWallpapers({int page = 1, int? categoryId}) async {
    final queryParams = {
      'page': page.toString(),
      'per_page': '24',
      if (categoryId != null) 'category_id': categoryId.toString(),
    };

    final uri = Uri.parse('$_baseUrl/wallpapers').replace(queryParameters: queryParams);

    final response = await http.get(
      uri,
      headers: {
        'Authorization': 'Bearer $_apiKey',
        'Accept': 'application/json',
      },
    );

    if (response.statusCode == 200) {
      final decoded = jsonDecode(response.body);
      final List data = decoded['data'] ?? [];
      return data.map((item) => WallpaperItem.fromJson(item)).toList();
    } else {
      throw Exception('Failed to load wallpapers: ${response.statusCode}');
    }
  }
}

5. Grid View UI Implementation

import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'services/wallpaper_api_service.dart';
import 'models/wallpaper_model.dart';

class WallpaperFeedScreen extends StatefulWidget {
  @override
  _WallpaperFeedScreenState createState() => _WallpaperFeedScreenState();
}

class _WallpaperFeedScreenState extends State<WallpaperFeedScreen> {
  late Future<List<WallpaperItem>> _wallpapersFuture;

  @override
  void initState() {
    super.initState();
    _wallpapersFuture = WallpaperApiService.fetchWallpapers();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFF0F1117),
      appBar: AppBar(
        title: const Text('NexWall 4K Wallpapers'),
        backgroundColor: Colors.transparent,
        elevation: 0,
      ),
      body: FutureBuilder<List<WallpaperItem>>(
        future: _wallpapersFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator(color: Color(0xFF7C8CFF)));
          }
          if (snapshot.hasError) {
            return Center(child: Text('Error: ${snapshot.error}', style: const TextStyle(color: Colors.white70)));
          }

          final wallpapers = snapshot.data ?? [];
          return GridView.builder(
            padding: const EdgeInsets.all(12),
            gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 2,
              crossAxisSpacing: 10,
              mainAxisSpacing: 10,
              childAspectRatio: 9 / 16,
            ),
            itemCount: wallpapers.length,
            itemBuilder: (context, index) {
              final item = wallpapers[index];
              return ClipRRect(
                borderRadius: BorderRadius.circular(16),
                child: CachedNetworkImage(
                  imageUrl: item.thumbnailUrl,
                  fit: BoxFit.cover,
                  placeholder: (context, url) => Container(color: const Color(0xFF1E2130)),
                  errorWidget: (context, url, error) => const Icon(Icons.broken_image, color: Colors.grey),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

Want to test this endpoint right now?

Use the interactive Live Sandbox Console to test queries without writing code.

Try In Sandbox