Как исправить проблему с несовпадением типов при использовании PermissionsService в Delphi: правильное определение анонимного метода и параметров для запроса разрешений на доступ к внешнему хранилищу.
Решение проблемы с несовпадением типов при использовании PermissionsService в Delphi
При работе с системой разрешений в Delphi, особенно в версии 12.2 Athens, разработчики могут столкнуться с проблемой несовпадения типов при использовании PermissionsService.RequestPermissions. В этой статье я подробно разберу проблему и предложу несколько рабочих решений.
Понимание проблемы
Основная проблема возникает при определении параметров анонимного метода для обработки результатов запроса разрешений. Рассмотрим оригинальный код:
PermissionsService.RequestPermissions(
[
JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE),
JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE),
JStringToString(TJManifest_permission.JavaClass.MANAGE_EXTERNAL_STORAGE)
],
procedure(const APermissions: TClassicStringDynArray; const AGrantResults: TArray<string>)
begin
if PermissionsService.IsEveryPermissionGranted(AGrantResults) then
ThenDo;
end,
procedure(const APermissions: TClassicStringDynArray; const APostRationaleProc: TProc)
begin
TDialogService.ShowMessage(UserMessage,
procedure(const AResult: TModalResult)
begin
APostRationaleProc;
end)
end
);
Проблема заключается в том, что:
PermissionsService.IsEveryPermissionGranted ожидает параметр типа TArray<string>
Но сигнатура RequestPermissions требует, чтобы второй параметр анонимного метода был TClassicPermissionStatusDynArray
Причины проблемы
Это не ошибка компилятора, а особенность системы типов в Delphi:
TClassicStringDynArray - это псевдоним для array of string
TArray<string> - это также псевдоним для array of string
Однако с точки зрения компилятора это разные типы, несмотря на то, что они оба представляют массив строк
Решение 1: Приведение типов
Простейшее решение - явное приведение типов:
PermissionsService.RequestPermissions(
// ...
procedure(const APermissions: TClassicStringDynArray;
const AGrantResults: TClassicPermissionStatusDynArray)
begin
if PermissionsService.IsEveryPermissionGranted(TArray<string>(APermissions)) then
ThenDo;
end,
// ...
);
Это решение работает, но имеет недостаток - мы проверяем исходные разрешения, а не результаты их предоставления.
Решение 2: Проверка результатов напрямую
Более правильный подход - проверять непосредственно результаты (AGrantResults), а не снова запрашивать статус разрешений:
PermissionsService.RequestPermissions(
// ...
procedure(const APermissions: TClassicStringDynArray;
const AGrantResults: TClassicPermissionStatusDynArray)
var
I: Integer;
AllGranted: Boolean;
begin
AllGranted := True;
for I := Low(AGrantResults) to High(AGrantResults) do
begin
if AGrantResults[I] <> TPermissionStatus.Granted then
begin
AllGranted := False;
Break;
end;
end;
if AllGranted then
ThenDo;
end,
// ...
);
Решение 3: Создание собственного помощника
Если вы часто работаете с разрешениями, можно создать собственный помощник:
type
TPermissionHelper = class
class function IsAllGranted(const AGrantResults: TClassicPermissionStatusDynArray): Boolean;
end;
class function TPermissionHelper.IsAllGranted(const AGrantResults: TClassicPermissionStatusDynArray): Boolean;
var
I: Integer;
begin
Result := True;
for I := Low(AGrantResults) to High(AGrantResults) do
if AGrantResults[I] <> TPermissionStatus.Granted then
Exit(False);
end;
И использовать его:
PermissionsService.RequestPermissions(
// ...
procedure(const APermissions: TClassicStringDynArray;
const AGrantResults: TClassicPermissionStatusDynArray)
begin
if TPermissionHelper.IsAllGranted(AGrantResults) then
ThenDo;
end,
// ...
);
Альтернативное решение с TArray
Если вы предпочитаете работать с generics, можно использовать следующий подход:
function CheckAllPermissionsGranted(const AGrantResults: TArray<TPermissionStatus>): Boolean;
var
Status: TPermissionStatus;
begin
for Status in AGrantResults do
if Status <> TPermissionStatus.Granted then
Exit(False);
Result := True;
end;
// Использование:
PermissionsService.RequestPermissions(
// ...
procedure(const APermissions: TClassicStringDynArray;
const AGrantResults: TClassicPermissionStatusDynArray)
begin
if CheckAllPermissionsGranted(TArray<TPermissionStatus>(AGrantResults)) then
ThenDo;
end,
// ...
);
Рекомендации
Единообразие типов: Старайтесь использовать либо классические динамические массивы (array of T), либо generics (TArray<T>), но не смешивать их в одном проекте.
Обработка ошибок: Всегда предусматривайте обработку случаев, когда разрешения не предоставлены.
Тестирование: Тщательно тестируйте поведение приложения на устройствах с разными версиями Android, так как система разрешений может работать по-разному.
Документирование: Комментируйте код, особенно места с приведениями типов, чтобы другие разработчики понимали причины таких решений.
Заключение
Проблема несовпадения типов при работе с PermissionsService в Delphi 12.2 Athens действительно существует, но она решаема. Лучшим подходом является прямое использование предоставленных результатов (AGrantResults) вместо повторного вызова IsEveryPermissionGranted. Если же вам необходимо использовать именно IsEveryPermissionGranted, применяйте явное приведение типов.
Для проектов, где работа с разрешениями является частой задачей, рекомендуется создать собственные вспомогательные методы, которые обеспечат единообразие кода и упростят его поддержку.
```json
{
"response": "Проблема несовпадения типов при работе с PermissionsService в Delphi 12.2, требующая явного приведения типов или использования альтернативных методов для корректной обработки разрешений."
}
```
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.