react-native-mesmart 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +364 -103
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,178 +1,439 @@
|
|
|
1
1
|
# react-native-mesmart
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Módulos nativos (Android) para POS usadas pela Beerpass: leitura de cartão RFID (Mifare), impressão térmica e SDKs de pagamento.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
| Módulo | Para que serve | Onde roda |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| [`Plugpag`](#plugpag-pagbank) | Pagamento PagBank (PlugPag) | POS PagBank |
|
|
8
|
+
| [`Stone`](#stone) | Pagamento Stone (SDK de providers) | POS Stone |
|
|
9
|
+
| [`Paystore`](#paystore) | Pagamento Paystore | POS com Paystore |
|
|
10
|
+
| [`Sunmi`](#sunmi-p2-b--p2-a11) | RFID e impressão | Sunmi P2-B, P2-A11 |
|
|
11
|
+
| [`Tectoy`](#tectoy-t8) | RFID e impressão | Tectoy T8 |
|
|
12
|
+
| [`Gertec`](#gertec-gpos780--gpos780s) | RFID e impressão | Gertec GPOS780, GPOS780S |
|
|
13
|
+
| [`Pax`](#pax-a910) | RFID e impressão | Pax A910 |
|
|
14
|
+
|
|
15
|
+
Referências dos SDKs: [PlugPag](https://developer.pagbank.com.br/v1.0/reference/smart-pos-introducao) · [Stone](https://sdkandroid.stone.com.br/reference/bem-vindo-sdk-android) · [Paystore](http://177.69.97.18:6655/)
|
|
16
|
+
|
|
17
|
+
> Só Android. Importar no iOS lança `IOS_ERROR`.
|
|
18
|
+
|
|
19
|
+
## Sumário
|
|
20
|
+
|
|
21
|
+
- [Compatibilidade](#compatibilidade)
|
|
22
|
+
- [Instalação](#instalação)
|
|
23
|
+
- [Configuração do app Android](#configuração-do-app-android)
|
|
24
|
+
- [Qual APK para qual POS](#qual-apk-para-qual-pos)
|
|
25
|
+
- [API](#api)
|
|
26
|
+
- [Eventos](#eventos)
|
|
27
|
+
- [Formato do RFID](#formato-do-rfid)
|
|
28
|
+
- [App de exemplo](#app-de-exemplo)
|
|
29
|
+
- [Migrando da 2.x para a 3.x](#migrando-da-2x-para-a-3x)
|
|
30
|
+
- [Publicando uma versão](#publicando-uma-versão)
|
|
31
|
+
|
|
32
|
+
## Compatibilidade
|
|
33
|
+
|
|
34
|
+
| react-native-mesmart | SDK Stone | React Native | Toolchain Android |
|
|
35
|
+
|---|---|---|---|
|
|
36
|
+
| **3.x** | 4.20.16 | **≥ 0.80** (arquitetura antiga, `newArchEnabled=false`) | AGP ≥ 8.6, Gradle 8.14, compileSdk 35, JDK 17, Kotlin ≥ 2.1, minSdk 24 |
|
|
37
|
+
| 2.x | 4.12.0 | 0.72 | AGP 7.4, compileSdk 33, JDK 11 |
|
|
38
|
+
|
|
39
|
+
A 3.x exige RN ≥ 0.80 porque o SDK Stone 4.20 traz dependências compiladas em Kotlin 2.2, que só um compilador Kotlin 2.1 consegue ler. O RN 0.80 é o primeiro com Kotlin 2.1.
|
|
8
40
|
|
|
9
41
|
## Instalação
|
|
10
42
|
|
|
11
43
|
```sh
|
|
12
|
-
|
|
44
|
+
yarn add react-native-mesmart
|
|
13
45
|
```
|
|
14
46
|
|
|
15
|
-
|
|
47
|
+
ou
|
|
16
48
|
|
|
17
49
|
```sh
|
|
18
|
-
|
|
50
|
+
npm install react-native-mesmart
|
|
19
51
|
```
|
|
20
52
|
|
|
21
|
-
##
|
|
22
|
-
|
|
23
|
-
Adicione a seguinte permissão no AndroidManifest do seu app
|
|
53
|
+
## Configuração do app Android
|
|
24
54
|
|
|
25
|
-
|
|
26
|
-
<uses-permission android:name="com.sunmi.perm.CONTACTLESS_CARD" />
|
|
27
|
-
```
|
|
55
|
+
O [app de exemplo](example/android) está configurado assim e serve de referência completa.
|
|
28
56
|
|
|
29
|
-
|
|
57
|
+
### 1. Repositórios Maven
|
|
30
58
|
|
|
31
|
-
|
|
59
|
+
O SDK da Stone e o SDK da Sunmi vêm do repositório privado da Stone no packagecloud. O token é fornecido pela Stone. Coloque-o no `android/local.properties` do app, que não vai para o git:
|
|
32
60
|
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
<uses-permission android:name="com.pax.permission.PRINTER" />
|
|
61
|
+
```properties
|
|
62
|
+
packageCloudReadToken=SEU_TOKEN
|
|
36
63
|
```
|
|
37
64
|
|
|
38
|
-
|
|
65
|
+
Também é aceito pela variável de ambiente `PACKAGECLOUD_READ_TOKEN`, útil em CI.
|
|
39
66
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
67
|
+
`android/build.gradle`:
|
|
68
|
+
|
|
69
|
+
```gradle
|
|
70
|
+
buildscript {
|
|
71
|
+
ext {
|
|
72
|
+
// ...
|
|
73
|
+
compileSdkVersion = 35
|
|
74
|
+
stone_sdk_version = "4.20.16" // lido pela lib e pelos flavors do app
|
|
75
|
+
|
|
76
|
+
localProp = new Properties()
|
|
77
|
+
localProp.load(new FileInputStream(rootProject.file('local.properties')))
|
|
78
|
+
stoneToken = System.env.PACKAGECLOUD_READ_TOKEN ?: (localProp["packageCloudReadToken"] ?: "")
|
|
48
79
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
allprojects {
|
|
83
|
+
repositories {
|
|
84
|
+
mavenCentral()
|
|
85
|
+
// O GitHub responde 504 para artefatos que não existem e o Gradle aborta;
|
|
86
|
+
// por isso este repo fica restrito ao grupo do PlugPag.
|
|
87
|
+
maven {
|
|
88
|
+
url 'https://github.com/pagseguro/PlugPagServiceWrapper/raw/master'
|
|
89
|
+
content { includeGroupByRegex 'br\\.com\\.uol\\.pagseguro.*' }
|
|
53
90
|
}
|
|
91
|
+
maven { url "https://packagecloud.io/priv/${stoneToken}/stone/pos-android/maven2" }
|
|
92
|
+
google()
|
|
54
93
|
}
|
|
55
94
|
}
|
|
56
95
|
```
|
|
57
96
|
|
|
58
|
-
|
|
97
|
+
### 2. Um flavor por POS (HAL da Stone)
|
|
59
98
|
|
|
60
|
-
|
|
99
|
+
Cada fabricante tem um HAL (driver) próprio no SDK da Stone. Na 4.20, os HALs da Sunmi e da Tectoy usam versões incompatíveis da mesma biblioteca e **não cabem no mesmo APK**. A lib não embute nenhum HAL: o app escolhe por product flavor, que é o modelo que a [documentação da Stone](https://sdkandroid.stone.com.br/reference/processo-de-build-de-aplicação.md) adota.
|
|
61
100
|
|
|
62
|
-
|
|
101
|
+
`android/app/build.gradle`:
|
|
63
102
|
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
|
|
103
|
+
```gradle
|
|
104
|
+
react {
|
|
105
|
+
// Com flavors, as variantes debug passam a ter o nome do flavor.
|
|
106
|
+
debuggableVariants = ["pagbankDebug", "sunmiDebug", "tectoyDebug"]
|
|
107
|
+
}
|
|
67
108
|
|
|
68
|
-
|
|
109
|
+
android {
|
|
110
|
+
defaultConfig {
|
|
111
|
+
ndk { abiFilters "armeabi-v7a" } // todas as POS suportadas são 32 bits
|
|
112
|
+
}
|
|
69
113
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
114
|
+
flavorDimensions = ["pos"]
|
|
115
|
+
productFlavors {
|
|
116
|
+
pagbank {} // PagBank: sem HAL da Stone
|
|
117
|
+
sunmi {} // Stone em Sunmi P2-B / P2-A11
|
|
118
|
+
tectoy {} // Stone em Tectoy T8
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
compileOptions {
|
|
122
|
+
coreLibraryDesugaringEnabled true // exigido pelo SDK Stone 4.20
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
packagingOptions {
|
|
126
|
+
jniLibs { useLegacyPackaging true }
|
|
77
127
|
}
|
|
78
128
|
}
|
|
79
|
-
```
|
|
80
129
|
|
|
81
|
-
|
|
130
|
+
dependencies {
|
|
131
|
+
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
|
|
82
132
|
|
|
83
|
-
|
|
133
|
+
sunmiImplementation("br.com.stone:stone-sdk-posandroid-sunmi:${rootProject.ext.stone_sdk_version}")
|
|
134
|
+
tectoyImplementation("br.com.stone:stone-sdk-posandroid-tectoy:${rootProject.ext.stone_sdk_version}")
|
|
84
135
|
|
|
136
|
+
// AARs de fabricante que a lib usa mas não distribui (ver passo 4)
|
|
137
|
+
implementation fileTree(dir: 'libs', include: ['*.aar'])
|
|
138
|
+
}
|
|
85
139
|
```
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
140
|
+
|
|
141
|
+
Build de cada APK: `./gradlew :app:assembleTectoyRelease`, `:app:assembleSunmiRelease`, `:app:assemblePagbankRelease`.
|
|
142
|
+
|
|
143
|
+
### 3. AndroidManifest
|
|
144
|
+
|
|
145
|
+
Uma dependência do SDK Stone declara `allowBackup`; sem o `tools:replace` o merge do manifest falha:
|
|
146
|
+
|
|
147
|
+
```xml
|
|
148
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
149
|
+
xmlns:tools="http://schemas.android.com/tools">
|
|
150
|
+
|
|
151
|
+
<!-- Sunmi: leitor RFID -->
|
|
152
|
+
<uses-permission android:name="com.sunmi.perm.CONTACTLESS_CARD" />
|
|
153
|
+
<!-- PlugPag -->
|
|
154
|
+
<uses-permission android:name="br.com.uol.pagseguro.permission.MANAGE_PAYMENTS" />
|
|
155
|
+
<!-- Pax -->
|
|
156
|
+
<uses-permission android:name="com.pax.permission.PICC" />
|
|
157
|
+
<uses-permission android:name="com.pax.permission.PRINTER" />
|
|
158
|
+
<!-- Paystore -->
|
|
159
|
+
<uses-permission android:name="br.com.phoebus.android.payments.provider.READ_PERMISSION" />
|
|
160
|
+
|
|
91
161
|
<application
|
|
92
|
-
|
|
93
|
-
android:allowBackup
|
|
94
|
-
tools:replace="android:allowBackup"
|
|
95
|
-
>
|
|
162
|
+
android:allowBackup="false"
|
|
163
|
+
tools:replace="android:allowBackup">
|
|
96
164
|
...
|
|
97
165
|
</application>
|
|
98
166
|
</manifest>
|
|
99
167
|
```
|
|
100
168
|
|
|
101
|
-
|
|
169
|
+
Inclua só as permissões dos módulos que o app usa. Stone, Tectoy e Gertec não pedem permissão no app; os HALs trazem as deles.
|
|
170
|
+
|
|
171
|
+
### 4. Arquivos de fabricante no app
|
|
102
172
|
|
|
173
|
+
A lib compila contra esses arquivos, mas quem os empacota é o app. Copie do [`example/android/app`](example/android/app) para os mesmos caminhos no seu app:
|
|
174
|
+
|
|
175
|
+
| Módulo | Arquivo | Destino |
|
|
176
|
+
|---|---|---|
|
|
177
|
+
| Gertec | `android-easy-layer-gpos780-2.1.4-debug.aar`, `libgedi-1.16.21-gpos780-payment-release.aar` | `android/app/libs/` |
|
|
178
|
+
| Paystore | `paystore-api-v2.11.7.31.aar` | `android/app/libs/` |
|
|
179
|
+
| Pax | `libDeviceConfig.so` | `android/app/src/main/jniLibs/armeabi-v7a/` |
|
|
180
|
+
|
|
181
|
+
## Qual APK para qual POS
|
|
182
|
+
|
|
183
|
+
| POS | Adquirente | Flavor | Pagamento | RFID e impressão |
|
|
184
|
+
|---|---|---|---|---|
|
|
185
|
+
| Sunmi P2-B / P2-A11 | Stone | `sunmi` | `Stone` | `Sunmi` |
|
|
186
|
+
| Tectoy T8 | Stone | `tectoy` | `Stone` | `Tectoy` |
|
|
187
|
+
| Gertec GPOS780 / GPOS780S | PagBank | `pagbank` | `Plugpag` | `Gertec` |
|
|
188
|
+
| Sunmi P2-B / P2-A11 | PagBank | `pagbank` | `Plugpag` | `Sunmi` |
|
|
189
|
+
|
|
190
|
+
O SDK de pagamento ativado no app tem que bater com o flavor instalado: o APK `pagbank` não tem HAL da Stone, então `Stone.pay` não funciona nele.
|
|
191
|
+
|
|
192
|
+
## API
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
import { Plugpag, Stone, Paystore, Sunmi, Tectoy, Gertec, Pax } from 'react-native-mesmart';
|
|
103
196
|
```
|
|
104
|
-
buildscript {
|
|
105
|
-
ext {
|
|
106
|
-
...
|
|
107
|
-
localProp = new Properties()
|
|
108
|
-
fileName = 'local.properties'
|
|
109
|
-
localProp.load(new FileInputStream(rootProject.file(fileName)))
|
|
110
|
-
stoneToken = System.env.PACKAGECLOUD_READ_TOKEN != null ? System.env.PACKAGECLOUD_READ_TOKEN : (localProp["packageCloudReadToken"] ?: "")
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
197
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
198
|
+
Todos os métodos retornam `Promise`. Em erro, a promise é rejeitada com a mensagem do SDK. Valores monetários de **Stone e PlugPag são em centavos, como string** (`'500'` = R$ 5,00).
|
|
199
|
+
|
|
200
|
+
`PaymentMethod` = `'debitCard' | 'creditCard' | 'pix' | 'voucher' | 'money' | 'bonus'`. Cada SDK aceita só uma parte deles (ver em cada módulo).
|
|
201
|
+
|
|
202
|
+
### Plugpag (PagBank)
|
|
203
|
+
|
|
204
|
+
Requer o PlugPagService instalado na POS (POS PagBank).
|
|
205
|
+
|
|
206
|
+
| Método | Retorno | Descrição |
|
|
207
|
+
|---|---|---|
|
|
208
|
+
| `init(activationCode)` | `null` | Ativa o terminal com o código de ativação da conta PagBank. |
|
|
209
|
+
| `isActivated()` | `boolean` | Se o `init` já rodou nesta sessão do app. |
|
|
210
|
+
| `pay(value, paymentMethod)` | `PlugpagTransactionResult` | Venda à vista. `value` em centavos. Métodos: `debitCard`, `creditCard`, `voucher`, `pix`. |
|
|
211
|
+
| `voidPayment({ transactionCode, transactionId, printReceipt?, voidType? })` | `PlugpagTransactionResult` | Estorno. `voidType`: `'payment'` (padrão) ou `'qrcode'`/`'pix'`. |
|
|
212
|
+
| `abortPayment()` | `null` | Cancela a transação em andamento. |
|
|
213
|
+
| `resolveEvent(eventData)` | `string` | Traduz um evento de `onPlugpagEventData` em mensagem para o cliente. |
|
|
214
|
+
| `destroy()` | `null` | Desativa o terminal. |
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
import { Plugpag, PlugpagResult } from 'react-native-mesmart';
|
|
218
|
+
|
|
219
|
+
await Plugpag.init('123456');
|
|
220
|
+
const result = await Plugpag.pay('1500', 'creditCard'); // R$ 15,00
|
|
221
|
+
if (result.result === PlugpagResult.RET_OK) {
|
|
222
|
+
// aprovado: guarde result.transactionCode e result.transactionId para estorno
|
|
119
223
|
}
|
|
120
224
|
```
|
|
121
225
|
|
|
122
|
-
|
|
226
|
+
O progresso da transação chega pelo evento [`onPlugpagEventData`](#eventos).
|
|
227
|
+
|
|
228
|
+
### Stone
|
|
123
229
|
|
|
124
|
-
|
|
230
|
+
Funciona nas POS Stone (flavors `sunmi` e `tectoy`).
|
|
125
231
|
|
|
126
|
-
|
|
232
|
+
| Método | Retorno | Descrição |
|
|
233
|
+
|---|---|---|
|
|
234
|
+
| `init({ providerId, authorization }, appName)` | `null` | Inicializa o SDK. As chaves são as de QR Code/PIX fornecidas pela Stone (`authorization` inclui o `Bearer`). `appName` é obrigatório. |
|
|
235
|
+
| `isActivated()` | `boolean` | Se o `init` já rodou. |
|
|
236
|
+
| `getStoneCode()` | `string` | Stone Code do usuário ativado na POS. |
|
|
237
|
+
| `pay(value, paymentMethod, isCapture = true)` | `null` | Inicia a venda. `value` em centavos. Métodos: `debitCard`, `creditCard`, `voucher`, `pix`. A resolução da promise **não** é o resultado: ele chega pelo evento [`onStoneEventData`](#eventos). |
|
|
238
|
+
| `abortPayment()` | `boolean` | Aborta a venda em andamento (`false` se não havia nenhuma). |
|
|
239
|
+
| `printVia(transaction, 'MERCHANT' \| 'CLIENT')` | `null` | Imprime a via padrão da Stone. |
|
|
240
|
+
| `captureTransaction(transaction)` | `StoneCaptureResponse` | Captura uma venda feita com `isCapture = false`. |
|
|
241
|
+
| `cancelTransaction(transaction)` | `StoneCancelResponse` | Cancela (estorna) uma venda. |
|
|
127
242
|
|
|
243
|
+
```ts
|
|
244
|
+
await Stone.init({ providerId, authorization }, 'BeerPass');
|
|
245
|
+
await Stone.pay('1500', 'pix');
|
|
246
|
+
// acompanhe onStoneEventData: onStatusChanged (com qrCode no PIX), onSuccess ou onError
|
|
128
247
|
```
|
|
129
|
-
|
|
248
|
+
|
|
249
|
+
`transaction` é o `StoneTransaction` recebido no evento `onSuccess`.
|
|
250
|
+
|
|
251
|
+
### Paystore
|
|
252
|
+
|
|
253
|
+
| Método | Retorno | Descrição |
|
|
254
|
+
|---|---|---|
|
|
255
|
+
| `init()` | `null` | Inicializa o client da Paystore. |
|
|
256
|
+
| `isActivated()` | `boolean` | Se o `init` já rodou. |
|
|
257
|
+
| `pay(value, transactionId, showReceipt, paymentMethods, installments)` | `void` | Inicia o pagamento. `value` em reais com ponto (`'15.00'`). `paymentMethods` aceita `creditCard`, `debitCard` e `voucher`. `installments = 0` é à vista. |
|
|
258
|
+
|
|
259
|
+
O pagamento é confirmado automaticamente e o resultado (`PaystorePaymentResult`) chega pelo evento [`onPayment`](#eventos). A promise de `pay` resolve assim que o fluxo começa.
|
|
260
|
+
|
|
261
|
+
### Sunmi (P2-B / P2-A11)
|
|
262
|
+
|
|
263
|
+
Usa o SDK da própria Sunmi (paylib e serviço de impressora), não o da Stone. Funciona em qualquer flavor.
|
|
264
|
+
|
|
265
|
+
| Método | Retorno | Descrição |
|
|
266
|
+
|---|---|---|
|
|
267
|
+
| `scanRfid()` | `string` | Lê um cartão Mifare. Ver [formato do RFID](#formato-do-rfid). |
|
|
268
|
+
| `cancelScan()` | `null` | Cancela a leitura. |
|
|
269
|
+
| `setPrinterAlign('left' \| 'center' \| 'right')` | `null` | Alinhamento das próximas impressões. |
|
|
270
|
+
| `printText(text, fontSize = 24, isBold = false, isUnderline = false)` | `null` | Imprime texto. A quebra de linha vem do `\n` no texto. Com tamanho 24 cabem 32 colunas. |
|
|
271
|
+
| `printEmptyLine()` | `null` | Avança uma linha. |
|
|
272
|
+
| `printBitmap(base64, width = 200, height = 200)` | `null` | Imprime imagem PNG/JPEG em base64 (por exemplo, QR Code). |
|
|
273
|
+
| `printBpLogo()` | `null` | Imprime o logo da Beerpass. |
|
|
274
|
+
| `printClientReceipt(date, rechargeType, name, document, paymentMethod, rfid, rechargeValue)` | `void` | Comprovante de recarga pronto. |
|
|
275
|
+
|
|
276
|
+
Cada chamada imprime na hora.
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
await Sunmi.setPrinterAlign('center');
|
|
280
|
+
await Sunmi.printBpLogo();
|
|
281
|
+
await Sunmi.printText('Cupom de Consumo\n', 28, true);
|
|
282
|
+
await Sunmi.setPrinterAlign('left');
|
|
283
|
+
await Sunmi.printText('================================\n', 24, true);
|
|
284
|
+
await Sunmi.printText('Valor: R$ 18,00\n');
|
|
285
|
+
await Sunmi.printEmptyLine();
|
|
130
286
|
```
|
|
131
287
|
|
|
132
|
-
|
|
288
|
+
### Tectoy (T8)
|
|
289
|
+
|
|
290
|
+
Usa o SDK da Stone com o HAL da Tectoy, então precisa do flavor `tectoy`. Inicializa o SDK Stone sozinho, sem depender do `Stone.init`.
|
|
133
291
|
|
|
292
|
+
| Método | Retorno | Descrição |
|
|
293
|
+
|---|---|---|
|
|
294
|
+
| `scanRfid()` | `string` | Lê um cartão Mifare (espera até 30 s). Ver [formato do RFID](#formato-do-rfid). |
|
|
295
|
+
| `cancelScan()` | `true` | Cancela a leitura; a promise do `scanRfid` é rejeitada. |
|
|
296
|
+
| `setPrinterAlign`, `printText`, `printEmptyLine`, `printBitmap`, `printBpLogo` | `null` | Mesmas assinaturas da [`Sunmi`](#sunmi-p2-b--p2-a11), mas **acumulam** o cupom em vez de imprimir na hora. |
|
|
297
|
+
| `commitPrint()` | `true` | **Imprime** tudo que foi acumulado, num único job. Obrigatório no fim de cada cupom. |
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
await Tectoy.setPrinterAlign('center');
|
|
301
|
+
await Tectoy.printBpLogo();
|
|
302
|
+
await Tectoy.printText('Cupom de Consumo\n', 28, true);
|
|
303
|
+
await Tectoy.setPrinterAlign('left');
|
|
304
|
+
await Tectoy.printText('================================\n', 24, true);
|
|
305
|
+
await Tectoy.printText('Valor: R$ 18,00\n');
|
|
306
|
+
await Tectoy.commitPrint(); // sem isso nada sai
|
|
134
307
|
```
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
308
|
+
|
|
309
|
+
Por que é diferente da Sunmi:
|
|
310
|
+
|
|
311
|
+
- **Cupom num job só:** o HAL da Tectoy avança o papel de corte ao fim de cada impressão. Imprimir linha a linha deixaria um espaço de corte entre as linhas.
|
|
312
|
+
- **Sem HTML:** o firmware Stone da T8 bloqueia o processo da WebView, então impressão via HTML (como a da Gertec) não funciona. O texto é desenhado em bitmap com a mesma métrica da Sunmi (32 colunas no tamanho 24), e os templates da P2 servem sem ajuste, bastando chamar `commitPrint()` no final.
|
|
313
|
+
|
|
314
|
+
### Gertec (GPOS780 / GPOS780S)
|
|
315
|
+
|
|
316
|
+
Usa o SDK da Gertec (easylayer e GEDI). Precisa das AARs da Gertec no app ([passo 4](#4-arquivos-de-fabricante-no-app)).
|
|
317
|
+
|
|
318
|
+
| Método | Retorno | Descrição |
|
|
319
|
+
|---|---|---|
|
|
320
|
+
| `scanRfid()` | `string` | Lê um cartão Mifare (espera até 30 s). |
|
|
321
|
+
| `cancelScan()` | `true` | Cancela a leitura. |
|
|
322
|
+
| `printHtml(html)` | `true` | Imprime um HTML (largura útil de 384 px). |
|
|
323
|
+
| `scrollPrinterPaper(lines)` | `true` | Avança o papel. |
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
await Gertec.printHtml(`<html><body style="width:384px">...</body></html>`);
|
|
327
|
+
await Gertec.scrollPrinterPaper(60);
|
|
139
328
|
```
|
|
140
329
|
|
|
141
|
-
|
|
330
|
+
### Pax (A910)
|
|
331
|
+
|
|
332
|
+
Usa a NeptuneLite (já inclusa na lib). Precisa do `libDeviceConfig.so` no app ([passo 4](#4-arquivos-de-fabricante-no-app)). A lib só inicializa leitor e impressora quando o modelo é **A910**.
|
|
333
|
+
|
|
334
|
+
| Método | Retorno | Descrição |
|
|
335
|
+
|---|---|---|
|
|
336
|
+
| `scanRfid()` | `string` | Lê um cartão Mifare. |
|
|
337
|
+
| `cancelScan()` | `null` | Cancela a leitura. |
|
|
338
|
+
| `printerInit()` | `null` | Começa um cupom. |
|
|
339
|
+
| `addText(text, fontSize = 24)` | `null` | Adiciona texto ao cupom. |
|
|
340
|
+
| `addBpLogo()` | `null` | Adiciona o logo da Beerpass. |
|
|
341
|
+
| `printerStart()` | `null` | Imprime o cupom montado. |
|
|
342
|
+
| `printClientReceipt(date, rechargeType, name, document, paymentMethod, rfid, rechargeValue)` | `void` | Comprovante de recarga pronto. |
|
|
343
|
+
|
|
344
|
+
## Eventos
|
|
142
345
|
|
|
143
|
-
|
|
346
|
+
Os eventos chegam pelo `DeviceEventEmitter`:
|
|
347
|
+
|
|
348
|
+
| Evento | Payload | Quando |
|
|
349
|
+
|---|---|---|
|
|
350
|
+
| `onPlugpagEventData` | `PlugpagEventData` (`eventCode`, `customMessage`) | Etapas da transação PlugPag (aguardando cartão, senha, aprovada…). |
|
|
351
|
+
| `onStoneEventData` | `StoneEventData` (`type`: `onStatusChanged`, `onSuccess` ou `onError`) | Progresso e resultado de `Stone.pay`. No PIX, `onStatusChanged` traz o `qrCode` em base64. |
|
|
352
|
+
| `onPayment` | `PaystorePaymentResult` | Resultado de `Paystore.pay`, já confirmado. |
|
|
144
353
|
|
|
145
354
|
```ts
|
|
146
355
|
import { DeviceEventEmitter } from 'react-native';
|
|
147
356
|
import {
|
|
357
|
+
Plugpag,
|
|
148
358
|
type PlugpagEventData,
|
|
149
359
|
type StoneEventData,
|
|
360
|
+
type PaystorePaymentResult,
|
|
150
361
|
} from 'react-native-mesmart';
|
|
151
362
|
|
|
152
363
|
useEffect(() => {
|
|
153
|
-
const
|
|
154
|
-
'onPlugpagEventData',
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
'
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
return () => {
|
|
168
|
-
plugpagSubscribe.remove();
|
|
169
|
-
stoneSubscribe.remove();
|
|
170
|
-
};
|
|
364
|
+
const subs = [
|
|
365
|
+
DeviceEventEmitter.addListener('onPlugpagEventData', async (event: PlugpagEventData) => {
|
|
366
|
+
const message = await Plugpag.resolveEvent(event); // texto para mostrar ao cliente
|
|
367
|
+
}),
|
|
368
|
+
DeviceEventEmitter.addListener('onStoneEventData', (event: StoneEventData) => {
|
|
369
|
+
if (event.type === 'onSuccess') { /* event.transaction */ }
|
|
370
|
+
if (event.type === 'onError') { /* event.listOfErrors */ }
|
|
371
|
+
}),
|
|
372
|
+
DeviceEventEmitter.addListener('onPayment', (payment: PaystorePaymentResult) => {}),
|
|
373
|
+
];
|
|
374
|
+
return () => subs.forEach((s) => s.remove());
|
|
171
375
|
}, []);
|
|
172
376
|
```
|
|
173
377
|
|
|
378
|
+
Todos os tipos (`PlugpagTransactionResult`, `StoneTransaction`, `StoneEventData`, `PaystorePaymentResult`, `SunmiAPI`, `TectoyAPI`…) são exportados pelo pacote.
|
|
379
|
+
|
|
380
|
+
## Formato do RFID
|
|
381
|
+
|
|
382
|
+
Todos os módulos devolvem o mesmo formato: os bytes do UID do cartão em ordem invertida, convertidos para decimal e completados com zeros à esquerda até 10 dígitos (ex.: `1839402837`). Assim, o mesmo cartão tem o mesmo número em qualquer POS.
|
|
383
|
+
|
|
384
|
+
## App de exemplo
|
|
385
|
+
|
|
386
|
+
O [`example/`](example) tem uma tela por módulo (PLUGPAG, STONE, SUNMI, GERTEC e TECTOY) para testar na POS.
|
|
387
|
+
|
|
388
|
+
1. `yarn` na raiz do repositório.
|
|
389
|
+
2. Crie `example/android/local.properties` com `sdk.dir` e `packageCloudReadToken`.
|
|
390
|
+
3. Build com **JDK 17** e o flavor da POS:
|
|
391
|
+
|
|
392
|
+
```sh
|
|
393
|
+
cd example/android && ./gradlew :app:assembleTectoyDebug
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
O APK sai em `example/android/app/build/outputs/apk/tectoy/debug/`.
|
|
397
|
+
|
|
398
|
+
4. Metro e instalação:
|
|
399
|
+
|
|
400
|
+
```sh
|
|
401
|
+
cd example && yarn start
|
|
402
|
+
adb install -r android/app/build/outputs/apk/tectoy/debug/app-tectoy-debug.apk
|
|
403
|
+
adb reverse tcp:8081 tcp:8081
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
Se a POS reconectar no USB, o `adb reverse` se perde e precisa ser refeito.
|
|
407
|
+
|
|
408
|
+
## Migrando da 2.x para a 3.x
|
|
409
|
+
|
|
410
|
+
1. Atualize o app para **RN ≥ 0.80**, com AGP ≥ 8.6, Gradle 8.14, compileSdk 35 e JDK 17. Mantenha `newArchEnabled=false`.
|
|
411
|
+
2. Crie os **flavors por POS** e mova o HAL da Stone para eles ([passo 2](#2-um-flavor-por-pos-hal-da-stone)). Defina `stone_sdk_version = "4.20.16"`.
|
|
412
|
+
3. Ative o **core library desugaring** (`desugar_jdk_libs` 2.1.5).
|
|
413
|
+
4. Adicione `tools:replace="android:allowBackup"` no manifest.
|
|
414
|
+
5. Restrinja o repositório do PlugPag no GitHub com o `content { includeGroupByRegex ... }`.
|
|
415
|
+
6. O SDK da Sunmi agora vem da própria lib: não dependa mais do HAL Sunmi da Stone para ter `Sunmi` em APKs PagBank.
|
|
416
|
+
7. Nas Tectoy T8, imprima com os templates da P2 + `Tectoy.commitPrint()`.
|
|
417
|
+
|
|
418
|
+
## Publicando uma versão
|
|
419
|
+
|
|
420
|
+
Para mantenedores. O bump de versão é feito pelo `release-it`, nunca à mão.
|
|
421
|
+
|
|
422
|
+
1. Faça o merge na `main`.
|
|
423
|
+
2. Commit, tag e release no GitHub (passe a versão explícita: sem ela, o `release-it` calcula pelos commits):
|
|
424
|
+
|
|
425
|
+
```sh
|
|
426
|
+
GITHUB_TOKEN=$(gh auth token) yarn release-it X.Y.Z --no-npm.publish
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
`--npm.publish=false` **não** desliga a publicação; use `--no-npm.publish`.
|
|
430
|
+
|
|
431
|
+
3. Publique no npm. A conta exige 2FA por chave de segurança/Touch ID, e o CLI abre o navegador para confirmar:
|
|
432
|
+
|
|
433
|
+
```sh
|
|
434
|
+
npm publish
|
|
435
|
+
```
|
|
436
|
+
|
|
174
437
|
## License
|
|
175
438
|
|
|
176
439
|
MIT
|
|
177
|
-
|
|
178
|
-
---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-mesmart",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Native methods for integrating with Sunmi P2-B/P2-A11 POS, Pax A910/A920, Pagbank's Plugpag payment SDK, Stone's payment SDK, and Paystore's payment SDK.",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|