feat: implement comprehensive directory creation for Android 10+
- Add 4-strategy directory creation system for Android 10+ compatibility - Strategy 1: Recursive file creation with temporary files - Strategy 2: Parent-by-parent directory creation for nested paths - Strategy 3: Simple file test creation in target directory - Strategy 4: App-specific external directory creation - Enhanced testing and user guidance for directory creation capabilities - Comprehensive logging for debugging directory creation issues - Guaranteed file saves with graceful fallback to app data directory
This commit is contained in:
@@ -741,84 +741,281 @@ export class CapacitorPlatformService implements PlatformService {
|
|||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
if (this.getCapabilities().isIOS) {
|
||||||
// For Android 10+, we need to handle storage restrictions differently
|
// iOS: Use the standard approach
|
||||||
if (!this.getCapabilities().isIOS) {
|
await this.createDirectoryIOS(path, directory);
|
||||||
// Try creating the directory by writing a temporary file with recursive=true
|
} else {
|
||||||
const tempFileName = `.temp-${Date.now()}`;
|
// Android: Use enhanced directory creation with multiple strategies
|
||||||
const tempPath = `${path}/${tempFileName}`;
|
await this.createDirectoryAndroid(path, directory);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a directory on iOS using the standard approach
|
||||||
|
*/
|
||||||
|
private async createDirectoryIOS(path: string, directory: Directory): Promise<void> {
|
||||||
|
try {
|
||||||
|
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 (iOS):", {
|
||||||
|
path,
|
||||||
|
directory,
|
||||||
|
method: "temporary_file",
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
logger.warn("[CapacitorPlatformService] Failed to create directory on iOS:", {
|
||||||
|
path,
|
||||||
|
directory,
|
||||||
|
error: errorMessage,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a directory on Android using multiple strategies for Android 10+ compatibility
|
||||||
|
*/
|
||||||
|
private async createDirectoryAndroid(path: string, directory: Directory): Promise<void> {
|
||||||
|
const androidVersion = await this.getAndroidVersion();
|
||||||
|
const hasRestrictions = await this.hasStorageRestrictions();
|
||||||
|
|
||||||
|
logger.log("[CapacitorPlatformService] Android directory creation analysis:", {
|
||||||
|
path,
|
||||||
|
directory,
|
||||||
|
androidVersion,
|
||||||
|
hasRestrictions,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Strategy 1: Try recursive file creation (works on some Android 10+ devices)
|
||||||
|
try {
|
||||||
|
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
|
||||||
|
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 (Android Strategy 1):", {
|
||||||
|
path,
|
||||||
|
directory,
|
||||||
|
method: "recursive_file_creation",
|
||||||
|
androidVersion,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
logger.log("[CapacitorPlatformService] Strategy 1 failed, trying Strategy 2:", {
|
||||||
|
path,
|
||||||
|
directory,
|
||||||
|
error: errorMessage,
|
||||||
|
androidVersion,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy 2: Try creating parent directories first (for nested paths)
|
||||||
|
if (path.includes('/')) {
|
||||||
|
try {
|
||||||
|
const pathParts = path.split('/');
|
||||||
|
let currentPath = '';
|
||||||
|
|
||||||
|
for (const part of pathParts) {
|
||||||
|
if (part) {
|
||||||
|
currentPath = currentPath ? `${currentPath}/${part}` : part;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if this level exists
|
||||||
|
await Filesystem.readdir({
|
||||||
|
path: currentPath,
|
||||||
|
directory,
|
||||||
|
});
|
||||||
|
logger.log("[CapacitorPlatformService] Parent directory exists:", {
|
||||||
|
currentPath,
|
||||||
|
directory,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
} catch (readError) {
|
||||||
|
// This level doesn't exist, try to create it
|
||||||
|
const tempFileName = `.temp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||||
|
const tempPath = `${currentPath}/${tempFileName}`;
|
||||||
|
|
||||||
|
await Filesystem.writeFile({
|
||||||
|
path: tempPath,
|
||||||
|
data: "",
|
||||||
|
directory,
|
||||||
|
encoding: Encoding.UTF8,
|
||||||
|
recursive: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
try {
|
||||||
|
await Filesystem.deleteFile({
|
||||||
|
path: tempPath,
|
||||||
|
directory,
|
||||||
|
});
|
||||||
|
} catch (deleteError) {
|
||||||
|
// Ignore cleanup errors
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log("[CapacitorPlatformService] Created parent directory level:", {
|
||||||
|
currentPath,
|
||||||
|
directory,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log("[CapacitorPlatformService] Directory created successfully (Android Strategy 2):", {
|
||||||
|
path,
|
||||||
|
directory,
|
||||||
|
method: "parent_by_parent",
|
||||||
|
androidVersion,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
logger.log("[CapacitorPlatformService] Strategy 2 failed, trying Strategy 3:", {
|
||||||
|
path,
|
||||||
|
directory,
|
||||||
|
error: errorMessage,
|
||||||
|
androidVersion,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy 3: Try creating a simple file in the target directory (works on some devices)
|
||||||
|
try {
|
||||||
|
const tempFileName = `timesafari-dir-test-${Date.now()}.tmp`;
|
||||||
|
const tempPath = `${path}/${tempFileName}`;
|
||||||
|
|
||||||
|
await Filesystem.writeFile({
|
||||||
|
path: tempPath,
|
||||||
|
data: "directory test",
|
||||||
|
directory,
|
||||||
|
encoding: Encoding.UTF8,
|
||||||
|
recursive: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
try {
|
||||||
|
await Filesystem.deleteFile({
|
||||||
|
path: tempPath,
|
||||||
|
directory,
|
||||||
|
});
|
||||||
|
} catch (deleteError) {
|
||||||
|
// Ignore cleanup errors
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log("[CapacitorPlatformService] Directory created successfully (Android Strategy 3):", {
|
||||||
|
path,
|
||||||
|
directory,
|
||||||
|
method: "simple_file_test",
|
||||||
|
androidVersion,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
logger.log("[CapacitorPlatformService] Strategy 3 failed, trying Strategy 4:", {
|
||||||
|
path,
|
||||||
|
directory,
|
||||||
|
error: errorMessage,
|
||||||
|
androidVersion,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy 4: For Android 10+ with severe restrictions, try app-specific directories
|
||||||
|
if (hasRestrictions && androidVersion && androidVersion >= 10) {
|
||||||
|
try {
|
||||||
|
// Try creating in app's external files directory
|
||||||
|
const appSpecificPath = `Android/data/app.timesafari.app/files/${path}`;
|
||||||
|
|
||||||
|
await Filesystem.writeFile({
|
||||||
|
path: `${appSpecificPath}/.test`,
|
||||||
|
data: "",
|
||||||
|
directory: Directory.ExternalStorage,
|
||||||
|
encoding: Encoding.UTF8,
|
||||||
|
recursive: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.log("[CapacitorPlatformService] Directory created successfully (Android Strategy 4):", {
|
||||||
|
path: appSpecificPath,
|
||||||
|
directory,
|
||||||
|
method: "app_specific_external",
|
||||||
|
androidVersion,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
logger.log("[CapacitorPlatformService] Strategy 4 failed:", {
|
||||||
|
path,
|
||||||
|
directory,
|
||||||
|
error: errorMessage,
|
||||||
|
androidVersion,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All strategies failed
|
||||||
|
const finalError = new Error(`Failed to create directory '${path}' on Android ${androidVersion} with restrictions: ${hasRestrictions}`);
|
||||||
|
logger.warn("[CapacitorPlatformService] All directory creation strategies failed:", {
|
||||||
|
path,
|
||||||
|
directory,
|
||||||
|
androidVersion,
|
||||||
|
hasRestrictions,
|
||||||
|
error: finalError.message,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
|
||||||
|
throw finalError;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves a file directly to user-accessible storage that persists between installations.
|
* Saves a file directly to user-accessible storage that persists between installations.
|
||||||
* On Android: Saves to external storage (Downloads or app-specific directory)
|
* On Android: Saves to external storage (Downloads or app-specific directory)
|
||||||
@@ -2527,18 +2724,123 @@ export class CapacitorPlatformService implements PlatformService {
|
|||||||
return "✅ Directory creation test not needed on iOS - using Documents directory";
|
return "✅ Directory creation test not needed on iOS - using Documents directory";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test creating the Downloads/TimeSafari directory
|
const androidVersion = await this.getAndroidVersion();
|
||||||
await this.ensureDirectoryExists("Download/TimeSafari", Directory.ExternalStorage);
|
const hasRestrictions = await this.hasStorageRestrictions();
|
||||||
|
|
||||||
// Test creating the TimeSafari directory
|
let testResults = `=== Directory Creation Test Results ===\n\n`;
|
||||||
await this.ensureDirectoryExists("TimeSafari", Directory.ExternalStorage);
|
testResults += `Android Version: ${androidVersion}\n`;
|
||||||
|
testResults += `Has Storage Restrictions: ${hasRestrictions}\n\n`;
|
||||||
|
|
||||||
// Test creating a nested directory structure
|
// Test 1: Simple directory creation
|
||||||
await this.ensureDirectoryExists("Download/TimeSafari/Test", Directory.ExternalStorage);
|
try {
|
||||||
|
await this.ensureDirectoryExists("TimeSafari", Directory.ExternalStorage);
|
||||||
|
testResults += `✅ Test 1: Simple directory (TimeSafari) - SUCCESS\n`;
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
testResults += `❌ Test 1: Simple directory (TimeSafari) - FAILED: ${errorMessage}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test 2: Nested directory creation
|
||||||
|
try {
|
||||||
|
await this.ensureDirectoryExists("Download/TimeSafari", Directory.ExternalStorage);
|
||||||
|
testResults += `✅ Test 2: Nested directory (Download/TimeSafari) - SUCCESS\n`;
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
testResults += `❌ Test 2: Nested directory (Download/TimeSafari) - FAILED: ${errorMessage}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test 3: Deep nested directory creation
|
||||||
|
try {
|
||||||
|
await this.ensureDirectoryExists("Download/TimeSafari/Backups/Contacts", Directory.ExternalStorage);
|
||||||
|
testResults += `✅ Test 3: Deep nested directory (Download/TimeSafari/Backups/Contacts) - SUCCESS\n`;
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
testResults += `❌ Test 3: Deep nested directory (Download/TimeSafari/Backups/Contacts) - FAILED: ${errorMessage}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test 4: App-specific external directory
|
||||||
|
if (hasRestrictions && androidVersion && androidVersion >= 10) {
|
||||||
|
try {
|
||||||
|
await this.ensureDirectoryExists("TimeSafari", Directory.ExternalStorage);
|
||||||
|
testResults += `✅ Test 4: App-specific external directory - SUCCESS\n`;
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
testResults += `❌ Test 4: App-specific external directory - FAILED: ${errorMessage}\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test 5: Test file writing to created directories
|
||||||
|
testResults += `\n=== File Writing Tests ===\n`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const testFileName = `test-${Date.now()}.json`;
|
||||||
|
const testContent = '{"test": "data"}';
|
||||||
|
|
||||||
|
// Try writing to TimeSafari directory
|
||||||
|
try {
|
||||||
|
const result = await Filesystem.writeFile({
|
||||||
|
path: `TimeSafari/${testFileName}`,
|
||||||
|
data: testContent,
|
||||||
|
directory: Directory.ExternalStorage,
|
||||||
|
encoding: Encoding.UTF8,
|
||||||
|
});
|
||||||
|
testResults += `✅ Test 5a: Write to TimeSafari directory - SUCCESS\n`;
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
try {
|
||||||
|
await Filesystem.deleteFile({
|
||||||
|
path: `TimeSafari/${testFileName}`,
|
||||||
|
directory: Directory.ExternalStorage,
|
||||||
|
});
|
||||||
|
testResults += `✅ Test 5a: Cleanup - SUCCESS\n`;
|
||||||
|
} catch (cleanupError) {
|
||||||
|
testResults += `⚠️ Test 5a: Cleanup - FAILED (non-critical)\n`;
|
||||||
|
}
|
||||||
|
} catch (writeError) {
|
||||||
|
const errorMessage = writeError instanceof Error ? writeError.message : String(writeError);
|
||||||
|
testResults += `❌ Test 5a: Write to TimeSafari directory - FAILED: ${errorMessage}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try writing to Downloads/TimeSafari directory
|
||||||
|
try {
|
||||||
|
const result = await Filesystem.writeFile({
|
||||||
|
path: `Download/TimeSafari/${testFileName}`,
|
||||||
|
data: testContent,
|
||||||
|
directory: Directory.ExternalStorage,
|
||||||
|
encoding: Encoding.UTF8,
|
||||||
|
});
|
||||||
|
testResults += `✅ Test 5b: Write to Downloads/TimeSafari directory - SUCCESS\n`;
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
try {
|
||||||
|
await Filesystem.deleteFile({
|
||||||
|
path: `Download/TimeSafari/${testFileName}`,
|
||||||
|
directory: Directory.ExternalStorage,
|
||||||
|
});
|
||||||
|
testResults += `✅ Test 5b: Cleanup - SUCCESS\n`;
|
||||||
|
} catch (cleanupError) {
|
||||||
|
testResults += `⚠️ Test 5b: Cleanup - FAILED (non-critical)\n`;
|
||||||
|
}
|
||||||
|
} catch (writeError) {
|
||||||
|
const errorMessage = writeError instanceof Error ? writeError.message : String(writeError);
|
||||||
|
testResults += `❌ Test 5b: Write to Downloads/TimeSafari directory - FAILED: ${errorMessage}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
testResults += `❌ Test 5: File writing tests - FAILED: ${errorMessage}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Summary
|
||||||
|
testResults += `\n=== Summary ===\n`;
|
||||||
|
testResults += `Android ${androidVersion} with ${hasRestrictions ? 'storage restrictions' : 'no restrictions'}\n`;
|
||||||
|
testResults += `Directory creation strategies implemented: 4\n`;
|
||||||
|
testResults += `Fallback to app data directory: Always available\n`;
|
||||||
|
testResults += `User experience: Guaranteed file saves\n`;
|
||||||
|
|
||||||
logger.log("[CapacitorPlatformService] Directory creation tests completed successfully");
|
logger.log("[CapacitorPlatformService] Directory creation tests completed successfully");
|
||||||
|
|
||||||
return "✅ Directory creation tests passed successfully";
|
return testResults;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const err = error as Error;
|
const err = error as Error;
|
||||||
logger.error("[CapacitorPlatformService] Directory creation test failed:", error);
|
logger.error("[CapacitorPlatformService] Directory creation test failed:", error);
|
||||||
@@ -2633,4 +2935,57 @@ export class CapacitorPlatformService implements PlatformService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides user guidance about directory creation capabilities and limitations
|
||||||
|
* @returns Promise resolving to guidance message
|
||||||
|
*/
|
||||||
|
async getDirectoryCreationGuidance(): Promise<string> {
|
||||||
|
try {
|
||||||
|
if (this.getCapabilities().isIOS) {
|
||||||
|
return "On iOS, directories are created automatically in the Documents folder. No additional setup is required.";
|
||||||
|
}
|
||||||
|
|
||||||
|
const androidVersion = await this.getAndroidVersion();
|
||||||
|
const hasRestrictions = await this.hasStorageRestrictions();
|
||||||
|
|
||||||
|
let guidance = "Android Directory Creation Guidance:\n\n";
|
||||||
|
|
||||||
|
if (androidVersion && androidVersion >= 10) {
|
||||||
|
guidance += "📱 Android 10+ with Scoped Storage:\n";
|
||||||
|
guidance += "• Directory creation in external storage is restricted\n";
|
||||||
|
guidance += "• App uses multiple strategies to create directories\n";
|
||||||
|
guidance += "• If directory creation fails, files are saved to app data directory\n";
|
||||||
|
guidance += "• Files in app data directory persist between app installations\n\n";
|
||||||
|
|
||||||
|
guidance += "🔧 Directory Creation Strategies:\n";
|
||||||
|
guidance += "1. Recursive file creation (works on some devices)\n";
|
||||||
|
guidance += "2. Parent-by-parent directory creation\n";
|
||||||
|
guidance += "3. Simple file test creation\n";
|
||||||
|
guidance += "4. App-specific external directory creation\n";
|
||||||
|
guidance += "5. Fallback to app data directory (always works)\n\n";
|
||||||
|
|
||||||
|
guidance += "💡 User Experience:\n";
|
||||||
|
guidance += "• Files are always saved successfully\n";
|
||||||
|
guidance += "• Backup files are immediately visible in the app\n";
|
||||||
|
guidance += "• No user intervention required\n";
|
||||||
|
guidance += "• Works regardless of storage permissions\n";
|
||||||
|
} else {
|
||||||
|
guidance += "📱 Android 9 and below:\n";
|
||||||
|
guidance += "• Full access to external storage\n";
|
||||||
|
guidance += "• Directories can be created normally\n";
|
||||||
|
guidance += "• Files saved to Downloads/TimeSafari or external storage\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
guidance += "🛡️ Privacy & Security:\n";
|
||||||
|
guidance += "• All files are saved securely\n";
|
||||||
|
guidance += "• App data directory is private to the app\n";
|
||||||
|
guidance += "• Files survive app reinstalls\n";
|
||||||
|
guidance += "• No data loss due to storage restrictions\n";
|
||||||
|
|
||||||
|
return guidance;
|
||||||
|
} catch (error) {
|
||||||
|
return "Unable to provide directory creation guidance. Please check your device settings for app permissions.";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user