Permissions Android et changements à partir de Delphi 11 Alexandria

Depuis la version 10.3 Rio de Delphi et la fameuse API 25 d'Android il est nécessaire de demander des autorisations dans nos programmes avant d'utiliser certaines fonctionnalités susceptibles d'obtenir des informations personnelles sur nos utilisateurs. Ca se gère à la fois dans les options de projet (rubrique Application / Permissions d'utilisation) et dans le code pour certaines d'entre elles.

Pour que ça fonctionne il nous faut l'unité System.Permissions et depuis la version 11 Alexandria l'unité System.Types.

Si vous avez du code à utiliser dans plusieurs versions de Delphi, vous devriez avoir quelque chose comme ça dans la clause USES des unités accédant aux API Android :

Uses
{$IF CompilerVersion >= 33.0}
  // Delphi 10.3 Rio
  System.Permissions,
{$ENDIF}
{$IF CompilerVersion >= 35.0}
  // Delphi 11 Alexandria
  System.Types,
{$ENDIF}
xxx,yyy,zzz;

Et lorsqu'on a besoin de tester ou demander une autorisation on fait appel à PermissionsService.RequestPermissions par exemple dans un bloc de code comme 

{$IF CompilerVersion >= 33.0}
    PermissionsService.RequestPermissions(Permissions, RequestPermissionsResultProc, DisplayRationaleProc);
{$ENDIF}

où on pointe vers des procédures de demande et vérification des permissions (RequestPermissionsResultProc) ou affichage d'un message si elles ont été rejetées par l'utilisateur (DisplayRationaleProc). On peut mettre du code directement dedans (sous forme de procédure anonyme) comme on peut aussi utiliser des méthodes plutôt que des procédures.

Il se trouve que dans Delphi version 11 Alexandria la déclaration de TRequestPermissionsResultProc et TDisplayRationaleEvent ont été modifiées par Embarcadero. Nos blocs de déclarations existants doivent être adaptés.

Si on travaille à la fois sur des versions antérieures à Alexandria et des suivantes, on doit ruser.

Voici donc la solution la plus simple : fournir les deux déclarations au compilateur qui choisira la bonne selon sa version.

{$IFDEF ANDROID}
  PermissionsService.RequestPermissions(['android.permission.CAMERA'],
{$IF CompilerVersion >= 35.0}
    procedure(const APermissions: TClassicStringDynArray;
      const AGrantResults: TClassicPermissionStatusDynArray)
{$ELSE}
  procedure(const APermissions: TArray<string>;
    const AGrantResults: TArray<TPermissionStatus>)
{$ENDIF}
  begin
    if (Length(AGrantResults) = 1) and
      (AGrantResults[0] = TPermissionStatus.Granted) then
      // autorisation reçue, faire ce qu'on ferait si on n'était pas sous Android
      CameraComponentQRCode.Active := true
    else
    begin
      // Pas d'autorisation, c'est triste, mais c'est son droit
      showmessage('Caméra nécessaire');
      close;
    end;
  end,
{$IF CompilerVersion >= 35.0}
  procedure(const APermissions: TClassicStringDynArray;
    const APostRationaleProc: TProc)
{$ELSE}
  procedure(const APermissions: TArray<string>;
    const APostRationaleProc: TProc)
{$ENDIF}
  begin
    // affiche un message à l'utilisateur pour justifier de la demande de permission (par exemple ShowMessage)
    // appelle APostRationaleProc en sortie (sur le bouton du ShowMessage par exemple)
  end);
{$ELSE}
    // on n'est pas sous Android, on en profite (mais avec modération)
    CameraComponentQRCode.Active := true;
{$ENDIF}

Si on passe par des procédures anonymes ou 

{$IF CompilerVersion >= 35.0}
procedure TMobilePermissionsAndroid.RequestPermissionsResultProc
  (const APermissions: TClassicStringDynArray;
  const AGrantResults: TClassicPermissionStatusDynArray);
{$ELSE}
procedure TMobilePermissionsAndroid.RequestPermissionsResultProc(
  const APermissions: TArray<string>;
  const AGrantResults: TArray<TPermissionStatus>);
{$ENDIF}
begin
  // faire ce qu'on a à faire
end;

si on passe par des appels de procédures. Ce qui sera à faire aussi pour des méthodes si on préfère cette option puisque leur signature a aussi été modifiée.

Notez que je conditionne parfois au fait d'être sur Android ou de ne pas y être. C'est aussi le cas sur pas mal d'exemples ou projets que l'on trouve en faisant des recherches sur Internet. En réalité ça ne sert à rien.

Sur Android l'unité System.Permissions fait le traitement de demande des permissions.
Sur les autres plateformes elle nous dit que c'est ok sans rien faire d'autre.

Le seul vrai test à faire est de savoir si on est avant ou après la 10.3 Rio pour conditionner les traitements liés aux permissions, et avant ou après la 11 Alexandria pour conditionner les déclarations des callbacks.

Bien entendu, si on travaille uniquement sur la dernière version et qu'on ne diffuse pas nos codes sources à d'autres développeurs Delphi, pas de raison de s'embêter avec tout ça : on change tout simplement nos sources en suivant ces évolutions.


Mug carte postale SydneyMug Chinese New Year 2023 : year of the rabbit