- ZarinpalService (request/verify) + /api/coins/pay/request (JWT) and /api/coins/pay/callback (verify → credit via ProfileService.BuyCoins → redirect back with ?pay=success); merchant id from config (sandbox default) - Client buyCoins (live) returns the StartPay redirect URL; BuyCoinsScreen redirects; page.tsx handles the ?pay return (notify + refresh) - Verified: sandbox request returns a real StartPay URL - Documented Cafe Bazaar (Poolakey) / Myket IAB as the required store payment path Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3.4 KiB
برگ وسط — Android (Capacitor) build
The app is packaged with Capacitor for Cafe Bazaar / Myket.
Layout
next.config.ts→output: "export"(static site inout/)capacitor.config.ts→ appIdcom.bargevasat.app, appName «برگ وسط», webDiroutandroid/→ generated native project (committed; build outputs are git-ignored)- Hardware back button handled by
src/components/CapacitorBack.tsx(@capacitor/app)
Build the web + sync native
npm run cap:sync # next build (export) + cap sync android
Build the APK
npm run android:apk # → android/app/build/outputs/apk/debug/app-debug.apk
# or open in Android Studio:
npm run android:open
Point the app at the live server at build time:
NEXT_PUBLIC_USE_SERVER=1 NEXT_PUBLIC_SERVER_URL=https://api.example.com npm run cap:sync
⚠️ Maven mirror (Iran) — VERIFIED WORKING
Gradle pulls the Android Gradle Plugin from dl.google.com + Maven Central,
blocked in Iran. The Myket mirror proxies both — at the root (no /maven2):
https://maven.myket.ir
Copy android/gradle-mirror.init.gradle.example → android/gradle-mirror.init.gradle,
then build with the init script. (The gradlew.bat wrapper has a CLASSPATH quirk on
this setup, so invoke the wrapper jar with java directly):
cd android
java -classpath gradle\wrapper\gradle-wrapper.jar org.gradle.wrapper.GradleWrapperMain \
assembleDebug --init-script gradle-mirror.init.gradle --no-daemon
# → app/build/outputs/apk/debug/app-debug.apk (≈4.5 MB)
The init script also pins build-tools 36.0.0 and Java 17 compatibility, which are the versions installed here (Capacitor 8 defaults to build-tools 35 / JDK 21). On a CI box with JDK 21 + build-tools 35 you can drop those overrides.
For Nexus instead of Myket directly: create a maven2 (proxy) repo with Remote storage URL
https://maven.myket.ir, add it to a maven2 (group), and pointMIRRORat the group URL.
💳 Payments — ZarinPal (web) vs store billing (Android)
- Web / PWA: buying coins uses ZarinPal (sandbox now). Flow:
POST /api/coins/pay/request→ redirect toStartPay→ ZarinPal →GET /api/coins/pay/callback(server verifies + credits) → back to the app with?pay=success. Merchant id is config-driven (Zarinpal:MerchantId, swap in the admin panel / appsettings;Sandbox: true). - Cafe Bazaar / Myket (APK): app stores in Iran require their own
in-app billing — do NOT use ZarinPal inside the store build. Use:
- Cafe Bazaar: Poolakey (
ir.cafebazaar.poolakey) — define in-app products in the Bazaar panel. - Myket: Myket IAB SDK — define products in the Myket panel.
Wire a Capacitor plugin that detects the store build and routes
buyCoinsto the store SDK; verify the purchase token on the server, then credit coins via the sameProfileService.BuyCoins. (TODO — needs store accounts + product SKUs.)
- Cafe Bazaar: Poolakey (
Release (Cafe Bazaar / Myket)
- Generate a keystore:
keytool -genkey -v -keystore bargevasat.keystore -alias bargevasat -keyalg RSA -keysize 2048 -validity 10000 - Configure signing in
android/app/build.gradle(releasesigningConfig). gradlew.bat assembleRelease(orbundleReleasefor AAB) → upload to Cafe Bazaar / Myket.- App icon/splash: replace
android/app/src/main/res/**(use@capacitor/assetsto generate).