From a090f042831429e60126468d1f5e5007ad74407c Mon Sep 17 00:00:00 2001 From: Lorenzo Dalla Vecchia Date: Wed, 16 Oct 2024 09:27:29 +0200 Subject: [PATCH] Add content file system support in WebView This is a cherry-pick of a non-final implementation of PR https://github.com/apache/cordova-plugin-file/pull/629 WR-Issue: #17891 --- src/android/FileUtils.java | 49 ++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/src/android/FileUtils.java b/src/android/FileUtils.java index 0edf90a0..45099ca3 100644 --- a/src/android/FileUtils.java +++ b/src/android/FileUtils.java @@ -36,6 +36,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.cordova.CordovaInterface; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.CordovaPluginPathHandler; +import org.apache.cordova.CordovaResourceApi; import org.apache.cordova.CordovaWebView; import org.apache.cordova.LOG; import org.apache.cordova.PermissionHelper; @@ -1240,6 +1241,8 @@ private String getMimeType(Uri uri) { } public CordovaPluginPathHandler getPathHandler() { + final CordovaResourceApi resourceApi = webView.getResourceApi(); + WebViewAssetLoader.PathHandler pathHandler = path -> { String targetFileSystem = null; @@ -1263,9 +1266,11 @@ public CordovaPluginPathHandler getPathHandler() { targetFileSystem = "cache-external"; } else if (path.startsWith(LocalFilesystemURL.fsNameToCdvKeyword("assets"))) { targetFileSystem = "assets"; + } else if (path.startsWith(LocalFilesystemURL.fsNameToCdvKeyword("content"))) { + targetFileSystem = "content"; } - boolean isAssetsFS = targetFileSystem == "assets"; + boolean isAssetsFS = "assets".equals(targetFileSystem); if (targetFileSystem != null) { // Loop the registered file systems to find the target. @@ -1279,26 +1284,46 @@ public CordovaPluginPathHandler getPathHandler() { */ if (fileSystem.name.equals(targetFileSystem)) { // E.g. replace __cdvfile_persistent__ with native path "/data/user/0/com.example.file/files/files/" + + if ("content".equals(targetFileSystem)) { + // The WebviewAssetLoader uses getPath API, which gives us a decoded path + // For content paths however, we need it to remain encoded. + // The Uri.encode API will encode forward slashes, therefore we must + // split the path, encode each segment, and rebuild the path + String[] pathParts = path.split("/"); + path = ""; + for (String part : pathParts) { + if ("".equals(path)) { + path = Uri.encode(part); + } + else { + path += "/" + Uri.encode(part); + } + } + } + String fileSystemNativeUri = fileSystem.rootUri.toString().replace("file://", ""); String fileTarget = path.replace(LocalFilesystemURL.fsNameToCdvKeyword(targetFileSystem) + "/", fileSystemNativeUri); - File file = null; if (isAssetsFS) { fileTarget = fileTarget.replace("/android_asset/", ""); - } else { - file = new File(fileTarget); } - try { - InputStream fileIS = !isAssetsFS ? - new FileInputStream(file) : - webView.getContext().getAssets().open(fileTarget); + Uri fileUri = Uri.parse(fileTarget); + String mimeType = null; - String filePath = !isAssetsFS ? file.toString() : fileTarget; - Uri fileUri = Uri.parse(filePath); - String fileMimeType = getMimeType(fileUri); + try { + InputStream io = null; + if (isAssetsFS) { + io = webView.getContext().getAssets().open(fileTarget); + mimeType = getMimeType(fileUri); + } else { + CordovaResourceApi.OpenForReadResult resource = resourceApi.openForRead(fileUri); + io = resource.inputStream; + mimeType = resource.mimeType; + } - return new WebResourceResponse(fileMimeType, null, fileIS); + return new WebResourceResponse(mimeType, null, io); } catch (FileNotFoundException e) { Log.e(LOG_TAG, e.getMessage()); } catch (IOException e) {