fix: in-app browser download opens file inline

- Detect in-app WebViews (WeChat / TokenPocket / imToken / Telegram / iOS WKWebView, etc.) and show a guide modal asking the user to open the link in their system browser, with a copy-link action.
- For normal browsers, fetch the attachment as a Blob and trigger download from a same-origin object URL so the file always lands in the user's Downloads folder with the original filename, even when the browser would otherwise inline-preview the response.
- Fall back to the anchor download for files larger than 50MB (avoid loading them entirely into memory) or when fetch fails.
- Pass `sizeBytes` from known call sites so the threshold actually applies.
- Add localized strings for the guide modal in all 7 locales.

See .unipi/docs/debug/2026-06-05-in-app-browser-download-debug.md.
This commit is contained in:
TerryM
2026-06-05 19:06:53 +08:00
parent abfd92b16a
commit 7a33a62c8f
16 changed files with 494 additions and 106 deletions

View File

@@ -264,4 +264,16 @@ export const enDict: Dict = {
featureUnavailableDesc: "This feature is not available yet.",
confirm: "Got it",
backToHome: "Back to Home",
inAppDownloadTitle: "Please open in your system browser to download",
inAppDownloadIntro:
"Your current in-app browser cannot download files. Open the page in your system browser (Safari, Chrome, etc.) and tap download again.",
inAppDownloadIntroNamed:
"{browser} cannot download files directly. Open the page in your system browser (Safari, Chrome, etc.) and tap download again.",
inAppDownloadStepCopy: "Tap “Copy link” below.",
inAppDownloadStepOpen:
"Open the menu (top-right), choose “Open in browser”, and paste the link if needed.",
inAppDownloadStepDownload:
"Tap the download button on the page — the file will save to your downloads.",
inAppDownloadCopied: "Link copied",
inAppDownloadCopyFail: "Could not copy the link, please copy it manually",
};

View File

@@ -267,4 +267,16 @@ export const idDict: Dict = {
featureUnavailableDesc: "Fitur ini belum tersedia.",
confirm: "Mengerti",
backToHome: "Kembali ke Beranda",
inAppDownloadTitle: "Silakan buka di peramban sistem untuk mengunduh",
inAppDownloadIntro:
"Peramban dalam aplikasi saat ini tidak dapat mengunduh berkas. Buka halaman ini di peramban sistem (Safari, Chrome, dll.) lalu ketuk unduh lagi.",
inAppDownloadIntroNamed:
"{browser} tidak dapat mengunduh berkas secara langsung. Buka halaman ini di peramban sistem (Safari, Chrome, dll.) lalu ketuk unduh lagi.",
inAppDownloadStepCopy: "Ketuk “Salin tautan” di bawah.",
inAppDownloadStepOpen:
"Buka menu di kanan atas, pilih “Buka di peramban”, tempelkan tautan jika diperlukan.",
inAppDownloadStepDownload:
"Di peramban sistem, ketuk lagi tombol unduh dan berkas akan tersimpan.",
inAppDownloadCopied: "Tautan disalin",
inAppDownloadCopyFail: "Tidak dapat menyalin, silakan salin secara manual",
};

View File

@@ -268,4 +268,16 @@ export const jaDict: Dict = {
featureUnavailableDesc: "この機能はまだご利用いただけません。",
confirm: "了解",
backToHome: "ホームへ戻る",
inAppDownloadTitle: "システムブラウザで開いてダウンロードしてください",
inAppDownloadIntro:
"現在のアプリ内ブラウザはファイルをダウンロードできません。Safari や Chrome などのシステムブラウザでページを開いてから、もう一度ダウンロードしてください。",
inAppDownloadIntroNamed:
"{browser} のアプリ内ブラウザはファイルを直接ダウンロードできません。Safari や Chrome などのシステムブラウザでページを開いてから、もう一度ダウンロードしてください。",
inAppDownloadStepCopy: "下の「リンクをコピー」をタップします。",
inAppDownloadStepOpen:
"右上のメニューから「ブラウザで開く」を選び、必要に応じてリンクを貼り付けます。",
inAppDownloadStepDownload:
"システムブラウザで再度ダウンロードボタンをタップすると、ファイルがダウンロード先に保存されます。",
inAppDownloadCopied: "リンクをコピーしました",
inAppDownloadCopyFail: "コピーに失敗しました。手動でコピーしてください",
};

View File

@@ -263,4 +263,16 @@ export const koDict: Dict = {
featureUnavailableDesc: "이 기능은 아직 사용할 수 없습니다.",
confirm: "확인",
backToHome: "홈으로",
inAppDownloadTitle: "시스템 브라우저에서 열어 다운로드하세요",
inAppDownloadIntro:
"현재 앱 내 브라우저는 파일을 다운로드할 수 없습니다. Safari나 Chrome 등 시스템 브라우저에서 페이지를 연 다음 다시 다운로드해 주세요.",
inAppDownloadIntroNamed:
"{browser} 앱 내 브라우저는 파일을 직접 다운로드할 수 없습니다. Safari나 Chrome 등 시스템 브라우저에서 페이지를 연 다음 다시 다운로드해 주세요.",
inAppDownloadStepCopy: "아래의 “링크 복사”를 누릅니다.",
inAppDownloadStepOpen:
"오른쪽 위 메뉴에서 “브라우저로 열기”를 선택하고 필요하면 링크를 붙여 넣습니다.",
inAppDownloadStepDownload:
"시스템 브라우저에서 다운로드 버튼을 다시 누르면 파일이 저장됩니다.",
inAppDownloadCopied: "링크를 복사했습니다",
inAppDownloadCopyFail: "복사하지 못했습니다. 직접 복사해 주세요",
};

View File

@@ -266,4 +266,16 @@ export const msDict: Dict = {
featureUnavailableDesc: "Ciri ini belum tersedia.",
confirm: "Faham",
backToHome: "Kembali ke Laman Utama",
inAppDownloadTitle: "Sila buka dalam pelayar sistem untuk muat turun",
inAppDownloadIntro:
"Pelayar dalam aplikasi semasa tidak dapat memuat turun fail. Buka halaman ini dalam pelayar sistem (Safari, Chrome, dsb.), kemudian ketik muat turun semula.",
inAppDownloadIntroNamed:
"{browser} tidak dapat memuat turun fail secara langsung. Buka halaman ini dalam pelayar sistem (Safari, Chrome, dsb.), kemudian ketik muat turun semula.",
inAppDownloadStepCopy: "Ketik “Salin pautan” di bawah.",
inAppDownloadStepOpen:
"Buka menu di atas kanan, pilih “Buka dalam pelayar”, tampal pautan jika perlu.",
inAppDownloadStepDownload:
"Dalam pelayar sistem, ketik butang muat turun semula dan fail akan disimpan.",
inAppDownloadCopied: "Pautan disalin",
inAppDownloadCopyFail: "Tidak dapat menyalin, sila salin secara manual",
};

View File

@@ -262,4 +262,16 @@ export const viDict: Dict = {
featureUnavailableDesc: "Tính năng này hiện chưa khả dụng.",
confirm: "Đã hiểu",
backToHome: "Về trang chủ",
inAppDownloadTitle: "Vui lòng mở bằng trình duyệt hệ thống để tải",
inAppDownloadIntro:
"Trình duyệt trong ứng dụng hiện tại không thể tải tệp. Hãy mở trang trong trình duyệt hệ thống (Safari, Chrome…) rồi nhấn tải lại.",
inAppDownloadIntroNamed:
"{browser} không thể tải tệp trực tiếp. Hãy mở trang trong trình duyệt hệ thống (Safari, Chrome…) rồi nhấn tải lại.",
inAppDownloadStepCopy: "Nhấn “Sao chép liên kết” bên dưới.",
inAppDownloadStepOpen:
"Mở menu ở góc trên bên phải, chọn “Mở bằng trình duyệt”, dán liên kết nếu cần.",
inAppDownloadStepDownload:
"Trong trình duyệt hệ thống, nhấn lại nút tải để lưu tệp.",
inAppDownloadCopied: "Đã sao chép liên kết",
inAppDownloadCopyFail: "Không sao chép được, vui lòng tự sao chép",
};

View File

@@ -245,4 +245,16 @@ export const zhDict: Dict = {
featureUnavailableDesc: "该功能暂未开放。",
confirm: "知道了",
backToHome: "返回首页",
inAppDownloadTitle: "请使用系统浏览器打开后下载",
inAppDownloadIntro:
"当前内置浏览器无法直接下载文件请在系统浏览器Safari、Chrome 等)中打开页面后再点击下载。",
inAppDownloadIntroNamed:
"{browser} 内置浏览器无法直接下载文件请在系统浏览器Safari、Chrome 等)中打开页面后再点击下载。",
inAppDownloadStepCopy: "点击下方「复制链接」。",
inAppDownloadStepOpen:
"点右上角菜单,选择「在浏览器中打开」,如需要请把刚才复制的链接粘贴进地址栏。",
inAppDownloadStepDownload:
"在系统浏览器中再次点击下载按钮,文件会保存到下载文件夹。",
inAppDownloadCopied: "链接已复制",
inAppDownloadCopyFail: "复制失败,请手动复制",
};