teads-react-native 6.0.2

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.
Files changed (175) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +93 -0
  3. package/android/bin/build/generated/source/buildConfig/debug/com/outbrainreactnative/BuildConfig.class +0 -0
  4. package/android/bin/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/AndroidManifest.xml +7 -0
  5. package/android/bin/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/output-metadata.json +18 -0
  6. package/android/bin/build/intermediates/aar_metadata/debug/aar-metadata.properties +6 -0
  7. package/android/bin/build/intermediates/annotation_processor_list/debug/annotationProcessors.json +1 -0
  8. package/android/bin/build/intermediates/compile_library_classes_jar/debug/classes.jar +0 -0
  9. package/android/bin/build/intermediates/compile_r_class_jar/debug/R.jar +0 -0
  10. package/android/bin/build/intermediates/compile_symbol_list/debug/R.txt +0 -0
  11. package/android/bin/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -0
  12. package/android/bin/build/intermediates/incremental/debug/packageDebugResources/merger.xml +2 -0
  13. package/android/bin/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +2 -0
  14. package/android/bin/build/intermediates/incremental/mergeDebugShaders/merger.xml +2 -0
  15. package/android/bin/build/intermediates/incremental/packageDebugAssets/merger.xml +2 -0
  16. package/android/bin/build/intermediates/local_only_symbol_list/debug/R-def.txt +2 -0
  17. package/android/bin/build/intermediates/manifest_merge_blame_file/debug/manifest-merger-blame-debug-report.txt +7 -0
  18. package/android/bin/build/intermediates/merged_manifest/debug/AndroidManifest.xml +7 -0
  19. package/android/bin/build/intermediates/navigation_json/debug/navigation.json +1 -0
  20. package/android/bin/build/intermediates/runtime_library_classes_jar/debug/classes.jar +0 -0
  21. package/android/bin/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt +1 -0
  22. package/android/bin/build/outputs/logs/manifest-merger-debug-report.txt +16 -0
  23. package/android/bin/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  24. package/android/bin/build.gradle +101 -0
  25. package/android/bin/gradle/wrapper/gradle-wrapper.jar +0 -0
  26. package/android/bin/gradle/wrapper/gradle-wrapper.properties +7 -0
  27. package/android/bin/gradle.properties +5 -0
  28. package/android/bin/gradlew +249 -0
  29. package/android/bin/gradlew.bat +92 -0
  30. package/android/bin/src/main/AndroidManifest.xml +3 -0
  31. package/android/bin/src/main/AndroidManifestNew.xml +2 -0
  32. package/android/bin/src/main/java/com/outbrainreactnative/OutbrainNativePackage.class +0 -0
  33. package/android/bin/src/main/java/com/outbrainreactnative/SFWebViewWidgetManager.class +0 -0
  34. package/android/bin/src/main/java/com/outbrainreactnative/SFWebViewWidgetWrapper.class +0 -0
  35. package/android/bin/src/main/java/com/outbrainreactnative/Utils.class +0 -0
  36. package/android/build.gradle +129 -0
  37. package/android/generated/java/com/facebook/react/viewmanagers/TeadsAdPlacementFeedManagerDelegate.java +62 -0
  38. package/android/generated/java/com/facebook/react/viewmanagers/TeadsAdPlacementFeedManagerInterface.java +28 -0
  39. package/android/generated/java/com/facebook/react/viewmanagers/TeadsAdPlacementMediaManagerDelegate.java +44 -0
  40. package/android/generated/java/com/facebook/react/viewmanagers/TeadsAdPlacementMediaManagerInterface.java +22 -0
  41. package/android/generated/jni/CMakeLists.txt +36 -0
  42. package/android/generated/jni/RNTeadsReactNativeViewSpec-generated.cpp +22 -0
  43. package/android/generated/jni/RNTeadsReactNativeViewSpec.h +24 -0
  44. package/android/generated/jni/react/renderer/components/RNTeadsReactNativeViewSpec/ComponentDescriptors.cpp +23 -0
  45. package/android/generated/jni/react/renderer/components/RNTeadsReactNativeViewSpec/ComponentDescriptors.h +25 -0
  46. package/android/generated/jni/react/renderer/components/RNTeadsReactNativeViewSpec/EventEmitters.cpp +17 -0
  47. package/android/generated/jni/react/renderer/components/RNTeadsReactNativeViewSpec/EventEmitters.h +30 -0
  48. package/android/generated/jni/react/renderer/components/RNTeadsReactNativeViewSpec/Props.cpp +46 -0
  49. package/android/generated/jni/react/renderer/components/RNTeadsReactNativeViewSpec/Props.h +51 -0
  50. package/android/generated/jni/react/renderer/components/RNTeadsReactNativeViewSpec/RNTeadsReactNativeViewSpecJSI-generated.cpp +17 -0
  51. package/android/generated/jni/react/renderer/components/RNTeadsReactNativeViewSpec/RNTeadsReactNativeViewSpecJSI.h +19 -0
  52. package/android/generated/jni/react/renderer/components/RNTeadsReactNativeViewSpec/ShadowNodes.cpp +18 -0
  53. package/android/generated/jni/react/renderer/components/RNTeadsReactNativeViewSpec/ShadowNodes.h +43 -0
  54. package/android/generated/jni/react/renderer/components/RNTeadsReactNativeViewSpec/States.cpp +16 -0
  55. package/android/generated/jni/react/renderer/components/RNTeadsReactNativeViewSpec/States.h +41 -0
  56. package/android/gradle.properties +5 -0
  57. package/android/src/main/AndroidManifest.xml +3 -0
  58. package/android/src/main/AndroidManifestNew.xml +2 -0
  59. package/android/src/main/java/tv/teads/reactnative/SFWidgetContainer.java +19 -0
  60. package/android/src/main/java/tv/teads/reactnative/TeadsAdPlacementFeedManager.java +109 -0
  61. package/android/src/main/java/tv/teads/reactnative/TeadsFeedPackage.java +53 -0
  62. package/android/src/main/java/tv/teads/reactnative/TeadsMediaPlacementManager.java +76 -0
  63. package/android/src/main/java/tv/teads/reactnative/TeadsPlacementContainer.java +327 -0
  64. package/android/src/main/java/tv/teads/reactnative/Utils.java +65 -0
  65. package/ios/RCTTeadsAdPlacementFeed.h +22 -0
  66. package/ios/RCTTeadsAdPlacementFeed.mm +114 -0
  67. package/ios/RCTTeadsAdPlacementMedia.h +23 -0
  68. package/ios/RCTTeadsAdPlacementMedia.mm +91 -0
  69. package/ios/TeadsAdContainer.swift +212 -0
  70. package/ios/TeadsEventModule.h +16 -0
  71. package/ios/TeadsEventModule.mm +52 -0
  72. package/ios/TeadsReactNative.h +8 -0
  73. package/ios/generated/RNTeadsReactNativeViewSpec/ComponentDescriptors.cpp +23 -0
  74. package/ios/generated/RNTeadsReactNativeViewSpec/ComponentDescriptors.h +25 -0
  75. package/ios/generated/RNTeadsReactNativeViewSpec/EventEmitters.cpp +17 -0
  76. package/ios/generated/RNTeadsReactNativeViewSpec/EventEmitters.h +30 -0
  77. package/ios/generated/RNTeadsReactNativeViewSpec/Props.cpp +46 -0
  78. package/ios/generated/RNTeadsReactNativeViewSpec/Props.h +51 -0
  79. package/ios/generated/RNTeadsReactNativeViewSpec/RCTComponentViewHelpers.h +24 -0
  80. package/ios/generated/RNTeadsReactNativeViewSpec/RNTeadsReactNativeViewSpec-generated.mm +16 -0
  81. package/ios/generated/RNTeadsReactNativeViewSpec/RNTeadsReactNativeViewSpec.h +38 -0
  82. package/ios/generated/RNTeadsReactNativeViewSpec/ShadowNodes.cpp +18 -0
  83. package/ios/generated/RNTeadsReactNativeViewSpec/ShadowNodes.h +43 -0
  84. package/ios/generated/RNTeadsReactNativeViewSpec/States.cpp +16 -0
  85. package/ios/generated/RNTeadsReactNativeViewSpec/States.h +41 -0
  86. package/ios/generated/RNTeadsReactNativeViewSpecJSI-generated.cpp +17 -0
  87. package/ios/generated/RNTeadsReactNativeViewSpecJSI.h +19 -0
  88. package/lib/commonjs/DefaultTeadsWidgetHandler.js +21 -0
  89. package/lib/commonjs/DefaultTeadsWidgetHandler.js.map +1 -0
  90. package/lib/commonjs/TeadsAdPlacementFeed.js +131 -0
  91. package/lib/commonjs/TeadsAdPlacementFeed.js.map +1 -0
  92. package/lib/commonjs/TeadsAdPlacementMedia.js +115 -0
  93. package/lib/commonjs/TeadsAdPlacementMedia.js.map +1 -0
  94. package/lib/commonjs/TeadsInAppBrowser.js +48 -0
  95. package/lib/commonjs/TeadsInAppBrowser.js.map +1 -0
  96. package/lib/commonjs/TeadsMediaNativeComponent.ts +15 -0
  97. package/lib/commonjs/WebViewNativeComponent.ts +21 -0
  98. package/lib/commonjs/constants.js +9 -0
  99. package/lib/commonjs/constants.js.map +1 -0
  100. package/lib/commonjs/index.js +20 -0
  101. package/lib/commonjs/index.js.map +1 -0
  102. package/lib/commonjs/package.json +1 -0
  103. package/lib/commonjs/types.d.js +2 -0
  104. package/lib/commonjs/types.d.js.map +1 -0
  105. package/lib/commonjs/version.js +8 -0
  106. package/lib/commonjs/version.js.map +1 -0
  107. package/lib/module/DefaultTeadsWidgetHandler.js +17 -0
  108. package/lib/module/DefaultTeadsWidgetHandler.js.map +1 -0
  109. package/lib/module/TeadsAdPlacementFeed.js +126 -0
  110. package/lib/module/TeadsAdPlacementFeed.js.map +1 -0
  111. package/lib/module/TeadsAdPlacementMedia.js +110 -0
  112. package/lib/module/TeadsAdPlacementMedia.js.map +1 -0
  113. package/lib/module/TeadsInAppBrowser.js +44 -0
  114. package/lib/module/TeadsInAppBrowser.js.map +1 -0
  115. package/lib/module/TeadsMediaNativeComponent.ts +15 -0
  116. package/lib/module/WebViewNativeComponent.ts +21 -0
  117. package/lib/module/constants.js +5 -0
  118. package/lib/module/constants.js.map +1 -0
  119. package/lib/module/index.js +5 -0
  120. package/lib/module/index.js.map +1 -0
  121. package/lib/module/package.json +1 -0
  122. package/lib/module/types.d.js +2 -0
  123. package/lib/module/types.d.js.map +1 -0
  124. package/lib/module/version.js +4 -0
  125. package/lib/module/version.js.map +1 -0
  126. package/lib/typescript/commonjs/package.json +1 -0
  127. package/lib/typescript/commonjs/src/DefaultTeadsWidgetHandler.d.ts +4 -0
  128. package/lib/typescript/commonjs/src/DefaultTeadsWidgetHandler.d.ts.map +1 -0
  129. package/lib/typescript/commonjs/src/TeadsAdPlacementFeed.d.ts +3 -0
  130. package/lib/typescript/commonjs/src/TeadsAdPlacementFeed.d.ts.map +1 -0
  131. package/lib/typescript/commonjs/src/TeadsAdPlacementMedia.d.ts +3 -0
  132. package/lib/typescript/commonjs/src/TeadsAdPlacementMedia.d.ts.map +1 -0
  133. package/lib/typescript/commonjs/src/TeadsInAppBrowser.d.ts +4 -0
  134. package/lib/typescript/commonjs/src/TeadsInAppBrowser.d.ts.map +1 -0
  135. package/lib/typescript/commonjs/src/TeadsMediaNativeComponent.d.ts +12 -0
  136. package/lib/typescript/commonjs/src/TeadsMediaNativeComponent.d.ts.map +1 -0
  137. package/lib/typescript/commonjs/src/WebViewNativeComponent.d.ts +18 -0
  138. package/lib/typescript/commonjs/src/WebViewNativeComponent.d.ts.map +1 -0
  139. package/lib/typescript/commonjs/src/constants.d.ts +3 -0
  140. package/lib/typescript/commonjs/src/constants.d.ts.map +1 -0
  141. package/lib/typescript/commonjs/src/index.d.ts +4 -0
  142. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  143. package/lib/typescript/commonjs/src/version.d.ts +2 -0
  144. package/lib/typescript/commonjs/src/version.d.ts.map +1 -0
  145. package/lib/typescript/module/package.json +1 -0
  146. package/lib/typescript/module/src/DefaultTeadsWidgetHandler.d.ts +4 -0
  147. package/lib/typescript/module/src/DefaultTeadsWidgetHandler.d.ts.map +1 -0
  148. package/lib/typescript/module/src/TeadsAdPlacementFeed.d.ts +3 -0
  149. package/lib/typescript/module/src/TeadsAdPlacementFeed.d.ts.map +1 -0
  150. package/lib/typescript/module/src/TeadsAdPlacementMedia.d.ts +3 -0
  151. package/lib/typescript/module/src/TeadsAdPlacementMedia.d.ts.map +1 -0
  152. package/lib/typescript/module/src/TeadsInAppBrowser.d.ts +4 -0
  153. package/lib/typescript/module/src/TeadsInAppBrowser.d.ts.map +1 -0
  154. package/lib/typescript/module/src/TeadsMediaNativeComponent.d.ts +12 -0
  155. package/lib/typescript/module/src/TeadsMediaNativeComponent.d.ts.map +1 -0
  156. package/lib/typescript/module/src/WebViewNativeComponent.d.ts +18 -0
  157. package/lib/typescript/module/src/WebViewNativeComponent.d.ts.map +1 -0
  158. package/lib/typescript/module/src/constants.d.ts +3 -0
  159. package/lib/typescript/module/src/constants.d.ts.map +1 -0
  160. package/lib/typescript/module/src/index.d.ts +4 -0
  161. package/lib/typescript/module/src/index.d.ts.map +1 -0
  162. package/lib/typescript/module/src/version.d.ts +2 -0
  163. package/lib/typescript/module/src/version.d.ts.map +1 -0
  164. package/package.json +227 -0
  165. package/src/DefaultTeadsWidgetHandler.ts +17 -0
  166. package/src/TeadsAdPlacementFeed.tsx +142 -0
  167. package/src/TeadsAdPlacementMedia.tsx +127 -0
  168. package/src/TeadsInAppBrowser.ts +42 -0
  169. package/src/TeadsMediaNativeComponent.ts +15 -0
  170. package/src/WebViewNativeComponent.ts +21 -0
  171. package/src/constants.ts +11 -0
  172. package/src/index.tsx +9 -0
  173. package/src/types.d.ts +32 -0
  174. package/src/version.ts +1 -0
  175. package/teads-react-native.podspec +42 -0
@@ -0,0 +1,327 @@
1
+ package tv.teads.reactnative;
2
+
3
+ import android.annotation.SuppressLint;
4
+ import android.graphics.Rect;
5
+ import android.net.Uri;
6
+ import android.util.Log;
7
+ import android.view.View;
8
+ import android.view.ViewGroup;
9
+ import android.view.ViewTreeObserver;
10
+ import android.widget.FrameLayout;
11
+
12
+ import androidx.annotation.NonNull;
13
+ import androidx.annotation.Nullable;
14
+
15
+ import com.facebook.react.bridge.Arguments;
16
+ import com.facebook.react.bridge.ReactContext;
17
+ import com.facebook.react.bridge.ReadableMap;
18
+ import com.facebook.react.bridge.WritableMap;
19
+ import com.facebook.react.modules.core.DeviceEventManagerModule;
20
+ import com.facebook.react.uimanager.ThemedReactContext;
21
+ import com.facebook.react.views.view.ReactViewGroup;
22
+
23
+ import java.util.Map;
24
+
25
+ import tv.teads.sdk.AdRatio;
26
+ import tv.teads.sdk.TeadsSDK;
27
+ import tv.teads.sdk.combinedsdk.TeadsAdPlacementEventName;
28
+ import tv.teads.sdk.combinedsdk.adplacement.TeadsAdPlacementFeed;
29
+ import tv.teads.sdk.combinedsdk.adplacement.TeadsAdPlacementMedia;
30
+ import tv.teads.sdk.combinedsdk.adplacement.config.TeadsAdPlacementFeedConfig;
31
+ import tv.teads.sdk.combinedsdk.adplacement.config.TeadsAdPlacementMediaConfig;
32
+ import tv.teads.sdk.combinedsdk.adplacement.interfaces.TeadsAdPlacementEventsDelegate;
33
+ import tv.teads.sdk.combinedsdk.adplacement.interfaces.core.TeadsAdPlacement;
34
+ import tv.teads.sdk.framework.WrapperFrameworkInfo;
35
+
36
+
37
+ @SuppressLint("ViewConstructor")
38
+ public class TeadsPlacementContainer extends ReactViewGroup implements TeadsAdPlacementEventsDelegate {
39
+ /**
40
+ * this class has two main functions:
41
+ * 1. connect the React Native native view interface with the Teads ad view
42
+ * 2. implement event handling and propagating the events up to RN
43
+ **/
44
+
45
+ TeadsAdPlacementFeed teadsAdPlacementFeed;
46
+ TeadsAdPlacementMedia teadsAdPlacementMedia;
47
+ FrameLayout widgetLayout;
48
+ ReactContext context;
49
+ String widgetId;
50
+ String pid;
51
+ Uri articleUrl;
52
+ int widgetRandomId;
53
+ boolean isTeadsVideoPlacement = false;
54
+ private volatile boolean isCleanedUp = false;
55
+
56
+ private final WritableMap initParams = Arguments.createMap();
57
+
58
+ public TeadsPlacementContainer(ReactContext context) {
59
+ super(context);
60
+ this.context = context;
61
+ setBackgroundColor(android.graphics.Color.TRANSPARENT);
62
+ configureComponent();
63
+ }
64
+
65
+ private void configureComponent() {
66
+ this.setLayoutParams(new ViewGroup.LayoutParams(
67
+ ViewGroup.LayoutParams.MATCH_PARENT,
68
+ ViewGroup.LayoutParams.MATCH_PARENT
69
+ ));
70
+ }
71
+
72
+ public void initialize(ReadableMap args) {
73
+ this.isTeadsVideoPlacement = args.hasKey("pid");
74
+ Log.i("TeadsFeedContainer", "inside initialize(): " + (isTeadsVideoPlacement ? "Teads Video Placement" : "Teads Feed Placement"));
75
+ if (!this.isTeadsVideoPlacement && teadsAdPlacementFeed == null) {
76
+ initializeTeadsFeedPlacement(args);
77
+ } else if (this.isTeadsVideoPlacement && teadsAdPlacementMedia == null) {
78
+ initializeTeadsVideoPlacement(args);
79
+ } else {
80
+ Log.d("TeadsFeedContainer", "Widget already exists — skipping creation");
81
+ }
82
+ }
83
+
84
+ private void initializeTeadsFeedPlacement(ReadableMap args) {
85
+ if (teadsAdPlacementFeed == null) {
86
+ Log.i("TeadsFeedContainer", "Initializing Feed placement with params: " + args.toString());
87
+ this.widgetId = args.getString("widgetId");
88
+ int widgetIndex = args.getInt("widgetIndex");
89
+ this.widgetRandomId = args.getInt("widgetRandomId");
90
+ String articleUrlString = args.getString("articleUrl");
91
+ this.articleUrl = Uri.parse(articleUrlString);
92
+ String installationKey = args.getString("partnerKey");
93
+ boolean darkMode = args.hasKey("darkMode") && args.getBoolean("darkMode");
94
+ String extId = args.hasKey("extId") ? args.getString("extId") : null;
95
+ String extSecondaryId = args.hasKey("extSecondaryId") ? args.getString("extSecondaryId") : null;
96
+ String pubImpId = args.hasKey("pubImpId") ? args.getString("pubImpId") : null;
97
+ String RN_packageVersion = args.getString("packageVersion");
98
+
99
+ initTeadsSDK(installationKey);
100
+ TeadsAdPlacementFeedConfig feedConfig = new TeadsAdPlacementFeedConfig(
101
+ this.articleUrl,
102
+ this.widgetId,
103
+ installationKey,
104
+ widgetIndex, // TODO: currently 2 widgets on the same page can work only if widgetIndex is 0 for both (that's a bug in the SDK)
105
+ null, // userId
106
+ darkMode, // darkMode
107
+ false, // testDisplay
108
+ extId, // extId
109
+ extSecondaryId, // extSecondaryId
110
+ pubImpId // obPubImpl
111
+ );
112
+ teadsAdPlacementFeed = new TeadsAdPlacementFeed(context, feedConfig,this);
113
+ this.widgetLayout = teadsAdPlacementFeed.loadAd();
114
+ commonSetupLayout();
115
+ }
116
+ }
117
+
118
+ private void initializeTeadsVideoPlacement(ReadableMap args) {
119
+ if (teadsAdPlacementMedia == null) {
120
+ try {
121
+ Log.i("TeadsFeedContainer", "Initializing Video placement widget with params: " + args.toString());
122
+ this.pid = args.getString("pid");
123
+ this.widgetRandomId = args.getInt("widgetRandomId");
124
+ String articleUrlString = args.getString("articleUrl");
125
+ this.articleUrl = Uri.parse(articleUrlString);
126
+ String installationKey = args.getString("partnerKey");
127
+ String RN_packageVersion = args.getString("packageVersion");
128
+
129
+ // TeadsSDK.INSTANCE.setTestMode(true);
130
+ TeadsSDK.INSTANCE.setWrapperFrameworkInfo(WrapperFrameworkInfo.reactNative(RN_packageVersion));
131
+
132
+ TeadsAdPlacementMediaConfig mediaConfig = new TeadsAdPlacementMediaConfig(
133
+ Integer.parseInt(this.pid), // test video ad placement ID
134
+ this.articleUrl,
135
+ false
136
+ );
137
+ teadsAdPlacementMedia = new TeadsAdPlacementMedia(context, mediaConfig, this);
138
+ this.widgetLayout = teadsAdPlacementMedia.loadAd();
139
+ commonSetupLayout();
140
+ } catch (Exception e) {
141
+ Log.e("TeadsFeedContainer", "Exception in initializeTeadsVideoPlacement: " + e.getLocalizedMessage());
142
+ }
143
+ }
144
+ }
145
+
146
+ private void commonSetupLayout() {
147
+ this.widgetLayout.setLayoutParams(new ViewGroup.LayoutParams(
148
+ LayoutParams.MATCH_PARENT,
149
+ ViewGroup.LayoutParams.WRAP_CONTENT
150
+ ));
151
+
152
+ post(() -> {
153
+ addView(this.widgetLayout);
154
+ this.widgetLayout.requestLayout();
155
+ requestLayout();
156
+ });
157
+ }
158
+
159
+ private void initTeadsSDK(String installationKey) {
160
+ try {
161
+ TeadsSDK.INSTANCE.configure(this.context.getApplicationContext(), installationKey);
162
+ if (BuildConfig.DEBUG) {
163
+ TeadsSDK.INSTANCE.setTestMode(true);
164
+ }
165
+ } catch (Exception e) {
166
+ Log.e("TeadsFeedContainer", "Error configuring TeadsSDK: " + e.getMessage());
167
+ }
168
+ }
169
+
170
+ public void emitEvent(String eventName, ReadableMap params) {
171
+ context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
172
+ .emit(eventName, params);
173
+ }
174
+
175
+ @Override
176
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
177
+ // Layout the child view
178
+ if (this.widgetLayout != null) {
179
+ this.widgetLayout.layout(0, 0, getWidth(), getHeight());
180
+ }
181
+ }
182
+
183
+ @Override
184
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
185
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
186
+ if (this.widgetLayout != null) {
187
+ this.widgetLayout.measure(widthMeasureSpec, heightMeasureSpec);
188
+ }
189
+ }
190
+
191
+ @Override
192
+ public void requestLayout() {
193
+ super.requestLayout();
194
+ post(() -> {
195
+ measure(
196
+ MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
197
+ MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY)
198
+ );
199
+ layout(getLeft(), getTop(), getRight(), getBottom());
200
+ });
201
+ }
202
+
203
+ public void toggleDarkMode(boolean darkMode) {
204
+ if (this.teadsAdPlacementFeed != null) {
205
+ this.teadsAdPlacementFeed.toggleDarkMode(darkMode);
206
+ } else {
207
+ Log.w("TeadsFeedContainer", "Widget is not initialized, cannot toggle dark mode");
208
+ }
209
+ }
210
+
211
+ public WritableMap getInitParams() {
212
+ return initParams;
213
+ }
214
+
215
+ /**
216
+ * Clean up resources when the view is detached from the window
217
+ */
218
+ @Override
219
+ protected void onDetachedFromWindow() {
220
+ super.onDetachedFromWindow();
221
+ Log.d("TeadsFeedContainer", "onDetachedFromWindow() - widgetRandomId: " + widgetRandomId);
222
+ cleanup();
223
+ }
224
+
225
+ @Override
226
+ protected void onWindowVisibilityChanged(int visibility) {
227
+ super.onWindowVisibilityChanged(visibility);
228
+ // When the window becomes invisible (GONE or INVISIBLE), the SDK should stop visibility checks
229
+ Log.d("TeadsFeedContainer", "onWindowVisibilityChanged() - visibility: " + visibility + ", widgetRandomId: " + widgetRandomId);
230
+ }
231
+
232
+
233
+ @Override
234
+ protected void onAttachedToWindow() {
235
+ super.onAttachedToWindow();
236
+ Log.d("TeadsFeedContainer", "onAttachedToWindow() - widgetRandomId: " + widgetRandomId);
237
+ if (widgetLayout != null) {
238
+ widgetLayout.requestLayout();
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Clean up TeadsSDK placements and resources
244
+ */
245
+ public void cleanup() {
246
+ Log.d("TeadsFeedContainer", "cleanup() called - widgetRandomId: " + widgetRandomId);
247
+ isCleanedUp = true;
248
+
249
+ // Clean up SDK placements first (this stops internal polling/visibility tracking)
250
+ if (teadsAdPlacementMedia != null) {
251
+ teadsAdPlacementMedia.clean();
252
+ teadsAdPlacementMedia = null;
253
+ }
254
+ if (teadsAdPlacementFeed != null) {
255
+ // TeadsAdPlacementFeed doesn't have a clean() method
256
+ teadsAdPlacementFeed = null;
257
+ }
258
+
259
+ // Remove the widget layout to break SDK's internal references
260
+ if (widgetLayout != null) {
261
+ widgetLayout.removeAllViews();
262
+ removeView(widgetLayout);
263
+ widgetLayout = null;
264
+ }
265
+
266
+ // Remove all child views from this container
267
+ removeAllViews();
268
+
269
+ widgetRandomId = -1;
270
+ widgetId = null;
271
+ pid = null;
272
+ articleUrl = null;
273
+ }
274
+
275
+ @Override
276
+ public void onPlacementEvent(@NonNull TeadsAdPlacement<?, ?> teadsAdPlacement, @NonNull TeadsAdPlacementEventName teadsAdPlacementEventName, @Nullable Map<String, ?> map) {
277
+ // Guard against events after cleanup
278
+ if (isCleanedUp) {
279
+ Log.d("TeadsFeedContainer", "Ignoring event after cleanup: " + teadsAdPlacementEventName.name());
280
+ return;
281
+ }
282
+ if (teadsAdPlacementEventName == TeadsAdPlacementEventName.CLICKED) {
283
+ Log.d("TeadsFeedContainer", "Teads Ad Placement Clicked - widgetId: " + widgetId);
284
+ WritableMap params = Arguments.createMap();
285
+ String url = map != null && map.get("url") instanceof String ? (String) map.get("url") : "";
286
+ emitClickEvent("onRecClick", url);
287
+ } else if (teadsAdPlacementEventName == TeadsAdPlacementEventName.CLICKED_ORGANIC) {
288
+ Log.d("TeadsFeedContainer", "Teads Ad Placement Clicked Organic - widgetId: " + widgetId);
289
+ WritableMap params = Arguments.createMap();
290
+ String url = map != null && map.get("url") instanceof String ? (String) map.get("url") : "";
291
+ // prepare JS parameters to send with the event
292
+ emitClickEvent("onOrganicClick", url);
293
+ } else if (teadsAdPlacementEventName == TeadsAdPlacementEventName.HEIGHT_UPDATED) {
294
+ Log.d("TeadsFeedContainer", "Teads Ad Placement Height Updated; map: " + (map != null ? map.toString() : "null"));
295
+ int newHeight = 0;
296
+ if (map != null && map.get("adRatio") instanceof AdRatio) {
297
+ AdRatio adRatio = (AdRatio) map.get("adRatio");
298
+ int widthDP = (int)(this.widgetLayout.getWidth() / getResources().getDisplayMetrics().density);
299
+ newHeight = adRatio.calculateHeight(widthDP);
300
+ Log.d("TeadsFeedContainer", "Teads Ad Placement Height Updated - ad ratio: calculateHeight: " + newHeight + ", width: " + widthDP + ", widgetId: " + widgetId);
301
+ }
302
+ if (map != null && map.get("height") instanceof Integer) {
303
+ newHeight = (Integer) map.get("height");
304
+ Log.d("TeadsFeedContainer", "Teads Ad Placement Height Updated - new height: " + newHeight + ", widgetId: " + widgetId);
305
+ }
306
+ if (newHeight > 0) {
307
+ WritableMap params = Arguments.createMap();
308
+ params.putString("widgetId", widgetId);
309
+ params.putInt("widgetRandomId", widgetRandomId);
310
+ params.putInt("height", newHeight);
311
+ emitEvent("didChangeHeight", params);
312
+ }
313
+ } else {
314
+ Log.d("TeadsFeedContainer", "Teads Ad Placement Event: " + teadsAdPlacementEventName.name() + ", params: " + (map != null ? map.toString() : "null"));
315
+ }
316
+
317
+ }
318
+
319
+ private void emitClickEvent(String eventName, String clickUrl) {
320
+ WritableMap params = Arguments.createMap();
321
+ params.putString("widgetId", widgetId);
322
+ params.putInt("widgetRandomId", widgetRandomId);
323
+ params.putString("url", clickUrl);
324
+ emitEvent(eventName, params);
325
+ }
326
+ }
327
+
@@ -0,0 +1,65 @@
1
+ package tv.teads.reactnative;
2
+
3
+ import com.facebook.react.bridge.Arguments;
4
+ import com.facebook.react.bridge.WritableArray;
5
+ import com.facebook.react.bridge.WritableMap;
6
+ import com.google.gson.Gson;
7
+ import com.google.gson.reflect.TypeToken;
8
+
9
+ import org.json.JSONObject;
10
+
11
+ import java.util.List;
12
+ import java.util.Map;
13
+
14
+ public class Utils {
15
+ public static WritableMap convertJsonObjectToWritableMap(JSONObject jsonObject) {
16
+ Gson gson = new Gson();
17
+ Map<String, Object> map = gson.fromJson(jsonObject.toString(), new TypeToken<Map<String, Object>>(){}.getType());
18
+ return convertMapToWritableMap(map);
19
+ }
20
+ private static WritableMap convertMapToWritableMap(Map<String, Object> map) {
21
+ WritableMap writableMap = Arguments.createMap();
22
+ for (Map.Entry<String, Object> entry : map.entrySet()) {
23
+ String key = entry.getKey();
24
+ Object value = entry.getValue();
25
+ if (value instanceof Boolean) {
26
+ writableMap.putBoolean(key, (Boolean) value);
27
+ } else if (value instanceof Integer) {
28
+ writableMap.putInt(key, (Integer) value);
29
+ } else if (value instanceof Double) {
30
+ writableMap.putDouble(key, (Double) value);
31
+ } else if (value instanceof String) {
32
+ writableMap.putString(key, (String) value);
33
+ } else if (value instanceof Map) {
34
+ writableMap.putMap(key, convertMapToWritableMap((Map<String, Object>) value));
35
+ } else if (value instanceof List) {
36
+ writableMap.putArray(key, convertListToWritableArray((List) value));
37
+ } else if (value == null) {
38
+ writableMap.putNull(key);
39
+ }
40
+ }
41
+ return writableMap;
42
+ }
43
+
44
+ private static WritableArray convertListToWritableArray(List list) {
45
+ WritableArray writableArray = Arguments.createArray();
46
+ for (Object item : list) {
47
+ if (item instanceof Boolean) {
48
+ writableArray.pushBoolean((Boolean) item);
49
+ } else if (item instanceof Integer) {
50
+ writableArray.pushInt((Integer) item);
51
+ } else if (item instanceof Double) {
52
+ writableArray.pushDouble((Double) item);
53
+ } else if (item instanceof String) {
54
+ writableArray.pushString((String) item);
55
+ } else if (item instanceof Map) {
56
+ writableArray.pushMap(convertMapToWritableMap((Map<String, Object>) item));
57
+ } else if (item instanceof List<?>) {
58
+ writableArray.pushArray(convertListToWritableArray((List) item));
59
+ } else if (item == null) {
60
+ writableArray.pushNull();
61
+ }
62
+ }
63
+ return writableArray;
64
+ }
65
+ }
@@ -0,0 +1,22 @@
1
+ //
2
+ // RCTTeadsAdPlacementFeed.h
3
+ // TeadsReactNative
4
+ //
5
+ // Created by Ofek Cohen on 03/04/2025.
6
+ //
7
+
8
+ #import <UIKit/UIKit.h>
9
+ #import <React/RCTViewComponentView.h>
10
+ #import <React/RCTComponent.h>
11
+
12
+
13
+ NS_ASSUME_NONNULL_BEGIN
14
+
15
+ @interface RCTTeadsAdPlacementFeed : RCTViewComponentView
16
+
17
+ // You would declare native methods you'd want to access from the view here
18
+
19
+ @end
20
+
21
+ NS_ASSUME_NONNULL_END
22
+
@@ -0,0 +1,114 @@
1
+ //
2
+ // RCTTeadsAdPlacementFeed.mm
3
+ // TeadsReactNative
4
+ //
5
+ // Created by Ofek Cohen on 03/04/2025.
6
+ //
7
+
8
+ #import "RCTTeadsAdPlacementFeed.h"
9
+ #import "RCTAppDelegate.h"
10
+ #import <WebKit/WebKit.h>
11
+ #import "TeadsSDK/TeadsSDK-Swift.h"
12
+
13
+ #import "TeadsReactNative-Swift.h" // auto-generated file that enables the Objective-C code to use the Swift code.
14
+
15
+ #import "generated/RNTeadsReactNativeViewSpec/ComponentDescriptors.h"
16
+ #import "generated/RNTeadsReactNativeViewSpec/EventEmitters.h"
17
+ #import "generated/RNTeadsReactNativeViewSpec/Props.h"
18
+ #import "generated/RNTeadsReactNativeViewSpec/RCTComponentViewHelpers.h"
19
+
20
+ using namespace facebook::react;
21
+
22
+ @interface RCTTeadsAdPlacementFeed ()
23
+ @end
24
+
25
+ @implementation RCTTeadsAdPlacementFeed {
26
+ TeadsAdContainer *widgetView;
27
+ BOOL _initialPropsSet;
28
+ }
29
+
30
+
31
+ - (instancetype)init {
32
+ if (self = [super init]) {
33
+ _initialPropsSet = NO;
34
+ }
35
+ return self;
36
+ }
37
+
38
+ - (void)prepareForRecycle {
39
+ [super prepareForRecycle];
40
+ // Reset state for view recycling - cleanup the widget container
41
+ if (widgetView != nil) {
42
+ [(TeadsAdContainer *)widgetView cleanup];
43
+ [widgetView removeFromSuperview];
44
+ widgetView = nil;
45
+ }
46
+ _initialPropsSet = NO;
47
+ }
48
+
49
+
50
+ - (void)layoutSubviews {
51
+ [super layoutSubviews];
52
+ widgetView.frame = self.bounds;
53
+ }
54
+
55
+
56
+ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
57
+ {
58
+ const auto &newViewProps = *std::static_pointer_cast<const TeadsAdPlacementFeedProps>(props);
59
+
60
+ NSString *widgetId = [NSString stringWithCString:newViewProps.widgetId.c_str() encoding:NSUTF8StringEncoding];
61
+ NSInteger widgetRandomId = newViewProps.widgetRandomId;
62
+ NSInteger widgetIndex = newViewProps.widgetIndex;
63
+ NSString *url = [NSString stringWithCString:newViewProps.url.c_str() encoding:NSUTF8StringEncoding];
64
+ NSString *installationKey = [NSString stringWithCString:newViewProps.installationKey.c_str() encoding:NSUTF8StringEncoding];
65
+ NSString *packageVersion = [NSString stringWithCString:newViewProps.packageVersion.c_str() encoding:NSUTF8StringEncoding];
66
+ NSString *extId = newViewProps.extId.empty() ? nil : [NSString stringWithCString:newViewProps.extId.c_str() encoding:NSUTF8StringEncoding];
67
+ NSString *extSecondaryId = newViewProps.extSecondaryId.empty() ? nil : [NSString stringWithCString:newViewProps.extSecondaryId.c_str() encoding:NSUTF8StringEncoding];
68
+ NSString *userId = newViewProps.userId.empty() ? nil : [NSString stringWithCString:newViewProps.userId.c_str() encoding:NSUTF8StringEncoding];
69
+ NSString *pubImpId = newViewProps.pubImpId.empty() ? nil : [NSString stringWithCString:newViewProps.pubImpId.c_str() encoding:NSUTF8StringEncoding];
70
+ BOOL darkMode = newViewProps.darkMode;
71
+
72
+
73
+ if (widgetView == nil) {
74
+ widgetView = [[TeadsAdContainer alloc] initWithFrame:self.bounds];
75
+ widgetView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
76
+ [self addSubview:widgetView];
77
+ }
78
+
79
+
80
+ // call configure with widget props only once, prevents rerendering
81
+ if (!_initialPropsSet) {
82
+ _initialPropsSet = YES;
83
+ [(TeadsAdContainer *)widgetView configureWithWidgetId:widgetId
84
+ widgetRandomId:widgetRandomId
85
+ widgetIndex:widgetIndex
86
+ url:url
87
+ installationKey:installationKey
88
+ packageVersion:packageVersion
89
+ extId:extId
90
+ extSecondaryId:extSecondaryId
91
+ userId:userId
92
+ pubImpId:pubImpId
93
+ darkMode:darkMode];
94
+ }
95
+ else if (oldProps != nullptr) {
96
+ const auto &oldViewProps = *std::static_pointer_cast<const TeadsAdPlacementFeedProps>(oldProps);
97
+ if (newViewProps.darkMode != oldViewProps.darkMode) {
98
+ [(TeadsAdContainer *)widgetView toggleDarkMode:newViewProps.darkMode];
99
+ }
100
+ }
101
+
102
+ [super updateProps:props oldProps:oldProps];
103
+ }
104
+
105
+
106
+ + (ComponentDescriptorProvider)componentDescriptorProvider
107
+ {
108
+ return concreteComponentDescriptorProvider<TeadsAdPlacementFeedComponentDescriptor>();
109
+ }
110
+
111
+
112
+
113
+ @end
114
+
@@ -0,0 +1,23 @@
1
+ //
2
+ // RCTTeadsAdPlacementMedia.h
3
+ // TeadsReactNative
4
+ //
5
+ // Created by Oded Regev on 10/11/2025.
6
+ //
7
+
8
+ #import <UIKit/UIKit.h>
9
+ #import <React/RCTViewComponentView.h>
10
+ #import <React/RCTComponent.h>
11
+ //#import <OutbrainSDK/OutbrainSDK.h>
12
+
13
+
14
+ NS_ASSUME_NONNULL_BEGIN
15
+
16
+ @interface RCTTeadsAdPlacementMedia : RCTViewComponentView
17
+
18
+ // You would declare native methods you'd want to access from the view here
19
+
20
+ @end
21
+
22
+ NS_ASSUME_NONNULL_END
23
+
@@ -0,0 +1,91 @@
1
+ //
2
+ // RCTTeadsAdPlacementMedia.mm
3
+ // TeadsReactNative
4
+ //
5
+ // Created by Ofek Cohen on 03/04/2025.
6
+ //
7
+
8
+ #import "RCTTeadsAdPlacementMedia.h"
9
+ #import "RCTAppDelegate.h"
10
+ #import <WebKit/WebKit.h>
11
+ #import "TeadsSDK/TeadsSDK-Swift.h"
12
+
13
+ #import "TeadsReactNative-Swift.h" // auto-generated file that enables the Objective-C code to use the Swift code.
14
+
15
+ #import "generated/RNTeadsReactNativeViewSpec/ComponentDescriptors.h"
16
+ #import "generated/RNTeadsReactNativeViewSpec/EventEmitters.h"
17
+ #import "generated/RNTeadsReactNativeViewSpec/Props.h"
18
+ #import "generated/RNTeadsReactNativeViewSpec/RCTComponentViewHelpers.h"
19
+
20
+ using namespace facebook::react;
21
+
22
+ @interface RCTTeadsAdPlacementMedia ()
23
+ @end
24
+
25
+ @implementation RCTTeadsAdPlacementMedia {
26
+ TeadsAdContainer *widgetView;
27
+ BOOL _initialPropsSet;
28
+ }
29
+
30
+
31
+ - (instancetype)init {
32
+ if (self = [super init]) {
33
+ _initialPropsSet = NO;
34
+ }
35
+ return self;
36
+ }
37
+
38
+ - (void)prepareForRecycle {
39
+ [super prepareForRecycle];
40
+ // Reset state for view recycling - cleanup the widget container
41
+ if (widgetView != nil) {
42
+ [(TeadsAdContainer *)widgetView cleanup];
43
+ [widgetView removeFromSuperview];
44
+ widgetView = nil;
45
+ }
46
+ _initialPropsSet = NO;
47
+ }
48
+
49
+
50
+ - (void)layoutSubviews {
51
+ [super layoutSubviews];
52
+ widgetView.frame = self.bounds;
53
+ }
54
+
55
+
56
+ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
57
+ {
58
+ const auto &newViewProps = *std::static_pointer_cast<const TeadsAdPlacementMediaProps>(props);
59
+ const auto &oldViewProps = *std::static_pointer_cast<const TeadsAdPlacementMediaProps>(oldProps);
60
+
61
+ NSString *pid = [NSString stringWithCString:newViewProps.pid.c_str() encoding:NSUTF8StringEncoding];
62
+ NSInteger widgetRandomId = newViewProps.widgetRandomId;
63
+ NSString *url = [NSString stringWithCString:newViewProps.url.c_str() encoding:NSUTF8StringEncoding];
64
+ NSString *installationKey = [NSString stringWithCString:newViewProps.installationKey.c_str() encoding:NSUTF8StringEncoding];
65
+ NSString *packageVersion = [NSString stringWithCString:newViewProps.packageVersion.c_str() encoding:NSUTF8StringEncoding];
66
+
67
+
68
+ if (widgetView == nil) {
69
+ widgetView = [[TeadsAdContainer alloc] initWithFrame:self.bounds];
70
+ widgetView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
71
+ [self addSubview:widgetView];
72
+ }
73
+
74
+ // call configure with widget props only once, prevents rerendering
75
+ if (!_initialPropsSet) {
76
+ _initialPropsSet = YES;
77
+ [(TeadsAdContainer *)widgetView configureWithPid:pid widgetRandomId:widgetRandomId url:url installationKey:installationKey packageVersion:packageVersion];
78
+ }
79
+
80
+ [super updateProps:props oldProps:oldProps];
81
+ }
82
+
83
+
84
+ + (ComponentDescriptorProvider)componentDescriptorProvider
85
+ {
86
+ return concreteComponentDescriptorProvider<TeadsAdPlacementMediaComponentDescriptor>();
87
+ }
88
+
89
+
90
+
91
+ @end