我有一个用 Delphi 12 FMX for Android 编写的应用程序。我想将文件从 '/storage/emulated/0/Documents/calorie_conspiration.db' 复制到 '/data/user/0/com.embarcadero.CC/files/calorie_conspiration.db'。 我的代码如下:
procedure TfrmMain.CopyDB(direction2download: Boolean);
var
f1, f2: String;
const
permRead = 'android.permission.READ_EXTERNAL_STORAGE';
permWrite = 'android.permission.WRITE_EXTERNAL_STORAGE';
begin
{$IFDEF ANDROID}
PermissionsService.RequestPermissions([permRead, permWrite],
procedure(const APermissions: TClassicStringDynArray; const AGrantResults: TClassicPermissionStatusDynArray)
begin
if (Length(AGrantResults) = 2) and (AGrantResults[0] = TPermissionStatus.Granted) and (AGrantResults[1] = TPermissionStatus.Granted) then
begin
dmCC.FDConnection.Connected := False;
f1 := TPath.Combine(TPath.GetDocumentsPath, 'calorie_consumption.db');
f2 := TPath.Combine(TPath.GetSharedDocumentsPath, 'calorie_consumption.db');
if direction2download then
begin
TFile.Copy(f2, f1, True);
memSQLTest.Lines.Add(f2 + ' -> ' + f1);
end else
begin
TFile.Copy(f1, f2, True);
memSQLTest.Lines.Add(f1 + ' -> ' + f2);
end;
dmCC.FDConnection.Connected := True;
end else
begin
TDialogService.ShowMessage('Permission not granted!');
end;
end);
{$ENDIF}
end;
在“使用权限”中,我将 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 设置为 True。
我的AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.embarcadero.CC"
android:versionCode="1"
android:versionName="1.0.1"
android:installLocation="auto">
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="34" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
<queries>
</queries>
<application
android:persistent="False"
android:restoreAnyVersion="False"
android:label="CC"
android:debuggable="true"
android:largeHeap="False"
android:icon="@drawable/ic_launcher"
android:theme="@style/AppTheme"
android:hardwareAccelerated="true"
android:resizeableActivity="true"
android:requestLegacyExternalStorage="true">
<meta-data android:name="com.google.android.gms.version" android:value="12451000" />
<!-- Trigger Google Play services to install the backported photo picker module. -->
<service
android:name="com.google.android.gms.metadata.ModuleDependencies"
android:enabled="false"
android:exported="false"
tools:ignore="MissingClass">
<intent-filter>
<action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" />
</intent-filter>
<meta-data android:name="photopicker_activity:0:required" android:value="" />
</service>
<!-- Our activity is a subclass of the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
<activity
android:name="com.embarcadero.firemonkey.FMXNativeActivity"
android:exported="true"
android:label="CC"
android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"
android:launchMode="singleTask">
<!-- Tell NativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name" android:value="CC" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.embarcadero.rtl.notifications.NotificationAlarm" />
</application>
</manifest>
<!-- END_INCLUDE(manifest) -->
当我尝试执行代码时,它不会请求许可,但会出现错误: Project CC.apk 引发异常类 EFCreateError 并显示消息“无法创建文件“/storage/emulated/0/Documents/calorie_conspiration.db”。权限被拒绝'。
我已经尝试了所有可能的选项,包括 TMobilePermissions 组件,但它不起作用。
任何人都可以帮助我并指出我正确的方向吗?
我设法通过从 TPath.GetPublicPath, 'Documents/calorie_conspiration.db 而不是从 TPath.GetSharedDocumentsPath, 'calorie_conspiration.db 复制文件来解决这个问题。这似乎无需分配任何权限即可工作。
procedure TfrmMain.CopyDB(direction2download: Boolean);
var
f1, f2: String;
begin
{$IFDEF ANDROID}
try
f1 := TPath.Combine(TPath.GetDocumentsPath, 'calorie_consumption.db');
f2 := TPath.Combine(TPath.GetPublicPath, 'Documents/calorie_consumption.db');
dmCC.FDConnection.Connected := False;
if direction2download then
begin
TFile.Copy(f2, f1, True);
memSQLTest.Lines.Add(f2 + ' -> ' + f1);
end else
begin
TFile.Copy(f1, f2, True);
memSQLTest.Lines.Add(f1 + ' -> ' + f2);
end;
dmCC.FDConnection.Connected := True;
except
on E: Exception do
TDialogService.ShowMessage('Error: ' + E.Message);
end;
{$ENDIF}
end;