@upeex/ads-sdk 1.1.23 → 1.1.25
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 +10 -91
- package/dist/AdBanner.d.ts +1 -2
- package/dist/index.js +116 -75
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,97 +1,16 @@
|
|
|
1
1
|
# SDK-apps-React-native
|
|
2
|
-
SDK
|
|
2
|
+
SDK para aplicaçõe React Native rodarem anúncios:
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
# Comando para inciar
|
|
5
|
+
npm i @upeex/ads-sdk
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
### Como importar
|
|
7
8
|
|
|
8
|
-
```
|
|
9
|
-
npm install @upeex/ads-sdk
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
## Como Usar
|
|
13
|
-
|
|
14
|
-
### Importação
|
|
15
|
-
|
|
16
|
-
```javascript
|
|
9
|
+
```js
|
|
17
10
|
import AdBanner from '@upeex/ads-sdk';
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
### 1. Banner Simples (Padrão)
|
|
21
|
-
|
|
22
|
-
Ideal para exibir em listas ou rodapés. O anúncio carrega no tamanho especificado ou padrão.
|
|
23
|
-
|
|
24
|
-
```javascript
|
|
25
|
-
<AdBanner
|
|
26
|
-
client="SEU_ID_CLIENTE"
|
|
27
|
-
slot="SEU_ID_SLOT"
|
|
28
|
-
/>
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### 2. Anúncio Popup (Modal)
|
|
32
|
-
|
|
33
|
-
Exibe um anúncio em tela cheia (modal) sobrepondo o conteúdo.
|
|
34
|
-
**Comportamento:**
|
|
35
|
-
- Abre automaticamente se houver anúncio disponível.
|
|
36
|
-
- **Bloqueio de 5 segundos:** O usuário deve aguardar 5 segundos antes de fechar.
|
|
37
|
-
- **Spinner:** Um indicador de carregamento aparece durante o bloqueio.
|
|
38
|
-
- **Sem Auto-Refresh:** O popup carrega apenas uma vez.
|
|
39
|
-
- **Visual:** Ocupa toda a tela (transparente na StatusBar) e a imagem é redimensionada para 90% da largura.
|
|
40
|
-
|
|
41
|
-
#### ⚠️ Onde Colocar o Popup (Importante!)
|
|
42
|
-
|
|
43
|
-
Para garantir que o popup abra corretamente e não sobreponha outros Modals de forma errada, **coloque o componente no final do seu container principal**, logo antes de fechar a view da tela.
|
|
44
|
-
|
|
45
|
-
**Exemplo Correto:**
|
|
46
|
-
|
|
47
|
-
```javascript
|
|
48
|
-
return (
|
|
49
|
-
<View style={{ flex: 1 }}> {/* Seu Container Principal (View, SafeAreaView, etc) */}
|
|
50
|
-
<Header />
|
|
51
|
-
<Conteudo />
|
|
52
|
-
|
|
53
|
-
{/* Outros Modals do seu App */}
|
|
54
|
-
<Modal visible={isLoading}>...</Modal>
|
|
55
|
-
|
|
56
|
-
{/* ✅ COLOCAR AQUI, NO FINAL: */}
|
|
57
|
-
<AdBanner
|
|
58
|
-
client="SEU_ID_CLIENTE"
|
|
59
|
-
slot="SEU_ID_SLOT"
|
|
60
|
-
typeads="popup"
|
|
61
|
-
/>
|
|
62
|
-
</View>
|
|
63
|
-
);
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
**Evite colocar dentro de:**
|
|
69
|
-
- Componentes que são desmontados condicionalmente (`{show && <AdBanner />}`).
|
|
70
|
-
- Headers ou Footers com `position: absolute` ou `zIndex` restritivo.
|
|
71
|
-
|
|
72
|
-
#### ⚠️ Conflito com Outros Modals (Loading, Alertas)
|
|
73
|
-
|
|
74
|
-
O React Native pode ter problemas ao tentar exibir **dois Modals ao mesmo tempo** (ex: um Loading Spinner e o Anúncio Popup).
|
|
75
|
-
- Se o seu app abre um Modal de "Carregando..." ao entrar na tela, aguarde ele fechar antes de renderizar o anúncio, ou use o anúncio como o próprio loading inicial.
|
|
76
|
-
- O SDK possui `zIndex` alto (9999), mas o sistema operacional (especialmente Android) pode priorizar o último Modal aberto na árvore de componentes.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
### Props Disponíveis
|
|
80
|
-
|
|
81
|
-
| Prop | Tipo | Descrição |
|
|
82
|
-
|Data | --- | --- |
|
|
83
|
-
| `client` | `string` | **Obrigatório**. ID do cliente fornecido pela Upeex. |
|
|
84
|
-
| `slot` | `string` | **Obrigatório**. ID do slot (espaço) do anúncio. |
|
|
85
|
-
| `typeads` | `'banner' \| 'popup'` | Define o formato. Padrão é `'banner'`. |
|
|
86
|
-
| `theme` | `'light' \| 'dark'` | Define o tema (cores de fundo). Padrão `'light'`. |
|
|
87
|
-
| `baseUrl` | `string` | URL base da API (opcional). |
|
|
88
|
-
| `debug` | `boolean` | Ativa logs no console (avisa se o componente foi desmontado erradamente). |
|
|
89
|
-
|
|
90
|
-
## Solução de Problemas
|
|
91
11
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- **Sobreposição**: O popup possui `zIndex: 9999` e `elevation: 11`. Se ainda estiver atrás de algum elemento, verifique se o pai não tem um `zIndex` maior.
|
|
12
|
+
// Carregar anúncio
|
|
13
|
+
<AdBanner
|
|
14
|
+
client="SEU_CLIENTE"
|
|
15
|
+
slot="SEU_SLOT"
|
|
16
|
+
/
|
package/dist/AdBanner.d.ts
CHANGED
|
@@ -8,6 +8,5 @@ type Props = {
|
|
|
8
8
|
style?: object;
|
|
9
9
|
debug?: boolean;
|
|
10
10
|
};
|
|
11
|
-
export default function AdBanner({ client, slot, baseUrl, theme, typeAds, typeads,
|
|
12
|
-
style, debug, }: Props): any;
|
|
11
|
+
export default function AdBanner({ client, slot, baseUrl, theme, typeAds, typeads, style, debug, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
13
12
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import
|
|
3
|
-
import { Platform, Dimensions,
|
|
2
|
+
import { useState, useRef, useEffect } from 'react';
|
|
3
|
+
import { Platform, Dimensions, Animated, StyleSheet, Modal, View, ActivityIndicator, TouchableOpacity, Text, Image, Linking } from 'react-native';
|
|
4
4
|
|
|
5
5
|
async function getSignals() {
|
|
6
6
|
var _a, _b, _c, _d, _e, _f;
|
|
@@ -79,22 +79,41 @@ async function fetchAd({ baseUrl, client, slot, debug = false, typeAds, }) {
|
|
|
79
79
|
return ad;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
// Default fallback ads shown when server returns an error
|
|
83
|
+
const DEFAULT_POPUP_IMAGE = 'https://app.upeex.com.br/files/show/ads_square.jpeg';
|
|
84
|
+
const DEFAULT_BANNER_IMAGE = 'https://app.upeex.com.br/files/show/ads_horizontal.jpg';
|
|
85
|
+
const DEFAULT_CLICK_URL = 'https://upeex.com/';
|
|
86
|
+
const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
|
|
87
|
+
// Workaround for TS2604: JSX element type 'Animated.View' does not have any construct or call signatures.
|
|
88
|
+
const AnimatedView = Animated.View;
|
|
89
|
+
function AdBanner({ client, slot, baseUrl = 'https://app.upeex.com.br/ad', theme = 'light', typeAds, typeads, style = {}, debug = false, }) {
|
|
84
90
|
var _a;
|
|
85
91
|
const [ad, setAd] = useState(null);
|
|
86
92
|
const [error, setError] = useState(null);
|
|
87
93
|
const [modalVisible, setModalVisible] = useState(false);
|
|
94
|
+
const [canClose, setCanClose] = useState(false);
|
|
95
|
+
const progressAnim = useRef(new Animated.Value(0)).current;
|
|
88
96
|
const log = (...args) => {
|
|
89
97
|
if (debug)
|
|
90
98
|
console.log('[UPEEX ADS]', ...args);
|
|
91
99
|
};
|
|
92
100
|
const effectiveTypeAds = (_a = (typeAds || typeads)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
93
101
|
const isPopup = effectiveTypeAds === 'popup';
|
|
94
|
-
//
|
|
95
|
-
const isVisibleRef = React.useRef(false);
|
|
102
|
+
// Start 5-second progress bar when popup becomes visible
|
|
96
103
|
useEffect(() => {
|
|
97
|
-
|
|
104
|
+
if (modalVisible) {
|
|
105
|
+
setCanClose(false);
|
|
106
|
+
progressAnim.setValue(0);
|
|
107
|
+
Animated.timing(progressAnim, {
|
|
108
|
+
toValue: 1,
|
|
109
|
+
duration: 5000,
|
|
110
|
+
useNativeDriver: false,
|
|
111
|
+
}).start(({ finished }) => {
|
|
112
|
+
if (finished) {
|
|
113
|
+
setCanClose(true);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
98
117
|
}, [modalVisible]);
|
|
99
118
|
useEffect(() => {
|
|
100
119
|
let refreshTimer;
|
|
@@ -119,8 +138,7 @@ style = {}, debug = false, }) {
|
|
|
119
138
|
if (isPopup) {
|
|
120
139
|
setModalVisible(true);
|
|
121
140
|
}
|
|
122
|
-
|
|
123
|
-
if (!isPopup && data.refresh && data.refresh > 0) {
|
|
141
|
+
if (data.refresh && data.refresh > 0) {
|
|
124
142
|
log(`Refresh ativo: ${data.refresh}s`);
|
|
125
143
|
refreshTimer = setTimeout(() => {
|
|
126
144
|
log('Refazendo request do anúncio');
|
|
@@ -140,27 +158,41 @@ style = {}, debug = false, }) {
|
|
|
140
158
|
return () => {
|
|
141
159
|
if (refreshTimer)
|
|
142
160
|
clearTimeout(refreshTimer);
|
|
143
|
-
|
|
144
|
-
|
|
161
|
+
};
|
|
162
|
+
}, [client, slot, baseUrl]);
|
|
163
|
+
// ─── FALLBACK: default ad on error ────────────────────────────────────────
|
|
164
|
+
if (error) {
|
|
165
|
+
const fallbackImage = isPopup ? DEFAULT_POPUP_IMAGE : DEFAULT_BANNER_IMAGE;
|
|
166
|
+
const handleFallbackPress = () => {
|
|
167
|
+
if (Platform.OS === 'web') {
|
|
168
|
+
window.open(DEFAULT_CLICK_URL, '_blank');
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
Linking.openURL(DEFAULT_CLICK_URL);
|
|
145
172
|
}
|
|
146
173
|
};
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
174
|
+
if (isPopup) {
|
|
175
|
+
return (jsx(Modal, { transparent: true, animationType: "fade", visible: true, onRequestClose: () => { }, children: jsxs(View, { style: styles.modalBackground, children: [jsx(View, { style: styles.progressBarContainer, children: jsx(AnimatedView, { style: [
|
|
176
|
+
styles.progressBar,
|
|
177
|
+
{
|
|
178
|
+
width: progressAnim.interpolate({
|
|
179
|
+
inputRange: [0, 1],
|
|
180
|
+
outputRange: ['0%', '100%'],
|
|
181
|
+
}),
|
|
182
|
+
backgroundColor: '#fff',
|
|
183
|
+
},
|
|
184
|
+
] }) }), !canClose && (jsx(View, { style: styles.spinnerOverlay, children: jsx(ActivityIndicator, { size: "small", color: "#fff" }) })), canClose && (jsx(TouchableOpacity, { style: styles.closeButton, onPress: () => { }, children: jsx(Text, { style: styles.closeButtonText, children: "X" }) })), jsx(TouchableOpacity, { style: styles.fullScreenTouch, activeOpacity: 1, onPress: handleFallbackPress, children: jsx(Image, { source: { uri: fallbackImage }, style: styles.fullScreenImage, resizeMode: "contain" }) })] }) }));
|
|
157
185
|
}
|
|
158
|
-
|
|
186
|
+
// Banner fallback
|
|
187
|
+
return (jsx(TouchableOpacity, { activeOpacity: 0.9, style: [styles.container, theme === 'dark' && styles.dark, style], onPress: handleFallbackPress, children: jsx(Image, { source: { uri: fallbackImage }, style: { width: 320, height: 50, resizeMode: 'contain' } }) }));
|
|
188
|
+
}
|
|
189
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
190
|
+
if (!ad) {
|
|
191
|
+
return debug ? (jsx(View, { style: [styles.container, styles.loading], children: jsx(Text, { style: styles.loadingText, children: "Carregando an\u00FAncio\u2026" }) })) : null;
|
|
192
|
+
}
|
|
159
193
|
const handlePress = () => {
|
|
160
194
|
log('Clique no anúncio', ad.clickUrl);
|
|
161
|
-
if (isPopup) {
|
|
162
|
-
// Allow close on click even if timer not finished?
|
|
163
|
-
// Usually ads allow clicking through immediately.
|
|
195
|
+
if (isPopup && canClose) {
|
|
164
196
|
setModalVisible(false);
|
|
165
197
|
}
|
|
166
198
|
if (!ad.clickUrl)
|
|
@@ -172,93 +204,102 @@ style = {}, debug = false, }) {
|
|
|
172
204
|
Linking.openURL(ad.clickUrl);
|
|
173
205
|
}
|
|
174
206
|
};
|
|
175
|
-
|
|
176
|
-
if (canClose) {
|
|
177
|
-
setModalVisible(false);
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
if (error) {
|
|
181
|
-
return debug ? (jsx(View, { style: [styles.upeexContainer, styles.upeexDebug], children: jsx(Text, { style: styles.upeexDebugText, children: error }) })) : null;
|
|
182
|
-
}
|
|
183
|
-
if (!ad) {
|
|
184
|
-
return debug ? (jsx(View, { style: [styles.upeexContainer, styles.upeexLoading], children: jsx(Text, { style: styles.upeexLoadingText, children: "Carregando an\u00FAncio\u2026" }) })) : null;
|
|
185
|
-
}
|
|
207
|
+
// ─── POPUP ─────────────────────────────────────────────────────────────────
|
|
186
208
|
if (isPopup) {
|
|
187
|
-
return (jsx(Modal, { transparent: true,
|
|
188
|
-
styles.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
209
|
+
return (jsx(Modal, { transparent: true, animationType: "fade", visible: modalVisible, onRequestClose: () => canClose && setModalVisible(false), children: jsxs(View, { style: styles.modalBackground, children: [jsx(View, { style: styles.progressBarContainer, children: jsx(AnimatedView, { style: [
|
|
210
|
+
styles.progressBar,
|
|
211
|
+
{
|
|
212
|
+
width: progressAnim.interpolate({
|
|
213
|
+
inputRange: [0, 1],
|
|
214
|
+
outputRange: ['0%', '100%'],
|
|
215
|
+
}),
|
|
216
|
+
backgroundColor: '#fff',
|
|
217
|
+
},
|
|
218
|
+
] }) }), !canClose && (jsx(View, { style: styles.spinnerOverlay, children: jsx(ActivityIndicator, { size: "small", color: "#fff" }) })), canClose && (jsx(TouchableOpacity, { style: styles.closeButton, onPress: () => setModalVisible(false), children: jsx(Text, { style: styles.closeButtonText, children: "X" }) })), jsx(TouchableOpacity, { style: styles.fullScreenTouch, activeOpacity: 1, onPress: handlePress, children: jsx(Image, { source: { uri: ad.image }, style: styles.fullScreenImage, resizeMode: "contain" }) })] }) }));
|
|
195
219
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
theme === 'dark' && styles.upeexDark,
|
|
199
|
-
style,
|
|
200
|
-
], onPress: handlePress, children: jsx(Image, { source: { uri: ad.image }, style: {
|
|
220
|
+
// ─── BANNER ────────────────────────────────────────────────────────────────
|
|
221
|
+
return (jsx(TouchableOpacity, { activeOpacity: 0.9, style: [styles.container, theme === 'dark' && styles.dark, style], onPress: handlePress, children: jsx(Image, { source: { uri: ad.image }, style: {
|
|
201
222
|
width: ad.width || 320,
|
|
202
223
|
height: ad.height || 50,
|
|
203
224
|
resizeMode: 'contain',
|
|
204
225
|
} }) }));
|
|
205
226
|
}
|
|
206
227
|
const styles = StyleSheet.create({
|
|
207
|
-
|
|
228
|
+
container: {
|
|
208
229
|
backgroundColor: '#f2f2f2',
|
|
209
230
|
padding: 8,
|
|
210
231
|
alignItems: 'center',
|
|
211
232
|
justifyContent: 'center',
|
|
212
233
|
},
|
|
213
|
-
|
|
234
|
+
dark: {
|
|
214
235
|
backgroundColor: '#121212',
|
|
215
236
|
},
|
|
216
|
-
|
|
237
|
+
loading: {
|
|
217
238
|
backgroundColor: '#fafafa',
|
|
218
239
|
},
|
|
219
|
-
|
|
240
|
+
loadingText: {
|
|
220
241
|
fontSize: 11,
|
|
221
242
|
color: '#999',
|
|
222
243
|
},
|
|
223
|
-
|
|
244
|
+
debug: {
|
|
224
245
|
backgroundColor: '#ffecec',
|
|
225
246
|
},
|
|
226
|
-
|
|
247
|
+
debugText: {
|
|
227
248
|
fontSize: 11,
|
|
228
249
|
color: '#c00',
|
|
229
250
|
},
|
|
230
|
-
|
|
251
|
+
// Modal / Popup
|
|
252
|
+
modalBackground: {
|
|
231
253
|
flex: 1,
|
|
232
|
-
backgroundColor: 'rgba(0,
|
|
254
|
+
backgroundColor: 'rgba(0,0,0,0.9)',
|
|
233
255
|
justifyContent: 'center',
|
|
234
256
|
alignItems: 'center',
|
|
235
|
-
zIndex: 9999,
|
|
236
|
-
elevation: 10,
|
|
237
257
|
},
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
258
|
+
fullScreenTouch: {
|
|
259
|
+
flex: 1,
|
|
260
|
+
width: '100%',
|
|
261
|
+
height: '100%',
|
|
262
|
+
justifyContent: 'center',
|
|
241
263
|
alignItems: 'center',
|
|
242
|
-
position: 'relative',
|
|
243
|
-
zIndex: 10000,
|
|
244
264
|
},
|
|
245
|
-
|
|
265
|
+
fullScreenImage: {
|
|
266
|
+
width: '90%',
|
|
267
|
+
height: '90%',
|
|
268
|
+
},
|
|
269
|
+
closeButton: {
|
|
246
270
|
position: 'absolute',
|
|
247
|
-
top:
|
|
248
|
-
right:
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
height: 30,
|
|
271
|
+
top: 50,
|
|
272
|
+
right: 20,
|
|
273
|
+
backgroundColor: 'rgba(0,0,0,0.6)',
|
|
274
|
+
width: 40,
|
|
275
|
+
height: 40,
|
|
276
|
+
borderRadius: 20,
|
|
254
277
|
justifyContent: 'center',
|
|
255
278
|
alignItems: 'center',
|
|
256
|
-
|
|
279
|
+
zIndex: 999,
|
|
257
280
|
},
|
|
258
|
-
|
|
281
|
+
closeButtonText: {
|
|
282
|
+
color: '#fff',
|
|
259
283
|
fontSize: 18,
|
|
260
284
|
fontWeight: 'bold',
|
|
261
|
-
|
|
285
|
+
},
|
|
286
|
+
progressBarContainer: {
|
|
287
|
+
position: 'absolute',
|
|
288
|
+
top: 0,
|
|
289
|
+
left: 0,
|
|
290
|
+
width: '100%',
|
|
291
|
+
height: 5,
|
|
292
|
+
backgroundColor: 'rgba(255,255,255,0.3)',
|
|
293
|
+
zIndex: 1000,
|
|
294
|
+
},
|
|
295
|
+
progressBar: {
|
|
296
|
+
height: '100%',
|
|
297
|
+
},
|
|
298
|
+
spinnerOverlay: {
|
|
299
|
+
position: 'absolute',
|
|
300
|
+
top: 12,
|
|
301
|
+
right: 20,
|
|
302
|
+
zIndex: 1000,
|
|
262
303
|
},
|
|
263
304
|
});
|
|
264
305
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@upeex/ads-sdk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.25",
|
|
4
4
|
"description": "Upeex Ads SDK for React Native and universal apps",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -27,10 +27,11 @@
|
|
|
27
27
|
"author": "Upeex",
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@upeex/ads-sdk": "^1.1.10",
|
|
31
30
|
"expo-localization": "^17.0.8"
|
|
32
31
|
},
|
|
33
32
|
"devDependencies": {
|
|
33
|
+
"@types/react": "^19.2.13",
|
|
34
|
+
"@types/react-native": "^0.73.0",
|
|
34
35
|
"rollup": "^4.57.0",
|
|
35
36
|
"rollup-plugin-typescript2": "^0.36.0",
|
|
36
37
|
"tslib": "^2.8.1",
|