cloudx-react-native 2.0.0-beta.1 → 2.0.0
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 +420 -1046
- package/android/src/main/AndroidManifest.xml +0 -4
- package/android/src/main/java/com/cloudxreactnative/CloudXAdEvents.kt +39 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdInfo.kt +32 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXModuleImpl.kt +694 -0
- package/android/src/{newarch/com/cloudxreactnative/CloudXReactNativePackage.kt → main/java/com/cloudxreactnative/CloudXPackage.kt} +14 -13
- package/android/src/newarch/com/cloudxreactnative/{CloudXReactNativeModule.kt → CloudXModule.kt} +31 -34
- package/android/src/oldarch/com/cloudxreactnative/{CloudXReactNativeModule.kt → CloudXModule.kt} +27 -32
- package/cloudx-react-native.podspec +1 -1
- package/ios/CloudX.h +47 -0
- package/ios/CloudX.mm +1406 -0
- package/lib/commonjs/AppTrackingTransparency.js +13 -13
- package/lib/commonjs/AppTrackingTransparency.js.map +1 -1
- package/lib/commonjs/CloudX.js +16 -12
- package/lib/commonjs/CloudX.js.map +1 -1
- package/lib/commonjs/CloudXAdPosition.js +23 -0
- package/lib/commonjs/CloudXAdPosition.js.map +1 -0
- package/lib/commonjs/{BannerAd.js → CloudXBannerAd.js} +42 -37
- package/lib/commonjs/CloudXBannerAd.js.map +1 -0
- package/lib/commonjs/CloudXErrorCode.js +116 -0
- package/lib/commonjs/CloudXErrorCode.js.map +1 -0
- package/lib/commonjs/{InterstitialAd.js → CloudXInterstitialAd.js} +10 -10
- package/lib/commonjs/CloudXInterstitialAd.js.map +1 -0
- package/lib/commonjs/{MRecAd.js → CloudXMRECAd.js} +42 -37
- package/lib/commonjs/CloudXMRECAd.js.map +1 -0
- package/lib/commonjs/{RewardedAd.js → CloudXRewardedAd.js} +10 -10
- package/lib/commonjs/CloudXRewardedAd.js.map +1 -0
- package/lib/commonjs/EventEmitter.js +3 -3
- package/lib/commonjs/EventEmitter.js.map +1 -1
- package/lib/commonjs/hooks.js +25 -26
- package/lib/commonjs/hooks.js.map +1 -1
- package/lib/commonjs/index.js +27 -41
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/{NativeCloudXModule.js → NativeCloudX.js} +2 -2
- package/lib/commonjs/specs/NativeCloudX.js.map +1 -0
- package/lib/commonjs/types/AdProps.js +6 -0
- package/lib/commonjs/types/AdProps.js.map +1 -0
- package/lib/commonjs/types/InterstitialAd.js +6 -0
- package/lib/commonjs/types/InterstitialAd.js.map +1 -0
- package/lib/commonjs/types/MRECAd.js +6 -0
- package/lib/commonjs/types/MRECAd.js.map +1 -0
- package/lib/commonjs/types/ViewAd.js +6 -0
- package/lib/commonjs/types/ViewAd.js.map +1 -0
- package/lib/module/AppTrackingTransparency.js +12 -12
- package/lib/module/AppTrackingTransparency.js.map +1 -1
- package/lib/module/CloudX.js +16 -12
- package/lib/module/CloudX.js.map +1 -1
- package/lib/module/CloudXAdPosition.js +17 -0
- package/lib/module/CloudXAdPosition.js.map +1 -0
- package/lib/module/{BannerAd.js → CloudXBannerAd.js} +41 -36
- package/lib/module/CloudXBannerAd.js.map +1 -0
- package/lib/module/CloudXErrorCode.js +110 -0
- package/lib/module/CloudXErrorCode.js.map +1 -0
- package/lib/module/{InterstitialAd.js → CloudXInterstitialAd.js} +9 -9
- package/lib/module/CloudXInterstitialAd.js.map +1 -0
- package/lib/module/{MRecAd.js → CloudXMRECAd.js} +41 -36
- package/lib/module/CloudXMRECAd.js.map +1 -0
- package/lib/module/{RewardedAd.js → CloudXRewardedAd.js} +9 -9
- package/lib/module/CloudXRewardedAd.js.map +1 -0
- package/lib/module/EventEmitter.js +2 -2
- package/lib/module/EventEmitter.js.map +1 -1
- package/lib/module/hooks.js +14 -15
- package/lib/module/hooks.js.map +1 -1
- package/lib/module/index.js +9 -10
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/{NativeCloudXModule.js → NativeCloudX.js} +2 -2
- package/lib/module/specs/NativeCloudX.js.map +1 -0
- package/lib/module/types/AdProps.js +2 -0
- package/lib/module/types/AdProps.js.map +1 -0
- package/lib/module/types/InterstitialAd.js +2 -0
- package/lib/module/types/InterstitialAd.js.map +1 -0
- package/lib/module/types/MRECAd.js +2 -0
- package/lib/module/types/MRECAd.js.map +1 -0
- package/lib/module/types/ViewAd.js +2 -0
- package/lib/module/types/ViewAd.js.map +1 -0
- package/lib/typescript/src/AppTrackingTransparency.d.ts +4 -4
- package/lib/typescript/src/AppTrackingTransparency.d.ts.map +1 -1
- package/lib/typescript/src/CloudX.d.ts.map +1 -1
- package/lib/typescript/src/CloudXAdPosition.d.ts +16 -0
- package/lib/typescript/src/CloudXAdPosition.d.ts.map +1 -0
- package/lib/typescript/src/CloudXBannerAd.d.ts +4 -0
- package/lib/typescript/src/CloudXBannerAd.d.ts.map +1 -0
- package/lib/typescript/src/{ErrorCode.d.ts → CloudXErrorCode.d.ts} +2 -2
- package/lib/typescript/src/CloudXErrorCode.d.ts.map +1 -0
- package/lib/typescript/src/CloudXInterstitialAd.d.ts +4 -0
- package/lib/typescript/src/CloudXInterstitialAd.d.ts.map +1 -0
- package/lib/typescript/src/CloudXMRECAd.d.ts +4 -0
- package/lib/typescript/src/CloudXMRECAd.d.ts.map +1 -0
- package/lib/typescript/src/CloudXRewardedAd.d.ts +4 -0
- package/lib/typescript/src/CloudXRewardedAd.d.ts.map +1 -0
- package/lib/typescript/src/EventEmitter.d.ts +4 -2
- package/lib/typescript/src/EventEmitter.d.ts.map +1 -1
- package/lib/typescript/src/hooks.d.ts +7 -8
- package/lib/typescript/src/hooks.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +12 -13
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/{NativeCloudXModule.d.ts → NativeCloudX.d.ts} +47 -64
- package/lib/typescript/src/specs/NativeCloudX.d.ts.map +1 -0
- package/lib/typescript/src/types/AdEvent.d.ts +3 -3
- package/lib/typescript/src/types/AdEvent.d.ts.map +1 -1
- package/lib/typescript/src/types/AdInfo.d.ts +7 -7
- package/lib/typescript/src/types/AdInfo.d.ts.map +1 -1
- package/lib/typescript/src/types/AdProps.d.ts +21 -0
- package/lib/typescript/src/types/AdProps.d.ts.map +1 -0
- package/lib/typescript/src/types/BannerAd.d.ts +8 -34
- package/lib/typescript/src/types/BannerAd.d.ts.map +1 -1
- package/lib/typescript/src/types/CloudX.d.ts +7 -4
- package/lib/typescript/src/types/CloudX.d.ts.map +1 -1
- package/lib/typescript/src/types/Configuration.d.ts +7 -3
- package/lib/typescript/src/types/Configuration.d.ts.map +1 -1
- package/lib/typescript/src/types/FullscreenAd.d.ts +10 -9
- package/lib/typescript/src/types/FullscreenAd.d.ts.map +1 -1
- package/lib/typescript/src/types/InterstitialAd.d.ts +8 -0
- package/lib/typescript/src/types/InterstitialAd.d.ts.map +1 -0
- package/lib/typescript/src/types/MRECAd.d.ts +13 -0
- package/lib/typescript/src/types/MRECAd.d.ts.map +1 -0
- package/lib/typescript/src/types/RewardedAd.d.ts +5 -4
- package/lib/typescript/src/types/RewardedAd.d.ts.map +1 -1
- package/lib/typescript/src/types/ViewAd.d.ts +29 -0
- package/lib/typescript/src/types/ViewAd.d.ts.map +1 -0
- package/lib/typescript/src/types/index.d.ts +11 -7
- package/lib/typescript/src/types/index.d.ts.map +1 -1
- package/package.json +8 -10
- package/src/AppTrackingTransparency.ts +10 -10
- package/src/CloudX.ts +21 -16
- package/src/CloudXAdPosition.ts +16 -0
- package/src/{BannerAd.ts → CloudXBannerAd.ts} +69 -47
- package/src/{ErrorCode.ts → CloudXErrorCode.ts} +1 -1
- package/src/{InterstitialAd.ts → CloudXInterstitialAd.ts} +17 -17
- package/src/{MRecAd.ts → CloudXMRECAd.ts} +69 -47
- package/src/{RewardedAd.ts → CloudXRewardedAd.ts} +18 -18
- package/src/EventEmitter.ts +4 -4
- package/src/hooks.ts +20 -22
- package/src/index.ts +27 -24
- package/src/specs/{NativeCloudXModule.ts → NativeCloudX.ts} +61 -82
- package/src/types/AdEvent.ts +3 -3
- package/src/types/AdInfo.ts +7 -7
- package/src/types/AdProps.ts +27 -0
- package/src/types/BannerAd.ts +8 -54
- package/src/types/CloudX.ts +10 -5
- package/src/types/Configuration.ts +8 -3
- package/src/types/FullscreenAd.ts +10 -9
- package/src/types/InterstitialAd.ts +8 -0
- package/src/types/MRECAd.ts +13 -0
- package/src/types/RewardedAd.ts +5 -4
- package/src/types/ViewAd.ts +38 -0
- package/src/types/index.ts +11 -7
- package/android/src/main/java/com/cloudxreactnative/CloudXAdViewEvent.kt +0 -15
- package/android/src/main/java/com/cloudxreactnative/CloudXBannerViewManagerImpl.kt +0 -472
- package/android/src/main/java/com/cloudxreactnative/CloudXReactNativeModuleImpl.kt +0 -861
- package/android/src/newarch/com/cloudxreactnative/CloudXBannerViewManager.kt +0 -90
- package/android/src/oldarch/com/cloudxreactnative/CloudXBannerViewManager.kt +0 -76
- package/android/src/oldarch/com/cloudxreactnative/CloudXReactNativePackage.kt +0 -16
- package/ios/RNCloudXBannerView.h +0 -51
- package/ios/RNCloudXBannerView.mm +0 -633
- package/ios/RNCloudXBannerViewManager.h +0 -11
- package/ios/RNCloudXBannerViewManager.mm +0 -60
- package/ios/RNCloudXModule.h +0 -30
- package/ios/RNCloudXModule.mm +0 -1088
- package/lib/commonjs/AdView.js +0 -151
- package/lib/commonjs/AdView.js.map +0 -1
- package/lib/commonjs/BannerAd.js.map +0 -1
- package/lib/commonjs/ErrorCode.js +0 -116
- package/lib/commonjs/ErrorCode.js.map +0 -1
- package/lib/commonjs/InterstitialAd.js.map +0 -1
- package/lib/commonjs/MRecAd.js.map +0 -1
- package/lib/commonjs/RewardedAd.js.map +0 -1
- package/lib/commonjs/specs/CloudXAdViewNativeComponent.js +0 -26
- package/lib/commonjs/specs/CloudXAdViewNativeComponent.js.map +0 -1
- package/lib/commonjs/specs/NativeCloudXModule.js.map +0 -1
- package/lib/module/AdView.js +0 -144
- package/lib/module/AdView.js.map +0 -1
- package/lib/module/BannerAd.js.map +0 -1
- package/lib/module/ErrorCode.js +0 -110
- package/lib/module/ErrorCode.js.map +0 -1
- package/lib/module/InterstitialAd.js.map +0 -1
- package/lib/module/MRecAd.js.map +0 -1
- package/lib/module/RewardedAd.js.map +0 -1
- package/lib/module/specs/CloudXAdViewNativeComponent.js +0 -20
- package/lib/module/specs/CloudXAdViewNativeComponent.js.map +0 -1
- package/lib/module/specs/NativeCloudXModule.js.map +0 -1
- package/lib/typescript/src/AdView.d.ts +0 -69
- package/lib/typescript/src/AdView.d.ts.map +0 -1
- package/lib/typescript/src/BannerAd.d.ts +0 -4
- package/lib/typescript/src/BannerAd.d.ts.map +0 -1
- package/lib/typescript/src/ErrorCode.d.ts.map +0 -1
- package/lib/typescript/src/InterstitialAd.d.ts +0 -4
- package/lib/typescript/src/InterstitialAd.d.ts.map +0 -1
- package/lib/typescript/src/MRecAd.d.ts +0 -4
- package/lib/typescript/src/MRecAd.d.ts.map +0 -1
- package/lib/typescript/src/RewardedAd.d.ts +0 -4
- package/lib/typescript/src/RewardedAd.d.ts.map +0 -1
- package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts +0 -61
- package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts.map +0 -1
- package/lib/typescript/src/specs/NativeCloudXModule.d.ts.map +0 -1
- package/src/AdView.tsx +0 -213
- package/src/specs/CloudXAdViewNativeComponent.ts +0 -82
package/README.md
CHANGED
|
@@ -1,1258 +1,632 @@
|
|
|
1
1
|
# CloudX React Native SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/cloudx-react-native)
|
|
4
|
+
|
|
5
|
+
The CloudX React Native SDK enables monetization of your React Native apps with banner, MREC, interstitial, and rewarded ads on iOS and Android. It supports both the New Architecture (Fabric) and the legacy architecture (Paper).
|
|
4
6
|
|
|
5
7
|
## Features
|
|
6
8
|
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
- **All Ad
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **Modern Patterns**: Follows React Native 0.70+ best practices
|
|
9
|
+
- **Cross-Platform**: Full iOS and Android support
|
|
10
|
+
- **Dual Architecture**: Works on both Fabric (New Architecture) and Paper (Legacy)
|
|
11
|
+
- **All Ad Formats**: Banner, MREC, Interstitial, and Rewarded ads
|
|
12
|
+
- **Programmatic Ad APIs**: Overlay APIs for banner and MREC, plus fullscreen formats
|
|
13
|
+
- **React Hooks**: Declarative hooks for fullscreen and banner ad lifecycles
|
|
14
|
+
- **Privacy Compliance**: IAB privacy handled automatically via CMP shared storage
|
|
15
|
+
- **App Tracking Transparency**: Built-in ATT support for iOS 14+
|
|
16
|
+
- **Type Safety**: Full TypeScript definitions with CloudX-prefixed namespace
|
|
16
17
|
|
|
17
18
|
## Installation
|
|
18
19
|
|
|
20
|
+
Requires React Native 0.70+, React 18.0+, iOS 13.0+, and Android API 23+.
|
|
21
|
+
|
|
19
22
|
```bash
|
|
20
23
|
npm install cloudx-react-native
|
|
21
|
-
# or
|
|
22
|
-
yarn add cloudx-react-native
|
|
23
24
|
```
|
|
24
25
|
|
|
25
26
|
### iOS Setup
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
Add ad network adapter pods to your `ios/Podfile`:
|
|
28
29
|
|
|
29
30
|
```ruby
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
target 'YourApp' do
|
|
32
|
+
# ... existing config ...
|
|
32
33
|
|
|
33
|
-
#
|
|
34
|
-
pod 'CloudXMetaAdapter'
|
|
34
|
+
# CloudX ad network adapters (add as needed)
|
|
35
|
+
pod 'CloudXMetaAdapter', '~> 2.2.0-beta'
|
|
36
|
+
pod 'CloudXVungleAdapter', '~> 2.2.0-beta'
|
|
37
|
+
pod 'CloudXInMobiAdapter', '~> 2.2.0-beta'
|
|
38
|
+
pod 'CloudXRenderer', '~> 2.2.0-beta'
|
|
39
|
+
end
|
|
35
40
|
```
|
|
36
41
|
|
|
37
|
-
|
|
42
|
+
Then install pods:
|
|
38
43
|
|
|
39
44
|
```bash
|
|
40
45
|
cd ios && pod install
|
|
41
46
|
```
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
```xml
|
|
46
|
-
<key>NSUserTrackingUsageDescription</key>
|
|
47
|
-
<string>This app uses tracking to provide personalized ads and better user experience.</string>
|
|
48
|
-
|
|
49
|
-
<key>SKAdNetworkItems</key>
|
|
50
|
-
<array>
|
|
51
|
-
<!-- Add your SKAdNetwork IDs -->
|
|
52
|
-
</array>
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Android Setup
|
|
56
|
-
|
|
57
|
-
> ⚠️ **Android support coming soon**
|
|
48
|
+
> **Note:** The `CloudXCore` pod is automatically included as a dependency of the `cloudx-react-native` npm package. You only need to add the adapter pods you want.
|
|
58
49
|
|
|
59
|
-
|
|
50
|
+
#### App Transport Security
|
|
60
51
|
|
|
61
|
-
|
|
52
|
+
If your ads use HTTP URLs, add the following to your `Info.plist`:
|
|
62
53
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const result = await CloudXSDK.initialize({
|
|
70
|
-
appKey: 'YOUR_APP_KEY',
|
|
71
|
-
testMode: false, // false = production, true = test ads
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
if (result.success) {
|
|
75
|
-
console.log('CloudX SDK initialized successfully');
|
|
76
|
-
} else {
|
|
77
|
-
console.error('Failed to initialize CloudX SDK:', result.message);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
// Check if initialized
|
|
82
|
-
const isInitialized = await CloudXSDK.isInitialized();
|
|
54
|
+
```xml
|
|
55
|
+
<key>NSAppTransportSecurity</key>
|
|
56
|
+
<dict>
|
|
57
|
+
<key>NSAllowsArbitraryLoads</key>
|
|
58
|
+
<true/>
|
|
59
|
+
</dict>
|
|
83
60
|
```
|
|
84
61
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
The SDK supports an optional `testMode` parameter:
|
|
88
|
-
|
|
89
|
-
- **Production (`testMode: false`)**: Real ads with actual billing. Use for production releases.
|
|
90
|
-
- **Test Mode (`testMode: true`)**: Test ads without billing. Use for development and QA testing.
|
|
91
|
-
|
|
92
|
-
When `testMode` is enabled:
|
|
93
|
-
- Bid requests include `test=1` flag per OpenRTB spec
|
|
94
|
-
- Adapter SDKs are configured for test mode (e.g., Meta test ads)
|
|
95
|
-
- No real monetization occurs
|
|
96
|
-
|
|
97
|
-
### 2. Using React Hooks (Recommended)
|
|
98
|
-
|
|
99
|
-
```jsx
|
|
100
|
-
import { useCloudXInterstitial, useCloudXRewarded } from 'cloudx-react-native';
|
|
101
|
-
|
|
102
|
-
function GameOverScreen() {
|
|
103
|
-
const interstitial = useCloudXInterstitial({
|
|
104
|
-
placement: 'game-over-interstitial',
|
|
105
|
-
adId: 'interstitial-1',
|
|
106
|
-
onLoaded: (ad) => console.log('Interstitial ready:', ad.placementName),
|
|
107
|
-
onFailed: (error) => console.error('Failed to load:', error),
|
|
108
|
-
onShown: (ad) => console.log('Interstitial shown'),
|
|
109
|
-
onClosed: (ad) => console.log('Interstitial closed'),
|
|
110
|
-
onRevenuePaid: (ad) => console.log('Revenue:', ad.revenue, ad.currency),
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
return (
|
|
114
|
-
<View>
|
|
115
|
-
<Button
|
|
116
|
-
title="Show Interstitial"
|
|
117
|
-
onPress={() => interstitial.show()}
|
|
118
|
-
disabled={!interstitial.isReady || interstitial.isLoading}
|
|
119
|
-
/>
|
|
120
|
-
{interstitial.isLoading && <ActivityIndicator />}
|
|
121
|
-
</View>
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
```
|
|
62
|
+
### Android Setup
|
|
125
63
|
|
|
126
|
-
|
|
64
|
+
Add CloudX SDK and adapter dependencies to your `android/app/build.gradle`:
|
|
127
65
|
|
|
128
|
-
```
|
|
129
|
-
|
|
66
|
+
```kotlin
|
|
67
|
+
dependencies {
|
|
68
|
+
// CloudX Android SDK
|
|
69
|
+
implementation "io.cloudx:sdk:2.0.0"
|
|
130
70
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
<CloudXBannerView
|
|
137
|
-
placement="home-banner"
|
|
138
|
-
adId="banner-1"
|
|
139
|
-
bannerSize={BannerSizes.BANNER}
|
|
140
|
-
autoRefresh={true}
|
|
141
|
-
refreshInterval={30000}
|
|
142
|
-
onAdLoaded={(event) => console.log('Banner loaded:', event.ad)}
|
|
143
|
-
onAdFailedToLoad={(event) => console.error('Banner failed:', event.error)}
|
|
144
|
-
onAdImpression={(event) => trackImpression(event.ad)}
|
|
145
|
-
onRevenuePaid={(event) => trackRevenue(event.ad)}
|
|
146
|
-
style={styles.banner}
|
|
147
|
-
/>
|
|
148
|
-
</View>
|
|
149
|
-
);
|
|
71
|
+
// Adapters for ad networks (add as needed)
|
|
72
|
+
implementation "io.cloudx:adapter-cloudx:2.0.0"
|
|
73
|
+
implementation "io.cloudx:adapter-meta:2.0.0"
|
|
74
|
+
implementation "io.cloudx:adapter-vungle:2.0.0"
|
|
75
|
+
implementation "io.cloudx:adapter-inmobi:2.0.0"
|
|
150
76
|
}
|
|
151
|
-
|
|
152
|
-
const styles = StyleSheet.create({
|
|
153
|
-
banner: {
|
|
154
|
-
width: 320,
|
|
155
|
-
height: 50,
|
|
156
|
-
marginVertical: 10,
|
|
157
|
-
},
|
|
158
|
-
});
|
|
159
77
|
```
|
|
160
78
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
## API Reference
|
|
79
|
+
> **Note:** At least one adapter is required for the SDK to serve ads.
|
|
164
80
|
|
|
165
|
-
|
|
81
|
+
## Initialization
|
|
166
82
|
|
|
167
|
-
|
|
83
|
+
Initialize the SDK before loading any ads:
|
|
168
84
|
|
|
169
|
-
|
|
85
|
+
```typescript
|
|
86
|
+
import { CloudX, CloudXLogLevel } from 'cloudx-react-native';
|
|
170
87
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const result = await CloudXSDK.initialize({
|
|
174
|
-
appKey: 'YOUR_APP_KEY',
|
|
175
|
-
testMode: false, // false = production, true = test ads
|
|
176
|
-
});
|
|
88
|
+
// Optional: enable verbose logging (development only)
|
|
89
|
+
CloudX.setMinLogLevel(CloudXLogLevel.VERBOSE);
|
|
177
90
|
|
|
178
|
-
//
|
|
91
|
+
// Initialize with your app key
|
|
92
|
+
const result = await CloudX.initialize('YOUR_APP_KEY');
|
|
93
|
+
if (result.success) {
|
|
94
|
+
console.log('CloudX initialized');
|
|
95
|
+
} else {
|
|
96
|
+
console.error('CloudX init failed:', result.message);
|
|
97
|
+
}
|
|
179
98
|
```
|
|
180
99
|
|
|
181
|
-
|
|
182
|
-
- `appKey` (string, required): Your CloudX app key
|
|
183
|
-
- `testMode` (boolean, optional): Enable test mode (false = production, true = test ads)
|
|
100
|
+
### Initialization API
|
|
184
101
|
|
|
185
|
-
|
|
102
|
+
| Method | Returns | Description |
|
|
103
|
+
|--------|---------|-------------|
|
|
104
|
+
| `CloudX.initialize(appKey)` | `Promise<CloudXInitializationResult>` | Initialize the SDK with your app key |
|
|
105
|
+
| `CloudX.isInitialized()` | `Promise<boolean>` | Check if the SDK has been initialized |
|
|
106
|
+
| `CloudX.getVersion()` | `Promise<string>` | Get the native SDK version string |
|
|
107
|
+
| `CloudX.isTablet()` | `Promise<boolean>` | Check if the device is a tablet |
|
|
186
108
|
|
|
187
|
-
|
|
109
|
+
The `CloudXInitializationResult` contains:
|
|
110
|
+
- `success: boolean` — whether initialization succeeded
|
|
111
|
+
- `message?: string` — additional details on failure
|
|
188
112
|
|
|
189
|
-
|
|
113
|
+
## Ad Integration
|
|
190
114
|
|
|
191
|
-
|
|
192
|
-
const initialized = await CloudXSDK.isInitialized();
|
|
193
|
-
```
|
|
115
|
+
### Banner Ads (Programmatic Overlay)
|
|
194
116
|
|
|
195
|
-
|
|
117
|
+
Banners overlay your content at a fixed screen position:
|
|
196
118
|
|
|
197
|
-
|
|
119
|
+
```typescript
|
|
120
|
+
import { CloudXBannerAd, CloudXAdPosition } from 'cloudx-react-native';
|
|
198
121
|
|
|
199
|
-
|
|
200
|
-
const version = await CloudXSDK.getVersion();
|
|
201
|
-
console.log('CloudX SDK version:', version);
|
|
202
|
-
```
|
|
122
|
+
const AD_UNIT_ID = 'home_banner';
|
|
203
123
|
|
|
204
|
-
|
|
124
|
+
// Set up event listeners
|
|
125
|
+
CloudXBannerAd.addAdLoadedEventListener((adInfo) => {
|
|
126
|
+
console.log('Banner loaded from', adInfo.networkName);
|
|
127
|
+
});
|
|
128
|
+
CloudXBannerAd.addAdLoadFailedEventListener((error) => {
|
|
129
|
+
console.log('Banner failed:', error.code, error.message);
|
|
130
|
+
});
|
|
131
|
+
CloudXBannerAd.addAdRevenuePaidListener((adInfo) => {
|
|
132
|
+
console.log('Banner revenue:', adInfo.revenue);
|
|
133
|
+
});
|
|
205
134
|
|
|
206
|
-
|
|
135
|
+
// Create and show
|
|
136
|
+
CloudXBannerAd.createAd(AD_UNIT_ID, CloudXAdPosition.BOTTOM_CENTER);
|
|
137
|
+
CloudXBannerAd.showAd(AD_UNIT_ID);
|
|
207
138
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
await CloudXSDK.setLoggingEnabled(true);
|
|
212
|
-
}
|
|
139
|
+
// Hide / destroy when done
|
|
140
|
+
CloudXBannerAd.hideAd(AD_UNIT_ID);
|
|
141
|
+
CloudXBannerAd.destroyAd(AD_UNIT_ID);
|
|
213
142
|
```
|
|
214
143
|
|
|
215
|
-
|
|
144
|
+
Auto-refresh is enabled by default. To control it manually:
|
|
216
145
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
await CloudXSDK.setEnvironment('staging');
|
|
221
|
-
await CloudXSDK.initialize('YOUR_APP_KEY');
|
|
146
|
+
```typescript
|
|
147
|
+
CloudXBannerAd.stopAutoRefresh(AD_UNIT_ID);
|
|
148
|
+
CloudXBannerAd.startAutoRefresh(AD_UNIT_ID);
|
|
222
149
|
```
|
|
223
150
|
|
|
224
|
-
|
|
151
|
+
#### Full Banner API
|
|
225
152
|
|
|
226
|
-
|
|
153
|
+
| Method | Description |
|
|
154
|
+
|--------|-------------|
|
|
155
|
+
| `createAd(adUnitId, position)` | Create a banner at the given `CloudXAdPosition` |
|
|
156
|
+
| `createAdWithOffsets(adUnitId, position, xOffset, yOffset)` | Create with pixel offsets from the position anchor |
|
|
157
|
+
| `showAd(adUnitId)` | Show the banner |
|
|
158
|
+
| `hideAd(adUnitId)` | Hide the banner (preserves the ad) |
|
|
159
|
+
| `destroyAd(adUnitId)` | Destroy the banner and release resources |
|
|
160
|
+
| `updatePosition(adUnitId, position)` | Move to a new `CloudXAdPosition` |
|
|
161
|
+
| `updateOffsets(adUnitId, xOffset, yOffset)` | Update pixel offsets |
|
|
162
|
+
| `setBackgroundColor(adUnitId, hexColor)` | Set banner background color (e.g., `"#000000"`) |
|
|
163
|
+
| `setPlacement(adUnitId, placement)` | Set placement name for reporting |
|
|
164
|
+
| `setCustomData(adUnitId, customData)` | Set custom data string |
|
|
165
|
+
| `startAutoRefresh(adUnitId)` | Resume auto-refresh |
|
|
166
|
+
| `stopAutoRefresh(adUnitId)` | Pause auto-refresh |
|
|
227
167
|
|
|
228
|
-
|
|
168
|
+
#### Banner Events
|
|
229
169
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
170
|
+
| Method | Callback Parameter |
|
|
171
|
+
|--------|--------------------|
|
|
172
|
+
| `addAdLoadedEventListener(fn)` | `CloudXAdInfo` |
|
|
173
|
+
| `addAdLoadFailedEventListener(fn)` | `CloudXAdLoadFailedInfo` |
|
|
174
|
+
| `addAdClickedEventListener(fn)` | `CloudXAdInfo` |
|
|
175
|
+
| `addAdExpandedEventListener(fn)` | `CloudXAdInfo` |
|
|
176
|
+
| `addAdCollapsedEventListener(fn)` | `CloudXAdInfo` |
|
|
177
|
+
| `addAdRevenuePaidListener(fn)` | `CloudXAdInfo` |
|
|
233
178
|
|
|
234
|
-
|
|
235
|
-
const userId = await CloudXSDK.getUserID();
|
|
179
|
+
Each `add*` listener has a corresponding `remove*` method (e.g., `removeAdLoadedEventListener()`).
|
|
236
180
|
|
|
237
|
-
|
|
238
|
-
await CloudXSDK.setUserID(null);
|
|
239
|
-
```
|
|
181
|
+
### MREC Ads (Programmatic Overlay)
|
|
240
182
|
|
|
241
|
-
|
|
183
|
+
MRECs work identically to banners but with a 300x250 size:
|
|
242
184
|
|
|
243
|
-
|
|
185
|
+
```typescript
|
|
186
|
+
import { CloudXMRECAd, CloudXAdPosition } from 'cloudx-react-native';
|
|
244
187
|
|
|
245
|
-
|
|
246
|
-
import { CloudX } from 'cloudx-react-native';
|
|
188
|
+
const AD_UNIT_ID = 'home_mrec';
|
|
247
189
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
CloudX.setUserKeyValue('subscription', 'premium');
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
### App-Level Targeting
|
|
190
|
+
CloudXMRECAd.addAdLoadedEventListener((adInfo) => {
|
|
191
|
+
console.log('MREC loaded from', adInfo.networkName);
|
|
192
|
+
});
|
|
255
193
|
|
|
256
|
-
|
|
194
|
+
CloudXMRECAd.createAd(AD_UNIT_ID, CloudXAdPosition.CENTERED);
|
|
195
|
+
CloudXMRECAd.showAd(AD_UNIT_ID);
|
|
257
196
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
CloudX.setAppKeyValue('app_version', '1.2.0');
|
|
261
|
-
CloudX.setAppKeyValue('build_type', 'release');
|
|
262
|
-
CloudX.setAppKeyValue('theme', 'dark');
|
|
197
|
+
// Destroy when done
|
|
198
|
+
CloudXMRECAd.destroyAd(AD_UNIT_ID);
|
|
263
199
|
```
|
|
264
200
|
|
|
265
|
-
|
|
201
|
+
The MREC API surface is identical to Banner — all the same methods and events are available on `CloudXMRECAd`, including `createAdWithOffsets`, `updatePosition`, `updateOffsets`, `setBackgroundColor`, `setPlacement`, `setCustomData`, auto-refresh control, and all event listeners.
|
|
266
202
|
|
|
267
|
-
|
|
268
|
-
// Clear all targeting key-values
|
|
269
|
-
CloudX.clearAllKeyValues();
|
|
270
|
-
```
|
|
203
|
+
### Interstitial Ads
|
|
271
204
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
## Banner Ads
|
|
275
|
-
|
|
276
|
-
### Using BannerView Component (Recommended)
|
|
277
|
-
|
|
278
|
-
```jsx
|
|
279
|
-
import { CloudXBannerView, BannerSizes } from 'cloudx-react-native';
|
|
280
|
-
|
|
281
|
-
function MyComponent() {
|
|
282
|
-
return (
|
|
283
|
-
<CloudXBannerView
|
|
284
|
-
// Required
|
|
285
|
-
placement="banner-placement"
|
|
286
|
-
adId="banner-1"
|
|
287
|
-
|
|
288
|
-
// Optional
|
|
289
|
-
bannerSize={BannerSizes.BANNER} // BANNER, MREC, LEADERBOARD
|
|
290
|
-
autoRefresh={true}
|
|
291
|
-
refreshInterval={30000} // milliseconds
|
|
292
|
-
|
|
293
|
-
// Event callbacks
|
|
294
|
-
onAdLoaded={(event) => console.log('Banner loaded:', event.ad)}
|
|
295
|
-
onAdFailedToLoad={(event) => console.error('Failed:', event.error)}
|
|
296
|
-
onAdShown={(event) => console.log('Banner shown')}
|
|
297
|
-
onAdImpression={(event) => console.log('Impression tracked')}
|
|
298
|
-
onAdClicked={(event) => console.log('Banner clicked')}
|
|
299
|
-
onAdExpanded={(event) => console.log('Banner expanded')}
|
|
300
|
-
onAdCollapsed={(event) => console.log('Banner collapsed')}
|
|
301
|
-
onRevenuePaid={(event) => console.log('Revenue:', event.ad.revenue)}
|
|
302
|
-
|
|
303
|
-
// Styling
|
|
304
|
-
style={{ width: 320, height: 50 }}
|
|
305
|
-
/>
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
```
|
|
205
|
+
Full-screen ads shown at natural transition points.
|
|
309
206
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
```jsx
|
|
313
|
-
import { useCloudXBanner } from 'cloudx-react-native';
|
|
314
|
-
|
|
315
|
-
function MyComponent() {
|
|
316
|
-
const banner = useCloudXBanner({
|
|
317
|
-
placement: 'banner-placement',
|
|
318
|
-
adId: 'banner-1',
|
|
319
|
-
bannerSize: BannerSizes.BANNER,
|
|
320
|
-
autoRefresh: true,
|
|
321
|
-
onLoaded: (ad) => console.log('Banner ready'),
|
|
322
|
-
onRevenuePaid: (ad) => trackRevenue(ad),
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
return (
|
|
326
|
-
<View>
|
|
327
|
-
{banner.render({ style: styles.banner })}
|
|
328
|
-
{banner.isLoading && <ActivityIndicator />}
|
|
329
|
-
</View>
|
|
330
|
-
);
|
|
331
|
-
}
|
|
332
|
-
```
|
|
207
|
+
```typescript
|
|
208
|
+
import { CloudXInterstitialAd } from 'cloudx-react-native';
|
|
333
209
|
|
|
334
|
-
|
|
210
|
+
const AD_UNIT_ID = 'level_complete';
|
|
335
211
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
212
|
+
// Set up event listeners
|
|
213
|
+
CloudXInterstitialAd.addAdLoadedEventListener((adInfo) => {
|
|
214
|
+
console.log('Interstitial loaded');
|
|
215
|
+
});
|
|
216
|
+
CloudXInterstitialAd.addAdLoadFailedEventListener((error) => {
|
|
217
|
+
console.log('Interstitial load failed:', error.code, error.message);
|
|
218
|
+
});
|
|
219
|
+
CloudXInterstitialAd.addAdDisplayedEventListener((adInfo) => {
|
|
220
|
+
console.log('Interstitial displayed');
|
|
221
|
+
});
|
|
222
|
+
CloudXInterstitialAd.addAdFailedToDisplayEventListener((error) => {
|
|
223
|
+
console.log('Interstitial display failed:', error.code, error.message);
|
|
224
|
+
});
|
|
225
|
+
CloudXInterstitialAd.addAdHiddenEventListener((adInfo) => {
|
|
226
|
+
// Reload for next use
|
|
227
|
+
CloudXInterstitialAd.loadAd(AD_UNIT_ID);
|
|
228
|
+
});
|
|
229
|
+
CloudXInterstitialAd.addAdRevenuePaidListener((adInfo) => {
|
|
230
|
+
console.log('Revenue:', adInfo.revenue);
|
|
342
231
|
});
|
|
343
232
|
|
|
344
|
-
// Load
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
// Show banner (if hidden)
|
|
348
|
-
await CloudXSDK.showBanner({ adId: 'banner-1' });
|
|
349
|
-
|
|
350
|
-
// Hide banner (keeps it loaded)
|
|
351
|
-
await CloudXSDK.hideBanner({ adId: 'banner-1' });
|
|
233
|
+
// Load
|
|
234
|
+
CloudXInterstitialAd.loadAd(AD_UNIT_ID);
|
|
352
235
|
|
|
353
|
-
//
|
|
354
|
-
await
|
|
355
|
-
|
|
236
|
+
// Show when ready (with optional placement and custom data)
|
|
237
|
+
const isReady = await CloudXInterstitialAd.isAdReady(AD_UNIT_ID);
|
|
238
|
+
if (isReady) {
|
|
239
|
+
CloudXInterstitialAd.showAd(AD_UNIT_ID);
|
|
240
|
+
// or with placement/custom data:
|
|
241
|
+
// CloudXInterstitialAd.showAd(AD_UNIT_ID, 'level_end', 'custom_data');
|
|
242
|
+
}
|
|
356
243
|
|
|
357
|
-
// Destroy
|
|
358
|
-
|
|
244
|
+
// Destroy when done
|
|
245
|
+
CloudXInterstitialAd.destroyAd(AD_UNIT_ID);
|
|
359
246
|
```
|
|
360
247
|
|
|
361
|
-
|
|
248
|
+
#### Interstitial API
|
|
362
249
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
```
|
|
250
|
+
| Method | Description |
|
|
251
|
+
|--------|-------------|
|
|
252
|
+
| `loadAd(adUnitId)` | Start loading an interstitial |
|
|
253
|
+
| `isAdReady(adUnitId)` | Returns `Promise<boolean>` — whether an ad is ready to show |
|
|
254
|
+
| `showAd(adUnitId, placement?, customData?)` | Show the loaded interstitial |
|
|
255
|
+
| `destroyAd(adUnitId)` | Destroy the interstitial and release resources |
|
|
370
256
|
|
|
371
|
-
|
|
257
|
+
#### Interstitial Events
|
|
372
258
|
|
|
373
|
-
|
|
259
|
+
| Method | Callback Parameter |
|
|
260
|
+
|--------|--------------------|
|
|
261
|
+
| `addAdLoadedEventListener(fn)` | `CloudXAdInfo` |
|
|
262
|
+
| `addAdLoadFailedEventListener(fn)` | `CloudXAdLoadFailedInfo` |
|
|
263
|
+
| `addAdDisplayedEventListener(fn)` | `CloudXAdInfo` |
|
|
264
|
+
| `addAdFailedToDisplayEventListener(fn)` | `CloudXAdDisplayFailedInfo` |
|
|
265
|
+
| `addAdClickedEventListener(fn)` | `CloudXAdInfo` |
|
|
266
|
+
| `addAdHiddenEventListener(fn)` | `CloudXAdInfo` |
|
|
267
|
+
| `addAdRevenuePaidListener(fn)` | `CloudXAdInfo` |
|
|
374
268
|
|
|
375
|
-
###
|
|
269
|
+
### Rewarded Ads
|
|
376
270
|
|
|
377
|
-
|
|
378
|
-
import { useCloudXInterstitial } from 'cloudx-react-native';
|
|
271
|
+
Full-screen ads that grant users a reward upon completion.
|
|
379
272
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
placement: 'game-over-interstitial',
|
|
383
|
-
adId: 'interstitial-1',
|
|
384
|
-
|
|
385
|
-
// Event callbacks
|
|
386
|
-
onLoaded: (ad) => {
|
|
387
|
-
console.log('Interstitial ready:', ad.placementName);
|
|
388
|
-
setAdReady(true);
|
|
389
|
-
},
|
|
390
|
-
onFailedToLoad: (error) => {
|
|
391
|
-
console.error('Failed to load:', error);
|
|
392
|
-
},
|
|
393
|
-
onShown: (ad) => {
|
|
394
|
-
console.log('Interstitial shown');
|
|
395
|
-
pauseGame();
|
|
396
|
-
},
|
|
397
|
-
onFailedToShow: (error) => {
|
|
398
|
-
console.error('Failed to show:', error);
|
|
399
|
-
},
|
|
400
|
-
onImpression: (ad) => {
|
|
401
|
-
console.log('Impression tracked:', ad.revenue);
|
|
402
|
-
},
|
|
403
|
-
onClosed: (ad) => {
|
|
404
|
-
console.log('Interstitial closed');
|
|
405
|
-
resumeGame();
|
|
406
|
-
},
|
|
407
|
-
onClicked: (ad) => {
|
|
408
|
-
console.log('Interstitial clicked');
|
|
409
|
-
},
|
|
410
|
-
onRevenuePaid: (ad) => {
|
|
411
|
-
console.log('Revenue:', ad.revenue, ad.currency);
|
|
412
|
-
trackRevenue(ad);
|
|
413
|
-
},
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
useEffect(() => {
|
|
417
|
-
// Auto-load on mount
|
|
418
|
-
interstitial.load();
|
|
419
|
-
|
|
420
|
-
// Cleanup on unmount
|
|
421
|
-
return () => {
|
|
422
|
-
interstitial.destroy();
|
|
423
|
-
};
|
|
424
|
-
}, []);
|
|
425
|
-
|
|
426
|
-
return (
|
|
427
|
-
<View>
|
|
428
|
-
<Text>Game Over!</Text>
|
|
429
|
-
<Button
|
|
430
|
-
title="Continue (Watch Ad)"
|
|
431
|
-
onPress={() => interstitial.show()}
|
|
432
|
-
disabled={!interstitial.isReady || interstitial.isShowing}
|
|
433
|
-
/>
|
|
434
|
-
{interstitial.isLoading && <ActivityIndicator />}
|
|
435
|
-
</View>
|
|
436
|
-
);
|
|
437
|
-
}
|
|
438
|
-
```
|
|
273
|
+
```typescript
|
|
274
|
+
import { CloudXRewardedAd } from 'cloudx-react-native';
|
|
439
275
|
|
|
440
|
-
|
|
276
|
+
const AD_UNIT_ID = 'rewarded_coins';
|
|
441
277
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
278
|
+
// Set up event listeners
|
|
279
|
+
CloudXRewardedAd.addAdLoadedEventListener((adInfo) => {
|
|
280
|
+
console.log('Rewarded loaded');
|
|
281
|
+
});
|
|
282
|
+
CloudXRewardedAd.addAdLoadFailedEventListener((error) => {
|
|
283
|
+
console.log('Rewarded load failed:', error.code, error.message);
|
|
284
|
+
});
|
|
285
|
+
CloudXRewardedAd.addAdDisplayedEventListener((adInfo) => {
|
|
286
|
+
console.log('Rewarded displayed');
|
|
287
|
+
});
|
|
288
|
+
CloudXRewardedAd.addAdFailedToDisplayEventListener((error) => {
|
|
289
|
+
console.log('Rewarded display failed:', error.code, error.message);
|
|
290
|
+
});
|
|
291
|
+
CloudXRewardedAd.addAdReceivedRewardEventListener((rewardInfo) => {
|
|
292
|
+
console.log(`Earned ${rewardInfo.rewardAmount} ${rewardInfo.rewardLabel}`);
|
|
293
|
+
});
|
|
294
|
+
CloudXRewardedAd.addAdHiddenEventListener((adInfo) => {
|
|
295
|
+
// Reload for next use
|
|
296
|
+
CloudXRewardedAd.loadAd(AD_UNIT_ID);
|
|
297
|
+
});
|
|
298
|
+
CloudXRewardedAd.addAdRevenuePaidListener((adInfo) => {
|
|
299
|
+
console.log('Revenue:', adInfo.revenue);
|
|
447
300
|
});
|
|
448
301
|
|
|
449
|
-
// Load
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
// Check if ready
|
|
453
|
-
const isReady = await CloudXSDK.isInterstitialReady({ adId: 'interstitial-1' });
|
|
302
|
+
// Load
|
|
303
|
+
CloudXRewardedAd.loadAd(AD_UNIT_ID);
|
|
454
304
|
|
|
455
|
-
// Show
|
|
305
|
+
// Show when ready (with optional placement and custom data)
|
|
306
|
+
const isReady = await CloudXRewardedAd.isAdReady(AD_UNIT_ID);
|
|
456
307
|
if (isReady) {
|
|
457
|
-
|
|
308
|
+
CloudXRewardedAd.showAd(AD_UNIT_ID);
|
|
458
309
|
}
|
|
459
310
|
|
|
460
311
|
// Destroy when done
|
|
461
|
-
|
|
312
|
+
CloudXRewardedAd.destroyAd(AD_UNIT_ID);
|
|
462
313
|
```
|
|
463
314
|
|
|
464
|
-
|
|
315
|
+
#### Rewarded API
|
|
465
316
|
|
|
466
|
-
|
|
317
|
+
| Method | Description |
|
|
318
|
+
|--------|-------------|
|
|
319
|
+
| `loadAd(adUnitId)` | Start loading a rewarded ad |
|
|
320
|
+
| `isAdReady(adUnitId)` | Returns `Promise<boolean>` — whether an ad is ready to show |
|
|
321
|
+
| `showAd(adUnitId, placement?, customData?)` | Show the loaded rewarded ad |
|
|
322
|
+
| `destroyAd(adUnitId)` | Destroy the rewarded ad and release resources |
|
|
467
323
|
|
|
468
|
-
|
|
324
|
+
#### Rewarded Events
|
|
469
325
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
onShown: (ad) => console.log('Showing rewarded ad'),
|
|
481
|
-
onRewardEarned: (ad) => {
|
|
482
|
-
console.log('🎉 User earned reward!');
|
|
483
|
-
grantExtraLife();
|
|
484
|
-
},
|
|
485
|
-
onVideoStarted: (ad) => console.log('Video started'),
|
|
486
|
-
onVideoCompleted: (ad) => console.log('Video completed'),
|
|
487
|
-
onClosed: (ad) => console.log('Rewarded ad closed'),
|
|
488
|
-
onRevenuePaid: (ad) => trackRevenue(ad),
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
useEffect(() => {
|
|
492
|
-
rewarded.load();
|
|
493
|
-
return () => rewarded.destroy();
|
|
494
|
-
}, []);
|
|
495
|
-
|
|
496
|
-
return (
|
|
497
|
-
<Button
|
|
498
|
-
title="Watch Ad for Extra Life"
|
|
499
|
-
onPress={() => rewarded.show()}
|
|
500
|
-
disabled={!rewarded.isReady}
|
|
501
|
-
/>
|
|
502
|
-
);
|
|
503
|
-
}
|
|
504
|
-
```
|
|
326
|
+
| Method | Callback Parameter |
|
|
327
|
+
|--------|--------------------|
|
|
328
|
+
| `addAdLoadedEventListener(fn)` | `CloudXAdInfo` |
|
|
329
|
+
| `addAdLoadFailedEventListener(fn)` | `CloudXAdLoadFailedInfo` |
|
|
330
|
+
| `addAdDisplayedEventListener(fn)` | `CloudXAdInfo` |
|
|
331
|
+
| `addAdFailedToDisplayEventListener(fn)` | `CloudXAdDisplayFailedInfo` |
|
|
332
|
+
| `addAdClickedEventListener(fn)` | `CloudXAdInfo` |
|
|
333
|
+
| `addAdHiddenEventListener(fn)` | `CloudXAdInfo` |
|
|
334
|
+
| `addAdReceivedRewardEventListener(fn)` | `CloudXAdRewardInfo` |
|
|
335
|
+
| `addAdRevenuePaidListener(fn)` | `CloudXAdInfo` |
|
|
505
336
|
|
|
506
|
-
|
|
337
|
+
## React Hooks
|
|
507
338
|
|
|
508
|
-
|
|
509
|
-
// Create rewarded ad
|
|
510
|
-
await CloudXSDK.createRewarded({
|
|
511
|
-
placement: 'rewarded-placement',
|
|
512
|
-
adId: 'rewarded-1',
|
|
513
|
-
});
|
|
339
|
+
The SDK provides React hooks for declarative ad management that handle event subscriptions and cleanup automatically.
|
|
514
340
|
|
|
515
|
-
|
|
516
|
-
await CloudXSDK.loadRewarded({ adId: 'rewarded-1' });
|
|
341
|
+
### useCloudXInterstitial
|
|
517
342
|
|
|
518
|
-
|
|
519
|
-
|
|
343
|
+
```typescript
|
|
344
|
+
import { useCloudXInterstitial } from 'cloudx-react-native';
|
|
520
345
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
}
|
|
346
|
+
function GameScreen() {
|
|
347
|
+
const { isLoaded, isLoading, error, load, show, destroy } =
|
|
348
|
+
useCloudXInterstitial('level_complete');
|
|
525
349
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
(event) => {
|
|
530
|
-
if (event.ad.adId === 'rewarded-1') {
|
|
531
|
-
console.log('User earned reward!');
|
|
532
|
-
grantReward();
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
);
|
|
536
|
-
|
|
537
|
-
// Clean up
|
|
538
|
-
listener.remove();
|
|
539
|
-
await CloudXSDK.destroyAd({ adId: 'rewarded-1' });
|
|
540
|
-
```
|
|
350
|
+
useEffect(() => {
|
|
351
|
+
load();
|
|
352
|
+
}, [load]);
|
|
541
353
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
import { useCloudXNative } from 'cloudx-react-native';
|
|
550
|
-
|
|
551
|
-
function FeedItemAd({ index }) {
|
|
552
|
-
const nativeAd = useCloudXNative({
|
|
553
|
-
placement: 'feed-native',
|
|
554
|
-
adId: `native-${index}`,
|
|
555
|
-
|
|
556
|
-
onLoaded: (ad) => {
|
|
557
|
-
console.log('Native ad loaded:', ad.assets);
|
|
558
|
-
},
|
|
559
|
-
onFailedToLoad: (error) => console.error('Failed:', error),
|
|
560
|
-
onImpression: (ad) => trackImpression(ad),
|
|
561
|
-
onClicked: (ad) => console.log('Native ad clicked'),
|
|
562
|
-
onRevenuePaid: (ad) => trackRevenue(ad),
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
useEffect(() => {
|
|
566
|
-
nativeAd.load();
|
|
567
|
-
return () => nativeAd.destroy();
|
|
568
|
-
}, []);
|
|
569
|
-
|
|
570
|
-
if (!nativeAd.isLoaded || !nativeAd.assets) {
|
|
571
|
-
return null;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
return (
|
|
575
|
-
<View style={styles.nativeAd}>
|
|
576
|
-
{nativeAd.assets.iconUrl && (
|
|
577
|
-
<Image source={{ uri: nativeAd.assets.iconUrl }} style={styles.icon} />
|
|
578
|
-
)}
|
|
579
|
-
<View style={styles.content}>
|
|
580
|
-
<Text style={styles.title}>{nativeAd.assets.title}</Text>
|
|
581
|
-
<Text style={styles.body}>{nativeAd.assets.body}</Text>
|
|
582
|
-
{nativeAd.assets.callToAction && (
|
|
583
|
-
<TouchableOpacity
|
|
584
|
-
style={styles.cta}
|
|
585
|
-
onPress={() => nativeAd.click()}
|
|
586
|
-
>
|
|
587
|
-
<Text style={styles.ctaText}>{nativeAd.assets.callToAction}</Text>
|
|
588
|
-
</TouchableOpacity>
|
|
589
|
-
)}
|
|
590
|
-
</View>
|
|
591
|
-
<Text style={styles.adBadge}>Ad</Text>
|
|
592
|
-
</View>
|
|
593
|
-
);
|
|
354
|
+
return (
|
|
355
|
+
<Button
|
|
356
|
+
title={isLoading ? 'Loading...' : 'Show Ad'}
|
|
357
|
+
onPress={() => show()}
|
|
358
|
+
disabled={!isLoaded}
|
|
359
|
+
/>
|
|
360
|
+
);
|
|
594
361
|
}
|
|
595
362
|
```
|
|
596
363
|
|
|
597
|
-
|
|
364
|
+
Returns `CloudXInterstitialHookResult`:
|
|
365
|
+
- `isLoaded: boolean` — ad is ready to show
|
|
366
|
+
- `isLoading: boolean` — load in progress
|
|
367
|
+
- `error: string | null` — last error message
|
|
368
|
+
- `load()` — start loading
|
|
369
|
+
- `show(placement?, customData?)` — show the loaded ad
|
|
370
|
+
- `destroy()` — destroy and reset state
|
|
598
371
|
|
|
599
|
-
|
|
600
|
-
// Create native ad
|
|
601
|
-
await CloudXSDK.createNative({
|
|
602
|
-
placement: 'native-placement',
|
|
603
|
-
adId: 'native-1',
|
|
604
|
-
});
|
|
372
|
+
### useCloudXRewarded
|
|
605
373
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
// Get native ad assets
|
|
610
|
-
const assets = await CloudXSDK.getNativeAdAssets({ adId: 'native-1' });
|
|
611
|
-
// assets = {
|
|
612
|
-
// title: string,
|
|
613
|
-
// body: string,
|
|
614
|
-
// callToAction: string,
|
|
615
|
-
// iconUrl: string,
|
|
616
|
-
// imageUrl: string,
|
|
617
|
-
// starRating: number,
|
|
618
|
-
// advertiser: string,
|
|
619
|
-
// }
|
|
620
|
-
|
|
621
|
-
// Register view for impression tracking
|
|
622
|
-
await CloudXSDK.registerNativeAdView({ adId: 'native-1' });
|
|
623
|
-
|
|
624
|
-
// Track click
|
|
625
|
-
await CloudXSDK.trackNativeAdClick({ adId: 'native-1' });
|
|
626
|
-
|
|
627
|
-
// Destroy
|
|
628
|
-
await CloudXSDK.destroyAd({ adId: 'native-1' });
|
|
629
|
-
```
|
|
374
|
+
```typescript
|
|
375
|
+
import { useCloudXRewarded } from 'cloudx-react-native';
|
|
630
376
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
bannerSize={BannerSizes.MREC}
|
|
653
|
-
autoRefresh={true}
|
|
654
|
-
onAdLoaded={(event) => console.log('MREC loaded')}
|
|
655
|
-
onRevenuePaid={(event) => trackRevenue(event.ad)}
|
|
656
|
-
style={{ width: 300, height: 250, alignSelf: 'center' }}
|
|
657
|
-
/>
|
|
658
|
-
|
|
659
|
-
<Article />
|
|
660
|
-
<Article />
|
|
661
|
-
</ScrollView>
|
|
662
|
-
);
|
|
377
|
+
function RewardScreen() {
|
|
378
|
+
const { isLoaded, isLoading, error, rewardEarned, load, show } =
|
|
379
|
+
useCloudXRewarded('rewarded_coins');
|
|
380
|
+
|
|
381
|
+
useEffect(() => {
|
|
382
|
+
load();
|
|
383
|
+
}, [load]);
|
|
384
|
+
|
|
385
|
+
useEffect(() => {
|
|
386
|
+
if (rewardEarned) {
|
|
387
|
+
grantCoinsToUser();
|
|
388
|
+
}
|
|
389
|
+
}, [rewardEarned]);
|
|
390
|
+
|
|
391
|
+
return (
|
|
392
|
+
<Button
|
|
393
|
+
title="Watch Ad for Coins"
|
|
394
|
+
onPress={() => show()}
|
|
395
|
+
disabled={!isLoaded}
|
|
396
|
+
/>
|
|
397
|
+
);
|
|
663
398
|
}
|
|
664
399
|
```
|
|
665
400
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
// Banner Events
|
|
676
|
-
CloudXEventTypes.BANNER_LOADED
|
|
677
|
-
CloudXEventTypes.BANNER_FAILED_TO_LOAD
|
|
678
|
-
CloudXEventTypes.BANNER_SHOWN
|
|
679
|
-
CloudXEventTypes.BANNER_FAILED_TO_SHOW
|
|
680
|
-
CloudXEventTypes.BANNER_HIDDEN
|
|
681
|
-
CloudXEventTypes.BANNER_CLICKED
|
|
682
|
-
CloudXEventTypes.BANNER_IMPRESSION
|
|
683
|
-
CloudXEventTypes.BANNER_EXPANDED
|
|
684
|
-
CloudXEventTypes.BANNER_COLLAPSED
|
|
685
|
-
CloudXEventTypes.BANNER_REVENUE_PAID
|
|
686
|
-
|
|
687
|
-
// Interstitial Events
|
|
688
|
-
CloudXEventTypes.INTERSTITIAL_LOADED
|
|
689
|
-
CloudXEventTypes.INTERSTITIAL_FAILED_TO_LOAD
|
|
690
|
-
CloudXEventTypes.INTERSTITIAL_SHOWN
|
|
691
|
-
CloudXEventTypes.INTERSTITIAL_FAILED_TO_SHOW
|
|
692
|
-
CloudXEventTypes.INTERSTITIAL_CLOSED
|
|
693
|
-
CloudXEventTypes.INTERSTITIAL_CLICKED
|
|
694
|
-
CloudXEventTypes.INTERSTITIAL_IMPRESSION
|
|
695
|
-
CloudXEventTypes.INTERSTITIAL_CLOSED_BY_USER
|
|
696
|
-
CloudXEventTypes.INTERSTITIAL_REVENUE_PAID
|
|
697
|
-
|
|
698
|
-
// Rewarded Events
|
|
699
|
-
CloudXEventTypes.REWARDED_LOADED
|
|
700
|
-
CloudXEventTypes.REWARDED_FAILED_TO_LOAD
|
|
701
|
-
CloudXEventTypes.REWARDED_SHOWN
|
|
702
|
-
CloudXEventTypes.REWARDED_FAILED_TO_SHOW
|
|
703
|
-
CloudXEventTypes.REWARDED_CLOSED
|
|
704
|
-
CloudXEventTypes.REWARDED_CLICKED
|
|
705
|
-
CloudXEventTypes.REWARDED_IMPRESSION
|
|
706
|
-
CloudXEventTypes.REWARDED_CLOSED_BY_USER
|
|
707
|
-
CloudXEventTypes.REWARDED_REVENUE_PAID
|
|
708
|
-
CloudXEventTypes.REWARD_EARNED
|
|
709
|
-
CloudXEventTypes.REWARDED_VIDEO_STARTED
|
|
710
|
-
CloudXEventTypes.REWARDED_VIDEO_COMPLETED
|
|
711
|
-
|
|
712
|
-
// Native Events
|
|
713
|
-
CloudXEventTypes.NATIVE_LOADED
|
|
714
|
-
CloudXEventTypes.NATIVE_FAILED_TO_LOAD
|
|
715
|
-
CloudXEventTypes.NATIVE_SHOWN
|
|
716
|
-
CloudXEventTypes.NATIVE_CLICKED
|
|
717
|
-
CloudXEventTypes.NATIVE_IMPRESSION
|
|
718
|
-
CloudXEventTypes.NATIVE_REVENUE_PAID
|
|
719
|
-
```
|
|
720
|
-
|
|
721
|
-
### Using Event Emitter
|
|
401
|
+
Returns `CloudXRewardedHookResult`:
|
|
402
|
+
- `isLoaded: boolean` — ad is ready to show
|
|
403
|
+
- `isLoading: boolean` — load in progress
|
|
404
|
+
- `error: string | null` — last error message
|
|
405
|
+
- `rewardEarned: boolean` — user completed the ad and earned a reward
|
|
406
|
+
- `load()` — start loading
|
|
407
|
+
- `show(placement?, customData?)` — show the loaded ad
|
|
408
|
+
- `destroy()` — destroy and reset state
|
|
722
409
|
|
|
723
|
-
|
|
724
|
-
import CloudXSDK, { CloudXEventTypes } from 'cloudx-react-native';
|
|
410
|
+
### useCloudXBanner
|
|
725
411
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
CloudXEventTypes.INTERSTITIAL_LOADED,
|
|
729
|
-
(event) => {
|
|
730
|
-
console.log('Ad loaded:', event.ad.adId);
|
|
731
|
-
console.log('Placement:', event.ad.placementName);
|
|
732
|
-
}
|
|
733
|
-
);
|
|
412
|
+
```typescript
|
|
413
|
+
import { useCloudXBanner, CloudXBannerAd, CloudXAdPosition } from 'cloudx-react-native';
|
|
734
414
|
|
|
735
|
-
|
|
736
|
-
|
|
415
|
+
function HomeScreen() {
|
|
416
|
+
const { isLoaded, error } = useCloudXBanner('home_banner');
|
|
737
417
|
|
|
738
|
-
|
|
739
|
-
|
|
418
|
+
useEffect(() => {
|
|
419
|
+
CloudXBannerAd.createAd('home_banner', CloudXAdPosition.BOTTOM_CENTER);
|
|
420
|
+
CloudXBannerAd.showAd('home_banner');
|
|
421
|
+
return () => CloudXBannerAd.destroyAd('home_banner');
|
|
422
|
+
}, []);
|
|
740
423
|
|
|
741
|
-
|
|
742
|
-
|
|
424
|
+
return <Text>{isLoaded ? 'Banner showing' : 'Loading banner...'}</Text>;
|
|
425
|
+
}
|
|
743
426
|
```
|
|
744
427
|
|
|
745
|
-
|
|
428
|
+
Returns `CloudXBannerHookResult`:
|
|
429
|
+
- `isLoaded: boolean` — banner has loaded an ad
|
|
430
|
+
- `error: string | null` — last error message
|
|
746
431
|
|
|
747
|
-
|
|
432
|
+
## Types Reference
|
|
748
433
|
|
|
749
|
-
|
|
750
|
-
interface CloudXAdEvent {
|
|
751
|
-
ad?: CloudXAd;
|
|
752
|
-
error?: string;
|
|
753
|
-
timestamp: number;
|
|
754
|
-
}
|
|
434
|
+
### CloudXAdInfo
|
|
755
435
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
436
|
+
Received by most ad event callbacks:
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
type CloudXAdInfo = {
|
|
440
|
+
adUnitId: string;
|
|
441
|
+
adFormat: string; // "BANNER", "MREC", "INTERSTITIAL", "REWARDED"
|
|
442
|
+
networkName: string;
|
|
443
|
+
networkPlacement?: string | null;
|
|
444
|
+
placement?: string | null;
|
|
445
|
+
revenue: number; // USD
|
|
446
|
+
};
|
|
765
447
|
```
|
|
766
448
|
|
|
767
|
-
###
|
|
449
|
+
### CloudXAdLoadFailedInfo
|
|
768
450
|
|
|
769
|
-
|
|
770
|
-
import { useEffect } from 'react';
|
|
771
|
-
import CloudXSDK, { CloudXEventTypes } from 'cloudx-react-native';
|
|
451
|
+
Received by `addAdLoadFailedEventListener`:
|
|
772
452
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
453
|
+
```typescript
|
|
454
|
+
type CloudXAdLoadFailedInfo = {
|
|
455
|
+
adUnitId: string;
|
|
456
|
+
code: CloudXErrorCode;
|
|
457
|
+
message?: string | null;
|
|
458
|
+
};
|
|
459
|
+
```
|
|
779
460
|
|
|
780
|
-
|
|
781
|
-
listener.remove(); // Cleanup on unmount
|
|
782
|
-
};
|
|
783
|
-
}, []);
|
|
461
|
+
### CloudXAdDisplayFailedInfo
|
|
784
462
|
|
|
785
|
-
|
|
786
|
-
console.log('Interstitial ready:', event.ad);
|
|
787
|
-
};
|
|
463
|
+
Received by `addAdFailedToDisplayEventListener`:
|
|
788
464
|
|
|
789
|
-
|
|
790
|
-
|
|
465
|
+
```typescript
|
|
466
|
+
type CloudXAdDisplayFailedInfo = CloudXAdInfo & {
|
|
467
|
+
code: CloudXErrorCode;
|
|
468
|
+
message?: string | null;
|
|
469
|
+
};
|
|
791
470
|
```
|
|
792
471
|
|
|
793
|
-
|
|
472
|
+
### CloudXAdRewardInfo
|
|
794
473
|
|
|
795
|
-
|
|
474
|
+
Received by `addAdReceivedRewardEventListener`:
|
|
796
475
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
const ErrorCodes = {
|
|
802
|
-
NO_FILL: 'NO_FILL', // No ad available
|
|
803
|
-
TIMEOUT: 'TIMEOUT', // Request timed out
|
|
804
|
-
NETWORK_ERROR: 'NETWORK_ERROR', // Network issue
|
|
805
|
-
INVALID_PLACEMENT: 'INVALID_PLACEMENT', // Placement not configured
|
|
806
|
-
SDK_NOT_INITIALIZED: 'SDK_NOT_INITIALIZED', // Must initialize first
|
|
807
|
-
AD_NOT_READY: 'AD_NOT_READY', // Ad not loaded yet
|
|
808
|
-
AD_ALREADY_SHOWN: 'AD_ALREADY_SHOWN', // Ad already displayed
|
|
809
|
-
INVALID_AD_ID: 'INVALID_AD_ID', // Ad ID not found
|
|
476
|
+
```typescript
|
|
477
|
+
type CloudXAdRewardInfo = CloudXAdInfo & {
|
|
478
|
+
rewardLabel?: string | null;
|
|
479
|
+
rewardAmount: number;
|
|
810
480
|
};
|
|
811
481
|
```
|
|
812
482
|
|
|
813
|
-
###
|
|
814
|
-
|
|
815
|
-
```javascript
|
|
816
|
-
// Try-catch for async methods
|
|
817
|
-
try {
|
|
818
|
-
await CloudXSDK.loadInterstitial({ adId: 'interstitial-1' });
|
|
819
|
-
} catch (error) {
|
|
820
|
-
if (error.code === 'NO_FILL') {
|
|
821
|
-
console.log('No ad available, continue without ad');
|
|
822
|
-
} else if (error.code === 'NETWORK_ERROR') {
|
|
823
|
-
console.log('Network error, retry later');
|
|
824
|
-
setTimeout(() => retry(), 5000);
|
|
825
|
-
} else {
|
|
826
|
-
console.error('Unexpected error:', error);
|
|
827
|
-
}
|
|
828
|
-
}
|
|
483
|
+
### CloudXAdPosition
|
|
829
484
|
|
|
830
|
-
|
|
831
|
-
CloudXSDK.addEventListener(
|
|
832
|
-
CloudXEventTypes.INTERSTITIAL_FAILED_TO_LOAD,
|
|
833
|
-
(event) => {
|
|
834
|
-
console.error('Failed to load ad:', event.error);
|
|
835
|
-
|
|
836
|
-
// Handle specific errors
|
|
837
|
-
switch (event.error) {
|
|
838
|
-
case 'NO_FILL':
|
|
839
|
-
// Show alternative content
|
|
840
|
-
break;
|
|
841
|
-
case 'TIMEOUT':
|
|
842
|
-
// Retry with longer timeout
|
|
843
|
-
break;
|
|
844
|
-
default:
|
|
845
|
-
// Generic error handling
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
);
|
|
849
|
-
```
|
|
485
|
+
Position constants for programmatic banner and MREC placement:
|
|
850
486
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
// Check if SDK is initialized
|
|
857
|
-
const initialized = await CloudXSDK.isInitialized();
|
|
858
|
-
if (!initialized) {
|
|
859
|
-
throw new Error('SDK not initialized');
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
// Check if ad is ready
|
|
863
|
-
const isReady = await CloudXSDK.isInterstitialReady({ adId });
|
|
864
|
-
if (!isReady) {
|
|
865
|
-
console.log('Ad not ready, loading...');
|
|
866
|
-
await CloudXSDK.loadInterstitial({ adId });
|
|
867
|
-
// Wait for load event before showing
|
|
868
|
-
return;
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
// Show the ad
|
|
872
|
-
await CloudXSDK.showInterstitial({ adId });
|
|
873
|
-
} catch (error) {
|
|
874
|
-
console.error('Error showing interstitial:', error);
|
|
875
|
-
// Continue app flow without ad
|
|
876
|
-
}
|
|
487
|
+
```typescript
|
|
488
|
+
enum CloudXAdPosition {
|
|
489
|
+
TOP_LEFT, TOP_CENTER, TOP_RIGHT,
|
|
490
|
+
CENTER_LEFT, CENTERED, CENTER_RIGHT,
|
|
491
|
+
BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT,
|
|
877
492
|
}
|
|
878
493
|
```
|
|
879
494
|
|
|
880
|
-
|
|
495
|
+
## Advanced Features
|
|
881
496
|
|
|
882
|
-
|
|
497
|
+
### Error Handling
|
|
883
498
|
|
|
884
|
-
|
|
499
|
+
All error callbacks receive an object with `code` and `message` properties:
|
|
885
500
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
501
|
+
| Range | Category | Common Codes |
|
|
502
|
+
|-------|----------|--------------|
|
|
503
|
+
| 0 | General | `internalError` |
|
|
504
|
+
| 100-199 | Network | `networkError`, `networkTimeout`, `networkNoConnection` |
|
|
505
|
+
| 200-299 | Initialization | `notInitialized`, `sdkDisabled`, `invalidAppKey` |
|
|
506
|
+
| 300-399 | Ad Loading | `noFill`, `invalidAdUnit`, `adsDisabled` |
|
|
507
|
+
| 400-499 | Display | `adNotReady`, `adAlreadyShowing` |
|
|
508
|
+
| 600-699 | Adapter | `adapterNoFill`, `adapterTimeout` |
|
|
892
509
|
|
|
893
|
-
|
|
894
|
-
placement: 'level-complete',
|
|
895
|
-
adId: 'level-2-interstitial',
|
|
896
|
-
});
|
|
510
|
+
See `CloudXErrorCode` export for the full list of error codes.
|
|
897
511
|
|
|
898
|
-
|
|
899
|
-
await CloudXSDK.loadInterstitial({ adId: 'level-1-interstitial' });
|
|
900
|
-
await CloudXSDK.loadInterstitial({ adId: 'level-2-interstitial' });
|
|
901
|
-
```
|
|
512
|
+
### Revenue Tracking
|
|
902
513
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
```javascript
|
|
906
|
-
// Preload ads early for better UX
|
|
907
|
-
async function preloadAds() {
|
|
908
|
-
// Preload interstitial
|
|
909
|
-
await CloudXSDK.createInterstitial({
|
|
910
|
-
placement: 'game-over',
|
|
911
|
-
adId: 'preloaded-interstitial',
|
|
912
|
-
});
|
|
913
|
-
await CloudXSDK.loadInterstitial({ adId: 'preloaded-interstitial' });
|
|
914
|
-
|
|
915
|
-
// Preload rewarded
|
|
916
|
-
await CloudXSDK.createRewarded({
|
|
917
|
-
placement: 'extra-life',
|
|
918
|
-
adId: 'preloaded-rewarded',
|
|
919
|
-
});
|
|
920
|
-
await CloudXSDK.loadRewarded({ adId: 'preloaded-rewarded' });
|
|
921
|
-
}
|
|
514
|
+
All ad formats provide revenue callbacks. The `CloudXAdInfo` object includes `revenue` (USD) and `networkName`:
|
|
922
515
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
}
|
|
516
|
+
```typescript
|
|
517
|
+
CloudXInterstitialAd.addAdRevenuePaidListener((adInfo) => {
|
|
518
|
+
trackRevenue(adInfo.revenue, adInfo.networkName, adInfo.adUnitId);
|
|
519
|
+
});
|
|
927
520
|
```
|
|
928
521
|
|
|
929
|
-
###
|
|
930
|
-
|
|
931
|
-
```javascript
|
|
932
|
-
// Implement your own frequency capping
|
|
933
|
-
class AdFrequencyCapper {
|
|
934
|
-
constructor(maxAdsPerHour = 5) {
|
|
935
|
-
this.maxAdsPerHour = maxAdsPerHour;
|
|
936
|
-
this.adTimestamps = [];
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
canShowAd() {
|
|
940
|
-
const oneHourAgo = Date.now() - 60 * 60 * 1000;
|
|
941
|
-
this.adTimestamps = this.adTimestamps.filter(ts => ts > oneHourAgo);
|
|
942
|
-
return this.adTimestamps.length < this.maxAdsPerHour;
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
recordAdShown() {
|
|
946
|
-
this.adTimestamps.push(Date.now());
|
|
947
|
-
}
|
|
948
|
-
}
|
|
522
|
+
### User Targeting
|
|
949
523
|
|
|
950
|
-
|
|
524
|
+
```typescript
|
|
525
|
+
import { CloudX } from 'cloudx-react-native';
|
|
951
526
|
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
console.log('Ad frequency cap reached');
|
|
955
|
-
return;
|
|
956
|
-
}
|
|
527
|
+
// Set hashed user ID
|
|
528
|
+
CloudX.setHashedUserID('hashed-user-id');
|
|
957
529
|
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
} catch (error) {
|
|
962
|
-
console.error('Failed to show ad:', error);
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
```
|
|
530
|
+
// Set custom key-value pairs
|
|
531
|
+
CloudX.setUserKeyValue('age_group', '25-34');
|
|
532
|
+
CloudX.setAppKeyValue('app_version', '1.0.0');
|
|
966
533
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
```javascript
|
|
970
|
-
// Track revenue from all ad types
|
|
971
|
-
CloudXSDK.addEventListener(
|
|
972
|
-
CloudXEventTypes.INTERSTITIAL_REVENUE_PAID,
|
|
973
|
-
(event) => trackRevenue(event.ad)
|
|
974
|
-
);
|
|
975
|
-
|
|
976
|
-
CloudXSDK.addEventListener(
|
|
977
|
-
CloudXEventTypes.REWARDED_REVENUE_PAID,
|
|
978
|
-
(event) => trackRevenue(event.ad)
|
|
979
|
-
);
|
|
980
|
-
|
|
981
|
-
CloudXSDK.addEventListener(
|
|
982
|
-
CloudXEventTypes.BANNER_REVENUE_PAID,
|
|
983
|
-
(event) => trackRevenue(event.ad)
|
|
984
|
-
);
|
|
985
|
-
|
|
986
|
-
function trackRevenue(ad: CloudXAd) {
|
|
987
|
-
if (ad.revenue && ad.currency) {
|
|
988
|
-
// Send to analytics
|
|
989
|
-
Analytics.logRevenue({
|
|
990
|
-
amount: ad.revenue,
|
|
991
|
-
currency: ad.currency,
|
|
992
|
-
adNetwork: ad.network,
|
|
993
|
-
adType: ad.adType,
|
|
994
|
-
placement: ad.placementName,
|
|
995
|
-
});
|
|
996
|
-
|
|
997
|
-
console.log(
|
|
998
|
-
`💰 Revenue: ${ad.currency} ${ad.revenue} from ${ad.network}`
|
|
999
|
-
);
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
534
|
+
// Clear all custom key-values
|
|
535
|
+
CloudX.clearAllKeyValues();
|
|
1002
536
|
```
|
|
1003
537
|
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
## React Hooks API
|
|
1007
|
-
|
|
1008
|
-
### useCloudXInterstitial
|
|
538
|
+
### App Tracking Transparency (iOS)
|
|
1009
539
|
|
|
1010
540
|
```typescript
|
|
1011
|
-
|
|
1012
|
-
placement: string;
|
|
1013
|
-
adId: string;
|
|
1014
|
-
onLoaded?: (ad: CloudXAd) => void;
|
|
1015
|
-
onFailedToLoad?: (error: string) => void;
|
|
1016
|
-
onShown?: (ad: CloudXAd) => void;
|
|
1017
|
-
onFailedToShow?: (error: string) => void;
|
|
1018
|
-
onClosed?: (ad: CloudXAd) => void;
|
|
1019
|
-
onClicked?: (ad: CloudXAd) => void;
|
|
1020
|
-
onImpression?: (ad: CloudXAd) => void;
|
|
1021
|
-
onRevenuePaid?: (ad: CloudXAd) => void;
|
|
1022
|
-
autoLoad?: boolean; // Default: false
|
|
1023
|
-
}
|
|
541
|
+
import { requestTrackingAuthorization, getTrackingAuthorizationStatus, CloudXATTStatus } from 'cloudx-react-native';
|
|
1024
542
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
isShowing: boolean;
|
|
1029
|
-
error: string | null;
|
|
1030
|
-
load: () => Promise<void>;
|
|
1031
|
-
show: () => Promise<void>;
|
|
1032
|
-
destroy: () => Promise<void>;
|
|
543
|
+
const status = await requestTrackingAuthorization();
|
|
544
|
+
if (status === CloudXATTStatus.AUTHORIZED) {
|
|
545
|
+
console.log('Tracking authorized');
|
|
1033
546
|
}
|
|
1034
|
-
|
|
1035
|
-
const interstitial = useCloudXInterstitial(options);
|
|
1036
547
|
```
|
|
1037
548
|
|
|
1038
|
-
|
|
549
|
+
> **Note:** Call `requestTrackingAuthorization()` before `CloudX.initialize()` for best ad targeting results.
|
|
1039
550
|
|
|
1040
|
-
|
|
1041
|
-
interface UseRewardedOptions extends UseInterstitialOptions {
|
|
1042
|
-
onRewardEarned?: (ad: CloudXAd) => void;
|
|
1043
|
-
onVideoStarted?: (ad: CloudXAd) => void;
|
|
1044
|
-
onVideoCompleted?: (ad: CloudXAd) => void;
|
|
1045
|
-
}
|
|
551
|
+
ATT status values: `AUTHORIZED`, `DENIED`, `RESTRICTED`, `NOT_DETERMINED`, `NOT_REQUIRED`.
|
|
1046
552
|
|
|
1047
|
-
|
|
1048
|
-
// Same as interstitial
|
|
1049
|
-
}
|
|
553
|
+
On Android or iOS < 14, `requestTrackingAuthorization()` returns `NOT_REQUIRED`.
|
|
1050
554
|
|
|
1051
|
-
|
|
1052
|
-
```
|
|
555
|
+
### Test Mode
|
|
1053
556
|
|
|
1054
|
-
|
|
557
|
+
Test mode is **server-controlled** via device whitelisting:
|
|
1055
558
|
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
adId: string;
|
|
1060
|
-
bannerSize?: BannerSize;
|
|
1061
|
-
autoRefresh?: boolean;
|
|
1062
|
-
refreshInterval?: number;
|
|
1063
|
-
onLoaded?: (ad: CloudXAd) => void;
|
|
1064
|
-
onFailedToLoad?: (error: string) => void;
|
|
1065
|
-
onShown?: (ad: CloudXAd) => void;
|
|
1066
|
-
onImpression?: (ad: CloudXAd) => void;
|
|
1067
|
-
onClicked?: (ad: CloudXAd) => void;
|
|
1068
|
-
onRevenuePaid?: (ad: CloudXAd) => void;
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
interface UseBannerResult {
|
|
1072
|
-
isLoaded: boolean;
|
|
1073
|
-
isVisible: boolean;
|
|
1074
|
-
error: string | null;
|
|
1075
|
-
render: (props?: ViewProps) => React.ReactElement;
|
|
1076
|
-
show: () => Promise<void>;
|
|
1077
|
-
hide: () => Promise<void>;
|
|
1078
|
-
destroy: () => Promise<void>;
|
|
1079
|
-
}
|
|
559
|
+
1. Initialize the SDK with verbose logging enabled
|
|
560
|
+
2. Find your device advertising ID in the console logs
|
|
561
|
+
3. Add the device to your whitelist on the CloudX dashboard
|
|
1080
562
|
|
|
1081
|
-
|
|
1082
|
-
```
|
|
1083
|
-
|
|
1084
|
-
### useCloudXNative
|
|
563
|
+
### Debug Logging
|
|
1085
564
|
|
|
1086
565
|
```typescript
|
|
1087
|
-
|
|
1088
|
-
placement: string;
|
|
1089
|
-
adId: string;
|
|
1090
|
-
onLoaded?: (ad: CloudXAd) => void;
|
|
1091
|
-
onFailedToLoad?: (error: string) => void;
|
|
1092
|
-
onImpression?: (ad: CloudXAd) => void;
|
|
1093
|
-
onClicked?: (ad: CloudXAd) => void;
|
|
1094
|
-
onRevenuePaid?: (ad: CloudXAd) => void;
|
|
1095
|
-
}
|
|
566
|
+
import { CloudX, CloudXLogLevel } from 'cloudx-react-native';
|
|
1096
567
|
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
assets: NativeAdAssets | null;
|
|
1100
|
-
error: string | null;
|
|
1101
|
-
load: () => Promise<void>;
|
|
1102
|
-
click: () => Promise<void>;
|
|
1103
|
-
destroy: () => Promise<void>;
|
|
1104
|
-
}
|
|
568
|
+
// Enable verbose logging (call before initialize)
|
|
569
|
+
CloudX.setMinLogLevel(CloudXLogLevel.VERBOSE);
|
|
1105
570
|
|
|
1106
|
-
|
|
571
|
+
// Available levels: VERBOSE, DEBUG, INFO, WARN, ERROR, NONE
|
|
1107
572
|
```
|
|
1108
573
|
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
## TypeScript Support
|
|
574
|
+
### Visual Debugging
|
|
1112
575
|
|
|
1113
|
-
|
|
576
|
+
Enable visual debugging overlays to see ad unit boundaries and network info:
|
|
1114
577
|
|
|
1115
578
|
```typescript
|
|
1116
|
-
|
|
1117
|
-
CloudXAd,
|
|
1118
|
-
CloudXAdEvent,
|
|
1119
|
-
CloudXEventTypes,
|
|
1120
|
-
BannerSizes,
|
|
1121
|
-
CloudXBannerView,
|
|
1122
|
-
useCloudXInterstitial,
|
|
1123
|
-
useCloudXRewarded,
|
|
1124
|
-
useCloudXBanner,
|
|
1125
|
-
useCloudXNative,
|
|
1126
|
-
} from 'cloudx-react-native';
|
|
1127
|
-
|
|
1128
|
-
// All types are exported and fully documented
|
|
579
|
+
CloudX.setVisualDebuggingEnabled(true);
|
|
1129
580
|
```
|
|
1130
581
|
|
|
1131
|
-
---
|
|
1132
|
-
|
|
1133
582
|
## Platform Support
|
|
1134
583
|
|
|
1135
584
|
| Platform | Status | Minimum Version |
|
|
1136
585
|
|----------|--------|-----------------|
|
|
1137
|
-
| iOS |
|
|
1138
|
-
| Android |
|
|
586
|
+
| iOS | Supported | iOS 13.0+ |
|
|
587
|
+
| Android | Supported | API 23+ |
|
|
1139
588
|
|
|
1140
589
|
### Requirements
|
|
1141
590
|
|
|
1142
|
-
#### iOS
|
|
1143
|
-
- iOS 14.0 or higher
|
|
1144
|
-
- CocoaPods
|
|
1145
|
-
- Xcode 13.0+
|
|
1146
|
-
|
|
1147
|
-
#### Android
|
|
1148
|
-
- Android API 21 (Android 5.0) or higher
|
|
1149
|
-
- Gradle 8.0+
|
|
1150
|
-
- Kotlin 1.8+
|
|
1151
|
-
|
|
1152
|
-
#### React Native
|
|
1153
591
|
- React Native 0.70+
|
|
1154
592
|
- React 18.0+
|
|
1155
|
-
- TypeScript 4.5+ (
|
|
593
|
+
- TypeScript 4.5+ (recommended)
|
|
594
|
+
- Xcode 14.0+ / CocoaPods (iOS)
|
|
595
|
+
- Gradle 8.0+ / Kotlin 1.8+ (Android)
|
|
1156
596
|
|
|
1157
|
-
|
|
597
|
+
### Native SDK Versions (2.0.0)
|
|
1158
598
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
```javascript
|
|
1164
|
-
// Make sure to await initialization with explicit testMode
|
|
1165
|
-
const result = await CloudXSDK.initialize({
|
|
1166
|
-
appKey: 'YOUR_APP_KEY',
|
|
1167
|
-
testMode: false, // Explicit for production
|
|
1168
|
-
});
|
|
1169
|
-
if (!result.success) {
|
|
1170
|
-
console.error('Initialization failed:', result.message);
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
// Check iOS setup
|
|
1174
|
-
// 1. Verify CloudXCore pod is installed
|
|
1175
|
-
// 2. Run `pod install` in ios/ directory
|
|
1176
|
-
// 3. Check Info.plist has required permissions
|
|
1177
|
-
```
|
|
1178
|
-
|
|
1179
|
-
### Ads Not Loading
|
|
1180
|
-
|
|
1181
|
-
```javascript
|
|
1182
|
-
// 1. Check SDK is initialized
|
|
1183
|
-
const initialized = await CloudXSDK.isInitialized();
|
|
1184
|
-
|
|
1185
|
-
// 2. Enable logging to see detailed errors
|
|
1186
|
-
await CloudXSDK.setLoggingEnabled(true);
|
|
1187
|
-
|
|
1188
|
-
// 3. Check placement is configured in CloudX dashboard
|
|
599
|
+
| Platform | Dependency | Version |
|
|
600
|
+
|----------|-----------|---------|
|
|
601
|
+
| iOS | CloudXCore | ~> 2.2.0-beta |
|
|
602
|
+
| Android | io.cloudx:sdk | 2.0.0 |
|
|
1189
603
|
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
// 5. Check for error events
|
|
1193
|
-
CloudXSDK.addEventListener(
|
|
1194
|
-
CloudXEventTypes.INTERSTITIAL_FAILED_TO_LOAD,
|
|
1195
|
-
(event) => console.error('Load error:', event.error)
|
|
1196
|
-
);
|
|
1197
|
-
```
|
|
604
|
+
## Troubleshooting
|
|
1198
605
|
|
|
1199
|
-
###
|
|
1200
|
-
|
|
1201
|
-
```javascript
|
|
1202
|
-
// Always destroy ads when done
|
|
1203
|
-
useEffect(() => {
|
|
1204
|
-
return () => {
|
|
1205
|
-
CloudXSDK.destroyAd({ adId: 'my-ad' });
|
|
1206
|
-
};
|
|
1207
|
-
}, []);
|
|
1208
|
-
|
|
1209
|
-
// Remove event listeners
|
|
1210
|
-
useEffect(() => {
|
|
1211
|
-
const listener = CloudXSDK.addEventListener(...);
|
|
1212
|
-
return () => listener.remove();
|
|
1213
|
-
}, []);
|
|
1214
|
-
```
|
|
606
|
+
### React Native 0.84.0 — TurboModuleRegistry crash
|
|
1215
607
|
|
|
1216
|
-
|
|
608
|
+
React Native 0.84.0 has a known issue where `TurboModuleRegistry.getEnforcing(...)` fails with:
|
|
1217
609
|
|
|
1218
|
-
|
|
610
|
+
> `TurboModuleRegistry.getEnforcing(...): 'PlatformConstants' could not be found. Verify that a module by this name is registered in the native binary.`
|
|
1219
611
|
|
|
1220
|
-
|
|
612
|
+
This is a React Native framework bug, not a CloudX SDK issue. It manifests as a red screen crash on app launch:
|
|
1221
613
|
|
|
1222
|
-
|
|
1223
|
-
# Run example app
|
|
1224
|
-
cd example
|
|
1225
|
-
npm install
|
|
1226
|
-
cd ios && pod install && cd ..
|
|
1227
|
-
npm run ios
|
|
1228
|
-
```
|
|
614
|
+

|
|
1229
615
|
|
|
1230
|
-
|
|
616
|
+
**Workaround:** Use React Native 0.83.x or wait for the fix in a later 0.84.x patch release. The CloudX SDK is fully compatible with RN 0.70 through 0.83.
|
|
1231
617
|
|
|
1232
618
|
## Documentation
|
|
1233
619
|
|
|
1234
|
-
- **[
|
|
1235
|
-
- **[
|
|
1236
|
-
- **[iOS Integration Guide](https://docs.cloudx.io/ios)**: CloudX iOS SDK documentation
|
|
1237
|
-
|
|
1238
|
-
---
|
|
620
|
+
- **[Integration Guide](https://docs.cloudx.io/en/react-native/integration)**: Complete integration documentation
|
|
621
|
+
- **[Changelog](https://docs.cloudx.io/en/react-native/changelog)**: Release history
|
|
1239
622
|
|
|
1240
623
|
## Support
|
|
1241
624
|
|
|
1242
|
-
For
|
|
1243
|
-
|
|
1244
|
-
- 📧 **Email**: support@cloudx.io
|
|
1245
|
-
- 🐛 **Issues**: [GitHub Issues](https://github.com/cloudx-io/cloudx-react-native/issues)
|
|
1246
|
-
- 📚 **Docs**: [docs.cloudx.io](https://docs.cloudx.io)
|
|
625
|
+
For support, contact mobile@cloudx.io
|
|
1247
626
|
|
|
1248
|
-
|
|
627
|
+
- Email: mobile@cloudx.io
|
|
628
|
+
- Issues: [GitHub Issues](https://github.com/cloudx-io/cloudx-react-native/issues)
|
|
1249
629
|
|
|
1250
630
|
## License
|
|
1251
631
|
|
|
1252
|
-
This project is licensed under the Elastic License 2.0
|
|
1253
|
-
|
|
1254
|
-
---
|
|
1255
|
-
|
|
1256
|
-
## Changelog
|
|
1257
|
-
|
|
1258
|
-
See [RELEASES](https://github.com/cloudx-io/cloudx-react-native/releases) for detailed changelog and version history.
|
|
632
|
+
This project is licensed under the Elastic License 2.0 — see the [LICENSE](LICENSE) file for details.
|