Utiliser l'action standard TakePhotoFromCamera pour les applications Android 9 et plus

Le composant TActionList de FireMonkey, comme celui de la VCL, propose des actions personnalisées mais aussi des actions standards.

Sur smartphones et tablettes ces actions standards donnent accès à des fonctionnalités classiques dans les applications mobiles : appels téléphoniques, envoi de textos, choix ou prises de photos.

L'utilisation est assez simple : on pose un TActionList sur une fiche, on ajoute les actions et actions standards qui nous intéressent et on les attache aux éléments d'interface ou on appelle leur méthode Execute.

Pour TTakePhotoFromCameraAction, l'événement DidFinishTaking nous permet de récupérer la photographie prise si l'utilisateur l'a validée dans l'application caméra de son appareil.

procedure TForm1.TakePhotoFromCameraAction1DidFinishTaking(Image: TBitmap);
begin
  ImageViewer1.Bitmap.Assign(Image);
end;

C'est bien joli tout ça mais ce n'est pas aussi simple en pratique : depuis Android 9 et son API 26 nous devons jouer avec différentes permissions et c'est à nous de les coder puisque les actions standards ne les gèrent pas d'elles-mêmes.

Pour faire appel à l'application de prises de photos de l'appareil il nous faut :

  • activer le droit de "partage de fichiers sécurisés" depuis Projet / Options / Application / Liste des droits
  • activer les permissions "Appareil photo", "Ecrire le stockage externe" et "Lire le stockage externe" depuis Projet / Options / Application / Permissions d'utilisation / Dangereux

Et comme pour toutes les permissions dangereuses il faut également le faire au niveau du code source du programme.

Par exemple il faudrait mettre le code suivant (ou une variante) dans le onClick d'un bouton déclenchant la prise de photo.

procedure TForm1.Button1Click(Sender: TObject);
begin
  PermissionsService.RequestPermissions(['android.permission.CAMERA',
    'android.permission.WRITE_EXTERNAL_STORAGE',
    'android.permission.READ_EXTERNAL_STORAGE'],
    procedure(const APermissions: TArray<string>;
      const AGrantResults: TArray<TPermissionStatus>)
    begin
      if PermissionsService.IsPermissionGranted('android.permission.CAMERA') and
        PermissionsService.IsPermissionGranted
        ('android.permission.WRITE_EXTERNAL_STORAGE') and
        PermissionsService.IsPermissionGranted
        ('android.permission.READ_EXTERNAL_STORAGE') then
        TakePhotoFromCameraAction1.Execute
      else
        showmessage('Permission needed');
    end);
end;

L'unité System.Permissions doit également être présente dans votre unité. Elle est disponible depuis Delphi 10.3 Rio.

Si vous ne faites pas tout ça l'appareil signalera qu'il lui manque des autorisations ou pourra envoyer l'erreur suivante : 

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference

Alors autant l'éviter, n'est-ce pas ?

Bien entendu si vous avez déjà publié des applications mobiles utilisant cette action standard il est fortement recommandé de les mettre à jour.

Et si vous utilisez le même source pour iOS et Android, aucune crainte, par défaut toutes les autorisations demandées pour Android sont acceptées sur les autres plateformes de façon transparente. Pas de test d'OS ni de conditionnement du compilateur nécessaire.


Mug Toucan DX dans la baie de RioMug Toucan DX dans la baie de Rio