fix(keyboard): support OPPO Facebook fallback

This commit is contained in:
2026-07-01 17:30:29 +08:00
parent fa5b380577
commit 94bb6adbb5
5 changed files with 42 additions and 52 deletions
@@ -7,42 +7,42 @@ function makeEnvironment(
overrides: Partial<KeyboardAdaptEnvironment> = {}, overrides: Partial<KeyboardAdaptEnvironment> = {},
): KeyboardAdaptEnvironment { ): KeyboardAdaptEnvironment {
return { return {
platform: "android",
osName: "Android",
osVersion: "16",
deviceVendor: "Xiaomi",
deviceModel: "2211133C",
isAndroid: true, isAndroid: true,
isIOS: false,
isMobile: true,
browserName: "Facebook",
browserVersion: "566.0.0.48.73",
isInAppBrowser: true,
inAppBrowserName: "facebook", inAppBrowserName: "facebook",
isXiaomiFamilyDevice: true, isXiaomiFamilyDevice: true,
isOppoFamilyDevice: false,
isFacebookInAppBrowser: true, isFacebookInAppBrowser: true,
hasVisualViewport: true, hasVisualViewport: true,
usesXiaomiFacebookFallback: true, usesAndroidFacebookFallback: true,
...overrides, ...overrides,
}; };
} }
describe("shouldEnableKeyboardAdaptation", () => { 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); expect(shouldEnableKeyboardAdaptation(makeEnvironment())).toBe(true);
});
it("enables for OPPO Android Facebook in-app browser fallback", () => {
expect( expect(
shouldEnableKeyboardAdaptation( shouldEnableKeyboardAdaptation(
makeEnvironment({ makeEnvironment({
platform: "ios",
osName: "iOS",
osVersion: "18",
deviceVendor: "Apple",
deviceModel: "iPhone",
isAndroid: false,
isIOS: true,
isXiaomiFamilyDevice: false, 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); ).toBe(false);
@@ -50,10 +50,9 @@ describe("shouldEnableKeyboardAdaptation", () => {
expect( expect(
shouldEnableKeyboardAdaptation( shouldEnableKeyboardAdaptation(
makeEnvironment({ makeEnvironment({
browserName: "Instagram",
inAppBrowserName: "instagram", inAppBrowserName: "instagram",
isFacebookInAppBrowser: false, isFacebookInAppBrowser: false,
usesXiaomiFacebookFallback: false, usesAndroidFacebookFallback: false,
}), }),
), ),
).toBe(false); ).toBe(false);
@@ -61,10 +60,9 @@ describe("shouldEnableKeyboardAdaptation", () => {
expect( expect(
shouldEnableKeyboardAdaptation( shouldEnableKeyboardAdaptation(
makeEnvironment({ makeEnvironment({
deviceVendor: "Samsung",
deviceModel: "SM-G991B",
isXiaomiFamilyDevice: false, isXiaomiFamilyDevice: false,
usesXiaomiFacebookFallback: false, isOppoFamilyDevice: false,
usesAndroidFacebookFallback: false,
}), }),
), ),
).toBe(false); ).toBe(false);
+8 -13
View File
@@ -8,32 +8,27 @@ export function getKeyboardAdaptEnvironment(
const platform = PlatformDetector.getPlatformInfo(ua); const platform = PlatformDetector.getPlatformInfo(ua);
const browser = BrowserDetector.getBrowserInfo(ua); const browser = BrowserDetector.getBrowserInfo(ua);
const isXiaomiFamilyDevice = PlatformDetector.isXiaomiFamilyDevice(ua); const isXiaomiFamilyDevice = PlatformDetector.isXiaomiFamilyDevice(ua);
const isOppoFamilyDevice = PlatformDetector.isOppoFamilyDevice(ua);
const isFacebookInAppBrowser = BrowserDetector.isFacebookInAppBrowser(ua); const isFacebookInAppBrowser = BrowserDetector.isFacebookInAppBrowser(ua);
const usesAndroidFacebookFallback =
platform.isAndroid &&
(isXiaomiFamilyDevice || isOppoFamilyDevice) &&
isFacebookInAppBrowser;
return { return {
platform: platform.platform,
osName: platform.osName,
osVersion: platform.osVersion,
deviceVendor: platform.deviceVendor,
deviceModel: platform.deviceModel,
isAndroid: platform.isAndroid, isAndroid: platform.isAndroid,
isIOS: platform.isIOS,
isMobile: platform.isMobile,
browserName: browser.name,
browserVersion: browser.version,
isInAppBrowser: browser.isInAppBrowser,
inAppBrowserName: browser.inAppBrowserName, inAppBrowserName: browser.inAppBrowserName,
isXiaomiFamilyDevice, isXiaomiFamilyDevice,
isOppoFamilyDevice,
isFacebookInAppBrowser, isFacebookInAppBrowser,
hasVisualViewport: hasVisualViewport:
typeof window !== "undefined" && window.visualViewport != null, typeof window !== "undefined" && window.visualViewport != null,
usesXiaomiFacebookFallback: usesAndroidFacebookFallback,
platform.isAndroid && isXiaomiFamilyDevice && isFacebookInAppBrowser,
}; };
} }
export function shouldEnableKeyboardAdaptation( export function shouldEnableKeyboardAdaptation(
environment: KeyboardAdaptEnvironment, environment: KeyboardAdaptEnvironment,
): boolean { ): boolean {
return environment.usesXiaomiFacebookFallback; return environment.usesAndroidFacebookFallback;
} }
+3 -3
View File
@@ -1,13 +1,13 @@
"use client"; "use client";
/** /**
* 小米 Android + Facebook IAB 专用输入框避让 hook。 * 特定 Android 设备 + Facebook IAB 专用输入框避让 hook。
* *
* 这不是通用软键盘方案。它只解决一个已知 WebView 问题: * 这不是通用软键盘方案。它只解决一个已知 WebView 问题:
* 输入框 focus 后键盘弹出,但 Facebook IAB 没有稳定调整页面 viewport * 输入框 focus 后键盘弹出,但 Facebook IAB 没有稳定调整页面 viewport
* 导致底部输入框被键盘遮挡。 * 导致底部输入框被键盘遮挡。
* *
* 策略: * 策略:
* - 非小米 Android Facebook IAB:完全不生效。 * - 非目标 Android Facebook IAB 设备:完全不生效。
* - focus 后短期多次测量输入框是否被 visibleViewport 遮挡。 * - focus 后短期多次测量输入框是否被 visibleViewport 遮挡。
* - 若 viewport 没有可靠变化,则使用固定 fallback 抬升。 * - 若 viewport 没有可靠变化,则使用固定 fallback 抬升。
* - 聚焦期间轻量轮询;一旦检测到 viewport 恢复,主动 blur 并清除抬升。 * - 聚焦期间轻量轮询;一旦检测到 viewport 恢复,主动 blur 并清除抬升。
@@ -67,7 +67,7 @@ export function useKeyboardHeight({
if (!shouldEnableKeyboardAdaptation(environment)) { if (!shouldEnableKeyboardAdaptation(environment)) {
resetInputLiftVar(); resetInputLiftVar();
log.debug("[keyboard] disabled", { log.debug("[keyboard] disabled", {
reason: "not-xiaomi-facebook-iab", reason: "not-android-facebook-fallback-device",
environment, environment,
}); });
return; return;
+2 -11
View File
@@ -7,20 +7,11 @@ export interface UseKeyboardHeightOptions {
} }
export interface KeyboardAdaptEnvironment { export interface KeyboardAdaptEnvironment {
platform: string;
osName: string;
osVersion: string;
deviceVendor: string;
deviceModel: string;
isAndroid: boolean; isAndroid: boolean;
isIOS: boolean;
isMobile: boolean;
browserName: string;
browserVersion: string;
isInAppBrowser: boolean;
inAppBrowserName: string | null; inAppBrowserName: string | null;
isXiaomiFamilyDevice: boolean; isXiaomiFamilyDevice: boolean;
isOppoFamilyDevice: boolean;
isFacebookInAppBrowser: boolean; isFacebookInAppBrowser: boolean;
hasVisualViewport: boolean; hasVisualViewport: boolean;
usesXiaomiFacebookFallback: boolean; usesAndroidFacebookFallback: boolean;
} }
+6
View File
@@ -91,6 +91,12 @@ export class PlatformDetector {
return /\b(Xiaomi|Redmi|POCO|Mi\s|MIX|MIUI)\b/i.test(target); 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 { private static getUserAgent(ua: string | null = null): string {
if (ua) return ua; if (ua) return ua;
if (typeof navigator === "undefined") return ""; if (typeof navigator === "undefined") return "";