Skip to content

chore: WebViewSyncPlugin#253

Open
crleona wants to merge 1 commit intomainfrom
webview_sync_plugin
Open

chore: WebViewSyncPlugin#253
crleona wants to merge 1 commit intomainfrom
webview_sync_plugin

Conversation

@crleona
Copy link
Copy Markdown
Collaborator

@crleona crleona commented Jan 9, 2025

Summary

Adds a prototype plugin to sync user, device, and session ids to all webviews in an app. This may be an easier approach for hybrid apps to sync Amplitude properties to their webviews, vs manually injecting device and session ids.

Screenshot 2025-01-09 at 9 50 39 AM

(The extraneous session start events are generated from the JS library auto tracking - we should add a method to set the session id without generating these).

Customers that are newly adopting this sync strategy may want to change the JS plugin to compare and report mismatches in device / user / session id vs setting them directly.

Current rough JS plugin:

amplitude.add((function () {
    if (!window.amp_webview_config) {
        return {};
    }

    var amplitude = null;
    var apiKey = null;

    const updateConfig = function(config) {
        if (!amplitude || !config) {
            return;
        }

        if (apiKey != config["api_key"]) {
            return;
        }

        const userId = config["user_id"];
        if (amplitude.getUserId() != userId) {
            amplitude.setUserId(userId);
        }

        const deviceId = config["device_id"];
        if (amplitude.getDeviceId() != deviceId) {
            amplitude.setDeviceId(deviceId);
        }

        const sessionId = config["session_id"];
        if (amplitude.getSessionId() != sessionId) {
            amplitude.setSessionId(sessionId);
        }
    }

    function setup(config, amp) {
        amplitude = amp;
        apiKey = config.apiKey;
        window.amp_webview_config.subscribe(updateConfig);
        const webviewConfig = window.amp_webview_config.getConfig();
        if (webviewConfig) {
            updateConfig(webviewConfig);
        }
    }

    function teardown() {
        window.amp_webview_config.unsubscribe(updateConfig);
    }
  
    return {
      setup: setup,
      teardown: teardown,
    };
  })());

How it works:

  • We swizzle WKWebView init to inject our loader script into each webview as it's created. The loader script has to be static as we can't change or remove it, so we need to inject the actual data elsewhere.
  • Each time the script loads (ie, when a page changes) the script sends a signal to re-inject the current amplitude data. This also is re-injected on config change.
  • Pre-injection guarantees availability on page load. Clients will be notified of any config changes when registered.
  • If the injected script is not detected or the api key is mismatched (we may load a third party website), config changes are ignored.

Checklist

  • Does your PR title have the correct title format?
  • Does your PR have a breaking change?: no

@crleona crleona requested a review from a team January 9, 2025 18:03
@Mercy811
Copy link
Copy Markdown
Collaborator

Mercy811 commented Jan 9, 2025

Thanks @crleona for better supporting web views.

(The extraneous session start events are generated from the JS library auto tracking - we should add a method to set the session id without generating these).

I don't see why customers should turn session tracking on in webviews as it's part of the mobile app. The session should start when they open the mobile app instead of open webviews. Customers should turn browser SDK session tracking off.

@crleona
Copy link
Copy Markdown
Collaborator Author

crleona commented Jan 9, 2025

I don't see why customers should turn session tracking on in webviews as it's part of the mobile app. The session should start when they open the mobile app instead of open webviews. Customers should turn browser SDK session tracking off.

@Mercy811 -
I agree they should not have session tracking on both, but for pages that may be used in both webview and browser contexts we'd either need clients to flag that and disable session tracking themselves or we just bypass it as described here. The latter seems a bit easier to me, but it does require changes to the browser API. (iirc we had a direct parallel in the legacy SDKs, though). Are there any cases that would break with this approach or is there any other context I'm missing? We should be able to test this without it but longer term (and especially if adoption picks up) it seems like an easy win.


private let webviews = NSHashTable<WKWebView>.weakObjects()

private static let swizzleWebViewInitializer: Void = {
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.

Instead of swizzling the initializer which would affect all web views, would it be better to document that consumers could attach WebViewSyncPlugin.registerWebview(webview) at their own callsites to attach the Amplitude plugin?

This would allow us to specify if we wish to attach the user script for a particular webview rather than automatically do it for all, as well as avoid any downsides of the swizzling approach.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Hi @thedavidharris, this is just a sample plugin that we do not expect to ship with the SDK, I'd encourage you to modify it to fit your specific needs.

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.

4 participants