fix(android): stop intercepting app fetches

This commit is contained in:
Tommaso Casaburi
2026-05-01 16:21:00 +07:00
parent d8bbe1c5ac
commit 24619ac02f
4 changed files with 45 additions and 3 deletions
@@ -4,7 +4,7 @@
"webDir": "build",
"plugins": {
"CapacitorHttp": {
"enabled": true
"enabled": false
},
"FileUploader": {
"enabled": true
+1 -1
View File
@@ -6,7 +6,7 @@ const config: CapacitorConfig = {
webDir: 'build',
plugins: {
CapacitorHttp: {
enabled: true,
enabled: false,
},
FileUploader: {
enabled: true,
@@ -520,6 +520,40 @@ describe('ChallengeModal', () => {
expect(testState.abandonCurrentChallengeMock).not.toHaveBeenCalled();
});
it('uses inline iframe confirmation in Android WebView even when Capacitor reports web', async () => {
testState.capacitorPlatform = 'web';
setNavigatorValue(
'userAgent',
'Mozilla/5.0 (Linux; Android 15; Pixel 9 Build/AP3A.241105.007) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/147.0.7727.137 Mobile Safari/537.36 wv',
);
testState.publicationType = 'reply';
testState.challenges = [
createStoredChallenge(
{
challenge: 'https://spamblocker.bitsocial.net/api/v1/iframe/session-123',
type: 'url/iframe',
},
{
...createPublication(),
content: '>>17\nreply from webview',
title: '',
},
),
];
await renderModal();
expect(confirmSpy).not.toHaveBeenCalled();
expect(container.textContent).toContain('mu wants to open spamblocker.bitsocial.net.\n\nFor reply: >>17 reply from webview');
expect(container.querySelector('iframe')).toBeNull();
await clickButton('Open');
const iframe = container.querySelector('iframe');
expect(iframe).not.toBeNull();
expect(iframe?.getAttribute('src')).toContain('https://spamblocker.bitsocial.net/api/v1/iframe/session-123?theme=dark');
});
it('abandons Android iframe challenges when inline confirmation is closed', async () => {
testState.capacitorPlatform = 'android';
testState.challenges = [
@@ -45,6 +45,14 @@ const getDisplayCommunityAddress = (shortCommunityAddress?: string, communityAdd
shortCommunityAddress || (communityAddress ? getShortAddress(communityAddress) : '') || communityAddress || '';
const iframeChallengeConfirmDecisions = new Map<string, 'accepted' | 'rejected'>();
const ANDROID_USER_AGENT_REGEX = /Android/;
const ANDROID_WEBVIEW_USER_AGENT_REGEX = /\bwv\b|Version\/\d+(?:\.\d+)?\s+Chrome\//;
const isAndroidWebViewUserAgent = () => {
if (typeof navigator === 'undefined') return false;
return ANDROID_USER_AGENT_REGEX.test(navigator.userAgent) && ANDROID_WEBVIEW_USER_AGENT_REGEX.test(navigator.userAgent);
};
const isIosWebKitUserAgent = () => {
if (typeof navigator === 'undefined') return false;
return /iPad|iPhone|iPod/.test(navigator.userAgent) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
@@ -60,7 +68,7 @@ const isDesktopSafariUserAgent = () => {
const shouldUseInlineIframeConfirm = () => {
const platform = Capacitor.getPlatform();
return platform === 'android' || platform === 'ios' || isIosWebKitUserAgent() || isDesktopSafariUserAgent();
return platform === 'android' || platform === 'ios' || isAndroidWebViewUserAgent() || isIosWebKitUserAgent() || isDesktopSafariUserAgent();
};
const TextChallenge = ({ challenge }: { challenge: string }) => <div className={styles.challengeMedia}>{challenge}</div>;