133 lines
2.8 KiB
Markdown
133 lines
2.8 KiB
Markdown
|
|
# WebView Bridge Contract
|
||
|
|
|
||
|
|
This document defines the Android WebView bridge contract used by tenant builds like `tis`.
|
||
|
|
|
||
|
|
## Scope
|
||
|
|
|
||
|
|
- The bridge is enabled per tenant via `environment.enableNativeBridge`.
|
||
|
|
- Current tenant config:
|
||
|
|
- `src/environments/environment.tis.ts` -> `enableNativeBridge: true`
|
||
|
|
- other environments -> `false`
|
||
|
|
|
||
|
|
## JavaScript host objects
|
||
|
|
|
||
|
|
The web app checks bridge methods on:
|
||
|
|
|
||
|
|
1. `window.AndroidBridge`
|
||
|
|
2. `window.Android` (fallback)
|
||
|
|
|
||
|
|
Your Android app can expose either one.
|
||
|
|
|
||
|
|
## Required native methods
|
||
|
|
|
||
|
|
Expose these synchronous methods through `@JavascriptInterface`:
|
||
|
|
|
||
|
|
- `pay(payloadJson: String): String`
|
||
|
|
- `print(payloadJson: String): String`
|
||
|
|
|
||
|
|
Both methods must return a JSON string.
|
||
|
|
|
||
|
|
## Return JSON format
|
||
|
|
|
||
|
|
Success:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"success": true,
|
||
|
|
"data": {}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Failure:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"success": false,
|
||
|
|
"error": "Reason message"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
If a non-JSON string is returned, the app treats it as success with raw data.
|
||
|
|
|
||
|
|
## Payload schemas
|
||
|
|
|
||
|
|
### pay(payload)
|
||
|
|
|
||
|
|
Called before invoice submit when terminal amount is greater than zero.
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"amount": 1200000,
|
||
|
|
"totalAmount": 3500000,
|
||
|
|
"invoiceDate": "2026-04-27T10:30:00.000Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Fields:
|
||
|
|
|
||
|
|
- `amount` number: terminal payment amount.
|
||
|
|
- `totalAmount` number: full invoice total.
|
||
|
|
- `invoiceDate` string: ISO date-time.
|
||
|
|
|
||
|
|
### print(payload)
|
||
|
|
|
||
|
|
Called after successful invoice creation (and from invoice view print action).
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"invoiceId": "a7e1f2...",
|
||
|
|
"code": "INV-1745730090000"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Fields are optional, but should be used when available.
|
||
|
|
|
||
|
|
## Web behavior summary
|
||
|
|
|
||
|
|
- On native pay failure:
|
||
|
|
- Invoice submit is stopped.
|
||
|
|
- User sees warning toast.
|
||
|
|
- On native print failure or missing bridge:
|
||
|
|
- In invoice page, app falls back to `window.print()`.
|
||
|
|
- In POS checkout flow, print failure does not block successful submit.
|
||
|
|
|
||
|
|
## Android integration example (Kotlin)
|
||
|
|
|
||
|
|
```kotlin
|
||
|
|
class AndroidBridge(
|
||
|
|
private val context: Context
|
||
|
|
) {
|
||
|
|
@JavascriptInterface
|
||
|
|
fun pay(payloadJson: String): String {
|
||
|
|
return try {
|
||
|
|
// TODO: parse payloadJson and run POS payment SDK synchronously
|
||
|
|
"""{"success":true,"data":{"txId":"12345"}}"""
|
||
|
|
} catch (e: Exception) {
|
||
|
|
"""{"success":false,"error":"${e.message ?: "Payment failed"}"}"""
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@JavascriptInterface
|
||
|
|
fun print(payloadJson: String): String {
|
||
|
|
return try {
|
||
|
|
// TODO: parse payloadJson and print with printer SDK
|
||
|
|
"""{"success":true}"""
|
||
|
|
} catch (e: Exception) {
|
||
|
|
"""{"success":false,"error":"${e.message ?: "Print failed"}"}"""
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Attach to WebView:
|
||
|
|
|
||
|
|
```kotlin
|
||
|
|
webView.settings.javaScriptEnabled = true
|
||
|
|
webView.addJavascriptInterface(AndroidBridge(this), "AndroidBridge")
|
||
|
|
```
|
||
|
|
|
||
|
|
## Notes
|
||
|
|
|
||
|
|
- For production, use HTTPS for web app + API to avoid mixed-content issues.
|
||
|
|
- Keep method names and payload keys exactly as specified.
|