Skip to content

Commit 4678800

Browse files
adsjs ping changes (#1922)
* Initial move * Trigger args updating * Add config listener * Add listener to web compat * Make idempotent and remove old code path * Rename method * Add updateFeatureArgs to integration test
1 parent 0c51a4e commit 4678800

File tree

6 files changed

+117
-11
lines changed

6 files changed

+117
-11
lines changed

injected/entry-points/android-adsjs.js

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,54 @@
11
/**
22
* @module Android AdsJS integration
33
*/
4-
import { load, init } from '../src/content-scope-features.js';
5-
import { processConfig } from './../src/utils';
6-
import { AndroidAdsjsMessagingConfig } from '../../messaging/index.js';
4+
import { load, init, updateFeatureArgs } from '../src/content-scope-features.js';
5+
import { processConfig, isBeingFramed } from './../src/utils';
6+
import { AndroidAdsjsMessagingConfig, MessagingContext, Messaging } from '../../messaging/index.js';
7+
8+
/**
9+
* Send initial ping once per frame to establish communication with the platform.
10+
* This replaces the per-feature ping that was previously sent in AndroidAdsjsMessagingTransport.
11+
* When response is received, updates all loaded feature configurations.
12+
*
13+
* @param {AndroidAdsjsMessagingConfig} messagingConfig
14+
* @param {object} processedConfig - The base configuration
15+
*/
16+
async function sendInitialPingAndUpdate(messagingConfig, processedConfig) {
17+
// Only send ping in top context, not in frames
18+
if (isBeingFramed()) {
19+
return;
20+
}
21+
22+
try {
23+
// Create messaging context for the initial ping
24+
const messagingContext = new MessagingContext({
25+
context: 'contentScopeScripts',
26+
env: processedConfig.debug ? 'development' : 'production',
27+
featureName: 'messaging',
28+
});
29+
30+
// Create messaging instance - handles all the subscription/error boilerplate
31+
const messaging = new Messaging(messagingContext, messagingConfig);
32+
33+
if (processedConfig.debug) {
34+
console.log('AndroidAdsjs: Sending initial ping...');
35+
}
36+
37+
// Send the ping request
38+
const response = await messaging.request('initialPing', {});
39+
40+
// Update all loaded features with merged configuration
41+
if (response && typeof response === 'object') {
42+
const updatedConfig = { ...processedConfig, ...response };
43+
44+
await updateFeatureArgs(updatedConfig);
45+
}
46+
} catch (error) {
47+
if (processedConfig.debug) {
48+
console.error('AndroidAdsjs: Initial ping failed:', error);
49+
}
50+
}
51+
}
752

853
function initCode() {
954
// @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f
@@ -24,6 +69,10 @@ function initCode() {
2469
debug: processedConfig.debug,
2570
});
2671

72+
// Send initial ping asynchronously to update feature configurations when response arrives
73+
sendInitialPingAndUpdate(processedConfig.messagingConfig, processedConfig);
74+
75+
// Load and init features immediately with base configuration
2776
load({
2877
platform: processedConfig.platform,
2978
site: processedConfig.site,

injected/entry-points/integration.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { load, init } from '../src/content-scope-features.js';
1+
import { load, init, updateFeatureArgs } from '../src/content-scope-features.js';
22
import { TestTransportConfig } from '../../messaging/index.js';
33
import { getTabUrl } from '../src/utils.js';
44

@@ -120,6 +120,7 @@ async function initCode() {
120120
window.__testContentScopeArgs = merged;
121121
// init features
122122
await init(merged);
123+
await updateFeatureArgs(merged);
123124

124125
// set status to initialized so that tests can resume
125126
setStatus('initialized');

injected/src/content-feature.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ export default class ContentFeature extends ConfigFeature {
4242
*/
4343
listenForUpdateChanges = false;
4444

45+
/**
46+
* Set this to true if you wish to receive configuration updates from initial ping responses (Android only).
47+
* @type {boolean}
48+
*/
49+
listenForConfigUpdates = false;
50+
4551
/** @type {ImportMeta} */
4652
#importConfig;
4753

@@ -223,6 +229,17 @@ export default class ContentFeature extends ConfigFeature {
223229
*/
224230
update() {}
225231

232+
/**
233+
* Called when user preferences are merged from initial ping response. (Android only)
234+
* Override this method in your feature to handle user preference updates.
235+
* This only happens once during initialization when the platform responds with user-specific settings.
236+
* @param {object} _updatedConfig - The configuration with merged user preferences
237+
*/
238+
onUserPreferencesMerged(_updatedConfig) {
239+
// Default implementation does nothing
240+
// Features can override this to handle user preference updates
241+
}
242+
226243
/**
227244
* Register a flag that will be added to page breakage reports
228245
*/

injected/src/content-scope-features.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,34 @@ export function update(args) {
117117
updateFeaturesInner(args);
118118
}
119119

120+
/**
121+
* Update the args for feature instances that opt in to configuration updates.
122+
* This is useful for applying configuration updates received after initial loading.
123+
*
124+
* @param {object} updatedArgs - The new arguments to apply to opted-in features
125+
*/
126+
export async function updateFeatureArgs(updatedArgs) {
127+
if (!isHTMLDocument) {
128+
return;
129+
}
130+
131+
const resolvedFeatures = await Promise.all(features);
132+
resolvedFeatures.forEach(({ featureInstance }) => {
133+
// Only update features that have opted in to config updates
134+
if (featureInstance && featureInstance.listenForConfigUpdates) {
135+
// Update the feature's args
136+
if (typeof featureInstance.setArgs === 'function') {
137+
featureInstance.setArgs(updatedArgs);
138+
}
139+
140+
// Call the optional onUserPreferencesMerged method if it exists
141+
if (typeof featureInstance.onUserPreferencesMerged === 'function') {
142+
featureInstance.onUserPreferencesMerged(updatedArgs);
143+
}
144+
}
145+
});
146+
}
147+
120148
function alwaysInitExtensionFeatures(args, featureName) {
121149
return args.platform.name === 'extension' && alwaysInitFeatures.has(featureName);
122150
}

injected/src/features/web-compat.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ export class WebCompat extends ContentFeature {
8787
/** @type {Promise<any> | null} */
8888
#activeScreenLockRequest = null;
8989

90+
// Opt in to receive configuration updates from initial ping responses
91+
listenForConfigUpdates = true;
92+
9093
init() {
9194
if (this.getFeatureSettingEnabled('windowSizing')) {
9295
windowSizingFix();
@@ -123,10 +126,6 @@ export class WebCompat extends ContentFeature {
123126
this.shimWebShare();
124127
}
125128

126-
if (this.getFeatureSettingEnabled('viewportWidth')) {
127-
this.viewportWidthFix();
128-
}
129-
130129
if (this.getFeatureSettingEnabled('screenLock')) {
131130
this.screenLockFix();
132131
}
@@ -146,6 +145,21 @@ export class WebCompat extends ContentFeature {
146145
}
147146
}
148147

148+
/**
149+
* Handle user preference updates when merged during initialization.
150+
* Re-applies viewport fixes if viewport configuration has changed.
151+
* @param {object} _updatedConfig - The configuration with merged user preferences
152+
*/
153+
onUserPreferencesMerged(_updatedConfig) {
154+
// Re-apply viewport width fix if viewport settings might have changed
155+
if (this.getFeatureSettingEnabled('viewportWidth')) {
156+
if (!this._viewportWidthFixApplied) {
157+
this.viewportWidthFix();
158+
this._viewportWidthFixApplied = true;
159+
}
160+
}
161+
}
162+
149163
/** Shim Web Share API in Android WebView */
150164
shimWebShare() {
151165
if (typeof navigator.canShare === 'function' || typeof navigator.share === 'function') return;

messaging/lib/android-adsjs.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ export class AndroidAdsjsMessagingTransport {
3333
constructor(config, messagingContext) {
3434
this.messagingContext = messagingContext;
3535
this.config = config;
36-
37-
// Send initial ping when transport is first created.
38-
this.config.sendInitialPing(messagingContext);
3936
}
4037

4138
/**

0 commit comments

Comments
 (0)