Files
MathApp_frontend/android/README.md
AliReza 5327fed1dd Android: reproducible signed build (keystore and Bazaar RSA key read from outside the repo), Gradle wrapper, build-apk.sh
First time the project has been built: debug and release both produce an APK.
Release refuses to build without keystore or RSA key.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 14:05:48 +03:30

66 lines
4.3 KiB
Markdown

# اپِ اندرویدِ تدریسینو (پوسته‌ی WebView + پرداختِ بازار)
همان سایتِ `math.tadrisino2.ir` داخلِ یک WebView. تنها کدِ بومی پرداختِ درون‌برنامه‌ایِ
کافه‌بازار است (کتابخانه‌ی Poolakey)، چون بازار برای اپی که در آن منتشر می‌شود پرداختِ
محصولِ دیجیتال را فقط از راهِ خودش می‌پذیرد. باقیِ اپ همان فرانتِ وب است و با دیپلویِ
فرانت به‌روز می‌شود، بی‌آن‌که نسخه‌ی تازه‌ی اپ لازم باشد.
> ⚠️ APIِ Poolakey از README خودِ کتابخانه است و خرید روی گوشی هنوز آزموده نشده.
## پیش از build — سه چیز از پیشخانِ بازار (سنیور / حسابِ شرکت)
| چه | کجا گذاشته می‌شود | وضعیت |
|---|---|---|
| اسمِ پکیج | `applicationId` در `app/build.gradle.kts` | `com.tadrisino.app` حدس است؛ تأیید نشده |
| کلیدِ RSAِ عمومیِ اپ | `bazaarRsaKey` در فایلِ تنظیماتِ بیرون از ریپو (پایین) | ندارد؛ بدونِ آن build نوعِ release نمی‌شود |
| SKUِ هر بسته (محصولِ **مصرف‌شدنی**) | پنلِ ادمینِ بک‌اند: `/admin/subscription/plan/` ← «Bazaar sku» | هیچ‌کدام تعریف نشده |
قیمتِ هر محصول در پیشخانِ بازار باید با قیمتِ همان بسته در ادمین یکی باشد؛ سرور مبلغ را از
بازار نمی‌خواند.
## تنظیماتِ بیرون از ریپو
keystore و کلیدِ RSA هرگز داخلِ ریپو نمی‌آیند. یک فایل با دسترسیِ ۶۰۰ بسازید: `~/.tadrisino/android.properties`
(یا مسیرِ دلخواه در `TADRISINO_ANDROID_CONFIG`):
```
storeFile=/مسیر/کامل/tadrisino-release.jks
storePassword=...
keyAlias=...
keyPassword=...
bazaarRsaKey=<کلیدِ RSA از پیشخانِ بازار، یک خط>
```
| مقدار | از کجا | اگر نبود |
|---|---|---|
| `storeFile` تا `keyPassword` | keystoreِ شرکت. **همان فایلِ APKِ فعلی را امضا کرده؛ نسخه‌ی تازه با کلیدِ دیگر روی بازار آپدیت نمی‌شود.** دو نسخه‌ی پشتیبان در دو جای جدا | build نوعِ release با پیامِ روشن می‌ایستد |
| `bazaarRsaKey` | پیشخان ← اپ ← پرداخت درون‌برنامه‌ای | build نوعِ release می‌ایستد (نه اپِ بی‌خرید) |
## build
نیازها (یک بار): JDK 17 (`brew install openjdk@17`) و Android SDK با `platforms;android-34` و `build-tools;34.0.0` در `~/Library/Android/sdk`.
```bash
cd android && ./build-apk.sh
```
خروجی `android/build-out/Tadrisino-<نسخه>-<versionCode>.apk` است. پیش از هر انتشار `versionCode` را در `app/build.gradle.kts`
بالا ببرید (بازار نسخه‌ی با شماره‌ی تکراری را نمی‌پذیرد). اسکریپت امضا را می‌سنجد و اثرانگشتِ گواهی را چاپ می‌کند؛ باید با APKِ قبلی یکی باشد.
APKِ آزمایشی بی‌نیاز از کلید: `./gradlew assembleDebug`.
## جریانِ خرید (برای عیب‌یابی)
```
فرانت POST /api/subscription/purchase {planId, paymentMethod:"bazaar"} → orderId, bazaarSku
فرانت TadrisinoAndroid.bazaarPurchase(sku, orderId)
اپ Poolakey.purchaseProduct(sku, payload=orderId) → purchaseToken
اپ رویدادِ «tadrisino:bazaar» {orderId, purchaseToken}
فرانت POST /api/payment/bazaar/verify {orderId, purchaseToken} ← سرور از بازار می‌پرسد
فرانت TadrisinoAndroid.bazaarConsume(token) ← تا همان بسته دوباره خریدنی باشد
```
اگر پول رفت ولی تأییدِ سرور نرسید، کاربر دوباره «پرداخت» می‌زند: فرانت همان سفارش را می‌فرستد
و اپ توکنِ ماندهٔ همان سفارش را از `getPurchasedProducts` پیدا می‌کند.
قرارداد سمتِ وب: `src/lib/bazaar.ts`. سمتِ سرور: `payment/bazaar.py` و `docs/operations.md`ِ بک‌اند.