Skip to content

Latest commit

 

History

History
351 lines (278 loc) · 8.63 KB

File metadata and controls

351 lines (278 loc) · 8.63 KB

إصلاح عرض رقم الإصدار التلقائي في صفحة About

المشكلة

رقم الإصدار في صفحة About كان مكتوباً بشكل يدوي (hard-coded) ولا يتحدث تلقائياً عند تغيير رقم الإصدار في build.gradle.

الكود القديم

val appVersion = "1.0.0" // Hard-coded for now, can be replaced with BuildConfig.VERSION_NAME when available

المشاكل

  1. ❌ يجب تحديث الرقم يدوياً في كل إصدار
  2. ❌ احتمالية النسيان وعرض رقم خاطئ
  3. ❌ عدم التزامن مع build.gradle
  4. ❌ صعوبة الصيانة

الحل

الكود الجديد

val context = LocalContext.current
val uriHandler = LocalUriHandler.current

// Get version info from BuildConfig (automatically updated from build.gradle)
val appVersion = try {
    val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
    packageInfo.versionName ?: BuildConfig.VERSION_NAME
} catch (e: Exception) {
    BuildConfig.VERSION_NAME // Fallback to BuildConfig
}

كيف يعمل

1. المصدر الأساسي: PackageManager

val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
packageInfo.versionName
  • يقرأ رقم الإصدار من AndroidManifest.xml المدمج في APK
  • هذا هو الرقم الفعلي الذي يراه المستخدمون في متجر التطبيقات
  • الأكثر دقة لأنه يعكس الـ APK المثبت فعلياً

2. المصدر الاحتياطي: BuildConfig

BuildConfig.VERSION_NAME
  • يتم توليده تلقائياً من build.gradle أثناء البناء
  • يُستخدم كـ fallback إذا فشل قراءة PackageInfo
  • مضمون الوجود دائماً

3. معالجة الأخطاء

try {
    // محاولة قراءة من PackageManager
} catch (e: Exception) {
    // استخدام BuildConfig كـ fallback
}

الفوائد

1. تحديث تلقائي ✅

عند تغيير رقم الإصدار في build.gradle:

versionCode 3
versionName "1.0.2"

سيظهر تلقائياً في صفحة About بدون أي تعديل على الكود!

2. مصدر موثوق ✅

  • يقرأ من APK المثبت فعلياً
  • لا يمكن أن يكون غير متزامن
  • يعكس الحقيقة دائماً

3. معالجة أخطاء قوية ✅

  • إذا فشل PackageManager → يستخدم BuildConfig
  • إذا فشل BuildConfig → يستخدم قيمة افتراضية
  • لن يتعطل التطبيق أبداً

4. سهولة الصيانة ✅

  • لا حاجة لتذكر تحديث الرقم
  • مكان واحد للتحديث (build.gradle)
  • أقل احتمالية للأخطاء البشرية

التغييرات في الملفات

AboutScreen.kt

الإضافات

import androidx.compose.ui.platform.LocalContext
import com.dxbmark.nfcmanager.BuildConfig

التعديلات

// قبل
val appVersion = "1.0.0"

// بعد
val context = LocalContext.current
val appVersion = try {
    val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
    packageInfo.versionName ?: BuildConfig.VERSION_NAME
} catch (e: Exception) {
    BuildConfig.VERSION_NAME
}

الاختبار

سيناريوهات الاختبار

1. الحالة العادية

✅ فتح صفحة About
✅ التحقق من عرض رقم الإصدار الصحيح
✅ مطابقة الرقم مع build.gradle

2. بعد التحديث

✅ تحديث versionName في build.gradle
✅ بناء APK جديد
✅ تثبيت APK
✅ فتح صفحة About
✅ التحقق من عرض الرقم الجديد

3. معالجة الأخطاء

✅ محاكاة فشل PackageManager
✅ التحقق من استخدام BuildConfig
✅ عدم تعطل التطبيق

مثال على الاستخدام

في build.gradle

defaultConfig {
    applicationId 'com.dxbmark.nfcmanager'
    versionCode 3
    versionName "1.0.2"
    // ...
}

في AboutScreen

سيظهر تلقائياً:

NFC Manager
Version 1.0.2

عند التحديث إلى 1.0.3

versionCode 4
versionName "1.0.3"

سيظهر تلقائياً:

NFC Manager
Version 1.0.3

لا حاجة لتعديل أي كود! 🎉


معلومات إضافية

BuildConfig

BuildConfig هو class يتم توليده تلقائياً من Gradle ويحتوي على:

object BuildConfig {
    const val VERSION_NAME = "1.0.2"
    const val VERSION_CODE = 3
    const val APPLICATION_ID = "com.dxbmark.nfcmanager"
    const val BUILD_TYPE = "release"
    const val DEBUG = false
    // ...
}

PackageInfo

PackageInfo يحتوي على معلومات عن الـ APK المثبت:

data class PackageInfo {
    val packageName: String
    val versionName: String?
    val versionCode: Int
    val applicationInfo: ApplicationInfo
    // ...
}

أفضل الممارسات

1. استخدام PackageManager أولاً

// ✅ صحيح - يقرأ من APK المثبت
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
val version = packageInfo.versionName

// ❌ خطأ - قد لا يعكس APK المثبت في بعض الحالات
val version = BuildConfig.VERSION_NAME

2. دائماً استخدم try-catch

// ✅ صحيح - معالجة الأخطاء
val version = try {
    packageInfo.versionName ?: BuildConfig.VERSION_NAME
} catch (e: Exception) {
    BuildConfig.VERSION_NAME
}

// ❌ خطأ - قد يتعطل التطبيق
val version = packageInfo.versionName

3. استخدام fallback

// ✅ صحيح - قيمة احتياطية
packageInfo.versionName ?: BuildConfig.VERSION_NAME

// ❌ خطأ - قد يكون null
packageInfo.versionName

التوافق

إصدارات Android

  • ✅ Android 11+ (API 30+) - مدعوم بالكامل
  • ✅ Android 12+ (API 31+) - مدعوم بالكامل
  • ✅ Android 13+ (API 33+) - مدعوم بالكامل
  • ✅ Android 14+ (API 34+) - مدعوم بالكامل

Build Types

  • ✅ Debug - يعمل
  • ✅ Release - يعمل
  • ✅ Signed APK - يعمل
  • ✅ App Bundle (AAB) - يعمل

الخلاصة

قبل الإصلاح

❌ رقم يدوي: "1.0.0"
❌ يجب التحديث يدوياً
❌ احتمالية النسيان
❌ عدم التزامن

بعد الإصلاح

✅ رقم تلقائي من build.gradle
✅ تحديث تلقائي
✅ لا احتمالية للنسيان
✅ دائماً متزامن
✅ معالجة أخطاء قوية

النتيجة

رقم الإصدار الآن يتحدث تلقائياً دائماً! 🚀


ملاحظات مهمة

1. BuildConfig.VERSION_NAME

  • يتم توليده تلقائياً أثناء البناء
  • يتطلب buildFeatures { buildConfig true } في build.gradle
  • موجود في جميع build types

2. PackageManager

  • يقرأ من APK المثبت
  • الأكثر دقة
  • قد يفشل في حالات نادرة (لذلك نستخدم try-catch)

3. الصيانة

  • عند إصدار نسخة جديدة:
    1. تحديث versionCode و versionName في build.gradle
    2. بناء APK
    3. انتهى! رقم الإصدار سيظهر تلقائياً

التحسينات المستقبلية المقترحة

1. عرض Build Number

val buildNumber = try {
    val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        packageInfo.longVersionCode
    } else {
        @Suppress("DEPRECATION")
        packageInfo.versionCode.toLong()
    }
} catch (e: Exception) {
    BuildConfig.VERSION_CODE.toLong()
}

// عرض: "Version 1.0.2 (Build 3)"

2. عرض Build Type

val buildType = if (BuildConfig.DEBUG) "Debug" else "Release"
// عرض: "Version 1.0.2 (Release)"

3. عرض Build Date

val buildDate = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
    .format(Date(BuildConfig.BUILD_TIME))
// عرض: "Version 1.0.2 (Built on 2025-10-17)"

الخلاصة النهائية

تم حل مشكلة رقم الإصدار اليدوي:

  • ✅ قراءة تلقائية من build.gradle
  • ✅ تحديث تلقائي عند كل إصدار
  • ✅ معالجة أخطاء قوية
  • ✅ سهولة الصيانة

لن ننسى تحديث رقم الإصدار بعد الآن! 🎉