mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-07-24 17:20:51 +02:00
refactor(fs): cfg gate some ios code (#3510)
This commit is contained in:
+106
-109
@@ -74,7 +74,7 @@ pub type CommandResult<T> = std::result::Result<T, CommandError>;
|
|||||||
/// Represents either a plain PathBuf or a PathHandle that manages security-scoped resources.
|
/// Represents either a plain PathBuf or a PathHandle that manages security-scoped resources.
|
||||||
pub enum PathKind<R: Runtime> {
|
pub enum PathKind<R: Runtime> {
|
||||||
/// A plain path that doesn't manage security-scoped resources.
|
/// A plain path that doesn't manage security-scoped resources.
|
||||||
#[allow(dead_code)] // only used on mobile
|
#[cfg(mobile)] // only used on mobile
|
||||||
Path(PathBuf),
|
Path(PathBuf),
|
||||||
/// A path handle that manages security-scoped resources and will clean them up on drop.
|
/// A path handle that manages security-scoped resources and will clean them up on drop.
|
||||||
Handle(PathHandle<R>),
|
Handle(PathHandle<R>),
|
||||||
@@ -84,6 +84,7 @@ impl<R: Runtime> PathKind<R> {
|
|||||||
/// Get a reference to the underlying path.
|
/// Get a reference to the underlying path.
|
||||||
pub fn as_path(&self) -> &Path {
|
pub fn as_path(&self) -> &Path {
|
||||||
match self {
|
match self {
|
||||||
|
#[cfg(mobile)]
|
||||||
PathKind::Path(p) => p.as_ref(),
|
PathKind::Path(p) => p.as_ref(),
|
||||||
PathKind::Handle(h) => h.as_ref(),
|
PathKind::Handle(h) => h.as_ref(),
|
||||||
}
|
}
|
||||||
@@ -92,6 +93,7 @@ impl<R: Runtime> PathKind<R> {
|
|||||||
/// Get a reference to the underlying PathBuf.
|
/// Get a reference to the underlying PathBuf.
|
||||||
pub fn as_path_buf(&self) -> &PathBuf {
|
pub fn as_path_buf(&self) -> &PathBuf {
|
||||||
match self {
|
match self {
|
||||||
|
#[cfg(mobile)]
|
||||||
PathKind::Path(p) => p,
|
PathKind::Path(p) => p,
|
||||||
PathKind::Handle(h) => h,
|
PathKind::Handle(h) => h,
|
||||||
}
|
}
|
||||||
@@ -114,27 +116,13 @@ impl<R: Runtime> AsRef<PathBuf> for PathKind<R> {
|
|||||||
pub struct FileHandle<R: Runtime> {
|
pub struct FileHandle<R: Runtime> {
|
||||||
file: File,
|
file: File,
|
||||||
path: PathKind<R>,
|
path: PathKind<R>,
|
||||||
#[allow(dead_code)] // Used in Drop implementation
|
#[cfg(target_os = "ios")]
|
||||||
path_: SafeFilePath,
|
path_: SafeFilePath,
|
||||||
#[allow(dead_code)] // Used in Drop implementation
|
#[cfg(target_os = "ios")]
|
||||||
app_handle: tauri::AppHandle<R>,
|
app_handle: tauri::AppHandle<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Runtime> FileHandle<R> {
|
impl<R: Runtime> FileHandle<R> {
|
||||||
fn new(
|
|
||||||
file: File,
|
|
||||||
path: PathKind<R>,
|
|
||||||
path_: SafeFilePath,
|
|
||||||
app_handle: tauri::AppHandle<R>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
file,
|
|
||||||
path,
|
|
||||||
path_,
|
|
||||||
app_handle,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the resolved path.
|
/// Get the resolved path.
|
||||||
pub fn path(&self) -> &Path {
|
pub fn path(&self) -> &Path {
|
||||||
self.path.as_path()
|
self.path.as_path()
|
||||||
@@ -155,41 +143,39 @@ impl<R: Runtime> DerefMut for FileHandle<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
impl<R: Runtime> Drop for FileHandle<R> {
|
impl<R: Runtime> Drop for FileHandle<R> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
#[cfg(target_os = "ios")]
|
// Only clean up if we have a plain PathBuf, not a PathHandle
|
||||||
{
|
// PathHandle will handle its own cleanup when it's dropped
|
||||||
// Only clean up if we have a plain PathBuf, not a PathHandle
|
if let PathKind::Path(_) = &self.path {
|
||||||
// PathHandle will handle its own cleanup when it's dropped
|
use crate::{FilePath, FsExt};
|
||||||
if let PathKind::Path(_) = &self.path {
|
// Convert SafeFilePath to FilePath
|
||||||
use crate::{FilePath, FsExt};
|
let file_path: FilePath = match &self.path_ {
|
||||||
// Convert SafeFilePath to FilePath
|
SafeFilePath::Url(url) => FilePath::Url(url.clone()),
|
||||||
let file_path: FilePath = match &self.path_ {
|
SafeFilePath::Path(safe_path) => FilePath::Path(safe_path.as_ref().to_owned()),
|
||||||
SafeFilePath::Url(url) => FilePath::Url(url.clone()),
|
};
|
||||||
SafeFilePath::Path(safe_path) => FilePath::Path(safe_path.as_ref().to_owned()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Only clean up if we're tracking this resource
|
// Only clean up if we're tracking this resource
|
||||||
// If start_accessing_security_scoped_resource was used, it won't be in our tracking
|
// If start_accessing_security_scoped_resource was used, it won't be in our tracking
|
||||||
// and we shouldn't interfere
|
// and we shouldn't interfere
|
||||||
if let FilePath::Url(url) = file_path {
|
if let FilePath::Url(url) = file_path {
|
||||||
if url.scheme() == "file" {
|
if url.scheme() == "file" {
|
||||||
let security_scoped_resources =
|
let security_scoped_resources =
|
||||||
self.app_handle.state::<crate::SecurityScopedResources>();
|
self.app_handle.state::<crate::SecurityScopedResources>();
|
||||||
|
|
||||||
// Only clean up if it's not tracked manually
|
// Only clean up if it's not tracked manually
|
||||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||||
log::debug!("Stopping accessing security-scoped resource for URL: {url} on drop");
|
log::debug!(
|
||||||
let _ = self
|
"Stopping accessing security-scoped resource for URL: {url} on drop"
|
||||||
.app_handle
|
);
|
||||||
.fs()
|
let _ = self
|
||||||
.stop_accessing_security_scoped_resource(FilePath::Url(
|
.app_handle
|
||||||
url.clone(),
|
.fs()
|
||||||
));
|
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
|
||||||
security_scoped_resources.remove(url.as_str());
|
security_scoped_resources.remove(url.as_str());
|
||||||
} else {
|
} else {
|
||||||
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,38 +222,36 @@ impl<R: Runtime> AsRef<PathBuf> for PathHandle<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
impl<R: Runtime> Drop for PathHandle<R> {
|
impl<R: Runtime> Drop for PathHandle<R> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
#[cfg(target_os = "ios")]
|
use crate::{FilePath, FsExt};
|
||||||
{
|
// Convert SafeFilePath to FilePath
|
||||||
use crate::{FilePath, FsExt};
|
let file_path: FilePath = match &self.path_ {
|
||||||
// Convert SafeFilePath to FilePath
|
SafeFilePath::Url(url) => FilePath::Url(url.clone()),
|
||||||
let file_path: FilePath = match &self.path_ {
|
SafeFilePath::Path(safe_path) => FilePath::Path(safe_path.as_ref().to_owned()),
|
||||||
SafeFilePath::Url(url) => FilePath::Url(url.clone()),
|
};
|
||||||
SafeFilePath::Path(safe_path) => FilePath::Path(safe_path.as_ref().to_owned()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Only clean up if we're tracking this resource (i.e., resolve_path started it)
|
// Only clean up if we're tracking this resource (i.e., resolve_path started it)
|
||||||
// If start_accessing_security_scoped_resource was used, it won't be in our tracking
|
// If start_accessing_security_scoped_resource was used, it won't be in our tracking
|
||||||
// and we shouldn't interfere
|
// and we shouldn't interfere
|
||||||
if let FilePath::Url(url) = file_path {
|
if let FilePath::Url(url) = file_path {
|
||||||
if url.scheme() == "file" {
|
if url.scheme() == "file" {
|
||||||
let security_scoped_resources =
|
let security_scoped_resources =
|
||||||
self.app_handle.state::<crate::SecurityScopedResources>();
|
self.app_handle.state::<crate::SecurityScopedResources>();
|
||||||
|
|
||||||
// Only clean up if it's not tracked manually
|
// Only clean up if it's not tracked manually
|
||||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Stopping accessing security-scoped resource for URL: {url} on drop"
|
"Stopping accessing security-scoped resource for URL: {url} on drop"
|
||||||
);
|
);
|
||||||
let _ = self
|
let _ = self
|
||||||
.app_handle
|
.app_handle
|
||||||
.fs()
|
.fs()
|
||||||
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
|
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
|
||||||
security_scoped_resources.remove(url.as_str());
|
security_scoped_resources.remove(url.as_str());
|
||||||
} else {
|
} else {
|
||||||
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -288,6 +272,7 @@ pub fn create<R: Runtime>(
|
|||||||
path: SafeFilePath,
|
path: SafeFilePath,
|
||||||
options: Option<BaseOptions>,
|
options: Option<BaseOptions>,
|
||||||
) -> CommandResult<ResourceId> {
|
) -> CommandResult<ResourceId> {
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
let path_ = path.clone();
|
let path_ = path.clone();
|
||||||
let resolved_path_handle = resolve_path(
|
let resolved_path_handle = resolve_path(
|
||||||
"create",
|
"create",
|
||||||
@@ -303,13 +288,16 @@ pub fn create<R: Runtime>(
|
|||||||
resolved_path_handle.display()
|
resolved_path_handle.display()
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
let app_handle = webview.app_handle().clone();
|
let app_handle = webview.app_handle().clone();
|
||||||
let file_handle = FileHandle::new(
|
let file_handle = FileHandle {
|
||||||
file,
|
file,
|
||||||
PathKind::Handle(resolved_path_handle),
|
path: PathKind::Handle(resolved_path_handle),
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
path_,
|
path_,
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
app_handle,
|
app_handle,
|
||||||
);
|
};
|
||||||
let rid = webview
|
let rid = webview
|
||||||
.resources_table()
|
.resources_table()
|
||||||
.add(StdFileResource::new(file_handle));
|
.add(StdFileResource::new(file_handle));
|
||||||
@@ -1417,6 +1405,7 @@ fn resolve_file_in_fs<R: Runtime>(
|
|||||||
path: SafeFilePath,
|
path: SafeFilePath,
|
||||||
open_options: OpenOptions,
|
open_options: OpenOptions,
|
||||||
) -> CommandResult<FileHandle<R>> {
|
) -> CommandResult<FileHandle<R>> {
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
let path_ = path.clone();
|
let path_ = path.clone();
|
||||||
let resolved_path_handle = resolve_path(
|
let resolved_path_handle = resolve_path(
|
||||||
permission,
|
permission,
|
||||||
@@ -1436,13 +1425,16 @@ fn resolve_file_in_fs<R: Runtime>(
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
let app_handle = webview.app_handle().clone();
|
let app_handle = webview.app_handle().clone();
|
||||||
Ok(FileHandle::new(
|
Ok(FileHandle {
|
||||||
file,
|
file,
|
||||||
PathKind::Handle(resolved_path_handle),
|
path: PathKind::Handle(resolved_path_handle),
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
path_,
|
path_,
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
app_handle,
|
app_handle,
|
||||||
))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(mobile)]
|
#[cfg(mobile)]
|
||||||
@@ -1456,6 +1448,7 @@ pub fn resolve_file<R: Runtime>(
|
|||||||
) -> CommandResult<FileHandle<R>> {
|
) -> CommandResult<FileHandle<R>> {
|
||||||
use crate::FsExt;
|
use crate::FsExt;
|
||||||
|
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
let path_ = path.clone();
|
let path_ = path.clone();
|
||||||
match path {
|
match path {
|
||||||
SafeFilePath::Url(url) => {
|
SafeFilePath::Url(url) => {
|
||||||
@@ -1463,13 +1456,16 @@ pub fn resolve_file<R: Runtime>(
|
|||||||
let file = webview
|
let file = webview
|
||||||
.fs()
|
.fs()
|
||||||
.open(SafeFilePath::Url(url.clone()), open_options.options)?;
|
.open(SafeFilePath::Url(url.clone()), open_options.options)?;
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
let app_handle = webview.app_handle().clone();
|
let app_handle = webview.app_handle().clone();
|
||||||
Ok(FileHandle::new(
|
Ok(FileHandle {
|
||||||
file,
|
file,
|
||||||
PathKind::Path(resolved_path),
|
path: PathKind::Path(resolved_path),
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
path_,
|
path_,
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
app_handle,
|
app_handle,
|
||||||
))
|
})
|
||||||
}
|
}
|
||||||
SafeFilePath::Path(path) => resolve_file_in_fs(
|
SafeFilePath::Path(path) => resolve_file_in_fs(
|
||||||
permission,
|
permission,
|
||||||
@@ -1494,36 +1490,37 @@ pub fn resolve_path<R: Runtime>(
|
|||||||
// On iOS, start accessing security-scoped resource if the path is a file URL
|
// On iOS, start accessing security-scoped resource if the path is a file URL
|
||||||
// Only if it hasn't been started already via start_accessing_security_scoped_resource
|
// Only if it hasn't been started already via start_accessing_security_scoped_resource
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
{
|
if let SafeFilePath::Url(url) = &path {
|
||||||
if let SafeFilePath::Url(url) = &path {
|
if url.scheme() == "file" {
|
||||||
if url.scheme() == "file" {
|
use objc2_foundation::{NSString, NSURL};
|
||||||
use objc2_foundation::{NSString, NSURL};
|
|
||||||
|
|
||||||
let security_scoped_resources = webview.state::<crate::SecurityScopedResources>();
|
let security_scoped_resources = webview.state::<crate::SecurityScopedResources>();
|
||||||
|
|
||||||
// Check if already active (started via start_accessing_security_scoped_resource)
|
// Check if already active (started via start_accessing_security_scoped_resource)
|
||||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||||
let url_nsstring = NSString::from_str(url.as_str());
|
let url_nsstring = NSString::from_str(url.as_str());
|
||||||
let ns_url = unsafe { NSURL::URLWithString(&url_nsstring) };
|
let ns_url = unsafe { NSURL::URLWithString(&url_nsstring) };
|
||||||
if let Some(ns_url) = ns_url {
|
if let Some(ns_url) = ns_url {
|
||||||
// Start accessing the security-scoped resource
|
// Start accessing the security-scoped resource
|
||||||
// This is required for files outside the app's sandbox (e.g., from file picker)
|
// This is required for files outside the app's sandbox (e.g., from file picker)
|
||||||
unsafe {
|
unsafe {
|
||||||
let success = ns_url.startAccessingSecurityScopedResource();
|
let success = ns_url.startAccessingSecurityScopedResource();
|
||||||
if success {
|
if success {
|
||||||
log::debug!("Started accessing security-scoped resource for URL: {} (via resolve_path)", url.as_str());
|
log::debug!("Started accessing security-scoped resource for URL: {} (via resolve_path)", url.as_str());
|
||||||
// Track it so we know to clean it up
|
// Track it so we know to clean it up
|
||||||
security_scoped_resources.track_manually(url.as_str().to_string());
|
security_scoped_resources.track_manually(url.as_str().to_string());
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Failed to start accessing security-scoped resource for URL: {}", url.as_str());
|
log::warn!(
|
||||||
}
|
"Failed to start accessing security-scoped resource for URL: {}",
|
||||||
|
url.as_str()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
log::debug!("Failed to create NSURL from URL: {}, ignoring security-scoped resource access request", url.as_str());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::debug!("Security-scoped resource already active for URL: {} (started via start_accessing_security_scoped_resource), skipping", url.as_str());
|
log::debug!("Failed to create NSURL from URL: {}, ignoring security-scoped resource access request", url.as_str());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log::debug!("Security-scoped resource already active for URL: {} (started via start_accessing_security_scoped_resource), skipping", url.as_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user