creatix / app-version-manager
Enterprise-ready Laravel package for mobile app version policy enforcement, forced/optional update gates (HTTP 426), in-app update checks, and automated App Store & Google Play Store release sync.
Package info
github.com/Creatix-Infotech/app-version-manager
pkg:composer/creatix/app-version-manager
Requires
- php: ^8.2|^8.3|^8.4|^8.5
- firebase/php-jwt: ^6.10|^7.0
- google/auth: ^1.30
- illuminate/contracts: ^11.0|^12.0|^13.0
- illuminate/database: ^11.0|^12.0|^13.0
- illuminate/http: ^11.0|^12.0|^13.0
- illuminate/routing: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0
- phpunit/phpunit: ^10.5|^11.0|^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-30 11:01:17 UTC
README
Enterprise-grade Laravel package for mobile app version policy enforcement, forced & optional update gates, in-app update checks, and automated App Store & Google Play release synchronization.
๐ Table of Contents
- Overview
- Why Use App Version Manager?
- Key Features
- Architecture & Request Flow
- Compatibility
- Installation
- Configuration
- Usage Guide
- Client Integration Examples
- Frequently Asked Questions (FAQ)
- Testing
- Changelog
- Contributing
- Security
- License
๐ Overview
When maintaining mobile applications (iOS, Android, Flutter, React Native), breaking API changes, deprecated database schemas, and critical security patches require a dependable way to enforce minimum supported app versions.
App Version Manager provides a plug-and-play solution for Laravel applications:
- Intercepts requests from outdated builds before they reach your controller logic with HTTP 426 Upgrade Required.
- Notifies mobile clients when a newer version is available without blocking functionality (optional updates).
- Synchronizes newly published releases directly from Apple App Store Connect and Google Play Developer API.
- Delivers sub-millisecond response times with zero database overhead via smart policy caching.
๐ก Why Use App Version Manager?
| Traditional Approach | With Creatix App Version Manager |
|---|---|
Hardcoding minimum versions in .env or route files |
Clean database-driven version management per platform (ios, android) |
| Manually updating version numbers after every store release | Automatic scheduled background synchronization with App Store & Google Play |
| Checking database on every single mobile API hit | Multi-layer cached policies that eliminate redundant database queries |
| Custom, inconsistent response codes across endpoints | Standardized HTTP 426 Upgrade Required with store links & update notes |
๐ Key Features
- ๐ก๏ธ Forced Update Middleware Gate: Intercepts requests containing outdated client build numbers and returns a clean
HTTP 426 Upgrade Requiredpayload with store URLs. - ๐ก Optional In-App Update Prompts: Allows mobile apps to display non-intrusive upgrade prompts when newer features are available.
- โก Zero-Overhead Caching: Policies are cached with customizable TTL and automatically invalidated on updates, keeping your API lightning fast.
- ๐ Automated Store Sync: Command-line tool and scheduler task to fetch live release data directly from Apple App Store Connect and Google Play Console.
- ๐ฑ RESTful Version Check Endpoint: Ready-to-use
/api/v1/app-versionroute for splash screen or launch checks. - ๐ Event-Driven Architecture: Dispatches
StoreVersionReleasedevents to trigger notifications, Slack alerts, or emails when new versions go live. - ๐งฉ Multi-Platform Support: Tailored configurations for iOS, Android, and cross-platform frameworks (Flutter, React Native, Ionic, Capacitor).
๐ Architecture & Request Flow
flowchart TD
Client["๐ฑ Mobile Client (iOS / Android)"] --> Request["HTTP Request + Headers (X-App-Platform, X-App-Build)"]
Request --> Middleware["๐ก๏ธ EnforceMinAppVersion Middleware"]
Middleware --> CacheCheck{"Cached Version Policy Exists?"}
CacheCheck -- Yes --> ReadCache["Read Active Policy from Cache"]
CacheCheck -- No --> ReadDB["Query Database & Cache Policy"]
ReadCache --> Evaluate{"Compare Client Build vs Policy"}
ReadDB --> Evaluate
Evaluate -- "Client Build < Minimum Build" --> HTTP426["๐ 426 Upgrade Required\n(Forced Update JSON + Store URL)"]
Evaluate -- "Client Build >= Minimum Build" --> Controller["โ
Pass to API Controller / App Logic"]
Loading
๐ฆ Compatibility
| Environment | Supported Versions |
|---|---|
| PHP | 8.2.x, 8.3.x, 8.4.x, 8.5.x |
| Laravel | 11.x, 12.x, 13.x |
| Databases | MySQL, PostgreSQL, SQLite, SQL Server |
| Client Platforms | iOS, Android, Flutter, React Native, Swift, Kotlin |
๐ ๏ธ Installation
Install the package via Composer:
composer require creatix/app-version-manager
Publish the package configuration and database migration files:
php artisan vendor:publish --tag=app-version-manager-config php artisan vendor:publish --tag=app-version-manager-migrations
Execute the database migration:
php artisan migrate
โ๏ธ Configuration
The published config/app-version-manager.php file allows you to customize headers, cache TTL, API routes, and store API credentials:
return [ /* |-------------------------------------------------------------------------- | Database Table |-------------------------------------------------------------------------- */ 'table_name' => 'app_versions', /* |-------------------------------------------------------------------------- | Request Headers |-------------------------------------------------------------------------- | Custom headers sent by mobile clients to identify platform and build. */ 'headers' => [ 'platform' => 'X-App-Platform', // 'ios' or 'android' 'build' => 'X-App-Build', // integer build number (e.g. 42) ], /* |-------------------------------------------------------------------------- | Version Check API Endpoint |-------------------------------------------------------------------------- */ 'api' => [ 'enabled' => true, 'prefix' => 'api/v1', 'route' => 'app-version', ], /* |-------------------------------------------------------------------------- | Cache Settings |-------------------------------------------------------------------------- | Reduces database load by caching current platform policies. */ 'cache' => [ 'enabled' => true, 'ttl' => 3600, // seconds ], /* |-------------------------------------------------------------------------- | Store API Credentials |-------------------------------------------------------------------------- | Credentials for App Store Connect and Google Play Developer API. */ 'stores' => [ 'appstore' => [ 'issuer_id' => env('ASC_ISSUER_ID'), 'key_id' => env('ASC_KEY_ID'), 'private_key' => env('ASC_PRIVATE_KEY'), 'app_id' => env('ASC_APP_ID'), ], 'googleplay' => [ 'service_account' => env('GOOGLE_PLAY_SERVICE_ACCOUNT'), 'package_name' => env('GOOGLE_PLAY_PACKAGE_NAME'), ], ], ];
๐ป Usage Guide
1. Protecting Routes with Forced Update Middleware
Apply the enforce.min.app.version middleware to any API route or group:
use Illuminate\Support\Facades\Route; Route::middleware(['api', 'enforce.min.app.version'])->group(function () { Route::get('/user/profile', [UserController::class, 'profile']); Route::post('/orders', [OrderController::class, 'store']); });
When a mobile client sends a request with headers:
X-App-Platform: androidX-App-Build: 12
If your minimum required build is 15, the middleware intercepts the request and responds with HTTP 426 Upgrade Required:
{
"success": false,
"message": "A newer version of the app is required to continue.",
"code": 426,
"data": {
"platform": "android",
"update_required": "forced",
"minimum_version": "1.5.0",
"minimum_build": 15,
"latest_version": "2.0.0",
"latest_build": 20,
"store_url": "https://play.google.com/store/apps/details?id=com.example",
"update_message": "Please update to continue using the app."
}
}
2. Mobile App Launch Version Check Endpoint
Call the built-in endpoint on app startup (splash screen) to verify version status:
GET /api/v1/app-version?platform=ios&build=18
(Alternatively, send via headers X-App-Platform: ios and X-App-Build: 18)
Example Response (Optional Update Available):
{
"success": true,
"message": "App version status retrieved successfully.",
"data": {
"platform": "ios",
"update_required": "optional",
"is_supported": true,
"latest_version": "2.0.0",
"latest_build": 20,
"minimum_version": "1.5.0",
"minimum_build": 15,
"store_url": "https://apps.apple.com/app/id123456789",
"update_message": "A new version with performance improvements is available!"
}
}
Status Enum:
forced: Client build is below minimum build. App should block user interaction and redirect to store.optional: Client build meets minimum build, but a newer release exists. Display a dismissible dialog.none: Client is running the latest available build.
3. Programmatic Usage via Facade
Use the AppVersion facade anywhere in your Laravel services:
use Creatix\AppVersionManager\Facades\AppVersion; // Retrieve the active policy model for a given platform $policy = AppVersion::currentFor('android'); // Check requirement status for a specific build $check = AppVersion::check('ios', 42); if ($check['update_required'] === 'forced') { // Custom fallback or analytics logging }
4. Automated App Store & Google Play Sync
Keep your database up-to-date automatically whenever a new build is approved on the stores:
php artisan app-versions:sync
Schedule it in your routes/console.php (Laravel 11+):
use Illuminate\Support\Facades\Schedule; Schedule::command('app-versions:sync')->hourly();
When a new version is detected, a StoreVersionReleased event is triggered:
use Creatix\AppVersionManager\Events\StoreVersionReleased; use Illuminate\Support\Facades\Event; Event::listen(StoreVersionReleased::class, function ($event) { // Notify your mobile team or send an alert via Slack/Email Log::info("New version released for {$event->platform}: {$event->version} (Build {$event->build})"); });
๐ฑ Client Integration Examples
Flutter (Dart)
Using a Dio interceptor to handle forced updates globally:
import 'package:dio/dio.dart'; import 'package:url_launcher/url_launcher.dart'; class ForceUpdateInterceptor extends Interceptor { @override void onError(DioException err, ErrorInterceptorHandler handler) { if (err.response?.statusCode == 426) { final storeUrl = err.response?.data['data']['store_url']; final message = err.response?.data['message']; // Show non-dismissible dialog and launch store URL launchUrl(Uri.parse(storeUrl), mode: LaunchMode.externalApplication); return; } super.onError(err, handler); } }
React Native (Axios)
import axios from 'axios'; import { Alert, Linking } from 'react-native'; const api = axios.create({ baseURL: 'https://api.yourdomain.com', headers: { 'X-App-Platform': Platform.OS, // 'ios' or 'android' 'X-App-Build': 12, }, }); api.interceptors.response.use( (response) => response, (error) => { if (error.response && error.response.status === 426) { const { store_url, update_message } = error.response.data.data; Alert.alert( 'Update Required', update_message || 'Please update the app to continue.', [{ text: 'Update Now', onPress: () => Linking.openURL(store_url) }], { cancelable: false } ); } return Promise.reject(error); } );
iOS (Swift)
func handleResponse(response: HTTPURLResponse, data: Data) { if response.statusCode == 426 { if let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any], let responseData = json["data"] as? [String: Any], let storeUrlString = responseData["store_url"] as? String, let storeUrl = URL(string: storeUrlString) { DispatchQueue.main.async { UIApplication.shared.open(storeUrl) } } } }
Android (Kotlin)
if (response.code() == 426) { val errorBody = response.errorBody()?.string() val storeUrl = JSONObject(errorBody).getJSONObject("data").getString("store_url") val intent = Intent(Intent.ACTION_VIEW, Uri.parse(storeUrl)) context.startActivity(intent) }
โ Frequently Asked Questions (FAQ)
How does App Version Manager achieve zero database overhead?
When caching is enabled (config('app-version-manager.cache.enabled')), the active version policy for each platform is stored in your configured Laravel cache store (Redis, Memcached, DynamoDB, etc.). All incoming mobile API requests read directly from cache without hitting the database. Cache keys are automatically invalidated whenever a policy is created or updated.
What happens if a request does not contain version headers?
If the configured headers (X-App-Platform and X-App-Build) are missing, the middleware gracefully allows the request to pass through by default, ensuring non-mobile clients (such as web frontends or webhooks) are never inadvertently blocked.
Why does the package use HTTP 426 Upgrade Required?
HTTP 426 Upgrade Required is the official IETF RFC 7231 standard status code designed specifically to inform clients that the server refuses to perform the request using the current protocol or build and will proceed only after the client upgrades.
Can I bypass version enforcement in automated testing or local development?
Yes. Simply omit the X-App-Platform / X-App-Build headers in test suites, or mock the AppVersion facade using AppVersion::shouldReceive('check')->andReturn(...).
๐งช Testing
Run tests with Composer:
composer test
Or invoke PHPUnit directly:
vendor/bin/phpunit
๐ Changelog
Please see CHANGELOG.md for details on recent releases and updates.
๐ค Contributing
Contributions, bug reports, and pull requests are welcome! Please review CONTRIBUTING.md for guidelines.
๐ Security Vulnerabilities
If you discover any security-related issues, please review our Security Policy or email hello@creatixinfotech.com instead of using the public issue tracker.
๐ License
The MIT License (MIT). Please see License File for more information.
Crafted with โค๏ธ by Creatix Infotech