From 46f0e8e7f60ff74b148c74440424b487789e732e Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Wed, 16 Apr 2025 23:36:11 +0800 Subject: [PATCH] feat: open files with readest from file manager on iOS (#898) --- apps/readest-app/src-tauri/Info.plist | 195 ++++++++++++++++++ .../src-tauri/capabilities/default.json | 11 + apps/readest-app/src-tauri/tauri.conf.json | 7 +- apps/readest-app/src/helpers/openWith.ts | 27 ++- apps/readest-app/src/services/appService.ts | 3 +- .../src/services/nativeAppService.ts | 4 +- 6 files changed, 232 insertions(+), 15 deletions(-) create mode 100644 apps/readest-app/src-tauri/Info.plist diff --git a/apps/readest-app/src-tauri/Info.plist b/apps/readest-app/src-tauri/Info.plist new file mode 100644 index 00000000..3809d268 --- /dev/null +++ b/apps/readest-app/src-tauri/Info.plist @@ -0,0 +1,195 @@ + + + + + ITSAppUsesNonExemptEncryption + + LSSupportsOpeningDocumentsInPlace + + CFBundleDocumentTypes + + + CFBundleTypeName + EPUB Document + LSHandlerRank + Alternate + LSItemContentTypes + + org.idpf.epub-container + + + + + CFBundleTypeName + PDF Document + LSHandlerRank + Alternate + LSItemContentTypes + + com.adobe.pdf + + + + + CFBundleTypeName + FB2 Document + LSHandlerRank + Alternate + LSItemContentTypes + + com.readest.fb2 + + + + + CFBundleTypeName + CBZ Archive + LSHandlerRank + Alternate + LSItemContentTypes + + com.readest.cbz + + + + + CFBundleTypeName + MOBI Document + LSHandlerRank + Alternate + LSItemContentTypes + + org.mobipocket.mobi + + + + + CFBundleTypeName + AZW Document + LSHandlerRank + Alternate + LSItemContentTypes + + com.amazon.azw + com.amazon.azw3 + + + + + CFBundleTypeName + Text File + LSHandlerRank + Alternate + LSItemContentTypes + + public.plain-text + + + + + UTExportedTypeDeclarations + + + UTTypeIdentifier + org.idpf.epub-container + UTTypeDescription + EPUB Document + UTTypeConformsTo + + public.data + public.content + + UTTypeTagSpecification + + public.filename-extension + + epub + + public.mime-type + application/epub+zip + + + + + UTTypeIdentifier + com.readest.fb2 + UTTypeDescription + FB2 Document + UTTypeConformsTo + + public.xml + + UTTypeTagSpecification + + public.filename-extension + + fb2 + + public.mime-type + application/xml + + + + + UTTypeIdentifier + com.readest.cbz + UTTypeDescription + CBZ Archive + UTTypeConformsTo + + public.archive + + UTTypeTagSpecification + + public.filename-extension + + cbz + + public.mime-type + application/x-cbz + + + + + UTTypeIdentifier + org.mobipocket.mobi + UTTypeDescription + MOBI Document + UTTypeConformsTo + + public.data + + UTTypeTagSpecification + + public.filename-extension + + mobi + + public.mime-type + application/x-mobipocket-ebook + + + + + UTTypeIdentifier + com.amazon.azw + UTTypeDescription + AZW Document + UTTypeConformsTo + + public.data + + UTTypeTagSpecification + + public.filename-extension + + azw + azw3 + + public.mime-type + application/vnd.amazon.ebook + + + + + \ No newline at end of file diff --git a/apps/readest-app/src-tauri/capabilities/default.json b/apps/readest-app/src-tauri/capabilities/default.json index f47736f2..2bd4cbf3 100644 --- a/apps/readest-app/src-tauri/capabilities/default.json +++ b/apps/readest-app/src-tauri/capabilities/default.json @@ -39,6 +39,17 @@ } ] }, + { + "identifier": "fs:allow-cache-read", + "allow": [ + { + "path": "$CACHEDIR/**/*" + }, + { + "path": "/private/var/mobile/Containers/Data/Application/**/*" + } + ] + }, { "identifier": "http:default", "allow": [ diff --git a/apps/readest-app/src-tauri/tauri.conf.json b/apps/readest-app/src-tauri/tauri.conf.json index 085705ab..650d5fe1 100644 --- a/apps/readest-app/src-tauri/tauri.conf.json +++ b/apps/readest-app/src-tauri/tauri.conf.json @@ -25,7 +25,12 @@ "assetProtocol": { "enable": true, "scope": { - "allow": ["$RESOURCE/**", "$APPDATA/**/*", "$TEMP/**/*"], + "allow": [ + "$RESOURCE/**", + "$APPDATA/**/*", + "$TEMP/**/*", + "/private/var/mobile/Containers/Data/Application/**/*" + ], "deny": [] } } diff --git a/apps/readest-app/src/helpers/openWith.ts b/apps/readest-app/src/helpers/openWith.ts index 269d33bf..81e404f1 100644 --- a/apps/readest-app/src/helpers/openWith.ts +++ b/apps/readest-app/src/helpers/openWith.ts @@ -37,13 +37,18 @@ const parseIntentOpenWithFiles = async () => { const urls = await getCurrent(); if (urls && urls.length > 0) { console.log('Intent Open with URL:', urls); - const files = urls.map((url) => { - if (url.startsWith('file://')) { - return decodeURI(url.replace('file://', '')); - } - return url; - }); - return files; + return urls + .map((url) => { + if (url.startsWith('file://')) { + return decodeURI(url.replace('file://', '')); + } else if (url.startsWith('content://')) { + return url; + } else { + console.info('Skip non-file URL:', url); + return null; + } + }) + .filter((url) => url !== null) as string[]; } return null; }; @@ -52,11 +57,11 @@ export const parseOpenWithFiles = async () => { if (isWebAppPlatform()) return []; let files = parseWindowOpenWithFiles(); - if (!files) { - files = await parseIntentOpenWithFiles(); - } - if (!files && hasCli()) { + if ((!files || files.length === 0) && hasCli()) { files = await parseCLIOpenWithFiles(); } + if (!files || files.length === 0) { + files = await parseIntentOpenWithFiles(); + } return files; }; diff --git a/apps/readest-app/src/services/appService.ts b/apps/readest-app/src/services/appService.ts index ec92ace7..09b1c43b 100644 --- a/apps/readest-app/src/services/appService.ts +++ b/apps/readest-app/src/services/appService.ts @@ -137,7 +137,8 @@ export abstract class BaseAppService implements AppService { async importBook( // file might be: - // 1. absolute path for local file + // 1.1 absolute path for local file on Desktop + // 1.2 /private/var inbox file path on iOS // 2. remote url // 3. content provider uri // 4. File object from browsers diff --git a/apps/readest-app/src/services/nativeAppService.ts b/apps/readest-app/src/services/nativeAppService.ts index ab764caf..92a0d6b8 100644 --- a/apps/readest-app/src/services/nativeAppService.ts +++ b/apps/readest-app/src/services/nativeAppService.ts @@ -99,12 +99,12 @@ export const nativeFileSystem: FileSystem = { } } else { const prefix = this.getPrefix(base); - if (prefix && OS_TYPE !== 'android') { + const absolutePath = path.startsWith('/') ? path : prefix ? await join(prefix, path) : null; + if (absolutePath && OS_TYPE !== 'android') { // NOTE: RemoteFile currently performs about 2× faster than NativeFile // due to an unresolved performance issue in Tauri (see tauri-apps/tauri#9190). // Once the bug is resolved, we should switch back to using NativeFile. // RemoteFile is not usable on Android due to unknown issues of range fetch with Android WebView. - const absolutePath = await join(prefix, path); return await new RemoteFile(this.getURL(absolutePath), fname).open(); } else { return await new NativeFile(fp, fname, base ? baseDir : null).open();