@vynix-org/react-native-ads-sdk 0.1.4 → 0.1.5
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/lib/module/ads-manager/AppOpenAdsManager.js +3 -0
- package/lib/module/ads-manager/AppOpenAdsManager.js.map +1 -1
- package/lib/module/ads-manager/InterstitialAdsManager.js +26 -3
- package/lib/module/ads-manager/InterstitialAdsManager.js.map +1 -1
- package/lib/module/ads-manager/NativeAdsManager.js +27 -3
- package/lib/module/ads-manager/NativeAdsManager.js.map +1 -1
- package/lib/module/ads-manager/RewardedAdsManager.js +26 -2
- package/lib/module/ads-manager/RewardedAdsManager.js.map +1 -1
- package/lib/module/ads-manager/RewardedInterstitialAdsManager.js +25 -1
- package/lib/module/ads-manager/RewardedInterstitialAdsManager.js.map +1 -1
- package/lib/module/analytics/AnalyticsManager.js +132 -0
- package/lib/module/analytics/AnalyticsManager.js.map +1 -0
- package/lib/module/analytics/EventTracking.js +11 -0
- package/lib/module/analytics/EventTracking.js.map +1 -0
- package/lib/module/analytics/TrackingManager.js +26 -0
- package/lib/module/analytics/TrackingManager.js.map +1 -0
- package/lib/module/components/BannerAdComponent.js +26 -3
- package/lib/module/components/BannerAdComponent.js.map +1 -1
- package/lib/module/components/NativeAdComponent.js +49 -80
- package/lib/module/components/NativeAdComponent.js.map +1 -1
- package/lib/module/components/NativeStyles.js +22 -14
- package/lib/module/components/NativeStyles.js.map +1 -1
- package/lib/typescript/src/ads-manager/AppOpenAdsManager.d.ts.map +1 -1
- package/lib/typescript/src/ads-manager/InterstitialAdsManager.d.ts.map +1 -1
- package/lib/typescript/src/ads-manager/NativeAdsManager.d.ts.map +1 -1
- package/lib/typescript/src/ads-manager/RewardedAdsManager.d.ts.map +1 -1
- package/lib/typescript/src/ads-manager/RewardedInterstitialAdsManager.d.ts.map +1 -1
- package/lib/typescript/src/analytics/AnalyticsManager.d.ts +50 -0
- package/lib/typescript/src/analytics/AnalyticsManager.d.ts.map +1 -0
- package/lib/typescript/src/analytics/EventTracking.d.ts +14 -0
- package/lib/typescript/src/analytics/EventTracking.d.ts.map +1 -0
- package/lib/typescript/src/analytics/TrackingManager.d.ts +12 -0
- package/lib/typescript/src/analytics/TrackingManager.d.ts.map +1 -0
- package/lib/typescript/src/components/BannerAdComponent.d.ts.map +1 -1
- package/lib/typescript/src/components/NativeAdComponent.d.ts.map +1 -1
- package/lib/typescript/src/components/NativeStyles.d.ts +15 -7
- package/lib/typescript/src/components/NativeStyles.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/ads-manager/AppOpenAdsManager.ts +4 -0
- package/src/ads-manager/InterstitialAdsManager.ts +29 -3
- package/src/ads-manager/NativeAdsManager.ts +31 -2
- package/src/ads-manager/RewardedAdsManager.ts +30 -2
- package/src/ads-manager/RewardedInterstitialAdsManager.ts +30 -1
- package/src/analytics/AnalyticsManager.ts +140 -0
- package/src/analytics/EventTracking.ts +14 -0
- package/src/analytics/TrackingManager.ts +33 -0
- package/src/components/BannerAdComponent.tsx +47 -17
- package/src/components/NativeAdComponent.tsx +35 -79
- package/src/components/NativeStyles.ts +20 -12
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import analytics from '@react-native-firebase/analytics';
|
|
2
|
+
import { EventTracking, type EventParams } from './EventTracking';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Event names cho Ads Analytics
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Analytics Manager để quản lý Firebase Analytics events
|
|
10
|
+
*/
|
|
11
|
+
export class AnalyticsManager {
|
|
12
|
+
private static instance: AnalyticsManager;
|
|
13
|
+
private isEnabled = true;
|
|
14
|
+
private isInitialized = false;
|
|
15
|
+
private initPromise: Promise<void> | null = null;
|
|
16
|
+
|
|
17
|
+
private constructor() {}
|
|
18
|
+
|
|
19
|
+
static getInstance(): AnalyticsManager {
|
|
20
|
+
if (!AnalyticsManager.instance) {
|
|
21
|
+
AnalyticsManager.instance = new AnalyticsManager();
|
|
22
|
+
}
|
|
23
|
+
return AnalyticsManager.instance;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Khởi tạo Analytics Manager
|
|
28
|
+
*/
|
|
29
|
+
async initialize(): Promise<void> {
|
|
30
|
+
if (this.isInitialized) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (this.initPromise) {
|
|
35
|
+
return this.initPromise;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.initPromise = this.initializeInternal();
|
|
39
|
+
return this.initPromise;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private async initializeInternal(): Promise<void> {
|
|
43
|
+
try {
|
|
44
|
+
// Kiểm tra xem analytics có sẵn không
|
|
45
|
+
await analytics().setAnalyticsCollectionEnabled(this.isEnabled);
|
|
46
|
+
this.isInitialized = true;
|
|
47
|
+
console.log('Analytics Manager initialized successfully');
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error('Failed to initialize Analytics Manager:', error);
|
|
50
|
+
// Không throw error để không làm gián đoạn app
|
|
51
|
+
this.isInitialized = false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Bật/tắt analytics collection
|
|
57
|
+
*/
|
|
58
|
+
async setEnabled(enabled: boolean): Promise<void> {
|
|
59
|
+
this.isEnabled = enabled;
|
|
60
|
+
try {
|
|
61
|
+
await analytics().setAnalyticsCollectionEnabled(enabled);
|
|
62
|
+
console.log(`Analytics collection ${enabled ? 'enabled' : 'disabled'}`);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error('Failed to set analytics collection enabled:', error);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Kiểm tra xem analytics có được bật không
|
|
70
|
+
*/
|
|
71
|
+
isAnalyticsEnabled(): boolean {
|
|
72
|
+
return this.isEnabled;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Log một custom event
|
|
77
|
+
*/
|
|
78
|
+
async logEvent(eventName: string, params?: EventParams): Promise<void> {
|
|
79
|
+
if (!this.isEnabled) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
await this.ensureInitialized();
|
|
85
|
+
await analytics().logEvent(eventName, params);
|
|
86
|
+
console.log(`Analytics event logged: ${eventName}`, params);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error(`Failed to log analytics event ${eventName}:`, error);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Log ad event với các parameters chuẩn
|
|
94
|
+
*/
|
|
95
|
+
async logAdEvent(event: EventTracking, params?: EventParams): Promise<void> {
|
|
96
|
+
await this.logEvent(event, params);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async logRequestAdEvent(params?: EventParams): Promise<void> {
|
|
100
|
+
await this.logAdEvent(EventTracking.TRACK_AD_REQUEST, params);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async logClickAdEvent(params?: EventParams): Promise<void> {
|
|
104
|
+
await this.logAdEvent(EventTracking.EVENT_CLICK_AD, params);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async logRevenueAdEvent(params?: EventParams): Promise<void> {
|
|
108
|
+
await this.logAdEvent(EventTracking.PAID_AD_IMPRESSION, params);
|
|
109
|
+
await this.logAdEvent(EventTracking.EVENT_PURCHASE, params);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async logAdLoadedEvent(params?: EventParams): Promise<void> {
|
|
113
|
+
await this.logAdEvent(EventTracking.EVENT_AD_LOADED, params);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Reset analytics data
|
|
118
|
+
*/
|
|
119
|
+
async resetAnalyticsData(): Promise<void> {
|
|
120
|
+
try {
|
|
121
|
+
await this.ensureInitialized();
|
|
122
|
+
await analytics().resetAnalyticsData();
|
|
123
|
+
console.log('Analytics data reset');
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error('Failed to reset analytics data:', error);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Đảm bảo analytics đã được khởi tạo
|
|
131
|
+
*/
|
|
132
|
+
private async ensureInitialized(): Promise<void> {
|
|
133
|
+
if (!this.isInitialized) {
|
|
134
|
+
await this.initialize();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Singleton instance
|
|
140
|
+
export const analyticsManager = AnalyticsManager.getInstance();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export enum EventTracking {
|
|
2
|
+
TRACK_AD_REQUEST = 'track_ad_request',
|
|
3
|
+
PAID_AD_IMPRESSION = 'paid_ad_impression_value',
|
|
4
|
+
EVENT_CLICK_AD = 'event_user_click_ads',
|
|
5
|
+
EVENT_AD_LOADED = 'track_ad_matched_request',
|
|
6
|
+
EVENT_PURCHASE = 'purchase',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface EventParams {
|
|
10
|
+
adUnitId?: string;
|
|
11
|
+
adFormat?: string;
|
|
12
|
+
currency?: string;
|
|
13
|
+
value?: number;
|
|
14
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { analyticsManager } from './AnalyticsManager';
|
|
2
|
+
import type { EventParams } from './EventTracking';
|
|
3
|
+
|
|
4
|
+
export class TrackingManager {
|
|
5
|
+
private static instance: TrackingManager;
|
|
6
|
+
|
|
7
|
+
private constructor() {}
|
|
8
|
+
|
|
9
|
+
static getInstance(): TrackingManager {
|
|
10
|
+
if (!TrackingManager.instance) {
|
|
11
|
+
TrackingManager.instance = new TrackingManager();
|
|
12
|
+
}
|
|
13
|
+
return TrackingManager.instance;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async onTrackingRequestAd(params?: EventParams) {
|
|
17
|
+
await analyticsManager.logRequestAdEvent(params);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async onTrackingClickAd(params?: EventParams) {
|
|
21
|
+
await analyticsManager.logClickAdEvent(params);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async onTrackingRevenueAd(params?: EventParams) {
|
|
25
|
+
await analyticsManager.logRevenueAdEvent(params);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async onTrackingAdLoaded(params?: EventParams) {
|
|
29
|
+
await analyticsManager.logAdLoadedEvent(params);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const trackingManager = TrackingManager.getInstance();
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import React, { useEffect, useState, useRef } from 'react';
|
|
2
2
|
import { View, StyleSheet } from 'react-native';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
BannerAd,
|
|
5
|
+
type PaidEvent,
|
|
6
|
+
type RequestOptions,
|
|
7
|
+
} from 'react-native-google-mobile-ads';
|
|
4
8
|
import {
|
|
5
9
|
Placeholder,
|
|
6
10
|
PlaceholderMedia,
|
|
7
11
|
PlaceholderLine,
|
|
8
12
|
Fade,
|
|
9
13
|
} from 'rn-placeholder';
|
|
14
|
+
import { trackingManager } from '../analytics/TrackingManager';
|
|
10
15
|
|
|
11
16
|
interface BannerAdComponentProps {
|
|
12
17
|
adId: string;
|
|
@@ -75,6 +80,10 @@ export const BannerAdComponent: React.FC<BannerAdComponentProps> = ({
|
|
|
75
80
|
setError(null);
|
|
76
81
|
console.log('PreloadedBannerAd loaded:', currentAdId);
|
|
77
82
|
onAdLoaded?.();
|
|
83
|
+
trackingManager.onTrackingRequestAd({
|
|
84
|
+
adUnitId: currentAdId,
|
|
85
|
+
adFormat: 'Banner',
|
|
86
|
+
});
|
|
78
87
|
};
|
|
79
88
|
|
|
80
89
|
const handleAdFailedToLoad = (error: Error) => {
|
|
@@ -117,11 +126,29 @@ export const BannerAdComponent: React.FC<BannerAdComponentProps> = ({
|
|
|
117
126
|
const handleAdClicked = () => {
|
|
118
127
|
console.log('PreloadedBannerAd clicked');
|
|
119
128
|
onAdClicked?.();
|
|
129
|
+
trackingManager.onTrackingClickAd({
|
|
130
|
+
adUnitId: currentAdId,
|
|
131
|
+
adFormat: 'Banner',
|
|
132
|
+
});
|
|
120
133
|
};
|
|
121
134
|
|
|
122
135
|
const handleAdImpression = () => {
|
|
123
136
|
console.log('PreloadedBannerAd impression');
|
|
124
137
|
onAdImpression?.();
|
|
138
|
+
trackingManager.onTrackingAdLoaded({
|
|
139
|
+
adUnitId: currentAdId,
|
|
140
|
+
adFormat: 'Banner',
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const handlePaid = (paid: PaidEvent) => {
|
|
145
|
+
console.log('PreloadedBannerAd paid:', paid);
|
|
146
|
+
trackingManager.onTrackingRevenueAd({
|
|
147
|
+
adUnitId: currentAdId,
|
|
148
|
+
adFormat: 'Banner',
|
|
149
|
+
currency: paid.currency,
|
|
150
|
+
value: paid.value,
|
|
151
|
+
});
|
|
125
152
|
};
|
|
126
153
|
|
|
127
154
|
if (!shouldRender) {
|
|
@@ -148,21 +175,24 @@ export const BannerAdComponent: React.FC<BannerAdComponentProps> = ({
|
|
|
148
175
|
|
|
149
176
|
{error && showError && <View />}
|
|
150
177
|
|
|
151
|
-
|
|
152
|
-
<
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
178
|
+
{isLoaded && !error && (
|
|
179
|
+
<View style={{ minHeight: 50 }}>
|
|
180
|
+
<BannerAd
|
|
181
|
+
key={currentAdId}
|
|
182
|
+
ref={bannerRef}
|
|
183
|
+
unitId={currentAdId}
|
|
184
|
+
size={size}
|
|
185
|
+
onAdLoaded={handleAdLoaded}
|
|
186
|
+
onAdFailedToLoad={handleAdFailedToLoad}
|
|
187
|
+
onAdOpened={handleAdOpened}
|
|
188
|
+
onAdClosed={handleAdClosed}
|
|
189
|
+
onAdClicked={handleAdClicked}
|
|
190
|
+
onAdImpression={handleAdImpression}
|
|
191
|
+
requestOptions={requestOptions}
|
|
192
|
+
onPaid={(paid) => handlePaid(paid)}
|
|
193
|
+
/>
|
|
194
|
+
</View>
|
|
195
|
+
)}
|
|
166
196
|
</View>
|
|
167
197
|
);
|
|
168
198
|
};
|
|
@@ -181,7 +211,7 @@ const styles = StyleSheet.create({
|
|
|
181
211
|
justifyContent: 'center',
|
|
182
212
|
backgroundColor: 'rgba(255, 255, 255, 0.9)',
|
|
183
213
|
paddingHorizontal: 20,
|
|
184
|
-
paddingVertical:
|
|
214
|
+
paddingVertical: 12,
|
|
185
215
|
borderRadius: 8,
|
|
186
216
|
},
|
|
187
217
|
loadingText: {
|
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
View,
|
|
4
4
|
Text,
|
|
5
5
|
ActivityIndicator,
|
|
6
|
-
TouchableOpacity,
|
|
7
6
|
type ViewStyle,
|
|
8
7
|
type TextStyle,
|
|
9
8
|
} from 'react-native';
|
|
@@ -17,6 +16,7 @@ import {
|
|
|
17
16
|
import { useNativeAd } from '../hook/useNativeAd';
|
|
18
17
|
import type { AdInstance } from '../types/ads-types';
|
|
19
18
|
import { styles } from './NativeStyles';
|
|
19
|
+
import { Image } from 'react-native';
|
|
20
20
|
|
|
21
21
|
interface NativeAdComponentProps {
|
|
22
22
|
adKey: string;
|
|
@@ -51,11 +51,8 @@ export const NativeAdComponent: React.FC<NativeAdComponentProps> = ({
|
|
|
51
51
|
adBadgeStyles,
|
|
52
52
|
headlineStyles,
|
|
53
53
|
bodyStyles,
|
|
54
|
-
ratingStyles,
|
|
55
|
-
priceStyles,
|
|
56
|
-
storeStyles,
|
|
57
54
|
}) => {
|
|
58
|
-
const { ad, isLoading, error, isLoaded
|
|
55
|
+
const { ad, isLoading, error, isLoaded } = useNativeAd({
|
|
59
56
|
adKey,
|
|
60
57
|
adId,
|
|
61
58
|
autoLoad,
|
|
@@ -80,27 +77,12 @@ export const NativeAdComponent: React.FC<NativeAdComponentProps> = ({
|
|
|
80
77
|
|
|
81
78
|
// Render error state
|
|
82
79
|
if (error) {
|
|
83
|
-
return
|
|
84
|
-
<View style={[styles.wrapper, style]}>
|
|
85
|
-
<View style={[styles.container, styles.centerContent]}>
|
|
86
|
-
<Text style={styles.errorText}>Lỗi: {error}</Text>
|
|
87
|
-
<TouchableOpacity onPress={() => loadAd()} style={styles.retryButton}>
|
|
88
|
-
<Text style={styles.retryText}>Thử lại</Text>
|
|
89
|
-
</TouchableOpacity>
|
|
90
|
-
</View>
|
|
91
|
-
</View>
|
|
92
|
-
);
|
|
80
|
+
return null;
|
|
93
81
|
}
|
|
94
82
|
|
|
95
83
|
// Render empty state
|
|
96
84
|
if (!isLoaded || !ad?.data?.nativeAd) {
|
|
97
|
-
return
|
|
98
|
-
<View style={[styles.wrapper, style]}>
|
|
99
|
-
<View style={[styles.container, styles.centerContent]}>
|
|
100
|
-
<Text style={styles.emptyText}>Không có quảng cáo</Text>
|
|
101
|
-
</View>
|
|
102
|
-
</View>
|
|
103
|
-
);
|
|
85
|
+
return null;
|
|
104
86
|
}
|
|
105
87
|
|
|
106
88
|
const nativeAd = ad.data.nativeAd as NativeAd;
|
|
@@ -110,9 +92,6 @@ export const NativeAdComponent: React.FC<NativeAdComponentProps> = ({
|
|
|
110
92
|
<NativeAdView nativeAd={nativeAd} style={[styles.container]}>
|
|
111
93
|
{/* Ad Badge và Advertiser */}
|
|
112
94
|
<View style={styles.adHeader}>
|
|
113
|
-
{/* <NativeAsset assetType={NativeAssetType.ADVERTISER}> */}
|
|
114
|
-
<Text style={[styles.adBadge, adBadgeStyles]}>Ad</Text>
|
|
115
|
-
{/* </NativeAsset> */}
|
|
116
95
|
{nativeAd.advertiser && (
|
|
117
96
|
<NativeAsset assetType={NativeAssetType.ADVERTISER}>
|
|
118
97
|
<Text style={styles.advertiserText} numberOfLines={1}>
|
|
@@ -122,6 +101,14 @@ export const NativeAdComponent: React.FC<NativeAdComponentProps> = ({
|
|
|
122
101
|
)}
|
|
123
102
|
</View>
|
|
124
103
|
|
|
104
|
+
{nativeAd.callToAction && (
|
|
105
|
+
<NativeAsset assetType={NativeAssetType.CALL_TO_ACTION}>
|
|
106
|
+
<View style={[styles.ctaButton, buttonActionStyles]}>
|
|
107
|
+
<Text style={styles.ctaText}>{nativeAd.callToAction}</Text>
|
|
108
|
+
</View>
|
|
109
|
+
</NativeAsset>
|
|
110
|
+
)}
|
|
111
|
+
|
|
125
112
|
{/* Media View - Hiển thị ảnh hoặc video */}
|
|
126
113
|
{((nativeAd.images?.length && nativeAd.images.length > 0) ||
|
|
127
114
|
nativeAd.mediaContent) && (
|
|
@@ -137,71 +124,40 @@ export const NativeAdComponent: React.FC<NativeAdComponentProps> = ({
|
|
|
137
124
|
|
|
138
125
|
{/* Ad Content */}
|
|
139
126
|
<View style={styles.contentContainer}>
|
|
140
|
-
{
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
{/* Body */}
|
|
150
|
-
{nativeAd.body && (
|
|
151
|
-
<NativeAsset assetType={NativeAssetType.BODY}>
|
|
152
|
-
<Text style={[styles.bodyText, bodyStyles]} numberOfLines={3}>
|
|
153
|
-
{nativeAd.body}
|
|
154
|
-
</Text>
|
|
127
|
+
{nativeAd.icon && (
|
|
128
|
+
<NativeAsset assetType={NativeAssetType.ICON}>
|
|
129
|
+
<View style={styles.iconContainer}>
|
|
130
|
+
<Image
|
|
131
|
+
source={{ uri: nativeAd.icon?.url }}
|
|
132
|
+
style={styles.icon}
|
|
133
|
+
/>
|
|
134
|
+
</View>
|
|
155
135
|
</NativeAsset>
|
|
156
136
|
)}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
137
|
+
<View style={{ flex: 1 }}>
|
|
138
|
+
<View style={styles.vHeader}>
|
|
139
|
+
<Text style={[styles.adBadge, adBadgeStyles]}>Ad</Text>
|
|
140
|
+
{nativeAd.headline && (
|
|
141
|
+
<NativeAsset assetType={NativeAssetType.HEADLINE}>
|
|
142
|
+
<Text
|
|
143
|
+
style={[styles.headline, headlineStyles]}
|
|
144
|
+
numberOfLines={1}
|
|
145
|
+
>
|
|
146
|
+
{nativeAd.headline}
|
|
166
147
|
</Text>
|
|
167
148
|
</NativeAsset>
|
|
168
149
|
)}
|
|
150
|
+
</View>
|
|
169
151
|
|
|
170
|
-
{
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
{nativeAd.price}
|
|
175
|
-
</Text>
|
|
176
|
-
</NativeAsset>
|
|
177
|
-
)}
|
|
178
|
-
|
|
179
|
-
{/* Store */}
|
|
180
|
-
{nativeAd.store && (
|
|
181
|
-
<NativeAsset assetType={NativeAssetType.STORE}>
|
|
182
|
-
<Text style={[styles.storeText, storeStyles]} numberOfLines={1}>
|
|
183
|
-
{nativeAd.store}
|
|
152
|
+
{nativeAd.body && (
|
|
153
|
+
<NativeAsset assetType={NativeAssetType.BODY}>
|
|
154
|
+
<Text numberOfLines={2} style={[styles.bodyText, bodyStyles]}>
|
|
155
|
+
{nativeAd.body}
|
|
184
156
|
</Text>
|
|
185
157
|
</NativeAsset>
|
|
186
158
|
)}
|
|
187
159
|
</View>
|
|
188
|
-
|
|
189
|
-
{/* Call To Action Button */}
|
|
190
|
-
{nativeAd.callToAction && (
|
|
191
|
-
<NativeAsset assetType={NativeAssetType.CALL_TO_ACTION}>
|
|
192
|
-
<View style={[styles.ctaButton, buttonActionStyles]}>
|
|
193
|
-
<Text style={styles.ctaText}>{nativeAd.callToAction}</Text>
|
|
194
|
-
</View>
|
|
195
|
-
</NativeAsset>
|
|
196
|
-
)}
|
|
197
160
|
</View>
|
|
198
|
-
|
|
199
|
-
{/* Icon */}
|
|
200
|
-
{/* {nativeAd.icon && (
|
|
201
|
-
<NativeAsset assetType={NativeAssetType.ICON}>
|
|
202
|
-
<View style={styles.iconContainer} />
|
|
203
|
-
</NativeAsset>
|
|
204
|
-
)} */}
|
|
205
161
|
</NativeAdView>
|
|
206
162
|
</View>
|
|
207
163
|
);
|
|
@@ -55,13 +55,14 @@ export const styles = StyleSheet.create({
|
|
|
55
55
|
backgroundColor: '#F9F9F9',
|
|
56
56
|
},
|
|
57
57
|
adBadge: {
|
|
58
|
-
backgroundColor: '#
|
|
58
|
+
backgroundColor: '#57BF87',
|
|
59
59
|
paddingHorizontal: 6,
|
|
60
60
|
paddingVertical: 2,
|
|
61
61
|
borderRadius: 3,
|
|
62
62
|
fontSize: 10,
|
|
63
|
+
marginEnd: 10,
|
|
63
64
|
fontWeight: '700',
|
|
64
|
-
color: '#
|
|
65
|
+
color: '#fff',
|
|
65
66
|
},
|
|
66
67
|
advertiserText: {
|
|
67
68
|
fontSize: 11,
|
|
@@ -75,23 +76,22 @@ export const styles = StyleSheet.create({
|
|
|
75
76
|
minHeight: 180,
|
|
76
77
|
maxHeight: 250,
|
|
77
78
|
alignSelf: 'center',
|
|
78
|
-
backgroundColor: '#F0F0F0',
|
|
79
79
|
},
|
|
80
80
|
contentContainer: {
|
|
81
|
+
flexDirection: 'row',
|
|
82
|
+
alignItems: 'center',
|
|
81
83
|
padding: 12,
|
|
82
84
|
},
|
|
83
85
|
headline: {
|
|
84
86
|
fontSize: 16,
|
|
85
87
|
fontWeight: '700',
|
|
86
88
|
color: '#000',
|
|
87
|
-
marginBottom: 6,
|
|
88
89
|
lineHeight: 22,
|
|
89
90
|
},
|
|
90
91
|
bodyText: {
|
|
91
92
|
fontSize: 13,
|
|
92
93
|
color: '#666',
|
|
93
94
|
lineHeight: 18,
|
|
94
|
-
marginBottom: 10,
|
|
95
95
|
},
|
|
96
96
|
infoRow: {
|
|
97
97
|
flexDirection: 'row',
|
|
@@ -118,7 +118,8 @@ export const styles = StyleSheet.create({
|
|
|
118
118
|
ctaButton: {
|
|
119
119
|
backgroundColor: '#007AFF',
|
|
120
120
|
paddingVertical: 10,
|
|
121
|
-
|
|
121
|
+
marginHorizontal: 20,
|
|
122
|
+
marginBottom: 10,
|
|
122
123
|
borderRadius: 6,
|
|
123
124
|
alignItems: 'center',
|
|
124
125
|
justifyContent: 'center',
|
|
@@ -129,13 +130,20 @@ export const styles = StyleSheet.create({
|
|
|
129
130
|
color: '#FFFFFF',
|
|
130
131
|
},
|
|
131
132
|
iconContainer: {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
height: 36,
|
|
137
|
-
borderRadius: 18,
|
|
133
|
+
width: 40,
|
|
134
|
+
height: 40,
|
|
135
|
+
borderRadius: 8,
|
|
136
|
+
marginEnd: 10,
|
|
138
137
|
overflow: 'hidden',
|
|
139
138
|
backgroundColor: '#F0F0F0',
|
|
140
139
|
},
|
|
140
|
+
icon: {
|
|
141
|
+
width: '100%',
|
|
142
|
+
height: '100%',
|
|
143
|
+
resizeMode: 'cover',
|
|
144
|
+
},
|
|
145
|
+
vHeader: {
|
|
146
|
+
flexDirection: 'row',
|
|
147
|
+
alignItems: 'center',
|
|
148
|
+
},
|
|
141
149
|
});
|