From 94bb6adbb580f8da07f2ef6ef13bc69faa4ae65b Mon Sep 17 00:00:00 2001 From: chenhang Date: Wed, 1 Jul 2026 17:30:29 +0800 Subject: [PATCH] fix(keyboard): support OPPO Facebook fallback --- .../__tests__/environment.test.ts | 48 +++++++++---------- src/hooks/use-keyboard-height/environment.ts | 21 ++++---- src/hooks/use-keyboard-height/index.ts | 6 +-- src/hooks/use-keyboard-height/types.ts | 13 +---- src/utils/platform-detect.ts | 6 +++ 5 files changed, 42 insertions(+), 52 deletions(-) diff --git a/src/hooks/use-keyboard-height/__tests__/environment.test.ts b/src/hooks/use-keyboard-height/__tests__/environment.test.ts index 50a2d9c5..702be6ce 100644 --- a/src/hooks/use-keyboard-height/__tests__/environment.test.ts +++ b/src/hooks/use-keyboard-height/__tests__/environment.test.ts @@ -7,42 +7,42 @@ function makeEnvironment( overrides: Partial = {}, ): KeyboardAdaptEnvironment { return { - platform: "android", - osName: "Android", - osVersion: "16", - deviceVendor: "Xiaomi", - deviceModel: "2211133C", isAndroid: true, - isIOS: false, - isMobile: true, - browserName: "Facebook", - browserVersion: "566.0.0.48.73", - isInAppBrowser: true, inAppBrowserName: "facebook", isXiaomiFamilyDevice: true, + isOppoFamilyDevice: false, isFacebookInAppBrowser: true, hasVisualViewport: true, - usesXiaomiFacebookFallback: true, + usesAndroidFacebookFallback: true, ...overrides, }; } describe("shouldEnableKeyboardAdaptation", () => { - it("enables only for Xiaomi Android Facebook in-app browser fallback", () => { + it("enables for Xiaomi Android Facebook in-app browser fallback", () => { expect(shouldEnableKeyboardAdaptation(makeEnvironment())).toBe(true); + }); + it("enables for OPPO Android Facebook in-app browser fallback", () => { expect( shouldEnableKeyboardAdaptation( makeEnvironment({ - platform: "ios", - osName: "iOS", - osVersion: "18", - deviceVendor: "Apple", - deviceModel: "iPhone", - isAndroid: false, - isIOS: true, isXiaomiFamilyDevice: false, - usesXiaomiFacebookFallback: false, + isOppoFamilyDevice: true, + usesAndroidFacebookFallback: true, + }), + ), + ).toBe(true); + }); + + it("disables for non-target platforms, browsers, and devices", () => { + expect( + shouldEnableKeyboardAdaptation( + makeEnvironment({ + isAndroid: false, + isXiaomiFamilyDevice: false, + isOppoFamilyDevice: false, + usesAndroidFacebookFallback: false, }), ), ).toBe(false); @@ -50,10 +50,9 @@ describe("shouldEnableKeyboardAdaptation", () => { expect( shouldEnableKeyboardAdaptation( makeEnvironment({ - browserName: "Instagram", inAppBrowserName: "instagram", isFacebookInAppBrowser: false, - usesXiaomiFacebookFallback: false, + usesAndroidFacebookFallback: false, }), ), ).toBe(false); @@ -61,10 +60,9 @@ describe("shouldEnableKeyboardAdaptation", () => { expect( shouldEnableKeyboardAdaptation( makeEnvironment({ - deviceVendor: "Samsung", - deviceModel: "SM-G991B", isXiaomiFamilyDevice: false, - usesXiaomiFacebookFallback: false, + isOppoFamilyDevice: false, + usesAndroidFacebookFallback: false, }), ), ).toBe(false); diff --git a/src/hooks/use-keyboard-height/environment.ts b/src/hooks/use-keyboard-height/environment.ts index 876a1b69..3c3bcd3f 100644 --- a/src/hooks/use-keyboard-height/environment.ts +++ b/src/hooks/use-keyboard-height/environment.ts @@ -8,32 +8,27 @@ export function getKeyboardAdaptEnvironment( const platform = PlatformDetector.getPlatformInfo(ua); const browser = BrowserDetector.getBrowserInfo(ua); const isXiaomiFamilyDevice = PlatformDetector.isXiaomiFamilyDevice(ua); + const isOppoFamilyDevice = PlatformDetector.isOppoFamilyDevice(ua); const isFacebookInAppBrowser = BrowserDetector.isFacebookInAppBrowser(ua); + const usesAndroidFacebookFallback = + platform.isAndroid && + (isXiaomiFamilyDevice || isOppoFamilyDevice) && + isFacebookInAppBrowser; return { - platform: platform.platform, - osName: platform.osName, - osVersion: platform.osVersion, - deviceVendor: platform.deviceVendor, - deviceModel: platform.deviceModel, isAndroid: platform.isAndroid, - isIOS: platform.isIOS, - isMobile: platform.isMobile, - browserName: browser.name, - browserVersion: browser.version, - isInAppBrowser: browser.isInAppBrowser, inAppBrowserName: browser.inAppBrowserName, isXiaomiFamilyDevice, + isOppoFamilyDevice, isFacebookInAppBrowser, hasVisualViewport: typeof window !== "undefined" && window.visualViewport != null, - usesXiaomiFacebookFallback: - platform.isAndroid && isXiaomiFamilyDevice && isFacebookInAppBrowser, + usesAndroidFacebookFallback, }; } export function shouldEnableKeyboardAdaptation( environment: KeyboardAdaptEnvironment, ): boolean { - return environment.usesXiaomiFacebookFallback; + return environment.usesAndroidFacebookFallback; } diff --git a/src/hooks/use-keyboard-height/index.ts b/src/hooks/use-keyboard-height/index.ts index 96cce276..248246f5 100644 --- a/src/hooks/use-keyboard-height/index.ts +++ b/src/hooks/use-keyboard-height/index.ts @@ -1,13 +1,13 @@ "use client"; /** - * 小米 Android + Facebook IAB 专用输入框避让 hook。 + * 特定 Android 设备 + Facebook IAB 专用输入框避让 hook。 * * 这不是通用软键盘方案。它只解决一个已知 WebView 问题: * 输入框 focus 后键盘弹出,但 Facebook IAB 没有稳定调整页面 viewport, * 导致底部输入框被键盘遮挡。 * * 策略: - * - 非小米 Android Facebook IAB:完全不生效。 + * - 非目标 Android Facebook IAB 设备:完全不生效。 * - focus 后短期多次测量输入框是否被 visibleViewport 遮挡。 * - 若 viewport 没有可靠变化,则使用固定 fallback 抬升。 * - 聚焦期间轻量轮询;一旦检测到 viewport 恢复,主动 blur 并清除抬升。 @@ -67,7 +67,7 @@ export function useKeyboardHeight({ if (!shouldEnableKeyboardAdaptation(environment)) { resetInputLiftVar(); log.debug("[keyboard] disabled", { - reason: "not-xiaomi-facebook-iab", + reason: "not-android-facebook-fallback-device", environment, }); return; diff --git a/src/hooks/use-keyboard-height/types.ts b/src/hooks/use-keyboard-height/types.ts index d25e36a5..70dee2bc 100644 --- a/src/hooks/use-keyboard-height/types.ts +++ b/src/hooks/use-keyboard-height/types.ts @@ -7,20 +7,11 @@ export interface UseKeyboardHeightOptions { } export interface KeyboardAdaptEnvironment { - platform: string; - osName: string; - osVersion: string; - deviceVendor: string; - deviceModel: string; isAndroid: boolean; - isIOS: boolean; - isMobile: boolean; - browserName: string; - browserVersion: string; - isInAppBrowser: boolean; inAppBrowserName: string | null; isXiaomiFamilyDevice: boolean; + isOppoFamilyDevice: boolean; isFacebookInAppBrowser: boolean; hasVisualViewport: boolean; - usesXiaomiFacebookFallback: boolean; + usesAndroidFacebookFallback: boolean; } diff --git a/src/utils/platform-detect.ts b/src/utils/platform-detect.ts index 29816465..a2a77526 100644 --- a/src/utils/platform-detect.ts +++ b/src/utils/platform-detect.ts @@ -91,6 +91,12 @@ export class PlatformDetector { return /\b(Xiaomi|Redmi|POCO|Mi\s|MIX|MIUI)\b/i.test(target); } + static isOppoFamilyDevice(ua: string | null = null): boolean { + const info = PlatformDetector.getPlatformInfo(ua); + const target = `${info.deviceVendor} ${info.deviceModel} ${info.userAgent}`; + return /\b(OPPO|OPlus|ColorOS|CPH\d{3,})\b/i.test(target); + } + private static getUserAgent(ua: string | null = null): string { if (ua) return ua; if (typeof navigator === "undefined") return "";