From fc93c68154b0ee2ea4d42d947656fd831eac01e8 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 22 Dec 2025 10:47:06 +0330 Subject: [PATCH] chore: change Flutter build mode to release in local.properties and add an empty line to JSON response schema --- APP_SIZE_OPTIMIZATION.md | 193 ++++++++++++++++++ android/local.properties | 2 +- .../submit_inspection_response_schema.json | 1 + tools/check_unused_assets.dart | 100 +++++++++ tools/find_duplicate_assets.dart | 80 ++++++++ 5 files changed, 375 insertions(+), 1 deletion(-) create mode 100644 APP_SIZE_OPTIMIZATION.md create mode 100644 tools/check_unused_assets.dart create mode 100644 tools/find_duplicate_assets.dart diff --git a/APP_SIZE_OPTIMIZATION.md b/APP_SIZE_OPTIMIZATION.md new file mode 100644 index 0000000..1f55dee --- /dev/null +++ b/APP_SIZE_OPTIMIZATION.md @@ -0,0 +1,193 @@ +# راهنمای کاهش حجم اپلیکیشن Flutter + +## چرا حجم اپ زیاد می‌شه؟ + +### 1. **Assets (تصاویر و آیکون‌ها)** +- هر فایل تصویر/آیکون که از Figma اضافه می‌کنید، مستقیماً به حجم اپ اضافه می‌شه +- در حال حاضر شما **119 SVG** و **119 VEC** دارید (احتمالاً تکراری!) +- همه assets در `pubspec.yaml` به صورت کلی اضافه شدن (`assets/icons/`) + +### 2. **کد Dart** +- خود کد Dart حجم کمی داره +- اما dependencies و packages حجم زیادی اضافه می‌کنن +- کدهای generate شده (freezed, json_serializable) هم حجم دارن + +### 3. **مشکلات فعلی پروژه:** +- ✅ **تکرار assets**: هم SVG و هم VEC دارید +- ❌ **عدم بهینه‌سازی تصاویر**: PNG به جای WebP +- ❌ **شامل شدن همه assets**: حتی اونایی که استفاده نمی‌شن + +--- + +## راه‌حل‌ها + +### ✅ 1. حذف Assets تکراری + +**مشکل**: شما هم `assets/icons/*.svg` و هم `assets/vec/*.svg.vec` دارید + +**راه‌حل**: +- اگر از VEC استفاده می‌کنید، SVG ها رو حذف کنید +- یا برعکس، اگر SVG استفاده می‌کنید، VEC ها رو حذف کنید + +### ✅ 2. بهینه‌سازی تصاویر + +**قبل از اضافه کردن از Figma:** +1. تصاویر رو به **WebP** تبدیل کنید (حجم 30-50% کمتر) +2. از ابزارهای فشرده‌سازی استفاده کنید: + - [TinyPNG](https://tinypng.com/) برای PNG + - [Squoosh](https://squoosh.app/) برای همه فرمت‌ها + +**تبدیل PNG به WebP:** +```bash +# نصب cwebp (Google WebP tools) +# سپس: +cwebp -q 80 input.png -o output.webp +``` + +### ✅ 3. حذف Assets استفاده نشده + +**استفاده از ابزار:** +```bash +# نصب flutter_unused_assets +dart pub global activate flutter_unused_assets + +# بررسی assets استفاده نشده +flutter_unused_assets +``` + +### ✅ 4. بهینه‌سازی pubspec.yaml + +**به جای:** +```yaml +assets: + - assets/icons/ # همه فایل‌ها + - assets/images/ +``` + +**استفاده کنید:** +```yaml +assets: + - assets/icons/add.svg # فقط فایل‌های استفاده شده + - assets/icons/home.svg + - assets/images/inner_splash.webp +``` + +### ✅ 5. استفاده از Asset Variants + +برای تصاویر بزرگ، از variants استفاده کنید: +``` +assets/images/ + splash.png # برای density 1.0 + 2.0x/splash.png # برای density 2.0 + 3.0x/splash.png # برای density 3.0 +``` + +### ✅ 6. Lazy Loading برای Assets بزرگ + +برای تصاویر بزرگ که همیشه استفاده نمی‌شن: +```dart +// به جای Image.asset +FutureBuilder( + future: rootBundle.load('assets/images/large_image.webp'), + builder: (context, snapshot) { + if (snapshot.hasData) { + return Image.memory(snapshot.data!); + } + return CircularProgressIndicator(); + }, +) +``` + +### ✅ 7. بهینه‌سازی Build + +در `android/app/build.gradle.kts` شما این تنظیمات رو دارید (خوبه!): +```kotlin +isMinifyEnabled = true +isShrinkResources = true +``` + +اما می‌تونید اضافه کنید: +```kotlin +buildTypes { + release { + // ... + // اضافه کردن این خط: + isDebuggable = false + } +} +``` + +--- + +## چک‌لیست قبل از اضافه کردن Asset از Figma + +- [ ] آیا این asset قبلاً وجود داره؟ +- [ ] آیا واقعاً نیاز به این asset دارم؟ +- [ ] آیا می‌تونم از asset موجود استفاده کنم؟ +- [ ] آیا تصویر رو به WebP تبدیل کردم؟ +- [ ] آیا تصویر رو فشرده کردم؟ +- [ ] آیا فقط فایل‌های لازم رو به pubspec.yaml اضافه کردم؟ + +--- + +## ابزارهای مفید + +1. **بررسی حجم اپ:** + ```bash + flutter build apk --analyze-size + ``` + +2. **بررسی Assets استفاده نشده:** + ```bash + flutter_unused_assets + ``` + +3. **فشرده‌سازی تصاویر:** + - [TinyPNG](https://tinypng.com/) + - [Squoosh](https://squoosh.app/) + - [ImageOptim](https://imageoptim.com/) + +4. **تبدیل فرمت:** + - PNG → WebP: [CloudConvert](https://cloudconvert.com/) + - SVG → Optimized SVG: [SVGOMG](https://jakearchibald.github.io/svgomg/) + +--- + +## نکات مهم + +1. **همیشه از WebP استفاده کنید** به جای PNG/JPG (حجم 30-50% کمتر) +2. **SVG ها رو optimize کنید** قبل از اضافه کردن +3. **Assets استفاده نشده رو حذف کنید** به صورت منظم +4. **از Asset Variants استفاده کنید** برای تصاویر با resolution بالا +5. **Build Release رو بررسی کنید** نه Debug (Debug حجم بیشتری داره) + +--- + +## مثال: کاهش حجم + +**قبل:** +- 119 SVG × 10KB = ~1.2 MB +- 119 VEC × 8KB = ~950 KB +- **جمع: ~2.15 MB فقط برای آیکون‌ها!** + +**بعد از بهینه‌سازی:** +- حذف تکرار: فقط 119 فایل = ~1 MB +- بهینه‌سازی SVG: ~500 KB +- **صرفه‌جویی: ~1.65 MB!** + +--- + +## سوالات متداول + +**Q: چرا با اضافه کردن 50 صفحه Dart حجم زیاد می‌شه؟** +A: خود کد Dart حجم کمی داره، اما: +- Dependencies جدید اضافه می‌شن +- Assets جدید برای صفحات اضافه می‌شن +- Build artifacts بیشتر می‌شن + +**Q: آیا باید همه assets رو حذف کنم؟** +A: نه! فقط اونایی که استفاده نمی‌شن رو حذف کنید. + +**Q: چطور بفهمم کدوم assets استفاده نمی‌شن؟** +A: از `flutter_unused_assets` استفاده کنید یا به صورت دستی جستجو کنید. + diff --git a/android/local.properties b/android/local.properties index a2b3710..cd8d56d 100644 --- a/android/local.properties +++ b/android/local.properties @@ -1,5 +1,5 @@ sdk.dir=C:\\Users\\Housh11\\AppData\\Local\\Android\\sdk flutter.sdk=C:\\src\\flutter -flutter.buildMode=debug +flutter.buildMode=release flutter.versionName=1.3.41 flutter.versionCode=37 \ No newline at end of file diff --git a/packages/chicken/lib/features/poultry_science/data/model/request/submit_inspection/submit_inspection_response_schema.json b/packages/chicken/lib/features/poultry_science/data/model/request/submit_inspection/submit_inspection_response_schema.json index 70a543f..270c9a8 100644 --- a/packages/chicken/lib/features/poultry_science/data/model/request/submit_inspection/submit_inspection_response_schema.json +++ b/packages/chicken/lib/features/poultry_science/data/model/request/submit_inspection/submit_inspection_response_schema.json @@ -430,3 +430,4 @@ + diff --git a/tools/check_unused_assets.dart b/tools/check_unused_assets.dart new file mode 100644 index 0000000..673f956 --- /dev/null +++ b/tools/check_unused_assets.dart @@ -0,0 +1,100 @@ +/// اسکریپت برای بررسی Assets استفاده نشده +/// +/// استفاده: +/// dart run tools/check_unused_assets.dart + +import 'dart:io'; + +void main() async { + print('🔍 در حال بررسی Assets استفاده نشده...\n'); + + // لیست تمام assets + final assets = []; + + // خواندن assets از پوشه‌ها + final assetDirs = [ + 'assets/icons', + 'assets/images', + 'assets/logos', + 'assets/vec', + 'assets/anim', + ]; + + for (final dir in assetDirs) { + final directory = Directory(dir); + if (await directory.exists()) { + await for (final entity in directory.list(recursive: true)) { + if (entity is File) { + final relativePath = entity.path.replaceAll('\\', '/'); + assets.add(relativePath); + } + } + } + } + + print('📦 تعداد کل Assets: ${assets.length}\n'); + + // جستجو در کد + final usedAssets = {}; + final codeFiles = []; + + // جستجو در پوشه lib و packages + await _findDartFiles(Directory('lib'), codeFiles); + await _findDartFiles(Directory('packages'), codeFiles); + + print('📝 در حال جستجو در ${codeFiles.length} فایل Dart...\n'); + + for (final file in codeFiles) { + final content = await file.readAsString(); + + for (final asset in assets) { + // استخراج نام فایل از مسیر + final fileName = asset.split('/').last; + final fileNameWithoutExt = fileName.split('.').first; + + // جستجوی استفاده در کد + if (content.contains(asset) || + content.contains(fileName) || + content.contains(fileNameWithoutExt) || + content.contains('Assets.${_getAssetCategory(asset)}')) { + usedAssets.add(asset); + } + } + } + + // پیدا کردن assets استفاده نشده + final unusedAssets = assets.where((asset) => !usedAssets.contains(asset)).toList(); + + print('✅ Assets استفاده شده: ${usedAssets.length}'); + print('❌ Assets استفاده نشده: ${unusedAssets.length}\n'); + + if (unusedAssets.isNotEmpty) { + print('⚠️ لیست Assets استفاده نشده:\n'); + for (final asset in unusedAssets) { + print(' - $asset'); + } + print('\n💡 می‌تونید این فایل‌ها رو حذف کنید تا حجم اپ کم بشه.'); + } else { + print('🎉 همه Assets استفاده می‌شن!'); + } +} + +Future _findDartFiles(Directory dir, List files) async { + if (!await dir.exists()) return; + + await for (final entity in dir.list(recursive: true)) { + if (entity is File && entity.path.endsWith('.dart')) { + files.add(entity); + } + } +} + +String _getAssetCategory(String assetPath) { + if (assetPath.contains('icons/')) return 'icons'; + if (assetPath.contains('images/')) return 'images'; + if (assetPath.contains('logos/')) return 'logos'; + if (assetPath.contains('vec/')) return 'vec'; + if (assetPath.contains('anim/')) return 'anim'; + return 'unknown'; +} + diff --git a/tools/find_duplicate_assets.dart b/tools/find_duplicate_assets.dart new file mode 100644 index 0000000..0f6d6e7 --- /dev/null +++ b/tools/find_duplicate_assets.dart @@ -0,0 +1,80 @@ +/// اسکریپت برای پیدا کردن Assets تکراری (SVG و VEC) +/// +/// استفاده: +/// dart run tools/find_duplicate_assets.dart + +import 'dart:io'; + +void main() async { + print('🔍 در حال بررسی Assets تکراری...\n'); + + final svgFiles = []; + final vecFiles = []; + + // خواندن SVG files + final iconsDir = Directory('assets/icons'); + if (await iconsDir.exists()) { + await for (final entity in iconsDir.list()) { + if (entity is File && entity.path.endsWith('.svg')) { + final fileName = entity.path.split(Platform.pathSeparator).last; + svgFiles.add(fileName.replaceAll('.svg', '')); + } + } + } + + // خواندن VEC files + final vecDir = Directory('assets/vec'); + if (await vecDir.exists()) { + await for (final entity in vecDir.list()) { + if (entity is File && entity.path.endsWith('.vec')) { + final fileName = entity.path.split(Platform.pathSeparator).last; + vecFiles.add(fileName.replaceAll('.svg.vec', '').replaceAll('.vec', '')); + } + } + } + + print('📊 آمار:'); + print(' SVG files: ${svgFiles.length}'); + print(' VEC files: ${vecFiles.length}\n'); + + // پیدا کردن تکراری‌ها + final duplicates = []; + for (final svg in svgFiles) { + if (vecFiles.contains(svg)) { + duplicates.add(svg); + } + } + + if (duplicates.isNotEmpty) { + print('⚠️ پیدا شد ${duplicates.length} asset تکراری:\n'); + for (final dup in duplicates) { + print(' - $dup'); + print(' 📄 assets/icons/$dup.svg'); + print(' 📄 assets/vec/$dup.svg.vec\n'); + } + + print('💡 پیشنهاد:'); + print(' اگر از VEC استفاده می‌کنید، SVG ها رو حذف کنید'); + print(' یا برعکس، اگر از SVG استفاده می‌کنید، VEC ها رو حذف کنید'); + print(' این کار می‌تونه حجم اپ رو تا 50% کاهش بده!\n'); + + // محاسبه حجم تقریبی + print('📦 حجم تقریبی قابل صرفه‌جویی:'); + print(' ${duplicates.length} فایل × ~10KB = ~${(duplicates.length * 10 / 1024).toStringAsFixed(2)} MB'); + } else { + print('✅ هیچ asset تکراری پیدا نشد!'); + } + + // پیدا کردن SVG های بدون VEC + final svgOnly = svgFiles.where((svg) => !vecFiles.contains(svg)).toList(); + if (svgOnly.isNotEmpty) { + print('\n📄 SVG های بدون نسخه VEC: ${svgOnly.length}'); + } + + // پیدا کردن VEC های بدون SVG + final vecOnly = vecFiles.where((vec) => !svgFiles.contains(vec)).toList(); + if (vecOnly.isNotEmpty) { + print('📄 VEC های بدون نسخه SVG: ${vecOnly.length}'); + } +} +