|
|
@ -304,7 +304,8 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
if ( |
|
|
|
err.message.includes("permission") || |
|
|
|
err.message.includes("access") || |
|
|
|
err.message.includes("denied") |
|
|
|
err.message.includes("denied") || |
|
|
|
err.message.includes("User denied storage permission") |
|
|
|
) { |
|
|
|
logger.log( |
|
|
|
"Permission check failed, requesting permissions", |
|
|
@ -325,6 +326,20 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
return; |
|
|
|
} catch (retryError: unknown) { |
|
|
|
const retryErr = retryError as Error; |
|
|
|
|
|
|
|
// If permission is still denied, log it but don't throw an error
|
|
|
|
// This allows the app to continue with limited functionality
|
|
|
|
if (retryErr.message.includes("User denied storage permission")) { |
|
|
|
logger.warn( |
|
|
|
"External storage permissions denied by user, continuing with limited functionality", |
|
|
|
JSON.stringify({ |
|
|
|
error: retryErr.message, |
|
|
|
timestamp: new Date().toISOString() |
|
|
|
}, null, 2), |
|
|
|
); |
|
|
|
return; // Don't throw error, just return
|
|
|
|
} |
|
|
|
|
|
|
|
throw new Error( |
|
|
|
`Failed to obtain external storage permissions: ${retryErr.message}`, |
|
|
|
); |
|
|
@ -688,6 +703,113 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Ensures a directory exists by creating it if necessary. |
|
|
|
* This is a workaround for Android's Filesystem.writeFile recursive option not working reliably. |
|
|
|
* @param path - The directory path to ensure exists |
|
|
|
* @param directory - The base directory type |
|
|
|
* @returns Promise that resolves when the directory is ready |
|
|
|
*/ |
|
|
|
private async ensureDirectoryExists(path: string, directory: Directory): Promise<void> { |
|
|
|
try { |
|
|
|
// Try to read the directory to see if it exists
|
|
|
|
await Filesystem.readdir({ |
|
|
|
path, |
|
|
|
directory, |
|
|
|
}); |
|
|
|
logger.log("[CapacitorPlatformService] Directory already exists:", { |
|
|
|
path, |
|
|
|
directory, |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
} catch (error) { |
|
|
|
// Directory doesn't exist, try to create it
|
|
|
|
const errorMessage = error instanceof Error ? error.message : String(error); |
|
|
|
logger.log("[CapacitorPlatformService] Directory doesn't exist, attempting to create:", { |
|
|
|
path, |
|
|
|
directory, |
|
|
|
error: errorMessage, |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
|
|
|
|
try { |
|
|
|
// For Android 10+, we need to handle storage restrictions differently
|
|
|
|
if (!this.getCapabilities().isIOS) { |
|
|
|
// Try creating the directory by writing a temporary file with recursive=true
|
|
|
|
const tempFileName = `.temp-${Date.now()}`; |
|
|
|
const tempPath = `${path}/${tempFileName}`; |
|
|
|
|
|
|
|
await Filesystem.writeFile({ |
|
|
|
path: tempPath, |
|
|
|
data: "", |
|
|
|
directory, |
|
|
|
encoding: Encoding.UTF8, |
|
|
|
recursive: true, |
|
|
|
}); |
|
|
|
|
|
|
|
// Clean up the temporary file, leaving the directory
|
|
|
|
try { |
|
|
|
await Filesystem.deleteFile({ |
|
|
|
path: tempPath, |
|
|
|
directory, |
|
|
|
}); |
|
|
|
} catch (deleteError) { |
|
|
|
// Ignore delete errors - the directory was created successfully
|
|
|
|
const deleteErrorMessage = deleteError instanceof Error ? deleteError.message : String(deleteError); |
|
|
|
logger.log("[CapacitorPlatformService] Temporary file cleanup failed (non-critical):", { |
|
|
|
tempPath, |
|
|
|
error: deleteErrorMessage, |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
logger.log("[CapacitorPlatformService] Directory created successfully:", { |
|
|
|
path, |
|
|
|
directory, |
|
|
|
method: "temporary_file", |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
} else { |
|
|
|
// For iOS, use the standard approach
|
|
|
|
const tempFileName = `.temp-${Date.now()}`; |
|
|
|
const tempPath = `${path}/${tempFileName}`; |
|
|
|
|
|
|
|
await Filesystem.writeFile({ |
|
|
|
path: tempPath, |
|
|
|
data: "", |
|
|
|
directory, |
|
|
|
encoding: Encoding.UTF8, |
|
|
|
recursive: true, |
|
|
|
}); |
|
|
|
|
|
|
|
await Filesystem.deleteFile({ |
|
|
|
path: tempPath, |
|
|
|
directory, |
|
|
|
}); |
|
|
|
|
|
|
|
logger.log("[CapacitorPlatformService] Directory created successfully:", { |
|
|
|
path, |
|
|
|
directory, |
|
|
|
method: "temporary_file", |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
} |
|
|
|
} catch (createError) { |
|
|
|
const createErrorMessage = createError instanceof Error ? createError.message : String(createError); |
|
|
|
logger.warn("[CapacitorPlatformService] Failed to create directory, will try without it:", { |
|
|
|
path, |
|
|
|
directory, |
|
|
|
error: createErrorMessage, |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
|
|
|
|
// For Android 10+, some directories may not be accessible
|
|
|
|
// We'll let the calling method handle the fallback
|
|
|
|
throw createError; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Saves a file directly to user-accessible storage that persists between installations. |
|
|
|
* On Android: Saves to external storage (Downloads or app-specific directory) |
|
|
@ -707,57 +829,97 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
encoding: Encoding.UTF8, |
|
|
|
}); |
|
|
|
|
|
|
|
logger.log("[CapacitorPlatformService] File saved to iOS Documents (persistent):", { |
|
|
|
uri: result.uri, |
|
|
|
logger.log("[CapacitorPlatformService] File saved to iOS Documents:", { |
|
|
|
fileName, |
|
|
|
note: "File persists between app installations and is accessible via Files app", |
|
|
|
uri: result.uri, |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
|
|
|
|
return result.uri; |
|
|
|
} else { |
|
|
|
// Android: Save to external storage that persists between installations
|
|
|
|
// Try to save to Downloads first, then fallback to app's external storage
|
|
|
|
// Android: Check for storage restrictions
|
|
|
|
const hasRestrictions = await this.hasStorageRestrictions(); |
|
|
|
const androidVersion = await this.getAndroidVersion(); |
|
|
|
|
|
|
|
logger.log("[CapacitorPlatformService] Android storage analysis:", { |
|
|
|
hasRestrictions, |
|
|
|
androidVersion, |
|
|
|
fileName, |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
|
|
|
|
if (hasRestrictions) { |
|
|
|
// For Android 10+ with storage restrictions, try app-specific external storage first
|
|
|
|
try { |
|
|
|
// Try to save to app's external storage directory
|
|
|
|
await this.ensureDirectoryExists("TimeSafari", Directory.ExternalStorage); |
|
|
|
|
|
|
|
const result = await Filesystem.writeFile({ |
|
|
|
path: `TimeSafari/${fileName}`, |
|
|
|
data: content, |
|
|
|
directory: Directory.ExternalStorage, |
|
|
|
encoding: Encoding.UTF8, |
|
|
|
}); |
|
|
|
|
|
|
|
logger.log("[CapacitorPlatformService] File saved to app external storage (Android 10+):", { |
|
|
|
fileName, |
|
|
|
uri: result.uri, |
|
|
|
androidVersion, |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
|
|
|
|
return result.uri; |
|
|
|
} catch (error) { |
|
|
|
const errorMessage = error instanceof Error ? error.message : String(error); |
|
|
|
logger.warn("[CapacitorPlatformService] Failed to save to app external storage, trying Downloads:", { |
|
|
|
fileName, |
|
|
|
error: errorMessage, |
|
|
|
androidVersion, |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Try Downloads directory (works on older Android versions)
|
|
|
|
try { |
|
|
|
// Attempt to save to Downloads directory (most accessible)
|
|
|
|
const downloadsPath = `Download/TimeSafari/${fileName}`; |
|
|
|
await this.ensureDirectoryExists("Download/TimeSafari", Directory.ExternalStorage); |
|
|
|
|
|
|
|
const result = await Filesystem.writeFile({ |
|
|
|
path: downloadsPath, |
|
|
|
path: `Download/TimeSafari/${fileName}`, |
|
|
|
data: content, |
|
|
|
directory: Directory.ExternalStorage, // External storage (persists between installations)
|
|
|
|
directory: Directory.ExternalStorage, |
|
|
|
encoding: Encoding.UTF8, |
|
|
|
recursive: true, |
|
|
|
}); |
|
|
|
|
|
|
|
logger.log("[CapacitorPlatformService] File saved to Android Downloads (persistent):", { |
|
|
|
uri: result.uri, |
|
|
|
logger.log("[CapacitorPlatformService] File saved to Downloads (Android):", { |
|
|
|
fileName, |
|
|
|
downloadsPath, |
|
|
|
note: "File persists between app installations and is accessible via file managers", |
|
|
|
uri: result.uri, |
|
|
|
androidVersion, |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
|
|
|
|
return result.uri; |
|
|
|
} catch (downloadsError) { |
|
|
|
logger.warn("[CapacitorPlatformService] Could not save to Downloads, using app external storage:", downloadsError); |
|
|
|
|
|
|
|
// Fallback: Save to app's external storage directory
|
|
|
|
const appStoragePath = `TimeSafari/${fileName}`; |
|
|
|
} catch (error) { |
|
|
|
const errorMessage = error instanceof Error ? error.message : String(error); |
|
|
|
logger.warn("[CapacitorPlatformService] Could not save to Downloads, using app external storage:", { |
|
|
|
fileName, |
|
|
|
error: errorMessage, |
|
|
|
androidVersion, |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
|
|
|
|
// Final fallback: app's external storage without subdirectory
|
|
|
|
const result = await Filesystem.writeFile({ |
|
|
|
path: appStoragePath, |
|
|
|
path: fileName, |
|
|
|
data: content, |
|
|
|
directory: Directory.ExternalStorage, // External storage (persists between installations)
|
|
|
|
directory: Directory.ExternalStorage, |
|
|
|
encoding: Encoding.UTF8, |
|
|
|
recursive: true, |
|
|
|
}); |
|
|
|
|
|
|
|
logger.log("[CapacitorPlatformService] File saved to Android app external storage (persistent):", { |
|
|
|
uri: result.uri, |
|
|
|
logger.log("[CapacitorPlatformService] File saved to external storage (fallback):", { |
|
|
|
fileName, |
|
|
|
appStoragePath, |
|
|
|
note: "File persists between app installations and is accessible via file managers", |
|
|
|
uri: result.uri, |
|
|
|
androidVersion, |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
|
|
|
@ -765,8 +927,30 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
logger.error("[CapacitorPlatformService] Save to persistent storage failed:", error); |
|
|
|
throw new Error(`Failed to save to persistent storage: ${error}`); |
|
|
|
const errorMessage = error instanceof Error ? error.message : String(error); |
|
|
|
logger.error("[CapacitorPlatformService] Save to persistent storage failed:", { |
|
|
|
fileName, |
|
|
|
error: errorMessage, |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
|
|
|
|
// Final fallback: app's data directory (not user-accessible but guaranteed to work)
|
|
|
|
logger.warn("[CapacitorPlatformService] Attempting final fallback to app data directory"); |
|
|
|
|
|
|
|
const result = await Filesystem.writeFile({ |
|
|
|
path: fileName, |
|
|
|
data: content, |
|
|
|
directory: Directory.Data, |
|
|
|
encoding: Encoding.UTF8, |
|
|
|
}); |
|
|
|
|
|
|
|
logger.log("[CapacitorPlatformService] File saved to app data directory (fallback):", { |
|
|
|
fileName, |
|
|
|
uri: result.uri, |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
|
|
|
|
return result.uri; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -823,6 +1007,7 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
} else { |
|
|
|
// Android: List files from persistent storage locations
|
|
|
|
const allFiles: Array<{name: string, uri: string, size?: number}> = []; |
|
|
|
|
|
|
|
// Try to list files from Downloads/TimeSafari directory
|
|
|
|
try { |
|
|
|
const downloadsResult = await Filesystem.readdir({ |
|
|
@ -840,8 +1025,14 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
})); |
|
|
|
allFiles.push(...downloadFiles); |
|
|
|
} catch (downloadsError) { |
|
|
|
logger.warn("[CapacitorPlatformService] Could not read Downloads/TimeSafari directory:", downloadsError); |
|
|
|
const err = downloadsError as Error; |
|
|
|
if (err.message.includes("User denied storage permission")) { |
|
|
|
logger.warn("[CapacitorPlatformService] Storage permission denied for Downloads/TimeSafari, skipping"); |
|
|
|
} else { |
|
|
|
logger.warn("[CapacitorPlatformService] Could not read Downloads/TimeSafari directory:", downloadsError); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Try to list files from app's external storage directory
|
|
|
|
try { |
|
|
|
const appStorageResult = await Filesystem.readdir({ |
|
|
@ -859,8 +1050,14 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
})); |
|
|
|
allFiles.push(...appStorageFiles); |
|
|
|
} catch (appStorageError) { |
|
|
|
logger.warn("[CapacitorPlatformService] Could not read app external storage directory:", appStorageError); |
|
|
|
const err = appStorageError as Error; |
|
|
|
if (err.message.includes("User denied storage permission")) { |
|
|
|
logger.warn("[CapacitorPlatformService] Storage permission denied for TimeSafari, skipping"); |
|
|
|
} else { |
|
|
|
logger.warn("[CapacitorPlatformService] Could not read app external storage directory:", appStorageError); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Remove duplicates based on filename
|
|
|
|
const uniqueFiles = allFiles.filter((file, index, self) => |
|
|
|
index === self.findIndex(f => f.name === file.name) |
|
|
@ -873,6 +1070,11 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
return uniqueFiles; |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
const err = error as Error; |
|
|
|
if (err.message.includes("User denied storage permission")) { |
|
|
|
logger.warn("[CapacitorPlatformService] Storage permission denied, returning empty file list"); |
|
|
|
return []; |
|
|
|
} |
|
|
|
logger.error("[CapacitorPlatformService] Failed to list user accessible files:", error); |
|
|
|
return []; |
|
|
|
} |
|
|
@ -1294,6 +1496,9 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
|
|
|
|
// Try to save to the user-selected directory
|
|
|
|
try { |
|
|
|
// Ensure the selected directory exists before writing
|
|
|
|
await this.ensureDirectoryExists(directoryResult.path, Directory.ExternalStorage); |
|
|
|
|
|
|
|
const result = await Filesystem.writeFile({ |
|
|
|
path: fullPath, |
|
|
|
data: content, |
|
|
@ -1817,7 +2022,12 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
})); |
|
|
|
allFiles.push(...appStorageFiles); |
|
|
|
} catch (error) { |
|
|
|
logger.warn("[CapacitorPlatformService] Could not read TimeSafari external storage:", error); |
|
|
|
const err = error as Error; |
|
|
|
if (err.message.includes("User denied storage permission")) { |
|
|
|
logger.warn("[CapacitorPlatformService] Storage permission denied for TimeSafari, skipping"); |
|
|
|
} else { |
|
|
|
logger.warn("[CapacitorPlatformService] Could not read TimeSafari external storage:", error); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 2. Common user-chosen locations (if accessible) with recursive search
|
|
|
@ -1903,7 +2113,12 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (subDirError) { |
|
|
|
logger.warn(`[CapacitorPlatformService] Could not read subdirectory ${path}/${fileName}:`, subDirError); |
|
|
|
const subDirErr = subDirError as Error; |
|
|
|
if (subDirErr.message.includes("User denied storage permission")) { |
|
|
|
logger.warn(`[CapacitorPlatformService] Storage permission denied for subdirectory ${path}/${fileName}, skipping`); |
|
|
|
} else { |
|
|
|
logger.warn(`[CapacitorPlatformService] Could not read subdirectory ${path}/${fileName}:`, subDirError); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
// Check if file matches backup criteria
|
|
|
@ -1932,9 +2147,13 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
}); |
|
|
|
allFiles.push(...relevantFiles); |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
// Silently skip inaccessible directories
|
|
|
|
logger.debug(`[CapacitorPlatformService] Could not access ${path}:`, error); |
|
|
|
} catch (pathError) { |
|
|
|
const pathErr = pathError as Error; |
|
|
|
if (pathErr.message.includes("User denied storage permission")) { |
|
|
|
logger.warn(`[CapacitorPlatformService] Storage permission denied for ${path}, skipping`); |
|
|
|
} else { |
|
|
|
logger.warn(`[CapacitorPlatformService] Could not read ${path}:`, pathError); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -2277,8 +2496,113 @@ export class CapacitorPlatformService implements PlatformService { |
|
|
|
|
|
|
|
return entries; |
|
|
|
} catch (error) { |
|
|
|
const err = error as Error; |
|
|
|
if (err.message.includes("User denied storage permission")) { |
|
|
|
logger.warn("[CapacitorPlatformService] Storage permission denied for directory listing, returning empty array:", { path, error: err.message }); |
|
|
|
return []; |
|
|
|
} |
|
|
|
logger.error("[CapacitorPlatformService] Failed to list directory:", { path, error }); |
|
|
|
return []; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Provides user guidance when storage permissions are denied |
|
|
|
* @returns Promise resolving to guidance message |
|
|
|
*/ |
|
|
|
async getStoragePermissionGuidance(): Promise<string> { |
|
|
|
try { |
|
|
|
if (this.getCapabilities().isIOS) { |
|
|
|
return "On iOS, files are saved to the Documents folder and can be accessed via the Files app. No additional permissions are required."; |
|
|
|
} else { |
|
|
|
// For Android, provide guidance on how to grant permissions
|
|
|
|
return "To access your backup files, please grant storage permissions:\n\n" + |
|
|
|
"1. Go to your device Settings\n" + |
|
|
|
"2. Find 'Apps' or 'Application Manager'\n" + |
|
|
|
"3. Find 'TimeSafari' in the list\n" + |
|
|
|
"4. Tap 'Permissions'\n" + |
|
|
|
"5. Enable 'Storage' permission\n" + |
|
|
|
"6. Return to the app and try again\n\n" + |
|
|
|
"Alternatively, you can save files to your app's private storage which doesn't require external storage permissions."; |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
return "Unable to provide permission guidance. Please check your device settings for app permissions."; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Tests directory creation functionality to ensure the ensureDirectoryExists method works correctly. |
|
|
|
* @returns Promise resolving to a test result message |
|
|
|
*/ |
|
|
|
async testDirectoryCreation(): Promise<string> { |
|
|
|
try { |
|
|
|
logger.log("[CapacitorPlatformService] Testing directory creation functionality"); |
|
|
|
|
|
|
|
if (this.getCapabilities().isIOS) { |
|
|
|
return "✅ Directory creation test not needed on iOS - using Documents directory"; |
|
|
|
} |
|
|
|
|
|
|
|
// Test creating the Downloads/TimeSafari directory
|
|
|
|
await this.ensureDirectoryExists("Download/TimeSafari", Directory.ExternalStorage); |
|
|
|
|
|
|
|
// Test creating the TimeSafari directory
|
|
|
|
await this.ensureDirectoryExists("TimeSafari", Directory.ExternalStorage); |
|
|
|
|
|
|
|
// Test creating a nested directory structure
|
|
|
|
await this.ensureDirectoryExists("Download/TimeSafari/Test", Directory.ExternalStorage); |
|
|
|
|
|
|
|
logger.log("[CapacitorPlatformService] Directory creation tests completed successfully"); |
|
|
|
|
|
|
|
return "✅ Directory creation tests passed successfully"; |
|
|
|
} catch (error) { |
|
|
|
const err = error as Error; |
|
|
|
logger.error("[CapacitorPlatformService] Directory creation test failed:", error); |
|
|
|
return `❌ Directory creation test failed: ${err.message}`; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Detects the Android version to handle storage restrictions appropriately |
|
|
|
* @returns Promise resolving to Android version number or null if not Android |
|
|
|
*/ |
|
|
|
private async getAndroidVersion(): Promise<number | null> { |
|
|
|
try { |
|
|
|
if (!this.getCapabilities().isIOS) { |
|
|
|
// For Android, we can try to detect version from user agent
|
|
|
|
// This is a fallback since we don't have the Device plugin
|
|
|
|
const userAgent = navigator.userAgent; |
|
|
|
const androidMatch = userAgent.match(/Android\s+(\d+)/); |
|
|
|
if (androidMatch) { |
|
|
|
const version = parseInt(androidMatch[1], 10); |
|
|
|
logger.log("[CapacitorPlatformService] Android version detected from user agent:", { |
|
|
|
version, |
|
|
|
userAgent: userAgent.substring(0, 100) + "...", |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
return version; |
|
|
|
} |
|
|
|
|
|
|
|
// If we can't detect from user agent, assume Android 10+ for safety
|
|
|
|
logger.log("[CapacitorPlatformService] Could not detect Android version, assuming 10+ for safety"); |
|
|
|
return 10; |
|
|
|
} |
|
|
|
return null; |
|
|
|
} catch (error) { |
|
|
|
logger.warn("[CapacitorPlatformService] Could not detect Android version:", { |
|
|
|
error: error instanceof Error ? error.message : String(error), |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
}); |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Checks if the current Android version has storage restrictions |
|
|
|
* @returns Promise resolving to true if storage restrictions apply |
|
|
|
*/ |
|
|
|
private async hasStorageRestrictions(): Promise<boolean> { |
|
|
|
const androidVersion = await this.getAndroidVersion(); |
|
|
|
// Android 10 (API 29) and above have stricter storage restrictions
|
|
|
|
return androidVersion !== null && androidVersion >= 29; |
|
|
|
} |
|
|
|
} |
|
|
|