|
| 1 | +<!doctype html> |
| 2 | +<html lang="en"> |
| 3 | + <head> |
| 4 | + <meta charset="utf-8" /> |
| 5 | + <meta name="viewport" content="width=device-width, initial-scale=1" /> |
| 6 | + <title>mParticle WebView Bridge Test</title> |
| 7 | + <style> |
| 8 | + body { font-family: sans-serif; background: #111; color: #fff; padding: 16px; } |
| 9 | + button { padding: 12px 14px; margin-right: 10px; border-radius: 10px; border: 0; background: #4079fe; color: #fff; font-weight: 600; } |
| 10 | + .muted { opacity: 0.7; } |
| 11 | + </style> |
| 12 | + <script type="text/javascript"> |
| 13 | + // WebView-only snippet (NO API KEY) + required bridge name. |
| 14 | + const mySdkConfig = { |
| 15 | + requiredWebviewBridgeName: "higgsWebviewBridge", |
| 16 | + isDevelopmentMode: true |
| 17 | + }; |
| 18 | + window.mParticle = { config: mySdkConfig }; |
| 19 | + |
| 20 | + (function () { |
| 21 | + window.mParticle = window.mParticle || { |
| 22 | + EventType: { Unknown: 0, Navigation: 1, Location: 2, Search: 3, Transaction: 4, UserContent: 5, UserPreference: 6, Social: 7, Other: 8 } |
| 23 | + }; |
| 24 | + window.mParticle.eCommerce = { Cart: {} }; |
| 25 | + window.mParticle.Identity = {}; |
| 26 | + window.mParticle.config = window.mParticle.config || {}; |
| 27 | + window.mParticle.config.rq = []; |
| 28 | + window.mParticle.ready = function (t) { window.mParticle.config.rq.push(t); }; |
| 29 | + function e(e, o) { |
| 30 | + return function () { |
| 31 | + if (o) { e = o + "." + e; } |
| 32 | + var t = Array.prototype.slice.call(arguments); |
| 33 | + t.unshift(e); |
| 34 | + window.mParticle.config.rq.push(t); |
| 35 | + }; |
| 36 | + } |
| 37 | + var o = ["endSession", "logError", "logEvent", "logForm", "logLink", "logPageView", "setSessionAttribute", "setAppName", "setAppVersion", "setOptOut", "setPosition", "startNewSession", "startTrackingLocation", "stopTrackingLocation"]; |
| 38 | + var n = ["setCurrencyCode", "logCheckout"]; |
| 39 | + var i = ["identify", "login", "logout", "modify"]; |
| 40 | + o.forEach(function (t) { window.mParticle[t] = e(t); }); |
| 41 | + n.forEach(function (t) { window.mParticle.eCommerce[t] = e(t, "eCommerce"); }); |
| 42 | + i.forEach(function (t) { window.mParticle.Identity[t] = e(t, "Identity"); }); |
| 43 | + var r = document.createElement("script"); |
| 44 | + r.type = "text/javascript"; |
| 45 | + r.async = true; |
| 46 | + r.src = "https://jssdkcdns.mparticle.com/js/v2/mparticle.js"; |
| 47 | + var c = document.getElementsByTagName("script")[0]; |
| 48 | + c.parentNode.insertBefore(r, c); |
| 49 | + })(); |
| 50 | + </script> |
| 51 | + </head> |
| 52 | + <body> |
| 53 | + <h2>mParticle WebView Bridge</h2> |
| 54 | + <p class="muted"> |
| 55 | + This page is loaded from <code>file:///android_asset</code> and uses the Web SDK in bridged mode. |
| 56 | + Click the button to log a JS event that should be forwarded through the Android SDK. |
| 57 | + </p> |
| 58 | + |
| 59 | + <button id="btnEvent">Log JS Event</button> |
| 60 | + <button id="btnPage">Log Page View</button> |
| 61 | + |
| 62 | + <hr style="border:0;border-top:1px solid rgba(255,255,255,0.15);margin:18px 0;" /> |
| 63 | + |
| 64 | + <h3 style="margin:0 0 10px 0;">Identity Alias (JS → Native)</h3> |
| 65 | + <p class="muted" style="margin-top:0;"> |
| 66 | + This calls <code>mParticle.Identity.aliasUsers</code>. In WebView bridge mode this is queued as a JS request and |
| 67 | + forwarded to the Android SDK. We auto-populate a valid aliasRequest from the native SDK (MPIDs + time window), |
| 68 | + similar to the docs reference. |
| 69 | + </p> |
| 70 | + |
| 71 | + <div style="display:flex;flex-direction:column;gap:10px;max-width:520px;"> |
| 72 | + <div class="muted" id="aliasInfo">Waiting for native MPIDs…</div> |
| 73 | + <div> |
| 74 | + <button id="btnAlias" disabled style="opacity:0.6;">Send Alias Users</button> |
| 75 | + </div> |
| 76 | + </div> |
| 77 | + |
| 78 | + <script> |
| 79 | + function log(msg) { |
| 80 | + // Keep logs out of the UI; use console instead. |
| 81 | + console.log((new Date().toISOString()) + " " + msg); |
| 82 | + } |
| 83 | + |
| 84 | + document.getElementById("btnEvent").addEventListener("click", function () { |
| 85 | + if (!window.mParticle) return log("mParticle not available"); |
| 86 | + window.mParticle.logEvent( |
| 87 | + "WebView JS Button Click", |
| 88 | + window.mParticle.EventType.Other, |
| 89 | + { source: "webview", bridgeName: "higgsWebviewBridge" } |
| 90 | + ); |
| 91 | + log("Called mParticle.logEvent('WebView JS Button Click')"); |
| 92 | + }); |
| 93 | + |
| 94 | + document.getElementById("btnPage").addEventListener("click", function () { |
| 95 | + if (!window.mParticle) return log("mParticle not available"); |
| 96 | + window.mParticle.logPageView("WebView Bridge Test", { source: "webview" }); |
| 97 | + log("Called mParticle.logPageView('WebView Bridge Test')"); |
| 98 | + }); |
| 99 | + |
| 100 | + window.__mp = window.__mp || {}; |
| 101 | + window.__mp.aliasRequest = window.__mp.aliasRequest || null; |
| 102 | + |
| 103 | + // Called by native via evaluateJavascript after page load |
| 104 | + window.setNativeAliasRequest = function (aliasRequest) { |
| 105 | + window.__mp.aliasRequest = aliasRequest || null; |
| 106 | + const info = document.getElementById("aliasInfo"); |
| 107 | + const btn = document.getElementById("btnAlias"); |
| 108 | + if (!window.__mp.aliasRequest) { |
| 109 | + info.textContent = "Missing aliasRequest from native SDK"; |
| 110 | + btn.disabled = true; |
| 111 | + btn.style.opacity = "0.6"; |
| 112 | + return; |
| 113 | + } |
| 114 | + const ar = window.__mp.aliasRequest; |
| 115 | + const valid = !!ar.sourceMpid && !!ar.destinationMpid && String(ar.sourceMpid) !== String(ar.destinationMpid); |
| 116 | + info.textContent = |
| 117 | + `Using sourceMpid=${ar.sourceMpid} → destinationMpid=${ar.destinationMpid} ` + |
| 118 | + `(scope=${ar.scope || "device"})`; |
| 119 | + btn.disabled = !valid; |
| 120 | + btn.style.opacity = valid ? "1" : "0.6"; |
| 121 | + if (!valid) { |
| 122 | + info.textContent = "Invalid MPIDs from native SDK (need 2 unique users)"; |
| 123 | + } |
| 124 | + }; |
| 125 | + |
| 126 | + // If native injected a pending request before this function was defined, apply it now. |
| 127 | + if (window.__mp && window.__mp._pendingAliasRequest) { |
| 128 | + window.setNativeAliasRequest(window.__mp._pendingAliasRequest); |
| 129 | + } |
| 130 | + |
| 131 | + // Log screen view from JS (not native) when page loads |
| 132 | + window.mParticle.ready(function() { |
| 133 | + if (window.mParticle && typeof window.mParticle.logScreen === "function") { |
| 134 | + window.mParticle.logScreen("WebView Bridge"); |
| 135 | + log("Called mParticle.logScreen('WebView Bridge') from JS"); |
| 136 | + } |
| 137 | + }); |
| 138 | + |
| 139 | + document.getElementById("btnAlias").addEventListener("click", function () { |
| 140 | + // Send alias request from WebView (JS) per Web SDK docs: |
| 141 | + // https://docs.mparticle.com/developers/client-sdks/web/idsync/#user-aliasing |
| 142 | + if (!window.mParticle || !window.mParticle.Identity) return log("mParticle.Identity not available"); |
| 143 | + if (typeof window.mParticle.Identity.aliasUsers !== "function") return log("mParticle.Identity.aliasUsers not available yet"); |
| 144 | + if (!window.__mp.aliasRequest) return log("Alias blocked: missing aliasRequest (native injection not ready)"); |
| 145 | + |
| 146 | + const sourceMpidStr = String(window.__mp.aliasRequest.sourceMpid || "").trim(); |
| 147 | + const destinationMpidStr = String(window.__mp.aliasRequest.destinationMpid || "").trim(); |
| 148 | + |
| 149 | + if (!sourceMpidStr || !destinationMpidStr) { |
| 150 | + return log("Alias blocked: missing MPIDs"); |
| 151 | + } |
| 152 | + if (sourceMpidStr === destinationMpidStr) { |
| 153 | + return log("Alias blocked: sourceMpid and destinationMpid must be unique"); |
| 154 | + } |
| 155 | + |
| 156 | + // Parse MPIDs as numbers for the bridge (may lose precision for very large MPIDs, |
| 157 | + // but the bridge might require numeric values to convert to native long). |
| 158 | + const sourceMpidNum = Number(sourceMpidStr); |
| 159 | + const destinationMpidNum = Number(destinationMpidStr); |
| 160 | + |
| 161 | + if (!Number.isFinite(sourceMpidNum) || !Number.isFinite(destinationMpidNum)) { |
| 162 | + return log(`Alias blocked: MPIDs not numeric (source=${sourceMpidStr}, dest=${destinationMpidStr})`); |
| 163 | + } |
| 164 | + if (sourceMpidNum <= 0 || destinationMpidNum <= 0) { |
| 165 | + return log(`Alias blocked: MPIDs must be positive (source=${sourceMpidNum}, dest=${destinationMpidNum})`); |
| 166 | + } |
| 167 | + |
| 168 | + const now = Date.now(); |
| 169 | + // Per Web SDK docs format: MPIDs as numbers, times as numbers (ms since epoch) |
| 170 | + const aliasRequest = { |
| 171 | + sourceMpid: sourceMpidNum, |
| 172 | + destinationMpid: destinationMpidNum, |
| 173 | + startTime: now - (30 * 60 * 1000), // last 30 minutes |
| 174 | + endTime: now, |
| 175 | + scope: "device" |
| 176 | + }; |
| 177 | + |
| 178 | + log(`Sending aliasRequest: sourceMpid=${sourceMpidNum} (from "${sourceMpidStr}"), destinationMpid=${destinationMpidNum} (from "${destinationMpidStr}")`); |
| 179 | + |
| 180 | + window.mParticle.Identity.aliasUsers(aliasRequest, function (code, body) { |
| 181 | + log(`aliasUsers callback: code=${code} body=${JSON.stringify(body)}`); |
| 182 | + }); |
| 183 | + log(`Called mParticle.Identity.aliasUsers(${JSON.stringify(aliasRequest)})`); |
| 184 | + }); |
| 185 | + |
| 186 | + log("Loaded. Waiting for user action…"); |
| 187 | + </script> |
| 188 | + </body> |
| 189 | +</html> |
0 commit comments