Skip to content

更新日志

This content is not available in your language yet.

📌 双端发布:Android Maven 1.0.0.64-SNAPSHOT + iOS xcframework 均源码重建。supersimples Android 模板 sdk.androidVersion 切到 1.0.0.64-SNAPSHOT。

H5 navigator.mediaDevices.getUserMedia({ audio: true }) 由 SuperSDK 容器接管,宿主不必再包 WebChromeClient / WKUIDelegate。

  • Android
    • 容器处理纯 AUDIO_CAPTURE;含 VIDEO_CAPTURE 或其它非音频资源的请求整次 deny。
    • 使用 SuperPageActivity / IPageController.open():不用写 Java,自动注入公开 com.supersdk.api.page.IFileChooserHost。
    • 自包装:Activity 实现该接口(含 launchMicrophonePermission),在 onCreate 注册 launcher,禁止替换 WebChromeClient。
    • 宿主必须自行声明 RECORD_AUDIO(SDK 不 merge)。CAMERA 仍由 SDK merge(<input type="file" capture> 拍照)。
  • iOS 15+
    • SuperWebView 实现 WKUIDelegate.requestMediaCapturePermissionFor:microphone 无/空 NSMicrophoneUsageDescription → Deny,否则 Prompt;camera 恒 Prompt;cameraAndMicrophone 无 mic 说明 → Deny,否则 Prompt。不读 AVCaptureDevice。
    • iOS 14 无该 API,保持系统默认。createPageView / createPageViewController 无需再包 UIDelegate。
    • 宿主 Info.plist 必填 NSMicrophoneUsageDescription;缺说明时容器 Deny、不启动采集。
  • Demo / supersimples iOS 模板已带麦克风用途说明;fe-main 测试页增加 getUserMedia 音频按钮(需 https 安全源)。

📌 本次仅发布 Android(Maven):1.0.0.63-SNAPSHOT 已发 Maven Central Snapshots(api / base / impl / supersdk / auth-google / pay-google / ad-admob 同批)。iOS xcframework 未重建,release_doc/supersdk/1.0.0-SNAPSHOT/iOS/ 保持既有产物;本批发版环境为 Linux,无 Xcode,iOS 源码(SFeedback + JSB)待 macOS 上 xcodegen generate && xcodebuild … test 验证后补发。

同批切换:supersimples Android 模板 sdk.androidVersion 从 1.0.0.62-SNAPSHOT 切到 1.0.0.63-SNAPSHOT。

用户反馈(Android / iOS / JSSDK 2.3.0 / Super Server / Console)

Section titled “用户反馈(Android / iOS / JSSDK 2.3.0 / Super Server / Console)”
  • SDK 三端新增反馈提交 API:JSSDK SuperSDK.submitFeedback({ scene, subScene?, title, content, userId?, extra? }) → { feedbackId }(端内走新共享 JSB submitFeedback(callbackId, paramsJson),web 直连 /v2/feedback);Android SFeedback.submit(FeedbackRequest, Callback)(com.supersdk.base.feedback);iOS SFeedback.submit(FeedbackRequest, completion:)。SDK 自动补齐 spid / env / device_id / platform / app_version / sdk_version / os_version / device_model;userId 由调用方按次传入。
  • 服务端:Super Server 新增 POST /superapi/v2/feedback(+ /api/v2/feedback)代理到 console-main 公开入库 POST /api/public/v2/feedback(spid/env 语法 clamp → fail-closed 限流:每 IP 10 次/分钟、每项目 600 次/分钟 → 项目/环境解析 → 校验 → 入库 console_user_feedback,记录提交时间与用户 IP)。字段规则:scene ≤64、title ≤200、content ≤5000、sub_scene ≤64、user_id/device_id ≤128、extra JSON object ≤4KB。
  • 控制台:「业务运营」新增首项「用户反馈」(/feedback,同时成为业务运营落地页):按项目 × 环境列出 scene / sub_scene / user_id / device_id / title / 反馈时间 / 状态,支持标题/内容关键字、scene、状态筛选与服务端分页;点击行弹出详情(内容、用户 IP、平台/版本/机型、extra)并可「标记已处理 / 重新打开」。
  • JSB 协议清单增至 53 个方法;BridgeProtocol 双端由 protocol/v1.json 重新生成。

📌 本次仅发布 Android(Maven):1.0.0.62-SNAPSHOT 已在 Maven Central Snapshots(含 querySubscriptionOffers)。iOS xcframework 未重建,release_doc/supersdk/1.0.0-SNAPSHOT/iOS/ 保持 1.0.0.60 产物(source_commit=40635ffd)。本批发版环境为 Linux,无 Xcode。

同批切换:supersimples Android 模板 sdk.androidVersion 从 1.0.0.60-SNAPSHOT 切到 1.0.0.62-SNAPSHOT。

Google Play eligible subscription offers(Android + JSSDK 2.2.0)

Section titled “Google Play eligible subscription offers(Android + JSSDK 2.2.0)”
  • 新增 SuperSDK.pay.querySubscriptionOffers({ provider, productIds }),只返回 queryProductDetailsAsync() 为当前 Play 账号给出的 eligible offers;结构包含 product/base plan/nullable offer ID/tags/title/description/pricing phases,不含 offerToken。
  • 新增 Android 公共 DTO SubscriptionOfferInfo / SubscriptionPricingPhase,并贯通 PayProvider → PayService → SDKPayService → PayBridge → AppBridge;旧 provider/宿主通过默认 NOT_SUPPORTED 保持兼容。iOS 共享 JSB 仅返回 NOT_SUPPORTED。
  • 订阅购买不再复用历史 ProductDetails:每次购买前重新查询 ProductType.SUBS,用 productId + basePlanId + nullable offerId 精确匹配最新 eligible offer,再把其 token 交给 setOfferToken();资格变化返回 OFFER_UNAVAILABLE,不静默换价。
  • 删除错误的 new JSONObject(productDetails.toString());商品和 offer DTO 全部通过 BillingClient 公共 getter 构造,不依赖内部 JSON、反射或 toString()。
  • 新增/收敛错误契约:PRODUCT_NOT_FOUND、OFFER_UNAVAILABLE、BILLING_UNAVAILABLE、QUERY_FAILED、USER_CANCELLED、PURCHASE_FAILED。错误与日志均不包含 offer token。
  • queryProducts()、INAPP 购买和非 Google provider 的公开行为保持不变;Settings、UI 排序、Play Console 完整目录、业务创单/权益和服务端验单仍不在 SDK 范围。

Google Play 订阅(supersdk-pay-google 外挂包)

Section titled “Google Play 订阅(supersdk-pay-google 外挂包)”
  • google_play provider 输入新增 productType: "subs"、必填 basePlanId 和可选 offerId;未传 productType 时继续按 inapp 处理,既有一次性商品购买兼容。
  • 订阅商品改用 ProductType.SUBS 查询,并从 Google 返回的用户可用 SubscriptionOfferDetails 中精确匹配 basePlanId + offerId;省略 offerId 时选择该 base plan 自身的 offer。
  • 匹配成功后向 BillingFlowParams.ProductDetailsParams 写入对应 offerToken;无匹配返回 OFFER_UNAVAILABLE,不拉起 Billing UI。
  • ITEM_ALREADY_OWNED 的既有购买补偿查询跟随当前购买的 productType,订阅不再先查 INAPP。
  • google_play 的 restorePurchases 仅查询订阅,不再合并一次性商品。
  • 新增订阅查询、base plan/offer 选择、缺参/无匹配错误及恢复购买测试。

本版本仅变更 Android 外挂包与参数文档;SuperSDK 核心、PayBridge 和 JSSDK 运行逻辑未改。Maven 同批发布未修改的 supersdk-api / supersdk-base,仅用于满足 supersdk-pay-google:1.0.0.61-SNAPSHOT 的同版本传递依赖。

新增:统一 suenc 响应混淆能力(Android / iOS / JSSDK / Super Server 四端)

Section titled “新增:统一 suenc 响应混淆能力(Android / iOS / JSSDK / Super Server 四端)”

轻量响应混淆协议 suenc:客户端显式请求(?suenc=1)时,服务端用自定义 Base64 表编码 JSON 响应体并回 X-Su-Enc: b64t1,客户端在统一网络层透明解码。

⚠️ 只用于降低通用关键字扫描与规则匹配的有效性,不是加密:不提供机密性、防篡改、防重放,也挡不住已取得客户端代码的攻击者还原编码表。

  • codec 单一数据源:packages/jssdk/protocol/suenc-v1.json + 跨语言稳定向量 suenc-v1-golden.json,由 scripts/generate-suenc-contract.mjs 生成 JS / TS / Android / iOS 四端常量(--check 可校验生成物漂移)。编码表经 fail-closed 校验必须是标准 Base64 64 字符的合法全排列。b64t1 发布后编码表永不可改,新表必须使用新的 codec key。
  • SDK 内部请求自动解码:settings / reportEvent / 归因 / 短链等全部覆盖;非 2xx 响应同样先解码再构造错误;同一响应最多解码一次。响应无 X-Su-Enc 时行为与此前完全一致。
  • SDK 自身不默认追加 suenc=1:是否启用属于宿主与目标服务端之间的发布决策。宿主经新增的 HostNetworkExtensionService(双端,全部可选、默认不生效)为 SDK 内部请求注入扩展 query / header;与 SDK 自有参数冲突时 SDK 值恒胜(header 名大小写不敏感比较),宿主实现抛异常或返回非法值一律跳过并输出脱敏日志,绝不阻断主流程。
  • 防明文降级:本次请求带了 suenc=1 却收到无 X-Su-Enc 的响应时判定该线路失败(SUENC_DOWNGRADE),复用既有多 baseUrl 轮转切换下一条线路,绝不把明文响应交给业务。
  • 对外 API:JSSDK SuperSDK.getSuEncCapabilities() / SuperSDK.decodeSuEnc(encodedData, codec)(同步纯函数,不经 JSBridge);Android SuperSDK.decodeSuEnc/getSuEncCapabilities;iOS SuperSDKManager.decodeSuEnc(_:codec:)/getSuEncCapabilities()。错误码:UNSUPPORTED_SUENC_CODEC / SUENC_DECODE_FAILED / SUENC_INVALID_UTF8 / SUENC_DOWNGRADE / SUENC_RESPONSE_TOO_LARGE / SUENC_PROTOCOL_ERROR。
  • Super Server:新增响应编码中间件,仅对 application/json 与 *+json 生效,保留原状态码,非 JSON(attr.js / healthy / 短链跳转等)原样透传;suenc 参数在进入业务 handler 与转发上游前被剥离。

兼容性:不带 suenc=1 的请求与老客户端行为完全不变;新增宿主接口均为可选默认实现,既有接入方零改动。

📌 双端发布(版本号双端统一):本版本功能改动为 iOS 侧离线包加载机制;Android 为随版本重建(内容无功能变化)。

变更(iOS · 离线包请求级拦截)

Section titled “变更(iOS · 离线包请求级拦截)”
  • 离线包加载从 loadFileURL 改为自定义 scheme(super-offline://)请求级拦截,对齐 Android shouldInterceptRequest 语义。此前离线命中走 loadFileURL 只映射主文档,用 base:'/'(绝对路径)+ History 路由构建的离线包(子资源落到文件系统根 → 404)会白屏;改造后页面跑在稳定的 super-offline://{host} origin 上,/ 映射到包目录,每个子资源经 OfflineSchemeHandler 逐请求映射到本地文件,base:'/' 与 History 路由均成立。
    • 命中响应对齐 Android:200 + Content-Type(文本类型带 charset=utf-8)+ Access-Control-Allow-Origin: *;含 SPA fallback(无扩展名且不存在 → index.html)与目录穿越守门(解析后路径必须仍在包目录内);MIME 表对齐 Android 33 项。
    • 顺带修复:此前 file:// 加载下 getEnv() 的 wappVersion 恒空的隐患(现 webView.url 为 scheme,getPackageForUrl 直接命中)。
  • ⚠️ iOS 离线页 origin 变为 super-offline://{host}(非真实域名、非 secure context):接入方注意——① 若离线页依赖 Service Worker / WebCrypto,本 scheme 不支持(super-offline:// 非安全上下文);② 离线页打自家后端 API 为跨域,需后端返回 CORS 头(带 cookie 凭据时不能用 *,需回显 origin + Allow-Credentials);③ 经 fetch/XHR 发往本 scheme 的 POST/PUT body 会被 WebKit 丢弃,API 应走绝对 https URL。

📌 双端发布:本版本在 macOS 上重建并发布 iOS xcframework(1.0.0.54 起累计欠付的 iOS 产物在本版收口,包含 1.0.0.55~57 的全部 iOS 侧源码变更)+ Android Maven。 iOS 相对 Android 的 JSBridge 功能缺口自本版清零。

  • showRewardedInterstitialAd JSB:补齐 iOS 实现(此前仅 Android 支持)。宿主注入模式:AdService 协议新增 loadRewardedInterstitialAd(带默认实现,老宿主 provider 零改动兼容),未注入时回 NOT_IMPLEMENTED。行为与 Android 对齐:全屏广告互斥(AD_ALREADY_SHOWING)、{dismissed, rewarded} 回调。
  • ShareController 原生短链 API:SuperSDKManager.getShareController() 提供 requestShortUrl / requestShortUrlWithHtml(支持自定义 baseUrl 前缀),与 Android SuperSDK.getShareController() 对齐;ShareBridge 短链 JSB 改为委托同一实现(与 Android 架构一致)。H5 系统分享(UIActivityViewController)本就内置,无需宿主注入。
  • SReporter 重复 asyncFlush() 编译错误:1.0.0.55(Android-only 发版、无 macOS 编译验证)误增 internal 重复声明,导致 iOS 源码此后无法编译。移除重复版,保留与 Android 语义一致的 asyncFlush() → flush()(先落盘再上传)。
  • SuperSDKTests 目标补 GENERATE_INFOPLIST_FILE: YES(apps/ios/project.yml):新版 Xcode 下 xcodebuild test 可直接运行。
  • JSSDK.md 的 showRewardedInterstitialAd 移除「当前仅 Android 原生桥支持」注记(双端已对齐)。
  • iOS README 新增 ShareController - 短链生成 章节。

合并发布:feat/sdk-api-environment(项目环境运行时化)合入 staging

本版本 = 1.0.0.55 的项目环境运行时化 + 1.0.0.56 的 deviceId 隐私合规整改, 两者此前分别只发在各自分支上,从未同时存在于一个产物中。接入方请直接用本版本, 不要再用 1.0.0.55 / 1.0.0.56(各缺一半)。

📌 本次仅发布 Android(Maven):iOS 侧源码与文档均已就绪,但未重建 xcframework, release_doc/supersdk/1.0.0-SNAPSHOT/iOS/ 保持既有产物不变。iOS 需在 macOS 上另行 执行 bash scripts/publish.sh --platform ios 出包(1.0.0.54 起累计欠 iOS 产物)。

  • supersimples Android 模板与相关断言从 1.0.0.55-SNAPSHOT 切到 1.0.0.57-SNAPSHOT(test_sdk_identity_contract 守卫钉死「模板版本 == VERSION_CODE 推导值」)。iOS 模板/mock 仍 pin 1.0.0.54 旧签名、锚点保持临时分裂,待 iOS 产物补发后同批收口。
  • 1.0.0.55-SNAPSHOT 的全部内容(init 移除 environment 参数 · setAPIEnvironment/getAPIEnvironment · JSSDK 2.1.0 · getNetEnv/ApiEnv 废弃)——详见下方 1.0.0.55 条目,破坏性变更与迁移示例同样适用于本版本。
  • 1.0.0.56-SNAPSHOT 的全部内容(移除 ANDROID_ID 读取 · HostConfigService.generateDeviceId())——详见下方 1.0.0.56 条目。

设备标识隐私合规整改(Android)+ 宿主接管 deviceId 生成(双端 API)

📌 本次仅发布 Android(Maven):iOS 侧 generateDeviceId 源码与文档已就绪,但未重建 xcframework,release_doc/supersdk/1.0.0-SNAPSHOT/iOS/ 保持既有产物不变。iOS 需在 macOS 上 另行执行 bash scripts/publish.sh --platform ios 出包。

  • 移除 Settings.Secure.ANDROID_ID 读取:应监管「未见明示,APP 存在收集 AndroidID 的行为 / 请求携带 AndroidID」通报整改。SDevice.getOrCreateDeviceId 不再读取 ANDROID_ID,deviceId 默认自生成随机 UUID 并持久化到 SP。
  • deviceId 降级链变更为:内存缓存 → SP 持久化值 → 宿主 generateDeviceId() → SDK 自生成 UUID。全链路不读取 ANDROID_ID / IMEI / MAC / OAID 等系统设备标识。
  • 存量老用户不受影响:旧版本写入 SP 的 16-hex 值继续沿用(isValidAndroidId 改名 isLegacyHexDeviceId,仅作存量沿用判定),避免设备标识断层造成归因/留存断点;BUG-SDK-B001 的退化值拦截(全零 / 全同字符 / Froyo 碰撞值 / 非 hex / 长度异常)原样保留。
  • iOS 不涉及:identifierForVendor 是 Apple 官方厂商标识,不在通报条款内,行为不变。

新增(双端 · 宿主接管 deviceId)

Section titled “新增(双端 · 宿主接管 deviceId)”
  • HostConfigService 新增可选方法 generateDeviceId()(Android @Nullable String / iOS String?,均有默认实现,不破坏既有宿主接入)。
  • 仅在 SDK 需要生成新 deviceId 时调用(首装或本地旧值失效),已持久化的 deviceId 继续沿用;返回非空字符串即被采用并持久化(Android 落 SP,iOS 落 Keychain),返回 null/nil/空串走 SDK 默认逻辑。
  • 宿主来源的 ID 允许自定义格式,仅拒绝空白值(不套用 SDK 侧形态校验,避免自定义格式被误判退化丢弃)。
  • 实现要求:同步快速返回(可能在网络请求/事件上报路径早期调用)、多次调用返回稳定值;宿主实现抛异常时 SDK 捕获并回退默认逻辑。

📌 本版本 Android Maven 已发布;iOS xcframework/SPM 包需在 macOS 上另行 bash scripts/publish.sh --platform ios 构建发布(本批发布环境无 Xcode,与 1.0.0.54 先例一致)。 supersimples Android 模板已同批切换到本版本与新 API;iOS 模板与 MockSuperSDKPackage 仍镜像 1.0.0.54 旧签名(test_ios_spm_template.py 中锚点临时分裂),待 iOS 产物发布后同批切换并统一锚点。 发布文档版本目录(release_doc/supersdk/1.0.0-SNAPSHOT/)刷新同样留待 iOS 产物就绪后执行,避免复制旧二进制。

  • init 移除 environment 参数:Android 删除 init(context, spid, environment, provider) 重载,只保留 init(context, spid, provider);iOS initialize 同步移除 environment: 参数。项目环境改为独立的运行时状态,init 不再触碰它。
  • setAPIEnvironment(environment) / getAPIEnvironment()(Android SuperSDK 静态方法 / iOS SuperSDKManager 实例方法):对应控制台顶栏 env,运行时可随时切换(init 前后均可)。SDK 不持久化,进程启动默认 prod,宿主自行持久化并在启动后 set。切换副作用:冲刷旧环境存量上报事件 → 换值 → settings 清缓存并按新环境重拉 → 刷新存活 WebView UA。settings 拉取(env 参数)、上报(basic_data.env + X-Super-API-ENV 头)、UA ProjectEnv/、JSB getEnv() 全链路动态跟随。
  • JSSDK 2.1.0:同名 Promise 接口。web 降级模式生效(切换前冲刷待发事件,settings 请求缓存按环境天然隔离);端内 set reject UNSUPPORTED(环境由原生宿主控制)、get 透传原生值。
  • HostConfigService.getNetEnv() 与 ApiEnv(Android @Deprecated / iOS 文档标注):该「API 网络环境」维度从未被 SDK 消费。项目环境用 setAPIEnvironment,API 域名用 getSdkApiBaseUrls()。
  • Android:SuperSDK.init(context, "ab12cd34", "prod", provider) → SuperSDK.setAPIEnvironment("prod"); SuperSDK.init(context, "ab12cd34", provider)
  • iOS:initialize(spid:environment:provider:) → try setAPIEnvironment("prod"); try initialize(spid: "ab12cd34", provider: provider)
  • JSSDK web:initFallback({ spid, environment }) 不变(作为初始值);运行时切换用 await SuperSDK.setAPIEnvironment('staging')

BREAKING: 三端项目身份统一为 spid + environment

📌 Android 产物实际补发于 2026-08-09:2026-07-30 完成的是代码与文档,vars.properties 的 VERSION_CODE 当时停在 1000053、Maven 发布未执行,因此 1.0.0.54-SNAPSHOT 长期不存在, 而 SIMP 模板已 pin 到它 —— 生成的工程 android 端依赖解析 404、开箱即挂。现已补发,并新增 离线守卫(supersimples/tests/test_sdk_identity_contract.py)钉死「模板版本 == VERSION_CODE 推导值」,防止再次漂移。iOS xcframework 需在 macOS 上另行 bash scripts/publish.sh --platform ios。

  • Android 初始化由 init(context, aid, provider) 改为 init(context, spid, environment, provider);iOS 由 initialize(aid:provider:) 改为 initialize(spid:environment:provider:)。spid 必须是控制台签发的 8 位小写字母/数字,显式 environment 必须是 1–10 位小写字母/数字,省略环境时默认为 prod。
  • JSSDK 浏览器兜底改为 initFallback({ spid: 'ab12cd34', environment: 'prod' }),不再接受旧 aid。初始化先完整校验候选配置,再一次性提交;失败不会污染既有配置。
  • JSB getEnv() 从 aid 切换到 spid + environment;UA 字段从 HostAid 切换到 HostSpid + ProjectEnv;settings 查询参数从 aid 切换到 spid + env。
  • Web 上报体使用 basic_data.host_spid 与 basic_data.env,不再伪造原生语义的 basic_data.app_id,也不再发送 host_aid。兼容请求头名仍为 X-Aid,但值为 spid,并新增 X-Super-API-ENV;不新增 X-Spid。
  • SIMP 根配置从 app_id 迁移为 spid + environment,并由同一根值投影到 Android BuildConfig、iOS SimpleConfig 与 Web initFallback。
  • Android:SuperSDK.init(context, "ab12cd34", "prod", provider)
  • iOS:try SuperSDKManager.shared.initialize(spid: "ab12cd34", environment: "prod", provider: provider)
  • JSSDK:SuperSDK.initFallback({ spid: 'ab12cd34', environment: 'prod' })

示例中的 ab12cd34 仅展示合法形态,接入时必须替换为控制台签发的真实 spid。原生事件中的 basic_data.app_id 与 AdMob App ID 是各自独立概念,不得机械改名。release_doc/**/1.0.0-SNAPSHOT/** 为历史发布快照,本次迁移不回写。

Android AdMob 可选 Provider 与 Rewarded Interstitial H5 桥接

  • 独立 AdMob Provider:新增 com.supersdk:supersdk-ad-admob,传递 Google Mobile Ads 25.4.0,完整实现 Rewarded、Interstitial、Banner、Native、Rewarded Interstitial 五类原生 AdService,核心 supersdk 不携带广告依赖。
  • Rewarded Interstitial JSBridge:Android 新增 showRewardedInterstitialAd(config, callbackId),JSSDK 新增 SuperSDK.showRewardedInterstitialAd(options);返回 { dismissed, rewarded },沿用全屏广告并发与唯一终态保护。
  • H5/宿主调用 Rewarded Interstitial 前必须先展示奖励内容说明和可跳过的 intro;旧 Android 桥或不支持平台由 JSSDK 立即返回 NOT_SUPPORTED。
  • 补充宿主 App ID、五类 Ad Unit ID、隐私同意、Provider 注册、资源生命周期及真机验收清单。

Google Play Billing 9 合规升级与离线包远程更新(Android / iOS / JSSDK)

  • 离线包远程清单 v1:Android / iOS 打开页面时可在后台探测站点根路径的 super_meta.json,按版本、大小、MD5、同源路径及包内清单完成安全下载与安装;失败不影响当前页面,成功后在下次加载时生效。
  • 显式预加载接口:双端提供 preloadPackage / preloadAllPackages,支持宿主主动检查并安装离线包;同步补充 OFFLINE_PKG_SPEC.md 与打包脚本产物。
  • Google Play Billing Library 升级到 9.1.0:更新 supersdk-pay-google 的 Billing 依赖及一次性商品 offer 兼容逻辑,满足 Google Play Billing Library 8.0.0+ 要求;购买、恢复购买及错误回调契约保持不变。
  • 离线包接口语义统一:Android / iOS 的 updatePackage* 更名为 preloadPackage*,与“预先下载安装、下次加载生效”的行为一致。

WebView 底部沉浸开关(Android / iOS)

  • setImmersiveBottom 底部沉浸开关:Android / iOS 的 SuperPageView 新增底部沉浸控制,默认 true 保持现有行为;置 false 时 WebView 内容缩短到底部安全区/系统导航栏之上,同时页面 env(safe-area-inset-bottom) 与 UA SafeAreaBottom 归零,适合 YouTube 等第三方站点底栏贴合系统栏、避免遮挡或多余白边。仅作用底部,顶部仍保持沉浸。

三端事件上报迁移到自有事件管道 v2 端点(Android / iOS / JSSDK)

  • 事件上报端点迁 v2:Android / iOS / JSSDK 三端事件上报由 /superapi/rptEvent 切换到 /superapi/v2/reportEvent,激活 SuperSDK 自有事件管道(服务端按上报体 host_aid 的 app_ 前缀内容路由:app_ 应用进自建 collector / 其余仍降级 legacy,零现网影响)。
  • JSSDK event_param 改为对象上报:reportEvent(name, params) 的 params 由 JSON 字符串改为 JSON 对象上报(与 Android / iOS 对齐,满足自建 collector 严格校验;非对象入参一律规整为 {})。

SDK 自身 settings 去耦(Android / iOS / JSSDK)

  • 移除 JSSDK getSDKSettings() / getSDKSettingsByKey():SDK 自身动态能力不再复用宿主业务 settings 通道,后续如需 SDK 专有动态能力走专有接口。
  • 移除端上 getSDKSettingsAsync / getSDKSettingsByKeyAsync JSB:Android / iOS 不再向 H5 暴露 SDK 自身 settings。
  • 离线包不再从 settings 读取 offline_pkg 自动同步:保留已缓存离线包加载与显式下载/安装能力,移除通过宿主/SDK settings 驱动离线包更新的耦合路径。
  • /v2/settings 数据形态与历史 settings 对齐:服务端 v2 成功响应包回 {code:"SUCCESS",msg:"",data:<配置>};Android / iOS 对 raw v2 响应也会本地归一化为该 envelope,按 key 读取兼容 data[key]。
  • SSettings.createSettings(namespace) 不再推导远端 configName:namespace 仅用于本地缓存 / 内置配置隔离,避免历史用法 createSettings(SEnv.getAid()) 生成 configName=<aid>;显式远端配置名请使用 Android createSettingsWithConfigName(configName) / iOS createSettings(configName:)。

宿主云控配置 configName 修复(Android / iOS / JSSDK)

  • 宿主配置不再把 aid 当作 configName:getHostSettings() / getHostSettingsByKey() 无参请求不带 configName,aid 仅作为应用标识参数。
  • JSSDK 支持显式配置名:新增可选参数 getHostSettings(configName?)、getHostSettingsByKey(key, configName?),端上优先走新增 JSB 方法并透传配置名称。
  • 兼容旧 JSB:保留原 getHostSettingsAsync / getHostSettingsByKeyAsync,旧调用路径也不再带 configName,避免生成 configName=<aid>。

openPage 对外接口调整:容器托管 → URL 路由(双端 · ⚠️ Breaking)

变更(容器导航 · 双端一致 · ⚠️ Breaking)

Section titled “变更(容器导航 · 双端一致 · ⚠️ Breaking)”
  • NavigationService 接口由「SDK 给容器」改为「给 URL,宿主决定怎么打开」:宿主拿到 url + PageConfig,返回 true=已自行处理 / false=交回 SDK 默认容器打开(选择性拦截 + SDK 兜底,类似 shouldOverrideUrlLoading)
    • Android:boolean openPage(Context, String url, PageConfig)
    • iOS:func openPage(url: String, config: PageConfig) -> Bool
    • 宿主若仍想用 SDK 的 WebView 容器,自取 getPageController().createPageView() 后 load(url) 再自行展示(可设 setOnClosePageListener / onClosePageListener 响应 H5 closePage)
  • 移除 PageControlHandler(两端):契约不再返回控制句柄;SDK 默认页(SuperPageActivity / SuperPageViewController)关闭改为页面自接管(OnClosePageListener → 关闭自身),前端 appbridge.closePage() 行为不变
  • 移除 DefaultNavigationService(两端):默认打开逻辑内联回承载页
  • 前端 appbridge.openPage(url, config) / SuperSDK.openPage 调用方式不变;无新增 JSB
  • 旧实现 openPage(context, container, config) → PageControlHandler:改为 openPage(context/url, config) → boolean/Bool;原先「摆放 container」的逻辑改为自取 createPageView() 并 return true,不接管则 return false

WebView 视频全屏 + 底层 WebView 透出 + 返回键修复(Android)

  • WebView 内 HTML5 视频支持全屏播放:SuperWebview 的 WebChromeClient 实现 onShowCustomView/onHideCustomView,通过 SViewUtils.findActivity 从视图树回溯宿主 Activity(兼容用 application context 创建的 WebView),将视频挂到 Activity decorView 全屏 + 沉浸式隐藏系统栏
    • 自适应横屏:仅当宿主 Activity 在 manifest 声明 configChanges=orientation|screenSize 时才强制横屏(SuperPageActivity 满足;否则维持当前朝向,避免 Activity 重建中断播放)
    • 返回键全屏中优先退出全屏;onDetachedFromWindow 清理残留全屏视图防泄漏
    • iOS 原生已支持视频全屏(allowsInlineMediaPlayback),本次为 Android 独有平台差异
  • AbsSuperPageView.getWebView():透出底层 WebView 实例,供宿主直调 evaluateJavascript / settings 等原生能力(对齐 iOS pageView.webView)
    • ⚠️ 勿替换 WebViewClient/WebChromeClient 或重置 settings,否则会破坏内置 JSBridge 与离线包拦截
  • Demo MainActivity 返回键改走 handleBackPressed:此前裸用 canGoBack/goBack 会绕过前端拦截(JSBridge.onBackPressed),现与官方文档示例一致(优先级:前端拦截 > 页面历史回退 > 退出)

WebView 识别 target="_blank" / window.open 统一走 openPage(双端)

  • H5 的 <a target="_blank"> 链接与 window.open(url) 现会被容器自动识别,统一通过 openPage 在端上以新页打开(等价 appbridge.openPage,并走宿主自定义 NavigationService);H5 无需额外适配
    • Android:开启 setSupportMultipleWindows + setJavaScriptCanOpenWindowsAutomatically;WebChromeClient.onCreateWindow 用临时 WebView 截获目标 URL 后转发 NavigationBridge.openPage
    • iOS:设置 uiDelegate,WKUIDelegate.createWebViewWith 在 targetFrame == nil 时转发 openPage 并返回 nil(不创建新 WKWebView)
    • 边界:极少数 window.open() 先开空白页再 document.write 的写法拿不到 URL(忽略),与「跳转到新页」语义不冲突
  • 无对外 API 签名变更(无新增 JSB);Demo fe-main 页面导航组新增 _blank / window.open 回归测试项

deviceId 退化值修复(Android)

修复(设备标识 · Android · SDK-B001-deviceId-000)

Section titled “修复(设备标识 · Android · SDK-B001-deviceId-000)”
  • 修复线上部分用户 deviceId 返回退化值(“000” / 全零类)且永久不变:SDevice.getOrCreateDeviceId 原本仅过滤单个已知坏 ANDROID_ID(9774d56d682e549c),未拦其它退化值,叠加缓存优先导致永久固化
    • ANDROID_ID 校验由黑名单单值升级为规则集 isValidAndroidId(16 位 hex + 非已知坏值集 + 非全同字符 + 全 hex)
    • 新增 isDegenerateDeviceId:读缓存时检出退化值(既非合法 ANDROID_ID 也非 UUID)→ 丢弃重生成,让历史中招用户自愈
    • 退化 ANDROID_ID 命中时埋点(脱敏 · 仅长度)确认线上分布
    • iOS 不受影响(identifierForVendor 系统 UUID)· 知识沉淀 KNOWLEDGE G-deviceId-001
    • ⚠️ 中招用户 deviceId 由退化值变为新 UUID(一次性归因断点 · 纠正优先)

Google 登录修复(Android)

  • 修复首次登录/新 client 直接抛 NoCredentialException("No credentials available")、连账号选择器都不弹:GoogleAuthProvider 由 GetGoogleIdOption(One Tap 静默资格检查)改用 GetSignInWithGoogleOption(显式 “Sign in with Google” 按钮流,强制弹账号选择器)
  • 提升登录失败可观测性(SDK-B001):GoogleAuthProvider.onError 不再吞掉 GetCredentialException 的结构化类型,回传 type=<getType()> class=<子类> msg=<message>;LoginBridge 失败回调补 SLogger.e 落 logcat(此前失败仅有 AndroidX 框架的泛化日志,无法定位精确原因)
  • 本次改动均为 Android 平台特有(Credential Manager API);仓内无 iOS Google 登录 provider,iOS xcframework 无对等改动,沿用上版二进制。
  • 无对外 API 签名变更(JSSDK / Android README 接口不变)。

SDK-F038 · 统一支付契约(SDK 退回哑管道)

  • 支付契约统一为 provider 两方法 + SDK 哑管道:provider = { createOrder(payParams)→json, pay(json)→三态 },参数对 SDK 传输层不透明,SDK 仅按 provider 名路由 + 透传 JSON(不再解析 productId/accountId/profileId)
    • pay.purchase({provider, payParams}) 内部聚合 createOrder→pay;不新增 createAndPay
    • 返回由 PurchaseResult 改为三态 PayResult3State:{ status: finished|cancelled|error, orderToken?, phase?, code?, message? };finished ≠ 成功(去业务查单);凭证不出 Native
    • JSB 由位置参数改为通用管道 nativePay(provider, jsonString, callbackId);老 SDK 无 nativePay → pay.purchase reject SDK_TOO_OLD
    • 现网 H5 必须配套升级(不留旧返回 alias);restorePurchases 契约保持 F036 不变
  • IAP:业务只实现 createOrder,pay 由 SDK 内置 google_play/apple provider(原生扣款·自读 json);三方业务自写 createOrder + pay 两方法
  • 凭证守门:provider.pay 把凭证返回 PayBridge → PayBridge 投宿主配置回执端点 + 白名单剥离三态给 H5;后端独立验签;Google RTDN / Apple ASSN 兜底
  • IAP 双端订单槽:Android obfuscatedAccountId(accountId) + obfuscatedProfileId(orderToken) / iOS appAccountToken(orderToken);orderToken 必须 UUID(内置 google provider 校验,非 UUID → INVALID_ORDER_TOKEN)
  • iOS:本 snapshot iOS xcframework 暂未重建(仍为上一版二进制 · 未含 F038 iOS 改动)· 待独立 iOS 出包流程重建后补齐;Android AAR / JSSDK 已含 F038。

累积 .39 之后的所有 SDK 改动(Pay namespace 重构 + JSSDK 文档与封装补全)

  • JS SDK 支付能力重构为 SuperSDK.pay 命名空间,删除 7 个顶层支付 API
    • 新增 SuperSDK.pay 命名空间:purchase / getProviders / registerProvider / restorePurchases
    • purchase 入参签名由 productId 改为 payParams(嵌套结构)
    • 新增 _webInlineInProgress 守门,避免 Web inline 购买并发
    • 详见 JSSDK.md § 支付 的「迁移指南」与错误码说明
  • JSSDK 新增 3 个 JSB 前端封装:addEventCommonParam / setStatusBarDarkMode / showKeyboard
  • onJSBridgeReady 内部注释标注
  • pay.purchase / restorePurchases 返回值 10 字段表 + purchaseState 枚举 + Native/Web inline 两路径差异说明
  • Settings 返回结构与降级说明;3 个新方法文档 + API 概览登记
  • 修正 JSSDK 文档与代码 6 处误差:
    • IAP 推荐架构示例改用嵌套 payParams(原扁平结构会触发 INVALID_PARAMS)
    • pay.purchase 超时 120s → 190s(与 Native IAP 实际值对齐)
    • 清理超时清单中已删 API、修正老命名为 pay.*、补全 requestLogin 与广告四件套
    • initFallback baseUrl 说明澄清 /superapi 自动补全

累积 .36 之后的所有改动(.37/.38 未单独 cut)

  • Pay Bridge:新增多 provider 购买能力 · Android + iOS + JS 三端
    • SuperSDK.purchase(...) 支持 GooglePayProvider 等多 provider
    • 新增 onProgress 回调 · 支持轮询进度 UI
    • JS 端购买超时与原生对齐(190s)· GooglePayProvider.purchase 串行化避免并发
  • SDK-F034:SNetwork commonHeaders 自动注入 X-Aid + X-Device-Id 用于归因关联
  • SDK-F001:Android WebView 容器补 <input type="file"> 支持
    • 补 onShowFileChooser override + Activity Result API 通路
    • 支持 accept / multiple / capture 属性透传 + 取消 / 拒权降级
    • 拍照路径走 FileProvider(子类 SuperSdkFileProvider 避免与宿主 manifest 合并冲突 · authority ${applicationId}.supersdk.fileprovider)
    • 接入 0 成本:SuperPageActivity 自动注入 IFileChooserHost
    • 宿主自包装路径:IFileChooserHost action API(3 方法)
    • iOS WKWebView 默认支持 · 本次不改 iOS 代码
  • Android SDK 依赖升级:appcompat 1.1.0 → 1.6.1 · 新增 androidx.activity 1.6.1 + androidx.core 1.9.0(解锁 Activity Result API)
  • JSSDK 文档同步 Pay Bridge purchase / onProgress 接口
  • 新增 IFileChooserHost 接入文档(Android SDK 宿主自包装路径)
  • 新增 downloadWithCache(fileUrl, fileMd5, cacheTts, fileCacheKey?) JSB/JSSDK API,支持下载并缓存文件,缓存命中时直接返回本地文件路径
  • Android/iOS 双端实现缓存命中、TTL 过期、MD5 校验、临时文件清理与元数据安全校验
  • 缓存 key 优先使用 fileCacheKey;未传或为空时使用去掉 query 的 URL
  • JSSDK/JSBridge 文档补充 downloadWithCache 参数、返回值、缓存策略与异常行为
  • 埋点上报支持多 base URL fallback:服务端 5xx 或网络失败时自动切换到下一个 base URL,提高上报稳定性
  • 埋点事件新增 new_user_today_utc8 公参:按 UTC+8 判断是否为当天新增用户,今日新增为 1,否则为 0
  • Android 10 以下系统导航栏高度适配:getSafeAreaInfo 在低版本设备正确返回虚拟导航栏高度,不再固定返回 0
  • Debug 模式下 WebView 允许远程调试(Android: Chrome DevTools, iOS: Safari Web Inspector)
  • 双端同步:Android WebView.setWebContentsDebuggingEnabled(true),iOS isInspectable = true(iOS 16.4+)
  • 离线包 SPA 路由 fallback:前端路由(如 /home)在刷新时未命中离线包,现在无扩展名路径自动 fallback 到 index.html
  • 双端(Android + iOS)同步修复
  • 双端 SDK API 路径从 /api/ 迁移到 /superapi/,与服务端路由演进方向一致(F030)
  • 涉及:事件上报、云控配置、归因获取、短链生成/HTML 直出,共 8 文件 12 处
  • Debug 模式:双端 HostConfigService 新增 isDebugMode 接口,宿主可选开启 debug 模式
  • Debug 模式:开启后网络请求失败时打印完整请求信息(URL、body、header、响应内容)
  • Android SEnv.setDebug(boolean) 支持手动覆盖 debug 开关
  • Android SEnv.isDebug() 优先级:setDebug > HostConfigService.isDebugMode > false
  • iOS SEnv.isDebug 优先级:#if DEBUG > HostConfigService.isDebugMode > envType
  • JSSDK 非端环境降级支持:新增 initFallback(config) 初始化降级配置,使前端项目在浏览器中也能正常运行和调试(F-JSSDK-001)
  • 新增 isFallbackMode() API,判断当前是否处于降级模式
  • 页面导航类 API 降级为浏览器原生行为(window.open/close)
  • UI 反馈类降级为 console.log 输出
  • 环境配置类 API 在非端环境返回默认空值(不再 reject)
  • reportEvent 降级为 fetch 直接 HTTP 上报(含 source: web_fallback 标记)
  • 不可降级 API 统一错误信息为 “Not in app environment”
  • deviceId 自动生成并持久化到 localStorage
  • JSB 短链生成支持自定义 base_url:requestShortUrl(url, baseUrl?) 和 requestShortUrlWithHtml(html, baseUrl?) 新增可选 baseUrl 参数,支持自定义短链前缀(如 https://s.a.com/),不传保持默认行为(F021)
  • Android/iOS/前端 SDK 全链路支持,向后兼容
  • JSSDK 文档审计修正:callHostMethod 补充无超时说明,注意事项中的超时说明改为各方法分类列表(5s/10s/30s/60s/无超时)
  • 离线包构建时间:OfflinePackageState 新增 buildTime 字段(秒级时间戳),getEnv 返回 wappBuildTime
  • 前端打包工具 super_package.sh 自动写入 build_time 到 __super_meta.json
  • Demo App 简化为单页面 SuperSDK 集成示例,移除更新检查、宿主 Settings、多 Tab、分享等逻辑
  • 短链 HTML 直出:requestShortUrlWithHtml(html) 通过 HTML 内容生成短链,访问短链直接渲染 HTML 页面(不做 302 跳转)
  • 服务端新增 POST /api/shorturl/html 接口,支持 HTML 内容存储与直出
  • Android/iOS/前端 SDK 全链路支持
  • JSBridge Ready 可靠性:onPageFinished 时检测 JSBridge 是否 ready,未 ready 则主动重试触发
  • JSBridge Ready 可靠性:消息被 buffer 时延迟 500ms 重试触发 JSBridge ready,防止回调永久卡死
  • JSBridge Ready 可靠性:AppBridge.onJSBridgeReady 中 webview 引用为 null 时增加错误日志
  • getEnv 新增 wappVersion 字段,返回当前 WApp(离线包)版本号,非离线包页面返回空字符串
  • OfflinePackageState 精简:移除 status、remoteVersion、updateAvailable 字段,仅保留 host、localVersion、source
  • OfflinePackageState 精简:移除 Status 枚举(Android)/ OfflinePackageStatus 枚举(iOS)
  • OfflinePackageState 精简:getAllPackages/getPackage/getPackageForUrl 仅返回状态正常的离线包
  • OfflinePackageState 精简:Source 枚举新增 MANUAL,区分外部手动安装的包
  • 离线包并发安全:临时文件名加 UUID 防冲突,避免多个下载任务写同一文件
  • 离线包并发安全:MD5 计算前增加文件存在性检查,避免 FileNotFoundException
  • 离线包并发安全:Android status 状态修改移入 per-host 锁,修复防重入失效问题
  • 离线包并发安全:iOS 新增初始化等待机制(NSCondition,10s 超时),与 Android 对齐
  • 离线包并发安全:下载安装前增加版本比较,防止云控旧版本覆盖已安装的新版本(版本降级)
  • 离线包并发安全:目录替换改为原子 rename 交换,避免 WebView 加载时文件被删除导致 FileNotFoundException
  • 移除 Google Play Install Referrer 库直接依赖,改为反射方式获取 install_referrer,减少 SDK 外部依赖
  • 离线包初始化:拆分为独立线程,不再被 Settings 初始化阻塞,解决 initialized=false 导致离线包不命中的问题
  • 离线包等待逻辑:URL 拦截时正确等待初始化完成(500ms 轮询,最长 10s),不再 2s 超时后直接放弃
  • 埋点上报:SReporter 上报接口统一使用 ApiHelper/SApiHelper 的 baseURL 拼接,支持宿主自定义域名
  • 发布文档同步:release_doc/supersdk/dev/JSSDK/supersdk.js 同步为最新版本
  • JSBridge 优化:reportEvent 改为直接 JSBridge 方法(不再通过 callHostMethod 中转)
  • JSBridge 优化:showToast 改为 SDK 内置实现(Android 使用系统 Toast,iOS 使用自定义浮层)
  • JSBridge 优化:openBrowser 改为 SDK 内置实现(使用系统浏览器打开)
  • 架构优化:SuperPageActivity 解耦 SuperWebview,统一通过 AbsSuperPageView API 交互
  • 架构优化:NavigationService.openPage() 参数从 View 收窄为 AbsSuperPageView
  • 架构优化:NavigationBridge.openPage() 改用 SuperPageView 代替裸 SuperWebview
  • API 优化:handleBackPressed(exitAction) 内部封装 canGoBack/goBack,调用方只需传退出动作
  • API 优化:AbsSuperPageView.fitSystemWindows(Activity) 一行代码适配沉浸式安全区域
  • API 优化:AbsSuperPageView.setOnClosePageListener(Runnable) 提升到 API 层
  • 内部简化:移除 SuperPageControlHandler 类,handler 改为匿名实现
  • 内部简化:移除 dispatchActivityResume/Pause,SuperWebview 通过 onWindowVisibilityChanged 自动感知
  • 客户端广播:sendBroadcast(eventKey, jsonData) 向前端发送广播,前端通过 SuperSDK.subscribe() 接收
  • 客户端广播:SuperSDK.broadcastToAll(eventKey, jsonData) 向所有 WebView 广播
  • 返回键拦截:前端通过 SuperSDK.onBackPressed(callback) 监听返回键,callback 返回 true 拦截
  • 安全区域设置:AbsSuperPageView.setSafeArea(statusBarHeight, navigationBarHeight) 统一设置安全区域
  • 云控配置拆分:getSettings 拆分为 getSDKSettings(configName=supersdk,已在 1.0.0.49-SNAPSHOT 移除)和 getHostSettings()(不带 configName)
  • 应用信息获取:SuperSDK.getAppName() 获取宿主 App 名称
  • 应用信息获取:SuperSDK.getAppIcon() 获取宿主 App 图标(Base64 格式)
  • Android SDK 初始化与核心容器能力
  • iOS SDK 初始化与核心容器能力
  • JS SDK 前端交互能力
  • JSBridge:环境信息、页面导航、分享、生命周期、WebView 通信
  • 文件操作:下载、读写、ZIP 压缩解压
  • 归因系统
  • Native Block(原生组件嵌入)
  • 离线包管理(查询、更新)
  • 云控配置
  • SLogger 日志 tag 添加 ss- 前缀,便于过滤 SDK 日志