# اضافه‌کردن چک آنلاین لغو به اپ اندروید (دفتر دستک)

این فایل برای برنامه‌نویسی است که به **سورس کد** اپ اندروید دسترسی دارد — نه فقط
فایل APK. بدون سورس کد، هیچ تغییری در رفتار اپ نصب‌شده ممکن نیست.

## واقعیت مهم قبل از شروع

اپ فعلی هیچ مجوز `INTERNET` ندارد و هیچ‌وقت با سروری تماس نمی‌گیرد. اضافه‌کردن این
قابلیت باعث می‌شود اپ **دیگر ۱۰۰٪ آفلاین نباشد** — نسخه‌ی جدید باید دوباره ساخته،
امضا و به مشتری‌ها داده شود (نصب‌های قبلی خودکار آپدیت نمی‌شوند مگر مشتری نسخه‌ی
جدید را دستی نصب کند). و حتی بعد از این تغییر، گوشی‌ای که اصلاً اینترنت ندارد،
همچنان تا پایان تاریخ انقضای کدش کار خواهد کرد — این تنها راهیست که برای آن گوشی
وجود دارد.

## ۱) مجوز اینترنت

```xml
<uses-permission android:name="android.permission.INTERNET" />
```

## ۲) صدا زدن اندپوینت پنل

پنل یک اندپوینت آماده دارد: `https://DOMAIN/PATH-PANEL/api/check.php`
ورودی: پارامتر `code` = همان رشته‌ی کد فعال‌سازی که همین الان روی گوشی ذخیره شده.

خروجی نمونه:
```json
{ "ok": true, "found": true, "revoked": false, "expired": false, "expires_at": 1735689599 }
```
اگر `revoked` برابر `true` بود، برنامه باید قفل شود (مثلاً همان صفحه‌ی «کد نامعتبر»
که موقع نداشتن لایسنس نشان می‌دهید).

## ۳) نمونه کد Kotlin (پیشنهادی: در پس‌زمینه، هر بار باز شدن اپ + حداکثر یک‌بار در روز)

```kotlin
import java.net.HttpURLConnection
import java.net.URL
import java.net.URLEncoder
import org.json.JSONObject

object LicenseGate {
    private const val CHECK_URL = "https://DOMAIN/PATH-PANEL/api/check.php"
    private const val TIMEOUT_MS = 5000

    // fail-open: اگر اینترنت نبود یا سرور جواب نداد، اپ همان‌طور که هست کار می‌کند
    // (چون هدف قطعِ فوریِ گوشی‌های آنلاین است، نه شکستنِ استفاده‌ی آفلاین)
    fun checkRevokedInBackground(code: String, onRevoked: () -> Unit) {
        Thread {
            try {
                val url = URL(CHECK_URL)
                val conn = url.openConnection() as HttpURLConnection
                conn.requestMethod = "POST"
                conn.doOutput = true
                conn.connectTimeout = TIMEOUT_MS
                conn.readTimeout = TIMEOUT_MS
                val body = "code=" + URLEncoder.encode(code, "UTF-8")
                conn.outputStream.use { it.write(body.toByteArray()) }

                if (conn.responseCode == 200) {
                    val text = conn.inputStream.bufferedReader().readText()
                    val json = JSONObject(text)
                    if (json.optBoolean("found", false) && json.optBoolean("revoked", false)) {
                        onRevoked() // این باید روی UI thread اجرا شود (runOnUiThread یا Handler)
                    }
                }
            } catch (_: Exception) {
                // بدون اینترنت یا خطای شبکه → کاری نکن، اپ کار خودش را می‌کند
            }
        }.start()
    }
}
```

نحوه‌ی استفاده در `MainActivity` (یا هرجا که کد فعال‌سازی را بعد از اعتبارسنجی
محلی موجود دارید):

```kotlin
LicenseGate.checkRevokedInBackground(storedCode) {
    runOnUiThread {
        // همان مسیر قفل‌کردن اپ که موقع نامعتبر بودن لایسنس استفاده می‌کنید
        showLicenseInvalidScreen()
    }
}
```

## ۴) نکات

- این چک فقط زمانی اثر دارد که گوشی اینترنت داشته باشد؛ نتیجه را کش نکنید طوری که
  مانع اجرای بدون اینترنت شود.
- اگر می‌خواهید هر روز فقط یک‌بار چک شود (برای کاهش مصرف دیتا)، زمان آخرین چک را
  در `SharedPreferences` نگه دارید.
- اندپوینت به ازای هر IP در دقیقه محدودیت تعداد درخواست دارد؛ برای استفاده‌ی عادی
  کافی است.
