Skip to content

MOBILE-328: Web bridge action handler registry, embedded blocks on the shared bridge - #757

Open
Vailence wants to merge 16 commits into
mission/storiesfrom
feature/MOBILE-328
Open

MOBILE-328: Web bridge action handler registry, embedded blocks on the shared bridge#757
Vailence wants to merge 16 commits into
mission/storiesfrom
feature/MOBILE-328

Conversation

@Vailence

Copy link
Copy Markdown
Collaborator

Description

MOBILE-328 разбирает JS-бридж вебвью на реестр обработчиков действий и переводит встроенные блоки на тот же бридж, что и in-app вебвью.

До этого вся логика бриджа жила внутри TransparentView (~800 строк), а встроенные блоки имели собственный параллельный канал сообщений (EmbeddedBlockPageMessage + EmbeddedBlockActionRouter). Теперь есть один общий набор обработчиков и два хоста, которые его обслуживают.

Что появилось

  • WebBridgeActionHandler — протокол одного действия (или семейства): объявляет свой набор actions, обрабатывает запрос и умеет tearDown(). Обработчик ничего не знает о конкретной странице — всё нужное приходит через WebBridgeHost.
  • WebBridgeActionRegistry — индексирует действия один раз при сборке, дальше диспетчеризация это словарный lookup. Дубль действия в двух обработчиках логируется как ошибка конфигурации, побеждает первый. Неизвестное действие возвращает false — веб-словарь имеет право быть новее SDK.
  • WebBridgeActionHandlerFactory — один общий набор обработчиков для всех вебвью, новые инстансы на каждую сессию (хаптик-движок и подписка на motion должны умирать вместе со страницей).
  • WebBridgeHost — то, что обработчик видит от страницы. Реализуют TransparentView и EmbeddedBlockWebViewPage.
  • Обработчики: Ready, Log, LocalState, OpenLink, Settings, Permission, Haptic, Motion, Operation, Lifecycle, ContentRendered, плюс заглушки CheckInappsTargeting и ShowInApp.
  • WebViewStartPayloadBuilder — сборка стартового payload вынесена из вью.
  • BridgeURLOpening — общее открытие ссылок; Safari для блока показывается от топового контроллера.

Что убрано

  • EmbeddedBlockPageMessage и EmbeddedBlockActionRouter — их заменил общий бридж.
  • Логика бриджа из TransparentView (−800 строк) и MindboxWebViewFacade.

Прочее

  • Страница держится слабо, пока система отвечает на асинхронный запрос (разрешения, операции) — чтобы не удерживать вебвью после закрытия.

Type of Change

  • Refactor
  • Feature (заглушки checkInappsTargeting / showInApp под будущую задачу)

Test Procedure

Покрытие юнит-тестами на каждый обработчик и на реестр:

  • WebBridgeActionRegistryTests, WebBridgeActionHandlerFactoryTests, WebBridgeHostTests
  • по тестовому файлу на каждый обработчик (LocalState, OpenLink, Settings, Permission, Haptic, Motion, Operation, Lifecycle, ContentRendered, Ready, Log)
  • WebViewStartPayloadBuilderTests, BridgeURLOpeningTests, TargetingAndShowStubTests
  • обновлены EmbeddedBlockWebViewPageTests, EmbeddedBlockWebViewProviderTests, MindboxEmbeddedBlockViewTests, TransparentViewJSBridgeTests

Прогон всей сюиты: 1571 / 1571 passed, 0 failed (iPhone 16 Pro, iOS 18.5).

Pre-flight Checklist

  • Все тесты проходят
  • Публичный API не менялся

Vailence added 15 commits August 13, 2026 13:22
Bridge action handling lives inside TransparentView today, in one switch on a
1000-line view, so nothing but the modal popup can reach log, localState or
openLink. This is the seam that lets any WebView reuse them.

A handler knows nothing about the page talking to it: everything it may need
arrives through WebBridgeHost. Surfaces differ by what they conform to, not by
a type the handlers switch on — a page sending an action its host does not
listen for is journalled and dropped, never an error. That is what lets an
in-app pick up contentRendered later by adding one conformance.

The registry indexes actions to owners at construction. Not for speed at this
size, but so that two handlers claiming one action is caught while the set is
assembled and reported, instead of resolving silently by array order.

Nothing is wired yet: TransparentView is untouched and behaviour is unchanged.
The Handlers folders are synchronized groups, so the handlers moving in next
need no project file edits.
First action out of the switch, and the first time the registry runs on the
real path: TransparentView now asks it before falling through to what has not
moved yet.

log is the cheapest action there is, which is the point — the risky part of
this step is the wiring, not the behaviour, so it is proved on something that
cannot hide a regression.

The handler takes its category from the host instead of naming one. For the
popup that resolves to the same category it always logged under; an embedded
block will get its own without the handler knowing either exists.

WebViewAction.onLog and its implementation go with it: the call that was moved
was the only one.

payloadString replaces the inline payload unwrapping, same logic, now shared
with the handler.

WKWebView leaves WebBridgeHost. It was there for safe-area insets, but those
belong to the start payload, which the host builds and which already holds the
web view — no handler ever needed it.
localState.get/set/init leave the switch, taking their two helpers with them.
The storage property goes too: nothing in the view referenced it any more.

Envelopes are unchanged. sendBridgeError produced the same shape respondError
does, so the error texts, the log formats and the .info level all survive the
move verbatim; only the log category now comes from the host, which for the
popup resolves to the one it always used.

Storage resolves lazily and through a seam. A handler set is built for every
show, so a page that never touches storage should not reach into the container
for it — and the tests get a double instead of the real UserDefaults suite.

payloadObject moves onto BridgeMessage: the same unwrapping is about to be
needed by motion, navigate, permission and the operations.

set and init carried two identical copies of the JSONValue to [String: String?]
conversion. They are now one function — a string stays a string, null stays an
erase distinct from empty, anything richer keeps its JSON text.
…egistry

These three travel together because they already did: settings.open has always
reached the system through the navigate handler's URL opening, so that path
becomes a small shared seam both handlers hold rather than a copy each.

The seam is also what makes the routing testable. Which way a link opens could
previously only be checked by actually leaving the app; now the decision is
observable and the fallback to Safari is not.

Two behaviours are corrected rather than carried:

The universal-link check no longer depends on the handler being alive. The
original called UIApplication.open unconditionally and only guarded the answer
with self?; translating that to self?.urlOpener would have silently dropped the
open itself if the show ended mid-check. Nothing captures self now, and the page
is held weakly — a show that ended gets no answer, and waiting on the system is
not what keeps it alive.

openLink and permission.request now accept an object payload, not only a JSON
string. localState and settings.open always accepted both; the difference read
as an accident, and it meant a page whose settings.open worked would be refused
on openLink for the same shape.

SettingsRequestParser drops the fourth copy of the payload unwrapping.

The navigate prefix in the shared opener's log is left as it was, including for
settings.open, which has always logged under it. It deserves fixing, but not in
a change whose point is that nothing moved.
Both services are registered transient, so a second resolution is a second
engine. Leaving one in the view for init/close while the handler owned another
would have preparing, playing and stopping land on three different objects and
silently do nothing — so the device state lives in the handlers alone, and the
view reaches them through the registry.

close now tears the registry down in the position it used to stop the pattern
and the sensors: devices are released before the window goes, because a pattern
playing into a closed show and a sensor callback reaching a dead page are the
shape crashes come in.

The lazy-initialisation guard is carried over for motion and added for haptics,
which never had one: today every close builds a haptic engine just to stop a
pattern that was never started. Stopping an engine that does not exist is a
no-op, so this is the same behaviour minus an allocation on every show.

A gesture arrives from the sensors with no request behind it, so the page is
remembered from the request that started monitoring — weakly, since a gesture
must not be what keeps a finished show alive. handleSystemShake stays on the
view because the system delivers a shake to the responder, not to the bridge.

The file_length exemption goes: the file no longer needs it, and leaving it
raises a new warning.
The previous commit moved asyncOperation and syncOperation into a handler but
never added it to the factory, so nothing owned them: the switch cases were
gone, the registry answered that it had no owner, and both actions are deferred
— meaning RequestMessageHandler had not answered either. The page would wait
for a response that was never coming.

It went unnoticed because the suite that covers these actions injects a
registry of its own, so it exercised the handler without ever consulting the
set the app actually ships. A guard against exactly this follows with the next
commit, once the last actions have left the switch and the shipped set is
supposed to be complete.
close, init, click and hide were the last actions in the switch, and with them
gone it collapses to a single guard for ready, which waits on its payload
builder.

They are also the first use of what the capability protocols are for. The
handler is registered everywhere like any other, and a host that has no window
to close simply does not conform: the message is journalled and dropped rather
than refused. That is the whole mechanism by which a surface picks one of these
up later — a conformance, and nothing else changes.

bridgeDidInit sets hasReceivedInit before it does anything else. The no-cache
retry policy decides whether a failed subresource is worth healing by asking
whether the page ever booted, and a flag set late silently disables the healing
with no other symptom.

The factory guard arrives here: every action a page can send must have an owner
in the shipped set, save ready and the two that only travel native to JS. It
was written against the omission fixed in the previous commit and does fail on
it, naming both actions.
The last action leaves the switch, and with it the switch itself: dispatch is
now the registry and nothing else.

Composing the payload moves into a builder of its own. Three callers need it
rather than one — ready, the config-update push, and shortly the embedded block
— and the assembly was private to the WebView facade, which is neither the
right owner nor reachable from a block.

What goes in belongs to the host, not the handler: an in-app knows its
operation, a block will know its configuration entry, while answering ready
with it is the same everywhere. The facade hands the payload over instead of
sending it, and sendReadyEvent goes with it.

The order the fields are applied in is preserved and now pinned: the
configuration's own params are merged before the operation and the track-visit
fields, so a colliding key resolves towards the operation.

Serialization is guarded before it runs. JSONSerialization raises an
Objective-C exception for a NaN or an infinity instead of throwing, so the
existing catch could never have run and the host app would have gone down —
the empty-object fallback the code already promised was not reachable. Values
arriving here are decoded from JSON today, which can express neither, but this
is the payload every surface is answered with and the assumption is not worth
a crash. Found by the test that pins the fallback.
The block spoke a dialect of its own: its own handler name, its own envelope,
one stub action, and no way for the SDK to say anything back. It now speaks
what in-apps speak, which is the whole point — a page written once works in
either surface, and the block gets logging, local state, links and operations
without a line of block-specific code.

Readiness comes from contentRendered instead of a height. The page reports how
much it drew, once per load: nothing drawn is a valid outcome and collapses the
block without an error screen, which is precisely why this is not init — that
one is welded to presenting a window and has no such ending.

height and heightChanged go with it. The host has always owned the block's
height; the page never had a say, and the site will not be sending a number.

Two files are deleted rather than adapted. EmbeddedBlockPageMessage was the
whole ad-hoc envelope, and EmbeddedBlockActionRouter knew a single action which
it only logged — the shared openLink replaces it outright.

The load's navigation is handed to the bridge. Its staleness gate drops every
script message until that exact document commits, so a reused web view cannot
deliver a previous owner's — and without this the page's messages would vanish
in silence while the block waited out its whole budget.

Navigation policy comes with the bridge too: a tap on a link is refused in
place. A block is a piece of the host's own layout, and replacing the feed with
the destination there is a dead end with no way back; links belong in openLink.

Whether a user is actually looking is now the page's business to know. The
provider keeps it current, and the bridge reads it before acting on the user's
behalf — a block off screen keeps a live page that can still deliver whatever
its setTimeout scheduled.

The waiting budget goes to twelve seconds. It now covers strictly more than
before: load, bridge boot, the start payload, the page's own pipeline including
up to three seconds of waiting on targeting, and only then the report.
Both are answered but neither is implemented: the web page already calls
checkInappsTargeting, and until something owns it the registry reports no owner,
the page waits out its three seconds and renders an empty feed. Answering is
what makes the rest of the contract reachable.

checkInappsTargeting lets every id through, in the order it was asked about —
the page maps the answer back onto its own cards. showInApp journals the request
and acknowledges it, so the page can finish its own flow instead of sitting on a
promise nothing will settle.

The shapes are taken from the page rather than from the ticket: it reads
payload.inappIds and throws when that key is absent, so a reply of the wrong
shape and no reply at all look identical from the feed. The tests pin those
shapes for the same reason.

What each will actually do is written down where it will be written, as
comments: the targeting source and its cold-cache behaviour, the thread the
segmentation cache is written from, and for the show — bypassing the gates by
not entering the pipeline at all, tracking the show anyway, and merging params
last so it overwrites everything including service keys.

The block address moves to the staging host, which is where the page that
implements this contract is published.
The base captured the view weakly here — handler.request { [weak self] … } —
and the move into a handler turned that into a strong capture of the host. A
system dialog stands for as long as the user leaves it standing, so a request
that actually shows one pinned TransparentView and with it the whole handler
set: an uncancelled ready checker, and a live sensor subscription if the page
had asked for motion.

settings.open had the same asymmetry inside one switch: the .application route
reached the system through BridgeURLOpening with [weak host], the .notifications
route did not. The hold there is short — the seconds of a screen change — but a
rule that holds on one branch of a switch and not the other is not a rule.

Both routes now answer only a page that is still around, which is what the base
did. The spies learned to hold their answer back: that pause is the only window
in which what the SDK keeps alive is observable at all.
openLink answers the page from the presentation completion, and UIKit does not
call that completion when the presentation does not happen. A controller that is
already presenting refuses to present anything else — and the block asked the
window's root, which is exactly the controller that is already presenting
whenever anything modal stands above it: the block inside a bottom sheet, an
alert, a share sheet, another in-app from this same SDK. The tap opened nothing,
nothing was journalled, and the promise in JS never settled.

The presenter is now the topmost of the presentation chain, the same walk the
snackbar strategy makes. The change is in the block's own answer to "what do I
present from" rather than in the handler, so the in-app surface stays as it is in
develop: for TransparentView the presenter is still its own view controller.

Presenting for real in a test would drag a visible window and a transition into
it, so the controllers report what the test put on top of them — what is checked
is the walk, not UIKit's animation.

The answer still leaves from the completion, so a presenter caught mid-dismissal
can still swallow it. That is the remaining half of this finding, not of this
commit.
OperationActionHandler was the largest handler of the move with no file of its
own. Its two neighbours keep what they already cover — makeSyncOperationResponse
as the pure mapping it is, and the tag merge through the view — so the new suite
takes the wiring between them: the queue write and the branch where it fails,
the answer to a sync operation in both outcomes, the shapes of payload it
refuses, and that a request in flight does not hold the page alive. Its event
repository holds its answer back, because that pause is the only window in which
what the SDK keeps alive is observable at all.

The block speaking the shared bridge was the point of 09bef19 and had no test
at all. Now a request from its document reaches the registry with the page as
the host, an answer is not routed as if it were a request, an action nobody owns
is dropped without disturbing the block, and the identity the page lends a
handler is its own.

BridgeURLOpening gets the half that has a decision in it: which outcome becomes
which answer. SystemURLOpener stays out, as its own documentation says it must.
WebBridgeHostResponseTests moves out of the registry's file, where it was a
stranger.

Three branches of moved code were reachable but unasserted: a url that does not
parse, a url with no scheme, and the Safari fallback with no presenter to fall
back on — the last being the path the presenter walk was changed for. Motion's
first guard is covered too, where nothing arrived at all as against something in
the wrong shape.

loadRegistersItsNavigation still does not prove what it is named for.
contentLoadIssued and contentURL are private to MindboxWebBridge, and a
WKScriptMessage cannot be built in a test to drive the gate from outside, so it
pins the visible half — the load goes to the block's own address — and says so
where it stands.
A weak local declared empty and assigned later carries no "never mutated"
warning, so watching a page's release needs no box to hold the reference.
@Vailence
Vailence requested a review from justSmK August 14, 2026 12:17
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor
TestsPassed ✅SkippedFailedTime ⏱
Unit tests report1698 ran1698 ✅1m 41s 370ms

The two `swiftlint:disable empty_count` directives read as superfluous to
SwiftLint 0.65, while older versions do flag those lines — dropping the
directives alone would only trade one error for the other. Naming the value
`renderedCount` leaves neither version anything to say.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Unifies in-app and embedded-block WebViews behind a shared action-handler registry.

Changes:

  • Extracts bridge actions into session-scoped handlers and a registry.
  • Migrates embedded blocks to the shared bridge.
  • Adds extensive handler, routing, lifecycle, and payload tests.

Reviewed changes

Copilot reviewed 58 out of 58 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
MindboxTests/InApp/Tests/WebView/TransparentViewJSBridgeTests.swift Updates bridge routing tests.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/WebViewStartPayloadBuilderTests.swift Tests start payload construction.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/WebBridgeHostTests.swift Tests response envelopes.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/WebBridgeActionRegistryTests.swift Tests registry routing and teardown.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/WebBridgeActionHandlerFactoryTests.swift Tests shipped handler composition.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/TargetingAndShowStubTests.swift Tests future-action stubs.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/SettingsActionHandlerTests.swift Tests settings handling.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/ReadyActionHandlerTests.swift Tests ready payload responses.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/PermissionActionHandlerTests.swift Tests permission requests.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/OperationActionHandlerTests.swift Tests operation dispatch.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/OpenLinkActionHandlerTests.swift Tests URL routing.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/MotionActionHandlerTests.swift Tests motion lifecycle.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/LogActionHandlerTests.swift Tests bridge logging.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/LocalStateActionHandlerTests.swift Tests local-state actions.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/LifecycleActionHandlerTests.swift Tests lifecycle callbacks.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/HapticActionHandlerTests.swift Tests haptic lifecycle.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/ContentRenderedActionHandlerTests.swift Tests rendered-content reports.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/BridgeURLOpeningTests.swift Tests system URL opening.
MindboxTests/InApp/Tests/WebView/BridgeHandlers/BridgeHandlerDoubles.swift Adds shared test doubles.
MindboxTests/InApp/Tests/TransparentViewSyncOperationResponseTests.swift Retargets operation response tests.
MindboxTests/EmbeddedBlocks/MindboxEmbeddedBlockViewTests.swift Updates block presentation tests.
MindboxTests/EmbeddedBlocks/EmbeddedBlockWebViewProviderTests.swift Tests content and presence state.
MindboxTests/EmbeddedBlocks/EmbeddedBlockWebViewPageTests.swift Tests shared bridge hosting.
MindboxTests/EmbeddedBlocks/EmbeddedBlockMocks.swift Updates embedded-block mocks.
MindboxTests/EmbeddedBlocks/EmbeddedBlockContentProviderFactoryTests.swift Updates factory tests.
Mindbox/Utilities/Constants.swift Extends embedded-block timeout.
Mindbox/InAppMessages/Presentation/Views/WebView/WebViewController.swift Removes legacy log callback.
Mindbox/InAppMessages/Presentation/Views/WebView/TransparentView.swift Delegates actions to the registry.
Mindbox/InAppMessages/Presentation/Views/WebView/Settings/SettingsRequestParser.swift Reuses shared payload parsing.
Mindbox/InAppMessages/Presentation/Views/WebView/Debug/MindboxWebViewFacade.swift Delegates start payload building.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/WebViewStartPayloadBuilder.swift Adds shared payload builder.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/WebBridgeHost.swift Defines bridge host capabilities.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/WebBridgeActionHandlerFactory.swift Builds per-session handlers.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/WebBridgeActionHandler.swift Defines handlers and registry.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/ShowInAppActionHandler.swift Adds show-in-app stub.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/SettingsActionHandler.swift Extracts settings handling.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/ReadyActionHandler.swift Extracts ready handling.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/PermissionActionHandler.swift Extracts permission handling.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/OperationActionHandler.swift Extracts operation handling.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/OpenLinkActionHandler.swift Extracts link handling.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/MotionActionHandler.swift Extracts motion handling.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/LogActionHandler.swift Extracts logging.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/LocalStateActionHandler.swift Extracts local-state handling.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/LifecycleActionHandler.swift Extracts lifecycle handling.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/HapticActionHandler.swift Extracts haptic handling.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/ContentRenderedActionHandler.swift Handles content counts.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/CheckInappsTargetingActionHandler.swift Adds targeting stub.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/Handlers/BridgeURLOpening.swift Adds shared URL-opening seam.
Mindbox/InAppMessages/Presentation/Views/WebView/Bridge/BridgeMessage.swift Extends action vocabulary and payload helpers.
Mindbox/EmbeddedBlocks/WebView/EmbeddedBlockWebViewProvider.swift Uses content reports and presence state.
Mindbox/EmbeddedBlocks/WebView/EmbeddedBlockWebViewPage.swift Migrates blocks to the shared bridge.
Mindbox/EmbeddedBlocks/WebView/EmbeddedBlockPageMessage.swift Removes the legacy message channel.
Mindbox/EmbeddedBlocks/WebView/EmbeddedBlockPageHosting.swift Updates the page-host contract.
Mindbox/EmbeddedBlocks/Resolver/EmbeddedBlockResolver.swift Changes the stories endpoint.
Mindbox/EmbeddedBlocks/Container/EmbeddedBlockContentProviderFactory.swift Removes legacy router injection.
Mindbox/EmbeddedBlocks/Actions/EmbeddedBlockActionRouter.swift Removes the legacy action router.
Mindbox/DI/Injections/InjectEmbeddedBlocks.swift Updates embedded-block registrations.
Mindbox.xcodeproj/project.pbxproj Adds synchronized handler groups.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

/// delivers whatever its `setTimeout` scheduled. Not a single touch stands behind such a
/// message, so anything acting on the user's behalf — opening a link, showing a window —
/// must not run on it.
var isUserPresent: Bool { get }
// deciding whether the page may act on the user's behalf.
outcome = nil
didReportContent = false
page?.isUserPresent = true
case .int(let count):
return count
case .double(let count):
return Int(exactly: count.rounded())
Comment on lines +323 to +327
/// JS asks which of these in-apps currently pass targeting.
///
/// Answered from targeting the SDK has already computed, without going to the network:
/// the page gives up on the answer after three seconds and renders nothing rather than
/// wait. The reply keeps the ids that pass, in the order they were asked about.
Comment on lines +339 to +346
/// JS asks for an in-app to be shown by id.
///
/// `params` is merged into that in-app's start payload and overwrites whatever it
/// collides with. The SDK neither validates nor limits it: what the page sends is what
/// the page gets, and avoiding collisions is the page's business.
///
/// `index` and `sourceInappId` describe where the request came from and are journalled,
/// not passed on — the page already puts everything it needs into `params`.
/// The stories feed page on static hosting. Hardcoded for now: once the admin panel config
/// arrives, the address will come from there together with the id → content mapping.
private static let storiesPageURL = "https://mobile-static.mindbox.ru/beta/inapps/webview/content/stories.html"
private static let storiesPageURL = "https://mobile-static-staging.mindbox.ru/inapps/webview/content/stories.html"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants