jh_services

A lightweight, robust Flutter service suite to manage network requests, local persistent storage, media picking, and internet connectivity seamlessly with best practices.

pub package license


Features

  • Network Service: Perform REST requests (GET, POST, PUT, PATCH, DELETE) with typed error handling and interceptors via Dio.
  • Shared Preferences Service: Store and retrieve typed values, DateTime, JSON objects, lists, and bulk key-values via shared_preferences.
  • Connectivity Service: Check network reachability and subscribe to real-time connection status streams via internet_connection_checker_plus.
  • Image Picker Service: Pick images or videos from the gallery or camera cross-platform via image_picker.
  • File Picker Service: Pick files or file data cross-platform via file_picker.
  • Dependency Injection: Seamless service registration and resolution using get_it.

Installation

Add jh_services to your project's pubspec.yaml:

dependencies:
  jh_services: ^0.2.1

Then run:

flutter pub get

Getting Started

1. Initialize Services

Call setupServiceLocator during application startup, typically in main():

import 'package:flutter/material.dart';
import 'package:jh_services/jh_services.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await setupServiceLocator(
    networkConfig: const NetworkConfig(
      baseUrl: 'https://api.example.com',
      defaultHeaders: {
        'Content-Type': 'application/json',
      },
      connectTimeout: 5000,
      receiveTimeout: 3000,
    ),
    sharedPrefsConfig: const SharedPrefsConfig(),
    connectivityConfig: const ConnectivityConfig(),
  );

  runApp(const MyApp());
}

Usage Guide

Shared Preferences Service

Retrieve the service instance anywhere:

final sharedPrefsService = serviceLocator<SharedPrefsService>();

// Primitives
await sharedPrefsService.saveString('username', 'ali');
final String? username = sharedPrefsService.getString('username');

await sharedPrefsService.saveBool('is_dark_mode', true);
final bool? isDarkMode = sharedPrefsService.getBool('is_dark_mode');

// DateTime storage
await sharedPrefsService.saveDateTime('last_login', DateTime.now());
final DateTime? lastLogin = sharedPrefsService.getDateTime('last_login');

// JSON Objects
await sharedPrefsService.saveJson('profile', {'id': 1, 'role': 'admin'});
final Map<String, dynamic>? profile = sharedPrefsService.getJson('profile');

// Lists
await sharedPrefsService.addToStringList('tags', 'flutter');
await sharedPrefsService.updateOrAppendToStringList('tags', ['dart', 'mobile']);

// Bulk actions & increments
await sharedPrefsService.saveBulk({'theme': 'dark', 'volume': 80});
final data = sharedPrefsService.getBulk(['theme', 'volume']);
await sharedPrefsService.incrementOrInitInt('launch_count', incrementBy: 1);

Network Service & Error Handling

final networkService = serviceLocator<NetworkService>();

// GET request
try {
  final response = await networkService.get('/posts/1');
  debugPrint('Post title: ${response['title']}');
} on ServerException catch (e) {
  debugPrint('Error: ${e.errorModel.message} (HTTP ${e.errorModel.statusCode})');
}

// POST request with JSON
final postResult = await networkService.post(
  '/posts',
  data: {'title': 'New Post', 'userId': 1},
);

// File upload with FormData (fully cross-platform on Web, Mobile, & Desktop)
final imagePickerService = serviceLocator<ImagePickerService>();
final XFile? image = await imagePickerService.pickImageFromGallery();

if (image != null) {
  final multipartFile = await convertImageToMultipartFile(image);
  await networkService.post(
    '/upload',
    data: {'file': multipartFile},
    isFormData: true,
  );
}

Exception Mapping

Network errors are mapped into a standardized ServerException:

Dio Exception Type Status Code Description
connectionTimeout 408 Request timed out while connecting.
sendTimeout 504 Request timed out while sending data.
receiveTimeout 504 Request timed out while awaiting response.
badCertificate 495 SSL certificate validation failure.
cancel 499 Request was cancelled by the client.
connectionError 503 Network connection error.
badResponse 400..504 Server returned an error status code.
unknown 520 Unspecified network error.

Connectivity Service

Check connectivity on demand or listen to connection status changes:

final connectivityService = serviceLocator<ConnectivityService>();

// Check current connectivity
final bool isConnected = await connectivityService.isConnected();

// Listen to status changes
connectivityService.onStatusChange.listen((status) {
  if (status == InternetStatus.connected) {
    debugPrint('Connected to the internet');
  } else {
    debugPrint('Lost internet connection');
  }
});

Image Picker Service

final imagePickerService = serviceLocator<ImagePickerService>();

// Pick from gallery
final XFile? image = await imagePickerService.pickImageFromGallery();

// Capture from camera
final XFile? photo = await imagePickerService.pickImageFromCamera();

// Pick multiple images
final List<XFile>? photos = await imagePickerService.pickMultipleImages();

// Pick video
final XFile? video = await imagePickerService.pickVideoFromGallery();

File Picker Service

final filePickerService = serviceLocator<FilePickerService>();

// Pick single file path (Mobile / Desktop)
final String? filePath = await filePickerService.pickSingleFile(
  allowedExtensions: ['pdf', 'doc'],
);

// Pick file details with bytes (Cross-platform including Web)
final PlatformFile? file = await filePickerService.pickFileDetails();
if (file != null) {
  debugPrint('Picked ${file.name} (${file.size} bytes)');
}

License

This project is licensed under the MIT License - see the LICENSE file for details.

Libraries

jh_services
A lightweight service package for Flutter to handle network requests, local storage, connectivity, and media selection seamlessly.