@shortkitsdk/react-native 0.2.41 → 0.2.43
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/android/libs/shortkit-release.aar +0 -0
- package/android/src/main/java/com/shortkit/reactnative/ShortKitBridge.kt +217 -7
- package/android/src/main/java/com/shortkit/reactnative/ShortKitFeedView.kt +59 -10
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Info.plist +2 -2
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json +1 -1
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/_CodeSignature/CodeResources +3 -3
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Info.plist +2 -2
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +1 -1
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +1 -1
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/ShortKitSDK +0 -0
- package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/_CodeSignature/CodeResources +5 -5
- package/package.json +1 -1
- package/src/serialization.ts +6 -0
|
Binary file
|
|
@@ -14,6 +14,7 @@ import com.shortkit.sdk.model.ContentSignal
|
|
|
14
14
|
import com.shortkit.sdk.model.FeedDirection
|
|
15
15
|
import com.shortkit.sdk.model.FeedFilter
|
|
16
16
|
import com.shortkit.sdk.model.FeedInput
|
|
17
|
+
import com.shortkit.sdk.model.FeedItem
|
|
17
18
|
import com.shortkit.sdk.model.FeedScrollPhase
|
|
18
19
|
import com.shortkit.sdk.model.FeedTransitionPhase
|
|
19
20
|
import com.shortkit.sdk.model.ImageCarouselItem
|
|
@@ -427,7 +428,10 @@ class ShortKitBridge(
|
|
|
427
428
|
"video" -> {
|
|
428
429
|
val playbackId = obj.optString("playbackId", null) ?: continue
|
|
429
430
|
val fallbackUrl = obj.optString("fallbackUrl", null)
|
|
430
|
-
|
|
431
|
+
val itemId = obj.optString("id", null)
|
|
432
|
+
val nativePlaybackId =
|
|
433
|
+
if (!itemId.isNullOrBlank() && !fallbackUrl.isNullOrBlank()) itemId else playbackId
|
|
434
|
+
result.add(FeedInput.Video(nativePlaybackId, fallbackUrl))
|
|
431
435
|
}
|
|
432
436
|
"imageCarousel" -> {
|
|
433
437
|
val itemObj = obj.optJSONObject("item") ?: continue
|
|
@@ -442,7 +446,10 @@ class ShortKitBridge(
|
|
|
442
446
|
val videoObj = videosArr.getJSONObject(i)
|
|
443
447
|
val playbackId = videoObj.optString("playbackId", null) ?: continue
|
|
444
448
|
val fallbackUrl = videoObj.optString("fallbackUrl", null)
|
|
445
|
-
|
|
449
|
+
val videoId = videoObj.optString("id", null)
|
|
450
|
+
val nativePlaybackId =
|
|
451
|
+
if (!videoId.isNullOrBlank() && !fallbackUrl.isNullOrBlank()) videoId else playbackId
|
|
452
|
+
videoInputs.add(VideoCarouselVideoInput(nativePlaybackId, fallbackUrl))
|
|
446
453
|
}
|
|
447
454
|
if (videoInputs.isEmpty()) continue
|
|
448
455
|
val carouselInput = VideoCarouselInput(
|
|
@@ -1098,22 +1105,220 @@ class ShortKitBridge(
|
|
|
1098
1105
|
// Custom feed operations
|
|
1099
1106
|
// ------------------------------------------------------------------
|
|
1100
1107
|
|
|
1108
|
+
private fun legacyFallbackIdsByFallbackUrl(itemsJSON: String): Map<String, String> {
|
|
1109
|
+
return try {
|
|
1110
|
+
val arr = JSONArray(itemsJSON)
|
|
1111
|
+
val ids = mutableMapOf<String, String>()
|
|
1112
|
+
|
|
1113
|
+
for (i in 0 until arr.length()) {
|
|
1114
|
+
val obj = arr.getJSONObject(i)
|
|
1115
|
+
when (obj.optString("type")) {
|
|
1116
|
+
"video" -> {
|
|
1117
|
+
val id = obj.optString("id", null)
|
|
1118
|
+
val fallbackUrl = obj.optString("fallbackUrl", null)
|
|
1119
|
+
if (!id.isNullOrBlank() && !fallbackUrl.isNullOrBlank()) {
|
|
1120
|
+
ids[fallbackUrl] = id
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
"videoCarousel" -> {
|
|
1124
|
+
val videos = obj.optJSONObject("item")?.optJSONArray("videos")
|
|
1125
|
+
if (videos != null) {
|
|
1126
|
+
for (videoIndex in 0 until videos.length()) {
|
|
1127
|
+
val video = videos.getJSONObject(videoIndex)
|
|
1128
|
+
val id = video.optString("id", null)
|
|
1129
|
+
val fallbackUrl = video.optString("fallbackUrl", null)
|
|
1130
|
+
if (!id.isNullOrBlank() && !fallbackUrl.isNullOrBlank()) {
|
|
1131
|
+
ids[fallbackUrl] = id
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
ids
|
|
1140
|
+
} catch (_: Throwable) {
|
|
1141
|
+
emptyMap()
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
private fun fallbackThumbnailUrl(fallbackUrl: String): String {
|
|
1146
|
+
val uploadMarker = "/video/upload/"
|
|
1147
|
+
val uploadIndex = fallbackUrl.indexOf(uploadMarker)
|
|
1148
|
+
|
|
1149
|
+
if (uploadIndex >= 0) {
|
|
1150
|
+
val prefix = fallbackUrl.substring(0, uploadIndex)
|
|
1151
|
+
val path = fallbackUrl.substring(uploadIndex + uploadMarker.length)
|
|
1152
|
+
val withoutExtension = path.substringBeforeLast('.', path)
|
|
1153
|
+
return "$prefix/video/upload/so_0/$withoutExtension.jpg"
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
return fallbackUrl
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
private fun legacyFallbackContentItem(contentId: String, fallbackUrl: String): ContentItem {
|
|
1160
|
+
return ContentItem(
|
|
1161
|
+
id = contentId,
|
|
1162
|
+
playbackId = contentId,
|
|
1163
|
+
title = "",
|
|
1164
|
+
description = null,
|
|
1165
|
+
duration = 0.0,
|
|
1166
|
+
streamingUrl = fallbackUrl,
|
|
1167
|
+
thumbnailUrl = fallbackThumbnailUrl(fallbackUrl),
|
|
1168
|
+
captionTracks = emptyList(),
|
|
1169
|
+
customMetadata = null,
|
|
1170
|
+
author = null,
|
|
1171
|
+
articleUrl = null,
|
|
1172
|
+
commentCount = null,
|
|
1173
|
+
fallbackUrl = fallbackUrl,
|
|
1174
|
+
)
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
private fun patchLegacyFallbackFeedItems(
|
|
1178
|
+
fragment: ShortKitFeedFragment,
|
|
1179
|
+
legacyIdsByFallbackUrl: Map<String, String>,
|
|
1180
|
+
): Boolean {
|
|
1181
|
+
if (legacyIdsByFallbackUrl.isEmpty()) return false
|
|
1182
|
+
|
|
1183
|
+
try {
|
|
1184
|
+
val feedDataSourceField = fragment.javaClass.getDeclaredField("feedDataSource").apply {
|
|
1185
|
+
isAccessible = true
|
|
1186
|
+
}
|
|
1187
|
+
val feedDataSource = feedDataSourceField.get(fragment) ?: return false
|
|
1188
|
+
@Suppress("UNCHECKED_CAST")
|
|
1189
|
+
val feedItems = feedDataSource.javaClass.getMethod("getItems").invoke(feedDataSource) as? MutableList<FeedItem>
|
|
1190
|
+
?: return false
|
|
1191
|
+
var patchedCount = 0
|
|
1192
|
+
|
|
1193
|
+
feedItems.forEachIndexed { index, feedItem ->
|
|
1194
|
+
when (feedItem) {
|
|
1195
|
+
is FeedItem.Content -> {
|
|
1196
|
+
val item = feedItem.item
|
|
1197
|
+
val fallbackUrl = item.fallbackUrl
|
|
1198
|
+
val legacyId = fallbackUrl?.takeIf { it.isNotBlank() }?.let {
|
|
1199
|
+
legacyIdsByFallbackUrl[it]
|
|
1200
|
+
}
|
|
1201
|
+
if (!legacyId.isNullOrBlank() && !fallbackUrl.isNullOrBlank()) {
|
|
1202
|
+
feedItems[index] = FeedItem.Content(legacyFallbackContentItem(legacyId, fallbackUrl))
|
|
1203
|
+
patchedCount += 1
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
is FeedItem.VideoCarousel -> {
|
|
1207
|
+
val carouselItem = feedItem.item
|
|
1208
|
+
var didPatchCarousel = false
|
|
1209
|
+
val patchedVideos = carouselItem.videos.map { video ->
|
|
1210
|
+
val fallbackUrl = video.fallbackUrl
|
|
1211
|
+
val legacyId = fallbackUrl?.takeIf { it.isNotBlank() }?.let {
|
|
1212
|
+
legacyIdsByFallbackUrl[it]
|
|
1213
|
+
}
|
|
1214
|
+
if (legacyId.isNullOrBlank() || fallbackUrl.isNullOrBlank()) {
|
|
1215
|
+
video
|
|
1216
|
+
} else {
|
|
1217
|
+
didPatchCarousel = true
|
|
1218
|
+
legacyFallbackContentItem(legacyId, fallbackUrl)
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
if (didPatchCarousel) {
|
|
1223
|
+
feedItems[index] = FeedItem.VideoCarousel(carouselItem.copy(videos = patchedVideos))
|
|
1224
|
+
patchedCount += 1
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
else -> Unit
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
if (patchedCount > 0) {
|
|
1232
|
+
android.util.Log.d("SK:Bridge", "patched legacy fallback feed items count=$patchedCount")
|
|
1233
|
+
}
|
|
1234
|
+
return patchedCount > 0
|
|
1235
|
+
} catch (error: Throwable) {
|
|
1236
|
+
android.util.Log.w("SK:Bridge", "failed to patch legacy fallback feed items", error)
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
return false
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
private fun resubmitPatchedFeedItems(fragment: ShortKitFeedFragment, startAtId: String?) {
|
|
1243
|
+
try {
|
|
1244
|
+
val feedDataSourceField = fragment.javaClass.getDeclaredField("feedDataSource").apply {
|
|
1245
|
+
isAccessible = true
|
|
1246
|
+
}
|
|
1247
|
+
val feedDataSource = feedDataSourceField.get(fragment) ?: return
|
|
1248
|
+
@Suppress("UNCHECKED_CAST")
|
|
1249
|
+
val feedItems = feedDataSource.javaClass.getMethod("getItems").invoke(feedDataSource) as? List<FeedItem>
|
|
1250
|
+
?: return
|
|
1251
|
+
|
|
1252
|
+
val feedAdapterField = fragment.javaClass.getDeclaredField("feedAdapter").apply {
|
|
1253
|
+
isAccessible = true
|
|
1254
|
+
}
|
|
1255
|
+
val feedAdapter = feedAdapterField.get(fragment) ?: return
|
|
1256
|
+
val submitList = feedAdapter.javaClass.methods.firstOrNull { method ->
|
|
1257
|
+
method.name == "submitList" &&
|
|
1258
|
+
method.parameterTypes.size == 2 &&
|
|
1259
|
+
Runnable::class.java.isAssignableFrom(method.parameterTypes[1])
|
|
1260
|
+
} ?: return
|
|
1261
|
+
val callback = Runnable {
|
|
1262
|
+
if (!startAtId.isNullOrBlank()) {
|
|
1263
|
+
fragment.scrollToItem(startAtId, false)
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
submitList.invoke(feedAdapter, feedItems.toList(), callback)
|
|
1268
|
+
} catch (error: Throwable) {
|
|
1269
|
+
android.util.Log.w("SK:Bridge", "failed to resubmit patched legacy fallback feed items", error)
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
internal fun hasLegacyFallbackFeedItems(itemsJSON: String): Boolean {
|
|
1274
|
+
return legacyFallbackIdsByFallbackUrl(itemsJSON).isNotEmpty()
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
internal fun setFeedItemsResolvingLegacyFallback(
|
|
1278
|
+
fragment: ShortKitFeedFragment,
|
|
1279
|
+
parsed: List<FeedInput>,
|
|
1280
|
+
itemsJSON: String,
|
|
1281
|
+
startAtId: String?,
|
|
1282
|
+
) {
|
|
1283
|
+
val legacyIdsByFallbackUrl = legacyFallbackIdsByFallbackUrl(itemsJSON)
|
|
1284
|
+
val nativeStartAtId =
|
|
1285
|
+
if (!startAtId.isNullOrBlank() && legacyIdsByFallbackUrl.containsValue(startAtId)) null else startAtId
|
|
1286
|
+
|
|
1287
|
+
fragment.setFeedItems(parsed, nativeStartAtId)
|
|
1288
|
+
if (patchLegacyFallbackFeedItems(fragment, legacyIdsByFallbackUrl)) {
|
|
1289
|
+
resubmitPatchedFeedItems(fragment, startAtId)
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
internal fun appendFeedItemsResolvingLegacyFallback(
|
|
1294
|
+
fragment: ShortKitFeedFragment,
|
|
1295
|
+
parsed: List<FeedInput>,
|
|
1296
|
+
itemsJSON: String,
|
|
1297
|
+
) {
|
|
1298
|
+
val legacyIdsByFallbackUrl = legacyFallbackIdsByFallbackUrl(itemsJSON)
|
|
1299
|
+
|
|
1300
|
+
fragment.appendFeedItems(parsed)
|
|
1301
|
+
if (patchLegacyFallbackFeedItems(fragment, legacyIdsByFallbackUrl)) {
|
|
1302
|
+
resubmitPatchedFeedItems(fragment, null)
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1101
1306
|
fun setFeedItems(feedId: String, itemsJSON: String, startAtId: String?) {
|
|
1102
1307
|
val fragment = feedFragment(feedId)
|
|
1103
1308
|
if (fragment != null) {
|
|
1104
1309
|
val parsed = parseFeedInputs(itemsJSON) ?: return
|
|
1105
1310
|
Handler(Looper.getMainLooper()).post {
|
|
1106
|
-
fragment
|
|
1311
|
+
setFeedItemsResolvingLegacyFallback(fragment, parsed, itemsJSON, startAtId)
|
|
1107
1312
|
}
|
|
1108
1313
|
} else {
|
|
1109
1314
|
synchronized(pendingOpsLock) {
|
|
1110
1315
|
pendingOps.getOrPut(feedId) { mutableListOf() }.add { frag ->
|
|
1111
1316
|
val parsed = parseFeedInputs(itemsJSON) ?: return@add
|
|
1112
1317
|
if (Looper.myLooper() == Looper.getMainLooper()) {
|
|
1113
|
-
frag
|
|
1318
|
+
setFeedItemsResolvingLegacyFallback(frag, parsed, itemsJSON, startAtId)
|
|
1114
1319
|
} else {
|
|
1115
1320
|
Handler(Looper.getMainLooper()).post {
|
|
1116
|
-
frag
|
|
1321
|
+
setFeedItemsResolvingLegacyFallback(frag, parsed, itemsJSON, startAtId)
|
|
1117
1322
|
}
|
|
1118
1323
|
}
|
|
1119
1324
|
}
|
|
@@ -1143,14 +1348,14 @@ class ShortKitBridge(
|
|
|
1143
1348
|
if (fragment != null) {
|
|
1144
1349
|
val parsed = parseFeedInputs(itemsJSON) ?: return
|
|
1145
1350
|
Handler(Looper.getMainLooper()).post {
|
|
1146
|
-
fragment
|
|
1351
|
+
appendFeedItemsResolvingLegacyFallback(fragment, parsed, itemsJSON)
|
|
1147
1352
|
}
|
|
1148
1353
|
} else {
|
|
1149
1354
|
synchronized(pendingOpsLock) {
|
|
1150
1355
|
pendingOps.getOrPut(feedId) { mutableListOf() }.add { frag ->
|
|
1151
1356
|
val parsed = parseFeedInputs(itemsJSON) ?: return@add
|
|
1152
1357
|
Handler(Looper.getMainLooper()).post {
|
|
1153
|
-
frag
|
|
1358
|
+
appendFeedItemsResolvingLegacyFallback(frag, parsed, itemsJSON)
|
|
1154
1359
|
}
|
|
1155
1360
|
}
|
|
1156
1361
|
}
|
|
@@ -1222,6 +1427,11 @@ class ShortKitBridge(
|
|
|
1222
1427
|
callback("")
|
|
1223
1428
|
return
|
|
1224
1429
|
}
|
|
1430
|
+
if (hasLegacyFallbackFeedItems(itemsJSON)) {
|
|
1431
|
+
android.util.Log.d("SK:Bridge", "skipping custom preload for legacy fallback feed items")
|
|
1432
|
+
callback("")
|
|
1433
|
+
return
|
|
1434
|
+
}
|
|
1225
1435
|
val items = parseFeedInputs(itemsJSON)
|
|
1226
1436
|
if (items == null) {
|
|
1227
1437
|
callback("")
|
|
@@ -10,6 +10,7 @@ import android.view.ViewGroup
|
|
|
10
10
|
import android.widget.FrameLayout
|
|
11
11
|
import androidx.fragment.app.FragmentActivity
|
|
12
12
|
import com.shortkit.sdk.feed.ShortKitFeedFragment
|
|
13
|
+
import com.shortkit.sdk.model.FeedInput
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Fabric native view that embeds [ShortKitFeedFragment] using Android
|
|
@@ -162,7 +163,10 @@ class ShortKitFeedView(context: Context) : FrameLayout(context) {
|
|
|
162
163
|
val wSpec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY)
|
|
163
164
|
val hSpec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)
|
|
164
165
|
|
|
165
|
-
// Re-pin container
|
|
166
|
+
// Re-pin container — update layoutParams so subsequent layout traversals
|
|
167
|
+
// (scroll events, player binding, etc.) don't re-expand back to the
|
|
168
|
+
// first-pass full-screen size that was recorded at embed time.
|
|
169
|
+
fragmentContainer.layoutParams = LayoutParams(w, h)
|
|
166
170
|
fragmentContainer.measure(wSpec, hSpec)
|
|
167
171
|
fragmentContainer.layout(0, 0, w, h)
|
|
168
172
|
|
|
@@ -184,6 +188,27 @@ class ShortKitFeedView(context: Context) : FrameLayout(context) {
|
|
|
184
188
|
}
|
|
185
189
|
}
|
|
186
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Keep rnWidth/rnHeight current so constrainRunnable always re-pins to the
|
|
193
|
+
* correct dimensions if Fabric updates the view size (e.g. rotation) after
|
|
194
|
+
* the fragment has been embedded.
|
|
195
|
+
*/
|
|
196
|
+
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
|
197
|
+
super.onSizeChanged(w, h, oldw, oldh)
|
|
198
|
+
if (w > 0 && h > 0) {
|
|
199
|
+
rnWidth = w
|
|
200
|
+
rnHeight = h
|
|
201
|
+
if (feedFragment != null) {
|
|
202
|
+
// Fire immediately on size change so the correction lands within
|
|
203
|
+
// ~1ms rather than waiting 200ms. The embed fires with first-pass
|
|
204
|
+
// dimensions (before safe-area insets are applied) and this fires
|
|
205
|
+
// when the correct second-pass dimensions arrive — roughly 20ms
|
|
206
|
+
// later, which is 1-2 frames during the screen-push animation.
|
|
207
|
+
handler.removeCallbacks(constrainRunnable)
|
|
208
|
+
handler.post(constrainRunnable)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
187
212
|
|
|
188
213
|
// -----------------------------------------------------------------------
|
|
189
214
|
// Lifecycle
|
|
@@ -268,12 +293,10 @@ class ShortKitFeedView(context: Context) : FrameLayout(context) {
|
|
|
268
293
|
|
|
269
294
|
val explicitPreloadId = preloadId
|
|
270
295
|
val explicitFeedItemsJSON = feedItemsJSON
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
276
|
-
} else if (explicitFeedItemsJSON != null) {
|
|
296
|
+
var deferredFeedItemsJSON: String? = null
|
|
297
|
+
var deferredFeedItems: List<FeedInput>? = null
|
|
298
|
+
fun configureExplicitFeedItems() {
|
|
299
|
+
val sourceItemsJSON = explicitFeedItemsJSON ?: return
|
|
277
300
|
// Mount-time custom-feed fast-path (SHO-29 / iOS PR #150).
|
|
278
301
|
// Parse JSON → FeedInput[] → sdk.preloadFeed(items=) which
|
|
279
302
|
// internally calls FeedPreload.forCustomItems with the SDK's
|
|
@@ -286,15 +309,31 @@ class ShortKitFeedView(context: Context) : FrameLayout(context) {
|
|
|
286
309
|
// ShortKit.kt:232) instead of FeedPreload.forCustomItems
|
|
287
310
|
// directly — avoids needing to promote internal SDK helpers
|
|
288
311
|
// for cross-module access from the bridge.
|
|
289
|
-
val parsed = ShortKitBridge.parseFeedInputs(
|
|
312
|
+
val parsed = ShortKitBridge.parseFeedInputs(sourceItemsJSON)
|
|
290
313
|
if (parsed != null && parsed.isNotEmpty()) {
|
|
291
|
-
|
|
292
|
-
|
|
314
|
+
if (ShortKitBridge.shared?.hasLegacyFallbackFeedItems(sourceItemsJSON) == true) {
|
|
315
|
+
deferredFeedItemsJSON = sourceItemsJSON
|
|
316
|
+
deferredFeedItems = parsed
|
|
317
|
+
} else {
|
|
318
|
+
val preload = sdk.preloadFeed(items = parsed)
|
|
319
|
+
feedConfig = feedConfig.copy(preload = preload)
|
|
320
|
+
}
|
|
293
321
|
} else {
|
|
294
322
|
Log.w(TAG, "feedItemsJSON parsed to null/empty — ignoring (config feedSource will drive the fetch path)")
|
|
295
323
|
}
|
|
296
324
|
}
|
|
297
325
|
|
|
326
|
+
if (explicitPreloadId != null) {
|
|
327
|
+
val preload = ShortKitBridge.shared?.consumePreload(explicitPreloadId)
|
|
328
|
+
if (preload != null) {
|
|
329
|
+
feedConfig = feedConfig.copy(preload = preload)
|
|
330
|
+
} else {
|
|
331
|
+
configureExplicitFeedItems()
|
|
332
|
+
}
|
|
333
|
+
} else if (explicitFeedItemsJSON != null) {
|
|
334
|
+
configureExplicitFeedItems()
|
|
335
|
+
}
|
|
336
|
+
|
|
298
337
|
val fragment = ShortKitFeedFragment.newInstance(sdk, feedConfig, startAtItemId)
|
|
299
338
|
|
|
300
339
|
val debugPanelEnabled = if (debugPanelPropSet) debugPanel else sdk.debugPanelEnabled
|
|
@@ -324,6 +363,16 @@ class ShortKitFeedView(context: Context) : FrameLayout(context) {
|
|
|
324
363
|
.replace(fragmentContainerId, fragment)
|
|
325
364
|
.commitNowAllowingStateLoss()
|
|
326
365
|
this.feedFragment = fragment
|
|
366
|
+
val mountFeedItemsJSON = deferredFeedItemsJSON
|
|
367
|
+
val mountFeedItems = deferredFeedItems
|
|
368
|
+
if (mountFeedItemsJSON != null && mountFeedItems != null) {
|
|
369
|
+
ShortKitBridge.shared?.setFeedItemsResolvingLegacyFallback(
|
|
370
|
+
fragment,
|
|
371
|
+
mountFeedItems,
|
|
372
|
+
mountFeedItemsJSON,
|
|
373
|
+
startAtItemId,
|
|
374
|
+
)
|
|
375
|
+
}
|
|
327
376
|
|
|
328
377
|
// Android-specific first-mount race: Fabric may have set active=false
|
|
329
378
|
// BEFORE we got to embed the fragment. The fragment self-claims the
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
<key>CFBundlePackageType</key>
|
|
12
12
|
<string>FMWK</string>
|
|
13
13
|
<key>CFBundleVersion</key>
|
|
14
|
-
<string>0.2.
|
|
14
|
+
<string>0.2.43</string>
|
|
15
15
|
<key>CFBundleShortVersionString</key>
|
|
16
|
-
<string>0.2.
|
|
16
|
+
<string>0.2.43</string>
|
|
17
17
|
<key>MinimumOSVersion</key>
|
|
18
18
|
<string>16.0</string>
|
|
19
19
|
</dict>
|
|
@@ -53531,7 +53531,7 @@
|
|
|
53531
53531
|
"kind": "StringLiteral",
|
|
53532
53532
|
"offset": 154,
|
|
53533
53533
|
"length": 8,
|
|
53534
|
-
"value": "\"0.2.
|
|
53534
|
+
"value": "\"0.2.43\""
|
|
53535
53535
|
},
|
|
53536
53536
|
{
|
|
53537
53537
|
"filePath": "\/Users\/michaelseleman\/shortkit\/swift_sdk\/Sources\/ShortKit\/ShortKit.swift",
|
|
Binary file
|
package/ios/ShortKitSDK.xcframework/ios-arm64/ShortKitSDK.framework/_CodeSignature/CodeResources
CHANGED
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
</data>
|
|
11
11
|
<key>Info.plist</key>
|
|
12
12
|
<data>
|
|
13
|
-
|
|
13
|
+
TG3LP5ZMM8V3dELjK3Olw15ohCg=
|
|
14
14
|
</data>
|
|
15
15
|
<key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.abi.json</key>
|
|
16
16
|
<data>
|
|
17
|
-
|
|
17
|
+
3lW3HwkTYBJ3P/8BAI6tSSqybzM=
|
|
18
18
|
</data>
|
|
19
19
|
<key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface</key>
|
|
20
20
|
<data>
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
<dict>
|
|
51
51
|
<key>hash2</key>
|
|
52
52
|
<data>
|
|
53
|
-
|
|
53
|
+
xcfBvVw56QMYGrmvXutsz9+UxOyQoHa33Hgy7h5/lto=
|
|
54
54
|
</data>
|
|
55
55
|
</dict>
|
|
56
56
|
<key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios.private.swiftinterface</key>
|
package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/Info.plist
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
<key>CFBundlePackageType</key>
|
|
12
12
|
<string>FMWK</string>
|
|
13
13
|
<key>CFBundleVersion</key>
|
|
14
|
-
<string>0.2.
|
|
14
|
+
<string>0.2.43</string>
|
|
15
15
|
<key>CFBundleShortVersionString</key>
|
|
16
|
-
<string>0.2.
|
|
16
|
+
<string>0.2.43</string>
|
|
17
17
|
<key>MinimumOSVersion</key>
|
|
18
18
|
<string>16.0</string>
|
|
19
19
|
</dict>
|
|
@@ -53531,7 +53531,7 @@
|
|
|
53531
53531
|
"kind": "StringLiteral",
|
|
53532
53532
|
"offset": 154,
|
|
53533
53533
|
"length": 8,
|
|
53534
|
-
"value": "\"0.2.
|
|
53534
|
+
"value": "\"0.2.43\""
|
|
53535
53535
|
},
|
|
53536
53536
|
{
|
|
53537
53537
|
"filePath": "\/Users\/michaelseleman\/shortkit\/swift_sdk\/Sources\/ShortKit\/ShortKit.swift",
|
|
@@ -53531,7 +53531,7 @@
|
|
|
53531
53531
|
"kind": "StringLiteral",
|
|
53532
53532
|
"offset": 154,
|
|
53533
53533
|
"length": 8,
|
|
53534
|
-
"value": "\"0.2.
|
|
53534
|
+
"value": "\"0.2.43\""
|
|
53535
53535
|
},
|
|
53536
53536
|
{
|
|
53537
53537
|
"filePath": "\/Users\/michaelseleman\/shortkit\/swift_sdk\/Sources\/ShortKit\/ShortKit.swift",
|
package/ios/ShortKitSDK.xcframework/ios-arm64_x86_64-simulator/ShortKitSDK.framework/ShortKitSDK
CHANGED
|
Binary file
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
</data>
|
|
11
11
|
<key>Info.plist</key>
|
|
12
12
|
<data>
|
|
13
|
-
|
|
13
|
+
TG3LP5ZMM8V3dELjK3Olw15ohCg=
|
|
14
14
|
</data>
|
|
15
15
|
<key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.abi.json</key>
|
|
16
16
|
<data>
|
|
17
|
-
|
|
17
|
+
3lW3HwkTYBJ3P/8BAI6tSSqybzM=
|
|
18
18
|
</data>
|
|
19
19
|
<key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface</key>
|
|
20
20
|
<data>
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
</data>
|
|
31
31
|
<key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json</key>
|
|
32
32
|
<data>
|
|
33
|
-
|
|
33
|
+
3lW3HwkTYBJ3P/8BAI6tSSqybzM=
|
|
34
34
|
</data>
|
|
35
35
|
<key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface</key>
|
|
36
36
|
<data>
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
<dict>
|
|
67
67
|
<key>hash2</key>
|
|
68
68
|
<data>
|
|
69
|
-
|
|
69
|
+
xcfBvVw56QMYGrmvXutsz9+UxOyQoHa33Hgy7h5/lto=
|
|
70
70
|
</data>
|
|
71
71
|
</dict>
|
|
72
72
|
<key>Modules/ShortKitSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface</key>
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
<dict>
|
|
95
95
|
<key>hash2</key>
|
|
96
96
|
<data>
|
|
97
|
-
|
|
97
|
+
xcfBvVw56QMYGrmvXutsz9+UxOyQoHa33Hgy7h5/lto=
|
|
98
98
|
</data>
|
|
99
99
|
</dict>
|
|
100
100
|
<key>Modules/ShortKitSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface</key>
|
package/package.json
CHANGED
package/src/serialization.ts
CHANGED
|
@@ -100,7 +100,10 @@ export function deserializePlayerTime(event: {
|
|
|
100
100
|
function serializeVideoCarouselSlide(
|
|
101
101
|
slide: VideoCarouselVideoInput,
|
|
102
102
|
): Record<string, unknown> {
|
|
103
|
+
const legacyId = (slide as VideoCarouselVideoInput & { id?: string }).id;
|
|
104
|
+
|
|
103
105
|
return {
|
|
106
|
+
...(legacyId != null ? { id: String(legacyId) } : {}),
|
|
104
107
|
playbackId: slide.playbackId,
|
|
105
108
|
origin: slide.origin ?? 'other',
|
|
106
109
|
...(slide.fallbackUrl != null ? { fallbackUrl: slide.fallbackUrl } : {}),
|
|
@@ -114,8 +117,11 @@ function serializeVideoCarouselSlide(
|
|
|
114
117
|
export function serializeFeedInputs(items: FeedInput[]): string {
|
|
115
118
|
const serialized = items.map((input) => {
|
|
116
119
|
if (input.type === 'video') {
|
|
120
|
+
const legacyId = (input as FeedInput & { id?: string }).id;
|
|
121
|
+
|
|
117
122
|
return {
|
|
118
123
|
type: 'video',
|
|
124
|
+
...(legacyId != null ? { id: String(legacyId) } : {}),
|
|
119
125
|
playbackId: input.playbackId,
|
|
120
126
|
origin: input.origin ?? 'other',
|
|
121
127
|
...(input.fallbackUrl != null ? { fallbackUrl: input.fallbackUrl } : {}),
|